diff options
Diffstat (limited to 'src/libknot')
64 files changed, 4428 insertions, 3403 deletions
diff --git a/src/libknot/common.h b/src/libknot/common.h index 9b2d8ae..9b2d8ae 100644..100755 --- a/src/libknot/common.h +++ b/src/libknot/common.h diff --git a/src/libknot/consts.h b/src/libknot/consts.h index 4249763..4249763 100644..100755 --- a/src/libknot/consts.h +++ b/src/libknot/consts.h diff --git a/src/libknot/dname.c b/src/libknot/dname.c index 80de030..7d59b6b 100644..100755 --- a/src/libknot/dname.c +++ b/src/libknot/dname.c @@ -163,7 +163,7 @@ static int knot_dname_str_to_wire(const char *name, uint size, return -1; } - dbg_dname("Allocated space for wire format of dname: %p\n", wire); + dbg_dname_verb("Allocated space for wire format of dname: %p\n", wire); if (root) { *wire = '\0'; @@ -181,18 +181,18 @@ static int knot_dname_str_to_wire(const char *name, uint size, assert(w - wire - 1 == ch - (const uint8_t *)name); if (*ch == '.') { - dbg_dname("Position %zd (%p): " - "label length: %u\n", - label_start - wire, - label_start, label_length); + dbg_dname_detail("Position %zd (%p): " + "label length: %u\n", + label_start - wire, + label_start, label_length); *label_start = label_length; labels[label_count++] = label_start - wire; label_start = w; label_length = 0; } else { assert(w - wire < wire_size); - dbg_dname("Position %zd (%p): character: %c\n", - w - wire, w, *ch); + dbg_dname_detail("Position %zd (%p): character: %c\n", + w - wire, w, *ch); *w = *ch; ++label_length; } @@ -205,14 +205,13 @@ static int knot_dname_str_to_wire(const char *name, uint size, --ch; if (*ch == '.') { // put 0 for root label if the name ended with . --w; - dbg_dname("Position %zd (%p): character: (null)\n", - w - wire, w); + dbg_dname_detail("Position %zd (%p): character: (null)\n", + w - wire, w); *w = 0; } else { // otherwise we did not save the last label length - dbg_dname("Position %zd (%p): " - "label length: %u\n", - label_start - wire, - label_start, label_length); + dbg_dname_detail("Position %zd (%p): label length: %u\n", + label_start - wire, + label_start, label_length); *label_start = label_length; labels[label_count++] = label_start - wire; } @@ -277,7 +276,8 @@ static int knot_dname_find_labels(knot_dname_t *dname, int alloc) if (pos - name > size || *pos != '\0' ) { dbg_dname("Wrong wire format of domain name!\n"); - dbg_dname("Position: %d, character: %d, expected size: %d\n", pos - name, *pos, size); + dbg_dname("Position: %d, character: %d, expected size: %d\n", + pos - name, *pos, size); return -1; } @@ -298,12 +298,11 @@ static int knot_dname_find_labels(knot_dname_t *dname, int alloc) static int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2, int cs) { -dbg_dname_exec( +dbg_dname_exec_verb( char *name1 = knot_dname_to_str(d1); char *name2 = knot_dname_to_str(d2); - dbg_dname("Comparing dnames %s and %s\n", - name1, name2); + dbg_dname_verb("Comparing dnames %s and %s\n", name1, name2); for (int i = 0; i < strlen(name1); ++i) { name1[i] = knot_tolower(name1[i]); @@ -312,8 +311,7 @@ dbg_dname_exec( name2[i] = knot_tolower(name2[i]); } - dbg_dname("After to lower: %s and %s\n", - name1, name2); + dbg_dname_detail("After to lower: %s and %s\n", name1, name2); free(name1); free(name2); @@ -325,16 +323,16 @@ dbg_dname_exec( int l1 = d1->label_count; int l2 = d2->label_count; - dbg_dname("Label counts: %d and %d\n", l1, l2); + dbg_dname_detail("Label counts: %d and %d\n", l1, l2); assert(l1 >= 0); assert(l2 >= 0); // compare labels from last to first while (l1 > 0 && l2 > 0) { - dbg_dname("Comparing labels %d and %d\n", - l1 - 1, l2 - 1); - dbg_dname(" at offsets: %d and %d\n", - d1->labels[l1 - 1], d2->labels[l2 - 1]); + dbg_dname_detail("Comparing labels %d and %d\n", + l1 - 1, l2 - 1); + dbg_dname_detail(" at offsets: %d and %d\n", + d1->labels[l1 - 1], d2->labels[l2 - 1]); int res = knot_dname_compare_labels( &d1->name[d1->labels[--l1]], &d2->name[d2->labels[--l2]], @@ -434,26 +432,6 @@ dbg_dname_exec_verb( /*----------------------------------------------------------------------------*/ -//int knot_dname_from_wire(knot_dname_t *dname, const uint8_t *name, -// uint size) -//{ -// int i = 0; -// uint8_t labels[KNOT_MAX_DNAME_LABELS]; -// int label_i = 0; - -// while (name[i] != 0) { -// labels[label_i++] = i; -// uint8_t label_length = name[i]; -// if (i + label_length >= size) { -// return -2; -// } -// for (int j = 1; j <= label_length; ++j) { -// } -// } -//} - -/*----------------------------------------------------------------------------*/ - knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, uint size, struct knot_node *node) { @@ -510,12 +488,10 @@ knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire, return NULL; } labels[l] = i; - dbg_dname("Next label (%d.) position: %zu\n", l, i); + dbg_dname_detail("Next label (%d.) position: %zu\n", l, i); if (knot_wire_is_pointer(wire + p)) { // pointer. - -// printf("Pointer.\n"); size_t ptr = knot_wire_get_pointer(wire + p); /* Check that the pointer points backwards @@ -622,6 +598,10 @@ knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname) /* dname_new_from_wire() does not accept non-FQDN dnames, so we * do the copy by hand. It's faster anyway */ + if (dname == NULL) { + return NULL; + } + knot_dname_t *copy = knot_dname_new(); CHECK_ALLOC(copy, NULL); @@ -771,7 +751,44 @@ struct knot_node *knot_dname_get_node(const knot_dname_t *dname) if (dname == NULL) { return NULL; } - return dname->node; + + knot_node_t *node = dname->node; + + /* + * If the zone contains new zone contents (during an update), we should + * return new node. Check if the node has the new node set. If it does + * not, it means this is already the new node. If it has, return the + * new node. If the new node is empty, return NULL, as the node will be + * deleted later. + */ +dbg_dname_exec_detail( + dbg_dname_detail("Getting node from dname: node: %p, zone: %p\n", node, + knot_node_zone(node)); + if (node != NULL && knot_node_zone(node) != NULL + && knot_zone_contents(knot_node_zone(node)) != NULL) { + dbg_dname_detail("zone contents gen: %d, new node of the node: " + "%p, is empty: %d\n", + knot_zone_contents_gen_is_new(knot_zone_contents( + knot_node_zone(node))), + knot_node_new_node(node), + knot_node_new_node(node) + ? knot_node_is_empty(knot_node_new_node(node)) + : -1); + } +); + + if (node && knot_node_zone(node) + && knot_zone_contents(knot_node_zone(node)) + && knot_zone_contents_gen_is_new(knot_zone_contents( + knot_node_zone(node))) + && knot_node_new_node(node) != NULL) { + node = knot_node_get_new_node(node); + if (knot_node_is_empty(node)) { + node = NULL; + } + } + + return node; } /*----------------------------------------------------------------------------*/ @@ -785,7 +802,20 @@ void knot_dname_set_node(knot_dname_t *dname, knot_node_t *node) void knot_dname_update_node(knot_dname_t *dname) { +dbg_dname_exec_detail( + char *name = knot_dname_to_str(dname); + dbg_dname_detail("Updating node pointer in dname %p: %s. Before: %p\n", + dname, name, dname->node); + free(name); +); + knot_node_update_ref(&dname->node); + dbg_dname_detail("After: %p\n", dname->node); + + if (knot_node_is_empty(dname->node)) { + dbg_dname_detail("Node is empty, setting to NULL.\n"); + dname->node = NULL; + } } /*----------------------------------------------------------------------------*/ @@ -829,12 +859,6 @@ knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname) return parent; } - -// if (dname->label_count <= 1) { -// /* Nothing to chop. */ -// return NULL; -// } - parent->size = dname->size - dname->name[0] - 1; parent->name = (uint8_t *)malloc(parent->size); @@ -894,12 +918,11 @@ void knot_dname_left_chop_no_copy(knot_dname_t *dname) int knot_dname_is_subdomain(const knot_dname_t *sub, const knot_dname_t *domain) { -dbg_dname_exec( +dbg_dname_exec_verb( char *name1 = knot_dname_to_str(sub); char *name2 = knot_dname_to_str(domain); - dbg_dname("Checking if %s is subdomain of %s\n", - name1, name2); + dbg_dname_verb("Checking if %s is subdomain of %s\n", name1, name2); free(name1); free(name2); ); @@ -919,7 +942,7 @@ dbg_dname_exec( int l1 = sub->label_count; int l2 = domain->label_count; - dbg_dname("Label counts: %d and %d\n", l1, l2); + dbg_dname_detail("Label counts: %d and %d\n", l1, l2); if (l1 <= l2) { // if sub does not have more labes than domain return 0; // it is not its subdomain @@ -927,10 +950,10 @@ dbg_dname_exec( // compare labels from last to first while (l1 > 0 && l2 > 0) { - dbg_dname("Comparing labels %d and %d\n", - l1 - 1, l2 - 1); - dbg_dname(" at offsets: %d and %d\n", - sub->labels[l1 - 1], domain->labels[l2 - 1]); + dbg_dname_detail("Comparing labels %d and %d\n", + l1 - 1, l2 - 1); + dbg_dname_detail(" at offsets: %d and %d\n", + sub->labels[l1 - 1], domain->labels[l2 - 1]); // if some labels do not match if (knot_dname_compare_labels(&sub->name[sub->labels[--l1]], &domain->name[domain->labels[--l2]], 0) @@ -989,15 +1012,6 @@ int knot_dname_label_count(const knot_dname_t *dname) uint8_t knot_dname_label_size(const knot_dname_t *dname, int i) { -// printf("Returning size of %d. label starting on %d\n", -// i, dname->labels[i]); -// printf("Label count: %d, size of %d. label: %d, size of %d.label: %d\n", -// dname->label_count, i, dname->labels[i], i + 1, -// dname->labels[i+1]); -// printf("Size from the name: %u\n", dname->name[dname->labels[i]]); -// printf("Size from label offsets: %u\n", -// dname->labels[i + 1] - dname->labels[i]); - assert(i >= 0); assert(dname->size == 1 || i + 1 == dname->label_count || dname->labels[i + 1] - dname->labels[i] - 1 @@ -1007,17 +1021,16 @@ uint8_t knot_dname_label_size(const knot_dname_t *dname, int i) /*----------------------------------------------------------------------------*/ -knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname, - int size, - const knot_dname_t *suffix) +knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname, int size, + const knot_dname_t *suffix) { -dbg_dname_exec( +dbg_dname_exec_verb( char *name = knot_dname_to_str(dname); - dbg_dname("Replacing suffix of name %s, size %d with ", name, - size); + dbg_dname_verb("Replacing suffix of name %s, size %d with ", name, + size); free(name); name = knot_dname_to_str(suffix); - dbg_dname("%s (size %d)\n", name, suffix->size); + dbg_dname_verb("%s (size %d)\n", name, suffix->size); free(name); ); knot_dname_t *res = knot_dname_new(); @@ -1025,7 +1038,7 @@ dbg_dname_exec( res->size = dname->size - size + suffix->size; - dbg_dname("Allocating %d bytes...\n", res->size); + dbg_dname_detail("Allocating %d bytes...\n", res->size); res->name = (uint8_t *)malloc(res->size); if (res->name == NULL) { knot_dname_free(&res); @@ -1034,12 +1047,12 @@ dbg_dname_exec( dbg_dname_hex((char *)res->name, res->size); - dbg_dname("Copying %d bytes from the original name.\n", - dname->size - size); + dbg_dname_detail("Copying %d bytes from the original name.\n", + dname->size - size); memcpy(res->name, dname->name, dname->size - size); dbg_dname_hex((char *)res->name, res->size); - dbg_dname("Copying %d bytes from the suffix.\n", suffix->size); + dbg_dname_detail("Copying %d bytes from the suffix.\n", suffix->size); memcpy(res->name + dname->size - size, suffix->name, suffix->size); dbg_dname_hex((char *)res->name, res->size); @@ -1057,13 +1070,6 @@ void knot_dname_free(knot_dname_t **dname) return; } -// char *name = knot_dname_to_str((*dname)); - -// printf("freeing in dname: %s %p\n", name, *dname); - -// free(name); - - if ((*dname)->name != NULL) { free((*dname)->name); } @@ -1116,13 +1122,13 @@ knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2) return NULL; } - dbg_dname("1: copying %d bytes from adress %p to %p\n", - d1->size, d1->name, new_dname); + dbg_dname_detail("1: copying %d bytes from adress %p to %p\n", + d1->size, d1->name, new_dname); memcpy(new_dname, d1->name, d1->size); - dbg_dname("2: copying %d bytes from adress %p to %p\n", - d2->size, d2->name, new_dname + d1->size); + dbg_dname_detail("2: copying %d bytes from adress %p to %p\n", + d2->size, d2->name, new_dname + d1->size); memcpy(new_dname + d1->size, d2->name, d2->size); diff --git a/src/libknot/dname.h b/src/libknot/dname.h index 473bca7..43bc4d2 100644..100755 --- a/src/libknot/dname.h +++ b/src/libknot/dname.h @@ -224,8 +224,6 @@ const struct knot_node *knot_dname_node(const knot_dname_t *dname); struct knot_node *knot_dname_get_node(const knot_dname_t *dname); -void knot_dname_set_node(knot_dname_t *dname, struct knot_node *node); - void knot_dname_update_node(knot_dname_t *dname); void knot_dname_set_node(knot_dname_t *dname, struct knot_node *node); diff --git a/src/libknot/edns.c b/src/libknot/edns.c index ea630dd..8e1efcc 100644..100755 --- a/src/libknot/edns.c +++ b/src/libknot/edns.c @@ -71,21 +71,20 @@ int knot_edns_new_from_wire(knot_opt_rr_t *opt_rr, const uint8_t *wire, // owner of EDNS OPT RR must be root (0) if (*pos != 0) { dbg_edns("EDNS packet malformed (expected root " - "domain as owner).\n"); + "domain as owner).\n"); return KNOT_EMALF; } pos += 1; // check the type of the record (must be OPT) if (knot_wire_read_u16(pos) != KNOT_RRTYPE_OPT) { - dbg_edns("EDNS packet malformed (expected OPT type" - ".\n"); + dbg_edns("EDNS packet malformed (expected OPT type.\n"); return KNOT_EMALF; } pos += 2; opt_rr->payload = knot_wire_read_u16(pos); - dbg_edns("Parsed payload: %u\n", opt_rr->payload); + dbg_edns_verb("Parsed payload: %u\n", opt_rr->payload); pos += 2; opt_rr->ext_rcode = *(pos++); @@ -107,18 +106,18 @@ int knot_edns_new_from_wire(knot_opt_rr_t *opt_rr, const uint8_t *wire, while (parsed < rdlength + KNOT_EDNS_MIN_SIZE) { if (max_size - parsed < 4) { dbg_edns("Not enough data to parse OPT RR" - " OPTION header.\n"); + " OPTION header.\n"); return KNOT_EFEWDATA; } uint16_t code = knot_wire_read_u16(pos); pos += 2; uint16_t length = knot_wire_read_u16(pos); pos += 2; - dbg_edns("EDNS OPTION: Code: %u, Length: %u\n", - code, length); + dbg_edns_verb("EDNS OPTION: Code: %u, Length: %u\n", + code, length); if (max_size - parsed - 4 < length) { dbg_edns("Not enough data to parse OPT RR" - " OPTION data.\n"); + " OPTION data.\n"); return KNOT_EFEWDATA; } int ret; @@ -144,28 +143,28 @@ int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, return KNOT_EBADARG; } - dbg_edns("Parsing payload.\n"); + dbg_edns_verb("Parsing payload.\n"); opt_rr->payload = knot_rrset_class(rrset); // the TTL has switched bytes uint32_t ttl; - dbg_edns("TTL: %u\n", knot_rrset_ttl(rrset)); + dbg_edns_detail("TTL: %u\n", knot_rrset_ttl(rrset)); knot_wire_write_u32((uint8_t *)&ttl, knot_rrset_ttl(rrset)); // first byte of TTL is extended RCODE - dbg_edns("TTL: %u\n", ttl); + dbg_edns_detail("TTL: %u\n", ttl); memcpy(&opt_rr->ext_rcode, &ttl, 1); - dbg_edns("Parsed extended RCODE: %u.\n", opt_rr->ext_rcode); + dbg_edns_detail("Parsed extended RCODE: %u.\n", opt_rr->ext_rcode); // second is the version memcpy(&opt_rr->version, (const uint8_t *)(&ttl) + 1, 1); - dbg_edns("Parsed version: %u.\n", opt_rr->version); + dbg_edns_detail("Parsed version: %u.\n", opt_rr->version); // third and fourth are flags opt_rr->flags = knot_wire_read_u16((const uint8_t *)(&ttl) + 2); - dbg_edns("Parsed flags: %u.\n", opt_rr->flags); + dbg_edns_detail("Parsed flags: %u.\n", opt_rr->flags); // size of the header, options are counted elsewhere opt_rr->size = 11; int rc = 0; - dbg_edns("Parsing options.\n"); + dbg_edns_verb("Parsing options.\n"); const knot_rdata_t *rdata = knot_rrset_rdata(rrset); // in OPT RR, all RDATA are in one RDATA item stored as BINARY data, @@ -206,7 +205,7 @@ int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, } - dbg_edns("EDNS created.\n"); + dbg_edns_verb("EDNS created.\n"); return KNOT_EOK; } @@ -316,10 +315,10 @@ int knot_edns_add_option(knot_opt_rr_t *opt_rr, uint16_t code, free(old_options); } - dbg_edns("Adding option.\n"); - dbg_edns("Code: %u.\n", code); - dbg_edns("Length: %u.\n", length); - dbg_edns("Data: %p.\n", data); + dbg_edns_verb("Adding option.\n"); + dbg_edns_verb("Code: %u.\n", code); + dbg_edns_verb("Length: %u.\n", length); + dbg_edns_verb("Data: %p.\n", data); opt_rr->options[opt_rr->option_count].data = (uint8_t *)malloc(length); CHECK_ALLOC_LOG(opt_rr->options[opt_rr->option_count].data, KNOT_ENOMEM); @@ -370,9 +369,9 @@ short knot_edns_to_wire(const knot_opt_rr_t *opt_rr, uint8_t *wire, uint8_t *pos = wire; - dbg_edns_detail("Putting OPT RR to the wire format. Size: %d, " - "position: %zu\n", - opt_rr->size, (size_t)(pos - wire)); + dbg_edns_verb("Putting OPT RR to the wire format. Size: %d, " + "position: %zu\n", + opt_rr->size, (size_t)(pos - wire)); *(pos++) = 0; knot_wire_write_u16(pos, KNOT_RRTYPE_OPT); diff --git a/src/libknot/edns.h b/src/libknot/edns.h index 022ac36..022ac36 100644..100755 --- a/src/libknot/edns.h +++ b/src/libknot/edns.h diff --git a/src/libknot/hash/cuckoo-hash-table.c b/src/libknot/hash/cuckoo-hash-table.c index 9db32bf..7358e14 100644..100755 --- a/src/libknot/hash/cuckoo-hash-table.c +++ b/src/libknot/hash/cuckoo-hash-table.c @@ -30,7 +30,6 @@ #include "util/debug.h" #include "hash/cuckoo-hash-table.h" #include "hash/hash-functions.h" -#include "common/dynamic-array.h" /*----------------------------------------------------------------------------*/ /* Macros and inline functions */ @@ -283,6 +282,8 @@ static int ck_stash_is_full(const ck_hash_table_t *table) */ static inline void ck_clear_item(ck_hash_table_item_t **item) { + dbg_stash("[EMPTY STASH] [CREATE] setting item %p (%p) to NULL.\n", + item, *item); *item = NULL; } @@ -320,49 +321,11 @@ static inline void ck_swap_items(ck_hash_table_item_t **item1, static inline void ck_put_item(ck_hash_table_item_t **to, ck_hash_table_item_t *item) { - *to = item; -} - -/*----------------------------------------------------------------------------*/ -/*! - * \brief Checks if the hash was already used twice. - * - * If yes, it means we entered a loop in the hashing process, so we must stop. - * Otherwise it remembers that we used the hash. - * - * \note According to Kirsch, et al. a check that at most one hash was used - * twice should be sufficient. We will retain our version for now. - * - * \param used Array of used table indices (hashes). - * \param hash Hash to check. - * - * \retval -1 if the hash was already used twice. - * \retval -2 if an error occured. - * \retval 0 if the hash was not used twice yet. - */ -static uint ck_check_used_twice(da_array_t *used, uint32_t hash) -{ - uint i = 0, found = 0; - while (i < da_get_count(used) && found < 2) { - if (((uint *)(da_get_items(used)))[i] == hash) { - ++found; - } - ++i; - } - - if (found == 2) { - dbg_ck_hash("Hashing entered infinite loop.\n"); - return -1; - } else { - if (da_reserve(used, 1) < 0) { - ERR_ALLOC_FAILED; - return -2; - } - ((uint *)da_get_items(used))[da_get_count(used)] = hash; - da_occupy(used, 1); - assert(da_get_count(used) < RELOCATIONS_MAX); - return 0; + if (item == NULL) { + dbg_stash("[EMPTY STASH] [CREATE] Putting NULL to item %p.\n", + to); } + *to = item; } /*----------------------------------------------------------------------------*/ @@ -419,12 +382,14 @@ static ck_hash_table_item_t **ck_find_in_stash(const ck_hash_table_t *table, * non-NULL. */ if (item->item && ck_items_match(item->item, key, length)) { - dbg_ck("Comparing item in stash (key: %.*s (size %zu))" - "with searched item (key %.*s (size %u)).\n", - (int)item->item->key_length, item->item->key, - item->item->key_length, (int)length, key, - length); + dbg_ck_detail("Comparing item in stash (key: %.*s (size" + " %zu)) with searched item (key %.*s (size %u)).\n", + (int)item->item->key_length, item->item->key, + item->item->key_length, (int)length, key, length); return &item->item; + } else if (item->item == NULL) { + dbg_stash("[EMPTY STASH] [FIND] STASH ITEM IS EMPTY: " + "%p (%p)\n", item, item->item); } item = item->next; } @@ -448,18 +413,18 @@ static ck_hash_table_item_t **ck_find_gen(const ck_hash_table_t *table, size_t length, uint8_t generation) { uint32_t hash; - dbg_ck("Finding item in generation: %u\n", generation); + dbg_ck_verb("Finding item in generation: %u\n", generation); // check hash tables for (uint t = 0; t < table->table_count; ++t) { hash = HASH(&table->hash_system, key, length, table->table_size_exp, generation, t); - dbg_ck("Hash: %u, key: %.*s\n", hash, (int)length, key); - dbg_ck("Table %d, hash: %u, item: %p\n", t + 1, hash, - table->tables[t][hash]); + dbg_ck_detail("Hash: %u, key: %.*s\n", hash, (int)length, key); + dbg_ck_detail("Table %d, hash: %u, item: %p\n", t + 1, hash, + table->tables[t][hash]); if (table->tables[t][hash] != NULL) { - dbg_ck("Table %u, key: %.*s, value: %p, key " + dbg_ck_detail("Table %u, key: %.*s, value: %p, key " "length: %zu\n", t + 1, (int)table->tables[t][hash]->key_length, table->tables[t][hash]->key, @@ -475,16 +440,16 @@ static ck_hash_table_item_t **ck_find_gen(const ck_hash_table_t *table, } // try to find in stash - dbg_ck("Searching in stash...\n"); + dbg_ck_verb("Searching in stash...\n"); ck_hash_table_item_t **found = ck_find_in_stash(table, key, length); - dbg_ck("Found pointer: %p\n", found); + dbg_ck_verb("Found pointer: %p\n", found); if (found != NULL) { - dbg_ck("Stash, key: %.*s, value: %p, key length: %zu\n", - (int)(*found)->key_length, (*found)->key, - (*found)->value, (*found)->key_length); + dbg_ck_verb("Stash, key: %.*s, value: %p, key length: %zu\n", + (int)(*found)->key_length, (*found)->key, + (*found)->value, (*found)->key_length); } // ck_find_in_buffer returns NULL if not found, otherwise pointer to @@ -520,6 +485,136 @@ static ck_hash_table_item_t **ck_find_item_nc(const ck_hash_table_t *table, } /*----------------------------------------------------------------------------*/ +/* Lightweight dynamic array for keeping track of used items. */ +/*----------------------------------------------------------------------------*/ + +typedef struct ck_used { + uint32_t *items; + uint array_count; + size_t *counts; + size_t allocated; +} ck_used_t; + +/*----------------------------------------------------------------------------*/ + +static int ck_used_create(ck_used_t *used, uint table_count) +{ + // all tables in one array + used->items = malloc(table_count * RELOCATIONS_DEFAULT + * sizeof(uint32_t)); + if (used->items == NULL) { + return -1; + } + + used->counts = malloc(table_count * sizeof(size_t)); + if (used->counts == NULL) { + free(used->items); + return -1; + } + + used->array_count = table_count; + used->allocated = RELOCATIONS_DEFAULT; + + for (int i = 0; i < table_count; ++i) { + used->counts[i] = 0; + } + + memset(used->items, 0, + used->array_count * used->allocated * sizeof(uint32_t)); + + return 0; +} + +/*----------------------------------------------------------------------------*/ + +static void ck_used_free(ck_used_t *used) +{ + free(used->items); + free(used->counts); + used->allocated = 0; +} + +/*----------------------------------------------------------------------------*/ + +static int ck_used_add(ck_used_t *used, uint table_nr, uint32_t to_add) +{ + dbg_ck_hash_verb("1) Table nr: %u, count: %zu, allocated: %zu\n", + table_nr, used->counts[table_nr], used->allocated); + + if (used->counts[table_nr] == used->allocated) { + dbg_ck_hash_verb("Reallocating...\n"); + size_t allocated_new = used->allocated * 2; + uint32_t *items_new = malloc(used->array_count * allocated_new + * sizeof(uint32_t)); + if (items_new == NULL) { + return -1; + } + + memcpy(items_new, used->items, + used->allocated * used->array_count); + + uint32_t *old_items = used->items; + + used->items = items_new; + used->allocated = allocated_new; + + free(old_items); + } + + dbg_ck_hash_verb("2) Table nr: %u, count: %zu, allocated: %zu\n", + table_nr, used->counts[table_nr], used->allocated); + + assert(used->counts[table_nr] < used->allocated); + used->items[table_nr * used->allocated + used->counts[table_nr]] + = to_add; + ++used->counts[table_nr]; + + dbg_ck_hash_verb("3)Table nr: %u, count: %zu, allocated: %zu\n", + table_nr, used->counts[table_nr], used->allocated); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Checks if the hash was already used twice. + * + * If yes, it means we entered a loop in the hashing process, so we must stop. + * Otherwise it remembers that we used the hash. + * + * \note According to Kirsch, et al. a check that at most one hash was used + * twice should be sufficient. We will retain our version for now. + * + * \param used Array of used table indices (hashes). + * \param hash Hash to check. + * + * \retval -1 if the hash was already used twice. + * \retval -2 if an error occured. + * \retval 0 if the hash was not used twice yet. + */ +static int ck_check_used_twice(ck_used_t *used, uint table_nr, + uint32_t hash) +{ + uint i = 0, found = 0; + + while (i < used->counts[table_nr] && found < 2) { + if (used->items[table_nr * used->allocated + i] == hash) { + ++found; + } + ++i; + } + + if (found == 2) { + dbg_ck_hash("Hashing entered infinite loop.\n"); + return -1; + } else { + return ck_used_add(used, table_nr, hash); + } +} + +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ /*! * \brief Hashes the given item using the given generation. * @@ -532,20 +627,26 @@ static ck_hash_table_item_t **ck_find_item_nc(const ck_hash_table_t *table, * * \retval 0 if successful and no loop occured. * \retval 1 if a loop occured and the item was inserted to the \a free place. + * \retval < 0 if an error occured. */ static int ck_hash_item(ck_hash_table_t *table, ck_hash_table_item_t **to_hash, ck_hash_table_item_t **free, uint8_t generation) { - da_array_t used[table->table_count]; - for (uint i = 0; i < table->table_count; ++i) { - da_initialize(&used[i], RELOCATIONS_DEFAULT, sizeof(uint)); +// da_array_t used[table->table_count]; +// for (uint i = 0; i < table->table_count; ++i) { +// da_initialize(&used[i], RELOCATIONS_DEFAULT, sizeof(uint)); +// } + ck_used_t used; + int ret = ck_used_create(&used, table->table_count); + if (ret != 0) { + return -1; } // hash until empty cell is encountered or until loop appears - dbg_ck_hash("Hashing key: %.*s of size %zu.\n", - (int)(*to_hash)->key_length, (*to_hash)->key, - (*to_hash)->key_length); + dbg_ck_hash_verb("Hashing key: %.*s of size %zu.\n", + (int)(*to_hash)->key_length, (*to_hash)->key, + (*to_hash)->key_length); uint next_table = 0; @@ -553,21 +654,24 @@ static int ck_hash_item(ck_hash_table_t *table, ck_hash_table_item_t **to_hash, (*to_hash)->key_length, table->table_size_exp, generation, next_table); - dbg_ck_hash("New hash: %u.\n", hash); + dbg_ck_hash_detail("New hash: %u.\n", hash); assert(hash < hashsize(table->table_size_exp)); - ((uint *)da_get_items(&used[next_table])) - [da_get_count(&used[next_table])] = hash; + ret = ck_used_add(&used, next_table, hash); + if (ret != 0) { + return -2; + } + ck_hash_table_item_t **next = &table->tables[next_table][hash]; - dbg_ck_hash("Item to be moved: %p, place in table: %p\n", - *next, next); + dbg_ck_hash_detail("Item to be moved: %p, place in table: %p\n", + *next, next); ck_hash_table_item_t **moving = to_hash; int loop = 0; while (*next != NULL) { - dbg_ck_hash("Swapping items to hash: %p and Moving: %p\n", - to_hash, moving); + dbg_ck_hash_detail("Swapping items: To hash: %p, Moving: %p\n", + to_hash, moving); ck_swap_items(to_hash, moving); // first time it's unnecessary // set the generation of the inserted item to the next @@ -575,9 +679,10 @@ static int ck_hash_item(ck_hash_table_t *table, ck_hash_table_item_t **to_hash, moving = next; - dbg_ck_hash("Moving item from table %u, key: %.*s, hash %u ", - next_table + 1, (int)(*moving)->key_length, - (*moving)->key, hash); + dbg_ck_hash_detail("Moving item from table %u, key: %.*s, hash " + "%u \n", next_table + 1, + (int)(*moving)->key_length, + (*moving)->key, hash); // if rehashing and the 'next' item is from the old generation, // start from table 1 @@ -594,31 +699,31 @@ static int ck_hash_item(ck_hash_table_t *table, ck_hash_table_item_t **to_hash, next = &table->tables[next_table][hash]; - dbg_ck_hash("to table %u, hash %u, item: %p, place: %p\n", - next_table + 1, hash, *next, next); + dbg_ck_hash_detail("To table %u, hash %u, item: %p, place: %p" + "\n", next_table + 1, hash, *next, next); if ((*next) != NULL) { - dbg_ck_hash("Table %u, hash: %u, key: %.*s\n", - next_table + 1, hash, - (int)(*next)->key_length, (*next)->key); + dbg_ck_hash_detail("Table %u, hash: %u, key: %.*s\n", + next_table + 1, hash, + (int)(*next)->key_length, (*next)->key); } // check if this cell wasn't already used in this item's hashing - if (ck_check_used_twice(&used[next_table], hash) != 0) { + if (ck_check_used_twice(&used, next_table, hash) != 0) { next = free; loop = -1; break; } } - dbg_ck_hash("Putting pointer %p (*moving) to item %p (next).\n", - *moving, next); + dbg_ck_hash_detail("Putting pointer %p (*moving) to item %p (next).\n", + *moving, next); ck_put_item(next, *moving); // set the new generation for the inserted item SET_GENERATION(&(*next)->timestamp, generation); - dbg_ck_hash("Putting pointer %p (*old) to item %p (moving).\n", - *to_hash, moving); + dbg_ck_hash_detail("Putting pointer %p (*old) to item %p (moving).\n", + *to_hash, moving); ck_put_item(moving, *to_hash); @@ -626,9 +731,7 @@ static int ck_hash_item(ck_hash_table_t *table, ck_hash_table_item_t **to_hash, SET_GENERATION(&(*moving)->timestamp, generation); *to_hash = NULL; - for (uint i = 0; i < table->table_count; ++i) { - da_destroy(&used[i]); - } + ck_used_free(&used); return loop; } @@ -670,6 +773,10 @@ static void ck_rollback_rehash(ck_hash_table_t *table) */ int ck_add_to_stash(ck_hash_table_t *table, ck_hash_table_item_t *item) { + if (item == NULL) { + dbg_stash("[EMPTY STASH] [CREATE] ADDING NULL ITEM TO STASH\n"); + } + ck_stash_item_t *new_item = (ck_stash_item_t *)malloc(sizeof(ck_stash_item_t)); if (new_item == NULL) { @@ -681,8 +788,8 @@ int ck_add_to_stash(ck_hash_table_t *table, ck_hash_table_item_t *item) new_item->next = table->stash; table->stash = new_item; - dbg_ck_hash("First item in stash (now inserted): key: %.*s (size %zu)" - ", value: %p\n", (int)table->stash->item->key_length, + dbg_ck_hash_verb("First item in stash (now inserted): key: %.*s (size" + " %zu), value: %p\n", (int)table->stash->item->key_length, table->stash->item->key, table->stash->item->key_length, table->stash->item->value); @@ -739,12 +846,12 @@ ck_hash_table_t *ck_create_table(uint items) dbg_ck("Creating hash table for %u items.\n", items); dbg_ck("Exponent: %u, number of tables: %u\n ", - table->table_size_exp, table->table_count); + table->table_size_exp, table->table_count); dbg_ck("Table size: %u items, each %zu bytes, total %zu bytes\n", - hashsize(table->table_size_exp), - sizeof(ck_hash_table_item_t *), - hashsize(table->table_size_exp) - * sizeof(ck_hash_table_item_t *)); + hashsize(table->table_size_exp), + sizeof(ck_hash_table_item_t *), + hashsize(table->table_size_exp) + * sizeof(ck_hash_table_item_t *)); // create tables for (uint t = 0; t < table->table_count; ++t) { @@ -805,18 +912,6 @@ void ck_destroy_table(ck_hash_table_t **table, void (*dtor_value)(void *value), } // destroy items in stash -// ck_hash_table_item_t **stash = -// ((ck_hash_table_item_t **)(da_get_items(&(*table)->stash))); -// for (uint i = 0; i < da_get_count(&(*table)->stash); ++i) { -// assert(stash[i] != NULL); -// if (dtor_value) { -// dtor_value(stash[i]->value); -// } -// if (delete_key != 0) { -// free((void *)stash[i]->key); -// } -// free((void *)stash[i]); -// } ck_stash_item_t *item = (*table)->stash; while (item != NULL) { // disconnect the item @@ -842,8 +937,6 @@ void ck_destroy_table(ck_hash_table_t **table, void (*dtor_value)(void *value), for (uint t = 0; t < (*table)->table_count; ++t) { free((*table)->tables[t]); } - // destroy stash -// da_destroy(&(*table)->stash); pthread_mutex_unlock(&(*table)->mtx_table); // destroy mutex, assuming that here noone will lock the mutex again @@ -884,7 +977,7 @@ void ck_table_free(ck_hash_table_t **table) int ck_resize_table(ck_hash_table_t *table) { dbg_ck("Resizing hash table.\n"); - + /* * Easiest is just to increment the exponent, resulting in doubling * the table sizes. This is not very memory-effective, but should do @@ -900,7 +993,7 @@ int ck_resize_table(ck_hash_table_t *table) ck_hash_table_item_t **tables_old[MAX_TABLES]; int exp_new = table->table_size_exp + 1; - dbg_ck("New tables exponent: %d\n", exp_new); + dbg_ck_verb("New tables exponent: %d\n", exp_new); for (int t = 0; t < table->table_count; ++t) { if (ck_new_table(&tables_new[t], exp_new) != 0) { @@ -919,14 +1012,14 @@ int ck_resize_table(ck_hash_table_t *table) * sizeof(ck_hash_table_item_t *); // copy the old table items - dbg_ck("Copying to: %p, from %p, size: %zu\n", - tables_new[t], table->tables[t], old_size); + dbg_ck_verb("Copying to: %p, from %p, size: %zu\n", + tables_new[t], table->tables[t], old_size); memcpy(tables_new[t], table->tables[t], old_size); // set the rest to 0 - dbg_ck("Setting to 0 from %p, size %zu\n", - tables_new[t] + hashsize(table->table_size_exp), - (hashsize(exp_new) * sizeof(ck_hash_table_item_t *)) - - old_size); + dbg_ck_verb("Setting to 0 from %p, size %zu\n", + tables_new[t] + hashsize(table->table_size_exp), + (hashsize(exp_new) * sizeof(ck_hash_table_item_t *)) + - old_size); memset(tables_new[t] + hashsize(table->table_size_exp), 0, (hashsize(exp_new) * sizeof(ck_hash_table_item_t *)) - old_size); @@ -948,7 +1041,6 @@ int ck_resize_table(ck_hash_table_t *table) } return ck_rehash(table); - //return 0; } int ck_insert_item(ck_hash_table_t *table, const char *key, @@ -980,9 +1072,6 @@ int ck_insert_item(ck_hash_table_t *table, const char *key, } } - // there should be at least 2 free places - //assert(da_try_reserve(&table->stash, 2) == 0); - //da_reserve(&table->stash, 1); ck_hash_table_item_t *free_place = NULL; if (ck_hash_item(table, &new_item, &free_place, table->generation) != 0) { @@ -1104,6 +1193,8 @@ ck_hash_table_item_t *ck_remove_item(ck_hash_table_t *table, const char *key, int ck_shallow_copy(const ck_hash_table_t *from, ck_hash_table_t **to) { + dbg_ck("ck_shallow_copy()\n"); + if (from == NULL || to == NULL) { return -1; } @@ -1176,26 +1267,27 @@ int ck_shallow_copy(const ck_hash_table_t *from, ck_hash_table_t **to) return -2; } - dbg_ck("Copying stash item: %p with item %p, ", si, si->item); - dbg_ck("key: %.*s\n", (int)si->item->key_length, si->item->key); + dbg_ck_detail("Copying stash item: %p with item %p, key: %.*s" + "\n", si, si->item, (int)si->item->key_length, + si->item->key); si_new->item = si->item; *pos = si_new; pos = &si_new->next; si = si->next; - - dbg_ck("Old stash item: %p with item %p, ", si, - ((si == NULL) ? NULL : si->item)); +dbg_ck_exec_detail( + dbg_ck_detail("Old stash item: %p with item %p, \n", si, + ((si == NULL) ? NULL : si->item)); if (si != NULL) { - dbg_ck("key: %.*s\n", (int)si->item->key_length, si->item->key); - } else { - dbg_ck("\n"); + dbg_ck_detail("key: %.*s\n", (int)si->item->key_length, + si->item->key); } - dbg_ck("New stash item: %p with item %p, ", si_new, - si_new->item); - dbg_ck("key: %.*s\n", (int)si_new->item->key_length, - si_new->item->key); + dbg_ck_detail("New stash item: %p with item %p, ", si_new, + si_new->item); + dbg_ck_detail("key: %.*s\n", (int)si_new->item->key_length, + si_new->item->key); +); } *pos = NULL; @@ -1273,11 +1365,12 @@ void ck_deep_copy_cleanup(ck_hash_table_t *table, int table_count) int ck_deep_copy(ck_hash_table_t *from, ck_hash_table_t **to) { + dbg_ck("ck_deep_copy()\n"); + if (from == NULL || to == NULL) { return -1; } - dbg_ck("Allocating new table...\n"); *to = (ck_hash_table_t *)malloc(sizeof(ck_hash_table_t)); if (*to == NULL) { @@ -1341,10 +1434,12 @@ int ck_deep_copy(ck_hash_table_t *from, ck_hash_table_t **to) return -2; } - dbg_ck("Copying stash item: %p with item %p, ", si, si->item); -// dbg_ck("key: %.*s\n", (int)si->item->key_length, si->item->key); + dbg_ck_detail("Copying stash item: %p with item %p, ", si, + si->item); if (si->item == NULL) { + dbg_stash("[EMPTY STASH] [FIND] STASH ITEM IS EMPTY: " + "%p (%p)\n", si, si->item); si_new->item = NULL; si_new->next = NULL; } else { @@ -1367,22 +1462,20 @@ int ck_deep_copy(ck_hash_table_t *from, ck_hash_table_t **to) pos = &si_new->next; si = si->next; -dbg_ck_exec( - dbg_ck("Old stash item: %p with item %p, ", si, - ((si == NULL) ? NULL : si->item)); +dbg_ck_exec_detail( + dbg_ck_detail("Old stash item: %p with item %p, \n", si, + ((si == NULL) ? NULL : si->item)); if (si != NULL && si->item != NULL) { - dbg_ck("key: %.*s\n", (int)si->item->key_length, - si->item->key); - } else { - dbg_ck("\n"); + dbg_ck_detail("key: %.*s\n", (int)si->item->key_length, + si->item->key); } - dbg_ck("New stash item: %p with item %p, ", si_new, - (si_new) ? si_new->item : NULL); + dbg_ck_detail("New stash item: %p with item %p, ", si_new, + (si_new) ? si_new->item : NULL); assert(si_new != NULL); assert(si_new->item != NULL); - dbg_ck("key: %.*s\n", (int)si_new->item->key_length, - si_new->item->key); + dbg_ck_detail("key: %.*s\n", (int)si_new->item->key_length, + si_new->item->key); ); } @@ -1446,13 +1539,13 @@ int ck_rehash(ck_hash_table_t *table) do { // 1) Rehash items from stash - dbg_ck_rehash("Rehashing items from stash.\n"); + dbg_ck_hash_verb("Rehashing items from stash.\n"); ck_stash_item_t *item = table->stash; ck_stash_item_t **item_place = &table->stash; // terminate when at the end; this way the newly added items // (added to the beginning) will be properly ignored while (item != NULL) { - dbg_ck_rehash("Rehashing item with " + dbg_ck_hash_detail("Rehashing item with " "key (length %zu): %.*s, generation: %hu, " "table generation: %hu.\n", item->item->key_length, (int)item->item->key_length, item->item->key, @@ -1481,6 +1574,8 @@ int ck_rehash(ck_hash_table_t *table) assert(item->item == NULL); // and the item should be hashed too // assert(table->hashed == NULL); + dbg_stash("[EMPTY STASH] [CREATE] Created empty" + " item: %p (%p)\n", item, item->item); // fix the pointer from the previous hash item *item_place = item->next; @@ -1501,12 +1596,11 @@ int ck_rehash(ck_hash_table_t *table) // which will be put to the stash ck_hash_table_item_t *free = NULL; assert(table->hashed == NULL); -// ck_hash_table_item_t *old = table->hashed; for (uint t = 0; t < table->table_count; ++t) { uint rehashed = 0; - dbg_ck_rehash("Rehashing table %d.\n", t); + dbg_ck_hash_verb("Rehashing table %d.\n", t); while (rehashed < hashsize(table->table_size_exp)) { @@ -1516,13 +1610,13 @@ int ck_rehash(ck_hash_table_t *table) || !(EQUAL_GENERATIONS( table->tables[t][rehashed]->timestamp, table->generation))) { - dbg_ck_rehash("Skipping item.\n"); + dbg_ck_hash_detail("Skipping item.\n"); ++rehashed; continue; } - dbg_ck_rehash("Rehashing item with hash %u, " - "key (length %zu): %.*s, generation: %hu, " + dbg_ck_hash_detail("Rehashing item with hash %u" + ", key (length %zu): %.*s, generation: %hu, " "table generation: %hu.\n", rehashed, table->tables[t][rehashed]->key_length, (int)(table->tables[t][rehashed]->key_length), @@ -1537,8 +1631,8 @@ int ck_rehash(ck_hash_table_t *table) // get rehashed again ck_clear_item(&table->tables[t][rehashed]); - dbg_ck_rehash("Table generation: %hu, next " - "generation: %hu.\n", + dbg_ck_hash_detail("Table generation: %hu, next" + " generation: %hu.\n", GET_GENERATION(table->generation), NEXT_GENERATION(table->generation)); @@ -1546,8 +1640,8 @@ int ck_rehash(ck_hash_table_t *table) NEXT_GENERATION(table->generation)) != 0) { // loop occured dbg_ck_hash("Hashing entered a loop." - "\n"); - dbg_ck_rehash("Item with key %.*s " + "\n"); + dbg_ck_hash_verb("Item with key %.*s " "inserted into the free slot.\n", free->key_length, free->key); @@ -1561,6 +1655,12 @@ int ck_rehash(ck_hash_table_t *table) free_stash_items; free_stash_items = item->next; + if (free == NULL) { + dbg_stash("[EMPTY STASH] " + "[CREATE] STORING NULL" + " in the stash\n"); + } + item->item = free; item->next = table->stash; table->stash = item; @@ -1579,15 +1679,15 @@ int ck_rehash(ck_hash_table_t *table) } } - dbg_ck_rehash("Old table generation: %u\n", - GET_GENERATION(table->generation)); + dbg_ck_hash("Old table generation: %u\n", + GET_GENERATION(table->generation)); // rehashing completed, switch generation of the table SET_NEXT_GENERATION(&table->generation); - dbg_ck_rehash("New table generation: %u\n", - GET_GENERATION(table->generation)); + dbg_ck_hash("New table generation: %u\n", + GET_GENERATION(table->generation)); // generate new hash functions for the old generation - dbg_ck_rehash("Generating coeficients for generation: %u\n", - NEXT_GENERATION(table->generation)); + dbg_ck_hash("Generating coeficients for generation: %u\n", + NEXT_GENERATION(table->generation)); us_next(&table->hash_system, NEXT_GENERATION(table->generation)); @@ -1609,248 +1709,6 @@ int ck_rehash(ck_hash_table_t *table) } /*----------------------------------------------------------------------------*/ -/*! - * \brief Rehashes the whole table. - * - * \param table Hash table to be rehashed. - * - * \note While rehashing no item should be inserted as it will result in a - * deadlock. - * - * \retval 0 No error. - * \retval -1 Rehashing failed. Some items may have been already moved and the - * rehashing flag remains set. - * - * \todo What if the stash is reallocated during ck_hash_item()? We'd be using - * the old stash for saving items! The old stash would not get deallocated - * (due to RCU - maybe put some rcu_read_lock() here), but the item - * would not be saved into the new stash! - * Maybe add a function for getting a pointer to particular item from - * the dynamic array and protect it using rcu_read_lock(). - * Other option: Do not use pointer to an item in stash in the call to - * ck_hash_item(). Use some new place & put the item to the stash - * afterwards, protecting it using rcu_read_lock() and rcu_assign_pointer. - */ -//int ck_rehash(ck_hash_table_t *table) -//{ -// dbg_ck_rehash("Rehashing items in table.\n"); -// SET_REHASHING_ON(&table->generation); - -// // we already have functions for the next generation, begin rehashing -// // we wil use the last item in the buffer as free cell for hashing -// assert(da_try_reserve(&table->stash, 1) == 0); -// ck_hash_table_item_t *old = (ck_hash_table_item_t *) -// (malloc(sizeof(ck_hash_table_item_t))); - -// do { -// dbg_ck_hash("Rehash!\n"); - -// if (da_get_count(&table->stash) > STASH_SIZE) { -// dbg_ck_hash("STASH RESIZED!!! (new stash size: %d)\n", -// da_get_count(&table->stash)); -// } - -// // rehash items from stash, starting from the last old item -// int stash_i = da_get_count(&table->stash) - 1; -// while (stash_i >= 0) { -// // if item's generation is the new generation, skip -// if (STASH_ITEMS(&table->stash)[stash_i] == NULL -// || !(EQUAL_GENERATIONS(STASH_ITEMS(&table->stash) -// [stash_i]->timestamp, -// table->generation))) { -// dbg_ck_rehash("Skipping item.\n"); -// --stash_i; -// continue; -// } - -// dbg_ck_rehash("Rehashing item from buffer position %u" -// ", key (length %u): %.*s, generation: " -// "%hu, table generation: %hu.\n", -// stash_i, -// STASH_ITEMS(&table->stash)[stash_i]->key_length, -// (int)STASH_ITEMS(&table->stash)[stash_i]->key_length, -// STASH_ITEMS(&table->stash)[stash_i]->key, -// GET_GENERATION( -// STASH_ITEMS(&table->stash)[stash_i]->timestamp), -// GET_GENERATION(table->generation)); - -// // otherwise copy the item for rehashing -// ck_put_item(&old, STASH_ITEMS(&table->stash)[stash_i]); -// // clear the place so that this item will not get -// // rehashed again -// ck_clear_item(&STASH_ITEMS(&table->stash)[stash_i]); -// da_release(&table->stash, 1); - -// // there should be at least one place in the stash -// assert(da_try_reserve(&table->stash, 1) == 0); -// da_reserve(&table->stash, 1); - -// assert(STASH_ITEMS(&table->stash)[stash_i] == NULL); - -// // and start rehashing -// if (ck_hash_item(table, &old, -// &STASH_ITEMS(&table->stash)[stash_i], -// NEXT_GENERATION(table->generation)) != 0) { -// // loop occured -// dbg_ck_hash("Hashing entered a loop.\n"); - -// dbg_ck_rehash("Item with key %.*s inserted " -// "into the stash on position %d.\n", -// STASH_ITEMS(&table->stash) -// [stash_i]->key_length, -// STASH_ITEMS(&table->stash) -// [stash_i]->key, -// da_get_count(&table->stash)); - -// // hashing unsuccessful, the item was inserted -// // into the stash -// da_occupy(&table->stash, 1); -// assert(STASH_ITEMS(&table->stash)[stash_i] -// != NULL); - -// // if only one place left, resize the stash -// // TODO: Why??? -// if (da_reserve(&table->stash, 2) < 0) { -// // stash could not be resized => !!! -// dbg_ck_hash("Failed to rehash items " -// "from " -// "table, no other rehash possible!\n"); -// // so rollback -// ck_rollback_rehash(table); -// // clear the 'old' item -// ck_clear_item(&old); -// return -1; -// } -// } - -// // clear the 'old' item -// ck_clear_item(&old); -// // decrement the index -// --stash_i; -// } - -// uint i = 0; -// while (i < da_get_count(&table->stash)) { -// assert(STASH_ITEMS(&table->stash)[i] != NULL); -// ++i; -// } -// dbg_ck_hash("OK\n"); -// assert(da_try_reserve(&table->stash, 1) == 0); -// assert(STASH_ITEMS(&table->stash)[da_get_count(&table->stash)] -// == NULL); - -// // rehash items from hash tables -// for (uint t = TABLE_FIRST; -// t <= TABLE_LAST(table->table_count); ++t) { -// dbg_ck_rehash("Rehashing items from table %d.\n", -// t + 1); -// uint rehashed = 0; - -// while (rehashed < hashsize(table->table_size_exp)) { - -// // if item's generation is the new generation, -// // skip -// if (table->tables[t][rehashed] == NULL -// || !(EQUAL_GENERATIONS( -// table->tables[t][rehashed]->timestamp, -// table->generation))) { -// dbg_ck_rehash("Skipping item.\n"); -// ++rehashed; -// continue; -// } - -// dbg_ck_rehash("Rehashing item with hash %u, " -// "key (length %u): %.*s, generation: %hu, " -// "table generation: %hu.\n", rehashed, -// table->tables[t][rehashed]->key_length, -// (int)(table->tables[t][rehashed]->key_length), -// table->tables[t][rehashed]->key, -// GET_GENERATION( -// table->tables[t][rehashed]->timestamp), -// GET_GENERATION(table->generation)); - -// // otherwise copy the item for rehashing -// ck_put_item(&old, table->tables[t][rehashed]); -// // clear the place so that this item will not -// // get rehashed again -// ck_clear_item(&table->tables[t][rehashed]); - -// dbg_ck_rehash("Table generation: %hu, next " -// "generation: %hu.\n", -// GET_GENERATION(table->generation), -// NEXT_GENERATION(table->generation)); - -// // and start rehashing -// assert(&old != &STASH_ITEMS(&table->stash)[ -// da_get_count(&table->stash)]); -// assert(da_try_reserve(&table->stash, 1) == 0); -// da_reserve(&table->stash, 1); - -// if (ck_hash_item(table, &old, -// &STASH_ITEMS(&table->stash)[ -// da_get_count(&table->stash)], -// NEXT_GENERATION(table->generation)) != 0) { -// // loop occured -// dbg_ck_hash("Hashing entered a loop." -// "\n"); -// dbg_ck_rehash("Item with key %.*s " -// "inserted into the stash on position " -// "%d.\n", STASH_ITEMS(&table->stash)[ -// da_get_count(&table->stash)] -// ->key_length, -// STASH_ITEMS(&table->stash)[ -// da_get_count(&table->stash)]->key, -// da_get_count(&table->stash)); - -// assert(STASH_ITEMS(&table->stash)[ -// da_get_count(&table->stash)] != NULL); -// // loop occured, the item is already at -// // its new place in the buffer, so just -// // increment the index -// da_occupy(&table->stash, 1); - -// // if only one place left, resize the -// // stash TODO: Why? -// if (da_reserve(&table->stash, 2) < 0) { -// // stash could not be resized -// dbg_ck_hash("Failed to rehash" -// " items from table, no other " -// "rehash possible!\n"); -// // so rollback -// ck_rollback_rehash(table); -// // clear the 'old' item -// ck_clear_item(&old); -// return -1; -// } -// } -// ++rehashed; -// } -// } - -// dbg_ck_rehash("Old table generation: %u\n", -// GET_GENERATION(table->generation)); -// // rehashing completed, switch generation of the table -// SET_NEXT_GENERATION(&table->generation); -// dbg_ck_rehash("New table generation: %u\n", -// GET_GENERATION(table->generation)); -// // generate new hash functions for the old generation -// dbg_ck_rehash("Generating coeficients for generation: %u\n", -// NEXT_GENERATION(table->generation)); -// us_next(NEXT_GENERATION(table->generation)); - -// // repeat rehashing while there are more items in the stash than -// // its initial size -// if (da_get_count(&table->stash) > STASH_SIZE) { -// dbg_ck_rehash("Rehashing again!\n"); -// } -// } while (da_get_count(&table->stash) > STASH_SIZE); - -// SET_REHASHING_OFF(&table->generation); - -// return 0; -//} - -/*----------------------------------------------------------------------------*/ void ck_dump_table(const ck_hash_table_t *table) { @@ -1872,15 +1730,6 @@ void ck_dump_table(const ck_hash_table_t *table) } dbg_ck("Stash:\n"); -// for (i = 0; i < da_get_count(&table->stash); ++i) { -// dbg_ck("Index: %u, Key: %.*s Value: %p.\n", i, -// ((ck_hash_table_item_t **) -// da_get_items(&table->stash))[i]->key_length, -// ((ck_hash_table_item_t **) -// da_get_items(&table->stash))[i]->key, -// ((ck_hash_table_item_t **) -// da_get_items(&table->stash))[i]->value); -// } ck_stash_item_t *item = table->stash; while (item != NULL) { dbg_ck("Hash: %u, Key: %.*s, Value: %p.\n", i, diff --git a/src/libknot/hash/cuckoo-hash-table.h b/src/libknot/hash/cuckoo-hash-table.h index eaa6a89..c0fe9cc 100644..100755 --- a/src/libknot/hash/cuckoo-hash-table.h +++ b/src/libknot/hash/cuckoo-hash-table.h @@ -42,7 +42,6 @@ #include <pthread.h> #include "hash/universal-system.h" -#include "common/dynamic-array.h" /*----------------------------------------------------------------------------*/ diff --git a/src/libknot/hash/hash-functions.c b/src/libknot/hash/hash-functions.c index a33dd6b..a33dd6b 100644..100755 --- a/src/libknot/hash/hash-functions.c +++ b/src/libknot/hash/hash-functions.c diff --git a/src/libknot/hash/hash-functions.h b/src/libknot/hash/hash-functions.h index f23730b..f23730b 100644..100755 --- a/src/libknot/hash/hash-functions.h +++ b/src/libknot/hash/hash-functions.h diff --git a/src/libknot/hash/universal-system.c b/src/libknot/hash/universal-system.c index 096974c..096974c 100644..100755 --- a/src/libknot/hash/universal-system.c +++ b/src/libknot/hash/universal-system.c diff --git a/src/libknot/hash/universal-system.h b/src/libknot/hash/universal-system.h index 25330de..25330de 100644..100755 --- a/src/libknot/hash/universal-system.h +++ b/src/libknot/hash/universal-system.h diff --git a/src/libknot/libknot.h b/src/libknot/libknot.h index a401be7..a401be7 100644..100755 --- a/src/libknot/libknot.h +++ b/src/libknot/libknot.h diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c index 7a6bc4d..6924f44 100644..100755 --- a/src/libknot/nameserver/name-server.c +++ b/src/libknot/nameserver/name-server.c @@ -126,10 +126,9 @@ static const knot_zone_t *ns_get_zone_for_qname(knot_zonedb_t *zdb, static knot_rrset_t *ns_synth_from_wildcard( const knot_rrset_t *wildcard_rrset, const knot_dname_t *qname) { - dbg_ns("Synthetizing RRSet from wildcard...\n"); + dbg_ns_verb("Synthetizing RRSet from wildcard...\n"); knot_dname_t *owner = knot_dname_deep_copy(qname); -// printf("Copied owner ptr: %p\n", owner); knot_rrset_t *synth_rrset = knot_rrset_new( owner, knot_rrset_type(wildcard_rrset), @@ -143,7 +142,7 @@ static knot_rrset_t *ns_synth_from_wildcard( return NULL; } - dbg_ns("Created RRSet header:\n"); + dbg_ns_verb("Created RRSet header:\n"); knot_rrset_dump(synth_rrset, 1); // copy all RDATA @@ -159,15 +158,15 @@ static knot_rrset_t *ns_synth_from_wildcard( return NULL; } - dbg_ns("Copied RDATA:\n"); + dbg_ns_verb("Copied RDATA:\n"); knot_rdata_dump(rdata_copy, knot_rrset_type(synth_rrset), 1); - knot_rrset_add_rdata(synth_rrset, rdata_copy); + int ret = knot_rrset_add_rdata(synth_rrset, rdata_copy); + assert(ret == KNOT_EOK); rdata = knot_rrset_rdata_next(wildcard_rrset, rdata); } -// printf("Synthetized RRSet pointer: %p\n", synth_rrset); return synth_rrset; } @@ -182,8 +181,8 @@ static knot_rrset_t *ns_synth_from_wildcard( * temporary RRSet). * \param rrset RRSet to check (and possibly replace). */ -static void ns_check_wildcard(const knot_dname_t *name, knot_packet_t *resp, - knot_rrset_t **rrset) +static int ns_check_wildcard(const knot_dname_t *name, knot_packet_t *resp, + knot_rrset_t **rrset) { assert(name != NULL); assert(resp != NULL); @@ -193,11 +192,26 @@ static void ns_check_wildcard(const knot_dname_t *name, knot_packet_t *resp, if (knot_dname_is_wildcard((*rrset)->owner)) { knot_rrset_t *synth_rrset = ns_synth_from_wildcard(*rrset, name); - dbg_ns("Synthetized RRSet:\n"); + if (synth_rrset == NULL) { + dbg_ns("Failed to synthetize RRSet from wildcard.\n"); + return KNOT_ERROR; + } + +dbg_ns_exec_verb( + dbg_ns_verb("Synthetized RRSet:\n"); knot_rrset_dump(synth_rrset, 1); - knot_packet_add_tmp_rrset(resp, synth_rrset); +); + + int ret = knot_packet_add_tmp_rrset(resp, synth_rrset); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add sythetized RRSet to tmp list.\n"); + knot_rrset_deep_free(&synth_rrset, 1, 1, 1); + return ret; + } *rrset = synth_rrset; } + + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ @@ -230,23 +244,28 @@ static int ns_add_rrsigs(knot_rrset_t *rrset, knot_packet_t *resp, { knot_rrset_t *rrsigs; - dbg_ns("Adding RRSIGs for RRSet, type: %s.\n", - knot_rrtype_to_string(knot_rrset_type(rrset))); + dbg_ns_verb("Adding RRSIGs for RRSet, type: %s.\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); assert(resp != NULL); assert(add_rrset_to_resp != NULL); - dbg_ns("DNSSEC requested: %d\n", - knot_query_dnssec_requested(knot_packet_query(resp))); - dbg_ns("RRSIGS: %p\n", knot_rrset_rrsigs(rrset)); + dbg_ns_detail("DNSSEC requested: %d\n", + knot_query_dnssec_requested(knot_packet_query(resp))); + dbg_ns_detail("RRSIGS: %p\n", knot_rrset_rrsigs(rrset)); if (DNSSEC_ENABLED && knot_query_dnssec_requested(knot_packet_query(resp)) && (rrsigs = knot_rrset_get_rrsigs(rrset)) != NULL) { if (name != NULL) { - ns_check_wildcard(name, resp, &rrsigs); + int ret = ns_check_wildcard(name, resp, &rrsigs); + if (ret != KNOT_EOK) { + dbg_ns("Failed to process wildcard: %s\n", + knot_strerror(ret)); + return ret; + } } - return add_rrset_to_resp(resp, rrsigs, tc, 0, 0, 1); + return add_rrset_to_resp(resp, rrsigs, tc, 1, 0, 1); } return KNOT_EOK; @@ -265,7 +284,7 @@ static int ns_add_rrsigs(knot_rrset_t *rrset, knot_packet_t *resp, * \param tc Set to 1 if omitting the RRSIG RRSet should result in setting the * TC bit in the response. */ -static void ns_follow_cname(const knot_node_t **node, +static int ns_follow_cname(const knot_node_t **node, const knot_dname_t **qname, knot_packet_t *resp, int (*add_rrset_to_resp)(knot_packet_t *, @@ -273,19 +292,22 @@ static void ns_follow_cname(const knot_node_t **node, int, int, int, int), int tc) { - dbg_ns("Resolving CNAME chain...\n"); + dbg_ns_verb("Resolving CNAME chain...\n"); knot_rrset_t *cname_rrset; + int ret = 0; + while (*node != NULL && (cname_rrset = knot_node_get_rrset(*node, KNOT_RRTYPE_CNAME)) - != NULL) { + != NULL + && (knot_rrset_rdata(cname_rrset) != NULL)) { /* put the CNAME record to answer, but replace the possible wildcard name with qname */ assert(cname_rrset != NULL); - dbg_ns("CNAME RRSet: %p, owner: %p\n", cname_rrset, - cname_rrset->owner); + dbg_ns_detail("CNAME RRSet: %p, owner: %p\n", cname_rrset, + cname_rrset->owner); knot_rrset_t *rrset = cname_rrset; @@ -294,27 +316,67 @@ static void ns_follow_cname(const knot_node_t **node, /* if wildcard node, we must copy the RRSet and replace its owner */ rrset = ns_synth_from_wildcard(cname_rrset, *qname); - knot_packet_add_tmp_rrset(resp, rrset); - add_rrset_to_resp(resp, rrset, tc, 0, 0, 1); - ns_add_rrsigs(cname_rrset, resp, *qname, - add_rrset_to_resp, tc); + if (rrset == NULL) { + dbg_ns("Failed to synthetize RRSet from " + "wildcard RRSet followed from CNAME.\n"); + return KNOT_ERROR; /*! \todo Better error. */ + } + + ret = knot_packet_add_tmp_rrset(resp, rrset); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add synthetized RRSet (CNAME " + "follow) to the tmp RRSets in response." + "\n"); + knot_rrset_deep_free(&rrset, 1, 1, 1); + return ret; + } + + ret = add_rrset_to_resp(resp, rrset, tc, 0, 0, 1); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add synthetized RRSet (CNAME " + "follow) to the response.\n"); + return ret; + } + + ret = ns_add_rrsigs(cname_rrset, resp, *qname, + add_rrset_to_resp, tc); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIG for the synthetized" + "RRSet (CNAME follow) to the response." + "\n"); + return ret; + } int ret = knot_response_add_wildcard_node( resp, *node, *qname); - - /*! \todo Fix when return values are handled! */ if (ret != KNOT_EOK) { - assert(0); + dbg_ns("Failed to add wildcard node for later " + "processing.\n"); + return ret; } } else { - add_rrset_to_resp(resp, rrset, tc, 0, 0, 1); - ns_add_rrsigs(rrset, resp, *qname, add_rrset_to_resp, - tc); + ret = add_rrset_to_resp(resp, rrset, tc, 0, 0, 1); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add followed RRSet into" + "the response.\n"); + return ret; + } + + ret = ns_add_rrsigs(rrset, resp, *qname, + add_rrset_to_resp, tc); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIG for followed RRSet " + "into the response.\n"); + return ret; + } } - dbg_ns("Using RRSet: %p, owner: %p\n", rrset, rrset->owner); + dbg_ns_detail("Using RRSet: %p, owner: %p\n", rrset, + rrset->owner); -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(knot_rrset_owner(rrset)); dbg_ns("CNAME record for owner %s put to response.\n", name); free(name); @@ -323,18 +385,16 @@ dbg_ns_exec( // get the name from the CNAME RDATA const knot_dname_t *cname = knot_rdata_cname_name( knot_rrset_rdata(cname_rrset)); - dbg_ns("CNAME name from RDATA: %p\n", cname); + dbg_ns_detail("CNAME name from RDATA: %p\n", cname); // change the node to the node of that name *node = knot_dname_node(cname); - dbg_ns("This name's node: %p\n", *node); -// // it is not an old node and if yes, skip it -// if (knot_node_is_old(*node)) { -// *node = knot_node_new_node(*node); -// } + dbg_ns_detail("This name's node: %p\n", *node); // save the new name which should be used for replacing wildcard *qname = cname; - }; + } + + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ @@ -350,47 +410,70 @@ dbg_ns_exec( * * \return Number of RRSets added. */ -static int ns_put_answer(const knot_node_t *node, const knot_dname_t *name, - uint16_t type, knot_packet_t *resp) +static int ns_put_answer(const knot_node_t *node, + const knot_zone_contents_t *zone, + const knot_dname_t *name, + uint16_t type, knot_packet_t *resp, int *added, + int check_any) { - int added = 0; -dbg_ns_exec( + *added = 0; +dbg_ns_exec_verb( char *name_str = knot_dname_to_str(node->owner); - dbg_ns("Putting answers from node %s.\n", name_str); + dbg_ns_verb("Putting answers from node %s.\n", name_str); free(name_str); ); + int ret = KNOT_EOK; + switch (type) { case KNOT_RRTYPE_ANY: { - dbg_ns("Returning all RRTYPES.\n"); + dbg_ns_verb("Returning all RRTYPES.\n"); + + // if ANY not allowed, set TC bit + if (check_any && knot_zone_contents_any_disabled(zone)) { + knot_response_set_tc(resp); + break; + } + knot_rrset_t **rrsets = knot_node_get_rrsets(node); if (rrsets == NULL) { break; } int i = 0; - int ret = 0; knot_rrset_t *rrset; while (i < knot_node_rrset_count(node)) { assert(rrsets[i] != NULL); rrset = rrsets[i]; - dbg_ns(" Type: %s\n", + dbg_ns_detail(" Type: %s\n", knot_rrtype_to_string(knot_rrset_type(rrset))); - ns_check_wildcard(name, resp, &rrset); + ret = ns_check_wildcard(name, resp, &rrset); + if (ret != KNOT_EOK) { + dbg_ns("Failed to process wildcard.\n"); + break; + } + ret = knot_response_add_rrset_answer(resp, rrset, 1, 0, 0, 1); - if (ret >= 0 && (added += 1) - && (ret = ns_add_rrsigs(rrset, resp, name, - knot_response_add_rrset_answer, 1)) - >=0 ) { - added += 1; - } else { - free(rrsets); - rrsets = NULL; + if (ret != KNOT_EOK) { + dbg_ns("Failed add Answer RRSet: %s\n", + knot_strerror(ret)); + break; + } + + *added += 1; + + ret = ns_add_rrsigs(rrset, resp, name, + knot_response_add_rrset_answer, 1); + if (ret != KNOT_EOK) { + dbg_ns("Failed add RRSIGs for Answer RRSet: %s" + "\n", knot_strerror(ret)); break; } + *added += 1; + ++i; } if (rrsets != NULL) { @@ -399,7 +482,7 @@ dbg_ns_exec( break; } case KNOT_RRTYPE_RRSIG: { - dbg_ns("Returning all RRSIGs.\n"); + dbg_ns_verb("Returning all RRSIGs.\n"); knot_rrset_t **rrsets = knot_node_get_rrsets(node); if (rrsets == NULL) { break; @@ -416,15 +499,21 @@ dbg_ns_exec( continue; } - ns_check_wildcard(name, resp, &rrset); + ret = ns_check_wildcard(name, resp, &rrset); + if (ret != KNOT_EOK) { + dbg_ns("Failed to process wildcard.\n"); + break; + } + ret = knot_response_add_rrset_answer(resp, rrset, 1, 0, 0, 1); - - if (ret < 0) { + if (ret != KNOT_EOK) { + dbg_ns("Failed add Answer RRSet: %s\n", + knot_strerror(ret)); break; } - added += 1; + *added += 1; ++i; } free(rrsets); @@ -434,23 +523,41 @@ dbg_ns_exec( int ret = 0; knot_rrset_t *rrset = knot_node_get_rrset(node, type); knot_rrset_t *rrset2 = rrset; - if (rrset != NULL) { - dbg_ns("Found RRSet of type %s\n", - knot_rrtype_to_string(type)); - ns_check_wildcard(name, resp, &rrset2); + if (rrset != NULL && knot_rrset_rdata(rrset) != NULL) { + dbg_ns_verb("Found RRSet of type %s\n", + knot_rrtype_to_string(type)); + + ret = ns_check_wildcard(name, resp, &rrset2); + if (ret != KNOT_EOK) { + dbg_ns("Failed to process wildcard.\n"); + break; + } + ret = knot_response_add_rrset_answer(resp, rrset2, 1, 0, 0, 1); - if (ret >= 0 && (added += 1) - && (ret = ns_add_rrsigs(rrset, resp, name, - knot_response_add_rrset_answer, 1)) > 0) { - added += 1; + if (ret != KNOT_EOK) { + dbg_ns("Failed add Answer RRSet: %s\n", + knot_strerror(ret)); + break; } + + *added += 1; + + ret = ns_add_rrsigs(rrset, resp, name, + knot_response_add_rrset_answer, 1); + + if (ret != KNOT_EOK) { + dbg_ns("Failed add RRSIGs for Answer RRSet: %s" + "\n", knot_strerror(ret)); + break; + } + + *added += 1; } } } - knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); - return added; + return ret; } /*----------------------------------------------------------------------------*/ @@ -471,34 +578,36 @@ dbg_ns_exec( * \param resp Response where to add the Additional data. * \param rrset RRSet to get the Additional data for. */ -static void ns_put_additional_for_rrset(knot_packet_t *resp, - const knot_rrset_t *rrset) +static int ns_put_additional_for_rrset(knot_packet_t *resp, + const knot_rrset_t *rrset) { const knot_node_t *node = NULL; const knot_rdata_t *rdata = NULL; const knot_dname_t *dname = NULL; + int ret = 0; + // for all RRs in the RRset rdata = knot_rrset_rdata(rrset); while (rdata != NULL) { - dbg_ns("Getting name from RDATA, type %s..\n", - knot_rrtype_to_string(knot_rrset_type(rrset))); + dbg_ns_verb("Getting name from RDATA, type %s..\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); dname = knot_rdata_get_name(rdata, knot_rrset_type(rrset)); + +dbg_ns_exec_detail( + char *name = knot_dname_to_str(dname); + dbg_ns_detail("Name: %s\n", name); + free(name); +); assert(dname != NULL); node = knot_dname_node(dname); -// dbg_ns_detail("Node saved in RDATA dname: %p\n", node); -// char *name = knot_dname_to_str(dname); -// dbg_ns_detail("Owner of the node: %p, dname: %p (%s)\n", -// node->owner, dname, name); -// free(name); -// knot_node_dump((knot_node_t *)node, (void *)1); - + dbg_ns_detail("Node saved in RDATA dname: %p\n", node); if (node != NULL && node->owner != dname) { - // the stored node should be the closest encloser - assert(knot_dname_is_subdomain(dname, node->owner)); - // try the wildcard child, if any - node = knot_node_wildcard_child(node); + // the stored node should be the wildcard covering the + // name + dbg_ns_detail("Node is wildcard.\n"); + assert(knot_dname_is_wildcard(knot_node_owner(node))); } knot_rrset_t *rrset_add; @@ -506,43 +615,90 @@ static void ns_put_additional_for_rrset(knot_packet_t *resp, if (node != NULL) { dbg_ns_exec( char *name = knot_dname_to_str(node->owner); - dbg_ns("Putting additional from node %s\n", name); + dbg_ns_verb("Putting additional from node %s\n", name); free(name); ); - dbg_ns("Checking CNAMEs...\n"); - if (knot_node_rrset(node, KNOT_RRTYPE_CNAME) - != NULL) { - dbg_ns("Found CNAME in node, following...\n"); + dbg_ns_detail("Checking CNAMEs...\n"); + if (knot_node_rrset(node, KNOT_RRTYPE_CNAME) != NULL) { + dbg_ns_detail("Found CNAME in node.\n"); const knot_dname_t *dname = knot_node_owner(node); - ns_follow_cname(&node, &dname, resp, + ret = ns_follow_cname(&node, &dname, resp, knot_response_add_rrset_additional, 0); + if (ret != KNOT_EOK) { + dbg_ns("Failed to follow CNAME.\n"); + return ret; + } } // A RRSet - dbg_ns("A RRSets...\n"); + dbg_ns_detail("A RRSets...\n"); rrset_add = knot_node_get_rrset(node, KNOT_RRTYPE_A); if (rrset_add != NULL) { - dbg_ns("Found A RRsets.\n"); + dbg_ns_detail("Found A RRsets.\n"); knot_rrset_t *rrset_add2 = rrset_add; - ns_check_wildcard(dname, resp, &rrset_add2); - knot_response_add_rrset_additional( + ret = ns_check_wildcard(dname, resp, + &rrset_add2); + if (ret != KNOT_EOK) { + dbg_ns("Failed to process wildcard for" + "Additional section: %s.\n", + knot_strerror(ret)); + return ret; + } + + ret = knot_response_add_rrset_additional( resp, rrset_add2, 0, 1, 0, 1); - ns_add_rrsigs(rrset_add, resp, dname, + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add A RRSet to " + "Additional section: %s.\n", + knot_strerror(ret)); + return ret; + } + + ret = ns_add_rrsigs(rrset_add, resp, dname, knot_response_add_rrset_additional, 0); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIGs for A RR" + "Set to Additional section: %s." + "\n", knot_strerror(ret)); + return ret; + } } // AAAA RRSet - dbg_ns("AAAA RRSets...\n"); + dbg_ns_detail("AAAA RRSets...\n"); rrset_add = knot_node_get_rrset(node, KNOT_RRTYPE_AAAA); if (rrset_add != NULL) { - dbg_ns("Found AAAA RRsets.\n"); + dbg_ns_detail("Found AAAA RRsets.\n"); knot_rrset_t *rrset_add2 = rrset_add; - ns_check_wildcard(dname, resp, &rrset_add2); - knot_response_add_rrset_additional( + ret = ns_check_wildcard(dname, resp, + &rrset_add2); + if (ret != KNOT_EOK) { + dbg_ns("Failed to process wildcard for" + "Additional section: %s.\n", + knot_strerror(ret)); + return ret; + } + + ret = knot_response_add_rrset_additional( resp, rrset_add2, 0, 1, 0, 1); - ns_add_rrsigs(rrset_add, resp, dname, + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add AAAA RRSet to " + "Additional section.\n"); + return ret; + } + + ret = ns_add_rrsigs(rrset_add, resp, dname, knot_response_add_rrset_additional, 0); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIG for AAAA RR" + "Set to Additional section.\n"); + return ret; + } } } @@ -550,6 +706,8 @@ dbg_ns_exec( assert(rdata != NULL); rdata = knot_rrset_rdata_next(rrset, rdata); } + + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ @@ -580,26 +738,37 @@ static int ns_additional_needed(uint16_t qtype) * * \param resp Response to process. */ -static void ns_put_additional(knot_packet_t *resp) +static int ns_put_additional(knot_packet_t *resp) { - dbg_ns("ADDITIONAL SECTION PROCESSING\n"); + dbg_ns_verb("ADDITIONAL SECTION PROCESSING\n"); const knot_rrset_t *rrset = NULL; + int ret = 0; for (int i = 0; i < knot_packet_answer_rrset_count(resp); ++i) { rrset = knot_packet_answer_rrset(resp, i); assert(rrset != NULL); if (ns_additional_needed(knot_rrset_type(rrset))) { - ns_put_additional_for_rrset(resp, rrset); + ret = ns_put_additional_for_rrset(resp, rrset); + if (ret != KNOT_EOK) { + // if error, do not try to add other RRSets + return ret; + } } } for (int i = 0; i < knot_packet_authority_rrset_count(resp); ++i) { rrset = knot_packet_authority_rrset(resp, i); if (ns_additional_needed(knot_rrset_type(rrset))) { - ns_put_additional_for_rrset(resp, rrset); + ret = ns_put_additional_for_rrset(resp, rrset); + if (ret != KNOT_EOK) { + // if error, do not try to add other RRSets + return ret; + } } } + + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ @@ -609,18 +778,35 @@ static void ns_put_additional(knot_packet_t *resp) * \param zone Zone to take the authority NS RRSet from. * \param resp Response where to add the RRSet. */ -static void ns_put_authority_ns(const knot_zone_contents_t *zone, +static int ns_put_authority_ns(const knot_zone_contents_t *zone, knot_packet_t *resp) { + dbg_ns_verb("PUTTING AUTHORITY NS\n"); + knot_rrset_t *ns_rrset = knot_node_get_rrset( knot_zone_contents_apex(zone), KNOT_RRTYPE_NS); if (ns_rrset != NULL) { - knot_response_add_rrset_authority(resp, ns_rrset, 0, 1, 0, 1); - ns_add_rrsigs(ns_rrset, resp, knot_node_owner( + int ret = knot_response_add_rrset_authority(resp, ns_rrset, 0, + 1, 0, 1); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add Authority NSs to response.\n"); + return ret; + } + + ret = ns_add_rrsigs(ns_rrset, resp, knot_node_owner( knot_zone_contents_apex(zone)), - knot_response_add_rrset_authority, 1); + knot_response_add_rrset_authority, 1); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIGs for Authority NSs to " + "response.\n"); + return ret; + } } + + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ @@ -633,6 +819,8 @@ static void ns_put_authority_ns(const knot_zone_contents_t *zone, static int ns_put_authority_soa(const knot_zone_contents_t *zone, knot_packet_t *resp) { + dbg_ns_verb("PUTTING AUTHORITY SOA\n"); + int ret; knot_rrset_t *soa_rrset = knot_node_get_rrset( @@ -644,7 +832,7 @@ static int ns_put_authority_soa(const knot_zone_contents_t *zone, uint32_t min = knot_rdata_soa_minimum(knot_rrset_rdata(soa_rrset)); if (min < knot_rrset_ttl(soa_rrset)) { knot_rrset_t *soa_copy = NULL; - ret = knot_rrset_deep_copy(soa_rrset, &soa_copy); + ret = knot_rrset_deep_copy(soa_rrset, &soa_copy, 0); if (ret != KNOT_EOK) { return ret; @@ -655,7 +843,11 @@ static int ns_put_authority_soa(const knot_zone_contents_t *zone, knot_rrset_set_ttl(soa_copy, min); soa_rrset = soa_copy; /* Need to add it as temporary, so it get's freed. */ - knot_packet_add_tmp_rrset(resp, soa_copy); + ret = knot_packet_add_tmp_rrset(resp, soa_copy); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&soa_copy, 1, 1, 1); + return ret; + } } assert(soa_rrset != NULL); @@ -717,20 +909,36 @@ static knot_dname_t *ns_next_closer(const knot_dname_t *closest_encloser, * \param node Node to get the NSEC3 RRSet from. * \param resp Response where to add the RRSets. */ -static void ns_put_nsec3_from_node(const knot_node_t *node, +static int ns_put_nsec3_from_node(const knot_node_t *node, knot_packet_t *resp) { assert(DNSSEC_ENABLED && knot_query_dnssec_requested(knot_packet_query(resp))); - knot_rrset_t *rrset = knot_node_get_rrset(node, KNOT_RRTYPE_NSEC3); - assert(rrset != NULL); + knot_rrset_t *rrset = knot_node_get_rrset(node, KNOT_RRTYPE_NSEC3); + //assert(rrset != NULL); - int res = knot_response_add_rrset_authority(resp, rrset, 1, 1, 0, 1); + if (rrset == NULL) { + // bad zone, ignore + return KNOT_EOK; + } + + int res = KNOT_EOK; + if (knot_rrset_rdata(rrset) != NULL) { + res = knot_response_add_rrset_authority(resp, rrset, 1, 1, 0, + 1); + } // add RRSIG for the RRSet - if (res == 0 && (rrset = knot_rrset_get_rrsigs(rrset)) != NULL) { - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (res == KNOT_EOK && (rrset = knot_rrset_get_rrsigs(rrset)) != NULL + && knot_rrset_rdata(rrset) != NULL) { + res = knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, + 1); } + + /*! \note TC bit is already set, if something went wrong. */ + + // return the error code, so that other code may be skipped + return res; } /*----------------------------------------------------------------------------*/ @@ -753,31 +961,25 @@ static int ns_put_covering_nsec3(const knot_zone_contents_t *zone, const knot_node_t *prev, *node; /*! \todo Check version. */ int match = knot_zone_contents_find_nsec3_for_name(zone, name, - &node, &prev); - assert(match >= 0); -// node = knot_node_current(node); -// prev = knot_node_current(prev); + &node, &prev); + //assert(match >= 0); + if (match < 0) { + // ignoring, what can we do anyway? + return KNOT_EOK; + } - if (match == KNOT_ZONE_NAME_FOUND){ - // run-time collision => SERVFAIL + if (match == KNOT_ZONE_NAME_FOUND || prev == NULL){ + // if run-time collision => SERVFAIL return KNOT_EOK; } -// // check if the prev node is not old and if yes, take the new one -// if (knot_node_is_old(prev)) { -// prev = knot_node_new_node(prev); -// assert(prev != NULL); -// } - -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(prev->owner); - dbg_ns("Covering NSEC3 node: %s\n", name); + dbg_ns_verb("Covering NSEC3 node: %s\n", name); free(name); ); - ns_put_nsec3_from_node(prev, resp); - - return KNOT_EOK; + return ns_put_nsec3_from_node(prev, resp); } /*----------------------------------------------------------------------------*/ @@ -812,19 +1014,24 @@ static int ns_put_nsec3_closest_encloser_proof( assert(qname != NULL); assert(resp != NULL); + // this function should be called only if NSEC3 is enabled in the zone + assert(knot_zone_contents_nsec3params(zone) != NULL); + + dbg_ns_verb("Adding closest encloser proof\n"); + if (knot_zone_contents_nsec3params(zone) == NULL) { -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(knot_node_owner( knot_zone_contents_apex(zone))); - dbg_ns("No NSEC3PARAM found in zone %s.\n", name); + dbg_ns_verb("No NSEC3PARAM found in zone %s.\n", name); free(name); ); return KNOT_EOK; } -dbg_ns_exec( +dbg_ns_exec_detail( char *name = knot_dname_to_str(knot_node_owner(*closest_encloser)); - dbg_ns("Closest encloser: %s\n", name); + dbg_ns_detail("Closest encloser: %s\n", name); free(name); ); @@ -845,28 +1052,30 @@ dbg_ns_exec( assert(nsec3_node != NULL); -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(nsec3_node->owner); - dbg_ns("NSEC3 node: %s\n", name); + dbg_ns_verb("NSEC3 node: %s\n", name); free(name); name = knot_dname_to_str((*closest_encloser)->owner); - dbg_ns("Closest provable encloser: %s\n", name); + dbg_ns_verb("Closest provable encloser: %s\n", name); free(name); if (next_closer != NULL) { name = knot_dname_to_str(next_closer); - dbg_ns("Next closer name: %s\n", name); + dbg_ns_verb("Next closer name: %s\n", name); free(name); } else { - dbg_ns("Next closer name: none\n"); + dbg_ns_verb("Next closer name: none\n"); } ); - ns_put_nsec3_from_node(nsec3_node, resp); + int ret = ns_put_nsec3_from_node(nsec3_node, resp); + if (ret != KNOT_EOK) { + return ret; + } /* * 2) NSEC3 that covers the "next closer" name. */ - int ret = 0; if (next_closer == NULL) { // create the "next closer" name by appending from qname next_closer = ns_next_closer( @@ -875,9 +1084,9 @@ dbg_ns_exec( if (next_closer == NULL) { return NS_ERR_SERVFAIL; } -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(next_closer); - dbg_ns("Next closer name: %s\n", name); + dbg_ns_verb("Next closer name: %s\n", name); free(name); ); ret = ns_put_covering_nsec3(zone, next_closer, resp); @@ -914,9 +1123,9 @@ static knot_dname_t *ns_wildcard_child_name(const knot_dname_t *name) return NULL; } -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(wildcard); - dbg_ns("Wildcard: %s\n", name); + dbg_ns_verb("Wildcard: %s\n", name); free(name); ); return wildcard; @@ -971,26 +1180,55 @@ static int ns_put_nsec3_no_wildcard_child(const knot_zone_contents_t *zone, * RRSets of the requested type). * \param resp Response where to add the NSECs or NSEC3s. */ -static void ns_put_nsec_nsec3_nodata(const knot_node_t *node, - knot_packet_t *resp) +static int ns_put_nsec_nsec3_nodata(const knot_zone_contents_t *zone, + const knot_node_t *node, + knot_packet_t *resp) { if (!DNSSEC_ENABLED || !knot_query_dnssec_requested(knot_packet_query(resp))) { - return; + return KNOT_EOK; } - knot_node_t *nsec3_node = knot_node_get_nsec3_node(node); + /*! \todo Maybe distinguish different errors. */ + int ret = KNOT_ERROR; + knot_rrset_t *rrset = NULL; - if ((rrset = knot_node_get_rrset(node, KNOT_RRTYPE_NSEC)) != NULL - || (nsec3_node != NULL && (rrset = - knot_node_get_rrset(nsec3_node, KNOT_RRTYPE_NSEC3)) != NULL)) { - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); - // add RRSIG for the RRSet - if ((rrset = knot_rrset_get_rrsigs(rrset)) != NULL) { - knot_response_add_rrset_authority(resp, rrset, 1, - 0, 0, 1); + + if (knot_zone_contents_nsec3_enabled(zone)) { + knot_node_t *nsec3_node = knot_node_get_nsec3_node(node); + dbg_ns_verb("Adding NSEC3 for NODATA, NSEC3 node: %p\n", + nsec3_node); + + if (nsec3_node != NULL + && (rrset = knot_node_get_rrset(nsec3_node, + KNOT_RRTYPE_NSEC3)) != NULL + && knot_rrset_rdata(rrset) != NULL) { + dbg_ns_detail("Putting the RRSet to Authority\n"); + ret = knot_response_add_rrset_authority(resp, rrset, 1, + 0, 0, 1); } + } else { + dbg_ns_verb("Adding NSEC for NODATA\n"); + if ((rrset = knot_node_get_rrset(node, KNOT_RRTYPE_NSEC)) + != NULL + && knot_rrset_rdata(rrset) != NULL) { + dbg_ns_detail("Putting the RRSet to Authority\n"); + ret = knot_response_add_rrset_authority(resp, rrset, 1, + 0, 0, 1); + } + } + + if (ret != KNOT_EOK) { + return ret; } + + dbg_ns_detail("Putting RRSet's RRSIGs to Authority\n"); + if (rrset != NULL && (rrset = knot_rrset_get_rrsigs(rrset)) != NULL) { + ret = knot_response_add_rrset_authority(resp, rrset, 1, + 0, 0, 1); + } + + return ret; } /*----------------------------------------------------------------------------*/ @@ -1030,9 +1268,11 @@ static int ns_put_nsec_nxdomain(const knot_dname_t *qname, } } +dbg_ns_exec_verb( char *name = knot_dname_to_str(previous->owner); - dbg_ns("Previous node: %s\n", name); + dbg_ns_verb("Previous node: %s\n", name); free(name); +); // 1) NSEC proving that there is no node with the searched name rrset = knot_node_get_rrset(previous, KNOT_RRTYPE_NSEC); @@ -1043,11 +1283,21 @@ static int ns_put_nsec_nxdomain(const knot_dname_t *qname, } - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + int ret = knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add NSEC for NXDOMAIN to response: %s\n", + knot_strerror(ret)); + return ret; + } + rrset = knot_rrset_get_rrsigs(rrset); assert(rrset != NULL); - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); - + ret = knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIGs for NSEC for NXDOMAIN to response:" + "%s\n", knot_strerror(ret)); + return ret; + } // 2) NSEC proving that there is no wildcard covering the name // this is only different from 1) if the wildcard would be // before 'previous' in canonical order, i.e. we can @@ -1064,9 +1314,9 @@ static int ns_put_nsec_nxdomain(const knot_dname_t *qname, while (knot_dname_compare(knot_node_owner(prev_new), wildcard) > 0) { -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(knot_node_owner(prev_new)); - dbg_ns("Previous node: %s\n", name); + dbg_ns_verb("Previous node: %s\n", name); free(name); ); assert(prev_new != knot_zone_contents_apex(zone)); @@ -1075,9 +1325,9 @@ dbg_ns_exec( assert(knot_dname_compare(knot_node_owner(prev_new), wildcard) < 0); -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(knot_node_owner(prev_new)); - dbg_ns("Previous node: %s\n", name); + dbg_ns_verb("Previous node: %s\n", name); free(name); ); @@ -1086,11 +1336,27 @@ dbg_ns_exec( if (prev_new != previous) { rrset = knot_node_get_rrset(prev_new, KNOT_RRTYPE_NSEC); - assert(rrset != NULL); - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (rrset == NULL || knot_rrset_rdata(rrset) == NULL) { + // bad zone, ignore + return KNOT_EOK; + } + ret = knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add second NSEC for NXDOMAIN to " + "response: %s\n", knot_strerror(ret)); + return ret; + } rrset = knot_rrset_get_rrsigs(rrset); - assert(rrset != NULL); - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (rrset == NULL || knot_rrset_rdata(rrset) == NULL) { + // bad zone, ignore + return KNOT_EOK; + } + ret = knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIGs for second NSEC for " + "NXDOMAIN to response: %s\n", knot_strerror(ret)); + return ret; + } } return KNOT_EOK; @@ -1118,13 +1384,12 @@ static int ns_put_nsec3_nxdomain(const knot_zone_contents_t *zone, knot_packet_t *resp) { // 1) Closest encloser proof - dbg_ns("Putting closest encloser proof.\n"); int ret = ns_put_nsec3_closest_encloser_proof(zone, &closest_encloser, qname, resp); // 2) NSEC3 covering non-existent wildcard if (ret == KNOT_EOK && closest_encloser != NULL) { - dbg_ns("Putting NSEC3 for no wildcard child of closest " - "encloser.\n"); + dbg_ns_verb("Putting NSEC3 for no wildcard child of closest " + "encloser.\n"); ret = ns_put_nsec3_no_wildcard_child(zone, closest_encloser, resp); } @@ -1207,16 +1472,16 @@ static int ns_put_nsec3_wildcard(const knot_zone_contents_t *zone, * NSEC3 that covers the "next closer" name. */ // create the "next closer" name by appending from qname - dbg_ns("Finding next closer name for wildcard NSEC3.\n"); + dbg_ns_verb("Finding next closer name for wildcard NSEC3.\n"); knot_dname_t *next_closer = ns_next_closer(closest_encloser->owner, qname); if (next_closer == NULL) { return NS_ERR_SERVFAIL; } -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(next_closer); - dbg_ns("Next closer name: %s\n", name); + dbg_ns_verb("Next closer name: %s\n", name); free(name); ); int ret = ns_put_covering_nsec3(zone, next_closer, resp); @@ -1241,10 +1506,10 @@ dbg_ns_exec( * \param previous Previous node of \a qname in canonical order. * \param resp Response to put the NSEC3s into. */ -static void ns_put_nsec_wildcard(const knot_zone_contents_t *zone, - const knot_dname_t *qname, - const knot_node_t *previous, - knot_packet_t *resp) +static int ns_put_nsec_wildcard(const knot_zone_contents_t *zone, + const knot_dname_t *qname, + const knot_node_t *previous, + knot_packet_t *resp) { assert(DNSSEC_ENABLED && knot_query_dnssec_requested(knot_packet_query(resp))); @@ -1261,13 +1526,22 @@ static void ns_put_nsec_wildcard(const knot_zone_contents_t *zone, knot_rrset_t *rrset = knot_node_get_rrset(previous, KNOT_RRTYPE_NSEC); - if (rrset != NULL) { + + int ret = KNOT_EOK; + + if (rrset != NULL && knot_rrset_rdata(rrset) != NULL) { // NSEC proving that there is no node with the searched name - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); - rrset = knot_rrset_get_rrsigs(rrset); - assert(rrset != NULL); - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + ret = knot_response_add_rrset_authority(resp, rrset, 1, 0, + 0, 1); + if (ret == KNOT_EOK) { + rrset = knot_rrset_get_rrsigs(rrset); + assert(rrset != NULL); + ret = knot_response_add_rrset_authority(resp, rrset, 1, + 0, 0, 1); + } } + + return ret; } /*----------------------------------------------------------------------------*/ @@ -1306,10 +1580,10 @@ static int ns_put_nsec_nsec3_wildcard_nodata(const knot_node_t *node, if (ret == KNOT_EOK && (nsec3_node = knot_node_nsec3_node(node)) != NULL) { - ns_put_nsec3_from_node(nsec3_node, resp); + ret = ns_put_nsec3_from_node(nsec3_node, resp); } } else { - ns_put_nsec_wildcard(zone, qname, previous, resp); + ret = ns_put_nsec_wildcard(zone, qname, previous, resp); } } return ret; @@ -1339,18 +1613,18 @@ static int ns_put_nsec_nsec3_wildcard_answer(const knot_node_t *node, const knot_dname_t *qname, knot_packet_t *resp) { - int r = KNOT_EOK; + int ret = KNOT_EOK; if (DNSSEC_ENABLED && knot_query_dnssec_requested(knot_packet_query(resp)) && knot_dname_is_wildcard(knot_node_owner(node))) { if (knot_zone_contents_nsec3_enabled(zone)) { - r = ns_put_nsec3_wildcard(zone, closest_encloser, qname, - resp); + ret = ns_put_nsec3_wildcard(zone, closest_encloser, + qname, resp); } else { - ns_put_nsec_wildcard(zone, qname, previous, resp); + ret = ns_put_nsec_wildcard(zone, qname, previous, resp); } } - return r; + return ret; } /*----------------------------------------------------------------------------*/ @@ -1403,26 +1677,27 @@ static inline int ns_referral(const knot_node_t *node, knot_packet_t *resp, uint16_t qtype) { - dbg_ns("Referral response.\n"); + dbg_ns_verb("Referral response.\n"); while (!knot_node_is_deleg_point(node)) { assert(knot_node_parent(node) != NULL); node = knot_node_parent(node); } + int ret = KNOT_EOK; + // Special handling of DS queries if (qtype == KNOT_RRTYPE_DS) { knot_rrset_t *ds_rrset = knot_node_get_rrset(node, KNOT_RRTYPE_DS); - int ret = KNOT_EOK; if (ds_rrset) { - knot_response_add_rrset_answer(resp, ds_rrset, 1, 0, - 0, 1); - if (DNSSEC_ENABLED + ret = knot_response_add_rrset_answer(resp, ds_rrset, 1, + 0, 0, 1); + if (ret == KNOT_EOK && DNSSEC_ENABLED && knot_query_dnssec_requested( knot_packet_query(resp))) { - ns_add_rrsigs(ds_rrset, resp, node->owner, + ret = ns_add_rrsigs(ds_rrset, resp, node->owner, knot_response_add_rrset_authority, 1); } @@ -1430,18 +1705,13 @@ static inline int ns_referral(const knot_node_t *node, // normal NODATA response /*! \todo Handle in some generic way. */ - dbg_ns("Adding NSEC/NSEC3 for NODATA.\n"); - ns_put_nsec_nsec3_nodata(node, resp); + dbg_ns_verb("Adding NSEC/NSEC3 for NODATA.\n"); + ret = ns_put_nsec_nsec3_nodata(zone, node, resp); + if (ret != KNOT_EOK) { + return ret; + } - // wildcard delegations not supported! -// if (knot_dname_is_wildcard(node->owner)) { -// dbg_ns("Putting NSEC/NSEC3 for wildcard" -// " NODATA\n"); -// ret = ns_put_nsec_nsec3_wildcard_nodata(node, -// closest_encloser, previous, zone, qname, -// resp); -// } - ns_put_authority_soa(zone, resp); + ret = ns_put_authority_soa(zone, resp); } return ret; @@ -1449,39 +1719,42 @@ static inline int ns_referral(const knot_node_t *node, knot_rrset_t *rrset = knot_node_get_rrset(node, KNOT_RRTYPE_NS); assert(rrset != NULL); - - // TODO: wildcards?? - //ns_check_wildcard(name, resp, &rrset); - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); - ns_add_rrsigs(rrset, resp, node->owner, - knot_response_add_rrset_authority, 1); + ret = knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (ret == KNOT_EOK) { + ret = ns_add_rrsigs(rrset, resp, node->owner, + knot_response_add_rrset_authority, 1); + } - int ret = KNOT_EOK; // add DS records - dbg_ns("DNSSEC requested: %d\n", + dbg_ns_verb("DNSSEC requested: %d\n", knot_query_dnssec_requested(knot_packet_query(resp))); - dbg_ns("DS records: %p\n", knot_node_rrset(node, KNOT_RRTYPE_DS)); - if (DNSSEC_ENABLED + dbg_ns_verb("DS records: %p\n", knot_node_rrset(node, KNOT_RRTYPE_DS)); + if (ret == KNOT_EOK && DNSSEC_ENABLED && knot_query_dnssec_requested(knot_packet_query(resp))) { rrset = knot_node_get_rrset(node, KNOT_RRTYPE_DS); if (rrset != NULL) { - knot_response_add_rrset_authority(resp, rrset, 1, 0, - 0, 1); - ns_add_rrsigs(rrset, resp, node->owner, - knot_response_add_rrset_authority, 1); + ret = knot_response_add_rrset_authority(resp, rrset, 1, + 0, 0, 1); + if (ret == KNOT_EOK) { + ret = ns_add_rrsigs(rrset, resp, node->owner, + knot_response_add_rrset_authority, 1); + } } else { // no DS, add NSEC3 or NSEC // if NSEC3 enabled, search for NSEC3 if (knot_zone_contents_nsec3_enabled(zone)) { const knot_node_t *nsec3_node = knot_node_nsec3_node(node); - dbg_ns("There is no DS, putting NSEC3s...\n"); + dbg_ns_detail("There is no DS, putting NSEC3s." + "\n"); if (nsec3_node != NULL) { - dbg_ns("Putting NSEC3s from the node.\n"); - ns_put_nsec3_from_node(nsec3_node, resp); + dbg_ns_detail("Putting NSEC3s from the node.\n"); + ret = ns_put_nsec3_from_node(nsec3_node, + resp); } else { - dbg_ns("Putting Opt-Out NSEC3s.\n"); + dbg_ns_detail("Putting Opt-Out NSEC3s." + "\n"); // no NSEC3 (probably Opt-Out) // TODO: check if the zone is Opt-Out ret = ns_put_nsec3_closest_encloser_proof(zone, @@ -1492,10 +1765,11 @@ static inline int ns_referral(const knot_node_t *node, node, KNOT_RRTYPE_NSEC); if (nsec) { /*! \todo Check return value? */ - knot_response_add_rrset_authority( + ret = knot_response_add_rrset_authority( resp, nsec, 1, 1, 0, 1); - if ((nsec = knot_rrset_get_rrsigs(nsec)) != NULL) { - knot_response_add_rrset_authority( + if (ret == KNOT_EOK && + (nsec = knot_rrset_get_rrsigs(nsec)) != NULL) { + ret = knot_response_add_rrset_authority( resp, nsec, 1, 1, 0, 1); } } @@ -1503,10 +1777,13 @@ static inline int ns_referral(const knot_node_t *node, } } - if (ret == KNOT_EOK) { -// ns_put_additional(resp); + if (ret == KNOT_ESPACE) { + knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); + ret = KNOT_EOK; + } else if (ret == KNOT_EOK) { knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); } + return ret; } @@ -1540,65 +1817,65 @@ static int ns_answer_from_node(const knot_node_t *node, const knot_node_t *previous, const knot_zone_contents_t *zone, const knot_dname_t *qname, uint16_t qtype, - knot_packet_t *resp) + knot_packet_t *resp, int check_any) { - dbg_ns("Putting answers from found node to the response...\n"); - int answers = ns_put_answer(node, qname, qtype, resp); + dbg_ns_verb("Putting answers from found node to the response...\n"); + int answers = 0; + + int ret = ns_put_answer(node, zone, qname, qtype, resp, &answers, + check_any); + if (ret != KNOT_EOK) { + return ret; + } + + assert(ret == KNOT_EOK); - int ret = KNOT_EOK; if (answers == 0) { // if NODATA response, put SOA + ret = ns_put_authority_soa(zone, resp); if (knot_node_rrset_count(node) == 0 && !knot_zone_contents_nsec3_enabled(zone)) { // node is an empty non-terminal => NSEC for NXDOMAIN //assert(knot_node_rrset_count(closest_encloser) > 0); - dbg_ns("Adding NSEC/NSEC3 for NXDOMAIN.\n"); + dbg_ns_verb("Adding NSEC/NSEC3 for NXDOMAIN.\n"); ret = ns_put_nsec_nsec3_nxdomain(zone, knot_node_previous(node), closest_encloser, qname, resp); } else { - dbg_ns("Adding NSEC/NSEC3 for NODATA.\n"); - ns_put_nsec_nsec3_nodata(node, resp); + dbg_ns_verb("Adding NSEC/NSEC3 for NODATA.\n"); + ret = ns_put_nsec_nsec3_nodata(zone, node, resp); + if (ret != KNOT_EOK) { + dbg_ns("Failed adding NSEC/NSEC3 for NODATA: %s" + "\n", knot_strerror(ret)); + return ret; + } + if (knot_dname_is_wildcard(node->owner)) { - dbg_ns("Putting NSEC/NSEC3 for wildcard" - " NODATA\n"); + dbg_ns_verb("Putting NSEC/NSEC3 for wildcard" + " NODATA\n"); ret = ns_put_nsec_nsec3_wildcard_nodata(node, closest_encloser, previous, zone, qname, resp); + if (ret != KNOT_EOK) { + return ret; + } } } - ns_put_authority_soa(zone, resp); } else { // else put authority NS // if wildcard answer, add NSEC / NSEC3 - dbg_ns("Adding NSEC/NSEC3 for wildcard answer.\n"); - -// char *n = knot_dname_to_str(knot_node_owner(node)); -// char *ce = (closest_encloser) -// ? knot_dname_to_str(knot_node_owner(closest_encloser)) -// : "(nil)"; -// char *prev = (previous) -// ? knot_dname_to_str(knot_node_owner(previous)) -// : "(nil)"; -// printf("Node: %s, closest encloser: %s, previous: %s\n", -// n, ce, prev); -// free(n); -// if (closest_encloser) { -// free(ce); -// } -// if (previous) { -// free(prev); -// } + dbg_ns_verb("Adding NSEC/NSEC3 for wildcard answer.\n"); + assert(previous == NULL); assert(closest_encloser == knot_node_parent(node) || !knot_dname_is_wildcard(knot_node_owner(node))); ret = ns_put_nsec_nsec3_wildcard_answer(node, closest_encloser, previous, zone, qname, resp); - ns_put_authority_ns(zone, resp); + + if (ret == KNOT_EOK) { + ret = ns_put_authority_ns(zone, resp); + } } -// if (ret == KNOT_EOK) { -// ns_put_additional(resp); -// } return ret; } @@ -1617,7 +1894,7 @@ static int ns_answer_from_node(const knot_node_t *node, static knot_rrset_t *ns_cname_from_dname(const knot_rrset_t *dname_rrset, const knot_dname_t *qname) { - dbg_ns("Synthetizing CNAME from DNAME...\n"); + dbg_ns_verb("Synthetizing CNAME from DNAME...\n"); // create new CNAME RRSet @@ -1642,15 +1919,25 @@ static knot_rrset_t *ns_cname_from_dname(const knot_rrset_t *dname_rrset, knot_rdata_get_item(knot_rrset_rdata(dname_rrset), 0)->dname); dbg_ns_exec( char *name = knot_dname_to_str(cname); - dbg_ns("CNAME canonical name: %s.\n", name); + dbg_ns_verb("CNAME canonical name: %s.\n", name); free(name); ); knot_rdata_t *cname_rdata = knot_rdata_new(); knot_rdata_item_t cname_rdata_item; cname_rdata_item.dname = cname; - knot_rdata_set_items(cname_rdata, &cname_rdata_item, 1); + int ret = knot_rdata_set_items(cname_rdata, &cname_rdata_item, 1); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&cname_rrset, 1, 1, 1); + knot_rdata_deep_free(&cname_rdata, KNOT_RRTYPE_CNAME, 1); + return NULL; + } - knot_rrset_add_rdata(cname_rrset, cname_rdata); + ret = knot_rrset_add_rdata(cname_rrset, cname_rdata); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&cname_rrset, 1, 1, 1); + knot_rdata_deep_free(&cname_rdata, KNOT_RRTYPE_CNAME, 1); + return NULL; + } return cname_rrset; } @@ -1694,38 +1981,59 @@ static int ns_dname_is_too_long(const knot_rrset_t *dname_rrset, * \param qname Searched name. * \param resp Response. */ -static void ns_process_dname(knot_rrset_t *dname_rrset, - const knot_dname_t *qname, +static int ns_process_dname(knot_rrset_t *dname_rrset, + const knot_dname_t **qname, knot_packet_t *resp) { -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(knot_rrset_owner(dname_rrset)); - dbg_ns("Processing DNAME for owner %s...\n", name); + dbg_ns_verb("Processing DNAME for owner %s...\n", name); free(name); ); // TODO: check the number of RRs in the RRSet?? // put the DNAME RRSet into the answer - knot_response_add_rrset_answer(resp, dname_rrset, 1, 0, 0, 1); - ns_add_rrsigs(dname_rrset, resp, qname, - knot_response_add_rrset_answer, 1); + int ret = knot_response_add_rrset_answer(resp, dname_rrset, 1, 0, 0, 1); + if (ret != KNOT_EOK) { + return ret; + } - if (ns_dname_is_too_long(dname_rrset, qname)) { + ret = ns_add_rrsigs(dname_rrset, resp, *qname, + knot_response_add_rrset_answer, 1); + if (ret != KNOT_EOK) { + return ret; + } + + if (ns_dname_is_too_long(dname_rrset, *qname)) { knot_response_set_rcode(resp, KNOT_RCODE_YXDOMAIN); - return; + return KNOT_EOK; } // synthetize CNAME (no way to tell that client supports DNAME) - knot_rrset_t *synth_cname = ns_cname_from_dname(dname_rrset, qname); + knot_rrset_t *synth_cname = ns_cname_from_dname(dname_rrset, *qname); // add the synthetized RRSet to the Answer - knot_response_add_rrset_answer(resp, synth_cname, 1, 0, 0, 1); + ret = knot_response_add_rrset_answer(resp, synth_cname, 1, 0, 0, 1); + if (ret != KNOT_EOK) { + return ret; + } // no RRSIGs for this RRSet // add the synthetized RRSet into list of temporary RRSets of response - knot_packet_add_tmp_rrset(resp, synth_cname); + ret = knot_packet_add_tmp_rrset(resp, synth_cname); + if (ret != KNOT_EOK) { + return ret; + } + + // get the next SNAME from the CNAME RDATA + const knot_dname_t *cname = knot_rdata_cname_name( + knot_rrset_rdata(synth_cname)); + dbg_ns_verb("CNAME name from RDATA: %p\n", cname); - // do not search for the name in new zone (out-of-bailiwick) + // save the new name which should be used for replacing wildcard + *qname = cname; + + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ @@ -1735,15 +2043,23 @@ dbg_ns_exec( * \param apex Zone apex node. * \param resp Response. */ -static void ns_add_dnskey(const knot_node_t *apex, knot_packet_t *resp) +static int ns_add_dnskey(const knot_node_t *apex, knot_packet_t *resp) { knot_rrset_t *rrset = knot_node_get_rrset(apex, KNOT_RRTYPE_DNSKEY); + + int ret = KNOT_EOK; + if (rrset != NULL) { - knot_response_add_rrset_additional(resp, rrset, 0, 0, 0, 1); - ns_add_rrsigs(rrset, resp, apex->owner, - knot_response_add_rrset_additional, 0); + ret = knot_response_add_rrset_additional(resp, rrset, 0, 0, + 0, 1); + if (ret == KNOT_EOK) { + ret = ns_add_rrsigs(rrset, resp, apex->owner, + knot_response_add_rrset_additional, 0); + } } + + return ret; } /*----------------------------------------------------------------------------*/ @@ -1763,7 +2079,7 @@ static void ns_add_dnskey(const knot_node_t *apex, knot_packet_t *resp) * \todo Describe the answering logic in detail. */ static int ns_answer_from_zone(const knot_zone_contents_t *zone, - knot_packet_t *resp) + knot_packet_t *resp, int check_any) { const knot_node_t *node = NULL, *closest_encloser = NULL, *previous = NULL; @@ -1774,13 +2090,9 @@ static int ns_answer_from_zone(const knot_zone_contents_t *zone, search: #ifdef USE_HASH_TABLE - /*! \todo Check version. */ find_ret = knot_zone_contents_find_dname_hash(zone, qname, &node, &closest_encloser); -// node = knot_node_current(node); -// closest_encloser = knot_node_current(closest_encloser); #else - /*! \todo Check version. */ find_ret = knot_zone_contents_find_dname(zone, qname, &node, &closest_encloser, &previous); node = knot_node_current(node); @@ -1791,33 +2103,33 @@ search: return NS_ERR_SERVFAIL; } -dbg_ns_exec( +dbg_ns_exec_verb( char *name; if (node) { name = knot_dname_to_str(node->owner); - dbg_ns("zone_find_dname() returned node %s \n", name); + dbg_ns_verb("zone_find_dname() returned node %s \n", name); free(name); } else { - dbg_ns("zone_find_dname() returned no node,\n"); + dbg_ns_verb("zone_find_dname() returned no node,\n"); } if (closest_encloser != NULL) { name = knot_dname_to_str(closest_encloser->owner); - dbg_ns(" closest encloser %s.\n", name); + dbg_ns_verb(" closest encloser %s.\n", name); free(name); } else { - dbg_ns(" closest encloser (nil).\n"); + dbg_ns_verb(" closest encloser (nil).\n"); } if (previous != NULL) { name = knot_dname_to_str(previous->owner); - dbg_ns(" and previous node: %s.\n", name); + dbg_ns_verb(" and previous node: %s.\n", name); free(name); } else { - dbg_ns(" and previous node: (nil).\n"); + dbg_ns_verb(" and previous node: (nil).\n"); } ); if (find_ret == KNOT_EBADZONE) { - // possible only if we followed cname + // possible only if we followed CNAME or DNAME assert(cname != 0); knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); auth_soa = 1; @@ -1826,10 +2138,10 @@ dbg_ns_exec( } have_node: - dbg_ns("Closest encloser is deleg. point? %s\n", + dbg_ns_verb("Closest encloser is deleg. point? %s\n", (knot_node_is_deleg_point(closest_encloser)) ? "yes" : "no"); - dbg_ns("Closest encloser is non authoritative? %s\n", + dbg_ns_verb("Closest encloser is non authoritative? %s\n", (knot_node_is_non_auth(closest_encloser)) ? "yes" : "no"); if (knot_node_is_deleg_point(closest_encloser) @@ -1843,21 +2155,31 @@ have_node: knot_rrset_t *dname_rrset = knot_node_get_rrset( closest_encloser, KNOT_RRTYPE_DNAME); if (dname_rrset != NULL) { - ns_process_dname(dname_rrset, qname, resp); - auth_soa = 1; + ret = ns_process_dname(dname_rrset, &qname, resp); + knot_response_set_aa(resp); - goto finalize; + + if (ret != KNOT_EOK) { + goto finalize; + } + + // do not search for the name in new zone + // (out-of-bailiwick), just in the current zone if it + // belongs there + + cname = 1; + goto search; } // else check for a wildcard child const knot_node_t *wildcard_node = knot_node_wildcard_child(closest_encloser); if (wildcard_node == NULL) { - dbg_ns("No wildcard node. (cname: %d)\n", - cname); + dbg_ns_verb("No wildcard node. (cname: %d)\n", + cname); auth_soa = 1; if (cname == 0) { - dbg_ns("Setting NXDOMAIN RCODE.\n"); + dbg_ns_detail("Setting NXDOMAIN RCODE.\n"); // return NXDOMAIN knot_response_set_rcode(resp, KNOT_RCODE_NXDOMAIN); @@ -1884,24 +2206,31 @@ have_node: } if (knot_node_rrset(node, KNOT_RRTYPE_CNAME) != NULL - && qtype != KNOT_RRTYPE_CNAME) { + && qtype != KNOT_RRTYPE_CNAME && qtype != KNOT_RRTYPE_RRSIG) { dbg_ns_exec( char *name = knot_dname_to_str(node->owner); - dbg_ns("Node %s has CNAME record, resolving...\n", - name); + dbg_ns_verb("Node %s has CNAME record, resolving...\n", name); free(name); ); const knot_dname_t *act_name = qname; - ns_follow_cname(&node, &act_name, resp, - knot_response_add_rrset_answer, 1); -dbg_ns_exec( + ret = ns_follow_cname(&node, &act_name, resp, + knot_response_add_rrset_answer, 1); + + /*! \todo IS OK??? */ + knot_response_set_aa(resp); + + if (ret != KNOT_EOK) { + // KNOT_ESPACE case is handled there + goto finalize; + } +dbg_ns_exec_verb( char *name = (node != NULL) ? knot_dname_to_str(node->owner) : "(nil)"; char *name2 = knot_dname_to_str(act_name); - dbg_ns("Canonical name: %s (%p), node found: %p\n", - name2, act_name, node); - dbg_ns("The node's owner: %s (%p)\n", name, (node != NULL) - ? node->owner : NULL); + dbg_ns_verb("Canonical name: %s (%p), node found: %p\n", + name2, act_name, node); + dbg_ns_verb("The node's owner: %s (%p)\n", name, (node != NULL) + ? node->owner : NULL); if (node != NULL) { free(name); } @@ -1913,25 +2242,33 @@ dbg_ns_exec( // otherwise search for the new name if (node == NULL) { goto search; - } else if (node->owner != act_name) { - // the stored node is closest encloser - find_ret = KNOT_ZONE_NAME_NOT_FOUND; - closest_encloser = node; - node = NULL; - goto have_node; - } // else do nothing, just continue + } else if (knot_node_owner(node) != act_name) { + if(knot_dname_is_wildcard(knot_node_owner(node))) { + // we must set the closest encloser to the + // parent of the node, to be right + closest_encloser = knot_node_parent(node); + assert(closest_encloser != NULL); + } else { + // the stored node is closest encloser + find_ret = KNOT_ZONE_NAME_NOT_FOUND; + closest_encloser = node; + node = NULL; + goto have_node; + } + } } ret = ns_answer_from_node(node, closest_encloser, previous, zone, qname, - qtype, resp); + qtype, resp, check_any); if (ret == NS_ERR_SERVFAIL) { // in this case we should drop the response and send an error // for now, just send the error code with a non-complete answer -// knot_response_set_rcode(resp, KNOT_RCODE_SERVFAIL); -// goto finalize; return ret; } else if (ret != KNOT_EOK) { /*! \todo Handle RCODE return values!!! */ + // In case ret == KNOT_ESPACE, this is later converted to EOK + // so it does not cause error response + knot_response_set_aa(resp); goto finalize; } knot_response_set_aa(resp); @@ -1940,16 +2277,21 @@ dbg_ns_exec( // this is the only case when the servers answers from // particular node, i.e. the only case when it may return SOA // or NS records in Answer section - if (DNSSEC_ENABLED + if (knot_packet_tc(resp) == 0 && DNSSEC_ENABLED && knot_query_dnssec_requested(knot_packet_query(resp)) && node == knot_zone_contents_apex(zone) && (qtype == KNOT_RRTYPE_SOA || qtype == KNOT_RRTYPE_NS)) { - ns_add_dnskey(node, resp); + ret = ns_add_dnskey(node, resp); } finalize: - if (ret == KNOT_EOK && auth_soa) { - ns_put_authority_soa(zone, resp); + if (ret == KNOT_EOK && knot_packet_tc(resp) == 0 && auth_soa) { + ret = ns_put_authority_soa(zone, resp); + } + + if (ret == KNOT_ESPACE) { + knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); + ret = KNOT_EOK; } // add all missing NSECs/NSEC3s for wildcard nodes @@ -1976,20 +2318,9 @@ finalize: * \retval KNOT_EOK * \retval NS_ERR_SERVFAIL */ -static int ns_answer(const knot_zone_t *zone, knot_packet_t *resp) -{ -// const knot_dname_t *qname = knot_packet_qname(resp); -// assert(qname != NULL); - -// uint16_t qtype = knot_packet_qtype(resp); -//dbg_ns_exec( -// char *name_str = knot_dname_to_str(qname); -// dbg_ns("Trying to find zone for QNAME %s\n", name_str); -// free(name_str); -//); -// // find zone in which to search for the name -// const knot_zone_t *zone = -// ns_get_zone_for_qname(db, qname, qtype); +static int ns_answer(const knot_zone_t *zone, knot_packet_t *resp, + int check_any) +{ const knot_zone_contents_t *contents = knot_zone_contents(zone); // if no zone found, return REFUSED @@ -2012,9 +2343,7 @@ dbg_ns_exec( // take the zone contents and use only them for answering - return ns_answer_from_zone(contents, resp); - - //knot_dname_free(&qname); + return ns_answer_from_zone(contents, resp, check_any); } /*----------------------------------------------------------------------------*/ @@ -2026,10 +2355,9 @@ int ns_response_to_wire(knot_packet_t *resp, uint8_t *wire, size_t rsize = 0; int ret = 0; - if ((ret = knot_packet_to_wire(resp, &rwire, &rsize)) - != KNOT_EOK) { + if ((ret = knot_packet_to_wire(resp, &rwire, &rsize)) != KNOT_EOK) { dbg_ns("Error converting response packet " - "to wire format (error %d).\n", ret); + "to wire format (error %d).\n", ret); return NS_ERR_SERVFAIL; } @@ -2041,14 +2369,13 @@ int ns_response_to_wire(knot_packet_t *resp, uint8_t *wire, if (rwire != wire) { dbg_ns("Wire format reallocated, copying to place for " - "wire.\n"); + "wire.\n"); memcpy(wire, rwire, rsize); } else { dbg_ns("Using the same space or wire format.\n"); } *wire_size = rsize; - //free(rwire); return KNOT_EOK; } @@ -2073,17 +2400,17 @@ static int ns_error_response_to_wire(knot_packet_t *resp, uint8_t *wire, * wire format is assembled, but COUNTs in header are not set. * This is ideal, we just truncate the packet after the question. */ - dbg_ns("Creating error response.\n"); + dbg_ns_verb("Creating error response.\n"); size_t rsize = knot_packet_question_size(knot_packet_query(resp)); - dbg_ns("Error response (~ query) size: %zu\n", rsize); + dbg_ns_detail("Error response (~ query) size: %zu\n", rsize); // take 'qsize' from the current wireformat of the response // it is already assembled - Header and Question section are copied const uint8_t *rwire = knot_packet_wireformat(resp); if (rsize > *wire_size) { dbg_ns("Reponse size (%zu) larger than allowed wire size" - " (%zu).\n", rsize, *wire_size); + " (%zu).\n", rsize, *wire_size); return NS_ERR_SERVFAIL; } @@ -2116,8 +2443,8 @@ typedef struct ns_axfr_params { int knot_ns_tsig_required(int packet_nr) { - dbg_ns_detail("ns_tsig_required(%d): %d\n", packet_nr, - (packet_nr % KNOT_NS_TSIG_FREQ == 0)); + dbg_ns_verb("ns_tsig_required(%d): %d\n", packet_nr, + (packet_nr % KNOT_NS_TSIG_FREQ == 0)); return (packet_nr % KNOT_NS_TSIG_FREQ == 0); } @@ -2132,7 +2459,7 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) assert(xfr->send != NULL); // Transform the packet into wire format - dbg_ns("Converting response to wire format..\n"); + dbg_ns_verb("Converting response to wire format..\n"); size_t real_size = xfr->wire_size; if (ns_response_to_wire(xfr->response, xfr->wire, &real_size) != 0) { return NS_ERR_SERVFAIL; @@ -2154,15 +2481,14 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) xfr->tsig_data_size += real_size; } - /*! \note [TSIG] Generate TSIG if required (during XFR/IN). */ if (xfr->tsig_key && add_tsig) { if (xfr->packet_nr == 0) { /* Add key, digest and digest length. */ dbg_ns_detail("Calling tsig_sign(): %p, %zu, %zu, " - "%p, %zu, %p, %zu, %p\n", - xfr->wire, real_size, xfr->wire_size, - xfr->digest, xfr->digest_size, xfr->digest, - digest_real_size, xfr->tsig_key); + "%p, %zu, %p, %zu, %p\n", + xfr->wire, real_size, xfr->wire_size, + xfr->digest, xfr->digest_size, xfr->digest, + digest_real_size, xfr->tsig_key); res = knot_tsig_sign(xfr->wire, &real_size, xfr->wire_size, xfr->digest, xfr->digest_size, xfr->digest, @@ -2182,8 +2508,7 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) xfr->tsig_data_size); } - dbg_ns_detail("Sign function returned: %s\n", - knot_strerror(res)); + dbg_ns_verb("Sign function returned: %s\n", knot_strerror(res)); dbg_ns_detail("Real size of digest: %zu\n", digest_real_size); if (res != KNOT_EOK) { @@ -2198,8 +2523,8 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) xfr->tsig_data_size = 0; } else if (xfr->tsig_rcode != 0) { - dbg_ns_detail("Adding TSIG without signing, TSIG RCODE: %d.\n", - xfr->tsig_rcode); + dbg_ns_verb("Adding TSIG without signing, TSIG RCODE: %d.\n", + xfr->tsig_rcode); assert(xfr->tsig_rcode != KNOT_TSIG_RCODE_BADTIME); // add TSIG without signing assert(xfr->query != NULL); @@ -2225,12 +2550,11 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) return res; } else if (res != real_size) { dbg_ns("AXFR did not send right amount of bytes." - " Transfer size: %zu, sent: %d\n", - real_size, res); + " Transfer size: %zu, sent: %d\n", real_size, res); } // Clean the response structure - dbg_ns("Clearing response structure..\n"); + dbg_ns_verb("Clearing response structure..\n"); knot_response_clear(xfr->response, 0); // increment the packet number @@ -2243,8 +2567,10 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) knot_packet_set_tsig_size(xfr->response, 0); } - dbg_ns("Response structure after clearing:\n"); +dbg_ns_exec_verb( + dbg_ns_verb("Response structure after clearing:\n"); knot_packet_dump(xfr->response); +); return KNOT_EOK; } @@ -2260,15 +2586,15 @@ static void ns_axfr_from_node(knot_node_t *node, void *data) if (params->ret != KNOT_EOK) { // just skip (will be called on next node with the same params - dbg_ns("Params contain error: %s, skipping node...\n", + dbg_ns_detail("Params contain error: %s, skipping node...\n", knot_strerror(params->ret)); return; } - dbg_ns("Params OK, answering AXFR from node %p.\n", node); -dbg_ns_exec( + dbg_ns_detail("Params OK, answering AXFR from node %p.\n", node); +dbg_ns_exec_verb( char *name = knot_dname_to_str(knot_node_owner(node)); - dbg_ns("Node ownerr: %s\n", name); + dbg_ns_verb("Node owner: %s\n", name); free(name); ); @@ -2289,8 +2615,8 @@ dbg_ns_exec( assert(rrsets[i] != NULL); rrset = rrsets[i]; rrset: - dbg_ns(" Type: %s\n", - knot_rrtype_to_string(knot_rrset_type(rrset))); + dbg_ns_verb(" Type: %s\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); // do not add SOA if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA) { @@ -2477,9 +2803,7 @@ static int ns_ixfr_put_rrset(knot_ns_xfr_t *xfr, knot_rrset_t *rrset) /*! \todo Probably send back AXFR instead. */ knot_response_set_rcode(xfr->response, KNOT_RCODE_SERVFAIL); - /*! \todo Probably rename the function. */ ns_xfr_send_and_clear(xfr, 1); - //socket_close(xfr->session); /*! \todo Remove for UDP.*/ return res; } @@ -2546,12 +2870,10 @@ static int ns_ixfr_from_zone(knot_ns_xfr_t *xfr) 0, 0, 0); if (res != KNOT_EOK) { dbg_ns("IXFR query cannot be answered: %s.\n", - knot_strerror(res)); + knot_strerror(res)); knot_response_set_rcode(xfr->response, KNOT_RCODE_SERVFAIL); - /*! \todo Probably rename the function. */ ns_xfr_send_and_clear(xfr, 1); -// socket_close(xfr->session); /*! \todo Remove for UDP.*/ rcu_read_unlock(); return res; } @@ -2571,10 +2893,7 @@ static int ns_ixfr_from_zone(knot_ns_xfr_t *xfr) } if (res == KNOT_EOK) { - /*! \todo Probably rename the function. */ ns_xfr_send_and_clear(xfr, 1); - //socket_close(xfr->session); /*! \todo Remove for UDP.*/ -// return 1; } rcu_read_unlock(); @@ -2596,7 +2915,6 @@ static int ns_ixfr(knot_ns_xfr_t *xfr) // malformed packet dbg_ns("IXFR query does not contain authority record.\n"); knot_response_set_rcode(xfr->response, KNOT_RCODE_FORMERR); - /*! \todo Probably rename the function. */ if (ns_xfr_send_and_clear(xfr, 1) == KNOT_ECONN) { return KNOT_ECONN; } @@ -2614,11 +2932,9 @@ static int ns_ixfr(knot_ns_xfr_t *xfr) // malformed packet dbg_ns("IXFR query is malformed.\n"); knot_response_set_rcode(xfr->response, KNOT_RCODE_FORMERR); - /*! \todo Probably rename the function. */ if (ns_xfr_send_and_clear(xfr, 1) == KNOT_ECONN) { return KNOT_ECONN; } - //socket_close(xfr->session); /*! \todo Remove for UDP. */ return KNOT_EMALF; } @@ -2627,8 +2943,7 @@ static int ns_ixfr(knot_ns_xfr_t *xfr) /*----------------------------------------------------------------------------*/ -static int knot_ns_prepare_response(knot_nameserver_t *nameserver, - knot_packet_t *query, knot_packet_t **resp, +static int knot_ns_prepare_response(knot_packet_t *query, knot_packet_t **resp, size_t max_size) { assert(max_size >= 500); @@ -2641,8 +2956,6 @@ static int knot_ns_prepare_response(knot_nameserver_t *nameserver, } int ret = knot_packet_set_max_size(*resp, max_size); - //(*resp)->wireformat = response_wire;; - //(*resp)->max_size = max_size; if (ret != KNOT_EOK) { dbg_ns("Failed to init response structure.\n"); @@ -2827,14 +3140,12 @@ void knot_ns_set_nsid(knot_nameserver_t *nameserver, const char *nsid, size_t le int ret = knot_ns_replace_nsid(nameserver->opt_rr, nsid, len); -// int ret = knot_edns_add_option(nameserver->opt_rr, EDNS_OPTION_NSID, -// len, (const uint8_t *)nsid); if (ret != KNOT_EOK) { dbg_ns("NS: set_nsid: could not add EDNS option.\n"); return; } - dbg_ns("NS: set_nsid: added successfully.\n"); + dbg_ns_verb("NS: set_nsid: added successfully.\n"); } /*----------------------------------------------------------------------------*/ @@ -2847,28 +3158,21 @@ int knot_ns_parse_packet(const uint8_t *query_wire, size_t qsize, return KNOT_EBADARG; } - dbg_ns("ns_parse_packet() called with query size %zu.\n", qsize); - //dbg_ns_hex((char *)query_wire, qsize); - - if (qsize < 2) { - return KNOT_EMALF; - } + dbg_ns_verb("ns_parse_packet() called with query size %zu.\n", qsize); // 1) create empty response - dbg_ns("Parsing packet...\n"); - //parsed = knot_response_new_empty(NULL); + dbg_ns_verb("Parsing packet...\n"); int ret = 0; if ((ret = knot_packet_parse_from_wire(packet, query_wire, qsize, 1)) != 0) { dbg_ns("Error while parsing packet, " - "libknot error '%s'.\n", knot_strerror(ret)); -// knot_response_free(&parsed); + "libknot error '%s'.\n", knot_strerror(ret)); return KNOT_RCODE_FORMERR; } - dbg_ns("Parsed packet header and Question:\n"); + dbg_ns_verb("Parsed packet header and Question:\n"); knot_packet_dump(packet); // 3) determine the query type @@ -2904,17 +3208,15 @@ int knot_ns_parse_packet(const uint8_t *query_wire, size_t qsize, return KNOT_RCODE_NOTIMPL; } -// knot_packet_free(&packet); - return KNOT_EOK; } /*----------------------------------------------------------------------------*/ -void knot_ns_error_response(const knot_nameserver_t *nameserver, - uint16_t query_id, uint8_t *flags1_query, - uint8_t rcode, uint8_t *response_wire, - size_t *rsize) +static void knot_ns_error_response(const knot_nameserver_t *nameserver, + uint16_t query_id, uint8_t *flags1_query, + uint8_t rcode, uint8_t *response_wire, + size_t *rsize) { memcpy(response_wire, nameserver->err_response, nameserver->err_resp_size); @@ -2927,7 +3229,7 @@ void knot_ns_error_response(const knot_nameserver_t *nameserver, knot_wire_set_rd(response_wire); } knot_wire_set_opcode(response_wire, - knot_wire_flags_get_opcode(*flags1_query)); + knot_wire_flags_get_opcode(*flags1_query)); } // set the RCODE @@ -2937,10 +3239,10 @@ void knot_ns_error_response(const knot_nameserver_t *nameserver, /*----------------------------------------------------------------------------*/ -int knot_ns_error_response_from_query(const knot_nameserver_t *nameserver, - const uint8_t *query, size_t size, - uint8_t rcode, uint8_t *response_wire, - size_t *rsize) +int knot_ns_error_response_from_query_wire(const knot_nameserver_t *nameserver, + const uint8_t *query, size_t size, + uint8_t rcode, + uint8_t *response_wire, size_t *rsize) { if (size < 2) { // ignore packet @@ -2964,6 +3266,63 @@ int knot_ns_error_response_from_query(const knot_nameserver_t *nameserver, /*----------------------------------------------------------------------------*/ +int knot_ns_error_response_from_query(const knot_nameserver_t *nameserver, + const knot_packet_t *query, + uint8_t rcode, uint8_t *response_wire, + size_t *rsize) +{ + if (query->parsed < 2) { + // ignore packet + return KNOT_EFEWDATA; + } + + if (query->parsed < KNOT_WIRE_HEADER_SIZE) { + return knot_ns_error_response_from_query_wire(nameserver, + query->wireformat, query->size, rcode, response_wire, + rsize); + } + + size_t max_size = *rsize; + uint8_t flags1 = knot_wire_get_flags1(knot_packet_wireformat(query)); + + // prepare the generic error response + knot_ns_error_response(nameserver, knot_packet_id(query), + &flags1, rcode, response_wire, + rsize); + + if (query->parsed > KNOT_WIRE_HEADER_SIZE + + KNOT_WIRE_QUESTION_MIN_SIZE) { + // in this case the whole question was parsed, append it + size_t question_size = 4 + knot_dname_size( + knot_packet_qname(query)); + + if (max_size > KNOT_WIRE_HEADER_SIZE + question_size) { + /* + * At this point, the wireformat of query may be in the + * same place where the response is assembled. This does + * not matter before this point, although the query + * wireformat is rewritten. Now we just need to copy + * the original Question section. So if the pointers are + * the same, we may just leave it and increase the + * response wire size. Otherwise we must copy the data. + */ + if (response_wire != knot_packet_wireformat(query)) { + memcpy(response_wire + KNOT_WIRE_HEADER_SIZE, + knot_packet_wireformat(query) + + KNOT_WIRE_HEADER_SIZE, question_size); + } + *rsize += question_size; + + // adjust QDCOUNT + knot_wire_set_qdcount(response_wire, 1); + } + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + void knot_ns_error_response_full(knot_nameserver_t *nameserver, knot_packet_t *response, uint8_t rcode, uint8_t *response_wire, size_t *rsize) @@ -2971,11 +3330,10 @@ void knot_ns_error_response_full(knot_nameserver_t *nameserver, knot_response_set_rcode(response, rcode); if (ns_error_response_to_wire(response, response_wire, rsize) != 0) { - knot_ns_error_response(nameserver, knot_packet_id( - knot_packet_query(response)), - &response->header.flags1, - KNOT_RCODE_SERVFAIL, response_wire, - rsize); + knot_ns_error_response_from_query(nameserver, + knot_packet_query(response), + KNOT_RCODE_SERVFAIL, + response_wire, rsize); } } @@ -2985,7 +3343,7 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, knot_packet_t *query, knot_packet_t **resp, const knot_zone_t **zone, size_t max_size) { - dbg_ns("knot_ns_prep_normal_response()\n"); + dbg_ns_verb("knot_ns_prep_normal_response()\n"); if (nameserver == NULL || query == NULL || resp == NULL || zone == NULL) { @@ -2994,8 +3352,8 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, // first, parse the rest of the packet assert(knot_packet_is_query(query)); - dbg_ns("Query - parsed: %zu, total wire size: %zu\n", - knot_packet_parsed(query), knot_packet_size(query)); + dbg_ns_verb("Query - parsed: %zu, total wire size: %zu\n", + knot_packet_parsed(query), knot_packet_size(query)); int ret; ret = knot_packet_parse_rest(query); @@ -3017,10 +3375,38 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, if (knot_packet_ancount(query) > 0 || knot_packet_nscount(query) > 0 || knot_packet_qdcount(query) != 1) { - dbg_ns("ANCOUNT or NSCOUNT not 0 in query, reply FORMERR.\n"); + dbg_ns("ANCOUNT or NSCOUNT not 0 in query, " + "or QDCOUNT != 1. Reply FORMERR.\n"); return KNOT_EMALF; } + /* + * Check what is in the Additional section. Only OPT and TSIG are + * allowed. TSIG must be the last record if present. + */ + if (knot_packet_arcount(query) > 0) { + int ok = 0; + const knot_rrset_t *add1 = + knot_packet_additional_rrset(query, 0); + if (knot_packet_additional_rrset_count(query) == 1 + && (knot_rrset_type(add1) == KNOT_RRTYPE_OPT + || knot_rrset_type(add1) == KNOT_RRTYPE_TSIG)) { + ok = 1; + } else if (knot_packet_additional_rrset_count(query) == 2) { + const knot_rrset_t *add2 = + knot_packet_additional_rrset(query, 1); + if (knot_rrset_type(add1) == KNOT_RRTYPE_OPT + && knot_rrset_type(add2) == KNOT_RRTYPE_TSIG) { + ok = 1; + } + } + + if (!ok) { + dbg_ns("Additional section malformed. Reply FORMERR\n"); + return KNOT_EMALF; + } + } + size_t resp_max_size = 0; knot_packet_dump(query); @@ -3044,22 +3430,21 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, resp_max_size = MAX_UDP_PAYLOAD; } - ret = knot_ns_prepare_response(nameserver, query, resp, - resp_max_size); + ret = knot_ns_prepare_response(query, resp, resp_max_size); if (ret != KNOT_EOK) { return KNOT_ERROR; } - dbg_ns("Query - parsed: %zu, total wire size: %zu\n", - query->parsed, query->size); - dbg_ns("Opt RR: version: %d, payload: %d\n", + dbg_ns_verb("Query - parsed: %zu, total wire size: %zu\n", + query->parsed, query->size); + dbg_ns_detail("Opt RR: version: %d, payload: %d\n", query->opt_rr.version, query->opt_rr.payload); // get the answer for the query knot_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db); - dbg_ns("EDNS supported in query: %d\n", - knot_query_edns_supported(query)); + dbg_ns_detail("EDNS supported in query: %d\n", + knot_query_edns_supported(query)); // set the OPT RR to the response if (knot_query_edns_supported(query)) { @@ -3067,25 +3452,24 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, knot_query_nsid_requested(query)); if (ret != KNOT_EOK) { dbg_ns("Failed to set OPT RR to the response" - ": %s\n", knot_strerror(ret)); + ": %s\n", knot_strerror(ret)); } else { // copy the DO bit from the query if (knot_query_dnssec_requested(query)) { - /*! \todo API for this. */ knot_edns_set_do(&(*resp)->opt_rr); } } } - dbg_ns("Response max size: %zu\n", (*resp)->max_size); + dbg_ns_verb("Response max size: %zu\n", (*resp)->max_size); const knot_dname_t *qname = knot_packet_qname(*resp); assert(qname != NULL); uint16_t qtype = knot_packet_qtype(*resp); -dbg_ns_exec( +dbg_ns_exec_verb( char *name_str = knot_dname_to_str(qname); - dbg_ns("Trying to find zone for QNAME %s\n", name_str); + dbg_ns_verb("Trying to find zone for QNAME %s\n", name_str); free(name_str); ); // find zone in which to search for the name @@ -3098,11 +3482,11 @@ dbg_ns_exec( int knot_ns_answer_normal(knot_nameserver_t *nameserver, const knot_zone_t *zone, knot_packet_t *resp, - uint8_t *response_wire, size_t *rsize) + uint8_t *response_wire, size_t *rsize, int check_any) { - dbg_ns("ns_answer_normal()\n"); + dbg_ns_verb("ns_answer_normal()\n"); - int ret = ns_answer(zone, resp); + int ret = ns_answer(zone, resp, check_any); if (ret != 0) { // now only one type of error (SERVFAIL), later maybe more @@ -3110,7 +3494,7 @@ int knot_ns_answer_normal(knot_nameserver_t *nameserver, KNOT_RCODE_SERVFAIL, response_wire, rsize); } else { - dbg_ns("Created response packet.\n"); + dbg_ns_verb("Created response packet.\n"); //knot_response_dump(resp); knot_packet_dump(resp); @@ -3123,6 +3507,55 @@ int knot_ns_answer_normal(knot_nameserver_t *nameserver, } } + dbg_ns_verb("Returning response with wire size %zu\n", *rsize); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ns_answer_ixfr_udp(knot_nameserver_t *nameserver, + const knot_zone_t *zone, knot_packet_t *resp, + uint8_t *response_wire, size_t *rsize) +{ + dbg_ns("ns_answer_ixfr_udp()\n"); + + const knot_zone_contents_t *contents = knot_zone_contents(zone); + + // if no zone found, return REFUSED + if (zone == NULL) { + dbg_ns("No zone found.\n"); + knot_response_set_rcode(resp, KNOT_RCODE_REFUSED); + return KNOT_EOK; + } else if (contents == NULL) { + dbg_ns("Zone expired or not bootstrapped. Reply SERVFAIL.\n"); + knot_response_set_rcode(resp, KNOT_RCODE_SERVFAIL); + return KNOT_EOK; + } + + const knot_node_t *apex = knot_zone_contents_apex(contents); + assert(apex != NULL); + knot_rrset_t *soa = knot_node_get_rrset(apex, KNOT_RRTYPE_SOA); + + // just put the SOA to the Answer section of the response and send back + int ret = knot_response_add_rrset_answer(resp, soa, 1, 0, 0, 0); + if (ret != KNOT_EOK) { + knot_ns_error_response_full(nameserver, resp, + KNOT_RCODE_SERVFAIL, + response_wire, rsize); + } + + dbg_ns("Created response packet.\n"); + knot_packet_dump(resp); + + // Transform the packet into wire format + if (ns_response_to_wire(resp, response_wire, rsize) != 0) { + // send back SERVFAIL (as this is our problem) + knot_ns_error_response_full(nameserver, resp, + KNOT_RCODE_SERVFAIL, + response_wire, rsize); + } + dbg_ns("Returning response with wire size %zu\n", *rsize); return KNOT_EOK; @@ -3134,18 +3567,21 @@ int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) { dbg_ns("knot_ns_init_xfr()\n"); + int ret = 0; + if (nameserver == NULL || xfr == NULL) { - return KNOT_EBADARG; + dbg_ns("Wrong parameters given to function ns_init_xfr()\n"); + /* Sending error was totally wrong. If nameserver or xfr were + * NULL, the ns_error_response() function would crash. + */ + return ret; } - // no need to parse rest of the packet - /*! \todo Parse rest of packet because of EDNS. */ - int ret = knot_packet_parse_rest(xfr->query); + ret = knot_packet_parse_rest(xfr->query); if (ret != KNOT_EOK) { dbg_ns("Failed to parse rest of the query: %s\n", knot_strerror(ret)); - knot_ns_error_response(nameserver, xfr->query->header.id, - &xfr->query->header.flags1, + knot_ns_error_response_from_query(nameserver, xfr->query, (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR : KNOT_RCODE_SERVFAIL, xfr->wire, &xfr->wire_size); @@ -3154,8 +3590,10 @@ int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) return ret; } - dbg_packet("Parsed XFR query:\n"); +dbg_ns_exec_verb( + dbg_ns_verb("Parsed XFR query:\n"); knot_packet_dump(xfr->query); +); // initialize response packet structure knot_packet_t *response = knot_packet_new( @@ -3163,41 +3601,25 @@ int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) if (response == NULL) { dbg_ns("Failed to create packet structure.\n"); /*! \todo xfr->wire is not NULL, will fail on assert! */ - knot_ns_error_response(nameserver, xfr->query->header.id, - &xfr->query->header.flags1, - KNOT_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + knot_ns_error_response_from_query(nameserver, xfr->query, + KNOT_RCODE_SERVFAIL, + xfr->wire, &xfr->wire_size); ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, xfr->wire_size); - knot_packet_free(&response); return ret; } - //int ret = knot_packet_set_max_size(response, xfr->wire_size); response->wireformat = xfr->wire; response->max_size = xfr->wire_size; -// if (ret != KNOT_EOK) { -// dbg_ns("Failed to init response structure.\n"); -// /*! \todo xfr->wire is not NULL, will fail on assert! */ -// knot_ns_error_response(nameserver, xfr->query->header.id, -// KNOT_RCODE_SERVFAIL, xfr->wire, -// &xfr->wire_size); -// int res = xfr->send(xfr->session, &xfr->addr, xfr->wire, -// xfr->wire_size); -// knot_packet_free(&response); -// return res; -// } - ret = knot_response_init_from_query(response, xfr->query); if (ret != KNOT_EOK) { dbg_ns("Failed to init response structure.\n"); /*! \todo xfr->wire is not NULL, will fail on assert! */ - knot_ns_error_response(nameserver, xfr->query->header.id, - &xfr->query->header.flags1, - KNOT_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + knot_ns_error_response_from_query(nameserver, xfr->query, + KNOT_RCODE_SERVFAIL, + xfr->wire, &xfr->wire_size); int res = xfr->send(xfr->session, &xfr->addr, xfr->wire, xfr->wire_size); knot_packet_free(&response); @@ -3213,9 +3635,9 @@ int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) assert(knot_packet_qtype(xfr->response) == KNOT_RRTYPE_AXFR || knot_packet_qtype(xfr->response) == KNOT_RRTYPE_IXFR); -dbg_ns_exec( +dbg_ns_exec_verb( char *name_str = knot_dname_to_str(qname); - dbg_ns("Trying to find zone with name %s\n", name_str); + dbg_ns_verb("Trying to find zone with name %s\n", name_str); free(name_str); ); // find zone in which to search for the name @@ -3258,20 +3680,20 @@ int ns_ixfr_load_serials(const knot_ns_xfr_t *xfr, uint32_t *serial_from, { if (xfr == NULL || xfr->zone == NULL || serial_from == NULL || serial_to == NULL) { - dbg_ns_detail("Wrong parameters: xfr=%p," - " xfr->zone = %p\n", xfr, xfr->zone); + dbg_ns("Wrong parameters: xfr=%p," + " xfr->zone = %p\n", xfr, xfr->zone); return KNOT_EBADARG; } const knot_zone_t *zone = xfr->zone; const knot_zone_contents_t *contents = knot_zone_contents(zone); if (!contents) { - dbg_ns_detail("Missing contents\n"); + dbg_ns("Missing contents\n"); return KNOT_EBADARG; } if (knot_zone_contents_apex(contents) == NULL) { - dbg_ns_detail("No apex.\n"); + dbg_ns("No apex.\n"); return KNOT_EBADARG; } @@ -3279,17 +3701,17 @@ int ns_ixfr_load_serials(const knot_ns_xfr_t *xfr, uint32_t *serial_from, knot_node_rrset(knot_zone_contents_apex(contents), KNOT_RRTYPE_SOA); if (zone_soa == NULL) { - dbg_ns_verb("No SOA.\n"); + dbg_ns("No SOA.\n"); return KNOT_EBADARG; } if (knot_packet_nscount(xfr->query) < 1) { - dbg_ns_verb("No Authority record.\n"); + dbg_ns("No Authority record.\n"); return KNOT_EMALF; } if (knot_packet_authority_rrset(xfr->query, 0) == NULL) { - dbg_ns_verb("Authority record missing.\n"); + dbg_ns("Authority record missing.\n"); return KNOT_ERROR; } @@ -3309,13 +3731,13 @@ int knot_ns_xfr_send_error(const knot_nameserver_t *nameserver, /*! \todo Handle TSIG errors differently. */ knot_response_set_rcode(xfr->response, rcode); - /*! \todo Probably rename the function. */ int ret = 0; - if ((ret = ns_xfr_send_and_clear(xfr, 1)) != KNOT_EOK) { + if ((ret = ns_xfr_send_and_clear(xfr, 1)) != KNOT_EOK + || xfr->response == NULL) { size_t size = 0; - knot_ns_error_response(nameserver, xfr->query->header.id, - &xfr->query->header.flags1, - KNOT_RCODE_SERVFAIL, xfr->wire, &size); + knot_ns_error_response_from_query(nameserver, xfr->query, + KNOT_RCODE_SERVFAIL, + xfr->wire, &size); ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, size); } @@ -3337,11 +3759,7 @@ int knot_ns_answer_axfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) knot_zone_contents_t *contents = knot_zone_get_contents(xfr->zone); if (!contents) { dbg_ns("AXFR failed on stub zone\n"); - /*! \todo replace with knot_ns_xfr_send_error() */ - knot_ns_error_response(nameserver, xfr->query->header.id, - &xfr->query->header.flags1, - KNOT_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_SERVFAIL); ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, xfr->wire_size); rcu_read_unlock(); @@ -3349,16 +3767,16 @@ int knot_ns_answer_axfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) return ret; } - /*! - * \todo [TSIG] The TSIG data should already be stored in 'xfr'. - * Now just count the expected size of the TSIG RR and save it - * to the response structure. + /* + * The TSIG data should already be stored in 'xfr'. + * Now just count the expected size of the TSIG RR and save it + * to the response structure. */ /*! \todo [TSIG] Get the TSIG size from some API function. */ if (xfr->tsig_size > 0) { - dbg_ns_detail("Setting TSIG size in packet: %zu\n", - xfr->tsig_size); + dbg_ns_verb("Setting TSIG size in packet: %zu\n", + xfr->tsig_size); knot_packet_set_tsig_size(xfr->response, xfr->tsig_size); } @@ -3372,11 +3790,7 @@ int knot_ns_answer_axfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) dbg_ns("AXFR failed, sending SERVFAIL.\n"); // now only one type of error (SERVFAIL), later maybe more /*! \todo xfr->wire is not NULL, will fail on assert! */ - /*! \todo replace with knot_ns_xfr_send_error() */ - knot_ns_error_response(nameserver, xfr->query->header.id, - &xfr->query->header.flags1, - KNOT_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_SERVFAIL); ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, xfr->wire_size); } else if (ret > 0) { @@ -3398,14 +3812,12 @@ int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) || xfr->response == NULL) { return KNOT_EBADARG; } - - //uint8_t *wire = NULL; - //size_t size = xfr->wire_size; // parse rest of the packet (we need the Authority record) int ret = knot_packet_parse_rest(xfr->query); if (ret != KNOT_EOK) { - dbg_ns("Failed to parse rest of the packet. Reply FORMERR.\n"); + dbg_ns("Failed to parse rest of the packet: %s. " + "Reply FORMERR.\n", knot_strerror(ret)); knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_FORMERR); knot_packet_free(&xfr->response); return ret; @@ -3419,11 +3831,11 @@ int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) return ret; } - /*! - * \todo [TSIG] The TSIG data should already be stored in 'xfr'. - * Now just count the expected size of the TSIG RR and save it - * to the response structure. This should be optional, only if - * the request contained TSIG, i.e. if there is the data in 'xfr'. + /* + * The TSIG data should already be stored in 'xfr'. + * Now just count the expected size of the TSIG RR and save it + * to the response structure. This should be optional, only if + * the request contained TSIG, i.e. if there is the data in 'xfr'. */ /*! \todo [TSIG] Get the TSIG size from some API function. */ @@ -3433,16 +3845,6 @@ int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) ret = ns_ixfr(xfr); -// /*! \todo Somehow distinguish when it makes sense to send the SERVFAIL -// * and when it does not. E.g. if there was problem in sending -// * packet, it will probably fail when sending the SERVFAIL also. -// */ -// if (ret < 0) { -// dbg_ns("IXFR failed, sending SERVFAIL.\n"); -// // now only one type of error (SERVFAIL), later maybe more -// knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_SERVFAIL); -// } - knot_packet_free(&xfr->response); return ret; @@ -3452,18 +3854,16 @@ int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) { - /*! - * \todo [TSIG] Here we assume that 'xfr' contains TSIG information - * and the digest of the query sent to the master or the previous - * digest. + /* + * Here we assume that 'xfr' contains TSIG information + * and the digest of the query sent to the master or the previous + * digest. */ dbg_ns("ns_process_axfrin: incoming packet, wire size: %zu\n", - xfr->wire_size); + xfr->wire_size); - int ret = xfrin_process_axfr_packet(/*xfr->wire, xfr->wire_size,*/ - /*(xfrin_constructed_zone_t **)(&xfr->data)*/ - xfr); + int ret = xfrin_process_axfr_packet(xfr); if (ret > 0) { // transfer finished dbg_ns("ns_process_axfrin: AXFR finished, zone created.\n"); @@ -3477,19 +3877,19 @@ int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) assert(zone != NULL); /* Create and fill hash table */ - dbg_ns("ns_process_axfrin: filling hash table.\n"); + dbg_ns_verb("ns_process_axfrin: filling hash table.\n"); int rc = knot_zone_contents_create_and_fill_hash_table(zone); if (rc != KNOT_EOK) { return KNOT_ERROR; // TODO: change error code } - dbg_ns("ns_process_axfrin: adjusting zone.\n"); + dbg_ns_verb("ns_process_axfrin: adjusting zone.\n"); rc = knot_zone_contents_adjust(zone); if (rc != KNOT_EOK) { return rc; } - dbg_ns("ns_process_axfrin: checking loops.\n"); + dbg_ns_verb("ns_process_axfrin: checking loops.\n"); rc = knot_zone_contents_check_loops(zone); if (rc != KNOT_EOK) { return rc; @@ -3508,15 +3908,13 @@ int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) //knot_zone_contents_dump(zone, 0); // check zone integrity -dbg_xfrin_exec( +dbg_ns_exec_verb( int errs = knot_zone_contents_integrity_check(zone); - dbg_xfrin("Zone integrity check: %d errors.\n", errs); + dbg_ns_verb("Zone integrity check: %d errors.\n", errs); ); } - /*! - * \todo In case of error, shouldn't the zone be destroyed here? - */ + /*! \todo In case of error, shouldn't the zone be destroyed here? */ return ret; } @@ -3538,14 +3936,14 @@ int knot_ns_switch_zone(knot_nameserver_t *nameserver, return KNOT_ENOZONE; } - // find the zone in the zone db - knot_zone_t *z = knot_zonedb_find_zone(nameserver->zone_db, - knot_node_owner(knot_zone_contents_apex(zone))); + /* Zone must not be looked-up from server, as it may be a different zone if + * a reload occurs when transfer is pending. */ + knot_zone_t *z = xfr->zone; if (z == NULL) { char *name = knot_dname_to_str(knot_node_owner( knot_zone_contents_apex(zone))); dbg_ns("Failed to replace zone %s, old zone " - "not found\n", name); + "not found\n", name); free(name); return KNOT_ENOZONE; @@ -3555,16 +3953,18 @@ int knot_ns_switch_zone(knot_nameserver_t *nameserver, int ret = xfrin_switch_zone(z, zone, xfr->type); -dbg_ns_exec( - dbg_ns("Zone db contents: (zone count: %zu)\n", - nameserver->zone_db->zone_count); +dbg_ns_exec_verb( + dbg_ns_verb("Zone db contents: (zone count: %zu)\n", + nameserver->zone_db->zone_count); + /* Warning: may not show updated zone if updated zone that is already + * discarded from zone db (reload with pending transfer). */ const knot_zone_t **zones = knot_zonedb_zones(nameserver->zone_db); for (int i = 0; i < knot_zonedb_zone_count (nameserver->zone_db); i++) { - dbg_ns("%d. zone: %p", i, zones[i]); + dbg_ns_verb("%d. zone: %p\n", i, zones[i]); char *name = knot_dname_to_str(zones[i]->name); - dbg_ns(" zone name: %s\n", name); + dbg_ns_verb(" zone name: %s\n", name); free(name); } free(zones); @@ -3574,18 +3974,16 @@ dbg_ns_exec( } /*----------------------------------------------------------------------------*/ -/*! \todo In this function, xfr->zone is properly set. If this is so, we do not - * have to search for the zone after the transfer has finished. - */ + int knot_ns_process_ixfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) { dbg_ns("ns_process_ixfrin: incoming packet\n"); - /*! - * \todo [TSIG] Here we assume that 'xfr' contains TSIG information - * and the digest of the query sent to the master or the previous - * digest. + /* + * [TSIG] Here we assume that 'xfr' contains TSIG information + * and the digest of the query sent to the master or the previous + * digest. */ int ret = xfrin_process_ixfr_packet(xfr); @@ -3608,19 +4006,18 @@ int knot_ns_process_ixfrin(knot_nameserver_t *nameserver, } // find zone associated with the changesets - knot_zone_t *zone = knot_zonedb_find_zone( - nameserver->zone_db, - knot_rrset_owner(chgsets->first_soa)); + /* Must not search for the zone in zonedb as it may fetch a + * different zone than the one the transfer started on. */ + knot_zone_t *zone = xfr->zone; if (zone == NULL) { dbg_ns("No zone found for incoming IXFR!\n"); knot_free_changesets( (knot_changesets_t **)(&xfr->data)); - return KNOT_ENOZONE; /*! \todo Other error code? */ + return KNOT_ENOZONE; } switch (ret) { case XFRIN_RES_COMPLETE: - xfr->zone = zone; break; case XFRIN_RES_SOA_ONLY: { // compare the SERIAL from the changeset with the zone's @@ -3666,9 +4063,7 @@ int knot_ns_process_ixfrin(knot_nameserver_t *nameserver, } } - /*! - * \todo In case of error, shouldn't the zone be destroyed here? - */ + /*! \todo In case of error, shouldn't the zone be destroyed here? */ return ret; } @@ -3684,26 +4079,24 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, knot_packet_t *response; assert(*rsize >= MAX_UDP_PAYLOAD); - int ret = knot_ns_prepare_response(nameserver, query, &response, - MAX_UDP_PAYLOAD); + int ret = knot_ns_prepare_response(query, &response, MAX_UDP_PAYLOAD); if (ret != KNOT_EOK) { - knot_ns_error_response(nameserver, knot_packet_id(query), - &query->header.flags1, - KNOT_RCODE_SERVFAIL, response_wire, - rsize); + knot_ns_error_response_from_query(nameserver, query, + KNOT_RCODE_SERVFAIL, + response_wire, rsize); return KNOT_EOK; } assert(response != NULL); - dbg_ns("Query - parsed: %zu, total wire size: %zu\n", - query->parsed, query->size); + dbg_ns_verb("Query - parsed: %zu, total wire size: %zu\n", + query->parsed, query->size); if (knot_packet_parsed(query) < knot_packet_size(query)) { ret = knot_packet_parse_rest(query); if (ret != KNOT_EOK) { dbg_ns("Failed to parse rest of the query: " - "%s.\n", knot_strerror(ret)); + "%s.\n", knot_strerror(ret)); knot_ns_error_response_full(nameserver, response, (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR @@ -3714,17 +4107,16 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, } } - dbg_ns("Query - parsed: %zu, total wire size: %zu\n", - knot_packet_parsed(query), knot_packet_size(query)); + dbg_ns_verb("Query - parsed: %zu, total wire size: %zu\n", + knot_packet_parsed(query), knot_packet_size(query)); /*! \todo API for EDNS values. */ - dbg_ns("Opt RR: version: %d, payload: %d\n", - query->opt_rr.version, query->opt_rr.payload); + dbg_ns_verb("Opt RR: version: %d, payload: %d\n", + query->opt_rr.version, query->opt_rr.payload); // 2) Find zone for the query // we do not check if there is only one entry in the Question section // because the packet structure does not allow it - /*! \todo Check number of Question entries while parsing. */ if (knot_packet_qtype(query) != KNOT_RRTYPE_SOA) { dbg_ns("Question is not of type SOA.\n"); knot_ns_error_response_full(nameserver, response, @@ -3754,7 +4146,7 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, return KNOT_EBADZONE; } else if (ret != KNOT_EOK) { dbg_ns("Failed to check zone for update: " - "%s.\n", knot_strerror(ret)); + "%s.\n", knot_strerror(ret)); knot_ns_error_response_full(nameserver, response, rcode, response_wire, rsize); knot_packet_free(&response); @@ -3766,7 +4158,7 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, ret = knot_ddns_process_prereqs(query, &prereqs, &rcode); if (ret != KNOT_EOK) { dbg_ns("Failed to check zone for update: " - "%s.\n", knot_strerror(ret)); + "%s.\n", knot_strerror(ret)); knot_ns_error_response_full(nameserver, response, rcode, response_wire, rsize); knot_packet_free(&response); @@ -3783,7 +4175,7 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, &rcode); if (ret != KNOT_EOK) { dbg_ns("Failed to check zone for update: " - "%s.\n", knot_strerror(ret)); + "%s.\n", knot_strerror(ret)); knot_ns_error_response_full(nameserver, response, rcode, response_wire, rsize); knot_ddns_prereqs_free(&prereqs); @@ -3795,7 +4187,7 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, ret = knot_ddns_process_update(query, changeset, &rcode); if (ret != KNOT_EOK) { dbg_ns("Failed to check zone for update: " - "%s.\n", knot_strerror(ret)); + "%s.\n", knot_strerror(ret)); knot_ns_error_response_full(nameserver, response, rcode, response_wire, rsize); knot_ddns_prereqs_free(&prereqs); diff --git a/src/libknot/nameserver/name-server.h b/src/libknot/nameserver/name-server.h index da19f49..3fe1210 100644..100755 --- a/src/libknot/nameserver/name-server.h +++ b/src/libknot/nameserver/name-server.h @@ -115,8 +115,6 @@ typedef struct knot_ns_xfr { */ uint8_t *tsig_data; size_t tsig_data_size; /*!< Size of the message(s) in bytes */ -// const knot_rrset_t *tsig; /*!< Response TSIG. -// \todo [TSIG] Replace with separate data. */ size_t tsig_size; /*!< Size of the TSIG RR wireformat in bytes.*/ knot_key_t *tsig_key; /*!< Associated TSIG key for signing. */ @@ -127,13 +125,6 @@ typedef struct knot_ns_xfr { uint16_t tsig_rcode; uint64_t tsig_prev_time_signed; - /*! \brief Previous digest or request digest. - * - * Should be allocated before the transfer (known size). - */ -// uint8_t *prev_digest; -// size_t prev_digest_size; /*!< Size of previous digest in bytes. */ - /*! * \brief Number of the packet currently assembled. * @@ -154,7 +145,7 @@ static const size_t KNOT_NS_TSIG_DATA_MAX_SIZE = 100 * 64 * 1024; enum knot_ns_xfr_flag_t { XFR_FLAG_TCP = 1 << 0, /*!< XFR request is on TCP. */ XFR_FLAG_UDP = 1 << 1, /*!< XFR request is on UDP. */ - XFR_FLAG_AXFR_FINISHED = 1 << 2 + XFR_FLAG_AXFR_FINISHED = 1 << 2 /*!< Transfer is finished. */ }; typedef enum knot_ns_transport { @@ -218,26 +209,13 @@ void knot_ns_set_nsid(knot_nameserver_t *nameserver, const char *nsid, int knot_ns_parse_packet(const uint8_t *query_wire, size_t qsize, knot_packet_t *packet, knot_packet_type_t *type); -/*! - * \brief Prepares wire format of an error response using generic error template - * stored in the nameserver structure. - * - * The error response will not contain the Question section from the query, just - * a header with ID copied from the query and the given RCODE. - * - * \param nameserver Nameserver structure containing the error template. - * \param query_id ID of the query. - * \param rcode RCODE to set in the response. - * \param response_wire Place for wire format of the response. - * \param rsize Size of the error response will be stored here. - */ -void knot_ns_error_response(const knot_nameserver_t *nameserver, - uint16_t query_id, uint8_t *flags1_query, - uint8_t rcode, uint8_t *response_wire, - size_t *rsize); +int knot_ns_error_response_from_query_wire(const knot_nameserver_t *nameserver, + const uint8_t *query, size_t size, + uint8_t rcode, uint8_t *response_wire, + size_t *rsize); int knot_ns_error_response_from_query(const knot_nameserver_t *nameserver, - const uint8_t *query, size_t size, + const knot_packet_t *query, uint8_t rcode, uint8_t *response_wire, size_t *rsize); @@ -264,7 +242,11 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, */ int knot_ns_answer_normal(knot_nameserver_t *nameserver, const knot_zone_t *zone, knot_packet_t *resp, - uint8_t *response_wire, size_t *rsize); + uint8_t *response_wire, size_t *rsize, int check_any); + +int knot_ns_answer_ixfr_udp(knot_nameserver_t *nameserver, + const knot_zone_t *zone, knot_packet_t *resp, + uint8_t *response_wire, size_t *rsize); int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr); @@ -322,11 +304,11 @@ int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr); * \param nameserver Name server structure to provide the data for answering. * \param xfr Persistent transfer-specific data. * - * \todo Document me. */ int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr); +/*! \todo Document me. */ int knot_ns_switch_zone(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr); diff --git a/src/libknot/nsec3.c b/src/libknot/nsec3.c index 1414e7e..9cab4be 100644..100755 --- a/src/libknot/nsec3.c +++ b/src/libknot/nsec3.c @@ -74,7 +74,7 @@ int knot_nsec3_params_from_wire(knot_nsec3_params_t *params, dbg_nsec3("Flags: %hu\n", params->flags); dbg_nsec3("Iterations: %hu\n", params->iterations); dbg_nsec3("Salt length: %hu\n", params->salt_length); - dbg_nsec3("Salt: "); + dbg_nsec3("Salt: \n"); if (params->salt != NULL) { dbg_nsec3_hex((char *)params->salt, params->salt_length); @@ -171,8 +171,8 @@ int knot_nsec3_sha1(const knot_nsec3_params_t *params, EVP_MD_CTX_cleanup(&mdctx); - dbg_nsec3("NSEC3 hashing: calls: %lu, avg time per call: %f." - "\n", calls, (double)(total_time) / calls); + dbg_nsec3_verb("NSEC3 hashing: calls: %lu, avg time per call: %f." + "\n", calls, (double)(total_time) / calls); free(data_low); return 0; @@ -194,17 +194,17 @@ int knot_nsec3_sha1(const knot_nsec3_params_t *params, uint8_t salt_length = params->salt_length; uint16_t iterations = params->iterations; - dbg_nsec3("Hashing: \n"); - dbg_nsec3(" Data: %.*s \n", size, data); - dbg_nsec3_hex((const char *)data, size); - dbg_nsec3(" (size %d)\n Iterations: %u\n", (int)size, iterations); - dbg_nsec3(" Salt length: %u\n", salt_length); - dbg_nsec3(" Salt: "); + dbg_nsec3_verb("Hashing: \n"); + dbg_nsec3_verb(" Data: %.*s \n", size, data); + dbg_nsec3_hex_verb((const char *)data, size); + dbg_nsec3_verb(" (size %d)\n Iterations: %u\n", (int)size, iterations); + dbg_nsec3_verb(" Salt length: %u\n", salt_length); + dbg_nsec3_verb(" Salt: \n"); if (salt_length > 0) { - dbg_nsec3_hex((char *)salt, salt_length); - dbg_nsec3("\n"); + dbg_nsec3_hex_verb((char *)salt, salt_length); + dbg_nsec3_verb("\n"); } else { - dbg_nsec3("none\n"); + dbg_nsec3_verb("none\n"); } SHA_CTX ctx; @@ -251,9 +251,9 @@ int knot_nsec3_sha1(const knot_nsec3_params_t *params, *digest_size = SHA_DIGEST_LENGTH; - dbg_nsec3("Hash: %.*s\n", *digest_size, *digest); - dbg_nsec3_hex((const char *)*digest, *digest_size); - dbg_nsec3("\n"); + dbg_nsec3_verb("Hash: %.*s\n", *digest_size, *digest); + dbg_nsec3_hex_verb((const char *)*digest, *digest_size); + dbg_nsec3_verb("\n"); free(data_low); return KNOT_EOK; diff --git a/src/libknot/nsec3.h b/src/libknot/nsec3.h index 0ce6899..0ce6899 100644..100755 --- a/src/libknot/nsec3.h +++ b/src/libknot/nsec3.h diff --git a/src/libknot/packet/packet.c b/src/libknot/packet/packet.c index 82b65c6..6c7fd02 100644..100755 --- a/src/libknot/packet/packet.c +++ b/src/libknot/packet/packet.c @@ -22,6 +22,7 @@ #include "common.h" #include "util/descriptor.h" #include "util/wire.h" +#include "tsig.h" /*----------------------------------------------------------------------------*/ @@ -51,7 +52,7 @@ typedef enum { */ static void knot_packet_init_pointers_response(knot_packet_t *pkt) { - dbg_packet("Packet pointer: %p\n", pkt); + dbg_packet_detail("Packet pointer: %p\n", pkt); char *pos = (char *)pkt + PREALLOC_PACKET; @@ -59,7 +60,7 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) pkt->question.qname = (knot_dname_t *)pos; pos += PREALLOC_QNAME_DNAME; - dbg_packet("QNAME: %p\n", pkt->question.qname); + dbg_packet_detail("QNAME: %p\n", pkt->question.qname); pkt->question.qname->name = (uint8_t *)pos; pos += PREALLOC_QNAME_NAME; @@ -67,7 +68,7 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) pos += PREALLOC_QNAME_LABELS; pkt->owner_tmp = (uint8_t *)pos; - dbg_packet("Tmp owner: %p\n", pkt->owner_tmp); + dbg_packet_detail("Tmp owner: %p\n", pkt->owner_tmp); pos += PREALLOC_RR_OWNER; // then answer, authority and additional sections @@ -92,9 +93,9 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) pos += DEFAULT_ARCOUNT * sizeof(const knot_rrset_t *); } - dbg_packet("Answer section: %p\n", pkt->answer); - dbg_packet("Authority section: %p\n", pkt->authority); - dbg_packet("Additional section: %p\n", pkt->additional); + dbg_packet_detail("Answer section: %p\n", pkt->answer); + dbg_packet_detail("Authority section: %p\n", pkt->authority); + dbg_packet_detail("Additional section: %p\n", pkt->additional); pkt->max_an_rrsets = DEFAULT_ANCOUNT; pkt->max_ns_rrsets = DEFAULT_NSCOUNT; @@ -106,8 +107,8 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) pkt->compression.offsets = (size_t *)pos; pos += DEFAULT_DOMAINS_IN_RESPONSE * sizeof(size_t); - dbg_packet("Compression dnames: %p\n", pkt->compression.dnames); - dbg_packet("Compression offsets: %p\n", pkt->compression.offsets); + dbg_packet_detail("Compression dnames: %p\n", pkt->compression.dnames); + dbg_packet_detail("Compression offsets: %p\n", pkt->compression.offsets); pkt->compression.max = DEFAULT_DOMAINS_IN_RESPONSE; pkt->compression.default_count = DEFAULT_DOMAINS_IN_RESPONSE; @@ -118,8 +119,8 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) pkt->wildcard_nodes.snames = (const knot_dname_t **)pos; pos += DEFAULT_WILDCARD_NODES * sizeof(knot_dname_t *); - dbg_packet("Wildcard nodes: %p\n", pkt->wildcard_nodes.nodes); - dbg_packet("Wildcard SNAMEs: %p\n", pkt->wildcard_nodes.snames); + dbg_packet_detail("Wildcard nodes: %p\n", pkt->wildcard_nodes.nodes); + dbg_packet_detail("Wildcard SNAMEs: %p\n", pkt->wildcard_nodes.snames); pkt->wildcard_nodes.default_count = DEFAULT_WILDCARD_NODES; pkt->wildcard_nodes.max = DEFAULT_WILDCARD_NODES; @@ -127,7 +128,7 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) pkt->tmp_rrsets = (const knot_rrset_t **)pos; pos += DEFAULT_TMP_RRSETS * sizeof(const knot_rrset_t *); - dbg_packet("Tmp rrsets: %p\n", pkt->tmp_rrsets); + dbg_packet_detail("Tmp rrsets: %p\n", pkt->tmp_rrsets); pkt->tmp_rrsets_max = DEFAULT_TMP_RRSETS; @@ -141,7 +142,7 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) */ static void knot_packet_init_pointers_query(knot_packet_t *pkt) { - dbg_packet("Packet pointer: %p\n", pkt); + dbg_packet_detail("Packet pointer: %p\n", pkt); char *pos = (char *)pkt + PREALLOC_PACKET; @@ -149,17 +150,15 @@ static void knot_packet_init_pointers_query(knot_packet_t *pkt) pkt->question.qname = (knot_dname_t *)pos; pos += PREALLOC_QNAME_DNAME; - dbg_packet("QNAME: %p (%zu after start of packet)\n", - pkt->question.qname, - (void *)pkt->question.qname - (void *)pkt); + dbg_packet_detail("QNAME: %p (%zu after start of packet)\n", + pkt->question.qname, + (void *)pkt->question.qname - (void *)pkt); pkt->question.qname->name = (uint8_t *)pos; pos += PREALLOC_QNAME_NAME; pkt->question.qname->labels = (uint8_t *)pos; pos += PREALLOC_QNAME_LABELS; -// pkt->owner_tmp = (uint8_t *)((char *)pkt->question.qname->labels -// + PREALLOC_QNAME_LABELS); // then answer, authority and additional sections if (DEFAULT_ANCOUNT_QUERY == 0) { @@ -183,9 +182,9 @@ static void knot_packet_init_pointers_query(knot_packet_t *pkt) pos += DEFAULT_ARCOUNT_QUERY * sizeof(const knot_rrset_t *); } - dbg_packet("Answer section: %p\n", pkt->answer); - dbg_packet("Authority section: %p\n", pkt->authority); - dbg_packet("Additional section: %p\n", pkt->additional); + dbg_packet_detail("Answer section: %p\n", pkt->answer); + dbg_packet_detail("Authority section: %p\n", pkt->authority); + dbg_packet_detail("Additional section: %p\n", pkt->additional); pkt->max_an_rrsets = DEFAULT_ANCOUNT_QUERY; pkt->max_ns_rrsets = DEFAULT_NSCOUNT_QUERY; @@ -194,15 +193,11 @@ static void knot_packet_init_pointers_query(knot_packet_t *pkt) pkt->tmp_rrsets = (const knot_rrset_t **)pos; pos += DEFAULT_TMP_RRSETS_QUERY * sizeof(const knot_rrset_t *); - dbg_packet("Tmp rrsets: %p\n", pkt->tmp_rrsets); + dbg_packet_detail("Tmp rrsets: %p\n", pkt->tmp_rrsets); pkt->tmp_rrsets_max = DEFAULT_TMP_RRSETS_QUERY; -// dbg_packet("End of data: %p (%zu after start of packet)\n", -// pkt->tmp_rrsets + DEFAULT_TMP_RRSETS_QUERY, -// (void *)(pkt->tmp_rrsets + DEFAULT_TMP_RRSETS_QUERY) -// - (void *)pkt); - dbg_packet("Allocated total: %u\n", PREALLOC_QUERY); + dbg_packet_detail("Allocated total: %u\n", PREALLOC_QUERY); assert(pos == (char *)pkt + PREALLOC_QUERY); } @@ -230,7 +225,7 @@ static int knot_packet_parse_header(const uint8_t *wire, size_t *pos, assert(header != NULL); if (size - *pos < KNOT_WIRE_HEADER_SIZE) { - dbg_response("Not enough data to parse header.\n"); + dbg_packet("Not enough data to parse header.\n"); return KNOT_EFEWDATA; } @@ -238,10 +233,8 @@ static int knot_packet_parse_header(const uint8_t *wire, size_t *pos, // copy some of the flags: OPCODE and RD // do this by copying flags1 and setting QR to 1, AA to 0 and TC to 0 header->flags1 = knot_wire_get_flags1(wire); -// knot_wire_flags_set_qr(&header->flags1); -// knot_wire_flags_clear_aa(&header->flags1); -// knot_wire_flags_clear_tc(&header->flags1); // do not copy flags2 (all set by server) + header->qdcount = knot_wire_get_qdcount(wire); header->ancount = knot_wire_get_ancount(wire); header->nscount = knot_wire_get_nscount(wire); @@ -276,12 +269,11 @@ static int knot_packet_parse_question(const uint8_t *wire, size_t *pos, assert(question != NULL); if (size - *pos < KNOT_WIRE_QUESTION_MIN_SIZE) { - dbg_response("Not enough data to parse question.\n"); + dbg_packet("Not enough data to parse question.\n"); return KNOT_EFEWDATA; // malformed } - dbg_response("Parsing Question starting on position %zu.\n", - *pos); + dbg_packet("Parsing Question starting on position %zu.\n", *pos); // domain name must end with 0, so just search for 0 int i = *pos; @@ -290,13 +282,13 @@ static int knot_packet_parse_question(const uint8_t *wire, size_t *pos, } if (size - i - 1 < 4) { - dbg_response("Not enough data to parse question.\n"); + dbg_packet("Not enough data to parse question.\n"); return KNOT_EFEWDATA; // no 0 found or not enough data left } - dbg_response("Parsing dname starting on position %zu and " + dbg_packet_verb("Parsing dname starting on position %zu and " "%zu bytes long.\n", *pos, i - *pos + 1); - dbg_response("Alloc: %d\n", alloc); + dbg_packet_verb("Alloc: %d\n", alloc); if (alloc) { question->qname = knot_dname_new_from_wire( wire + *pos, i - *pos + 1, NULL); @@ -314,10 +306,7 @@ static int knot_packet_parse_question(const uint8_t *wire, size_t *pos, *pos = i + 1; question->qtype = knot_wire_read_u16(wire + i + 1); - //*pos += 2; question->qclass = knot_wire_read_u16(wire + i + 3); - //*pos += 2; - *pos += 4; return KNOT_EOK; @@ -340,7 +329,7 @@ static int knot_packet_realloc_rrsets(const knot_rrset_t ***rrsets, short *max_count, short default_max_count, short step) { - dbg_packet("Max count: %d, default max count: %d\n", + dbg_packet_verb("Max count: %d, default max count: %d\n", *max_count, default_max_count); int free_old = (*max_count) != default_max_count; const knot_rrset_t **old = *rrsets; @@ -368,11 +357,6 @@ static knot_rdata_t *knot_packet_parse_rdata(const uint8_t *wire, size_t *pos, size_t total_size, size_t rdlength, const knot_rrtype_descriptor_t *desc) { -// if (desc->type == 0) { -// dbg_packet("Unknown RR type.\n"); -// return NULL; -// } - knot_rdata_t *rdata = knot_rdata_new(); if (rdata == NULL) { return NULL; @@ -383,7 +367,7 @@ static knot_rdata_t *knot_packet_parse_rdata(const uint8_t *wire, if (rc != KNOT_EOK) { dbg_packet("rdata_from_wire() returned: %s\n", - knot_strerror(rc)); + knot_strerror(rc)); knot_rdata_free(&rdata); return NULL; } @@ -396,38 +380,32 @@ static knot_rdata_t *knot_packet_parse_rdata(const uint8_t *wire, static knot_rrset_t *knot_packet_parse_rr(const uint8_t *wire, size_t *pos, size_t size) { -// knot_rrset_t *rrset = -// (knot_rrset_t *)malloc(sizeof(knot_rrset_t)); -// CHECK_ALLOC_LOG(rrset, NULL); - dbg_packet("Parsing RR from position: %zu, total size: %zu\n", - *pos, size); + *pos, size); knot_dname_t *owner = knot_dname_parse_from_wire(wire, pos, size, NULL); - dbg_packet("Created owner: %p, actual position: %zu\n", owner, + dbg_packet_detail("Created owner: %p, actual position: %zu\n", owner, *pos); if (owner == NULL) { return NULL; } -dbg_packet_exec( +dbg_packet_exec_verb( char *name = knot_dname_to_str(owner); - dbg_packet("Parsed name: %s\n", name); + dbg_packet_verb("Parsed name: %s\n", name); free(name); ); - //*remaining -= knot_dname_size(rrset->owner); - /*! @todo Get rid of the numerical constant. */ if (size - *pos < 10) { dbg_packet("Malformed RR: Not enough data to parse RR" - " header.\n"); + " header.\n"); knot_dname_release(owner); return NULL; } - dbg_packet("Reading type from position %zu\n", *pos); + dbg_packet_detail("Reading type from position %zu\n", *pos); uint16_t type = knot_wire_read_u16(wire + *pos); uint16_t rclass = knot_wire_read_u16(wire + *pos + 2); @@ -445,7 +423,7 @@ dbg_packet_exec( uint16_t rdlength = knot_wire_read_u16(wire + *pos + 8); - dbg_packet("Read RR header: type %u, class %u, ttl %u, " + dbg_packet_detail("Read RR header: type %u, class %u, ttl %u, " "rdlength %u\n", rrset->type, rrset->rclass, rrset->ttl, rdlength); @@ -453,10 +431,8 @@ dbg_packet_exec( if (size - *pos < rdlength) { dbg_packet("Malformed RR: Not enough data to parse RR" - " RDATA (size: %zu, position: %zu).\n", - size, *pos); + " RDATA (size: %zu, position: %zu).\n", size, *pos); knot_rrset_deep_free(&rrset, 1, 1, 0); -// free(rrset); return NULL; } @@ -473,16 +449,13 @@ dbg_packet_exec( if (rdata == NULL) { dbg_packet("Malformed RR: Could not parse RDATA.\n"); knot_rrset_deep_free(&rrset, 1, 1, 0); -// free(rrset); return NULL; } if (knot_rrset_add_rdata(rrset, rdata) != KNOT_EOK) { - dbg_packet("Malformed RR: Could not add RDATA to RRSet" - ".\n"); + dbg_packet("Malformed RR: Could not add RDATA to RRSet.\n"); knot_rdata_free(&rdata); knot_rrset_deep_free(&rrset, 1, 1, 0); -// free(rrset); return NULL; } @@ -492,23 +465,22 @@ dbg_packet_exec( /*----------------------------------------------------------------------------*/ static int knot_packet_add_rrset(knot_rrset_t *rrset, - const knot_rrset_t ***rrsets, - short *rrset_count, - short *max_rrsets, - short default_rrsets, - const knot_packet_t *packet, - knot_packet_duplicate_handling_t dupl) + const knot_rrset_t ***rrsets, + short *rrset_count, + short *max_rrsets, + short default_rrsets, + const knot_packet_t *packet, + knot_packet_duplicate_handling_t dupl) { - assert(rrset != NULL); assert(rrsets != NULL); assert(rrset_count != NULL); assert(max_rrsets != NULL); -dbg_packet_exec( +dbg_packet_exec_verb( char *name = knot_dname_to_str(rrset->owner); - dbg_packet("packet_add_rrset(), owner: %s, type: %s\n", - name, knot_rrtype_to_string(rrset->type)); + dbg_packet_verb("packet_add_rrset(), owner: %s, type: %s\n", + name, knot_rrtype_to_string(rrset->type)); free(name); ); @@ -529,19 +501,20 @@ dbg_packet_exec( // try to find the RRSet in this array of RRSets for (int i = 0; i < *rrset_count; ++i) { -dbg_packet_exec( +dbg_packet_exec_detail( char *name = knot_dname_to_str((*rrsets)[i]->owner); - dbg_packet("Comparing to RRSet: owner: %s, " - "type: %s\n", name, - knot_rrtype_to_string( - (*rrsets)[i]->type)); + dbg_packet_detail("Comparing to RRSet: owner: %s, " + "type: %s\n", name, + knot_rrtype_to_string( + (*rrsets)[i]->type)); free(name); ); if (knot_rrset_compare((*rrsets)[i], rrset, KNOT_RRSET_COMPARE_HEADER)) { - //const knot_rrset_t *r = (*rrsets) /*! \todo Test this!!! */ + // no duplicate checking here, the packet should + // look exactly as it came from wire int rc = knot_rrset_merge( (void **)((*rrsets) + i), (void **)&rrset); if (rc != KNOT_EOK) { @@ -561,11 +534,12 @@ dbg_packet_exec( /*----------------------------------------------------------------------------*/ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos, - size_t size, uint16_t rr_count, - const knot_rrset_t ***rrsets, - short *rrset_count, short *max_rrsets, - short default_rrsets, - knot_packet_t *packet) + size_t size, uint16_t rr_count, + uint16_t *parsed_rrs, + const knot_rrset_t ***rrsets, + short *rrset_count, short *max_rrsets, + short default_rrsets, + knot_packet_t *packet) { assert(pos != NULL); assert(wire != NULL); @@ -574,12 +548,7 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos, assert(max_rrsets != NULL); assert(packet != NULL); - dbg_packet("Parsing RRSets starting on position: %zu\n", - *pos); - -// if (*rrsets == NULL) { -// knot_packet_realloc_rrsets(rrsets, max_rrsets, 0, 1); -// } + dbg_packet("Parsing RRSets starting on position: %zu\n", *pos); /* * The RRs from one RRSet may be scattered in the current section. @@ -589,7 +558,8 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos, int err = KNOT_EOK; knot_rrset_t *rrset = NULL; - for (int i = 0; i < rr_count; ++i) { + /* Start parsing from the first RR not parsed. */ + for (int i = *parsed_rrs; i < rr_count; ++i) { rrset = knot_packet_parse_rr(wire, pos, size); if (rrset == NULL) { dbg_packet("Failed to parse RR!\n"); @@ -597,13 +567,15 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos, break; } + ++(*parsed_rrs); + err = knot_packet_add_rrset(rrset, rrsets, rrset_count, - max_rrsets, default_rrsets, packet, - KNOT_PACKET_DUPL_MERGE); + max_rrsets, default_rrsets, packet, + KNOT_PACKET_DUPL_MERGE); if (err < 0) { break; } else if (err > 0) { // merged - dbg_packet("RRSet merged, freeing.\n"); + dbg_packet_detail("RRSet merged, freeing.\n"); knot_rrset_deep_free(&rrset, 1, 0, 0); // TODO: ok?? continue; } @@ -616,6 +588,23 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos, knot_rrset_deep_free(&rrset, 1, 1, 1); break; } + + if (knot_rrset_type(rrset) == KNOT_RRTYPE_TSIG) { + // if there is some TSIG already, treat as malformed + if (knot_packet_tsig(packet) != NULL) { + err = KNOT_EMALF; + break; + } + + // First check the format of the TSIG RR + if (!tsig_rdata_is_ok(rrset)) { + err = KNOT_EMALF; + break; + } + + // store the TSIG into the packet + knot_packet_set_tsig(packet, rrset); + } } return (err < 0) ? err : KNOT_EOK; @@ -630,9 +619,9 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos, */ static void knot_packet_free_allocated_space(knot_packet_t *pkt) { - dbg_packet("Freeing additional space in packet.\n"); + dbg_packet_verb("Freeing additional space in packet.\n"); if (pkt->prealloc_type == KNOT_PACKET_PREALLOC_NONE) { - dbg_packet("Freeing QNAME.\n"); + dbg_packet_detail("Freeing QNAME.\n"); knot_dname_release(pkt->question.qname); } @@ -674,37 +663,55 @@ static int knot_packet_parse_rr_sections(knot_packet_t *packet, int err; - dbg_packet("Parsing Answer RRs...\n"); + assert(packet->tsig_rr == NULL); + + dbg_packet_verb("Parsing Answer RRs...\n"); if ((err = knot_packet_parse_rrs(packet->wireformat, pos, - packet->size, packet->header.ancount, &packet->answer, - &packet->an_rrsets, &packet->max_an_rrsets, + packet->size, packet->header.ancount, &packet->parsed_an, + &packet->answer, &packet->an_rrsets, &packet->max_an_rrsets, DEFAULT_RRSET_COUNT(ANCOUNT, packet), packet)) != KNOT_EOK) { return err; } - dbg_packet("Parsing Authority RRs...\n"); + if (packet->tsig_rr != NULL) { + dbg_packet("TSIG in Answer section.\n"); + return KNOT_EMALF; + } + + dbg_packet_verb("Parsing Authority RRs...\n"); if ((err = knot_packet_parse_rrs(packet->wireformat, pos, - packet->size, packet->header.nscount, &packet->authority, - &packet->ns_rrsets, &packet->max_ns_rrsets, + packet->size, packet->header.nscount, &packet->parsed_ns, + &packet->authority, &packet->ns_rrsets, &packet->max_ns_rrsets, DEFAULT_RRSET_COUNT(NSCOUNT, packet), packet)) != KNOT_EOK) { return err; } - dbg_packet("Parsing Additional RRs...\n"); + if (packet->tsig_rr != NULL) { + dbg_packet("TSIG in Authority section.\n"); + return KNOT_EMALF; + } + + dbg_packet_verb("Parsing Additional RRs...\n"); if ((err = knot_packet_parse_rrs(packet->wireformat, pos, - packet->size, packet->header.arcount, &packet->additional, - &packet->ar_rrsets, &packet->max_ar_rrsets, + packet->size, packet->header.arcount, &packet->parsed_ar, + &packet->additional, &packet->ar_rrsets, &packet->max_ar_rrsets, DEFAULT_RRSET_COUNT(ARCOUNT, packet), packet)) != KNOT_EOK) { return err; } - dbg_packet("Trying to find OPT RR in the packet.\n"); + // If TSIG is not the last record + if (packet->tsig_rr != NULL + && packet->ar_rrsets[packet->additional - 1] != packet->tsig_rr) { + dbg_packet("TSIG in Additonal section but not last.\n"); + return KNOT_EMALF; + } + + dbg_packet_verb("Trying to find OPT RR in the packet.\n"); for (int i = 0; i < packet->ar_rrsets; ++i) { assert(packet->additional[i] != NULL); - if (knot_rrset_type(packet->additional[i]) - == KNOT_RRTYPE_OPT) { - dbg_packet("Found OPT RR, filling.\n"); + if (knot_rrset_type(packet->additional[i]) == KNOT_RRTYPE_OPT) { + dbg_packet_detail("Found OPT RR, filling.\n"); err = knot_edns_new_from_rr(&packet->opt_rr, packet->additional[i]); if (err != KNOT_EOK) { @@ -717,9 +724,10 @@ static int knot_packet_parse_rr_sections(knot_packet_t *packet, packet->parsed = *pos; if (*pos < packet->size) { - // some trailing garbage; ignore, but log - dbg_response("Packet: %zu bytes of trailing garbage " - "in packet.\n", packet->size - (*pos)); + // If there is some trailing garbage, treat the packet as + // malformed + dbg_packet_verb("Packet: %zu bytes of trailing garbage " + "in packet.\n", packet->size - (*pos)); return KNOT_EMALF; } @@ -784,12 +792,14 @@ int knot_packet_parse_from_wire(knot_packet_t *packet, packet->size = size; packet->free_wireformat = 0; - //uint8_t *pos = wireformat; + if (size < 2) { + return KNOT_EMALF; + } + size_t pos = 0; - //size_t remaining = size; - dbg_packet("Parsing wire format of packet (size %zu).\nHeader\n", - size); + dbg_packet_verb("Parsing wire format of packet (size %zu).\nHeader\n", + size); if ((err = knot_packet_parse_header(wireformat, &pos, size, &packet->header)) != KNOT_EOK) { return err; @@ -797,15 +807,14 @@ int knot_packet_parse_from_wire(knot_packet_t *packet, packet->parsed = pos; - dbg_packet("Question (prealloc type: %d)...\n", packet->prealloc_type); + dbg_packet_verb("Question (prealloc type: %d)...\n", + packet->prealloc_type); if (packet->header.qdcount > 1) { dbg_packet("QDCOUNT larger than 1, FORMERR.\n"); return KNOT_EMALF; } - knot_packet_dump(packet); - if (packet->header.qdcount == 1) { if ((err = knot_packet_parse_question(wireformat, &pos, size, &packet->question, packet->prealloc_type @@ -816,18 +825,20 @@ int knot_packet_parse_from_wire(knot_packet_t *packet, packet->parsed = pos; } +dbg_packet_exec_detail( knot_packet_dump(packet); +); if (question_only) { return KNOT_EOK; } /*! \todo Replace by call to parse_rest()? */ - err = knot_packet_parse_rr_sections(packet, &pos); + err = knot_packet_parse_rest(packet); -#ifdef KNOT_PACKET_DEBUG +dbg_packet_exec_detail( knot_packet_dump(packet); -#endif /* KNOT_RESPONSE_DEBUG */ +); return err; } @@ -840,16 +851,21 @@ int knot_packet_parse_rest(knot_packet_t *packet) return KNOT_EBADARG; } -// if (packet->parsed >= packet->size) { -// return KNOT_EOK; -// } - - if (packet->parsed == packet->size) { + if (packet->header.ancount == packet->parsed_an + && packet->header.nscount == packet->parsed_ns + && packet->header.arcount == packet->parsed_ar + && packet->parsed == packet->size) { return KNOT_EOK; } + + // If there is less data then required, the next function will find out. + // If there is more data than required, it also returns EMALF. size_t pos = packet->parsed; + /*! \todo If we already parsed some part of the packet, it is not ok + * to begin parsing from the Answer section. + */ return knot_packet_parse_rr_sections(packet, &pos); } @@ -866,16 +882,16 @@ int knot_packet_parse_next_rr_answer(knot_packet_t *packet, if (packet->parsed >= packet->size) { assert(packet->an_rrsets <= packet->header.ancount); - if (packet->an_rrsets != packet->header.ancount) { + if (packet->parsed_an != packet->header.ancount) { dbg_packet("Parsed less RRs than expected.\n"); return KNOT_EMALF; } else { - dbg_packet("Whole packet parsed\n"); + dbg_packet_detail("Whole packet parsed\n"); return KNOT_EOK; } } - if (packet->an_rrsets == packet->header.ancount) { + if (packet->parsed_an == packet->header.ancount) { assert(packet->parsed < packet->size); //dbg_packet("Trailing garbage, ignoring...\n"); // there may be other data in the packet @@ -885,19 +901,20 @@ int knot_packet_parse_next_rr_answer(knot_packet_t *packet, size_t pos = packet->parsed; - dbg_packet("Parsing next Answer RR (pos: %zu)...\n", pos); + dbg_packet_verb("Parsing next Answer RR (pos: %zu)...\n", pos); *rr = knot_packet_parse_rr(packet->wireformat, &pos, packet->size); if (*rr == NULL) { - dbg_packet("Failed to parse RR!\n"); + dbg_packet_verb("Failed to parse RR!\n"); return KNOT_EMALF; } - dbg_packet("Parsed. Pos: %zu.\n", pos); + dbg_packet_detail("Parsed. Pos: %zu.\n", pos); packet->parsed = pos; // increment the number of answer RRSets, though there are no saved // in the packet; it is OK, because packet->answer is NULL ++packet->an_rrsets; + ++packet->parsed_an; return KNOT_EOK; } @@ -916,37 +933,37 @@ int knot_packet_parse_next_rr_additional(knot_packet_t *packet, if (packet->parsed >= packet->size) { assert(packet->ar_rrsets <= packet->header.arcount); - if (packet->ar_rrsets != packet->header.arcount) { + if (packet->parsed_ar != packet->header.arcount) { dbg_packet("Parsed less RRs than expected.\n"); return KNOT_EMALF; } else { - dbg_packet("Whole packet parsed\n"); + dbg_packet_detail("Whole packet parsed\n"); return KNOT_EOK; } } - if (packet->ar_rrsets == packet->header.arcount) { + if (packet->parsed_ar == packet->header.arcount) { assert(packet->parsed < packet->size); - dbg_packet("Trailing garbage, ignoring...\n"); - /*! \todo Do not ignore. */ - return KNOT_EOK; + dbg_packet_verb("Trailing garbage, treating as malformed...\n"); + return KNOT_EMALF; } size_t pos = packet->parsed; - dbg_packet("Parsing next Additional RR (pos: %zu)...\n", pos); + dbg_packet_verb("Parsing next Additional RR (pos: %zu)...\n", pos); *rr = knot_packet_parse_rr(packet->wireformat, &pos, packet->size); if (*rr == NULL) { - dbg_packet("Failed to parse RR!\n"); + dbg_packet_verb("Failed to parse RR!\n"); return KNOT_EMALF; } - dbg_packet("Parsed. Pos: %zu.\n", pos); + dbg_packet_detail("Parsed. Pos: %zu.\n", pos); packet->parsed = pos; // increment the number of answer RRSets, though there are no saved // in the packet; it is OK, because packet->answer is NULL ++packet->ar_rrsets; + ++packet->parsed_ar; return KNOT_EOK; } @@ -1186,7 +1203,7 @@ const knot_rrset_t *knot_packet_tsig(const knot_packet_t *packet) void knot_packet_set_tsig(knot_packet_t *packet, const knot_rrset_t *tsig_rr) { - packet->tsig_rr = (knot_rrset_t *)tsig_rr; + packet->tsig_rr = (knot_rrset_t *)tsig_rr; } /*----------------------------------------------------------------------------*/ @@ -1268,19 +1285,19 @@ int knot_packet_contains(const knot_packet_t *packet, return KNOT_EBADARG; } - for (int i = 0; i < packet->header.ancount; ++i) { + for (int i = 0; i < packet->an_rrsets; ++i) { if (knot_rrset_compare(packet->answer[i], rrset, cmp)) { return 1; } } - for (int i = 0; i < packet->header.nscount; ++i) { + for (int i = 0; i < packet->ns_rrsets; ++i) { if (knot_rrset_compare(packet->authority[i], rrset, cmp)) { return 1; } } - for (int i = 0; i < packet->header.arcount; ++i) { + for (int i = 0; i < packet->ar_rrsets; ++i) { if (knot_rrset_compare(packet->additional[i], rrset, cmp)) { return 1; } @@ -1307,8 +1324,8 @@ int knot_packet_add_tmp_rrset(knot_packet_t *packet, } packet->tmp_rrsets[packet->tmp_rrsets_count++] = tmp_rrset; - dbg_packet("Current tmp RRSets count: %d, max count: %d\n", - packet->tmp_rrsets_count, packet->tmp_rrsets_max); + dbg_packet_detail("Current tmp RRSets count: %d, max count: %d\n", + packet->tmp_rrsets_count, packet->tmp_rrsets_max); return KNOT_EOK; } @@ -1329,7 +1346,7 @@ void knot_packet_free_tmp_rrsets(knot_packet_t *pkt) dbg_packet_exec( char *name = knot_dname_to_str( (((knot_rrset_t **)(pkt->tmp_rrsets))[i])->owner); - dbg_packet("Freeing tmp RRSet on ptr: %p (ptr to ptr:" + dbg_packet_verb("Freeing tmp RRSet on ptr: %p (ptr to ptr:" " %p, type: %s, owner: %s)\n", (((knot_rrset_t **)(pkt->tmp_rrsets))[i]), &(((knot_rrset_t **)(pkt->tmp_rrsets))[i]), @@ -1394,14 +1411,6 @@ int knot_packet_question_to_wire(knot_packet_t *packet) pos += 2; knot_wire_write_u16(pos, packet->question.qclass); -// int err = 0; - // TODO: put the qname into the compression table -// // TODO: get rid of the numeric constants -// if ((err = knot_response_store_dname_pos(&packet->compression, -// packet->question.qname,0, 12, 12)) != KNOT_EOK) { -// return err; -// } - packet->size += knot_dname_size(packet->question.qname) + 4; return KNOT_EOK; @@ -1486,8 +1495,6 @@ void knot_packet_free(knot_packet_t **packet) knot_packet_free_allocated_space(*packet); // free the space for wireformat -// assert((*packet)->wireformat != NULL); -// free((*packet)->wireformat); if ((*packet)->wireformat != NULL && (*packet)->free_wireformat) { free((*packet)->wireformat); } diff --git a/src/libknot/packet/packet.h b/src/libknot/packet/packet.h index 9e37c12..d76209a 100644..100755 --- a/src/libknot/packet/packet.h +++ b/src/libknot/packet/packet.h @@ -138,6 +138,9 @@ struct knot_packet { short free_wireformat; size_t parsed; + uint16_t parsed_an; + uint16_t parsed_ns; + uint16_t parsed_ar; size_t size; /*!< Current wire size of the packet. */ size_t max_size; /*!< Maximum allowed size of the packet. */ diff --git a/src/libknot/packet/query.c b/src/libknot/packet/query.c index b76059b..bc3a4db 100644..100755 --- a/src/libknot/packet/query.c +++ b/src/libknot/packet/query.c @@ -209,7 +209,7 @@ int knot_query_add_rrset_authority(knot_packet_t *query, // reserve space for OPT RR /*! \todo Why here??? */ endp -= query->opt_rr.size; - /*! \note [TSIG] reserve space for TSIG RR */ + /* Reserve space for TSIG RR */ endp -= query->tsig_size; uint8_t *pos = startp; diff --git a/src/libknot/packet/query.h b/src/libknot/packet/query.h index a979641..cda72b9 100644..100755 --- a/src/libknot/packet/query.h +++ b/src/libknot/packet/query.h @@ -61,12 +61,6 @@ int knot_query_nsid_requested(const knot_packet_t *query); int knot_query_edns_supported(const knot_packet_t *query); -//int knot_query_set_qname(knot_packet_t *query, const knot_dname_t *qname); - -//int knot_query_set_qtype(knot_packet_t *query, uint16_t qtype); - -//int knot_query_set_qclass(knot_packet_t *query, uint16_t qclass); - int knot_query_init(knot_packet_t *query); int knot_query_set_question(knot_packet_t *query, diff --git a/src/libknot/packet/response.c b/src/libknot/packet/response.c index 9f6277c..bb4d0f2 100644..100755 --- a/src/libknot/packet/response.c +++ b/src/libknot/packet/response.c @@ -164,15 +164,14 @@ static int knot_response_store_dname_pos(knot_compressed_dnames_t *table, { dbg_response_exec( char *name = knot_dname_to_str(dname); - dbg_response("Putting dname %s into compression table." - " Labels not matched: %d, position: %zu," - ", pointer: %p, unmatched off: %zu\n", name, - not_matched, pos, dname, unmatched_offset); + dbg_response_detail("Putting dname %s into compression table." + " Labels not matched: %d, position: %zu," + ", pointer: %p, unmatched off: %zu\n", name, + not_matched, pos, dname, unmatched_offset); free(name); ); if (pos > KNOT_RESPONSE_MAX_PTR) { - dbg_response("Pointer larger than it can be, not" - " saving\n"); + dbg_response("Pointer larger than it can be, not saving\n"); return KNOT_EDNAMEPTR; } @@ -181,11 +180,6 @@ dbg_response_exec( return KNOT_ENOMEM; } - // store the position of the name -// table->dnames[table->count] = dname; -// table->offsets[table->count] = pos; -// ++table->count; - /* * Store positions of ancestors if more than 1 label was not matched. * @@ -210,11 +204,11 @@ dbg_response_exec( parent_pos = unmatched_offset; } -dbg_response_exec( +dbg_response_exec_detail( char *name = knot_dname_to_str(to_save); - dbg_response("Putting dname %s into compression table." - " Position: %zu, pointer: %p\n", - name, parent_pos, to_save); + dbg_response_detail("Putting dname %s into compression table." + " Position: %zu, pointer: %p\n", + name, parent_pos, to_save); free(name); ); @@ -224,7 +218,6 @@ dbg_response_exec( return KNOT_ENOMEM; } -// dbg_response("Saving..\n"); knot_response_compr_save(table, to_save, parent_pos); /*! \todo Remove '!compr_cs'. */ @@ -234,16 +227,23 @@ dbg_response_exec( // If case-sensitive search is in place, we should not save the // node's parent's positions. - to_save = !compr_cs && (knot_dname_node(to_save) != NULL - && knot_node_parent(knot_dname_node(to_save)) - != NULL) ? knot_node_owner(knot_node_parent( + // Added check to rule out wildcard-covered dnames + // (in such case the offset is not right) + + /*! \todo The whole compression requires a serious refactoring. + * Or better - a rewrite! + */ + to_save = (!compr_cs && knot_dname_node(to_save) != NULL + && knot_node_owner(knot_dname_node(to_save)) + != to_save + && knot_node_parent(knot_dname_node(to_save)) + != NULL) + ? knot_node_owner(knot_node_parent( knot_dname_node(to_save))) - : NULL; + : NULL; dbg_response("i: %d\n", i); parent_pos += knot_dname_label_size(dname, i) + 1; -// parent_pos += (i > 0) -// ? knot_dname_label_size(dname, i - 1) + 1 : 0; ++i; } @@ -267,22 +267,12 @@ static size_t knot_response_find_dname_pos( const knot_dname_t *dname, int compr_cs) { for (int i = 0; i < table->count; ++i) { -// dbg_response("Comparing dnames %p and %p\n", -// dname, table->dnames[i]); -//dbg_response_exec( -// char *name = knot_dname_to_str(dname); -// dbg_response("(%s and ", name); -// name = knot_dname_to_str(table->dnames[i]); -// dbg_response("%s)\n", name); -// free(name); -//); - //if (table->dnames[i] == dname) { int ret = (compr_cs) ? knot_dname_compare_cs(table->dnames[i], dname) : knot_dname_compare(table->dnames[i], dname); if (ret == 0) { - dbg_response("Found offset: %zu\n", - table->offsets[i]); + dbg_response_detail("Found offset: %zu\n", + table->offsets[i]); return table->offsets[i]; } } @@ -319,7 +309,7 @@ static int knot_response_put_dname_ptr(const knot_dname_t *dname, memcpy(wire, knot_dname_name(dname), size); knot_wire_put_pointer(wire + size, offset); - dbg_response("Size of the dname with ptr: %d\n", size + 2); + dbg_response_detail("Size of the dname with ptr: %d\n", size + 2); return size + 2; } @@ -343,15 +333,9 @@ static int knot_response_compress_dname(const knot_dname_t *dname, knot_compr_t *compr, uint8_t *dname_wire, size_t max, int compr_cs) { int size = 0; - /*! - * \todo Compress!! - * - * if pos == 0, do not store the position! - */ // try to find the name or one of its ancestors in the compr. table #ifdef COMPRESSION_PEDANTIC - //knot_dname_t *to_find = knot_dname_copy(dname); knot_dname_t *to_find = (knot_dname_t *)dname; int copied = 0; #else @@ -361,11 +345,11 @@ static int knot_response_compress_dname(const knot_dname_t *dname, int not_matched = 0; while (to_find != NULL && knot_dname_label_count(to_find) != 0) { -dbg_response_exec( +dbg_response_exec_detail( char *name = knot_dname_to_str(to_find); - dbg_response("Searching for name %s in the compression" - " table, not matched labels: %d\n", name, - not_matched); + dbg_response_detail("Searching for name %s in the compression" + " table, not matched labels: %d\n", name, + not_matched); free(name); ); offset = knot_response_find_dname_pos(compr->table, to_find, @@ -396,17 +380,17 @@ dbg_response_exec( || knot_node_owner(knot_dname_node(to_find)) != to_find || knot_node_parent(knot_dname_node(to_find)) == NULL) { - dbg_response("compr_cs: %d\n", compr_cs); - dbg_response("knot_dname_node(to_find, 1) == %p" + dbg_response_detail("compr_cs: %d\n", compr_cs); + dbg_response_detail("knot_dname_node(to_find, 1) == %p" "\n", knot_dname_node(to_find)); if (knot_dname_node(to_find) != NULL) { - dbg_response("knot_node_owner(knot_dname_node(" - "to_find, 1)) = %p, to_find = %p\n", - knot_node_owner(knot_dname_node(to_find)), - to_find); - dbg_response("knot_node_parent(knot_dname_node(" - "to_find, 1), 1) = %p\n", + dbg_response_detail("knot_node_owner(knot_dname_node(" + "to_find, 1)) = %p, to_find = %p\n", + knot_node_owner(knot_dname_node(to_find)), + to_find); + dbg_response_detail("knot_node_parent(knot_dname_node(" + "to_find, 1), 1) = %p\n", knot_node_parent(knot_dname_node(to_find))); } break; @@ -417,7 +401,7 @@ dbg_response_exec( knot_node_parent(knot_dname_node(to_find)))); to_find = knot_node_owner( knot_node_parent(knot_dname_node(to_find))); - dbg_response("New to_find: %p\n", to_find); + dbg_response_detail("New to_find: %p\n", to_find); } #endif } @@ -428,10 +412,10 @@ dbg_response_exec( } #endif - dbg_response("Max size available for domain name: %zu\n", max); + dbg_response_detail("Max size available for domain name: %zu\n", max); if (offset > 0) { // found such dname somewhere in the packet - dbg_response("Found name in the compression table.\n"); + dbg_response_detail("Found name in the compression table.\n"); assert(offset >= KNOT_WIRE_HEADER_SIZE); size = knot_response_put_dname_ptr(dname, not_matched, offset, dname_wire, max); @@ -439,7 +423,7 @@ dbg_response_exec( return KNOT_ESPACE; } } else { - dbg_response("Not found, putting whole name.\n"); + dbg_response_detail("Not found, putting whole name.\n"); // now just copy the dname without compressing if (dname->size > max) { return KNOT_ESPACE; @@ -458,8 +442,7 @@ dbg_response_exec( if (knot_response_store_dname_pos(compr->table, dname, not_matched, compr->wire_pos, offset, compr_cs) != 0) { - dbg_response("Compression info could not be stored." - "\n"); + dbg_response_detail("Compression info could not be stored.\n"); } return size; @@ -488,7 +471,7 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, { int size = 0; - dbg_response("Max size: %zu, owner pos: %zu, owner size: %d\n", + dbg_response_detail("Max size: %zu, owner pos: %zu, owner size: %d\n", max_size, compr->owner.pos, compr->owner.size); if (size + ((compr->owner.pos == 0 @@ -498,7 +481,7 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, return KNOT_ESPACE; } - dbg_response("Owner position: %zu\n", compr->owner.pos); + dbg_response_detail("Owner position: %zu\n", compr->owner.pos); // put owner if needed (already compressed) if (compr->owner.pos == 0 || compr->owner.pos > KNOT_RESPONSE_MAX_PTR) { @@ -507,28 +490,28 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, *rrset_wire += compr->owner.size; size += compr->owner.size; } else { - dbg_response("Putting pointer: %zu\n", - compr->owner.pos); + dbg_response_detail("Putting pointer: %zu\n", + compr->owner.pos); knot_wire_put_pointer(*rrset_wire, compr->owner.pos); *rrset_wire += 2; size += 2; } - dbg_response("Max size: %zu, size: %d\n", max_size, size); + dbg_response_detail("Max size: %zu, size: %d\n", max_size, size); - dbg_response("Wire format:\n"); + dbg_response_detail("Wire format:\n"); // put rest of RR 'header' knot_wire_write_u16(*rrset_wire, rrset->type); - dbg_response(" Type: %u\n", rrset->type); + dbg_response_detail(" Type: %u\n", rrset->type); *rrset_wire += 2; knot_wire_write_u16(*rrset_wire, rrset->rclass); - dbg_response(" Class: %u\n", rrset->rclass); + dbg_response_detail(" Class: %u\n", rrset->rclass); *rrset_wire += 2; knot_wire_write_u32(*rrset_wire, rrset->ttl); - dbg_response(" TTL: %u\n", rrset->ttl); + dbg_response_detail(" TTL: %u\n", rrset->ttl); *rrset_wire += 4; // save space for RDLENGTH @@ -538,7 +521,7 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, size += 10; compr->wire_pos += size; - dbg_response("Max size: %zu, size: %d\n", max_size, size); + dbg_response_detail("Max size: %zu, size: %d\n", max_size, size); knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type(rrset->type); @@ -561,8 +544,7 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, return KNOT_ESPACE; } - dbg_response("Compressed dname size: %d\n", - ret); + dbg_response_detail("Compressed dname size: %d\n", ret); *rrset_wire += ret; rdlength += ret; compr->wire_pos += ret; @@ -579,8 +561,8 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, // save whole domain name memcpy(*rrset_wire, dname->name, dname->size); - dbg_response("Uncompressed dname size: %d\n", - dname->size); + dbg_response_detail("Uncompressed dname size: %d\n", + dname->size); *rrset_wire += dname->size; rdlength += dname->size; compr->wire_pos += dname->size; @@ -596,8 +578,8 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, // copy just the rdata item data (without size) memcpy(*rrset_wire, raw_data + 1, raw_data[0]); - dbg_response("Raw data size: %d\n", - raw_data[0]); + dbg_response_detail("Raw data size: %d\n", + raw_data[0]); *rrset_wire += raw_data[0]; rdlength += raw_data[0]; compr->wire_pos += raw_data[0]; @@ -606,7 +588,7 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, } } - dbg_response("Max size: %zu, size: %d\n", max_size, size); + dbg_response_detail("Max size: %zu, size: %d\n", max_size, size); assert(size + rdlength <= max_size); size += rdlength; @@ -639,12 +621,12 @@ static int knot_response_rrset_to_wire(const knot_rrset_t *rrset, knot_compressed_dnames_t *compr, int compr_cs) { -dbg_response_exec( +dbg_response_exec_verb( char *name = knot_dname_to_str(rrset->owner); - dbg_response("Converting RRSet with owner %s, type %s\n", - name, knot_rrtype_to_string(rrset->type)); + dbg_response_verb("Converting RRSet with owner %s, type %s\n", + name, knot_rrtype_to_string(rrset->type)); free(name); - dbg_response(" Size before: %zu\n", *size); + dbg_response_verb(" Size before: %zu\n", *size); ); // if no RDATA in RRSet, return @@ -652,10 +634,6 @@ dbg_response_exec( return KNOT_EOK; } - //uint8_t *rrset_wire = (uint8_t *)malloc(PREALLOC_RRSET_WIRE); - //short rrset_size = 0; - - //uint8_t *owner_wire = (uint8_t *)malloc(rrset->owner->size); /* * We may pass the current position to the compression function * because if the owner will be put somewhere, it will be on the @@ -665,7 +643,6 @@ dbg_response_exec( */ knot_compr_t compr_info; - //compr_info.new_entries = 0; compr_info.table = compr; compr_info.wire_pos = wire_pos; compr_info.owner.pos = 0; @@ -674,8 +651,8 @@ dbg_response_exec( knot_response_compress_dname(rrset->owner, &compr_info, owner_tmp, max_size, compr_cs); - dbg_response(" Owner size: %d, position: %zu\n", - compr_info.owner.size, compr_info.owner.pos); + dbg_response_detail(" Owner size: %d, position: %zu\n", + compr_info.owner.size, compr_info.owner.pos); if (compr_info.owner.size < 0) { return KNOT_ESPACE; } @@ -698,20 +675,17 @@ dbg_response_exec( return KNOT_ESPACE; } - dbg_response("RR of size %d added.\n", ret); + dbg_response_verb("RR of size %d added.\n", ret); rrset_size += ret; ++rrs; } while ((rdata = knot_rrset_rdata_next(rrset, rdata)) != NULL); - //memcpy(*pos, rrset_wire, rrset_size); - //*size += rrset_size; - //*pos += rrset_size; // the whole RRSet did fit in assert (rrset_size <= max_size); *size += rrset_size; - dbg_response(" Size after: %zu\n", *size); + dbg_response_verb(" Size after: %zu\n", *size); return rrs; } @@ -750,8 +724,8 @@ static int knot_response_try_add_rrset(const knot_rrset_t **rrsets, dbg_response_exec( char *name = knot_dname_to_str(rrset->owner); - dbg_response("\nAdding RRSet with owner %s and type %s: \n", - name, knot_rrtype_to_string(rrset->type)); + dbg_response_verb("\nAdding RRSet with owner %s and type %s: \n", + name, knot_rrtype_to_string(rrset->type)); free(name); ); @@ -764,11 +738,11 @@ dbg_response_exec( if (rrs >= 0) { rrsets[(*rrset_count)++] = rrset; resp->size += size; - dbg_response("RRset added, size: %zu, RRs: %d, total " - "size of response: %zu\n\n", size, rrs, - resp->size); + dbg_response_verb("RRset added, size: %zu, RRs: %d, total " + "size of response: %zu\n\n", size, rrs, + resp->size); } else if (tc) { - dbg_response("Setting TC bit.\n"); + dbg_response_verb("Setting TC bit.\n"); knot_wire_flags_set_tc(&resp->header.flags1); knot_wire_set_tc(resp->wireformat); } @@ -825,8 +799,8 @@ static int knot_response_realloc_wc_nodes(const knot_node_t ***nodes, short *max_count, short default_max_count, short step) { - dbg_packet("Max count: %d, default max count: %d\n", - *max_count, default_max_count); + dbg_packet_detail("Max count: %d, default max count: %d\n", + *max_count, default_max_count); int free_old = (*max_count) != default_max_count; const knot_node_t **old_nodes = *nodes; @@ -896,13 +870,10 @@ int knot_response_init_from_query(knot_packet_t *response, // copy the header from the query memcpy(&response->header, &query->header, sizeof(knot_header_t)); -// memmove(&response->header, &query->header, sizeof(knot_header_t)); // copy the Question section (but do not copy the QNAME) memcpy(&response->question, &query->question, sizeof(knot_question_t)); -// memmove(&response->question, &query->question, -// sizeof(knot_question_t)); int err = 0; // put the qname into the compression table @@ -917,18 +888,16 @@ int knot_response_init_from_query(knot_packet_t *response, size_t to_copy = 12 + 4 + knot_dname_size(response->question.qname); assert(response->max_size >= to_copy); -// printf("Resp init from query: Copying from: %p to: %p size: %d\n", -// response->wireformat, query->wireformat, -// to_copy); -// printf("Resp init from query: Question name size: %d Query name size: %d\n", -// knot_dname_size(response->question.qname), -// knot_dname_size(query->question.qname)); memcpy(response->wireformat, query->wireformat, to_copy); response->size = to_copy; // set the qr bit to 1 knot_wire_flags_set_qr(&response->header.flags1); knot_wire_set_qr(response->wireformat); + + // clear TC flag + knot_wire_flags_clear_tc(&response->header.flags1); + knot_wire_clear_tc(response->wireformat); // clear AD flag knot_wire_flags_clear_ad(&response->header.flags2); @@ -940,8 +909,11 @@ int knot_response_init_from_query(knot_packet_t *response, // set counts to 0 response->header.ancount = 0; + knot_wire_set_ancount(response->wireformat, 0); response->header.nscount = 0; + knot_wire_set_nscount(response->wireformat, 0); response->header.arcount = 0; + knot_wire_set_arcount(response->wireformat, 0); response->query = query; @@ -1039,16 +1011,14 @@ int knot_response_add_opt(knot_packet_t *resp, if (override_max_size && resp->max_size > 0 && resp->max_size < opt_rr->payload) { -// return KNOT_EPAYLOAD; return KNOT_EOK; } // set max size (less is OK) if (override_max_size) { dbg_response("Overriding max size to: %u\n", - resp->opt_rr.payload); + resp->opt_rr.payload); return knot_packet_set_max_size(resp, resp->opt_rr.payload); - //resp->max_size = resp->opt_rr.payload; } return KNOT_EOK; @@ -1065,7 +1035,7 @@ int knot_response_add_rrset_answer(knot_packet_t *response, return KNOT_EBADARG; } - dbg_response("add_rrset_answer()\n"); + dbg_response_verb("add_rrset_answer()\n"); assert(response->header.arcount == 0); assert(response->header.nscount == 0); @@ -1081,9 +1051,9 @@ int knot_response_add_rrset_answer(knot_packet_t *response, return KNOT_EOK; } - dbg_response("Trying to add RRSet to Answer section.\n"); - dbg_response("RRset: %p\n", rrset); - dbg_response("Owner: %p\n", rrset->owner); + dbg_response_verb("Trying to add RRSet to Answer section.\n"); + dbg_response_detail("RRset: %p\n", rrset); + dbg_response_detail("Owner: %p\n", rrset->owner); int rrs = knot_response_try_add_rrset(response->answer, &response->an_rrsets, response, @@ -1132,7 +1102,7 @@ int knot_response_add_rrset_authority(knot_packet_t *response, return KNOT_EOK; } - dbg_response("Trying to add RRSet to Authority section.\n"); + dbg_response_verb("Trying to add RRSet to Authority section.\n"); int rrs = knot_response_try_add_rrset(response->authority, &response->ns_rrsets, response, @@ -1188,7 +1158,7 @@ int knot_response_add_rrset_additional(knot_packet_t *response, return KNOT_EOK; } - dbg_response("Trying to add RRSet to Additional section.\n"); + dbg_response_verb("Trying to add RRSet to Additional section.\n"); int rrs = knot_response_try_add_rrset(response->additional, &response->ar_rrsets, response, @@ -1283,7 +1253,7 @@ int knot_response_add_wildcard_node(knot_packet_t *response, response->wildcard_nodes.snames[response->wildcard_nodes.count] = sname; ++response->wildcard_nodes.count; - dbg_response("Current wildcard nodes count: %d, max count: %d\n", + dbg_response_verb("Current wildcard nodes count: %d, max count: %d\n", response->wildcard_nodes.count, response->wildcard_nodes.max); diff --git a/src/libknot/packet/response.h b/src/libknot/packet/response.h index d3e66f3..d3e66f3 100644..100755 --- a/src/libknot/packet/response.h +++ b/src/libknot/packet/response.h diff --git a/src/libknot/rdata.c b/src/libknot/rdata.c index 8e9e8c1..1cdd339 100644..100755 --- a/src/libknot/rdata.c +++ b/src/libknot/rdata.c @@ -210,8 +210,8 @@ knot_rdata_t *knot_rdata_new() /*----------------------------------------------------------------------------*/ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, - size_t *pos, size_t total_size, size_t rdlength, - const knot_rrtype_descriptor_t *desc) + size_t *pos, size_t total_size, size_t rdlength, + const knot_rrtype_descriptor_t *desc) { int i = 0; uint8_t item_type; @@ -249,7 +249,6 @@ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, return KNOT_ERROR; } items[i].dname = dname; - //*pos += dname->size; parsed += pos2 - *pos; *pos = pos2; dname = 0; @@ -309,7 +308,6 @@ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, break; case 3: pos2 = *pos; - //fprintf(stderr, "reading dname from pos: %zu\n", pos2); dname = knot_dname_parse_from_wire( wire, &pos2, total_size, NULL); if (dname == NULL) { @@ -331,12 +329,9 @@ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, memcpy((uint8_t *)(items[i].raw_data + 1), knot_dname_name(dname), knot_dname_size(dname)); - -// items[i].dname = dname; - //*pos += dname->size; + parsed += pos2 - *pos; - - //fprintf(stderr, "read %zu bytes.\n", parsed); + *pos = pos2; knot_dname_free(&dname); @@ -374,9 +369,7 @@ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, memcpy(items[i].raw_data + 1, wire + *pos, item_size); *pos += item_size; parsed += item_size; - } else if (item_type == KNOT_RDATA_WF_BINARY/* - || item_type == KNOT_RDATA_WF_IPSECGATEWAY*/) { -// fprintf(stderr, "item_size was 0, creating empty rdata item.\n"); + } else if (item_type == KNOT_RDATA_WF_BINARY) { // in this case we are at the end of the RDATA // and should create an empty RDATA item items[i].raw_data = (uint16_t *)malloc(2); @@ -389,8 +382,6 @@ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, } else if (item_type != KNOT_RDATA_WF_COMPRESSED_DNAME && item_type != KNOT_RDATA_WF_UNCOMPRESSED_DNAME && item_type != KNOT_RDATA_WF_LITERAL_DNAME) { -// fprintf(stderr, "RDATA item not set (i: %d), type: %u" -// " RDATA item type: %d\n", i, desc->type ,item_type); assert(0); } @@ -519,6 +510,25 @@ int knot_rdata_item_set_raw_data(knot_rdata_t *rdata, uint pos, /*----------------------------------------------------------------------------*/ +int knot_rdata_count(const knot_rdata_t *rdata) +{ + if (rdata == NULL) { + return 0; + } + + int count = 1; + const knot_rdata_t *r = rdata; + + while (r->next != NULL && r->next != rdata) { + r = r->next; + ++count; + } + + return count; +} + +/*----------------------------------------------------------------------------*/ + void knot_rdata_free(knot_rdata_t **rdata) { if (rdata == NULL || *rdata == NULL) { @@ -541,134 +551,16 @@ void knot_rdata_deep_free(knot_rdata_t **rdata, uint type, return; } - knot_rdata_free_items((*rdata)->items, (*rdata)->count, type, - free_all_dnames); + if ((*rdata)->items != NULL) { + knot_rdata_free_items((*rdata)->items, (*rdata)->count, type, + free_all_dnames); + } free(*rdata); *rdata = NULL; } /*----------------------------------------------------------------------------*/ -/* CLEANUP */ -//uint knot_rdata_wire_size(const knot_rdata_t *rdata, -// const uint8_t *format) -//{ -// uint size = 0; - -// for (int i = 0; i < rdata->count; ++i) { -// switch (format[i]) { -// case KNOT_RDATA_WF_COMPRESSED_DNAME: -// case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: -// case KNOT_RDATA_WF_LITERAL_DNAME: -// size += knot_dname_size(rdata->items[i].dname); -// break; -// case KNOT_RDATA_WF_BYTE: -// size += 1; -// break; -// case KNOT_RDATA_WF_SHORT: -// size += 2; -// break; -// case KNOT_RDATA_WF_LONG: -// size += 4; -// break; -// case KNOT_RDATA_WF_A: -// size += 4; -// break; -// case KNOT_RDATA_WF_AAAA: -// size += 16; -// break; -// case KNOT_RDATA_WF_BINARY: -// case KNOT_RDATA_WF_APL: // saved as binary -// case KNOT_RDATA_WF_IPSECGATEWAY: // saved as binary -// size += rdata->items[i].raw_data[0]; -// break; -// case KNOT_RDATA_WF_TEXT: -// case KNOT_RDATA_WF_BINARYWITHLENGTH: -// size += rdata->items[i].raw_data[0] + 1; -// break; -// default: -// assert(0); -// } -// } -// return size; -//} - -/*----------------------------------------------------------------------------*/ - -//int knot_rdata_to_wire(const knot_rdata_t *rdata, const uint8_t *format, -// uint8_t *buffer, uint buf_size) -//{ -// uint copied = 0; -// uint8_t tmp[KNOT_MAX_RDATA_WIRE_SIZE]; -// uint8_t *to = tmp; - -// for (int i = 0; i < rdata->count; ++i) { -// assert(copied < KNOT_MAX_RDATA_WIRE_SIZE); - -// const uint8_t *from = (uint8_t *)rdata->items[i].raw_data; -// uint size = 0; - -// switch (format[i]) { -// case KNOT_RDATA_WF_COMPRESSED_DNAME: -// case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: -// case KNOT_RDATA_WF_LITERAL_DNAME: -// size = knot_dname_size(rdata->items[i].dname); -// from = knot_dname_name(rdata->items[i].dname); - -// break; -// case KNOT_RDATA_WF_BYTE: -// size = 1; -// break; -// case KNOT_RDATA_WF_SHORT: -// size = 2; -// break; -// case KNOT_RDATA_WF_LONG: -// size = 4; -// break; -// case KNOT_RDATA_WF_A: -// size = 4; -// break; -// case KNOT_RDATA_WF_AAAA: -// size = 16; -// break; -// case KNOT_RDATA_WF_TEXT: -// case KNOT_RDATA_WF_BINARYWITHLENGTH: -// // size stored in the first two bytes, but in little -// // endian and we need only the lower byte from it -// *to = *from; // lower byte is the first in little endian -// to += 1; -// case KNOT_RDATA_WF_BINARY: -// case KNOT_RDATA_WF_APL: // saved as binary -// case KNOT_RDATA_WF_IPSECGATEWAY: // saved as binary -// // size stored in the first two bytes, those bytes -// // must not be copied -// size = rdata->items[i].raw_data[0]; -// from += 2; // skip the first two bytes -// break; -// default: -// assert(0); -// } - -// assert(size != 0); -// assert(copied + size < KNOT_MAX_RDATA_WIRE_SIZE); - -// memcpy(to, from, size); -// to += size; -// copied += size; -// } - -// if (copied > buf_size) { -// dbg_rdata("Not enough place allocated for function " -// "knot_rdata_to_wire(). Allocated %u, need %u\n", -// buf_size, copied); -// return -1; -// } - -// memcpy(buffer, tmp, copied); -// return 0; -//} - -/*----------------------------------------------------------------------------*/ knot_rdata_t *knot_rdata_deep_copy(const knot_rdata_t *rdata, uint16_t type, int copy_dnames) @@ -728,33 +620,19 @@ int knot_rdata_compare(const knot_rdata_t *r1, const knot_rdata_t *r2, int cmp = 0; for (int i = 0; i < count; ++i) { - /* CLEANUP */ -// const uint8_t *data1, *data2; -// int size1, size2; - if (format[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || format[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || format[i] == KNOT_RDATA_WF_LITERAL_DNAME) { cmp = knot_dname_compare(r1->items[i].dname, r2->items[i].dname); -// data1 = knot_dname_name(r1->items[i].dname); -// data2 = knot_dname_name(r2->items[i].dname); -// size1 = knot_dname_size(r2->items[i].dname); -// size2 = knot_dname_size(r2->items[i].dname); } else { cmp = knot_rdata_compare_binary( (uint8_t *)(r1->items[i].raw_data + 1), (uint8_t *)(r2->items[i].raw_data + 1), r1->items[i].raw_data[0], r1->items[i].raw_data[0]); -// data1 = (uint8_t *)(r1->items[i].raw_data + 1); -// data2 = (uint8_t *)(r2->items[i].raw_data + 1); -// size1 = r1->items[i].raw_data[0]; -// size2 = r1->items[i].raw_data[0]; } -// cmp = - if (cmp != 0) { return cmp; } @@ -894,3 +772,48 @@ uint16_t knot_rdata_rrsig_type_covered(const knot_rdata_t *rdata) return knot_wire_read_u16((uint8_t *)(rdata->items[0].raw_data + 1)); } + +/*---------------------------------------------------------------------------*/ + +uint8_t knot_rdata_nsec3_algorithm(const knot_rdata_t *rdata) +{ + if (rdata->count < 1) { + return 0; + } + + return *((uint8_t *)(rdata->items[0].raw_data + 1)); +} + +/*---------------------------------------------------------------------------*/ + +uint16_t knot_rdata_nsec3_iterations(const knot_rdata_t *rdata) +{ + if (rdata->count < 3) { + // this is actually valid value...what to return?? + return 0; + } + + return knot_wire_read_u16((uint8_t *)(rdata->items[2].raw_data + 1)); +} + +/*---------------------------------------------------------------------------*/ + +uint8_t knot_rdata_nsec3_salt_length(const knot_rdata_t *rdata) +{ + if (rdata->count < 4) { + return 0; + } + + return *((uint8_t *)(rdata->items[3].raw_data + 1)); +} + +/*---------------------------------------------------------------------------*/ + +const uint8_t *knot_rdata_nsec3_salt(const knot_rdata_t *rdata) +{ + if (rdata->count < 4) { + return NULL; + } + + return ((uint8_t *)(rdata->items[3].raw_data + 1)) + 1; +} diff --git a/src/libknot/rdata.h b/src/libknot/rdata.h index bb45f50..acd678f 100644..100755 --- a/src/libknot/rdata.h +++ b/src/libknot/rdata.h @@ -220,6 +220,8 @@ int knot_rdata_item_set_dname(knot_rdata_t *rdata, unsigned int pos, int knot_rdata_item_set_raw_data(knot_rdata_t *rdata, unsigned int pos, uint16_t *raw_data); +int knot_rdata_count(const knot_rdata_t *rdata); + /*! * \brief Copies the given RDATA. * @@ -335,6 +337,11 @@ uint32_t knot_rdata_soa_minimum(const knot_rdata_t *rdata); uint16_t knot_rdata_rrsig_type_covered(const knot_rdata_t *rdata); +uint8_t knot_rdata_nsec3_algorithm(const knot_rdata_t *rdata); +uint16_t knot_rdata_nsec3_iterations(const knot_rdata_t *rdata); +uint8_t knot_rdata_nsec3_salt_length(const knot_rdata_t *rdata); +const uint8_t *knot_rdata_nsec3_salt(const knot_rdata_t *rdata); + #endif /* _KNOT_RDATA_H */ /*! @} */ diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c index d665c63..ef7fce8 100644..100755 --- a/src/libknot/rrset.c +++ b/src/libknot/rrset.c @@ -32,7 +32,7 @@ /*----------------------------------------------------------------------------*/ static void knot_rrset_disconnect_rdata(knot_rrset_t *rrset, - knot_rdata_t *prev, knot_rdata_t *rdata) + knot_rdata_t *prev, knot_rdata_t *rdata) { if (prev == NULL) { // find the previous RDATA in the series, as its pointer must @@ -113,6 +113,53 @@ int knot_rrset_add_rdata(knot_rrset_t *rrset, knot_rdata_t *rdata) /*----------------------------------------------------------------------------*/ +int knot_rrset_add_rdata_order(knot_rrset_t *rrset, knot_rdata_t *rdata) +{ + if (rrset == NULL || rdata == NULL) { + dbg_rrset("rrset: add_rdata_order: NULL arguments.\n"); + return KNOT_EBADARG; + } + + if (rrset->rdata == NULL) { + /* Easy peasy, just insert the first item. */ + rrset->rdata = rdata; + rrset->rdata->next = rrset->rdata; + } else { + knot_rdata_t *walk = NULL; + char found = 0; + knot_rdata_t *insert_after = rrset->rdata; + while (((walk = knot_rrset_rdata_get_next(rrset, + walk)) != NULL) && + (!found)) { + const knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrset->type); + assert(desc); + int cmp = knot_rdata_compare(rdata, walk, + desc->wireformat); + if (cmp < 1) { + /* We've found place for this item. */ + } else if (cmp == 0) { + /* This item will not be inserted. */ + found = 1; + insert_after = NULL; + } + assert(cmp > 1); + /* Continue the search. */ + insert_after = walk; + } + if (insert_after != NULL) { + rdata->next = insert_after->next; + insert_after->next = rdata; + } else { + ; + /* Consider returning something different than EOK. */ + } + } + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + knot_rdata_t *knot_rrset_remove_rdata(knot_rrset_t *rrset, const knot_rdata_t *rdata) { @@ -167,19 +214,30 @@ int knot_rrset_add_rrsigs(knot_rrset_t *rrset, knot_rrset_t *rrsigs, int rc; if (rrset->rrsigs != NULL) { if (dupl == KNOT_RRSET_DUPL_MERGE) { - rc = knot_rrset_merge((void **)&rrset->rrsigs, - (void **)&rrsigs); + rc = knot_rrset_merge_no_dupl((void **)&rrset->rrsigs, + (void **)&rrsigs); if (rc != KNOT_EOK) { return rc; } else { return 1; } } else if (dupl == KNOT_RRSET_DUPL_SKIP) { +// rc = knot_rrset_merge_no_dupl((void **)&rrset->rrsigs, +// (void **)&rrsigs); +// if (rc != KNOT_EOK) { +// return rc; +// } else { +// return 1; +// } return 2; } else if (dupl == KNOT_RRSET_DUPL_REPLACE) { rrset->rrsigs = rrsigs; } } else { + if (rrset->ttl != rrsigs->ttl) { + rrsigs->ttl = rrset->ttl; + } + rrset->rrsigs = rrsigs; } @@ -291,6 +349,10 @@ knot_rdata_t *knot_rrset_rdata_get_next(knot_rrset_t *rrset, int knot_rrset_rdata_rr_count(const knot_rrset_t *rrset) { + if (rrset == NULL) { + return 0; + } + int count = 0; const knot_rdata_t *rdata = rrset->rdata; @@ -341,7 +403,7 @@ int knot_rrset_compare_rdata(const knot_rrset_t *r1, const knot_rrset_t *r2) } // compare RDATA sets (order is not significant) - const knot_rdata_t *rdata1= knot_rrset_rdata(r1); + const knot_rdata_t *rdata1 = knot_rrset_rdata(r1); const knot_rdata_t *rdata2; // find all RDATA from r1 in r2 @@ -434,7 +496,6 @@ static int knot_rrset_rr_to_wire(const knot_rrset_t *rrset, *pos += 2; size += 10; -// compr->wire_pos += size; dbg_rrset_detail("Max size: %zu, size: %d\n", max_size, size); @@ -465,7 +526,6 @@ static int knot_rrset_rr_to_wire(const knot_rrset_t *rrset, knot_dname_size(dname)); *pos += knot_dname_size(dname); rdlength += knot_dname_size(dname); -// compr->wire_pos += dname->size; break; } default: { @@ -481,7 +541,6 @@ static int knot_rrset_rr_to_wire(const knot_rrset_t *rrset, dbg_rrset_detail("Raw data size: %d\n", raw_data[0]); *pos += raw_data[0]; rdlength += raw_data[0]; -// compr->wire_pos += raw_data[0]; break; } } @@ -523,11 +582,11 @@ int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, size_t *size, if (ret < 0) { // some RR didn't fit in, so no RRs should be used // TODO: remove last entries from compression table - dbg_rrset_detail("Some RR didn't fit in.\n"); + dbg_rrset_verb("Some RR didn't fit in.\n"); return KNOT_ESPACE; } - dbg_rrset_detail("RR of size %d added.\n", ret); + dbg_rrset_verb("RR of size %d added.\n", ret); rrset_size += ret; ++rrs; } while ((rdata = knot_rrset_rdata_next(rrset, rdata)) != NULL); @@ -556,7 +615,7 @@ int knot_rrset_compare(const knot_rrset_t *r1, int res = ((r1->rclass == r2->rclass) && (r1->type == r2->type) - && (r1->ttl == r2->ttl) +// && (r1->ttl == r2->ttl) && knot_dname_compare(r1->owner, r2->owner) == 0); if (cmp == KNOT_RRSET_COMPARE_WHOLE && res) { @@ -571,7 +630,8 @@ int knot_rrset_compare(const knot_rrset_t *r1, /*----------------------------------------------------------------------------*/ -int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to) +int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to, + int copy_rdata_dnames) { if (from == NULL || to == NULL) { return KNOT_EBADARG; @@ -582,14 +642,14 @@ int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to) *to = (knot_rrset_t *)calloc(1, sizeof(knot_rrset_t)); CHECK_ALLOC_LOG(*to, KNOT_ENOMEM); - //(*to)->owner = knot_dname_deep_copy(from->owner); (*to)->owner = from->owner; knot_dname_retain((*to)->owner); (*to)->rclass = from->rclass; (*to)->ttl = from->ttl; (*to)->type = from->type; if (from->rrsigs != NULL) { - ret = knot_rrset_deep_copy(from->rrsigs, &(*to)->rrsigs); + ret = knot_rrset_deep_copy(from->rrsigs, &(*to)->rrsigs, + copy_rdata_dnames); if (ret != KNOT_EOK) { knot_rrset_deep_free(to, 1, 0, 0); return ret; @@ -601,8 +661,19 @@ int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to) /*! \note Order of RDATA will be reversed. */ while (rdata != NULL) { - ret = knot_rrset_add_rdata(*to, knot_rdata_deep_copy(rdata, - knot_rrset_type(from), 1)); + knot_rdata_t *rdata_copy = knot_rdata_deep_copy(rdata, + knot_rrset_type(from), + copy_rdata_dnames); +dbg_rrset_exec_detail( + char *name = knot_dname_to_str(knot_rrset_owner(from)); + dbg_rrset_detail("Copying RDATA from RRSet with owner: %s, type" + ": %s. Old RDATA ptr: %p, new RDATA ptr: %p\n", + name, + knot_rrtype_to_string(knot_rrset_type(from)), + rdata, rdata_copy); + free(name); +); + ret = knot_rrset_add_rdata(*to, rdata_copy); if (ret != KNOT_EOK) { knot_rrset_deep_free(to, 1, 1, 1); return ret; @@ -632,6 +703,7 @@ int knot_rrset_shallow_copy(const knot_rrset_t *from, knot_rrset_t **to) void knot_rrset_rotate(knot_rrset_t *rrset) { + /*! \todo Maybe implement properly one day. */ //rrset->rdata = rrset->rdata->next; } @@ -659,12 +731,6 @@ void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner, return; } -// char *name = knot_dname_to_str(knot_rrset_owner(*rrset)); -// char *type = knot_rrtype_to_string(knot_rrset_type(*rrset)); -// fprintf(stderr, "Deleting RRSet (%p) %s, type %s, rdata: %p\n", -// *rrset, name, type, (*rrset)->rdata); -// free(name); - if (free_rdata) { knot_rdata_t *tmp_rdata; knot_rdata_t *next_rdata; @@ -679,7 +745,6 @@ void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner, tmp_rdata = next_rdata; } -// printf("test: %p\n", tmp_rdata->next->next); assert(tmp_rdata == NULL || tmp_rdata->next == (*rrset)->rdata); @@ -693,10 +758,7 @@ void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner, free_rdata_dnames); } - /*! \todo Release owner every time? */ - //if (free_owner) { - knot_dname_release((*rrset)->owner); - //} + knot_dname_release((*rrset)->owner); free(*rrset); *rrset = NULL; @@ -711,8 +773,7 @@ int knot_rrset_merge(void **r1, void **r2) if ((knot_dname_compare(rrset1->owner, rrset2->owner) != 0) || rrset1->rclass != rrset2->rclass - || rrset1->type != rrset2->type - || rrset1->ttl != rrset2->ttl) { + || rrset1->type != rrset2->type) { return KNOT_EBADARG; } @@ -744,6 +805,155 @@ int knot_rrset_merge(void **r1, void **r2) } tmp_rdata->next = rrset1->rdata; + rrset2->rdata = rrset1->rdata; + + return KNOT_EOK; +} + +int knot_rrset_merge_no_dupl(void **r1, void **r2) +{ + if (r1 == NULL || r2 == NULL) { + dbg_rrset("rrset: merge_no_dupl: NULL arguments."); + return KNOT_EBADARG; + } + + knot_rrset_t *rrset1 = (knot_rrset_t *)(*r1); + knot_rrset_t *rrset2 = (knot_rrset_t *)(*r2); + if (rrset1 == NULL || rrset2 == NULL) { + dbg_rrset("rrset: merge_no_dupl: NULL arguments."); + return KNOT_EBADARG; + } + +dbg_rrset_exec_detail( + char *name = knot_dname_to_str(rrset1->owner); + dbg_rrset_detail("rrset: merge_no_dupl: Merging %s.\n", name); + free(name); +); + + if ((knot_dname_compare(rrset1->owner, rrset2->owner) != 0) + || rrset1->rclass != rrset2->rclass + || rrset1->type != rrset2->type) { + dbg_rrset("rrset: merge_no_dupl: Trying to merge " + "different RRs.\n"); + return KNOT_EBADARG; + } + + knot_rdata_t *walk2 = rrset2->rdata; + + // no RDATA in RRSet 1 + if (rrset1->rdata == NULL && rrset2->rdata != NULL) { + /* + * This function has to assure that there are no duplicates in + * second RRSet's list. This can be done by putting a first + * item from the second list as a first item of the first list + * and then simply continuing with inserting items from second + * list to the first one. + * + * However, we must store pointer to second item in the second + * list, as the 'next' pointer of the first item will be altered + */ + + // Store pointer to the second item in RRSet2 RDATA so that + // we later start from this item. + walk2 = knot_rrset_rdata_get_next(rrset2, walk2); + assert(walk2 == rrset2->rdata->next || walk2 == NULL); + + // Connect the first item from second list to the first list. + rrset1->rdata = rrset2->rdata; + // Close the cyclic list (by pointing to itself). + rrset1->rdata->next = rrset1->rdata; + } else if (rrset2->rdata == NULL) { + return KNOT_EOK; + } + + /* + * Check that rrset1 does not contain any rdata from rrset2, if so + * such RDATA shall not be inserted. + */ + + /* Get last RDATA from first rrset, we'll need it for insertion. */ + knot_rdata_t *insert_after = rrset1->rdata; + while (insert_after->next != rrset1->rdata) { + dbg_rrset_detail("rrset: merge_dupl: first rrset rdata: %p.\n", + insert_after); + insert_after = insert_after->next; + } + assert(insert_after->next == rrset1->rdata); + + while (walk2 != NULL) { + knot_rdata_t *walk1 = rrset1->rdata; + char dupl = 0; + while ((walk1 != NULL) && + !dupl) { + const knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrset1->type); + assert(desc); + /* If walk1 and walk2 are equal, do not insert. */ + dupl = !knot_rdata_compare(walk1, walk2, + desc->wireformat); + walk1 = knot_rrset_rdata_get_next(rrset1, walk1); + dbg_rrset_detail("rrset: merge_dupl: next item: %p.\n", + walk1); + } + if (!dupl) { + dbg_rrset_detail("rrset: merge_dupl: Inserting " + "unique item (%p).\n", + walk2); + knot_rdata_t *tmp = walk2; + /* + * We need to move this, insertion + * will corrupt pointers. + */ + walk2 = knot_rrset_rdata_get_next(rrset2, walk2); + /* Insert this item at the end of first list. */ + tmp->next = insert_after->next; + insert_after->next = tmp; + insert_after = tmp; + /*!< \todo This message has to be removed after bugfix. */ + dbg_rrset_detail("rrset: merge_no_dupl: Insert after=%p" + ", tmp=%p, tmp->next=%p, " + " rrset1->rdata=%p" + "\n", + insert_after, tmp, tmp->next, + rrset1->rdata); + assert(tmp->next == rrset1->rdata); + } else { + dbg_rrset_detail("rrset: merge_dupl: Skipping and " + "freeing duplicated item " + "of type: %s (%p).\n", + knot_rrtype_to_string(rrset1->type), + walk2); + /* + * Not freeing this item will result in a leak. + * Since this operation destroys the second + * list, we have to free the item here. + */ + knot_rdata_t *tmp = walk2; + dbg_rrset_detail("rrset: merge_dupl: freeing: %p.\n", + tmp); + walk2 = knot_rrset_rdata_get_next(rrset2, walk2); + knot_rdata_deep_free(&tmp, rrset1->type, 1); + assert(tmp == NULL); + /* Maybe caller should be warned about this. */ + } + } + + assert(walk2 == NULL); +dbg_rrset_exec_detail( + dbg_rrset_detail("rrset: merge_dupl: RDATA after merge:\n "); + knot_rdata_t *walk1 = rrset1->rdata; + while (walk1 != NULL) { + dbg_rrset_detail("%p ->\n", walk1); + walk1 = knot_rrset_rdata_get_next(rrset1, walk1); + } + dbg_rrset_detail("rrset: merge_dupl: RDATA after merge: r1:%p r2: %p\n", + rrset1->rdata, rrset2->rdata); +); + /* + * Since there is a possibility of corrupted list for second RRSet, it + * is safer to set its list to NULL, so that it cannot be used. + */ + rrset2->rdata = NULL; return KNOT_EOK; } diff --git a/src/libknot/rrset.h b/src/libknot/rrset.h index b5c11dc..36d8da5 100644..100755 --- a/src/libknot/rrset.h +++ b/src/libknot/rrset.h @@ -105,6 +105,21 @@ knot_rrset_t *knot_rrset_new(knot_dname_t *owner, uint16_t type, */ int knot_rrset_add_rdata(knot_rrset_t *rrset, knot_rdata_t *rdata); +/*! + * \brief Adds the given RDATA to the RRSet but will not insert duplicated data. + * + * \warning Should be only used to insert one RDATA. (NO lists) + * + * \param rrset RRSet to add the RDATA to. + * \param rdata RDATA to add to the RRSet. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + * + * \todo Provide some function for comparing RDATAs. + */ +int knot_rrset_add_rdata_order(knot_rrset_t *rrset, knot_rdata_t *rdata); + knot_rdata_t * knot_rrset_remove_rdata(knot_rrset_t *rrset, const knot_rdata_t *rdata); @@ -249,7 +264,8 @@ int knot_rrset_compare(const knot_rrset_t *r1, knot_rrset_compare_type_t cmp); /*! \todo Add unit test. */ -int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to); +int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to, + int copy_rdata_dnames); /*! \todo Add unit test. */ int knot_rrset_shallow_copy(const knot_rrset_t *from, knot_rrset_t **to); @@ -296,9 +312,9 @@ void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner, * \brief Merges two RRSets. * * Merges \a r1 into \a r2 by concatenating the list of RDATAs in \a r2 after - * the list of RDATAs in \a r1. \a r2 is unaffected by this, though you must not - * destroy the RDATAs in \a r2 as they are now also in \a r1. (You may use - * function knot_rrset_free() though, as it does not touch RDATAs). + * the list of RDATAs in \a r1. You must not + * destroy the RDATAs in \a r2 as they are now identical to RDATAs in \a r1. + * (You may use function knot_rrset_free() though, as it does not touch RDATAs). * * \note Member \a rrsigs is preserved from the first RRSet. * @@ -311,6 +327,26 @@ void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner, */ int knot_rrset_merge(void **r1, void **r2); + +/*! + * \brief Merges two RRSets, but will discard and free any duplicates in \a r2. + * + * Merges \a r1 into \a r2 by concatenating the list of RDATAs in \a r2 after + * the list of RDATAs in \a r1. You must not + * destroy the RDATAs in \a r2 as they are now identical to RDATAs in \a r1. + * (You may use function knot_rrset_free() though, as it does not touch RDATAs). + * + * \note Member \a rrsigs is preserved from the first RRSet. + * + * \param r1 Pointer to RRSet to be merged into. + * \param r2 Poitner to RRSet to be merged. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG if the RRSets could not be merged, because their + * Owner, Type, Class or TTL does not match. + */ +int knot_rrset_merge_no_dupl(void **r1, void **r2); + #endif /* _KNOT_RRSET_H_ */ /*! @} */ diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c index 148fc87..173538c 100644..100755 --- a/src/libknot/tsig-op.c +++ b/src/libknot/tsig-op.c @@ -21,20 +21,27 @@ #include <time.h> #include "common.h" +#include "common/base64.h" #include "tsig.h" #include "tsig-op.h" #include "util/wire.h" -#include "libknot/util/conv.h" #include "util/error.h" #include "util/debug.h" #include "consts.h" const int KNOT_TSIG_MAX_DIGEST_SIZE = 64; // size of HMAC-SHA512 digest - +const uint16_t KNOT_TSIG_FUDGE_DEFAULT = 300; // default Fudge value +enum b64_const { + B64BUFSIZE = 65535 +}; static int knot_tsig_check_algorithm(const knot_rrset_t *tsig_rr) { + if (tsig_rr == NULL) { + return KNOT_EBADARG; + } + const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig_rr); if (!alg_name) { return KNOT_EMALF; @@ -53,6 +60,10 @@ static int knot_tsig_check_algorithm(const knot_rrset_t *tsig_rr) static int knot_tsig_check_key(const knot_rrset_t *tsig_rr, const knot_key_t *tsig_key) { + if (tsig_rr == NULL || tsig_key == NULL) { + return KNOT_EBADARG; + } + const knot_dname_t *tsig_name = knot_rrset_owner(tsig_rr); if (!tsig_name) { return KNOT_EMALF; @@ -94,28 +105,25 @@ static int knot_tsig_compute_digest(const uint8_t *wire, size_t wire_len, return KNOT_TSIG_EBADSIG; } - /* Create digest, using length of the algorithm. */ -// *digest = malloc(sizeof(uint8_t) * tsig_alg_digest_length(tsig_alg)); -// if (!digest) { -// ERR_ALLOC_FAILED; -// return KNOT_ENOMEM; -// } - /* Decode key from Base64. */ char decoded_key[B64BUFSIZE]; - - int decoded_key_size = b64_pton(key->secret, (uint8_t *)decoded_key, - B64BUFSIZE); + + size_t decoded_key_size = B64BUFSIZE; + int ret = base64_decode(key->secret, strlen(key->secret), + decoded_key, + &decoded_key_size); + if (ret != 1) { + dbg_tsig("TSIG: New decode function failed! (%d)\n", ret); + return KNOT_ERROR; + } + if (decoded_key_size < 0) { dbg_tsig("TSIG: Could not decode Base64\n"); return KNOT_ERROR; } - + dbg_tsig_detail("TSIG: decoded key size: %d\n", decoded_key_size); dbg_tsig_detail("TSIG: decoded key: '%*s'\n", decoded_key_size, decoded_key); - -// dbg_tsig_detail("TSIG: using this wire for digest calculation\n"); -// dbg_tsig_hex_detail(wire, wire_len); dbg_tsig_detail("Wire for signing is %zu bytes long.\n", wire_len); /* Compute digest. */ @@ -152,6 +160,7 @@ static int knot_tsig_check_time_signed(const knot_rrset_t *tsig_rr, uint64_t prev_time_signed) { if (!tsig_rr) { + dbg_tsig("TSIG: check_time_signed: NULL argument.\n"); return KNOT_EBADARG; } @@ -184,21 +193,14 @@ static int knot_tsig_check_time_signed(const knot_rrset_t *tsig_rr, return KNOT_EOK; } -static int knot_tsig_write_tsig_timers(uint8_t *wire, - const knot_rrset_t *tsig_rr) -{ - // put time signed - knot_wire_write_u48(wire, tsig_rdata_time_signed(tsig_rr)); - - // put fudge - knot_wire_write_u16(wire + 6, tsig_rdata_fudge(tsig_rr)); - - return KNOT_EOK; -} - static int knot_tsig_write_tsig_variables(uint8_t *wire, const knot_rrset_t *tsig_rr) { + if (wire == NULL || tsig_rr == NULL) { + dbg_tsig("TSIG: write tsig variables: NULL arguments.\n"); + return KNOT_EBADARG; + } + /* Copy TSIG variables - starting with key name. */ const knot_dname_t *tsig_owner = knot_rrset_owner(tsig_rr); if (!tsig_owner) { @@ -210,24 +212,23 @@ static int knot_tsig_write_tsig_variables(uint8_t *wire, memcpy(wire + offset, knot_dname_name(tsig_owner), sizeof(uint8_t) * knot_dname_size(tsig_owner)); - dbg_tsig("TSIG: write variables: written owner (tsig alg): \n"); - /*knot_rrset_class(tsig_rr));*/ - dbg_tsig_hex_detail(wire + offset, knot_dname_size(tsig_owner)); + dbg_tsig_verb("TSIG: write variables: written owner (tsig alg): \n"); + dbg_tsig_hex_verb(wire + offset, knot_dname_size(tsig_owner)); offset += knot_dname_size(tsig_owner); /*!< \todo which order? */ /* Copy class. */ knot_wire_write_u16(wire + offset, knot_rrset_class(tsig_rr)); - dbg_tsig("TSIG: write variables: written CLASS: %u - ", - knot_rrset_class(tsig_rr)); + dbg_tsig_verb("TSIG: write variables: written CLASS: %u - ", + knot_rrset_class(tsig_rr)); dbg_tsig_hex_detail(wire + offset, sizeof(uint16_t)); offset += sizeof(uint16_t); /* Copy TTL - always 0. */ knot_wire_write_u32(wire + offset, knot_rrset_ttl(tsig_rr)); - dbg_tsig("TSIG: write variables: written TTL: %u - ", - knot_rrset_ttl(tsig_rr)); + dbg_tsig_verb("TSIG: write variables: written TTL: %u - ", + knot_rrset_ttl(tsig_rr)); dbg_tsig_hex_detail(wire + offset, sizeof(uint32_t)); offset += sizeof(uint32_t); @@ -237,28 +238,25 @@ static int knot_tsig_write_tsig_variables(uint8_t *wire, dbg_tsig("TSIG: write variables: no algorithm name.\n"); return KNOT_EBADARG; } -// alg_name = knot_dname_new_from_str("HMAC-MD5.SIG-ALG.REG.INT.", - //strlen("HMAC-MD5.SIG-ALG.REG.INT."), - //NULL); memcpy(wire + offset, knot_dname_name(alg_name), sizeof(uint8_t) * knot_dname_size(alg_name)); offset += knot_dname_size(alg_name); - dbg_tsig_detail("TSIG: write variables: written alg name: %s\n", - knot_dname_to_str(alg_name)); + dbg_tsig_verb("TSIG: write variables: written alg name: %s\n", + knot_dname_to_str(alg_name)); /* Following data are written in network order. */ /* Time signed. */ knot_wire_write_u48(wire + offset, tsig_rdata_time_signed(tsig_rr)); offset += 6; - dbg_tsig_detail("TSIG: write variables: time signed: %llu - ", - tsig_rdata_time_signed(tsig_rr)); + dbg_tsig_verb("TSIG: write variables: time signed: %llu - ", + tsig_rdata_time_signed(tsig_rr)); dbg_tsig_hex_detail(wire + offset - 6, 6); /* Fudge. */ knot_wire_write_u16(wire + offset, tsig_rdata_fudge(tsig_rr)); offset += sizeof(uint16_t); - dbg_tsig_detail("TSIG: write variables: fudge: %hu\n", - tsig_rdata_fudge(tsig_rr)); + dbg_tsig_verb("TSIG: write variables: fudge: %hu\n", + tsig_rdata_fudge(tsig_rr)); /* TSIG error. */ knot_wire_write_u16(wire + offset, tsig_rdata_error(tsig_rr)); offset += sizeof(uint16_t); @@ -279,7 +277,7 @@ static int knot_tsig_write_tsig_variables(uint8_t *wire, offset += sizeof(uint16_t); /* Skip the length. */ - dbg_tsig_detail("Copying other data.\n"); + dbg_tsig_verb("Copying other data.\n"); memcpy(wire + offset, other_data, other_data_length); return KNOT_EOK; @@ -288,7 +286,14 @@ static int knot_tsig_write_tsig_variables(uint8_t *wire, static int knot_tsig_wire_write_timers(uint8_t *wire, const knot_rrset_t *tsig_rr) { + if (wire == NULL || tsig_rr == NULL) { + dbg_tsig("TSIG: write timers: NULL arguments.\n"); + return KNOT_EBADARG; + } + + //write time signed knot_wire_write_u48(wire, tsig_rdata_time_signed(tsig_rr)); + //write fudge knot_wire_write_u16(wire + 6, tsig_rdata_fudge(tsig_rr)); return KNOT_EOK; @@ -308,21 +313,14 @@ static int knot_tsig_create_sign_wire(const uint8_t *msg, size_t msg_len, /* Create tmp TSIG. */ int ret = KNOT_EOK; -// knot_rrset_t *tmp_tsig = -// knot_rrset_new(key->name, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0); -// if (!tmp_tsig) { -// return KNOT_ENOMEM; -// } - -// tsig_rdata_store_current_time(tmp_tsig); /* * Create tmp wire, it should contain message * plus request mac plus tsig varibles. */ - dbg_tsig("Counting wire size: %zu, %zu, %zu.\n", - msg_len, request_mac_len, - tsig_rdata_tsig_variables_length(tmp_tsig)); + dbg_tsig_verb("Counting wire size: %zu, %zu, %zu.\n", + msg_len, request_mac_len, + tsig_rdata_tsig_variables_length(tmp_tsig)); size_t wire_len = sizeof(uint8_t) * (msg_len + request_mac_len + ((request_mac_len > 0) ? 2 : 0) + @@ -339,23 +337,21 @@ static int knot_tsig_create_sign_wire(const uint8_t *msg, size_t msg_len, /* Copy the request MAC - should work even if NULL. */ if (request_mac_len > 0) { - dbg_tsig_detail("Copying request MAC size\n"); + dbg_tsig_verb("Copying request MAC size\n"); knot_wire_write_u16(pos, request_mac_len); pos += 2; } - dbg_tsig("Copying request mac.\n"); + dbg_tsig_verb("Copying request mac.\n"); memcpy(pos, request_mac, sizeof(uint8_t) * request_mac_len); dbg_tsig_detail("TSIG: create wire: request mac: "); dbg_tsig_hex_detail(pos, request_mac_len); pos += request_mac_len; /* Copy the original message. */ - dbg_tsig("Copying original message.\n"); + dbg_tsig_verb("Copying original message.\n"); memcpy(pos, msg, msg_len); - dbg_tsig_detail("TSIG: create wire: original message: \n"); - //dbg_tsig_hex_detail(pos, msg_len); pos += msg_len; /* Copy TSIG variables. */ - dbg_tsig("Writing TSIG variables.\n"); + dbg_tsig_verb("Writing TSIG variables.\n"); ret = knot_tsig_write_tsig_variables(pos, tmp_tsig); if (ret != KNOT_EOK) { dbg_tsig("TSIG: create wire: failed to write TSIG " @@ -375,20 +371,8 @@ static int knot_tsig_create_sign_wire(const uint8_t *msg, size_t msg_len, return ret; } -// assert(digest_tmp_len > 0); free(wire); -// if (digest_tmp_len > *digest_len) { -// *digest_len = 0; -// return KNOT_ESPACE; -// } - -// knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); - - // everything went ok, save the digest to the output parameter -// memcpy(digest, digest_tmp, digest_tmp_len); -// *digest_len = digest_tmp_len; - return KNOT_EOK; } @@ -411,9 +395,9 @@ static int knot_tsig_create_sign_wire_next(const uint8_t *msg, size_t msg_len, * Create tmp wire, it should contain message * plus request mac plus tsig varibles. */ - dbg_tsig("Counting wire size: %zu, %zu, %zu.\n", - msg_len, prev_mac_len, - tsig_rdata_tsig_timers_length()); + dbg_tsig_verb("Counting wire size: %zu, %zu, %zu.\n", + msg_len, prev_mac_len, + tsig_rdata_tsig_timers_length()); size_t wire_len = sizeof(uint8_t) * (msg_len + prev_mac_len + tsig_rdata_tsig_timers_length() + 2); @@ -426,27 +410,24 @@ static int knot_tsig_create_sign_wire_next(const uint8_t *msg, size_t msg_len, memset(wire, 0, wire_len); /* Copy the request MAC - should work even if NULL. */ - dbg_tsig("Copying request mac size.\n"); + dbg_tsig_verb("Copying request mac size.\n"); knot_wire_write_u16(wire, prev_mac_len); - dbg_tsig("Copying request mac.\n"); + dbg_tsig_verb("Copying request mac.\n"); memcpy(wire + 2, prev_mac, sizeof(uint8_t) * prev_mac_len); dbg_tsig_detail("TSIG: create wire: request mac: "); dbg_tsig_hex_detail(wire + 2, prev_mac_len); /* Copy the original message. */ - dbg_tsig("Copying original message.\n"); + dbg_tsig_verb("Copying original message.\n"); memcpy(wire + prev_mac_len + 2, msg, msg_len); - dbg_tsig_detail("TSIG: create wire: original message: \n"); - //dbg_tsig_hex_detail(wire + prev_mac_len, msg_len); /* Copy TSIG variables. */ - dbg_tsig("Writing TSIG timers.\n"); - ret = knot_tsig_write_tsig_timers(wire + prev_mac_len + msg_len + 2, + dbg_tsig_verb("Writing TSIG timers.\n"); + ret = knot_tsig_wire_write_timers(wire + prev_mac_len + msg_len + 2, tmp_tsig); -// ret = knot_tsig_write_tsig_variables(wire + prev_mac_len + msg_len, -// tmp_tsig); if (ret != KNOT_EOK) { dbg_tsig("TSIG: create wire: failed to write TSIG " "timers: %s\n", knot_strerror(ret)); + free(wire); return ret; } @@ -457,6 +438,7 @@ static int knot_tsig_create_sign_wire_next(const uint8_t *msg, size_t msg_len, dbg_tsig("TSIG: create wire: failed to compute digest: %s\n", knot_strerror(ret)); *digest_len = 0; + free(wire); return ret; } @@ -478,7 +460,7 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, knot_dname_t *key_name_copy = knot_dname_deep_copy(key->name); if (!key_name_copy) { - dbg_tsig_detail("TSIG: key_name_copy = NULL\n"); + dbg_tsig("TSIG: key_name_copy = NULL\n"); return KNOT_ENOMEM; } @@ -488,14 +470,14 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, /* Should be retained by rrsig or freed, release. */ knot_dname_release(key_name_copy); if (!tmp_tsig) { - dbg_tsig_detail("TSIG: tmp_tsig = NULL\n"); + dbg_tsig("TSIG: tmp_tsig = NULL\n"); return KNOT_ENOMEM; } /* Create rdata for TSIG RR. */ knot_rdata_t *rdata = knot_rdata_new(); if (!rdata) { - dbg_tsig_detail("TSIG: rdata = NULL\n"); + dbg_tsig("TSIG: rdata = NULL\n"); knot_rrset_free(&tmp_tsig); return KNOT_ENOMEM; } @@ -510,7 +492,7 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, knot_rdata_item_t *items = malloc(sizeof(knot_rdata_item_t) * desc->length); if (!items) { - dbg_tsig_detail("TSIG: items = NULL\n"); + dbg_tsig("TSIG: items = NULL\n"); ERR_ALLOC_FAILED; knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); @@ -521,7 +503,8 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, int ret = knot_rdata_set_items(rdata, items, desc->length); if (ret != KNOT_EOK) { - dbg_tsig_detail("TSIG: rdata_set_items returned %s\n", knot_strerror(ret)); + dbg_tsig("TSIG: rdata_set_items returned %s\n", + knot_strerror(ret)); free(items); knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); @@ -554,7 +537,7 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, tsig_rdata_set_other_data(tmp_tsig, 0, 0); } - tsig_rdata_set_fudge(tmp_tsig, 300); /*! \todo Bleeding eyes :-) */ + tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT); /* Set original ID */ tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg)); @@ -583,13 +566,11 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, int rr_count = 0; tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp); - //knot_rrset_dump(tmp_tsig, 1); - /* Write RRSet to wire */ ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len, &tsig_wire_len, &rr_count); if (ret != KNOT_EOK) { - dbg_tsig_detail("TSIG: rrset_to_wire = %s\n", knot_strerror(ret)); + dbg_tsig("TSIG: rrset_to_wire = %s\n", knot_strerror(ret)); *digest_len = 0; knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); @@ -633,7 +614,7 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, /* Create rdata for TSIG RR. */ knot_rdata_t *rdata = knot_rdata_new(); if (!rdata) { - dbg_tsig_detail("TSIG: rdata = NULL\n"); + dbg_tsig("TSIG: rdata = NULL\n"); knot_rrset_free(&tmp_tsig); return KNOT_ENOMEM; } @@ -642,7 +623,7 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, ret = knot_rrset_add_rdata(tmp_tsig, rdata); if (ret != KNOT_EOK) { - dbg_tsig_detail("TSIG: could not add rdata\n"); + dbg_tsig("TSIG: could not add rdata\n"); knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); return ret; @@ -656,7 +637,7 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, knot_rdata_item_t *items = malloc(sizeof(knot_rdata_item_t) * desc->length); if (!items) { - dbg_tsig_detail("TSIG: items = NULL\n"); + dbg_tsig("TSIG: items = NULL\n"); ERR_ALLOC_FAILED; knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); @@ -667,7 +648,8 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, ret = knot_rdata_set_items(rdata, items, desc->length); if (ret != KNOT_EOK) { - dbg_tsig_detail("TSIG: rdata_set_items returned %s\n", knot_strerror(ret)); + dbg_tsig("TSIG: rdata_set_items returned %s\n", + knot_strerror(ret)); knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); free(items); @@ -676,7 +658,7 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, free(items); tsig_rdata_store_current_time(tmp_tsig); - tsig_rdata_set_fudge(tmp_tsig, 300); + tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT); /* Create wire to be signed. */ size_t wire_len = prev_digest_len + to_sign_len @@ -739,8 +721,8 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, /* Set other data. */ tsig_rdata_set_other_data(tmp_tsig, 0, NULL); - dbg_tsig_detail("Message max length: %zu, message length: %zu\n", - msg_max_len, *msg_len); + dbg_tsig_verb("Message max length: %zu, message length: %zu\n", + msg_max_len, *msg_len); size_t tsig_wire_size = msg_max_len - *msg_len; int rr_count = 0; @@ -788,7 +770,7 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr, return ret; } - dbg_tsig("TSIG: time checked.\n"); + dbg_tsig_verb("TSIG: time checked.\n"); /* Check that libknot knows the algorithm. */ ret = knot_tsig_check_algorithm(tsig_rr); @@ -796,7 +778,7 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr, return ret; } - dbg_tsig("TSIG: algorithm checked.\n"); + dbg_tsig_verb("TSIG: algorithm checked.\n"); /* Check that key is valid, ie. the same as given in args. */ ret = knot_tsig_check_key(tsig_rr, tsig_key); @@ -804,22 +786,15 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr, return ret; } - dbg_tsig("TSIG: key validity checked.\n"); + dbg_tsig_verb("TSIG: key validity checked.\n"); /* Time OK algorithm OK, key name OK - do digest. */ /* Calculate the size of TSIG RR. */ size_t tsig_len = tsig_wire_actsize(tsig_rr); - dbg_tsig_detail("TSIG: check digest: wire before strip: \n"); - //dbg_tsig_hex_detail(wire, size); - /* Strip the TSIG. */ size -= tsig_len; - dbg_tsig_detail("TSIG: check digest: wire after strip (stripped %zu):\n", - tsig_len); - //dbg_tsig_hex_detail(wire, size); - uint8_t *wire_to_sign = malloc(sizeof(uint8_t) * size); if (!wire_to_sign) { ERR_ALLOC_FAILED; @@ -858,16 +833,7 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr, return ret; } -// uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE]; -// size_t digest_tmp_len = 0; -// ret = knot_tsig_compute_digest(wire, size, digest_tmp, -// &digest_tmp_len, tsig_key); -// if (ret != KNOT_EOK) { -// dbg_tsig("TSIG: digest could not be calculated\n"); -// return ret; -// } - - dbg_tsig("TSIG: digest calculated\n"); + dbg_tsig_verb("TSIG: digest calculated\n"); /* Compare MAC from TSIG RR RDATA with just computed digest. */ @@ -880,17 +846,16 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr, const uint8_t *tsig_mac = tsig_rdata_mac(tsig_rr); if (mac_length != tsig_alg_digest_length(alg)) { - dbg_tsig("TSIG: calculated digest length and given length do not match!\n"); + dbg_tsig("TSIG: calculated digest length and given length do " + "not match!\n"); return KNOT_TSIG_EBADSIG; } -// assert(tsig_alg_digest_length(alg) == mac_length); - - dbg_tsig("TSIG: calc digest : "); - dbg_tsig_hex(digest_tmp, digest_tmp_len); + dbg_tsig_verb("TSIG: calc digest : "); + dbg_tsig_hex_verb(digest_tmp, digest_tmp_len); - dbg_tsig("TSIG: given digest: "); - dbg_tsig_hex(tsig_mac, mac_length); + dbg_tsig_verb("TSIG: given digest: "); + dbg_tsig_hex_verb(tsig_mac, mac_length); if (strncasecmp((char *)(tsig_mac), (char *)digest_tmp, mac_length) != 0) { @@ -904,7 +869,7 @@ int knot_tsig_server_check(const knot_rrset_t *tsig_rr, const uint8_t *wire, size_t size, const knot_key_t *tsig_key) { - dbg_tsig_verb("tsig_server_check()\n"); + dbg_tsig("tsig_server_check()\n"); return knot_tsig_check_digest(tsig_rr, wire, size, NULL, 0, tsig_key, 0, 0); } @@ -915,7 +880,7 @@ int knot_tsig_client_check(const knot_rrset_t *tsig_rr, const knot_key_t *tsig_key, uint64_t prev_time_signed) { - dbg_tsig_verb("tsig_client_check()\n"); + dbg_tsig("tsig_client_check()\n"); return knot_tsig_check_digest(tsig_rr, wire, size, request_mac, request_mac_len, tsig_key, prev_time_signed, 0); @@ -928,9 +893,7 @@ int knot_tsig_client_check_next(const knot_rrset_t *tsig_rr, const knot_key_t *tsig_key, uint64_t prev_time_signed) { -// return knot_tsig_client_check(tsig_rr, wire, size, prev_digest, -// prev_digest_len, tsig_key); - dbg_tsig_verb("tsig_client_check_next()\n"); + dbg_tsig("tsig_client_check_next()\n"); return knot_tsig_check_digest(tsig_rr, wire, size, prev_digest, prev_digest_len, tsig_key, prev_time_signed, 1); @@ -950,15 +913,14 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, knot_dname_t *key_name = knot_dname_deep_copy(knot_rrset_owner(tsig_rr)); if (key_name == NULL) { - dbg_tsig_detail("TSIG: failed to copy owner\n"); + dbg_tsig("TSIG: failed to copy owner\n"); return KNOT_ERROR; } knot_rrset_t *tmp_tsig = - knot_rrset_new(key_name, - KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0); + knot_rrset_new(key_name, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0); if (!tmp_tsig) { - dbg_tsig_detail("TSIG: tmp_tsig = NULL\n"); + dbg_tsig("TSIG: tmp_tsig = NULL\n"); knot_dname_free(&key_name); return KNOT_ENOMEM; } @@ -966,7 +928,7 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, /* Create rdata for TSIG RR. */ knot_rdata_t *rdata = knot_rdata_new(); if (!rdata) { - dbg_tsig_detail("TSIG: rdata = NULL\n"); + dbg_tsig("TSIG: rdata = NULL\n"); knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); return KNOT_ENOMEM; } @@ -981,7 +943,7 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, knot_rdata_item_t *items = malloc(sizeof(knot_rdata_item_t) * desc->length); if (items == NULL) { - dbg_tsig_detail("TSIG: items = NULL\n"); + dbg_tsig("TSIG: items = NULL\n"); ERR_ALLOC_FAILED; knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); return KNOT_ENOMEM; @@ -992,8 +954,8 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, int ret = knot_rdata_set_items(rdata, items, desc->length); free(items); if (ret != KNOT_EOK) { - dbg_tsig_detail("TSIG: rdata_set_items returned %s\n", - knot_strerror(ret)); + dbg_tsig("TSIG: rdata_set_items returned %s\n", + knot_strerror(ret)); knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); return ret; } @@ -1001,14 +963,18 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, knot_dname_t *alg_name = knot_dname_deep_copy(tsig_rdata_alg_name(tsig_rr)); if (alg_name == NULL) { - dbg_tsig_detail("TSIG: failed to copy alg name\n"); + dbg_tsig("TSIG: failed to copy alg name\n"); knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); return KNOT_ERROR; } tsig_rdata_set_alg_name(tmp_tsig, alg_name); tsig_rdata_set_time_signed(tmp_tsig, tsig_rdata_time_signed(tsig_rr)); - tsig_rdata_set_fudge(tmp_tsig, tsig_rdata_fudge(tsig_rr)); + + /* Comparing to BIND it was found out that the Fudge should always be + * set to the server's value. + */ + tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT); tsig_rdata_set_mac(tmp_tsig, 0, NULL); knot_dname_release(alg_name); /* Already copied in tsig_rdata_set_alg_name() */ @@ -1029,7 +995,7 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len, &tsig_wire_len, &rr_count); if (ret != KNOT_EOK) { - dbg_tsig_detail("TSIG: rrset_to_wire = %s\n", knot_strerror(ret)); + dbg_tsig("TSIG: rrset_to_wire = %s\n", knot_strerror(ret)); knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); return ret; } diff --git a/src/libknot/tsig-op.h b/src/libknot/tsig-op.h index 07a84a8..07a84a8 100644..100755 --- a/src/libknot/tsig-op.h +++ b/src/libknot/tsig-op.h diff --git a/src/libknot/tsig.c b/src/libknot/tsig.c index e8df92e..86b7f9d 100644..100755 --- a/src/libknot/tsig.c +++ b/src/libknot/tsig.c @@ -319,21 +319,21 @@ tsig_algorithm_t tsig_rdata_alg(const knot_rrset_t *tsig) /* Get the algorithm name. */ const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig); if (!alg_name) { - dbg_tsig_detail("TSIG: rdata: cannot get algorithm name.\n"); + dbg_tsig("TSIG: rdata: cannot get algorithm name.\n"); return KNOT_TSIG_ALG_NULL; } /* Convert alg name to string. */ char *name = knot_dname_to_str(alg_name); if (!name) { - dbg_tsig_detail("TSIG: rdata: cannot convert alg name.\n"); + dbg_tsig("TSIG: rdata: cannot convert alg name.\n"); return KNOT_TSIG_ALG_NULL; } knot_lookup_table_t *item = knot_lookup_by_name(tsig_alg_table, name); free(name); if (!item) { - dbg_tsig_detail("TSIG: rdata: unknown algorithm.\n"); + dbg_tsig("TSIG: rdata: unknown algorithm.\n"); return KNOT_TSIG_ALG_NULL; } @@ -342,7 +342,7 @@ tsig_algorithm_t tsig_rdata_alg(const knot_rrset_t *tsig) uint64_t tsig_rdata_time_signed(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -366,7 +366,7 @@ uint64_t tsig_rdata_time_signed(const knot_rrset_t *tsig) uint16_t tsig_rdata_fudge(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -390,7 +390,7 @@ uint16_t tsig_rdata_fudge(const knot_rrset_t *tsig) const uint8_t *tsig_rdata_mac(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -424,7 +424,7 @@ size_t tsig_rdata_mac_length(const knot_rrset_t *tsig) uint16_t tsig_rdata_orig_id(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -448,7 +448,7 @@ uint16_t tsig_rdata_orig_id(const knot_rrset_t *tsig) uint16_t tsig_rdata_error(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -472,7 +472,7 @@ uint16_t tsig_rdata_error(const knot_rrset_t *tsig) const uint8_t *tsig_rdata_other_data(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -491,7 +491,7 @@ const uint8_t *tsig_rdata_other_data(const knot_rrset_t *tsig) uint16_t tsig_rdata_other_data_length(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -558,6 +558,9 @@ uint16_t tsig_alg_digest_length(tsig_algorithm_t alg) size_t tsig_rdata_tsig_variables_length(const knot_rrset_t *tsig) { + if (tsig == NULL) { + return 0; + } /* Key name, Algorithm name and Other data have variable lengths. */ const knot_dname_t *key_name = knot_rrset_owner(tsig); if (!key_name) { @@ -569,13 +572,6 @@ size_t tsig_rdata_tsig_variables_length(const knot_rrset_t *tsig) return 0; } -// dbg_tsig_detail("key_name: %.*s (size: %u) alg_name: %.*s (size: %u)\n", knot_dname_size(key_name), -// key_name->name, alg_name->size, alg_name->name, -// key_name->size, alg_name->size); - -// dbg_tsig_hex_detail(key_name->name, key_name->size); -// dbg_tsig_hex_detail(alg_name->name, alg_name->size); - uint16_t other_data_length = tsig_rdata_other_data_length(tsig); return knot_dname_size(key_name) + knot_dname_size(alg_name) + @@ -594,7 +590,7 @@ int tsig_rdata_store_current_time(knot_rrset_t *tsig) return KNOT_EBADARG; } time_t curr_time = time(NULL); - /*!< \todo bleeding eyes. */ + /*! \todo bleeding eyes. */ tsig_rdata_set_time_signed(tsig, (uint64_t)curr_time); return KNOT_EOK; } @@ -612,6 +608,10 @@ const char* tsig_alg_to_str(tsig_algorithm_t alg) size_t tsig_wire_maxsize(const knot_key_t* key) { + if (key == NULL) { + return 0; + } + size_t alg_name_size = strlen(tsig_alg_to_str(key->algorithm)) + 1; return knot_dname_size(key->name) + @@ -632,6 +632,10 @@ size_t tsig_wire_maxsize(const knot_key_t* key) size_t tsig_wire_actsize(const knot_rrset_t *tsig) { + if (tsig == NULL) { + return 0; + } + return knot_dname_size(knot_rrset_owner(tsig)) + sizeof(uint16_t) + /* TYPE */ sizeof(uint16_t) + /* CLASS */ @@ -648,3 +652,12 @@ size_t tsig_wire_actsize(const knot_rrset_t *tsig) tsig_rdata_other_data_length(tsig); } +int tsig_rdata_is_ok(const knot_rrset_t *tsig) +{ + return (tsig + && knot_rrset_rdata(tsig) != NULL + && knot_rdata_item_count(knot_rrset_rdata(tsig)) >= 7 + && tsig_rdata_alg_name(tsig) != NULL + && tsig_rdata_time_signed(tsig) != 0); +} + diff --git a/src/libknot/tsig.h b/src/libknot/tsig.h index 73fa832..249184d 100644..100755 --- a/src/libknot/tsig.h +++ b/src/libknot/tsig.h @@ -140,6 +140,8 @@ uint16_t tsig_alg_digest_length(tsig_algorithm_t alg); size_t tsig_wire_maxsize(const knot_key_t *key); size_t tsig_wire_actsize(const knot_rrset_t *tsig); +int tsig_rdata_is_ok(const knot_rrset_t *tsig); + #endif /* _KNOT_TSIG_H_ */ /*! @} */ diff --git a/src/libknot/updates/changesets.c b/src/libknot/updates/changesets.c index 1c3d3b9..502a858 100644..100755 --- a/src/libknot/updates/changesets.c +++ b/src/libknot/updates/changesets.c @@ -115,23 +115,20 @@ int knot_changeset_add_rr(knot_rrset_t ***rrsets, size_t *count, // try to find the RRSet in the list of RRSets, but search backwards // as it is probable that the last RRSet is the one to which the RR // belongs - int i = *count - 1; - - while (i >= 0 && !knot_changeset_rrsets_match((*rrsets)[i], rr)) { - --i; - } - if (i >= 0) { - // found RRSet to merge the new one into - if (knot_rrset_merge((void **)&(*rrsets)[i], - (void **)&rr) != KNOT_EOK) { + // Just check the last RRSet. If the RR belongs to it, merge it, + // otherwise just add the RR to the end of the list + + if (*count > 0 + && knot_changeset_rrsets_match((*rrsets)[*count - 1], rr)) { + // Create changesets exactly as they came, with possibly + // duplicate records + if (knot_rrset_merge((void **)&(*rrsets)[*count - 1], + (void **)&rr) != KNOT_EOK) { return KNOT_ERROR; } - // remove the RR - /*! \todo does this make sense? */ - knot_rrset_free(&rr); // used to be deep free with all 1's - + knot_rrset_free(&rr); return KNOT_EOK; } else { return knot_changeset_add_rrset(rrsets, count, allocated, rr); @@ -211,7 +208,7 @@ int knot_changeset_add_soa(knot_changeset_t *changeset, knot_rrset_t *soa, int knot_changesets_check_size(knot_changesets_t *changesets) { /* Check if allocated is sufficient. */ - if (changesets->count <= changesets->allocated) { + if (changesets->count < changesets->allocated) { return KNOT_EOK; } @@ -243,7 +240,6 @@ int knot_changesets_check_size(knot_changesets_t *changesets) void knot_free_changeset(knot_changeset_t **changeset) { - /* XXX XXX investigate wrong frees. */ assert((*changeset)->add_allocated >= (*changeset)->add_count); assert((*changeset)->remove_allocated >= (*changeset)->remove_count); assert((*changeset)->allocated >= (*changeset)->size); @@ -292,7 +288,3 @@ void knot_free_changesets(knot_changesets_t **changesets) free(*changesets); *changesets = NULL; } - -/*---------------------------------------------------------------------------*/ - - diff --git a/src/libknot/updates/changesets.h b/src/libknot/updates/changesets.h index 0570fc9..642b155 100644..100755 --- a/src/libknot/updates/changesets.h +++ b/src/libknot/updates/changesets.h @@ -5,7 +5,7 @@ * * \brief Structure for representing IXFR/DDNS changeset and its API. * - * \addtogroup libknot + * \addtogroup xfr * @{ */ /* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> @@ -90,9 +90,9 @@ typedef struct { int new_rdata_count; int new_rdata_allocated; -// /*! -// * Deleted (without contents) after successful update. -// */ + /*! + * Deleted (without contents) after successful update. + */ knot_node_t **old_nodes; int old_nodes_count; int old_nodes_allocated; diff --git a/src/libknot/updates/ddns.c b/src/libknot/updates/ddns.c index 025cd6b..905c44b 100644..100755 --- a/src/libknot/updates/ddns.c +++ b/src/libknot/updates/ddns.c @@ -97,7 +97,7 @@ static int knot_ddns_add_prereq_rrset(const knot_rrset_t *rrset, } knot_rrset_t *new_rrset = NULL; - ret = knot_rrset_deep_copy(rrset, &new_rrset); + ret = knot_rrset_deep_copy(rrset, &new_rrset, 0); if (ret != KNOT_EOK) { return ret; } @@ -202,7 +202,7 @@ static int knot_ddns_add_update(knot_changeset_t *changeset, * copy. */ knot_rrset_t *rrset_copy; - ret = knot_rrset_deep_copy(rrset, &rrset_copy); + ret = knot_rrset_deep_copy(rrset, &rrset_copy, 0); if (ret != KNOT_EOK) { return ret; } diff --git a/src/libknot/updates/ddns.h b/src/libknot/updates/ddns.h index dceebed..35dfcb7 100644..100755 --- a/src/libknot/updates/ddns.h +++ b/src/libknot/updates/ddns.h @@ -5,7 +5,7 @@ * * \brief Dynamic updates processing. * - * \addtogroup query_processing + * \addtogroup ddns * @{ */ /* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> diff --git a/src/libknot/updates/xfr-in.c b/src/libknot/updates/xfr-in.c index ea8178d..c870ece 100644..100755 --- a/src/libknot/updates/xfr-in.c +++ b/src/libknot/updates/xfr-in.c @@ -102,7 +102,7 @@ static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype, if (wire_size > *size) { dbg_xfrin("Not enough space provided for the wire " - "format of the query.\n"); + "format of the query.\n"); knot_packet_free(&pkt); return KNOT_ESPACE; } @@ -112,7 +112,7 @@ static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype, char *name = knot_dname_to_str(xfr->tsig_key->name); dbg_xfrin_detail("Signing XFR query with key (name %s): \n", name); - free(name); + free(name); dbg_xfrin_hex_detail(xfr->tsig_key->secret, xfr->tsig_key->secret_size); @@ -152,9 +152,9 @@ static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype, int xfrin_create_soa_query(knot_dname_t *owner, knot_ns_xfr_t *xfr, size_t *size) { - /*! \todo [TSIG] Should TSIG apply for SOA query too? */ return xfrin_create_query(owner, KNOT_RRTYPE_SOA, - KNOT_CLASS_IN, xfr, size, 0, 0); + KNOT_CLASS_IN, xfr, size, 0, + xfr->tsig_key != NULL); } /*----------------------------------------------------------------------------*/ @@ -164,8 +164,8 @@ int xfrin_transfer_needed(const knot_zone_contents_t *zone, { // first, parse the rest of the packet assert(!knot_packet_is_query(soa_response)); - dbg_xfrin("Response - parsed: %zu, total wire size: %zu\n", - soa_response->parsed, soa_response->size); + dbg_xfrin_verb("Response - parsed: %zu, total wire size: %zu\n", + soa_response->parsed, soa_response->size); int ret; if (soa_response->parsed < soa_response->size) { @@ -199,7 +199,7 @@ dbg_xfrin_exec( dbg_xfrin("Malformed data in SOA of zone %s\n", name); free(name); ); - return KNOT_EMALF; // maybe some other error + return KNOT_EMALF; // maybe some other error } /* @@ -273,8 +273,8 @@ static int xfrin_add_orphan_rrsig(xfrin_orphan_rrsig_t **rrsigs, && knot_rdata_rrsig_type_covered(knot_rrset_rdata( last->rrsig)) == knot_rdata_rrsig_type_covered(knot_rrset_rdata(rr))) { - ret = knot_rrset_merge((void **)&last->rrsig, - (void **)&rr); + ret = knot_rrset_merge_no_dupl((void **)&last->rrsig, + (void **)&rr); if (ret != KNOT_EOK) { return ret; } else { @@ -341,7 +341,7 @@ void xfrin_free_orphan_rrsigs(xfrin_orphan_rrsig_t **rrsigs) } /*----------------------------------------------------------------------------*/ -/*! \note [TSIG] */ + static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr, int tsig_req) { @@ -400,8 +400,8 @@ static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr, } if (ret != KNOT_EOK) { - /*! \note [TSIG] No need to check TSIG error - * here, propagate and check elsewhere.*/ + /* No need to check TSIG error + * here, propagate and check elsewhere.*/ knot_rrset_deep_free(&tsig, 1, 1, 1); return ret; } @@ -425,9 +425,7 @@ static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr, tsig_rdata_time_signed(tsig); - }/* else { // TSIG not required and not there - - }*/ + } } else if (tsig != NULL) { // TSIG where it should not be knot_rrset_deep_free(&tsig, 1, 1, 1); @@ -441,9 +439,7 @@ static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr, /*----------------------------------------------------------------------------*/ -int xfrin_process_axfr_packet(/*const uint8_t *pkt, size_t size, - xfrin_constructed_zone_t **constr*/ - knot_ns_xfr_t *xfr) +int xfrin_process_axfr_packet(knot_ns_xfr_t *xfr) { const uint8_t *pkt = xfr->wire; size_t size = xfr->wire_size; @@ -451,11 +447,10 @@ int xfrin_process_axfr_packet(/*const uint8_t *pkt, size_t size, (xfrin_constructed_zone_t **)(&xfr->data); if (pkt == NULL || constr == NULL) { - dbg_xfrin("Wrong parameters supported.\n"); return KNOT_EBADARG; } - dbg_xfrin("Processing AXFR packet of size %zu.\n", size); + dbg_xfrin_verb("Processing AXFR packet of size %zu.\n", size); // check if the response is OK if (knot_wire_get_rcode(pkt) != KNOT_RCODE_NOERROR) { @@ -473,8 +468,7 @@ int xfrin_process_axfr_packet(/*const uint8_t *pkt, size_t size, int ret = knot_packet_parse_from_wire(packet, pkt, size, 1); if (ret != KNOT_EOK) { - dbg_xfrin("Could not parse packet: %s.\n", - knot_strerror(ret)); + dbg_xfrin("Could not parse packet: %s.\n", knot_strerror(ret)); knot_packet_free(&packet); /*! \todo Cleanup. */ return KNOT_EMALF; @@ -510,18 +504,16 @@ int xfrin_process_axfr_packet(/*const uint8_t *pkt, size_t size, if (*constr == NULL) { // this should be the first packet - /*! \note [TSIG] Packet number for checking TSIG validation. */ + /*! Packet number for checking TSIG validation. */ xfr->packet_nr = 0; -// /*! \note [TSIG] Storing total size of data for TSIG digest. */ -// xfr->tsig_data_size = 0; // create new zone /*! \todo Ensure that the packet is the first one. */ if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) { dbg_xfrin("No zone created, but the first RR in " - "Answer is not a SOA RR.\n"); + "Answer is not a SOA RR.\n"); knot_packet_free(&packet); - knot_node_free(&node, 0); + knot_node_free(&node); knot_rrset_deep_free(&rr, 1, 1, 1); /*! \todo Cleanup. */ return KNOT_EMALF; @@ -543,7 +535,7 @@ dbg_xfrin_exec( ); /*! \todo Cleanup. */ knot_packet_free(&packet); - knot_node_free(&node, 0); + knot_node_free(&node); knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_EMALF; } @@ -564,19 +556,20 @@ dbg_xfrin_exec( if (*constr == NULL) { dbg_xfrin("Failed to create new constr. zone.\n"); knot_packet_free(&packet); - knot_node_free(&node, 0); + knot_node_free(&node); knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_ENOMEM; } memset(*constr, 0, sizeof(xfrin_constructed_zone_t)); - (*constr)->contents = knot_zone_contents_new(node, 0, 1, NULL); -// assert(0); + dbg_xfrin_verb("Creating new zone contents.\n"); + (*constr)->contents = knot_zone_contents_new(node, 0, 1, + xfr->zone); if ((*constr)->contents== NULL) { dbg_xfrin("Failed to create new zone.\n"); knot_packet_free(&packet); - knot_node_free(&node, 0); + knot_node_free(&node); knot_rrset_deep_free(&rr, 1, 1, 1); /*! \todo Cleanup. */ return KNOT_ENOMEM; @@ -588,21 +581,19 @@ dbg_xfrin_exec( assert(zone->apex == node); assert(zone->apex->owner == rr->owner); // add the RRSet to the node - //ret = knot_node_add_rrset(node, rr, 0); ret = knot_zone_contents_add_rrset(zone, rr, &node, KNOT_RRSET_DUPL_MERGE, 1); if (ret < 0) { dbg_xfrin("Failed to add RRSet to zone node: %s.\n", knot_strerror(ret)); knot_packet_free(&packet); - knot_node_free(&node, 0); + knot_node_free(&node); knot_rrset_deep_free(&rr, 1, 1, 1); /*! \todo Cleanup. */ return KNOT_ERROR; } else if (ret > 0) { dbg_xfrin("Merged SOA RRSet.\n"); // merged, free the RRSet - //knot_rrset_deep_free(&rr, 1, 0, 0); knot_rrset_free(&rr); } @@ -613,20 +604,6 @@ dbg_xfrin_exec( ++xfr->packet_nr; } - /*! \note [TSIG] add the packet wire size to the data to be verified by - * TSIG - */ -// if (xfr->tsig_key) { -// dbg_xfrin("Adding packet wire to TSIG data (size till now: %zu," -// " adding: %zu).\n", xfr->tsig_data_size, -// xfr->wire_size); -// assert(KNOT_NS_TSIG_DATA_MAX_SIZE - xfr->tsig_data_size -// >= xfr->wire_size); -// memcpy(xfr->tsig_data + xfr->tsig_data_size, xfr->wire, -// xfr->wire_size); -// xfr->tsig_data_size += xfr->wire_size; -// } - assert(zone != NULL); while (ret == KNOT_EOK && rr != NULL) { @@ -637,9 +614,9 @@ dbg_xfrin_exec( if (node != NULL && knot_dname_compare(rr->owner, node->owner) != 0) { -dbg_xfrin_exec( +dbg_xfrin_exec_detail( char *name = knot_dname_to_str(node->owner); - dbg_xfrin("Node owner: %s\n", name); + dbg_xfrin_detail("Node owner: %s\n", name); free(name); ); if (!in_zone) { @@ -659,16 +636,15 @@ dbg_xfrin_exec( assert(knot_zone_contents_apex((zone)) != NULL); assert(knot_node_rrset(knot_zone_contents_apex((zone)), KNOT_RRTYPE_SOA) != NULL); - dbg_xfrin("Found last SOA, transfer finished.\n"); + dbg_xfrin_verb("Found last SOA, transfer finished.\n"); - dbg_xfrin("Verifying TSIG...\n"); + dbg_xfrin_verb("Verifying TSIG...\n"); /*! \note [TSIG] Now check if there is not a TSIG record * at the end of the packet. */ ret = xfrin_check_tsig(packet, xfr, 1); - dbg_xfrin_detail("xfrin_check_tsig() returned %d\n", - ret); + dbg_xfrin_verb("xfrin_check_tsig() returned %d\n", ret); knot_packet_free(&packet); knot_rrset_deep_free(&rr, 1, 1, 1); @@ -682,8 +658,7 @@ dbg_xfrin_exec( ret = xfrin_process_orphan_rrsigs(zone, (*constr)->rrsigs); if (ret != KNOT_EOK) { - dbg_xfrin("Failed to process orphan " - "RRSIGs\n"); + dbg_xfrin("Failed to process orphan RRSIGs\n"); /*! \todo Cleanup?? */ return ret; } @@ -700,8 +675,8 @@ dbg_xfrin_exec( ret = knot_zone_contents_add_rrsigs(zone, rr, &tmp_rrset, &node, KNOT_RRSET_DUPL_MERGE, 1); if (ret == KNOT_ENONODE || ret == KNOT_ENORRSET) { - dbg_xfrin("No node or RRSet for RRSIGs\n"); - dbg_xfrin("Saving for later insertion.\n"); + dbg_xfrin_verb("No node or RRSet for RRSIGs\n"); + dbg_xfrin_verb("Saving for later insertion.\n"); if (ret == KNOT_ENORRSET) { in_zone = 1; @@ -711,13 +686,13 @@ dbg_xfrin_exec( rr); if (ret > 0) { - dbg_xfrin("Merged RRSIGs.\n"); + dbg_xfrin_detail("Merged RRSIGs.\n"); knot_rrset_free(&rr); } else if (ret != KNOT_EOK) { dbg_xfrin("Failed to save orphan" - " RRSIGs.\n"); + " RRSIGs.\n"); knot_packet_free(&packet); - knot_node_free(&node, 0); // ??? + knot_node_free(&node); // ??? knot_rrset_deep_free(&rr, 1, 1, 1); return ret; } @@ -725,15 +700,15 @@ dbg_xfrin_exec( dbg_xfrin("Failed to add RRSIGs (%s).\n", knot_strerror(ret)); knot_packet_free(&packet); - knot_node_free(&node, 0); // ??? + knot_node_free(&node); // ??? knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_ERROR; /*! \todo Other error code. */ } else if (ret == 1) { assert(node != NULL); dbg_xfrin_exec_verb( char *name = knot_dname_to_str(node->owner); - dbg_xfrin("Found node for the record in " - "zone: %s. Merged.\n", name); + dbg_xfrin_detail("Found node for the record in " + "zone: %s. Merged.\n", name); free(name); ); in_zone = 1; @@ -741,13 +716,12 @@ dbg_xfrin_exec_verb( } else if (ret == 2) { // should not happen assert(0); -// knot_rrset_deep_free(&rr, 1, 1, 1); } else { assert(node != NULL); dbg_xfrin_exec_verb( char *name = knot_dname_to_str(node->owner); - dbg_xfrin("Found node for the record in " - "zone: %s.\n", name); + dbg_xfrin_detail("Found node for the record in " + "zone: %s.\n", name); free(name); ); in_zone = 1; @@ -760,12 +734,12 @@ dbg_xfrin_exec_verb( continue; } - /*! \note [TSIG] TSIG where it should not be - in Answer section.*/ + /* TSIG where it should not be - in Answer section.*/ if (knot_rrset_type(rr) == KNOT_RRTYPE_TSIG) { // not allowed here - dbg_xfrin(" in Answer section.\n"); + dbg_xfrin("TSIG in Answer section.\n"); knot_packet_free(&packet); - knot_node_free(&node, 0); // ??? + knot_node_free(&node); // ??? knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_EMALF; } @@ -786,7 +760,7 @@ dbg_xfrin_exec_verb( if (node == NULL && (node = get_node(zone, knot_rrset_owner(rr))) != NULL) { // the node for this RR was found in the zone - dbg_xfrin("Found node for the record in zone.\n"); + dbg_xfrin_detail("Found node for the record in zone\n"); in_zone = 1; } @@ -800,31 +774,30 @@ dbg_xfrin_exec_verb( knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_ENOMEM; } - dbg_xfrin("Created new node for the record.\n"); + dbg_xfrin_detail("Created new node for the record.\n"); // insert the RRSet to the node - ret = knot_node_add_rrset(node, rr, 1); + ret = knot_node_add_rrset_no_dupl(node, rr); if (ret < 0) { - dbg_xfrin("Failed to add RRSet to node (%s" - ")\n", knot_strerror(ret)); + dbg_xfrin("Failed to add RRSet to node (%s)\n", + knot_strerror(ret)); knot_packet_free(&packet); - knot_node_free(&node, 0); // ??? + knot_node_free(&node); // ??? knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_ERROR; } else if (ret > 0) { // should not happen, this is new node assert(0); -// knot_rrset_deep_free(&rr, 1, 0, 0); } // insert the node into the zone ret = add_node(zone, node, 1, 0, 1); assert(node != NULL); if (ret != KNOT_EOK) { - dbg_xfrin("Failed to add node to zone (%s)" - ".\n", knot_strerror(ret)); + dbg_xfrin("Failed to add node to zone (%s).\n", + knot_strerror(ret)); knot_packet_free(&packet); - knot_node_free(&node, 0); // ??? + knot_node_free(&node); // ??? knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_ERROR; } @@ -837,12 +810,11 @@ dbg_xfrin_exec_verb( KNOT_RRSET_DUPL_MERGE, 1); if (ret < 0) { knot_packet_free(&packet); - dbg_xfrin("Failed to add RRSet to zone:" - "%s.\n", knot_strerror(ret)); + dbg_xfrin("Failed to add RRSet to zone :%s.\n", + knot_strerror(ret)); return KNOT_ERROR; } else if (ret > 0) { // merged, free the RRSet -// knot_rrset_deep_free(&rr, 1, 0, 0); knot_rrset_free(&rr); } @@ -858,12 +830,11 @@ dbg_xfrin_exec_verb( if (ret < 0) { // some error in parsing - dbg_xfrin("Could not parse next RR: %s.\n", - knot_strerror(ret)); + dbg_xfrin("Could not parse next RR: %s.\n", knot_strerror(ret)); knot_packet_free(&packet); if (!in_zone) { - knot_node_free(&node, 0); + knot_node_free(&node); } knot_rrset_deep_free(&rr, 1, 1, 1); @@ -878,25 +849,23 @@ dbg_xfrin_exec_verb( assert(node != NULL); ret = knot_zone_contents_add_node(zone, node, 1, 0, 1); if (ret != KNOT_EOK) { - dbg_xfrin("Failed to add last node into zone (%s)" - ".\n", knot_strerror(ret)); + dbg_xfrin("Failed to add last node into zone (%s).\n", + knot_strerror(ret)); knot_packet_free(&packet); - knot_node_free(&node, 0); + knot_node_free(&node); return KNOT_ERROR; /*! \todo Other error */ } } - /*! \note [TSIG] Now check if there is not a TSIG record at the end of - * the packet. - */ + /* Now check if there is not a TSIG record at the end of the packet. */ ret = xfrin_check_tsig(packet, xfr, knot_ns_tsig_required(xfr->packet_nr)); ++xfr->packet_nr; knot_packet_free(&packet); - dbg_xfrin("Processed one AXFR packet successfully.\n"); + dbg_xfrin_verb("Processed one AXFR packet successfully.\n"); - /*! \note [TSIG] TSIG errors are propagated and reported in a standard + /* TSIG errors are propagated and reported in a standard * manner, as we're in response processing, no further error response * should be sent. */ @@ -920,8 +889,7 @@ static int xfrin_parse_first_rr(knot_packet_t **packet, const uint8_t *pkt, int ret = knot_packet_parse_from_wire(*packet, pkt, size, 1); if (ret != KNOT_EOK) { - dbg_xfrin("Could not parse packet: %s.\n", - knot_strerror(ret)); + dbg_xfrin("Could not parse packet: %s.\n", knot_strerror(ret)); knot_packet_free(packet); return KNOT_EMALF; } @@ -986,7 +954,7 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) } if (*chs == NULL) { - dbg_xfrin("Changesets empty, creating new.\n"); + dbg_xfrin_verb("Changesets empty, creating new.\n"); ret = knot_changeset_allocate(chs); if (ret != KNOT_EOK) { @@ -1007,7 +975,7 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) (*chs)->first_soa = rr; state = -1; - dbg_xfrin("First SOA of IXFR saved, state set to -1.\n"); + dbg_xfrin_verb("First SOA of IXFR saved, state set to -1.\n"); // parse the next one ret = knot_packet_parse_next_rr_answer(packet, &rr); @@ -1050,7 +1018,7 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) ret = KNOT_EBADARG; goto cleanup; } - dbg_xfrin("Changesets present.\n"); + dbg_xfrin_detail("Changesets present.\n"); } /* @@ -1090,7 +1058,7 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) * calls to this function. */ if (state != -1) { - dbg_xfrin("State is not -1, deciding...\n"); + dbg_xfrin_detail("State is not -1, deciding...\n"); // there should be at least one started changeset right now if ((*chs)->count <= 0) { knot_rrset_deep_free(&rr, 1, 1, 1); @@ -1108,15 +1076,15 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) } } - dbg_xfrin("State before the loop: %d\n", state); + dbg_xfrin_detail("State before the loop: %d\n", state); /*! \todo This may be implemented with much less IFs! */ while (ret == KNOT_EOK && rr != NULL) { dbg_xfrin_exec_verb( - dbg_xfrin_verb("Next loop, state: %d\n", state); + dbg_xfrin_detail("Next loop, state: %d\n", state); char *name = knot_dname_to_str(knot_rrset_owner(rr)); - dbg_xfrin_verb("Actual RR: %s, type %s.\n", name, + dbg_xfrin_detail("Actual RR: %s, type %s.\n", name, knot_rrtype_to_string(knot_rrset_type(rr))); free(name); ); @@ -1128,7 +1096,7 @@ dbg_xfrin_exec_verb( // is quite weird in fact if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) { dbg_xfrin("First RR is not a SOA RR!\n"); - dbg_xfrin("RR type: %s\n", + dbg_xfrin_verb("RR type: %s\n", knot_rrtype_to_string(knot_rrset_type(rr))); ret = KNOT_EMALF; knot_rrset_deep_free(&rr, 1, 1, 1); @@ -1222,15 +1190,12 @@ dbg_xfrin_exec_verb( } } break; - // dead code -// default: -// assert(0); } // parse the next RR - dbg_xfrin_verb("Parsing next RR..\n"); + dbg_xfrin_detail("Parsing next RR..\n"); ret = knot_packet_parse_next_rr_answer(packet, &rr); - dbg_xfrin_verb("Returned %d, %p.\n", ret, rr); + dbg_xfrin_detail("Returned %d, %p.\n", ret, rr); } /*! \note Check TSIG, we're at the end of packet. It may not be @@ -1238,7 +1203,7 @@ dbg_xfrin_exec_verb( */ ret = xfrin_check_tsig(packet, xfr, knot_ns_tsig_required(xfr->packet_nr)); - dbg_xfrin_detail("xfrin_check_tsig() returned %d\n", ret); + dbg_xfrin_verb("xfrin_check_tsig() returned %d\n", ret); ++xfr->packet_nr; /*! \note [TSIG] Cleanup and propagate error if TSIG validation fails.*/ @@ -1255,7 +1220,7 @@ cleanup: /* We should go here only if some error occured. */ assert(ret < 0); - dbg_xfrin("Cleanup after processing IXFR/IN packet.\n"); + dbg_xfrin_detail("Cleanup after processing IXFR/IN packet.\n"); knot_free_changesets(chs); knot_packet_free(&packet); xfr->data = 0; @@ -1337,6 +1302,9 @@ static int xfrin_changes_check_rdata(knot_rdata_t ***rdatas, uint **types, } int new_count = (*allocated == 0) ? 2 : *allocated * 2; + while (new_count < count + to_add) { + new_count *= 2; + } /* Allocate new memory block. */ knot_rdata_t **rdatas_new = malloc(new_count * sizeof(knot_rdata_t *)); @@ -1372,36 +1340,21 @@ static int xfrin_changes_check_rdata(knot_rdata_t ***rdatas, uint **types, static void xfrin_changes_add_rdata(knot_rdata_t **rdatas, uint *types, int *count, knot_rdata_t *rdata, uint type) { - dbg_xfrin_detail("Adding RDATA to RDATA list: %p\n", rdata); - if (rdata == NULL) { return; } -//dbg_xfrin_exec_detail( -// // try to find the first RDATA in the given list -// for (int i = 0; i < *count; ++i) { -// knot_rdata_t *r = rdatas[i]; -// if (r == NULL) { -// continue; -// } -// while (r != NULL && r->next != rdatas[i]) { -// if (r == rdata) { -// dbg_xfrin_detail("Found same RDATA: %p\n", rdata); -// knot_rdata_dump(rdata, type, 0); -// } -// r = r->next; -// } -// if (r == rdata) { -// dbg_xfrin_detail("Found same RDATA: %p\n", rdata); -// knot_rdata_dump(rdata, type, 0); -// } -// } -//); + // Add all RDATAs from the chain!! - rdatas[*count] = rdata; - types[*count] = type; - ++*count; + knot_rdata_t *r = rdata; + do { + dbg_xfrin_detail("Adding RDATA to RDATA list: %p\n", r); + rdatas[*count] = r; + types[*count] = type; + ++*count; + + r = r->next; + } while (r != NULL && r != rdata); } /*----------------------------------------------------------------------------*/ @@ -1412,7 +1365,6 @@ static void xfrin_zone_contents_free(knot_zone_contents_t **contents) if ((*contents)->table != NULL) { ck_destroy_table(&(*contents)->table, NULL, 0); -// ck_table_free(&(*contents)->table); } // free the zone tree with nodes @@ -1459,10 +1411,9 @@ static knot_rdata_t *xfrin_remove_rdata(knot_rrset_t *from, static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, knot_changes_t *changes) { - dbg_xfrin_verb("Copying old RRSet: %p\n", old); + dbg_xfrin_detail("Copying old RRSet: %p\n", old); // create new RRSet by copying the old one -// int ret = knot_rrset_shallow_copy(old, copy); - int ret = knot_rrset_deep_copy(old, copy); + int ret = knot_rrset_deep_copy(old, copy, 0); if (ret != KNOT_EOK) { dbg_xfrin("Failed to create RRSet copy.\n"); return KNOT_ENOMEM; @@ -1479,11 +1430,14 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, return ret; } + int count = knot_rrset_rdata_rr_count(*copy); + count += knot_rrset_rdata_rr_count((*copy)->rrsigs); + // add the copied RDATA to the list of new RDATA ret = xfrin_changes_check_rdata(&changes->new_rdata, &changes->new_rdata_types, changes->new_rdata_count, - &changes->new_rdata_allocated, 2); + &changes->new_rdata_allocated, count); if (ret != KNOT_EOK) { dbg_xfrin("Failed to add new RRSet to list.\n"); knot_rrset_deep_free(copy, 1, 1, 1); @@ -1492,7 +1446,8 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, changes->new_rrsets[changes->new_rrsets_count++] = *copy; - dbg_xfrin_verb("Adding RDATA from the RRSet copy to new RDATA list.\n"); + dbg_xfrin_detail("Adding RDATA from the RRSet copy to new RDATA list." + "\n"); xfrin_changes_add_rdata(changes->new_rdata, changes->new_rdata_types, &changes->new_rdata_count, knot_rrset_get_rdata(*copy), @@ -1502,8 +1457,9 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, assert(old->rrsigs != NULL); changes->new_rrsets[changes->new_rrsets_count++] = (*copy)->rrsigs; - dbg_xfrin_verb("Adding RDATA from RRSIG of the RRSet copy to " - "new RDATA list.\n"); + + dbg_xfrin_detail("Adding RDATA from RRSIG of the RRSet copy to " + "new RDATA list.\n"); xfrin_changes_add_rdata(changes->new_rdata, changes->new_rdata_types, &changes->new_rdata_count, @@ -1520,11 +1476,14 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, return ret; } + count = knot_rrset_rdata_rr_count(old); + count += knot_rrset_rdata_rr_count(old->rrsigs); + // and old RDATA to the list of old RDATA ret = xfrin_changes_check_rdata(&changes->old_rdata, &changes->old_rdata_types, changes->old_rdata_count, - &changes->old_rdata_allocated, 2); + &changes->old_rdata_allocated, count); if (ret != KNOT_EOK) { dbg_xfrin("Failed to add old RRSet to list.\n"); return ret; @@ -1532,7 +1491,7 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, changes->old_rrsets[changes->old_rrsets_count++] = old; - dbg_xfrin_verb("Adding RDATA from old RRSet to old RDATA list.\n"); + dbg_xfrin_detail("Adding RDATA from old RRSet to old RDATA list.\n"); xfrin_changes_add_rdata(changes->old_rdata, changes->old_rdata_types, &changes->old_rdata_count, old->rdata, knot_rrset_type(old)); @@ -1541,8 +1500,8 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, assert(old->rrsigs != NULL); changes->old_rrsets[changes->old_rrsets_count++] = old->rrsigs; - dbg_xfrin_verb("Adding RDATA from RRSIG of the old RRSet to " - "old RDATA list.\n"); + dbg_xfrin_detail("Adding RDATA from RRSIG of the old RRSet to " + "old RDATA list.\n"); xfrin_changes_add_rdata(changes->old_rdata, changes->old_rdata_types, &changes->old_rdata_count, @@ -1558,15 +1517,15 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, static int xfrin_copy_rrset(knot_node_t *node, knot_rr_type_t type, knot_rrset_t **rrset, knot_changes_t *changes) { -dbg_xfrin_exec_verb( +dbg_xfrin_exec_detail( char *name = knot_dname_to_str(knot_node_owner(node)); - dbg_xfrin_verb("Removing RRSet of type %s from node %s (%p)\n", + dbg_xfrin_detail("Removing RRSet of type %s from node %s (%p)\n", knot_rrtype_to_string(type), name, node); free(name); ); knot_rrset_t *old = knot_node_remove_rrset(node, type); - dbg_xfrin_verb("Removed RRSet: %p\n", old); + dbg_xfrin_detail("Removed RRSet: %p\n", old); dbg_xfrin_detail("Other RRSet of the same type in the node: %p\n", knot_node_rrset(node, type)); @@ -1580,7 +1539,7 @@ dbg_xfrin_exec_verb( return ret; } - dbg_xfrin_verb("Copied old rrset %p to new %p.\n", old, *rrset); + dbg_xfrin_detail("Copied old rrset %p to new %p.\n", old, *rrset); // replace the RRSet in the node copy by the new one ret = knot_node_add_rrset(node, *rrset, 0); @@ -1597,7 +1556,8 @@ dbg_xfrin_exec_verb( static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, const knot_rrset_t *remove, knot_node_t *node, - knot_rrset_t **rrset) + knot_rrset_t **rrset, + knot_rrset_t **rrsigs_old) { assert(changes != NULL); assert(remove != NULL); @@ -1613,37 +1573,35 @@ static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, int copied = 0; - if (!*rrset - || knot_dname_compare(knot_rrset_owner(*rrset), - knot_node_owner(node)) != 0 - || knot_rrset_type(*rrset) != knot_rdata_rrsig_type_covered( - knot_rrset_rdata(remove))) { + if (*rrset + && knot_dname_compare(knot_rrset_owner(*rrset), + knot_node_owner(node)) == 0 + && knot_rrset_type(*rrset) == knot_rdata_rrsig_type_covered( + knot_rrset_rdata(remove))) { + // this RRSet should be the already copied RRSet so we may + // update it right away + /*! \todo Does this case even occur? */ + dbg_xfrin_verb("Using RRSet from previous iteration.\n"); + } else { // find RRSet based on the Type Covered knot_rr_type_t type = knot_rdata_rrsig_type_covered( knot_rrset_rdata(remove)); // copy the rrset - dbg_xfrin_verb("Copying RRSet that carries the RRSIGs.\n"); + dbg_xfrin_detail("Copying RRSet that carries the RRSIGs.\n"); ret = xfrin_copy_rrset(node, type, rrset, changes); if (ret != KNOT_EOK) { dbg_xfrin("Failed to copy rrset from changeset.\n"); return ret; } + dbg_xfrin_detail("Copied RRSet:\n"); + knot_rrset_dump(*rrset, 0); copied = 1; - } else { - // we should have the right RRSIG RRSet in *rrset - assert(knot_rrset_type(*rrset) - == knot_rdata_rrsig_type_covered( - knot_rrset_rdata(remove))); - // this RRSet should be the already copied RRSet so we may - // update it right away - /*! \todo Does this case even occur? */ - dbg_xfrin_verb("Using RRSet from previous iteration.\n"); } - + // get the old rrsigs knot_rrset_t *old = knot_rrset_get_rrsigs(*rrset); - dbg_xfrin_verb("Old RRSIGs from RRSet: %p\n", old); + dbg_xfrin_detail("Old RRSIGs from RRSet: %p\n", old); if (old == NULL) { return 1; } @@ -1651,14 +1609,22 @@ static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, // copy the RRSIGs knot_rrset_t *rrsigs = NULL; if (!copied) { - ret = xfrin_copy_old_rrset(old, &rrsigs, changes); - if (ret != KNOT_EOK) { - return ret; + // check if the stored RRSIGs are not the right ones + if (*rrsigs_old && *rrsigs_old == (*rrset)->rrsigs) { + dbg_xfrin_verb("Using RRSIG from previous iteration\n"); + rrsigs = *rrsigs_old; + } else { + ret = xfrin_copy_old_rrset(old, &rrsigs, changes); + if (ret != KNOT_EOK) { + return ret; + } + dbg_xfrin_detail("Copied RRSIGs: %p\n", rrsigs); + dbg_xfrin_detail("Copied RRSet:\n"); + knot_rrset_dump(rrsigs, 0); } - dbg_xfrin_verb("Copied RRSIGs: %p\n", rrsigs); } else { rrsigs = old; - dbg_xfrin_verb("Using old RRSIGs: %p\n", rrsigs); + dbg_xfrin_detail("Using old RRSIGs: %p\n", rrsigs); } // set the RRSIGs to the new RRSet copy @@ -1667,21 +1633,25 @@ static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, return KNOT_ERROR; } + *rrsigs_old = rrsigs; + // now in '*rrset' we have a copy of the RRSet which holds the RRSIGs // and in 'rrsigs' we have the copy of the RRSIGs knot_rdata_t *rdata = xfrin_remove_rdata(rrsigs, remove); if (rdata == NULL) { dbg_xfrin("Failed to remove RDATA from RRSet: %s.\n", - knot_strerror(ret)); + knot_strerror(ret)); return 1; } + + int count = knot_rdata_count(rdata); // connect the RDATA to the list of old RDATA ret = xfrin_changes_check_rdata(&changes->old_rdata, &changes->old_rdata_types, changes->old_rdata_count, - &changes->old_rdata_allocated, 1); + &changes->old_rdata_allocated, count); if (ret != KNOT_EOK) { return ret; } @@ -1704,7 +1674,7 @@ static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, 1); if (ret != KNOT_EOK) { dbg_xfrin("Failed to add empty RRSet to the " - "list of old RRSets."); + "list of old RRSets."); // delete the RRSet right away knot_rrset_free(&rrsigs); return ret; @@ -1729,7 +1699,7 @@ static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, 1); if (ret != KNOT_EOK) { dbg_xfrin("Failed to add empty RRSet to " - "the list of old RRSets."); + "the list of old RRSets."); // delete the RRSet right away knot_rrset_free(rrset); return ret; @@ -1762,10 +1732,13 @@ static int xfrin_apply_remove_normal(knot_changes_t *changes, // now we have the copy of the node, so lets get the right RRSet // check if we do not already have it - if (!*rrset - || knot_dname_compare(knot_rrset_owner(*rrset), - knot_node_owner(node)) != 0 - || knot_rrset_type(*rrset) != knot_rrset_type(remove)) { + if (*rrset + && knot_dname_compare(knot_rrset_owner(*rrset), + knot_node_owner(node)) == 0 + && knot_rrset_type(*rrset) == knot_rrset_type(remove)) { + /*! \todo Does some other case even occur? */ + dbg_xfrin_verb("Using RRSet from previous loop.\n"); + } else { /*! * \todo This may happen also with already * copied RRSet. In that case it would be @@ -1774,30 +1747,29 @@ static int xfrin_apply_remove_normal(knot_changes_t *changes, */ ret = xfrin_copy_rrset(node, knot_rrset_type(remove), rrset, changes); - dbg_xfrin_detail("Copied RRSet:\n"); - knot_rrset_dump(*rrset, 0); if (ret != KNOT_EOK) { return ret; } - } /*! \todo Does some other case even occur? */ + dbg_xfrin_detail("Copied RRSet:\n"); + knot_rrset_dump(*rrset, 0); + } if (*rrset == NULL) { dbg_xfrin_verb("RRSet not found for RR to be removed.\n"); return 1; } -dbg_xfrin_exec_verb( +dbg_xfrin_exec_detail( char *name = knot_dname_to_str(knot_rrset_owner(*rrset)); - dbg_xfrin("Updating RRSet with owner %s, type %s\n", name, - knot_rrtype_to_string(knot_rrset_type(*rrset))); + dbg_xfrin_detail("Updating RRSet with owner %s, type %s\n", name, + knot_rrtype_to_string(knot_rrset_type(*rrset))); free(name); ); - // remove the specified RRs from the RRSet (de facto difference of - // sets) + // remove the specified RRs from the RRSet (de facto difference of sets) knot_rdata_t *rdata = xfrin_remove_rdata(*rrset, remove); if (rdata == NULL) { - dbg_xfrin("Failed to remove RDATA from RRSet\n"); + dbg_xfrin_verb("Failed to remove RDATA from RRSet\n"); // In this case, the RDATA was not found in the RRSet return 1; } @@ -1814,11 +1786,12 @@ dbg_xfrin_exec_detail( } ); + int count = knot_rdata_count(rdata); // connect the RDATA to the list of old RDATA ret = xfrin_changes_check_rdata(&changes->old_rdata, &changes->old_rdata_types, changes->old_rdata_count, - &changes->old_rdata_allocated, 1); + &changes->old_rdata_allocated, count); if (ret != KNOT_EOK) { return ret; } @@ -1859,7 +1832,7 @@ dbg_xfrin_exec_detail( } /*----------------------------------------------------------------------------*/ - +/*! \todo Needs review - RRs may not be merged into RRSets. */ static int xfrin_apply_remove_all_rrsets(knot_changes_t *changes, knot_node_t *node, uint16_t type) { @@ -1918,9 +1891,6 @@ static knot_node_t *xfrin_add_new_node(knot_zone_contents_t *contents, // insert the node into zone structures and create parents if // necessary -// dbg_xfrin("Adding new node to zone. From owner: %s type %s\n", -// knot_dname_to_str(node->owner), -// knot_rrtype_to_string(rrset->type)); if (is_nsec3) { ret = knot_zone_contents_add_nsec3_node(contents, node, 1, 0, 1); @@ -1959,35 +1929,53 @@ static int xfrin_apply_add_normal(knot_changes_t *changes, int ret; - dbg_xfrin_verb("applying rrset:\n"); +dbg_xfrin_exec_detail( + dbg_xfrin_detail("applying rrset:\n"); knot_rrset_dump(add, 0); +); + int copied = 0; /*! \note Reusing RRSet from previous function caused it not to be * removed from the node. * Maybe modification of the code would allow reusing the RRSet * as in apply_add_rrsigs() - the RRSet should not be copied * in such case. */ -// if (!*rrset -// || knot_dname_compare(knot_rrset_owner(*rrset), -// knot_node_owner(node)) != 0 -// || knot_rrset_type(*rrset) -// != knot_rrset_type(add)) { -// dbg_xfrin("Removing rrset!\n"); -// *rrset = knot_node_remove_rrset(node, knot_rrset_type(add)); -// } - - *rrset = knot_node_remove_rrset(node, knot_rrset_type(add)); - - dbg_xfrin_verb("Removed RRSet: \n"); + if (*rrset + && knot_dname_compare(knot_rrset_owner(*rrset), + knot_node_owner(node)) == 0 + && knot_rrset_type(*rrset) == knot_rrset_type(add)) { + dbg_xfrin_verb("Using RRSet from previous iteration.\n"); + } else { + dbg_xfrin_detail("Removing rrset!\n"); + *rrset = knot_node_remove_rrset(node, knot_rrset_type(add)); + + knot_rrset_t *old = *rrset; + + if (*rrset != NULL) { + ret = xfrin_copy_old_rrset(old, rrset, changes); + if (ret != KNOT_EOK) { + return ret; + } + + dbg_xfrin_detail("Copied RRSet: %p\n", *rrset); + dbg_xfrin_detail("Copied RRSet:\n"); + knot_rrset_dump(*rrset, 0); + copied = 1; + } + } + +dbg_xfrin_exec_detail( + dbg_xfrin_detail("Removed RRSet: \n"); knot_rrset_dump(*rrset, 1); +); if (*rrset == NULL) { -dbg_xfrin_exec_verb( +dbg_xfrin_exec_detail( char *name = knot_dname_to_str(add->owner); - dbg_xfrin_verb("RRSet to be added not found in zone.\n"); - dbg_xfrin_verb("owner: %s type: %s\n", name, - knot_rrtype_to_string(add->type)); + dbg_xfrin_detail("RRSet to be added not found in zone.\n"); + dbg_xfrin_detail("owner: %s type: %s\n", name, + knot_rrtype_to_string(add->type)); free(name); ); // add the RRSet from the changeset to the node @@ -2013,25 +2001,12 @@ dbg_xfrin_exec_verb( return 1; // return 1 to indicate the add RRSet was used } - knot_rrset_t *old = *rrset; - -dbg_xfrin_exec_verb( +dbg_xfrin_exec_detail( char *name = knot_dname_to_str(knot_rrset_owner(*rrset)); - dbg_xfrin("Found RRSet with owner %s, type %s\n", name, - knot_rrtype_to_string(knot_rrset_type(*rrset))); + dbg_xfrin_detail("Found RRSet with owner %s, type %s\n", name, + knot_rrtype_to_string(knot_rrset_type(*rrset))); free(name); ); -// knot_rrset_dump(*rrset, 1); - ret = xfrin_copy_old_rrset(old, rrset, changes); - if (ret != KNOT_EOK) { - return ret; - } - - dbg_xfrin_verb("Copied RRSet: %p\n", *rrset); - -// dbg_xfrin("After copy: Found RRSet with owner %s, type %s\n", -// knot_dname_to_str((*rrset)->owner), -// knot_rrtype_to_string(knot_rrset_type(*rrset))); // merge the changeset RRSet to the copy /* What if the update fails? @@ -2044,25 +2019,38 @@ dbg_xfrin_exec_verb( * * TODO: add the 'add' rrset to list of old RRSets? */ - dbg_xfrin_verb("Merging RRSets with owners: %s, %s types: %s, %s\n", - (*rrset)->owner->name, add->owner->name, - knot_rrtype_to_string((*rrset)->type), - knot_rrtype_to_string(add->type)); + dbg_xfrin_detail("Merging RRSets with owners: %s, %s types: %s, %s\n", + (*rrset)->owner->name, add->owner->name, + knot_rrtype_to_string((*rrset)->type), + knot_rrtype_to_string(add->type)); dbg_xfrin_detail("RDATA in RRSet1: %p, RDATA in RRSet2: %p\n", (*rrset)->rdata, add->rdata); - ret = knot_rrset_merge((void **)rrset, (void **)&add); + /* In case the RRSet is empty (and only remained there because of the + * RRSIGs) it may happen that the TTL may be different than that of + * the new RRs. Update the TTL according to the first RR. + */ + + if (knot_rrset_rdata(*rrset) == NULL + && knot_rrset_ttl(*rrset) != knot_rrset_ttl(add)) { + knot_rrset_set_ttl(*rrset, knot_rrset_ttl(add)); + } + + ret = knot_rrset_merge_no_dupl((void **)rrset, (void **)&add); if (ret != KNOT_EOK) { - dbg_xfrin("Failed to merge changeset RRSet to copy.\n"); - return KNOT_ERROR; + dbg_xfrin("Failed to merge changeset RRSet.\n"); + return ret; } - dbg_xfrin_verb("Merge returned: %d\n", ret); + dbg_xfrin_detail("Merge returned: %d\n", ret); knot_rrset_dump(*rrset, 1); - ret = knot_node_add_rrset(node, *rrset, 0); - if (ret < 0) { - dbg_xfrin("Failed to add merged RRSet to the node.\n"); - return ret; + if (copied) { + ret = knot_node_add_rrset(node, *rrset, 0); + + if (ret < 0) { + dbg_xfrin("Failed to add merged RRSet to the node.\n"); + return ret; + } } // return 2 so that the add RRSet is removed from @@ -2078,6 +2066,7 @@ static int xfrin_apply_add_rrsig(knot_changes_t *changes, knot_rrset_t *add, knot_node_t *node, knot_rrset_t **rrset, + knot_rrset_t **rrsigs_old, knot_zone_contents_t *contents) { assert(changes != NULL); @@ -2095,8 +2084,8 @@ static int xfrin_apply_add_rrsig(knot_changes_t *changes, dbg_xfrin_exec_verb( char *name = knot_dname_to_str(knot_rrset_owner(add)); const char *typestr = knot_rrtype_to_string(type); - dbg_xfrin("Adding RRSIG: Owner %s, type covered %s.\n", - name, typestr); + dbg_xfrin_verb("Adding RRSIG: Owner %s, type covered %s.\n", + name, typestr); free(name); ); @@ -2105,11 +2094,12 @@ dbg_xfrin_exec_verb( /*! \note Here the check is OK, because if we aready have the RRSet, * it's a copied one, so it is OK to modify it right away. */ - if (!*rrset - || knot_dname_compare(knot_rrset_owner(*rrset), - knot_node_owner(node)) != 0 - || knot_rrset_type(*rrset) != knot_rdata_rrsig_type_covered( - knot_rrset_rdata(add))) { + if (*rrset + && knot_dname_compare(knot_rrset_owner(*rrset), + knot_node_owner(node)) == 0 + && knot_rrset_type(*rrset) == type) { + dbg_xfrin_verb("Using RRSet from previous iteration.\n"); + } else { // copy the rrset ret = xfrin_copy_rrset(node, type, rrset, changes); if (ret < 0) { @@ -2118,15 +2108,12 @@ dbg_xfrin_exec_verb( *rrset = NULL; } copied = 1; - } else { - // we should have the right RRSIG RRSet in *rrset - assert(knot_rrset_type(*rrset) == type); - // this RRSet should be the already copied RRSet so we may - // update it right away + dbg_xfrin_detail("Copied RRSet:\n"); + knot_rrset_dump(*rrset, 0); } if (*rrset == NULL) { - dbg_xfrin_verb("RRSet to be added not found in zone.\n"); + dbg_xfrin_detail("RRSet to be added not found in zone.\n"); // create a new RRSet to add the RRSIGs into *rrset = knot_rrset_new(knot_node_get_owner(node), type, @@ -2136,7 +2123,7 @@ dbg_xfrin_exec_verb( dbg_xfrin("Failed to create new RRSet for RRSIGs.\n"); return KNOT_ENOMEM; } - dbg_xfrin_verb("Created new RRSet for RRSIG: %p.\n", *rrset); + dbg_xfrin_detail("Created new RRSet for RRSIG: %p.\n", *rrset); // add the RRset to the list of new RRsets ret = xfrin_changes_check_rrsets( @@ -2144,8 +2131,7 @@ dbg_xfrin_exec_verb( &changes->new_rrsets_count, &changes->new_rrsets_allocated, 1); if (ret != KNOT_EOK) { - dbg_xfrin("Failed to add old RRSet to " - "list.\n"); + dbg_xfrin("Failed to add old RRSet to list.\n"); knot_rrset_free(rrset); return ret; } @@ -2163,20 +2149,19 @@ dbg_xfrin_exec_verb( changes->new_rrsets[changes->new_rrsets_count++] = *rrset; } -dbg_xfrin_exec_verb( +dbg_xfrin_exec_detail( char *name = knot_dname_to_str(knot_rrset_owner(*rrset)); - dbg_xfrin("Found RRSet with owner %s, type %s\n", name, - knot_rrtype_to_string(knot_rrset_type(*rrset))); + dbg_xfrin_detail("Found RRSet with owner %s, type %s\n", name, + knot_rrtype_to_string(knot_rrset_type(*rrset))); free(name); ); if (knot_rrset_rrsigs(*rrset) == NULL) { - dbg_xfrin_verb("Adding new RRSIGs to RRSet.\n"); + dbg_xfrin_detail("Adding new RRSIGs to RRSet.\n"); ret = knot_zone_contents_add_rrsigs(contents, add, rrset, &node, KNOT_RRSET_DUPL_SKIP, 1); -// ret = knot_rrset_set_rrsigs(*rrset, add); if (ret < 0) { dbg_xfrin("Failed to add RRSIGs to the RRSet.\n"); return KNOT_ERROR; @@ -2191,20 +2176,30 @@ dbg_xfrin_exec_verb( knot_rrset_t *rrsig; if (!copied) { - ret = xfrin_copy_old_rrset(old, &rrsig, changes); - if (ret != KNOT_EOK) { - return ret; + // check if the stored RRSIGs are not the right ones + if (*rrsigs_old && *rrsigs_old == old) { + dbg_xfrin_verb("Using RRSIG from previous iteration\n"); + rrsig = *rrsigs_old; + } else { + ret = xfrin_copy_old_rrset(old, &rrsig, changes); + if (ret != KNOT_EOK) { + return ret; + } + dbg_xfrin_detail("Copied RRSIGs: %p\n", rrsig); + dbg_xfrin_detail("Copied RRSet:\n"); + knot_rrset_dump(rrsig, 0); } } else { rrsig = old; + dbg_xfrin_verb("Using old RRSIGs: %p\n", rrsig); } // replace the old RRSIGs with the new ones knot_rrset_set_rrsigs(*rrset, rrsig); // merge the changeset RRSet to the copy - dbg_xfrin_verb("Merging RRSIG to the one in the RRSet.\n"); - ret = knot_rrset_merge((void **)&rrsig, (void **)&add); + dbg_xfrin_detail("Merging RRSIG to the one in the RRSet.\n"); + ret = knot_rrset_merge_no_dupl((void **)&rrsig, (void **)&add); if (ret != KNOT_EOK) { dbg_xfrin("Failed to merge changeset RRSIG to copy: %s" ".\n", knot_strerror(ret)); @@ -2232,23 +2227,50 @@ void xfrin_cleanup_successful_update(knot_changes_t **changes) // delete old RDATA for (int i = 0; i < (*changes)->old_rdata_count; ++i) { dbg_xfrin_detail("Deleting old RDATA: %p, type: %s\n", - (*changes)->old_rdata[i], - knot_rrtype_to_string((*changes)->old_rdata_types[i])); + (*changes)->old_rdata[i], + knot_rrtype_to_string((*changes)->old_rdata_types[i])); knot_rdata_dump((*changes)->old_rdata[i], (*changes)->old_rdata_types[i], 0); - knot_rdata_t *rdata = (*changes)->old_rdata[i]; - if (rdata != NULL) { - do { - knot_rdata_t *tmp = rdata->next; - knot_rdata_deep_free(&rdata, - (*changes)->old_rdata_types[i], 1); - rdata = tmp; - } while (rdata != NULL - && rdata != (*changes)->old_rdata[i]); - } + // RDATA are stored separately so do not delete the whole chain + knot_rdata_deep_free(&(*changes)->old_rdata[i], + (*changes)->old_rdata_types[i], 1); +// knot_rdata_t *rdata = (*changes)->old_rdata[i]; +// if (rdata != NULL) { +// do { +// knot_rdata_t *tmp = rdata->next; +// knot_rdata_deep_free(&rdata, +// (*changes)->old_rdata_types[i], 1); +// rdata = tmp; +// } while (rdata != NULL +// && rdata != (*changes)->old_rdata[i]); +// } } + // free the empty nodes + for (int i = 0; i < (*changes)->old_nodes_count; ++i) { +dbg_xfrin_exec_detail( + char *name = knot_dname_to_str( + knot_node_owner((*changes)->old_nodes[i])); + dbg_xfrin_detail("Deleting old empty node: %p, owner: %s\n", + (*changes)->old_nodes[i], name); + free(name); +); + knot_node_free(&(*changes)->old_nodes[i]); + } + + // free empty NSEC3 nodes + for (int i = 0; i < (*changes)->old_nsec3_count; ++i) { +dbg_xfrin_exec_detail( + char *name = knot_dname_to_str( + knot_node_owner((*changes)->old_nsec3[i])); + dbg_xfrin_detail("Deleting old empty node: %p, owner: %s\n", + (*changes)->old_nsec3[i], name); + free(name); +); + knot_node_free(&(*changes)->old_nsec3[i]); + } + // free allocated arrays of nodes and rrsets free((*changes)->new_rrsets); free((*changes)->new_rdata); @@ -2304,13 +2326,21 @@ static void xfrin_switch_node_in_dname_table(knot_dname_t *dname, void *data) { UNUSED(data); - if (knot_dname_node(dname) == NULL) { +dbg_xfrin_exec_detail( + char *name = knot_dname_to_str(dname); + dbg_xfrin_detail("Switching node in dname %s (%p)\n", name, dname->node); + free(name); +); + /* dname is not checked here (for NULL value), which resulted in crash + * on howl recently. However, dname should not be NULL here at all, + * it is a sign of some other error. + */ + + if (dname->node == NULL) { return; } - assert(knot_node_new_node(knot_dname_node(dname)) != NULL); - knot_dname_set_node(dname, knot_node_get_new_node( - knot_dname_get_node(dname))); + knot_dname_update_node(dname); } /*----------------------------------------------------------------------------*/ @@ -2333,10 +2363,10 @@ static int xfrin_switch_nodes(knot_zone_contents_t *contents_copy) xfrin_switch_node_in_hash_table, NULL); assert(ret == 0); - // Traverse also the dname table and change the node pointers in dnames - knot_zone_contents_dname_table_apply(contents_copy, - xfrin_switch_node_in_dname_table, - NULL); +// // Traverse also the dname table and change the node pointers in dnames +// knot_zone_contents_dname_table_apply(contents_copy, +// xfrin_switch_node_in_dname_table, +// NULL); return KNOT_EOK; } @@ -2349,7 +2379,6 @@ static void xfrin_zone_contents_free2(knot_zone_contents_t **contents) if ((*contents)->table != NULL) { ck_destroy_table(&(*contents)->table, NULL, 0); -// ck_table_free(&(*contents)->table); } // free the zone tree, but only the structure @@ -2423,8 +2452,8 @@ void xfrin_rollback_update(knot_zone_contents_t *old_contents, } for (int i = 0; i < (*changes)->new_rdata_count; ++i) { - dbg_xfrin("Freeing %d. RDATA chain: %p\n", i, - (*changes)->new_rdata[i]); + dbg_xfrin_detail("Freeing %d. RDATA: %p\n", i, + (*changes)->new_rdata[i]); /* * In some case, the same RDATA may be stored in @@ -2438,28 +2467,14 @@ void xfrin_rollback_update(knot_zone_contents_t *old_contents, * already deleted, but that may be very time-consuming. */ - // discard the whole chain of RDATA - knot_rdata_t *rdata = (*changes)->new_rdata[i]; - knot_rdata_t *rdata_next = NULL; - - while (rdata != NULL && rdata->next != - (*changes)->new_rdata[i]) { - assert(rdata->next != rdata); - rdata_next = rdata->next; - dbg_xfrin(" Deleting RDATA: %p\n", rdata); - knot_rdata_deep_free(&rdata, - (*changes)->new_rdata_types[i], 1); - rdata = rdata_next; - } - - assert(rdata == NULL - || rdata->next == (*changes)->new_rdata[i]); + /* + * Every RDATA from a chain is stored separately. + * We thus do not follow the RDATA chains and free only + * the first RDATA in each. + */ - dbg_xfrin(" Deleting RDATA: %p\n", rdata); - knot_rdata_deep_free(&rdata, + knot_rdata_deep_free(&(*changes)->new_rdata[i], (*changes)->new_rdata_types[i], 1); - - //(*changes)->new_rdata[i] = NULL; } // free allocated arrays of nodes and rrsets @@ -2481,9 +2496,9 @@ void xfrin_rollback_update(knot_zone_contents_t *old_contents, /*----------------------------------------------------------------------------*/ -static int xfrin_apply_remove2(knot_zone_contents_t *contents, - knot_changeset_t *chset, - knot_changes_t *changes) +static int xfrin_apply_remove(knot_zone_contents_t *contents, + knot_changeset_t *chset, + knot_changes_t *changes) { /* * Iterate over removed RRSets, and remove them from the new nodes @@ -2492,7 +2507,7 @@ static int xfrin_apply_remove2(knot_zone_contents_t *contents, */ int ret = 0; knot_node_t *node = NULL; - knot_rrset_t *rrset = NULL; + knot_rrset_t *rrset = NULL, *rrsigs = NULL; int is_nsec3 = 0; @@ -2501,8 +2516,8 @@ dbg_xfrin_exec_verb( char *name = knot_dname_to_str( knot_rrset_owner(chset->remove[i])); dbg_xfrin_verb("Removing RRSet: %s, type %s\n", name, - knot_rrtype_to_string( - knot_rrset_type(chset->remove[i]))); + knot_rrtype_to_string( + knot_rrset_type(chset->remove[i]))); free(name); ); dbg_xfrin_exec_detail( @@ -2551,7 +2566,7 @@ dbg_xfrin_exec_detail( // this should work also for UPDATE ret = xfrin_apply_remove_rrsigs(changes, chset->remove[i], - node, &rrset); + node, &rrset, &rrsigs); } else { // this should work also for UPDATE ret = xfrin_apply_remove_normal(changes, @@ -2559,7 +2574,7 @@ dbg_xfrin_exec_detail( node, &rrset); } - dbg_xfrin_verb("xfrin_apply_remove() ret = %d\n", ret); + dbg_xfrin_detail("xfrin_apply_remove() ret = %d\n", ret); if (ret > 0) { continue; @@ -2573,13 +2588,14 @@ dbg_xfrin_exec_detail( /*----------------------------------------------------------------------------*/ -static int xfrin_apply_add2(knot_zone_contents_t *contents, - knot_changeset_t *chset, - knot_changes_t *changes) +static int xfrin_apply_add(knot_zone_contents_t *contents, + knot_changeset_t *chset, + knot_changes_t *changes) { int ret = 0; knot_node_t *node = NULL; knot_rrset_t *rrset = NULL; + knot_rrset_t *rrsigs = NULL; int is_nsec3 = 0; @@ -2588,8 +2604,8 @@ dbg_xfrin_exec_verb( char *name = knot_dname_to_str( knot_rrset_owner(chset->add[i])); dbg_xfrin_verb("Adding RRSet: %s, type: %s\n", name, - knot_rrtype_to_string( - knot_rrset_type(chset->add[i]))); + knot_rrtype_to_string( + knot_rrset_type(chset->add[i]))); free(name); ); dbg_xfrin_exec_detail( @@ -2605,14 +2621,14 @@ dbg_xfrin_exec_detail( knot_rrset_rdata(chset->add[i])) == KNOT_RRTYPE_NSEC3)) { - dbg_xfrin_verb("This is NSEC3-related RRSet.\n"); + dbg_xfrin_detail("This is NSEC3-related RRSet.\n"); is_nsec3 = 1; } // check if the old node is not the one we should use if (!node || knot_rrset_owner(chset->add[i]) != knot_node_owner(node)) { - dbg_xfrin_verb("Searching for node...\n"); + dbg_xfrin_detail("Searching for node...\n"); if (is_nsec3) { node = knot_zone_contents_get_nsec3_node( contents, @@ -2624,7 +2640,8 @@ dbg_xfrin_exec_detail( if (node == NULL) { // create new node, connect it properly to the // zone nodes - dbg_xfrin_verb("Node not found. Creating new.\n"); + dbg_xfrin_detail("Node not found. Creating new." + "\n"); node = xfrin_add_new_node(contents, chset->add[i], is_nsec3); @@ -2640,7 +2657,8 @@ dbg_xfrin_exec_detail( if (knot_rrset_type(chset->add[i]) == KNOT_RRTYPE_RRSIG) { ret = xfrin_apply_add_rrsig(changes, chset->add[i], - node, &rrset, contents); + node, &rrset, &rrsigs, + contents); } else { ret = xfrin_apply_add_normal(changes, chset->add[i], node, &rrset, contents); @@ -2648,8 +2666,8 @@ dbg_xfrin_exec_detail( assert(ret != KNOT_EOK); - dbg_xfrin_verb("xfrin_apply_..() returned %d, rrset: %p\n", ret, - rrset); + dbg_xfrin_detail("xfrin_apply_..() returned %s, rrset: %p\n", + knot_strerror(ret), rrset); if (ret > 0) { if (ret == 1) { @@ -2670,21 +2688,24 @@ dbg_xfrin_exec_detail( = chset->add[i]; // the same goes for the RDATA + int count = knot_rrset_rdata_rr_count( + chset->add[i]); // connect the RDATA to the list of new RDATA - int res = xfrin_changes_check_rdata(&changes->new_rdata, + int res = xfrin_changes_check_rdata( + &changes->new_rdata, &changes->new_rdata_types, changes->new_rdata_count, - &changes->new_rdata_allocated, 1); + &changes->new_rdata_allocated, count); if (res != KNOT_EOK) { return res; } xfrin_changes_add_rdata(changes->new_rdata, - changes->new_rdata_types, - &changes->new_rdata_count, - knot_rrset_get_rdata(chset->add[i]), - knot_rrset_type(chset->add[i])); + changes->new_rdata_types, + &changes->new_rdata_count, + knot_rrset_get_rdata(chset->add[i]), + knot_rrset_type(chset->add[i])); chset->add[i] = NULL; } else if (ret == 2) { @@ -2712,9 +2733,9 @@ dbg_xfrin_exec_detail( /*----------------------------------------------------------------------------*/ -static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, - knot_changes_t *changes, - knot_changeset_t *chset) +static int xfrin_apply_replace_soa(knot_zone_contents_t *contents, + knot_changes_t *changes, + knot_changeset_t *chset) { dbg_xfrin("Replacing SOA record.\n"); knot_node_t *node = knot_zone_contents_get_apex(contents); @@ -2762,11 +2783,13 @@ static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, return ret; } + int count = knot_rrset_rdata_rr_count(rrset); + count += knot_rrset_rdata_rr_count(chset->soa_to); // save the new SOA RDATA ret = xfrin_changes_check_rdata(&changes->new_rdata, &changes->new_rdata_types, changes->new_rdata_count, - &changes->new_rdata_allocated, 1); + &changes->new_rdata_allocated, count); if (ret != KNOT_EOK) { dbg_xfrin("Failed to add new RDATA to list.\n"); return ret; @@ -2813,9 +2836,9 @@ static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, /*----------------------------------------------------------------------------*/ -static int xfrin_apply_changeset2(knot_zone_contents_t *contents, - knot_changes_t *changes, - knot_changeset_t *chset) +static int xfrin_apply_changeset(knot_zone_contents_t *contents, + knot_changes_t *changes, + knot_changeset_t *chset) { /* * Applies one changeset to the zone. Checks if the changeset may be @@ -2836,19 +2859,17 @@ static int xfrin_apply_changeset2(knot_zone_contents_t *contents, return KNOT_ERROR; } - int ret = xfrin_apply_remove2(contents, chset, changes); + int ret = xfrin_apply_remove(contents, chset, changes); if (ret != KNOT_EOK) { -// xfrin_clean_changes_after_fail2(changes); return ret; } - ret = xfrin_apply_add2(contents, chset, changes); + ret = xfrin_apply_add(contents, chset, changes); if (ret != KNOT_EOK) { -// xfrin_clean_changes_after_fail(changes); return ret; } - return xfrin_apply_replace_soa2(contents, changes, chset); + return xfrin_apply_replace_soa(contents, changes, chset); } /*----------------------------------------------------------------------------*/ @@ -2871,6 +2892,8 @@ static void xfrin_mark_empty(knot_node_t *node, void *data) } changes->old_nodes[changes->old_nodes_count++] = node; + // mark the node as empty + knot_node_set_empty(node); if (node->parent != NULL) { assert(node->parent->children > 0); @@ -2903,6 +2926,8 @@ static void xfrin_mark_empty_nsec3(knot_node_t *node, void *data) } changes->old_nsec3[changes->old_nsec3_count++] = node; + // mark the node as empty + knot_node_set_empty(node); if (node->parent != NULL) { assert(node->parent->children > 0); @@ -2950,11 +2975,13 @@ static int xfrin_remove_empty_nodes(knot_zone_contents_t *contents, zone_node = NULL; hash_item = NULL; +dbg_xfrin_exec_detail( char *name = knot_dname_to_str(knot_node_owner( changes->old_nodes[i])); dbg_xfrin_detail("Old node #%d: %p, %s\n", i, changes->old_nodes[i], name); free(name); +); ret = knot_zone_contents_remove_node( contents, changes->old_nodes[i], &zone_node, @@ -2967,9 +2994,7 @@ static int xfrin_remove_empty_nodes(knot_zone_contents_t *contents, free(hash_item); free(zone_node); - knot_node_free(&changes->old_nodes[i], 0); } - changes->old_nodes_count = 0; // remove NSEC3 nodes for (int i = 0; i < changes->old_nsec3_count; ++i) { @@ -2990,9 +3015,7 @@ static int xfrin_remove_empty_nodes(knot_zone_contents_t *contents, } free(zone_node); - knot_node_free(&changes->old_nsec3[i], 0); } - changes->old_nsec3_count = 0; return KNOT_EOK; } @@ -3060,9 +3083,6 @@ int xfrin_apply_changesets(knot_zone_t *zone, dbg_xfrin("Applying changesets to zone...\n"); -// dbg_xfrin("\nOLD ZONE CONTENTS:\n\n"); -// knot_zone_contents_dump(old_contents, 1); - /* * Ensure that the zone generation is set to 0. */ @@ -3130,7 +3150,7 @@ int xfrin_apply_changesets(knot_zone_t *zone, dbg_xfrin_verb("Old contents apex: %p, new apex: %p\n", old_contents->apex, contents_copy->apex); for (int i = 0; i < chsets->count; ++i) { - if ((ret = xfrin_apply_changeset2(contents_copy, changes, + if ((ret = xfrin_apply_changeset(contents_copy, changes, &chsets->sets[i])) != KNOT_EOK) { xfrin_rollback_update(old_contents, @@ -3155,7 +3175,8 @@ int xfrin_apply_changesets(knot_zone_t *zone, */ /* - * Select and delete empty nodes. + * Select and remove empty nodes from zone trees. Do not free them right + * away as they may be referenced by some domain names. */ ret = xfrin_remove_empty_nodes(contents_copy, changes); if (ret != KNOT_EOK) { @@ -3165,11 +3186,9 @@ int xfrin_apply_changesets(knot_zone_t *zone, return ret; } - dbg_xfrin("Adjusting zone contents.\n"); dbg_xfrin_verb("Old contents apex: %p, new apex: %p\n", old_contents->apex, contents_copy->apex); -// ret = xfrin_adjust_contents(contents_copy, &changes); ret = knot_zone_contents_adjust(contents_copy); if (ret != KNOT_EOK) { dbg_xfrin("Failed to finalize zone contents: %s\n", @@ -3187,7 +3206,6 @@ int xfrin_apply_changesets(knot_zone_t *zone, return ret; } - //xfrin_cleanup_update(&changes); chsets->changes = changes; *new_contents = contents_copy; @@ -3215,6 +3233,20 @@ int xfrin_switch_zone(knot_zone_t *zone, dbg_xfrin_verb("Old contents: %p, apex: %p, new apex: %p\n", old, (old) ? old->apex : NULL, new_contents->apex); + // switch pointers in domain names, now only the new zone is used + if (transfer_type == XFR_TYPE_IIN) { + // Traverse also the dname table and change the node pointers + // in dnames + int ret = knot_zone_contents_dname_table_apply( + new_contents, + xfrin_switch_node_in_dname_table, NULL); + assert(ret == KNOT_EOK); + } + + // set generation to old, so that the flags may be used in next transfer + // and we do not search for new nodes anymore + knot_zone_contents_set_gen_old(new_contents); + // wait for readers to finish dbg_xfrin_verb("Waiting for readers to finish...\n"); synchronize_rcu(); diff --git a/src/libknot/updates/xfr-in.h b/src/libknot/updates/xfr-in.h index b009152..a762b81 100644..100755 --- a/src/libknot/updates/xfr-in.h +++ b/src/libknot/updates/xfr-in.h @@ -5,7 +5,7 @@ * * \brief XFR client API. * - * \addtogroup query_processing + * \addtogroup xfr * @{ */ /* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> @@ -189,9 +189,6 @@ int xfrin_switch_zone(knot_zone_t *zone, knot_zone_contents_t *new_contents, int deep_free); -//void xfrin_cleanup_failed_update(knot_zone_contents_t *old_contents, -// knot_zone_contents_t **new_contents); - void xfrin_cleanup_successful_update(knot_changes_t **changes); void xfrin_rollback_update(knot_zone_contents_t *old_contents, diff --git a/src/libknot/util/conv.c b/src/libknot/util/conv.c deleted file mode 100644 index 6626ddd..0000000 --- a/src/libknot/util/conv.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdlib.h> -#include <stdint.h> -#include <ctype.h> -#include "conv.h" - -#define B64BUFSIZE 65535 /*!< Buffer size for b64 conversion. */ - - -static const char Base64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static const char Pad64 = '='; - -static int b64rmap_initialized = 0; -static uint8_t b64rmap[256]; - -static const uint8_t b64rmap_special = 0xf0; -static const uint8_t b64rmap_end = 0xfd; -static const uint8_t b64rmap_space = 0xfe; -static const uint8_t b64rmap_invalid = 0xff; - -/** - * Initializing the reverse map is not thread safe. - * Which is fine for NSD. For now... - **/ -static void b64_initialize_rmap() -{ - int i; - char ch; - - /* Null: end of string, stop parsing */ - b64rmap[0] = b64rmap_end; - - for (i = 1; i < 256; ++i) { - ch = (char)i; - /* Whitespaces */ - if (isspace(ch)) { - b64rmap[i] = b64rmap_space; - } - /* Padding: stop parsing */ - else if (ch == Pad64) { - b64rmap[i] = b64rmap_end; - } - /* Non-base64 char */ - else { - b64rmap[i] = b64rmap_invalid; - } - } - - /* Fill reverse mapping for base64 chars */ - for (i = 0; Base64[i] != '\0'; ++i) { - b64rmap[(uint8_t)Base64[i]] = i; - } - - b64rmap_initialized = 1; -} - -static int b64_pton_do(char const *src, uint8_t *target, size_t targsize) -{ - int tarindex, state, ch; - uint8_t ofs; - - state = 0; - tarindex = 0; - - while (1) { - ch = *src++; - ofs = b64rmap[ch]; - - if (ofs >= b64rmap_special) { - /* Ignore whitespaces */ - if (ofs == b64rmap_space) { - continue; - } - /* End of base64 characters */ - if (ofs == b64rmap_end) { - break; - } - /* A non-base64 character. */ - return (-1); - } - - switch (state) { - case 0: - if ((size_t)tarindex >= targsize) { - return (-1); - } - target[tarindex] = ofs << 2; - state = 1; - break; - case 1: - if ((size_t)tarindex + 1 >= targsize) { - return (-1); - } - target[tarindex] |= ofs >> 4; - target[tarindex+1] = (ofs & 0x0f) - << 4 ; - tarindex++; - state = 2; - break; - case 2: - if ((size_t)tarindex + 1 >= targsize) { - return (-1); - } - target[tarindex] |= ofs >> 2; - target[tarindex+1] = (ofs & 0x03) - << 6; - tarindex++; - state = 3; - break; - case 3: - if ((size_t)tarindex >= targsize) { - return (-1); - } - target[tarindex] |= ofs; - tarindex++; - state = 0; - break; - default: - abort(); - } - } - - /* - * We are done decoding Base-64 chars. Let's see if we ended - * on a byte boundary, and/or with erroneous trailing characters. - */ - - if (ch == Pad64) { /* We got a pad char. */ - ch = *src++; /* Skip it, get next. */ - switch (state) { - case 0: /* Invalid = in first position */ - case 1: /* Invalid = in second position */ - return (-1); - - case 2: /* Valid, means one byte of info */ - /* Skip any number of spaces. */ - for ((void)NULL; ch != '\0'; ch = *src++) - if (b64rmap[ch] != b64rmap_space) { - break; - } - /* Make sure there is another trailing = sign. */ - if (ch != Pad64) { - return (-1); - } - ch = *src++; /* Skip the = */ - /* Fall through to "single trailing =" case. */ - /* FALLTHROUGH */ - - case 3: /* Valid, means two bytes of info */ - /* - * We know this char is an =. Is there anything but - * whitespace after it? - */ - for ((void)NULL; ch != '\0'; ch = *src++) - if (b64rmap[ch] != b64rmap_space) { - return (-1); - } - - /* - * Now make sure for cases 2 and 3 that the "extra" - * bits that slopped past the last full byte were - * zeros. If we don't check them, they become a - * subliminal channel. - */ - if (target[tarindex] != 0) { - return (-1); - } - } - } else { - /* - * We ended by seeing the end of the string. Make sure we - * have no partial bytes lying around. - */ - if (state != 0) { - return (-1); - } - } - - return (tarindex); -} - - -static int b64_pton_len(char const *src) -{ - int tarindex, state, ch; - uint8_t ofs; - - state = 0; - tarindex = 0; - - while (1) { - ch = *src++; - ofs = b64rmap[ch]; - - if (ofs >= b64rmap_special) { - /* Ignore whitespaces */ - if (ofs == b64rmap_space) { - continue; - } - /* End of base64 characters */ - if (ofs == b64rmap_end) { - break; - } - /* A non-base64 character. */ - return (-1); - } - - switch (state) { - case 0: - state = 1; - break; - case 1: - tarindex++; - state = 2; - break; - case 2: - tarindex++; - state = 3; - break; - case 3: - tarindex++; - state = 0; - break; - default: - abort(); - } - } - - /* - * We are done decoding Base-64 chars. Let's see if we ended - * on a byte boundary, and/or with erroneous trailing characters. - */ - - if (ch == Pad64) { /* We got a pad char. */ - ch = *src++; /* Skip it, get next. */ - switch (state) { - case 0: /* Invalid = in first position */ - case 1: /* Invalid = in second position */ - return (-1); - - case 2: /* Valid, means one byte of info */ - /* Skip any number of spaces. */ - for ((void)NULL; ch != '\0'; ch = *src++) - if (b64rmap[ch] != b64rmap_space) { - break; - } - /* Make sure there is another trailing = sign. */ - if (ch != Pad64) { - return (-1); - } - ch = *src++; /* Skip the = */ - /* Fall through to "single trailing =" case. */ - /* FALLTHROUGH */ - - case 3: /* Valid, means two bytes of info */ - /* - * We know this char is an =. Is there anything but - * whitespace after it? - */ - for ((void)NULL; ch != '\0'; ch = *src++) - if (b64rmap[ch] != b64rmap_space) { - return (-1); - } - - } - } else { - /* - * We ended by seeing the end of the string. Make sure we - * have no partial bytes lying around. - */ - if (state != 0) { - return (-1); - } - } - - return (tarindex); -} - -int b64_pton(char const *src, uint8_t *target, size_t targsize) -{ - if (!b64rmap_initialized) { - b64_initialize_rmap(); - } - - if (target) { - return b64_pton_do(src, target, targsize); - } else { - return b64_pton_len(src); - } -} - -#define B64BUFSIZE 65535 /*!< Buffer size for b64 conversion. */ diff --git a/src/libknot/util/conv.h b/src/libknot/util/conv.h deleted file mode 100644 index d1e6dae..0000000 --- a/src/libknot/util/conv.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _KNOT_CONV_H_ -#define _KNOT_CONV_H_ - -#define B64BUFSIZE 65535 /*!< Buffer size for b64 conversion. */ - -/*! - * \brief Base64 presentation to wire conversion. - */ -int b64_pton(char const *src, uint8_t *target, size_t targsize); - -#endif // _KNOT_CONV_H_ diff --git a/src/libknot/util/debug.c b/src/libknot/util/debug.c index f14c3cd..a6555ad 100644..100755 --- a/src/libknot/util/debug.c +++ b/src/libknot/util/debug.c @@ -105,7 +105,6 @@ void knot_rrset_dump(const knot_rrset_t *rrset, char loaded_zone) return; } - fprintf(stderr, " rdata count: %d\n", rrset->rdata->count); knot_rdata_t *tmp = rrset->rdata; while (tmp->next != rrset->rdata && tmp->next != NULL) { @@ -133,11 +132,6 @@ void knot_node_dump(knot_node_t *node, void *loaded_zone) hex_print((char *)node->owner->labels, node->owner->label_count); fprintf(stderr, "node: %p\n", node); fprintf(stderr, "node (in node's owner): %p\n", node->owner->node); - if (loaded_zone && node->prev != NULL) { - name = knot_dname_to_str(node->prev->owner); - fprintf(stderr, "previous node: %s\n", name); - free(name); - } if (knot_node_is_deleg_point(node)) { fprintf(stderr, "delegation point\n"); @@ -197,6 +191,8 @@ void knot_node_dump(knot_node_t *node, void *loaded_zone) } else { fprintf(stderr, "none\n"); } + + fprintf(stderr, "Zone: %p\n", node->zone); fprintf(stderr, "RRSet count: %d\n", node->rrset_count); diff --git a/src/libknot/util/debug.h b/src/libknot/util/debug.h index b6aba6e..731fed8 100644..100755 --- a/src/libknot/util/debug.h +++ b/src/libknot/util/debug.h @@ -42,6 +42,7 @@ #define KNOT_ZONE_DEBUG #define KNOT_ZONEDB_DEBUG #define KNOT_NODE_DEBUG + #define KNOT_ZONEDIFF_DEBUG #endif #ifdef KNOT_NS_DEBUG @@ -368,6 +369,48 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); #define dbg_zonedb_exec_detail(cmds) #endif +#ifdef KNOT_ZONEDIFF_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_zonediff(msg...) fprintf(stderr, msg) +#define dbg_zonediff_hex(data, len) hex_print((data), (len)) +#else +#define dbg_zonediff(msg...) +#define dbg_zonediff_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_zonediff_verb(msg...) fprintf(stderr, msg) +#define dbg_zonediff_hex_verb(data, len) hex_print((data), (len)) +#else +#define dbg_zonediff_verb(msg...) +#define dbg_zonediff_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_zonediff_detail(msg...) fprintf(stderr, msg) +#define dbg_zonediff_hex_detail(data, len) hex_print((data), (len)) +#define dbg_zonediff_exec_detail(cmds) do { cmds } while (0) +#else +#define dbg_zonediff_detail(msg...) +#define dbg_zonediff_hex_detail(data, len) +#define dbg_zonediff_exec_detail(cmds) +#endif + +/* No messages. */ +#else +#define dbg_zonediff(msg...) +#define dbg_zonediff_hex(data, len) +#define dbg_zonediff_verb(msg...) +#define dbg_zonediff_hex_verb(data, len) +#define dbg_zonediff_detail(msg...) +#define dbg_zonediff_hex_detail(data, len) +#define dbg_zonediff_exec_detail(cmds) +#endif + /******************************************************************************/ #ifdef KNOT_RESPONSE_DEBUG @@ -607,7 +650,6 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF #define dbg_ck_hash(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) -#define dbg_ck_rehash(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) #define dbg_ck_hash_hex(data, len) hex_log(LOG_SERVER, (data), (len)) #else #define dbg_ck_hash(msg...) @@ -636,7 +678,6 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* No messages. */ #else #define dbg_ck_hash(msg...) -#define dbg_ck_rehash(msg...) #define dbg_ck_hash_hex(data, len) #define dbg_ck_hash_verb(msg...) #define dbg_ck_hash_hex_verb(data, len) @@ -646,6 +687,21 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /******************************************************************************/ +#ifdef KNOT_STASH_DEBUG + +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_stash(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#else +#define dbg_stash(msg...) +#endif + +#else +#define dbg_stash(msg...) +#endif + + +/******************************************************************************/ + #ifdef KNOT_XFRIN_DEBUG /* Brief messages. */ @@ -780,37 +836,46 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); #ifdef DEBUG_ENABLE_BRIEF #define dbg_rrset(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) #define dbg_rrset_hex(data, len) hex_log(LOG_ZONE, (data), (len)) +#define dbg_rrset_exec(cmds) do { cmds } while (0) #else #define dbg_rrset(msg...) #define dbg_rrset_hex(data, len) +#define dbg_rrset_exec(cmds) #endif /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE #define dbg_rrset_verb(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) #define dbg_rrset_hex_verb(data, len) hex_log(LOG_ZONE, (data), (len)) +#define dbg_rrset_exec_verb(cmds) do { cmds } while (0) #else #define dbg_rrset_verb(msg...) #define dbg_rrset_hex_verb(data, len) +#define dbg_rrset_exec_verb(cmds) #endif /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS #define dbg_rrset_detail(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) #define dbg_rrset_hex_detail(data, len) hex_log(LOG_ZONE, (data), (len)) +#define dbg_rrset_exec_detail(cmds) do { cmds } while (0) #else #define dbg_rrset_detail(msg...) #define dbg_rrset_hex_detail(data, len) +#define dbg_rrset_exec_detail(cmds) #endif /* No messages. */ #else #define dbg_rrset(msg...) #define dbg_rrset_hex(data, len) +#define dbg_rrset_exec(cmds) #define dbg_rrset_verb(msg...) #define dbg_rrset_hex_verb(data, len) +#define dbg_rrset_exec_verb(cmds) #define dbg_rrset_detail(msg...) #define dbg_rrset_hex_detail(data, len) +#define dbg_rrset_exec_detail(cmds) #endif /******************************************************************************/ diff --git a/src/libknot/util/descriptor.c b/src/libknot/util/descriptor.c index 63e1747..35ae77e 100644..100755 --- a/src/libknot/util/descriptor.c +++ b/src/libknot/util/descriptor.c @@ -569,3 +569,5 @@ int knot_rrtype_is_metatype(uint16_t type) || type == KNOT_RRTYPE_OPT); } +/*! @} */ + diff --git a/src/libknot/util/descriptor.h b/src/libknot/util/descriptor.h index b7e4a53..b7e4a53 100644..100755 --- a/src/libknot/util/descriptor.h +++ b/src/libknot/util/descriptor.h diff --git a/src/libknot/util/error.h b/src/libknot/util/error.h index 888669a..96eff68 100644..100755 --- a/src/libknot/util/error.h +++ b/src/libknot/util/error.h @@ -52,6 +52,7 @@ enum knot_error { KNOT_EACCES, /*!< Permission is denied. */ KNOT_ECRYPTO, /*!< Error in crypto library. */ KNOT_ENSEC3PAR, /*!< Missing or wrong NSEC3PARAM record. */ + KNOT_ENSEC3CHAIN, /*!< Missing or wrong NSEC3 chain in the zone. */ KNOT_EBADZONE, /*!< Domain name does not belong to the zone. */ KNOT_EHASH, /*!< Error in hash table. */ KNOT_EZONEIN, /*!< Error inserting zone. */ @@ -65,10 +66,12 @@ enum knot_error { KNOT_ENOXFR, /*!< Transfer was not sent. */ KNOT_ENOIXFR, /*!< Transfer is not IXFR (is in AXFR format). */ KNOT_EXFRREFUSED, /*!< Zone transfer refused by the server. */ + KNOT_EXFRDENIED, /*!< Transfer not allowed. */ KNOT_ECONN, /*!< Connection reset. */ KNOT_EIXFRSPACE, /*!< IXFR reply did not fit in. */ KNOT_ECNAME, /*!< CNAME loop found in zone. */ - KNOT_ERROR_COUNT = 34 + KNOT_ENODIFF, /*!< No zone diff can be created. */ + KNOT_ERROR_COUNT = 37 }; /*! \brief Table linking error messages to error codes. */ diff --git a/src/libknot/util/libknot_error.c b/src/libknot/util/libknot_error.c index f787565..dd4280d 100644..100755 --- a/src/libknot/util/libknot_error.c +++ b/src/libknot/util/libknot_error.c @@ -24,7 +24,7 @@ const error_table_t knot_error_msgs[KNOT_ERROR_COUNT] = { {KNOT_ENOTSUP, "Operation not supported."}, {KNOT_EAGAIN, "OS lacked necessary resources."}, {KNOT_ERANGE, "Value is out of range."}, - {KNOT_EBADARG, "Wrong argument supported."}, + {KNOT_EBADARG, "Wrong argument supplied."}, {KNOT_EFEWDATA, "Not enough data to parse."}, {KNOT_ESPACE, "Not enough space provided."}, {KNOT_EMALF, "Malformed data."}, @@ -32,6 +32,7 @@ const error_table_t knot_error_msgs[KNOT_ERROR_COUNT] = { {KNOT_EACCES, "Permission to perform requested operation is denied."}, {KNOT_ECRYPTO, "Error in crypto library."}, {KNOT_ENSEC3PAR, "Missing or wrong NSEC3PARAM record."}, + {KNOT_ENSEC3CHAIN, "Missing or wrong NSEC3 chain in the zone."}, {KNOT_EBADZONE, "Domain name does not belong to the given zone."}, {KNOT_EHASH, "Error in hash table."}, {KNOT_EZONEIN, "Error inserting zone."}, @@ -45,11 +46,13 @@ const error_table_t knot_error_msgs[KNOT_ERROR_COUNT] = { {KNOT_ENOXFR, "Transfer was not sent."}, {KNOT_ENOIXFR, "Transfer is not IXFR (is in AXFR format)."}, {KNOT_EXFRREFUSED, "Zone transfer refused by the server."}, + {KNOT_EXFRDENIED, "Transfer not allowed."}, {KNOT_TSIG_EBADSIG, "Failed to verify TSIG MAC." }, {KNOT_TSIG_EBADKEY, "TSIG key not recognized or invalid." }, {KNOT_TSIG_EBADTIME, "TSIG signing time out of range." }, {KNOT_ECONN, "Connection reset."}, {KNOT_EIXFRSPACE, "IXFR reply did not fit in."}, {KNOT_ECNAME, "CNAME loop found in zone."}, + {KNOT_ENODIFF, "Cannot create zone diff."}, {KNOT_ERROR, 0} }; diff --git a/src/libknot/util/tolower.c b/src/libknot/util/tolower.c index d71c467..d71c467 100644..100755 --- a/src/libknot/util/tolower.c +++ b/src/libknot/util/tolower.c diff --git a/src/libknot/util/tolower.h b/src/libknot/util/tolower.h index 6b9e98c..2e92258 100644..100755 --- a/src/libknot/util/tolower.h +++ b/src/libknot/util/tolower.h @@ -55,3 +55,5 @@ static inline uint8_t knot_tolower(uint8_t c) { } #endif /* _KNOT_TOLOWER_H_ */ + +/*! @} */ diff --git a/src/libknot/util/utils.c b/src/libknot/util/utils.c index 04e12c5..04e12c5 100644..100755 --- a/src/libknot/util/utils.c +++ b/src/libknot/util/utils.c diff --git a/src/libknot/util/utils.h b/src/libknot/util/utils.h index fd275b3..fd275b3 100644..100755 --- a/src/libknot/util/utils.h +++ b/src/libknot/util/utils.h diff --git a/src/libknot/util/wire.h b/src/libknot/util/wire.h index 0a24ff1..0a24ff1 100644..100755 --- a/src/libknot/util/wire.h +++ b/src/libknot/util/wire.h diff --git a/src/libknot/zone/dname-table.c b/src/libknot/zone/dname-table.c index d2d97c2..d2d97c2 100644..100755 --- a/src/libknot/zone/dname-table.c +++ b/src/libknot/zone/dname-table.c diff --git a/src/libknot/zone/dname-table.h b/src/libknot/zone/dname-table.h index 945b6de..945b6de 100644..100755 --- a/src/libknot/zone/dname-table.h +++ b/src/libknot/zone/dname-table.h diff --git a/src/libknot/zone/node.c b/src/libknot/zone/node.c index 4ad2a27..c196f29 100644..100755 --- a/src/libknot/zone/node.c +++ b/src/libknot/zone/node.c @@ -81,67 +81,29 @@ static inline void knot_node_flags_set_nonauth(uint8_t *flags) *flags |= KNOT_NODE_FLAGS_NONAUTH; } -///*----------------------------------------------------------------------------*/ -///*! -// * \brief Returns the old node flag -// * -// * \param flags Flags to retrieve the flag from. -// * -// * \return A byte with only the old node flag set if it was set in \a flags. -// */ -//static inline uint8_t knot_node_flags_get_old(uint8_t flags) -//{ -// return flags & KNOT_NODE_FLAGS_OLD; -//} - -///*----------------------------------------------------------------------------*/ -///*! -// * \brief Sets the old node flag. -// * -// * \param flags Flags to set the flag in. -// */ -//static inline void knot_node_flags_set_new(uint8_t *flags) -//{ -// *flags |= KNOT_NODE_FLAGS_NEW; -//} - -///*----------------------------------------------------------------------------*/ -///*! -// * \brief Returns the new node flag -// * -// * \param flags Flags to retrieve the flag from. -// * -// * \return A byte with only the new node flag set if it was set in \a flags. -// */ -//static inline uint8_t knot_node_flags_get_new(uint8_t flags) -//{ -// return flags & KNOT_NODE_FLAGS_NEW; -//} - -///*----------------------------------------------------------------------------*/ -///*! -// * \brief Sets the new node flag. -// * -// * \param flags Flags to set the flag in. -// */ -//static inline void knot_node_flags_set_old(uint8_t *flags) -//{ -// *flags |= KNOT_NODE_FLAGS_OLD; -//} - -///*----------------------------------------------------------------------------*/ - -//static inline void knot_node_flags_clear_new(uint8_t *flags) -//{ -// *flags &= ~KNOT_NODE_FLAGS_NEW; -//} - -///*----------------------------------------------------------------------------*/ - -//static inline void knot_node_flags_clear_old(uint8_t *flags) -//{ -// *flags &= ~KNOT_NODE_FLAGS_OLD; -//} +/*----------------------------------------------------------------------------*/ +/*! + * \brief Sets the empty node flag. + * + * \param flags Flags to set the flag in. + */ +static inline void knot_node_flags_set_empty(uint8_t *flags) +{ + *flags |= KNOT_NODE_FLAGS_EMPTY; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Returns the empty node flag + * + * \param flags Flags to retrieve the flag from. + * + * \return A byte with only the empty node flag set if it was set in \a flags. + */ +static inline uint8_t knot_node_flags_get_empty(uint8_t flags) +{ + return flags & KNOT_NODE_FLAGS_EMPTY; +} /*----------------------------------------------------------------------------*/ /*! @@ -166,26 +128,6 @@ static int compare_rrset_types(void *rr1, void *rr2) } /*----------------------------------------------------------------------------*/ - -//static int knot_node_zone_gen_is_new(const knot_node_t *node) -//{ -// assert(node->zone != NULL); -// knot_zone_contents_t *cont = rcu_dereference(node->zone->contents); -// assert(cont != NULL); -// return knot_zone_contents_gen_is_new(cont); -//} - -///*----------------------------------------------------------------------------*/ - -//static int knot_node_zone_gen_is_old(const knot_node_t *node) -//{ -// assert(node->zone != NULL); -// knot_zone_contents_t *cont = rcu_dereference(node->zone->contents); -// assert(cont != NULL); -// return knot_zone_contents_gen_is_old(cont); -//} - -/*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -211,9 +153,12 @@ knot_node_t *knot_node_new(knot_dname_t *owner, knot_node_t *parent, } /*----------------------------------------------------------------------------*/ - +/*! \todo Consider replacing rrset_merge() with rrset_merge_no_dupl(). Currently + * this function is never called with merge=1, so it's not a problem, + * but it may be in the future. + */ int knot_node_add_rrset(knot_node_t *node, knot_rrset_t *rrset, - int merge) + int merge) { if (node == NULL) { return KNOT_EBADARG; @@ -235,6 +180,24 @@ int knot_node_add_rrset(knot_node_t *node, knot_rrset_t *rrset, } } +int knot_node_add_rrset_no_dupl(knot_node_t *node, knot_rrset_t *rrset) +{ + int ret = 0; + + if ((ret = (gen_tree_add(node->rrset_tree, rrset, + knot_rrset_merge_no_dupl))) < 0) { + dbg_node("Failed to add rrset to node->rrset_tree.\n"); + return KNOT_ERROR; + } + + if (ret >= 0) { + node->rrset_count += (ret > 0 ? 0 : 1); + return ret; + } else { + return KNOT_ERROR; + } +} + /*----------------------------------------------------------------------------*/ const knot_rrset_t *knot_node_rrset(const knot_node_t *node, @@ -315,6 +278,8 @@ struct knot_node_save_rrset_arg { size_t max_count; }; +/*----------------------------------------------------------------------------*/ + static void save_rrset_to_array(void *node, void *data) { struct knot_node_save_rrset_arg *args = @@ -329,6 +294,8 @@ static void save_rrset_to_array(void *node, void *data) args->array[args->count++] = rrset; } +/*----------------------------------------------------------------------------*/ + knot_rrset_t **knot_node_get_rrsets(const knot_node_t *node) { if (node == NULL || node->rrset_count == 0) { @@ -463,17 +430,6 @@ knot_node_t *knot_node_get_previous(const knot_node_t *node) /*----------------------------------------------------------------------------*/ -const knot_node_t *knot_node_next(const knot_node_t *node) -{ - if (node == NULL) { - return NULL; - } - - return node->next; -} - -/*----------------------------------------------------------------------------*/ - void knot_node_set_previous(knot_node_t *node, knot_node_t *prev) { if (node == NULL) { @@ -620,7 +576,7 @@ void knot_node_set_new_node(knot_node_t *node, /*----------------------------------------------------------------------------*/ -void knot_node_set_zone(knot_node_t *node, knot_zone_t *zone) +void knot_node_set_zone(knot_node_t *node, const knot_zone_t *zone) { if (node == NULL) { return; @@ -631,6 +587,17 @@ void knot_node_set_zone(knot_node_t *node, knot_zone_t *zone) /*----------------------------------------------------------------------------*/ +const knot_zone_t *knot_node_zone(const knot_node_t *node) +{ + if (node == NULL) { + return NULL; + } + + return node->zone; +} + +/*----------------------------------------------------------------------------*/ + void knot_node_update_ref(knot_node_t **ref) { if (*ref != NULL && (*ref)->new_node != NULL) { @@ -644,8 +611,6 @@ void knot_node_update_refs(knot_node_t *node) { // reference to previous node knot_node_update_ref(&node->prev); - // reference to next node - knot_node_update_ref(&node->next); // reference to parent knot_node_update_ref(&node->parent); // reference to wildcard child @@ -713,6 +678,20 @@ int knot_node_is_auth(const knot_node_t *node) /*----------------------------------------------------------------------------*/ +int knot_node_is_empty(const knot_node_t *node) +{ + return knot_node_flags_get_empty(node->flags); +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_set_empty(knot_node_t *node) +{ + knot_node_flags_set_empty(&node->flags); +} + +/*----------------------------------------------------------------------------*/ + static void knot_node_free_rrsets_from_tree(void *item, void *data) { if (item == NULL) { @@ -727,14 +706,6 @@ static void knot_node_free_rrsets_from_tree(void *item, void *data) void knot_node_free_rrsets(knot_node_t *node, int free_rdata_dnames) { - /* CLEANUP */ -// knot_rrset_t **rrsets = knot_node_get_rrsets(node); -// for (int i = 0; i < node->rrset_count; i++) { -// knot_rrset_deep_free(&(rrsets[i]), 0, 1, free_rdata_dnames); -// } - -// free(rrsets); - if (node == NULL) { return; } @@ -748,16 +719,16 @@ void knot_node_free_rrsets(knot_node_t *node, int free_rdata_dnames) /*----------------------------------------------------------------------------*/ -void knot_node_free(knot_node_t **node, int fix_refs) +void knot_node_free(knot_node_t **node) { if (node == NULL || *node == NULL) { return; } - dbg_node("Freeing node: %p\n", *node); + dbg_node_detail("Freeing node: %p\n", *node); if ((*node)->rrset_tree != NULL) { - dbg_node("Freeing RRSets.\n"); + dbg_node_detail("Freeing RRSets.\n"); gen_tree_destroy(&(*node)->rrset_tree, NULL, NULL); } @@ -768,53 +739,13 @@ void knot_node_free(knot_node_t **node, int fix_refs) knot_dname_set_node((*node)->owner, NULL); } - dbg_node("Releasing owner.\n"); + dbg_node_detail("Releasing owner.\n"); knot_dname_release((*node)->owner); - // check nodes referencing this node and fix the references - - if (fix_refs) { - // previous node - dbg_node("Checking previous.\n"); - if ((*node)->prev && (*node)->prev->next == (*node)) { - (*node)->prev->next = (*node)->next; - } - - dbg_node("Checking next.\n"); - if ((*node)->next && (*node)->next->prev == (*node)) { - (*node)->next->prev = (*node)->prev; - } - - // NSEC3 node - dbg_node("Checking NSEC3.\n"); - if ((*node)->nsec3_node - && (*node)->nsec3_node->nsec3_referer == (*node)) { - (*node)->nsec3_node->nsec3_referer = NULL; - } - - dbg_node("Checking NSEC3 ref.\n"); - if ((*node)->nsec3_referer - && (*node)->nsec3_referer->nsec3_node == (*node)) { - (*node)->nsec3_referer->nsec3_node = NULL; - } - - // wildcard child node - dbg_node("Checking parent's wildcard child.\n"); - if ((*node)->parent - && (*node)->parent->wildcard_child == (*node)) { - (*node)->parent->wildcard_child = NULL; - } - - // fix parent's children count - if ((*node)->parent) { - --(*node)->parent->children; - } - } - free(*node); *node = NULL; - dbg_node("Done.\n"); + dbg_node_detail("Done.\n"); } /*----------------------------------------------------------------------------*/ diff --git a/src/libknot/zone/node.h b/src/libknot/zone/node.h index 11cd0ce..1ab814a 100644..100755 --- a/src/libknot/zone/node.h +++ b/src/libknot/zone/node.h @@ -62,8 +62,6 @@ struct knot_node { */ struct knot_node *prev; - struct knot_node *next; - /*! * \brief NSEC3 node corresponding to this node. * @@ -74,7 +72,7 @@ struct knot_node { struct knot_node *nsec3_referer; - struct knot_zone *zone; + const struct knot_zone *zone; struct knot_node *new_node; @@ -83,22 +81,12 @@ struct knot_node { unsigned short rrset_count; /*!< Number of RRSets stored in the node. */ /*! - * \brief Generation of node to be used. - * - * If set to 0, the old node will be used. Otherwise new nodes will - * be used. This applies when getting some referenced node. - - */ -// short **generation; - - /*! * \brief Various flags. * * Currently only two: * 0x01 - node is a delegation point * 0x02 - node is non-authoritative (under a delegation point) - * 0x80 - node is old and will be removed (during update) - * 0x40 - node is new, should not be used while zone is old + * 0x10 - node is empty and will be deleted after update */ uint8_t flags; }; @@ -113,9 +101,11 @@ typedef enum { /*! \brief Node is not authoritative (i.e. below a zone cut). */ KNOT_NODE_FLAGS_NONAUTH = (uint8_t)0x02, /*! \brief Node is old and will be removed (during update). */ - KNOT_NODE_FLAGS_OLD = (uint8_t)0x80, + KNOT_NODE_FLAGS_OLD = (uint8_t)0x04, /*! \brief Node is new and should not be used while zoen is old. */ - KNOT_NODE_FLAGS_NEW = (uint8_t)0x40 + KNOT_NODE_FLAGS_NEW = (uint8_t)0x08, + /*! \brief Node is empty and will be deleted after update. */ + KNOT_NODE_FLAGS_EMPTY = (uint8_t)0x10 } knot_node_flags_t; /*----------------------------------------------------------------------------*/ @@ -147,6 +137,8 @@ knot_node_t *knot_node_new(knot_dname_t *owner, knot_node_t *parent, int knot_node_add_rrset(knot_node_t *node, knot_rrset_t *rrset, int merge); +int knot_node_add_rrset_no_dupl(knot_node_t *node, knot_rrset_t *rrset); + /*! * \brief Returns the RRSet of the given type from the node. * @@ -255,8 +247,6 @@ const knot_node_t *knot_node_previous(const knot_node_t *node); */ knot_node_t *knot_node_get_previous(const knot_node_t *node); -const knot_node_t *knot_node_next(const knot_node_t *node); - /*! * \brief Sets the previous node of the given node. * @@ -351,7 +341,9 @@ knot_node_t *knot_node_get_new_node(const knot_node_t *node); void knot_node_set_new_node(knot_node_t *node, knot_node_t *new_node); -void knot_node_set_zone(knot_node_t *node, struct knot_zone *zone); +void knot_node_set_zone(knot_node_t *node, const struct knot_zone *zone); + +const struct knot_zone *knot_node_zone(const knot_node_t *node); void knot_node_update_ref(knot_node_t **ref); @@ -405,6 +397,10 @@ void knot_node_clear_new(knot_node_t *node); void knot_node_clear_old(knot_node_t *node); +int knot_node_is_empty(const knot_node_t *node); + +void knot_node_set_empty(knot_node_t *node); + /*! * \brief Destroys the RRSets within the node structure. * @@ -428,7 +424,7 @@ void knot_node_free_rrsets(knot_node_t *node, int free_rdata_dnames); * * \todo Document missing parameters. */ -void knot_node_free(knot_node_t **node, int fix_refs); +void knot_node_free(knot_node_t **node); /*! * \brief Compares two nodes according to their owner. diff --git a/src/libknot/zone/zone-contents.c b/src/libknot/zone/zone-contents.c index 19268c4..7e453a5 100644..100755 --- a/src/libknot/zone/zone-contents.c +++ b/src/libknot/zone/zone-contents.c @@ -20,6 +20,8 @@ #include "util/error.h" #include "util/debug.h" #include "common/base32hex.h" +/*! \todo XXX TODO FIXME remove once testing is done. */ +#include "zcompile/zcompile.h" #include "consts.h" /*----------------------------------------------------------------------------*/ @@ -42,7 +44,7 @@ typedef struct { const uint8_t KNOT_ZONE_FLAGS_GEN_OLD = 0; /* xxxxxx00 */ const uint8_t KNOT_ZONE_FLAGS_GEN_NEW = 1 << 0; /* xxxxxx01 */ -const uint8_t KNOT_ZONE_FLAGS_GEN_FIN = 1 << 2; /* xxxxxx10 */ +const uint8_t KNOT_ZONE_FLAGS_GEN_FIN = 1 << 1; /* xxxxxx10 */ const uint8_t KNOT_ZONE_FLAGS_GEN_MASK = 3; /* 00000011 */ const uint8_t KNOT_ZONE_FLAGS_ANY_MASK = 4; /* 00000100 */ const uint8_t KNOT_ZONE_FLAGS_ANY = 4; /* 00000100 */ @@ -91,8 +93,8 @@ dbg_zone_exec( char *node_owner = knot_dname_to_str(knot_node_owner(node)); char *apex_owner = knot_dname_to_str(contents->apex->owner); dbg_zone("zone: Trying to insert foreign node to a " - "zone. Node owner: %s, zone apex: %s\n", - node_owner, apex_owner); + "zone. Node owner: %s, zone apex: %s\n", + node_owner, apex_owner); free(node_owner); free(apex_owner); ); @@ -137,7 +139,7 @@ static void knot_zone_contents_destroy_node_owner_from_tree( UNUSED(data); /*!< \todo change completely! */ - knot_node_free(&tnode->node, 0); + knot_node_free(&tnode->node); } /*----------------------------------------------------------------------------*/ @@ -159,11 +161,8 @@ static int knot_zone_contents_dnames_from_rdata_to_table( == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || d->wireformat[j] == KNOT_RDATA_WF_LITERAL_DNAME) { -// printf("Saving dname from rdata to dname table: " -// "%p.\n", knot_rdata_get_item(rdata, j)->dname); rc = knot_dname_table_add_dname_check(table, &knot_rdata_get_item(rdata, j)->dname); -// printf("Returned: %d\n", rc); if (rc < 0) { dbg_zone("Error: %s\n", knot_strerror(rc)); return rc; @@ -171,7 +170,7 @@ static int knot_zone_contents_dnames_from_rdata_to_table( } } - dbg_zone("RDATA OK.\n"); + dbg_zone_detail("RDATA OK.\n"); return KNOT_EOK; } @@ -187,7 +186,7 @@ static int knot_zone_contents_dnames_from_rrset_to_table( // discard the old owner and replace it with the new knot_rrset_set_owner(rrset, owner); } - dbg_zone("RRSet owner: %p\n", rrset->owner); + dbg_zone_detail("RRSet owner: %p\n", rrset->owner); knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type( knot_rrset_type(rrset)); @@ -197,10 +196,6 @@ static int knot_zone_contents_dnames_from_rrset_to_table( return KNOT_EOK; } // for each RDATA in RRSet -// char *name = knot_dname_to_str(rrset->owner); -// char *type = knot_rrtype_to_string(rrset->type); -// printf("Storing dnames from RDATA from RRSet %s, %s\n", name, type); -// free(name); knot_rdata_t *rdata = knot_rrset_get_rdata(rrset); while (rdata != NULL) { int rc = knot_zone_contents_dnames_from_rdata_to_table(table, @@ -227,10 +222,10 @@ static int knot_zone_contents_dnames_from_node_to_table( // insert owner char *name = knot_dname_to_str(node->owner); - dbg_zone("Node owner before inserting to dname table: %p.\n", - node->owner); - dbg_zone("Node owner before inserting to dname table: %s.\n", - name); + dbg_zone_detail("Node owner before inserting to dname table: %p.\n", + node->owner); + dbg_zone_detail("Node owner before inserting to dname table: %s.\n", + name); free(name); //knot_dname_t *old_owner = node->owner; int rc = knot_dname_table_add_dname_check(table, &node->owner); @@ -239,17 +234,18 @@ static int knot_zone_contents_dnames_from_node_to_table( return rc; } int replace_owner = (rc > 0); - dbg_zone("Node owner after inserting to dname table: %p.\n", - node->owner); + +dbg_zone_exec_detail( name = knot_dname_to_str(node->owner); - dbg_zone("Node owner after inserting to dname table: %s.\n", - name); + dbg_zone_detail("Node owner after inserting to dname table: %p (%s).\n", + node->owner, name); free(name); +); knot_rrset_t **rrsets = knot_node_get_rrsets(node); // for each RRSet for (int i = 0; i < knot_node_rrset_count(node); ++i) { - dbg_zone("Inserting RRSets from node to table.\n"); + dbg_zone_detail("Inserting RRSets from node to table.\n"); rc = knot_zone_contents_dnames_from_rrset_to_table(table, rrsets[i], replace_owner, node->owner); if (rc != KNOT_EOK) { @@ -264,27 +260,46 @@ static int knot_zone_contents_dnames_from_node_to_table( } /*----------------------------------------------------------------------------*/ -/*! - * \brief Finds and sets wildcard child for given node's owner. - * - * \param zone Current zone. - * \param node Node to be used. - */ -//static void find_and_set_wildcard_child(knot_zone_contents_t *zone, -// knot_node_t *node) -//{ -// knot_dname_t *chopped = knot_dname_left_chop(node->owner); -// assert(chopped); -// knot_node_t *wildcard_parent; -// wildcard_parent = -// knot_zone_contents_get_node(zone, chopped); -// knot_dname_free(&chopped); +static const knot_node_t *knot_zone_contents_find_wildcard_child( + knot_zone_contents_t *zone, const knot_node_t *closest_encloser) +{ + assert(zone != NULL); + assert(closest_encloser != NULL); + + knot_dname_t *tmp = knot_dname_new_from_str("*", 1, NULL); + CHECK_ALLOC(tmp, NULL); -// assert(wildcard_parent); /* it *has* to be there */ + knot_dname_t *wildcard = knot_dname_cat(tmp, knot_node_owner( + closest_encloser)); + if (wildcard == NULL) { + free(tmp); + return NULL; + } -// knot_node_set_wildcard_child(wildcard_parent, node); -//} + assert(wildcard == tmp); + +dbg_zone_exec_detail( + char *name = knot_dname_to_str(knot_node_owner(closest_encloser)); + char *name2 = knot_dname_to_str(wildcard); + dbg_zone_detail("Searching for wildcard child of %s (%s)\n", name, + name2); + free(name); + free(name2); +); + + const knot_node_t *found = NULL, *ce = NULL, *prev = NULL; + int ret = knot_zone_contents_find_dname(zone, wildcard, &found, &ce, + &prev); + + knot_dname_free(&wildcard); + + if (ret != KNOT_ZONE_NAME_FOUND) { + return NULL; + } else { + return found; + } +} /*----------------------------------------------------------------------------*/ /*! @@ -303,54 +318,79 @@ static int knot_zone_contents_dnames_from_node_to_table( * \param zone Zone to which the RDATA belongs. * \param pos Position of the RDATA item in the RDATA. */ -//static void knot_zone_contents_adjust_rdata_item(knot_rdata_t *rdata, -// knot_zone_contents_t *zone, -// knot_node_t *node, -// int pos) -//{ -// return; -// const knot_rdata_item_t *dname_item -// = knot_rdata_item(rdata, pos); - -// assert(dname_item); - -// if (dname_item != NULL) { -// knot_dname_t *dname = dname_item->dname; -// const knot_node_t *n = NULL; -// const knot_node_t *closest_encloser = NULL; -// const knot_node_t *prev = NULL; - -// if (knot_dname_is_wildcard(dname)) { -// find_and_set_wildcard_child(zone, node); -// } - -// int ret = knot_zone_contents_find_dname(zone, dname, &n, -// &closest_encloser, &prev); - -// // n = knot_zone_find_node(zone, dname); - -// if (ret == KNOT_EBADARG || ret == KNOT_EBADZONE) { -// // TODO: do some cleanup if needed -// return; -// } - -// assert(ret != KNOT_ZONE_NAME_FOUND -// || n == closest_encloser); - -// if (ret != KNOT_ZONE_NAME_FOUND -// && (closest_encloser != NULL)) { -// dbg_zone("Saving closest encloser to RDATA.\n"); -// // save pointer to the closest encloser -// knot_rdata_item_t *item = -// knot_rdata_get_item(rdata, pos); -// assert(item->dname != NULL); -// assert(item->dname->node == NULL); -// //skip_insert(list, (void *)item->dname, -// // (void *)closest_encloser->owner, NULL); -// item->dname->node = closest_encloser->owner->node; -// } -// } -//} +static void knot_zone_contents_adjust_rdata_item(knot_rdata_t *rdata, + knot_zone_contents_t *zone, + knot_node_t *node, int pos) +{ + const knot_rdata_item_t *dname_item = knot_rdata_item(rdata, pos); + + assert(dname_item); + + if (dname_item != NULL) { + knot_dname_t *dname = dname_item->dname; + + /* + * The case when dname.node is already set is handled here. + * No use to check it later. + */ + if (knot_dname_node(dname) != NULL + || !knot_dname_is_subdomain(dname, knot_node_owner( + knot_zone_contents_apex(zone)))) { + // The name's node is either already set + // or the name does not belong to the zone + dbg_zone_detail("Name's node either set or the name " + "does not belong to the zone (%p).\n", + knot_dname_node(dname)); + return; + } + + const knot_node_t *n = NULL; + const knot_node_t *closest_encloser = NULL; + const knot_node_t *prev = NULL; + + int ret = knot_zone_contents_find_dname(zone, dname, &n, + &closest_encloser, &prev); + + if (ret == KNOT_EBADARG || ret == KNOT_EBADZONE) { + // TODO: do some cleanup if needed + dbg_zone_detail("Failed to find the name in zone: %s\n", + knot_strerror(ret)); + return; + } + + assert(ret != KNOT_ZONE_NAME_FOUND || n == closest_encloser); + + if (ret != KNOT_ZONE_NAME_FOUND && (closest_encloser != NULL)) { + /*! + * \note There is no need to set closer encloser to the + * name. We may find the possible wildcard child + * right away. + * Having the closest encloser saved in the dname + * would disrupt the query processing algorithms + * anyway. + */ + + dbg_zone_verb("Trying to find wildcard child.\n"); + + n = knot_zone_contents_find_wildcard_child(zone, + closest_encloser); + + if (n != NULL) { + knot_dname_set_node(dname, (knot_node_t *)n); + dbg_zone_exec_detail( + char *name = knot_dname_to_str( + knot_node_owner(n)); + char *name2 = knot_dname_to_str(dname); + dbg_zone_detail("Set wildcard node %s " + "to RDATA dname %s.\n", + name, name2); + free(name); + free(name2); + ); + } + } + } +} /*----------------------------------------------------------------------------*/ /*! @@ -364,65 +404,64 @@ static int knot_zone_contents_dnames_from_node_to_table( * \param rrset RRSet to adjust RDATA in. * \param zone Zone to which the RRSet belongs. */ -//static void knot_zone_contents_adjust_rdata_in_rrset(knot_rrset_t *rrset, -// knot_zone_contents_t *zone, -// knot_node_t *node) -//{ -// uint16_t type = knot_rrset_type(rrset); +static void knot_zone_contents_adjust_rdata_in_rrset(knot_rrset_t *rrset, + knot_zone_contents_t *zone, + knot_node_t *node) +{ + uint16_t type = knot_rrset_type(rrset); -// knot_rrtype_descriptor_t *desc = -// knot_rrtype_descriptor_by_type(type); -// assert(desc); + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(type); + assert(desc); -// knot_rdata_t *rdata_first = knot_rrset_get_rdata(rrset); -// knot_rdata_t *rdata = rdata_first; + knot_rdata_t *rdata_first = knot_rrset_get_rdata(rrset); + knot_rdata_t *rdata = rdata_first; -// if (rdata == NULL) { -// return; -// } + if (rdata == NULL) { + return; + } -// while (rdata->next != rdata_first) { -// for (int i = 0; i < rdata->count; ++i) { -// if (desc->wireformat[i] -// == KNOT_RDATA_WF_COMPRESSED_DNAME -// || desc->wireformat[i] -// == KNOT_RDATA_WF_UNCOMPRESSED_DNAME -// || desc->wireformat[i] -// == KNOT_RDATA_WF_LITERAL_DNAME) { -// dbg_zone("Adjusting domain name at " -// "position %d of RDATA of record with owner " -// "%s and type %s.\n", -// i, rrset->owner->name, -// knot_rrtype_to_string(type)); - -// knot_zone_contents_adjust_rdata_item(rdata, -// zone, -// node, -// i); -// } -// } -// rdata = rdata->next; -// } + while (rdata->next != rdata_first) { + for (int i = 0; i < rdata->count; ++i) { + if (desc->wireformat[i] + == KNOT_RDATA_WF_COMPRESSED_DNAME + || desc->wireformat[i] + == KNOT_RDATA_WF_UNCOMPRESSED_DNAME + || desc->wireformat[i] + == KNOT_RDATA_WF_LITERAL_DNAME) { + dbg_zone("Adjusting domain name at " + "position %d of RDATA of record with owner " + "%s and type %s.\n", + i, rrset->owner->name, + knot_rrtype_to_string(type)); + + knot_zone_contents_adjust_rdata_item(rdata, + zone, node, + i); + } + } + rdata = rdata->next; + } -// for (int i = 0; i < rdata->count; ++i) { -// if (desc->wireformat[i] -// == KNOT_RDATA_WF_COMPRESSED_DNAME -// || desc->wireformat[i] -// == KNOT_RDATA_WF_UNCOMPRESSED_DNAME -// || desc->wireformat[i] -// == KNOT_RDATA_WF_LITERAL_DNAME) { -// dbg_zone("Adjusting domain name at " -// "position %d of RDATA of record with owner " -// "%s and type %s.\n", -// i, rrset->owner->name, -// knot_rrtype_to_string(type)); - -// knot_zone_contents_adjust_rdata_item(rdata, zone, -// node, i); -// } -// } + for (int i = 0; i < rdata->count; ++i) { + if (desc->wireformat[i] + == KNOT_RDATA_WF_COMPRESSED_DNAME + || desc->wireformat[i] + == KNOT_RDATA_WF_UNCOMPRESSED_DNAME + || desc->wireformat[i] + == KNOT_RDATA_WF_LITERAL_DNAME) { + dbg_zone("Adjusting domain name at " + "position %d of RDATA of record with owner " + "%s and type %s.\n", + i, rrset->owner->name, + knot_rrtype_to_string(type)); + + knot_zone_contents_adjust_rdata_item(rdata, zone, node, + i); + } + } -//} +} /*----------------------------------------------------------------------------*/ /*! @@ -435,32 +474,29 @@ static int knot_zone_contents_dnames_from_node_to_table( * \param node Zone node to adjust the RRSets in. * \param zone Zone to which the node belongs. */ -//static void knot_zone_contents_adjust_rrsets(knot_node_t *node, -// knot_zone_contents_t *zone) -//{ -// //return; -// knot_rrset_t **rrsets = knot_node_get_rrsets(node); -// short count = knot_node_rrset_count(node); - -// assert(count == 0 || rrsets != NULL); - -// for (int r = 0; r < count; ++r) { -// assert(rrsets[r] != NULL); -// dbg_zone("Adjusting next RRSet.\n"); -// knot_zone_contents_adjust_rdata_in_rrset(rrsets[r], zone, -// node); -// knot_rrset_t *rrsigs = rrsets[r]->rrsigs; -// if (rrsigs != NULL) { -// dbg_zone("Adjusting next RRSIGs.\n"); -// knot_zone_contents_adjust_rdata_in_rrset(rrsigs, -// zone, -// node); -// } -// } - -// free(rrsets); -//} +static void knot_zone_contents_adjust_rrsets(knot_node_t *node, + knot_zone_contents_t *zone) +{ + knot_rrset_t **rrsets = knot_node_get_rrsets(node); + short count = knot_node_rrset_count(node); + + assert(count == 0 || rrsets != NULL); + + for (int r = 0; r < count; ++r) { + assert(rrsets[r] != NULL); + dbg_zone("Adjusting next RRSet.\n"); + knot_zone_contents_adjust_rdata_in_rrset(rrsets[r], zone, + node); + knot_rrset_t *rrsigs = rrsets[r]->rrsigs; + if (rrsigs != NULL) { + dbg_zone("Adjusting next RRSIGs.\n"); + knot_zone_contents_adjust_rdata_in_rrset(rrsigs, zone, + node); + } + } + free(rrsets); +} /*----------------------------------------------------------------------------*/ /*! * \brief Adjusts zone node for faster query processing. @@ -481,35 +517,24 @@ static int knot_zone_contents_dnames_from_node_to_table( static void knot_zone_contents_adjust_node(knot_node_t *node, knot_zone_contents_t *zone) { - -dbg_zone_exec( - char *name = knot_dname_to_str(node->owner); - dbg_zone("----- Adjusting node %s -----\n", name); - free(name); -); - // adjust domain names in RDATA - /*! - * \note This is unnecessary, as the code in adjust_rdata_item() is not - * reachable anyway. However, it's not clear why we disabled the - * code, so this would need further investigation. - */ - //knot_zone_contents_adjust_rrsets(node, zone); + /*! \note Enabled again after a LONG time. Should test thoroughly. */ + knot_zone_contents_adjust_rrsets(node, zone); -dbg_zone_exec( +dbg_zone_exec_detail( if (knot_node_parent(node)) { char *name = knot_dname_to_str(knot_node_owner( knot_node_parent(node))); - dbg_zone("Parent: %s\n", name); - dbg_zone("Parent is delegation point: %s\n", + dbg_zone_detail("Parent: %s\n", name); + dbg_zone_detail("Parent is delegation point: %s\n", knot_node_is_deleg_point(knot_node_parent(node)) ? "yes" : "no"); - dbg_zone("Parent is non-authoritative: %s\n", + dbg_zone_detail("Parent is non-authoritative: %s\n", knot_node_is_non_auth(knot_node_parent(node)) ? "yes" : "no"); free(name); } else { - dbg_zone("No parent!\n"); + dbg_zone_detail("No parent!\n"); } ); // delegation point / non-authoritative node @@ -539,17 +564,19 @@ dbg_zone_exec( int match = knot_zone_contents_find_nsec3_for_name(zone, knot_node_owner(node), &nsec3, &prev); + UNUSED(prev); + if (match != KNOT_ZONE_NAME_FOUND) { nsec3 = NULL; } knot_node_set_nsec3_node(node, (knot_node_t *)nsec3); - dbg_zone("Set flags to the node: \n"); - dbg_zone("Delegation point: %s\n", - knot_node_is_deleg_point(node) ? "yes" : "no"); - dbg_zone("Non-authoritative: %s\n", - knot_node_is_non_auth(node) ? "yes" : "no"); + dbg_zone_detail("Set flags to the node: \n"); + dbg_zone_detail("Delegation point: %s\n", + knot_node_is_deleg_point(node) ? "yes" : "no"); + dbg_zone_detail("Non-authoritative: %s\n", + knot_node_is_non_auth(node) ? "yes" : "no"); } /*----------------------------------------------------------------------------*/ @@ -578,19 +605,16 @@ static void knot_zone_contents_adjust_node_in_tree( return; } - /* - * 1) Set previous node pointer. - */ - knot_node_set_previous(node, args->previous_node); +dbg_zone_exec_verb( + char *name = knot_dname_to_str(node->owner); + dbg_zone_verb("----- Adjusting node %s -----\n", name); + free(name); +); - if (args->first_node == NULL) { - args->first_node = node; - } knot_zone_contents_t *zone = args->zone; /* - * 2) Store domain names to dname table. - * + * 1) Store domain names to dname table. * TODO: make optional! */ assert(zone->dname_table != NULL); @@ -605,13 +629,35 @@ static void knot_zone_contents_adjust_node_in_tree( } /* - * 3) Do other adjusting (flags, closest enclosers, wildcard children, + * 2) Do other adjusting (flags, closest enclosers, wildcard children, * etc.). */ knot_zone_contents_adjust_node(node, zone); +} + +/*----------------------------------------------------------------------------*/ + +static void knot_zone_contents_adjust_node_in_tree_ptr( + knot_zone_tree_node_t *tnode, void *data) +{ + assert(data != NULL); + assert(tnode != NULL); + assert(tnode->node != NULL); + + knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data; + knot_node_t *node = tnode->node; /* - * 4) Store previous node depending on the type of this node. + * 1) Set previous node pointer. + */ + knot_node_set_previous(node, args->previous_node); + + if (args->first_node == NULL) { + args->first_node = node; + } + + /* + * 2) Store previous node depending on the type of this node. */ if (!knot_node_is_non_auth(node) && knot_node_rrset_count(node) > 0) { @@ -639,8 +685,11 @@ static void knot_zone_contents_adjust_nsec3_node_in_tree( knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data; knot_node_t *node = tnode->node; - // set previous node - knot_node_set_previous(node, args->previous_node); + if (args->err != KNOT_EOK) { + dbg_xfrin_detail("Error during adjusting: %s, skipping node.\n", + knot_strerror(args->err)); + return; + } // assure that owner has proper node if (knot_dname_node(knot_node_owner(node)) == NULL) { @@ -661,6 +710,22 @@ static void knot_zone_contents_adjust_nsec3_node_in_tree( args->err = ret; return; } +} + +/*----------------------------------------------------------------------------*/ + +static void knot_zone_contents_adjust_nsec3_node_in_tree_ptr( + knot_zone_tree_node_t *tnode, void *data) +{ + assert(data != NULL); + assert(tnode != NULL); + assert(tnode->node != NULL); + + knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data; + knot_node_t *node = tnode->node; + + // set previous node + knot_node_set_previous(node, args->previous_node); // here is nothing to consider, all nodes are the same args->previous_node = node; @@ -710,9 +775,9 @@ dbg_zone_exec( uint8_t *hashed_name = NULL; size_t hash_size = 0; -dbg_zone_exec( +dbg_zone_exec_verb( char *n = knot_dname_to_str(name); - dbg_zone("Hashing name %s.\n", n); + dbg_zone_verb("Hashing name %s.\n", n); free(n); ); @@ -737,8 +802,7 @@ dbg_zone_exec( if (size == 0) { char *n = knot_dname_to_str(name); - dbg_zone("Error while encoding hashed name %s to " - "base32.\n", n); + dbg_zone("Error while encoding hashed name %s to base32.\n", n); free(n); if (name_b32 != NULL) { free(name_b32); @@ -749,7 +813,7 @@ dbg_zone_exec( assert(name_b32 != NULL); free(hashed_name); - dbg_zone("Base32-encoded hash: %s\n", name_b32); + dbg_zone_verb("Base32-encoded hash: %s\n", name_b32); /* Will be returned to caller, make sure it is released after use. */ *nsec3_name = knot_dname_new_from_str(name_b32, size, NULL); @@ -757,8 +821,7 @@ dbg_zone_exec( free(name_b32); if (*nsec3_name == NULL) { - dbg_zone("Error while creating domain name for hashed" - " name.\n"); + dbg_zone("Error while creating domain name for hashed name.\n"); return KNOT_ERROR; } @@ -767,7 +830,7 @@ dbg_zone_exec( if (ret == NULL) { dbg_zone("Error while creating NSEC3 domain name for " - "hashed name.\n"); + "hashed name.\n"); knot_dname_release(*nsec3_name); return KNOT_ERROR; } @@ -805,31 +868,14 @@ static int knot_zone_contents_find_in_tree(knot_zone_tree_t *tree, assert(previous != NULL); knot_node_t *found = NULL, *prev = NULL; -// knot_node_t *found2 = NULL, *prev2 = NULL; int exact_match = knot_zone_tree_get_less_or_equal(tree, name, &found, &prev); -// assert(prev != NULL); assert(exact_match >= 0); *node = found; *previous = prev; -// if (prev == NULL) { -// // either the returned node is the root of the tree, or it is -// // the leftmost node in the tree; in both cases node was found -// // set the previous node of the found node -// assert(exact_match); -// assert(found != NULL); -// *previous = knot_node_get_previous(found, 1); -// } else { -// // otherwise check if the previous node is not an empty -// // non-terminal -// *previous = (knot_node_rrset_count(prev) == 0) -// ? knot_node_get_previous(prev, 1) -// : prev; -// } - return exact_match; } @@ -852,7 +898,6 @@ static void knot_zone_contents_node_to_hash(knot_zone_tree_node_t *tnode, */ #ifdef USE_HASH_TABLE - //assert(zone->table != NULL); // add the node also to the hash table if authoritative, or deleg. point if (zone->table != NULL && ck_insert_item(zone->table, @@ -977,23 +1022,6 @@ static void knot_zone_contents_check_loops_in_tree(knot_zone_tree_node_t *tnode, args->zone, next_name, &next_node, &ce); -// char *name1 = knot_dname_to_str(next_name); -// char *name2 = (next_node != NULL) -// ? knot_dname_to_str(knot_node_owner(next_node)) -// : "none"; -// char *name3 = (ce != NULL) -// ? knot_dname_to_str(knot_node_owner(ce)) -// : "none"; -// printf("Searched: %s, found: %p (%s), %p (%s); ret: %d" -// ".\n", name1, next_node, name2, ce, name3, ret); -// free(name1); -// if (next_node != NULL) { -// free(name2); -// } -// if (ce != NULL) { -// free(name3); -// } - if (ret != KNOT_ZONE_NAME_FOUND && ce != NULL) { // try to find wildcard child @@ -1025,6 +1053,32 @@ static void knot_zone_contents_check_loops_in_tree(knot_zone_tree_node_t *tnode, } /*----------------------------------------------------------------------------*/ + +static int knot_zc_nsec3_parameters_match(const knot_rdata_t *rdata, + const knot_nsec3_params_t *params) +{ + assert(rdata != NULL && params != NULL); + + dbg_zone_detail("RDATA algo: %u, iterations: %u, salt length: %u, salt:" + " %.*s\n", + knot_rdata_nsec3_algorithm(rdata), + knot_rdata_nsec3_iterations(rdata), + knot_rdata_nsec3_salt_length(rdata), + knot_rdata_nsec3_salt_length(rdata), + knot_rdata_nsec3_salt(rdata)); + dbg_zone_detail("NSEC3PARAM algo: %u, iterations: %u, salt length: %u, " + "salt: %.*s\n", params->algorithm, params->iterations, + params->salt_length, params->salt_length, params->salt); + + return (knot_rdata_nsec3_algorithm(rdata) == params->algorithm + && knot_rdata_nsec3_iterations(rdata) == params->iterations + && knot_rdata_nsec3_salt_length(rdata) == params->salt_length + && strncmp((const char *)knot_rdata_nsec3_salt(rdata), + (const char *)params->salt, params->salt_length) + == 0); +} + +/*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -1041,22 +1095,19 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, return NULL; } -// printf("created cont: %p (%s)\n", -// contents, knot_dname_to_str(apex->owner)); - contents->apex = apex; contents->zone = zone; - knot_node_set_zone(apex, zone); + knot_node_set_zone(apex, contents->zone); contents->node_count = 1; - dbg_zone("Creating tree for normal nodes.\n"); + dbg_zone_verb("Creating tree for normal nodes.\n"); contents->nodes = malloc(sizeof(knot_zone_tree_t)); if (contents->nodes == NULL) { ERR_ALLOC_FAILED; goto cleanup; } - dbg_zone("Creating tree for NSEC3 nodes.\n"); + dbg_zone_verb("Creating tree for NSEC3 nodes.\n"); contents->nsec3_nodes = malloc(sizeof(knot_zone_tree_t)); if (contents->nsec3_nodes == NULL) { ERR_ALLOC_FAILED; @@ -1064,7 +1115,7 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, } if (use_domain_table) { - dbg_zone("Creating domain name table.\n"); + dbg_zone_verb("Creating domain name table.\n"); contents->dname_table = knot_dname_table_new(); if (contents->dname_table == NULL) { ERR_ALLOC_FAILED; @@ -1077,20 +1128,20 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, //contents->node_count = node_count; /* Initialize NSEC3 params */ - dbg_zone("Initializing NSEC3 parameters.\n"); + dbg_zone_verb("Initializing NSEC3 parameters.\n"); contents->nsec3_params.algorithm = 0; contents->nsec3_params.flags = 0; contents->nsec3_params.iterations = 0; contents->nsec3_params.salt_length = 0; contents->nsec3_params.salt = NULL; - dbg_zone("Initializing zone trees.\n"); + dbg_zone_verb("Initializing zone trees.\n"); if (knot_zone_tree_init(contents->nodes) != KNOT_EOK || knot_zone_tree_init(contents->nsec3_nodes) != KNOT_EOK) { goto cleanup; } - dbg_zone("Inserting apex into the zone tree.\n"); + dbg_zone_verb("Inserting apex into the zone tree.\n"); if (knot_zone_tree_insert(contents->nodes, apex) != KNOT_EOK) { dbg_zone("Failed to insert apex to the zone tree.\n"); goto cleanup; @@ -1098,14 +1149,14 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, #ifdef USE_HASH_TABLE if (node_count > 0) { - dbg_zone("Creating hash table.\n"); + dbg_zone_verb("Creating hash table.\n"); contents->table = ck_create_table(node_count); if (contents->table == NULL) { goto cleanup; } // insert the apex into the hash table - dbg_zone("Inserting apex into the hash table.\n"); + dbg_zone_verb("Inserting apex into the hash table.\n"); if (ck_insert_item(contents->table, (const char *)knot_dname_name( knot_node_owner(apex)), @@ -1121,7 +1172,7 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, // insert names from the apex to the domain table if (use_domain_table) { - dbg_zone("Inserting names from apex to table.\n"); + dbg_zone_verb("Inserting names from apex to table.\n"); int rc = knot_zone_contents_dnames_from_node_to_table( contents->dname_table, apex); if (rc != KNOT_EOK) { @@ -1133,7 +1184,7 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, return contents; cleanup: - dbg_zone("Cleaning up.\n"); + dbg_zone_verb("Cleaning up.\n"); free(contents->dname_table); free(contents->nodes); free(contents->nsec3_nodes); @@ -1234,6 +1285,12 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, return KNOT_EBADARG; } +dbg_zone_exec_detail( + char *name = knot_dname_to_str(knot_node_owner(node)); + dbg_zone_detail("Adding node to zone: %s.\n", name); + free(name); +); + int ret = 0; if ((ret = knot_zone_contents_check_node(zone, node)) != 0) { dbg_zone("Node check failed.\n"); @@ -1257,10 +1314,6 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, } #ifdef USE_HASH_TABLE -// char *name = knot_dname_to_str(node->owner); -// dbg_zone("Adding node with owner %s to hash table.\n", name); -// free(name); - //assert(zone->table != NULL); // add the node also to the hash table if authoritative, or deleg. point if (zone->table != NULL && ck_insert_item(zone->table, @@ -1281,7 +1334,7 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, return KNOT_EOK; } - dbg_zone("Creating parents of the node.\n"); + dbg_zone_detail("Creating parents of the node.\n"); knot_dname_t *chopped = knot_dname_left_chop(knot_node_owner(node)); @@ -1293,7 +1346,7 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, } if (knot_dname_compare(knot_node_owner(zone->apex), chopped) == 0) { - dbg_zone("Zone apex is the parent.\n"); + dbg_zone_detail("Zone apex is the parent.\n"); knot_node_set_parent(node, zone->apex); // check if the node is not wildcard child of the parent @@ -1307,7 +1360,7 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, = knot_zone_contents_get_node(zone, chopped)) == NULL && chopped != NULL) { /* Adding new dname to zone + add to table. */ - dbg_zone("Creating new node.\n"); + dbg_zone_detail("Creating new node.\n"); assert(chopped); next_node = knot_node_new(chopped, NULL, flags); @@ -1322,7 +1375,7 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, knot_zone_contents_dnames_from_node_to_table( zone->dname_table, next_node); if (ret != KNOT_EOK) { - knot_node_free(&next_node, 0); + knot_node_free(&next_node); knot_dname_release(chopped); return ret; } @@ -1339,14 +1392,13 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, == NULL); assert(knot_node_owner(next_node) == chopped); - dbg_zone("Inserting new node to zone tree.\n"); -// TREE_INSERT(zone->tree, knot_node, avl, next_node); + dbg_zone_detail("Inserting new node to zone tree.\n"); ret = knot_zone_tree_insert(zone->nodes, next_node); if (ret != KNOT_EOK) { dbg_zone("Failed to insert new node " - "to zone tree.\n"); + "to zone tree.\n"); /*! \todo Delete the node?? */ /* Directly discard. */ knot_dname_release(chopped); @@ -1354,11 +1406,11 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, } #ifdef USE_HASH_TABLE -dbg_zone_exec( +dbg_zone_exec_detail( char *name = knot_dname_to_str( knot_node_owner(next_node)); - dbg_zone("Adding new node with owner %s to " - "hash table.\n", name); + dbg_zone_detail("Adding new node with owner %s to " + "hash table.\n", name); free(name); ); @@ -1369,7 +1421,7 @@ dbg_zone_exec( knot_dname_size(knot_node_owner(next_node)), (void *)next_node) != 0) { dbg_zone("Error inserting node into " - "hash table!\n"); + "hash table!\n"); /*! \todo Delete the node?? */ /* Directly discard. */ knot_dname_release(chopped); @@ -1390,7 +1442,7 @@ dbg_zone_exec( ++zone->node_count; - dbg_zone("Next parent.\n"); + dbg_zone_detail("Next parent.\n"); node = next_node; knot_dname_t *chopped_last = chopped; chopped = knot_dname_left_chop(chopped); @@ -1406,7 +1458,7 @@ dbg_zone_exec( assert(knot_node_parent(node) == NULL); knot_node_set_parent(node, next_node); - dbg_zone("Created all parents.\n"); + dbg_zone_detail("Created all parents.\n"); } /* Directly discard. */ @@ -1419,15 +1471,22 @@ dbg_zone_exec( /*----------------------------------------------------------------------------*/ int knot_zone_contents_add_rrset(knot_zone_contents_t *zone, - knot_rrset_t *rrset, knot_node_t **node, - knot_rrset_dupl_handling_t dupl, - int use_domain_table) + knot_rrset_t *rrset, knot_node_t **node, + knot_rrset_dupl_handling_t dupl, + int use_domain_table) { if (zone == NULL || rrset == NULL || zone->apex == NULL || zone->apex->owner == NULL || node == NULL) { return KNOT_EBADARG; } +dbg_zone_exec_detail( + char *name = knot_dname_to_str(knot_rrset_owner(rrset)); + dbg_zone_detail("Adding RRSet to zone contents: %s, type %s\n", + name, knot_rrtype_to_string(knot_rrset_type(rrset))); + free(name); +); + // check if the RRSet belongs to the zone if (knot_dname_compare(knot_rrset_owner(rrset), zone->apex->owner) != 0 @@ -1448,8 +1507,12 @@ int knot_zone_contents_add_rrset(knot_zone_contents_t *zone, int rc; /*! \todo REMOVE RRSET */ - rc = knot_node_add_rrset(*node, rrset, - dupl == KNOT_RRSET_DUPL_MERGE); + if (dupl == KNOT_RRSET_DUPL_MERGE) { + rc = knot_node_add_rrset_no_dupl(*node, rrset); + } else { + rc = knot_node_add_rrset(*node, rrset, 0); + } + if (rc < 0) { dbg_zone("Failed to add RRSet to node.\n"); return rc; @@ -1458,14 +1521,13 @@ int knot_zone_contents_add_rrset(knot_zone_contents_t *zone, int ret = rc; if (use_domain_table) { - dbg_zone("Saving RRSet to table.\n"); + dbg_zone_detail("Saving RRSet to table.\n"); rc = knot_zone_contents_dnames_from_rrset_to_table( zone->dname_table, rrset, 0, (*node)->owner); if (rc != KNOT_EOK) { dbg_zone("Error saving domain names from " - "RRSIGs to the domain name table.\n " - "The zone may be in an inconsistent " - "state.\n"); + "RRSIGs to the domain name table.\n " + "The zone may be in an inconsistent state.\n"); // WARNING: the zone is not in consistent state now - // there may be domain names in it that are not inserted // into the domain table @@ -1480,7 +1542,7 @@ int knot_zone_contents_add_rrset(knot_zone_contents_t *zone, knot_rrset_set_owner(rrset, (*node)->owner); } - dbg_zone("RRSet OK.\n"); + dbg_zone_detail("RRSet OK.\n"); return ret; } @@ -1493,11 +1555,13 @@ int knot_zone_contents_add_rrsigs(knot_zone_contents_t *zone, knot_rrset_dupl_handling_t dupl, int use_domain_table) { + dbg_zone_verb("Adding RRSIGs to zone contents.\n"); + if (zone == NULL || rrsigs == NULL || rrset == NULL || node == NULL || zone->apex == NULL || zone->apex->owner == NULL) { dbg_zone_exec( dbg_zone("Parameters: zone=%p, rrsigs=%p, rrset=%p, " - "node=%p\n", zone, rrsigs, rrset, node); + "node=%p\n", zone, rrsigs, rrset, node); if (zone != NULL) { dbg_zone("zone->apex=%p\n", zone->apex); if (zone->apex != NULL) { @@ -1522,7 +1586,7 @@ dbg_zone_exec( if (*rrset != NULL && (knot_dname_compare(knot_rrset_owner(rrsigs), knot_rrset_owner(*rrset)) != 0)) { - dbg_zone("RRSIGs does not belong to the given RRSet.\n"); + dbg_zone("RRSIGs do not belong to the given RRSet.\n"); return KNOT_EBADARG; } @@ -1548,8 +1612,8 @@ dbg_zone_exec( // find the RRSet in the node // take only the first RDATA from the RRSIGs - dbg_zone("Finding RRSet for type %s\n", - knot_rrtype_to_string( + dbg_zone_detail("Finding RRSet for type %s\n", + knot_rrtype_to_string( knot_rdata_rrsig_type_covered( knot_rrset_rdata(rrsigs)))); *rrset = knot_node_get_rrset( @@ -1563,28 +1627,28 @@ dbg_zone_exec( assert(*rrset != NULL); - // add all domain names from the RRSet to domain name table int rc; int ret = KNOT_EOK; rc = knot_rrset_add_rrsigs(*rrset, rrsigs, dupl); if (rc < 0) { - dbg_dname("Failed to add RRSIGs to RRSet.\n"); + dbg_zone("Failed to add RRSIGs to RRSet.\n"); return rc; } else if (rc > 0) { - assert(dupl == KNOT_RRSET_DUPL_MERGE); + assert(dupl == KNOT_RRSET_DUPL_MERGE || + dupl == KNOT_RRSET_DUPL_SKIP); ret = 1; } + // add all domain names from the RRSet to domain name table if (use_domain_table) { - dbg_zone("Saving RRSIG RRSet to table.\n"); + dbg_zone_detail("Saving RRSIG RRSet to table.\n"); rc = knot_zone_contents_dnames_from_rrset_to_table( - zone->dname_table, rrsigs, 0, (*rrset)->owner); + zone->dname_table, (*rrset)->rrsigs, 0, (*rrset)->owner); if (rc != KNOT_EOK) { dbg_zone("Error saving domain names from " - "RRSIGs to the domain name table.\n " - "The zone may be in an inconsistent " - "state.\n"); + "RRSIGs to the domain name table.\n " + "The zone may be in an inconsistent state.\n"); // WARNING: the zone is not in consistent state now - // there may be domain names in it that are not inserted // into the domain table @@ -1598,7 +1662,7 @@ dbg_zone_exec( knot_rrset_set_owner((*rrset)->rrsigs, (*rrset)->owner); } - dbg_zone("RRSIGs OK\n"); + dbg_zone_detail("RRSIGs OK\n"); return ret; } @@ -1617,6 +1681,7 @@ int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *zone, int ret = 0; if ((ret = knot_zone_contents_check_node(zone, node)) != 0) { + dbg_zone("Failed node check: %s\n", knot_strerror(ret)); return ret; } @@ -1624,6 +1689,8 @@ int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *zone, // TREE_INSERT(zone->nsec3_nodes, knot_node, avl, node); ret = knot_zone_tree_insert(zone->nsec3_nodes, node); if (ret != KNOT_EOK) { + dbg_zone("Failed to insert node into NSEC3 tree: %s.\n", + knot_strerror(ret)); return ret; } @@ -1632,7 +1699,8 @@ int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *zone, zone->dname_table, node); if (ret != KNOT_EOK) { /*! \todo Remove the node from the tree. */ - dbg_zone("Failed to add dnames into table.\n"); + dbg_zone("Failed to add dnames into table: %s.\n", + knot_strerror(ret)); return ret; } } @@ -1682,8 +1750,12 @@ int knot_zone_contents_add_nsec3_rrset(knot_zone_contents_t *zone, int rc; /*! \todo REMOVE RRSET */ - rc = knot_node_add_rrset(*node, rrset, - dupl == KNOT_RRSET_DUPL_MERGE); + if (dupl == KNOT_RRSET_DUPL_MERGE) { + rc = knot_node_add_rrset_no_dupl(*node, rrset); + } else { + rc = knot_node_add_rrset(*node, rrset, 0); + } + if (rc < 0) { return rc; } @@ -1691,14 +1763,13 @@ int knot_zone_contents_add_nsec3_rrset(knot_zone_contents_t *zone, int ret = rc; if (use_domain_table) { - dbg_zone("Saving NSEC3 RRSet to table.\n"); + dbg_zone_detail("Saving NSEC3 RRSet to table.\n"); rc = knot_zone_contents_dnames_from_rrset_to_table( zone->dname_table, rrset, 0, (*node)->owner); if (rc != KNOT_EOK) { dbg_zone("Error saving domain names from " - "RRSIGs to the domain name table.\n " - "The zone may be in an inconsistent " - "state.\n"); + "RRSIGs to the domain name table.\n " + "The zone may be in an inconsistent state.\n"); // WARNING: the zone is not in consistent state now - // there may be domain names in it that are not inserted // into the domain table @@ -1713,7 +1784,7 @@ int knot_zone_contents_add_nsec3_rrset(knot_zone_contents_t *zone, knot_rrset_set_owner(rrset, (*node)->owner); } - dbg_zone("NSEC3 OK\n"); + dbg_zone_detail("NSEC3 OK\n"); return ret; } @@ -1740,9 +1811,6 @@ dbg_zone_exec_verb( *removed_hash = ck_remove_item(contents->table, (const char *)knot_dname_name(owner), knot_dname_size(owner)); -// int ret = ck_detete_item(contents->table, -// (const char *)knot_dname_name(owner), -// knot_dname_size(owner), NULL, 0); if (*removed_hash == NULL) { return KNOT_ENONODE; } @@ -1837,11 +1905,6 @@ knot_node_t *knot_zone_contents_get_node(const knot_zone_contents_t *zone, return NULL; } - // create dummy node to use for lookup -// knot_node_t *tmp = knot_node_new((knot_dname_t *)name, NULL); -// knot_node_t *n = TREE_FIND(zone->tree, knot_node, avl, tmp); -// knot_node_free(&tmp, 0); - knot_node_t *n; int ret = knot_zone_tree_get(zone->nodes, name, &n); if (ret != KNOT_EOK) { @@ -1861,10 +1924,6 @@ knot_node_t *knot_zone_contents_get_nsec3_node( return NULL; } - // create dummy node to use for lookup -// knot_node_t *tmp = knot_node_new((knot_dname_t *)name, NULL); -// knot_node_t *n = TREE_FIND(zone->nsec3_nodes, knot_node, avl, tmp); -// knot_node_free(&tmp, 0); knot_node_t *n; int ret = knot_zone_tree_get(zone->nsec3_nodes, name, &n); @@ -1899,11 +1958,11 @@ int knot_zone_contents_find_dname(const knot_zone_contents_t *zone, return KNOT_EBADARG; } -dbg_zone_exec( +dbg_zone_exec_verb( char *name_str = knot_dname_to_str(name); char *zone_str = knot_dname_to_str(zone->apex->owner); - dbg_zone("Searching for name %s in zone %s...\n", - name_str, zone_str); + dbg_zone_verb("Searching for name %s in zone %s...\n", + name_str, zone_str); free(name_str); free(zone_str); ); @@ -1928,14 +1987,14 @@ dbg_zone_exec( *node = found; *previous = prev; -dbg_zone_exec( +dbg_zone_exec_detail( char *name_str = (*node) ? knot_dname_to_str((*node)->owner) : "(nil)"; char *name_str2 = (*previous != NULL) ? knot_dname_to_str((*previous)->owner) : "(nil)"; - dbg_zone("Search function returned %d, node %s and prev: %s\n", - exact_match, name_str, name_str2); +dbg_zone_detail("Search function returned %d, node %s (%p) and prev: %s (%p)\n", + exact_match, name_str, *node, name_str2, *previous); if (*node) { free(name_str); @@ -1944,19 +2003,23 @@ dbg_zone_exec( free(name_str2); } ); - - *closest_encloser = *node; - // there must be at least one node with domain name less or equal to // the searched name if the name belongs to the zone (the root) - if (*node == NULL) { + if (*node == NULL && *previous == NULL) { return KNOT_EBADZONE; } - // TODO: this could be replaced by saving pointer to closest encloser - // in node + /* This function was quite out of date. The find_in_tree() function + * may return NULL in the 'found' field, so we cannot search for the + * closest encloser from this node. + */ + + if (exact_match) { + *closest_encloser = *node; + } else { + *closest_encloser = *previous; + assert(*closest_encloser != NULL); - if (!exact_match) { int matched_labels = knot_dname_matched_labels( knot_node_owner((*closest_encloser)), name); while (matched_labels < knot_dname_label_count( @@ -1968,11 +2031,11 @@ dbg_zone_exec( } dbg_zone_exec( char *n = knot_dname_to_str(knot_node_owner((*closest_encloser))); - dbg_zone("Closest encloser: %s\n", n); + dbg_zone_detail("Closest encloser: %s\n", n); free(n); ); - dbg_zone("find_dname() returning %d\n", exact_match); + dbg_zone_verb("find_dname() returning %d\n", exact_match); return (exact_match) ? KNOT_ZONE_NAME_FOUND @@ -2055,11 +2118,11 @@ int knot_zone_contents_find_dname_hash(const knot_zone_contents_t *zone, return KNOT_EBADARG; } -dbg_zone_exec( +dbg_zone_exec_verb( char *name_str = knot_dname_to_str(name); char *zone_str = knot_dname_to_str(zone->apex->owner); - dbg_zone("Searching for name %s in zone %s...\n", - name_str, zone_str); + dbg_zone_verb("Searching for name %s in zone %s...\n", + name_str, zone_str); free(name_str); free(zone_str); ); @@ -2092,9 +2155,9 @@ dbg_zone_exec( *node = (const knot_node_t *)item->value; *closest_encloser = *node; - dbg_zone("Found node in hash table: %p (owner %p, " - "labels: %d)\n", *node, (*node)->owner, - knot_dname_label_count((*node)->owner)); + dbg_zone_detail("Found node in hash table: %p (owner %p, " + "labels: %d)\n", *node, (*node)->owner, + knot_dname_label_count((*node)->owner)); assert(*node != NULL); assert(*closest_encloser != NULL); return KNOT_ZONE_NAME_FOUND; @@ -2104,34 +2167,22 @@ dbg_zone_exec( // chop leftmost labels until some node is found // copy the name for chopping - /* Local allocation, will be discarded. */ - //knot_dname_t *name_copy = knot_dname_deep_copy(name); -dbg_zone_exec( - //char *n = knot_dname_to_str(name_copy); - dbg_zone("Finding closest encloser..\nStarting with: %.*s\n", - (int)name_size, name_tmp); - //free(n); -); + + dbg_zone_detail("Finding closest encloser..\nStarting with: %.*s\n", + (int)name_size, name_tmp); while (item == NULL) { - //knot_dname_left_chop_no_copy(name_copy); knot_zone_contents_left_chop(name_tmp, &name_size); -dbg_zone_exec( - //char *n = knot_dname_to_str(name_copy); - dbg_zone("Chopped leftmost label: %.*s\n", - (int)name_size, name_tmp); - //free(n); +dbg_zone_exec_detail( + dbg_zone_detail("Chopped leftmost label: %.*s\n", + (int)name_size, name_tmp); ); // not satisfied in root zone!! - //assert(name_copy->label_count > 0); assert(name_size > 0); item = ck_find_item(zone->table, name_tmp, name_size); } - /* Directly discard. */ - //knot_dname_free(&name_copy); - assert(item != NULL); *closest_encloser = (const knot_node_t *)item->value; @@ -2165,9 +2216,16 @@ int knot_zone_contents_find_nsec3_for_name(const knot_zone_contents_t *zone, return ret; } -dbg_zone_exec( + // check if the NSEC3 tree is not empty + if (zone->nsec3_nodes->th_root == NULL) { + dbg_zone("NSEC3 tree is empty.\n"); + knot_dname_release(nsec3_name); + return KNOT_ENSEC3CHAIN; + } + +dbg_zone_exec_verb( char *n = knot_dname_to_str(nsec3_name); - dbg_zone("NSEC3 node name: %s.\n", n); + dbg_zone_verb("NSEC3 node name: %s.\n", n); free(n); ); @@ -2180,26 +2238,33 @@ dbg_zone_exec( knot_dname_release(nsec3_name); -dbg_zone_exec( +dbg_zone_exec_detail( if (found) { char *n = knot_dname_to_str(found->owner); - dbg_zone("Found NSEC3 node: %s.\n", n); + dbg_zone_detail("Found NSEC3 node: %s.\n", n); free(n); } else { - dbg_zone("Found no NSEC3 node.\n"); + dbg_zone_detail("Found no NSEC3 node.\n"); } if (prev) { assert(prev->owner); char *n = knot_dname_to_str(prev->owner); - dbg_zone("Found previous NSEC3 node: %s.\n", n); + dbg_zone_detail("Found previous NSEC3 node: %s.\n", n); free(n); } else { - dbg_zone("Found no previous NSEC3 node.\n"); + dbg_zone_detail("Found no previous NSEC3 node.\n"); } ); *nsec3_node = found; + // This check cannot be used now, the function returns proper return + // value if the node was not found +// if (*nsec3_node == NULL) { +// // there is no NSEC3 node even if there should be +// return KNOT_ENSEC3CHAIN; +// } + if (prev == NULL) { // either the returned node is the root of the tree, or it is // the leftmost node in the tree; in both cases node was found @@ -2211,7 +2276,55 @@ dbg_zone_exec( *nsec3_previous = prev; } - dbg_zone("find_nsec3_for_name() returning %d\n", exact_match); + dbg_zone_verb("find_nsec3_for_name() returning %d\n", exact_match); + + /* The previous may be from wrong NSEC3 chain. Search for previous + * from the right chain. Check iterations, hash algorithm and salt + * values and compare them to the ones from NSEC3PARAM. + */ + const knot_rrset_t *nsec3_rrset = knot_node_rrset(*nsec3_previous, + KNOT_RRTYPE_NSEC3); + const knot_rdata_t *nsec3_rdata = (nsec3_rrset != NULL) + ? knot_rrset_rdata(nsec3_rrset) + : NULL; + const knot_node_t *original_prev = *nsec3_previous; + + while (nsec3_rdata != NULL + && !knot_zc_nsec3_parameters_match(nsec3_rdata, + &zone->nsec3_params)) { + /* Try other RDATA if there are some. In case of name collision + * the node would contain records from both NSEC3 chains. + */ + if ((nsec3_rdata = knot_rrset_rdata_next( + nsec3_rrset, nsec3_rdata)) != NULL) { + continue; + } + + /* If there is none, try previous node. */ + + *nsec3_previous = knot_node_previous(*nsec3_previous); + nsec3_rrset = knot_node_rrset(*nsec3_previous, + KNOT_RRTYPE_NSEC3); + nsec3_rdata = (nsec3_rrset != NULL) + ? knot_rrset_rdata(nsec3_rrset) + : NULL; +dbg_zone_exec_detail( + char *name = (*nsec3_previous) + ? knot_dname_to_str( + knot_node_owner(*nsec3_previous)) + : "none"; + dbg_zone_detail("Previous node: %s, checking parameters...\n", + name); + if (*nsec3_previous) { + free(name); + } +); + if (*nsec3_previous == original_prev || nsec3_rdata == NULL) { + // cycle + *nsec3_previous = NULL; + break; + } + } return (exact_match) ? KNOT_ZONE_NAME_FOUND @@ -2257,23 +2370,18 @@ int knot_zone_contents_adjust(knot_zone_contents_t *zone) adjust_arg.first_node = NULL; adjust_arg.previous_node = NULL; adjust_arg.err = KNOT_EOK; -// adjust_arg.check_ver = check_ver; /* - * Adjust the NSEC3 nodes first. - * There are independent on the normal nodes, but the normal nodes are - * dependent on them. + * First of all we must set node.prev pointers, as these are used in + * the search functions. */ - - dbg_zone("Adjusting NSEC3 nodes.\n"); - int ret = knot_zone_tree_forward_apply_inorder( - zone->nsec3_nodes, - knot_zone_contents_adjust_nsec3_node_in_tree, - &adjust_arg); + dbg_zone("Setting 'prev' pointers to NSEC3 nodes.\n"); + int ret = knot_zone_tree_forward_apply_inorder(zone->nsec3_nodes, + knot_zone_contents_adjust_nsec3_node_in_tree_ptr, &adjust_arg); assert(ret == KNOT_EOK); if (adjust_arg.err != KNOT_EOK) { - dbg_zone("Failed to adjust NSEC3 nodes: %s\n", + dbg_zone("Failed to set 'prev' pointers to NSEC3 nodes: %s\n", knot_strerror(adjust_arg.err)); return adjust_arg.err; } @@ -2281,13 +2389,46 @@ int knot_zone_contents_adjust(knot_zone_contents_t *zone) // set the last node as previous of the first node if (adjust_arg.first_node) { knot_node_set_previous(adjust_arg.first_node, - adjust_arg.previous_node); + adjust_arg.previous_node); } dbg_zone("Done.\n"); adjust_arg.first_node = NULL; adjust_arg.previous_node = NULL; + dbg_zone("Setting 'prev' pointers to normal nodes.\n"); + ret = knot_zone_tree_forward_apply_inorder(zone->nodes, + knot_zone_contents_adjust_node_in_tree_ptr, &adjust_arg); + assert(ret == KNOT_EOK); + + if (adjust_arg.err != KNOT_EOK) { + dbg_zone("Failed to set 'prev' pointers to normal nodes: %s\n", + knot_strerror(adjust_arg.err)); + return adjust_arg.err; + } + + // set the last node as previous of the first node + assert(zone->apex == adjust_arg.first_node); + knot_node_set_previous(zone->apex, adjust_arg.previous_node); + dbg_zone("Done.\n"); + + /* + * Adjust the NSEC3 nodes first. + * There are independent on the normal nodes, but the normal nodes are + * dependent on them. + */ + + dbg_zone("Adjusting NSEC3 nodes.\n"); + ret = knot_zone_tree_forward_apply_inorder(zone->nsec3_nodes, + knot_zone_contents_adjust_nsec3_node_in_tree, &adjust_arg); + assert(ret == KNOT_EOK); + + if (adjust_arg.err != KNOT_EOK) { + dbg_zone("Failed to adjust NSEC3 nodes: %s\n", + knot_strerror(adjust_arg.err)); + return adjust_arg.err; + } + dbg_zone("Adjusting normal nodes.\n"); ret = knot_zone_tree_forward_apply_inorder(zone->nodes, knot_zone_contents_adjust_node_in_tree, @@ -2300,9 +2441,6 @@ int knot_zone_contents_adjust(knot_zone_contents_t *zone) return adjust_arg.err; } - assert(zone->apex == adjust_arg.first_node); - knot_node_set_previous(zone->apex, adjust_arg.previous_node); - dbg_zone("Done.\n"); return ret; @@ -2339,58 +2477,6 @@ int knot_zone_contents_check_loops(knot_zone_contents_t *zone) /*----------------------------------------------------------------------------*/ -int knot_zone_contents_adjust_old(knot_zone_contents_t *zone) -{ - if (zone == NULL) { - return KNOT_EBADARG; - } - - // load NSEC3PARAM (needed on adjusting function) - knot_zone_contents_load_nsec3param(zone); - - knot_zone_adjust_arg_t adjust_arg; - adjust_arg.zone = zone; - adjust_arg.first_node = NULL; - adjust_arg.previous_node = NULL; -// adjust_arg.check_ver = check_ver; - adjust_arg.err = KNOT_EOK; - - dbg_zone("Adjusting normal nodes.\n"); - int ret = knot_zone_tree_forward_apply_inorder(zone->nodes, - knot_zone_contents_adjust_node_in_tree, - &adjust_arg); - if (ret != KNOT_EOK) { - return ret; - } - if (adjust_arg.err != KNOT_EOK) { - dbg_zone("Failed node adjusting: %s\n", - knot_strerror(adjust_arg.err)); - return adjust_arg.err; - } - - dbg_zone("Done.\n"); - - assert(zone->apex == adjust_arg.first_node); - knot_node_set_previous(zone->apex, adjust_arg.previous_node); - - adjust_arg.first_node = NULL; - adjust_arg.previous_node = NULL; - - dbg_zone("Adjusting NSEC3 nodes.\n"); - ret = knot_zone_tree_forward_apply_inorder(zone->nsec3_nodes, - knot_zone_contents_adjust_nsec3_node_in_tree, &adjust_arg); - - dbg_zone("Done.\n"); - if (adjust_arg.first_node) { - knot_node_set_previous(adjust_arg.first_node, - adjust_arg.previous_node); - } - - return ret; -} - -/*----------------------------------------------------------------------------*/ - int knot_zone_contents_load_nsec3param(knot_zone_contents_t *zone) { if (zone == NULL || zone->apex == NULL) { @@ -2418,8 +2504,8 @@ int knot_zone_contents_nsec3_enabled(const knot_zone_contents_t *zone) return KNOT_EBADARG; } - //return (zone->nsec3_params.algorithm != 0); - return (zone->nsec3_nodes->th_root != NULL); + return (zone->nsec3_params.algorithm != 0 + && zone->nsec3_nodes->th_root != NULL); } /*----------------------------------------------------------------------------*/ @@ -2662,16 +2748,15 @@ int knot_zone_contents_shallow_copy(const knot_zone_contents_t *from, // ret = ck_copy_table(from->table, &contents->table); ret = ck_shallow_copy(from->table, &contents->table); if (ret != 0) { - dbg_zone("knot_zone_contents_shallow_copy: " - "hash table copied\n"); + dbg_zone_verb("knot_zone_contents_shallow_copy: " + "hash table copied\n"); ret = KNOT_ERROR; goto cleanup; } } #endif - dbg_zone("knot_zone_contents_shallow_copy: " - "finished OK\n"); + dbg_zone("knot_zone_contents_shallow_copy: finished OK\n"); *to = contents; return KNOT_EOK; @@ -2740,13 +2825,11 @@ int knot_zone_contents_shallow_copy2(const knot_zone_contents_t *from, contents->node_count = from->node_count; contents->flags = from->flags; + // set the 'new' flag + knot_zone_contents_set_gen_new(contents); contents->zone = from->zone; -// /* Initialize NSEC3 params */ -// memcpy(&contents->nsec3_params, &from->nsec3_params, -// sizeof(knot_nsec3_params_t)); - if ((ret = knot_zone_tree_deep_copy(from->nodes, contents->nodes)) != KNOT_EOK || (ret = knot_zone_tree_deep_copy(from->nsec3_nodes, @@ -2758,8 +2841,8 @@ int knot_zone_contents_shallow_copy2(const knot_zone_contents_t *from, if (from->table != NULL) { ret = ck_deep_copy(from->table, &contents->table); if (ret != 0) { - dbg_zone("knot_zone_contents_shallow_copy: " - "hash table copied\n"); + dbg_zone_verb("knot_zone_contents_shallow_copy: " + "hash table copied\n"); ret = KNOT_ERROR; goto cleanup; } @@ -2903,16 +2986,6 @@ static void knot_zc_integrity_check_previous(const knot_node_t *node, ++check_data->errors; } -// if (knot_node_next(check_data->previous) != node) { -// char *name2 = knot_dname_to_str(knot_node_owner( -// knot_node_next(check_data->previous))); -// fprintf(stderr, "Wrong next node: node %s, next %s. " -// "Should be %s.\n", name_prev, name2 ,name); -// free(name2); - -// ++check_data->errors; -// } - free(name_prev); } } @@ -2995,11 +3068,6 @@ static void knot_zc_integrity_check_parent(const knot_node_t *node, && knot_dname_matched_labels(node_owner, parent_owner) == knot_dname_label_count(parent_owner)) { -// // increase the parent's children count -// fprintf(stderr, "Parent: %s, node: %s. Increasing children count.\n", -// pname, name); -// ++check_data->children; - // check the parent pointer const knot_node_t *parent = knot_node_parent(node); if (parent != check_data->parent) { @@ -3038,22 +3106,6 @@ static void knot_zc_integrity_check_parent(const knot_node_t *node, ++check_data->errors; } } - } else { - // not a direct child, check children count -// if (check_data->parent -// && knot_node_children(check_data->parent) -// != check_data->children) { -// fprintf(stderr, "Wrong children count: node %s, count: " -// "%u. Should be: %u\n", pname, -// knot_node_children(check_data->parent), -// check_data->children); - -// ++check_data->errors; -// } - - // reset the children count - //check_data->parent = node; -// check_data->children = 0; } free(pname); @@ -3110,15 +3162,6 @@ static int knot_zc_integrity_check_find_dname(const knot_zone_contents_t *zone, const char *node_name) { int ret = 0; - -// find_dname_data_t data_find; -// data_find.found = NULL; -// data_find.to_find = to_find; - -// int res = knot_zone_contents_dname_table_apply( -// (knot_zone_contents_t *)zone, -// find_in_dname_table, (void *)&data_find); -// assert(res == KNOT_EOK); knot_dname_t *found = knot_dname_table_find_dname(zone->dname_table, (knot_dname_t *)to_find); @@ -3364,27 +3407,12 @@ static void reset_new_nodes(knot_zone_tree_node_t *tree_node, void *data) /*----------------------------------------------------------------------------*/ -/*!< \todo remove debug code. */ -//static void print_child_count(knot_node_t *node, void *data) -//{ -// UNUSED(data); -// assert(node != NULL); - -// char *name = knot_dname_to_str(knot_node_owner(node)); -// fprintf(stderr, "Node: %s, children count: %d\n", name, -// knot_node_children(node)); -// free(name); -//} - -/*----------------------------------------------------------------------------*/ - static void count_nsec3_nodes(knot_zone_tree_node_t *tree_node, void *data) { assert(tree_node != NULL); assert(tree_node->node != NULL); assert(data != NULL); -// int *count = (int *)data; knot_node_t *apex = (knot_node_t *)data; assert(apex != NULL); @@ -3406,10 +3434,6 @@ int knot_zc_integrity_check_child_count(check_data_t *data) knot_zone_tree_init(nodes_copy); -// int ret = knot_zone_contents_tree_apply_inorder(data->contents, -// print_child_count, -// NULL); - int ret = knot_zone_tree_deep_copy(data->contents->nodes, nodes_copy); assert(ret == KNOT_EOK); @@ -3425,9 +3449,8 @@ int knot_zc_integrity_check_child_count(check_data_t *data) knot_zone_tree_forward_apply_inorder(nodes_copy, count_children, NULL); // add count of NSEC3 nodes to the apex' children count -// int nsec3_nodes = 0; - dbg_zone("Children count of new apex before NSEC3: %d\n", - data->contents->apex->new_node->children); + fprintf(stderr, "Children count of new apex before NSEC3: %d\n", + data->contents->apex->new_node->children); knot_zone_tree_forward_apply_inorder(data->contents->nsec3_nodes, count_nsec3_nodes, (void *)apex_copy); @@ -3435,7 +3458,6 @@ int knot_zc_integrity_check_child_count(check_data_t *data) // now compare the children counts // iterate over the old zone and search for nodes in the copy -// data->children = nsec3_nodes; knot_zone_tree_forward_apply_inorder(nodes_copy, check_child_count, (void *)data); diff --git a/src/libknot/zone/zone-contents.h b/src/libknot/zone/zone-contents.h index 3143ef9..2ca333e 100644..100755 --- a/src/libknot/zone/zone-contents.h +++ b/src/libknot/zone/zone-contents.h @@ -55,7 +55,7 @@ typedef struct knot_zone_contents_t { knot_nsec3_params_t nsec3_params; - /*! + /*! * \todo Unify the use of this field - authoritative nodes vs. all. */ uint node_count; @@ -80,17 +80,14 @@ typedef struct knot_zone_contents_t { /*----------------------------------------------------------------------------*/ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, - uint node_count, - int use_domain_table, - struct knot_zone *zone); - -//short knot_zone_contents_generation(const knot_zone_contents_t *contents); + uint node_count, + int use_domain_table, + struct knot_zone *zone); int knot_zone_contents_gen_is_old(const knot_zone_contents_t *contents); int knot_zone_contents_gen_is_new(const knot_zone_contents_t *contents); int knot_zone_contents_gen_is_finished(const knot_zone_contents_t *contents); -//void knot_zone_contents_switch_generation(knot_zone_contents_t *contents); void knot_zone_contents_set_gen_old(knot_zone_contents_t *contents); void knot_zone_contents_set_gen_new(knot_zone_contents_t *contents); @@ -187,9 +184,6 @@ int knot_zone_contents_remove_node(knot_zone_contents_t *contents, const knot_node_t *node, knot_zone_tree_node_t **removed_tree, ck_hash_table_item_t **removed_hash); -//knot_zone_tree_node_t *knot_zone_contents_remove_node( -// knot_zone_contents_t *contents, const knot_node_t *node); - int knot_zone_contents_remove_nsec3_node(knot_zone_contents_t *contents, const knot_node_t *node, knot_zone_tree_node_t **removed); @@ -357,9 +351,6 @@ const knot_node_t *knot_zone_contents_apex( knot_node_t *knot_zone_contents_get_apex( const knot_zone_contents_t *contents); -//knot_dname_t *knot_zone_contents_name( -// const knot_zone_contents_t *contents); - /*! * \brief Optimizes zone by replacing domain names in RDATA with references to * domain names present in zone (as node owners). @@ -555,12 +546,6 @@ int knot_zone_contents_shallow_copy(const knot_zone_contents_t *from, int knot_zone_contents_shallow_copy2(const knot_zone_contents_t *from, knot_zone_contents_t **to); -//int knot_zone_contents_dnames_from_node_to_table( -// knot_dname_table_t *table, knot_node_t *node); - -//void knot_zone_contents_adjust_node(knot_node_t *node, -// knot_zone_contents_t *zone, int check_ver); - void knot_zone_contents_free(knot_zone_contents_t **contents); void knot_zone_contents_deep_free(knot_zone_contents_t **contents, diff --git a/src/libknot/zone/zone-diff.c b/src/libknot/zone/zone-diff.c new file mode 100755 index 0000000..d3fd961 --- /dev/null +++ b/src/libknot/zone/zone-diff.c @@ -0,0 +1,1004 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <config.h> + +#include "libknot/util/error.h" +#include "libknot/util/debug.h" +#include "libknot/rdata.h" +#include "zone-diff.h" +#include "libknot/nameserver/name-server.h" + +struct zone_diff_param { + const knot_zone_contents_t *contents; + char nsec3; + knot_changeset_t *changeset; + int ret; +}; + +// forward declaration +static int knot_zone_diff_rdata(const knot_rrset_t *rrset1, + const knot_rrset_t *rrset2, + knot_changeset_t *changeset); + +static int knot_zone_diff_load_soas(const knot_zone_contents_t *zone1, + const knot_zone_contents_t *zone2, + knot_changeset_t *changeset) +{ + if (zone1 == NULL || zone2 == NULL || changeset == NULL) { + return KNOT_EBADARG; + } + + const knot_node_t *apex1 = knot_zone_contents_apex(zone1); + const knot_node_t *apex2 = knot_zone_contents_apex(zone2); + if (apex1 == NULL || apex2 == NULL) { + dbg_zonediff("zone_diff: " + "both zones must have apex nodes.\n"); + return KNOT_EBADARG; + } + + knot_rrset_t *soa_rrset1 = knot_node_get_rrset(apex1, KNOT_RRTYPE_SOA); + knot_rrset_t *soa_rrset2 = knot_node_get_rrset(apex2, KNOT_RRTYPE_SOA); + if (soa_rrset1 == NULL || soa_rrset2 == NULL) { + dbg_zonediff("zone_diff: " + "both zones must have apex nodes.\n"); + return KNOT_EBADARG; + } + + if (knot_rrset_rdata(soa_rrset1) == NULL || + knot_rrset_rdata(soa_rrset2) == NULL) { + dbg_zonediff("zone_diff: " + "both zones must have apex nodes with SOA " + "RRs.\n"); + return KNOT_EBADARG; + } + + int64_t soa_serial1 = + knot_rdata_soa_serial(knot_rrset_rdata(soa_rrset1)); + if (soa_serial1 == -1) { + dbg_zonediff("zone_diff: load_soas: Got bad SOA.\n"); + } + + int64_t soa_serial2 = + knot_rdata_soa_serial(knot_rrset_rdata(soa_rrset2)); + + if (soa_serial2 == -1) { + dbg_zonediff("zone_diff: load_soas: Got bad SOA.\n"); + } + + if (ns_serial_compare(soa_serial1, soa_serial2) == 0) { + dbg_zonediff("zone_diff: " + "second zone must have higher serial than the " + "first one. (%lld vs. %lld)\n", + soa_serial1, soa_serial2); + return KNOT_ENODIFF; + } + + if (ns_serial_compare(soa_serial1, soa_serial2) > 0) { + dbg_zonediff("zone_diff: " + "second zone must have higher serial than the " + "first one. (%lld vs. %lld)\n", + soa_serial1, soa_serial2); + return KNOT_ERANGE; + } + + /* We will not touch SOA later, now is the time to handle RRSIGs. */ + int ret = knot_zone_diff_rdata(knot_rrset_rrsigs(soa_rrset1), + knot_rrset_rrsigs(soa_rrset2), + changeset); + if (ret != KNOT_EOK) { + dbg_zonediff_verb("zone_diff: load_soas: Failed to diff SOAs' RRSIGs." + " Reason: %s.\n", knot_strerror(ret)); + /* This might not necasarilly be an error. */ + } + + assert(changeset); + + ret = knot_rrset_deep_copy(soa_rrset1, &changeset->soa_from, 1); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: load_soas: Cannot copy RRSet.\n"); + return ret; + } + + /* We MUST NOT save this RRSIG. */ + knot_rrset_deep_free(&changeset->soa_from->rrsigs, 1, 1, 1); + assert(changeset->soa_from->rrsigs == NULL); + + ret = knot_rrset_deep_copy(soa_rrset2, &changeset->soa_to, 1); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: load_soas: Cannot copy RRSet.\n"); + return ret; + } + + knot_rrset_deep_free(&changeset->soa_to->rrsigs, 1, 1, 1); + assert(changeset->soa_to->rrsigs == NULL); + + changeset->serial_from = soa_serial1; + changeset->serial_to = soa_serial2; + + dbg_zonediff_verb("zone_diff: load_soas: SOAs diffed. (%lld -> %lld)\n", + soa_serial1, soa_serial2); + + return KNOT_EOK; +} + +/*!< \todo Only use add or remove function, not both as they are the same. */ +/*!< \todo Also, this might be all handled by function in changesets.h!!! */ +static int knot_zone_diff_changeset_add_rrset(knot_changeset_t *changeset, + const knot_rrset_t *rrset) +{ + /* Remove all RRs of the RRSet. */ + if (changeset == NULL || rrset == NULL) { + dbg_zonediff("zone_diff: add_rrset: NULL parameters.\n"); + return KNOT_EBADARG; + } + + if (knot_rrset_rdata_rr_count(rrset) == 0) { + dbg_zonediff_detail("zone_diff: Nothing to add.\n"); + return KNOT_EOK; + } + + dbg_zonediff_detail("zone_diff: add_rrset: Adding RRSet (%d RRs):\n", + knot_rrset_rdata_rr_count(rrset)); + knot_rrset_dump(rrset, 1); + + knot_rrset_t *rrset_copy = NULL; + int ret = knot_rrset_deep_copy(rrset, &rrset_copy, 1); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: add_rrset: Cannot copy RRSet.\n"); + return ret; + } + if (rrset_copy->rrsigs != NULL) { + knot_rrset_deep_free(&rrset_copy->rrsigs, 1, 1, 1); + } + assert(knot_rrset_rrsigs(rrset_copy) == NULL); + + ret = knot_changeset_add_new_rr(changeset, rrset_copy, + XFRIN_CHANGESET_ADD); + if (ret != KNOT_EOK) { + /* We have to free the copy now! */ + knot_rrset_deep_free(&rrset_copy, 1, 1, 1); + dbg_zonediff("zone_diff: add_rrset: Could not add RRSet. " + "Reason: %s.\n", knot_strerror(ret)); + return ret; + } + + return KNOT_EOK; +} + +static int knot_zone_diff_changeset_remove_rrset(knot_changeset_t *changeset, + const knot_rrset_t *rrset) +{ + /* Remove all RRs of the RRSet. */ + if (changeset == NULL) { + dbg_zonediff("zone_diff: remove_rrset: NULL parameters.\n"); + return KNOT_EBADARG; + } + + if (rrset == NULL) { + return KNOT_EOK; + } + + if (knot_rrset_rdata_rr_count(rrset) == 0) { + dbg_zonediff_detail("zone_diff: Nothing to remove.\n"); + return KNOT_EOK; + } + + dbg_zonediff_detail("zone_diff: remove_rrset: Removing RRSet (%d RRs):\n", + knot_rrset_rdata_rr_count(rrset)); + knot_rrset_dump(rrset, 1); + + knot_rrset_t *rrset_copy = NULL; + int ret = knot_rrset_deep_copy(rrset, &rrset_copy, 1); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: remove_rrset: Cannot copy RRSet.\n"); + return ret; + } + if (rrset_copy->rrsigs != NULL) { + knot_rrset_deep_free(&rrset_copy->rrsigs, 1, 1, 1); + } + assert(knot_rrset_rrsigs(rrset_copy) == NULL); + + ret = knot_changeset_add_new_rr(changeset, rrset_copy, + XFRIN_CHANGESET_REMOVE); + if (ret != KNOT_EOK) { + /* We have to free the copy now. */ + knot_rrset_deep_free(&rrset_copy, 1, 1, 1); + dbg_zonediff("zone_diff: remove_rrset: Could not remove RRSet. " + "Reason: %s.\n", knot_strerror(ret)); + return ret; + } + + return KNOT_EOK; +} + +static int knot_zone_diff_add_node(const knot_node_t *node, + knot_changeset_t *changeset) +{ + if (node == NULL || changeset == NULL) { + dbg_zonediff("zone_diff: add_node: NULL arguments.\n"); + return KNOT_EBADARG; + } + + /* Add all rrsets from node. */ + const knot_rrset_t **rrsets = knot_node_rrsets(node); + if (rrsets == NULL) { + /* Empty non-terminals - legal case. */ + dbg_zonediff_detail("zone_diff: Node has no RRSets.\n"); + return KNOT_EOK; + } + + for (uint i = 0; i < knot_node_rrset_count(node); i++) { + assert(rrsets[i]); + int ret = knot_zone_diff_changeset_add_rrset(changeset, + rrsets[i]); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: add_node: Cannot add RRSet (%s).\n", + knot_strerror(ret)); + free(rrsets); + return ret; + } + } + + free(rrsets); + + return KNOT_EOK; +} + +static int knot_zone_diff_remove_node(knot_changeset_t *changeset, + const knot_node_t *node) +{ + if (changeset == NULL || node == NULL) { + dbg_zonediff("zone_diff: remove_node: NULL parameters.\n"); + return KNOT_EBADARG; + } + + dbg_zonediff("zone_diff: remove_node: Removing node:\n"); +dbg_zonediff_exec_detail( + knot_node_dump((knot_node_t *)node, 1); +); + + const knot_rrset_t **rrsets = knot_node_rrsets(node); + if (rrsets == NULL) { + dbg_zonediff_verb("zone_diff: remove_node: " + "Nothing to remove.\n"); + return KNOT_EOK; + } + + dbg_zonediff_detail("zone_diff: remove_node: Will be removing %d RRSets.\n", + knot_node_rrset_count(node)); + + /* Remove all the RRSets of the node. */ + for (uint i = 0; i < knot_node_rrset_count(node); i++) { + int ret = knot_zone_diff_changeset_remove_rrset(changeset, + rrsets[i]); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: remove_node: Failed to " + "remove rrset. Error: %s\n", + knot_strerror(ret)); + free(rrsets); + return ret; + } + } + + free(rrsets); + + return KNOT_EOK; +} + +static int knot_zone_diff_rdata_return_changes(const knot_rrset_t *rrset1, + const knot_rrset_t *rrset2, + knot_rrset_t **changes) +{ + if (rrset1 == NULL || rrset2 == NULL) { + dbg_zonediff("zone_diff: diff_rdata: NULL arguments. (%p) (%p).\n", + rrset1, rrset2); + return KNOT_EBADARG; + } + + /* + * Take one rdata from first list and search through the second list + * looking for an exact match. If no match occurs, it means that this + * particular RR has changed. + * After the list has been traversed, we have a list of + * changed/removed rdatas. This has awful computation time. + */ + dbg_zonediff_detail("zone_diff: diff_rdata: Diff of %s, type=%s. " + "RR count 1=%d RR count 2=%d.\n", + knot_dname_to_str(rrset1->owner), + knot_rrtype_to_string(rrset1->type), + knot_rrset_rdata_rr_count(rrset1), + knot_rrset_rdata_rr_count(rrset2)); + + /* Create fake RRSet, it will be easier to handle. */ + *changes = knot_rrset_new(knot_rrset_get_owner(rrset1), + knot_rrset_type(rrset1), + knot_rrset_class(rrset1), + knot_rrset_ttl(rrset1)); + if (*changes == NULL) { + dbg_zonediff("zone_diff: diff_rdata: " + "Could not create RRSet with changes.\n"); + return KNOT_ENOMEM; + } + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(knot_rrset_type(rrset1)); + assert(desc); + + const knot_rdata_t *tmp_rdata = knot_rrset_rdata(rrset1); + while(tmp_rdata != NULL) { + const knot_rdata_t *tmp_rdata_second_rrset = + knot_rrset_rdata(rrset2); + while ((tmp_rdata_second_rrset != NULL) && + (knot_rdata_compare(tmp_rdata, + tmp_rdata_second_rrset, + desc->wireformat) != 0)) { + tmp_rdata_second_rrset = + knot_rrset_rdata_next(rrset2, + tmp_rdata_second_rrset); + } + if (tmp_rdata_second_rrset == NULL) { + /* + * This means that the while cycle above has finished + * because the list was traversed - there's no match. + */ + dbg_zonediff("zone_diff: diff_rdata: " + "No match for RR (type=%s owner=%s).\n", + knot_rrtype_to_string(knot_rrset_type(rrset1)), + knot_dname_to_str(rrset1->owner)); + /* Make a copy of tmp_rdata. */ + knot_rdata_t *tmp_rdata_copy = + knot_rdata_deep_copy(tmp_rdata, + knot_rrset_type(rrset1), + 1); + int ret = knot_rrset_add_rdata(*changes, + tmp_rdata_copy); + /*!< \todo dispose of the copy. */ + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_rdata: " + "Could not add rdata to rrset."); + knot_rrset_deep_free(changes, 1, 1, 0); + return ret; + } + } else { + dbg_zonediff_detail("zone_diff: diff_rdata: " + "Found matching RR for type %s.\n", + knot_rrtype_to_string(rrset1->type)); + } + tmp_rdata = knot_rrset_rdata_next(rrset1, tmp_rdata); + } + return KNOT_EOK; +} + +static int knot_zone_diff_rdata(const knot_rrset_t *rrset1, + const knot_rrset_t *rrset2, + knot_changeset_t *changeset) +{ + if ((changeset == NULL) || (rrset1 == NULL && rrset2 == NULL)) { + dbg_zonediff("zone_diff: diff_rdata: NULL arguments.\n"); + return KNOT_EBADARG; + } + /* + * The easiest solution is to remove all the RRs that had no match and + * to add all RRs that had no match, but those from second RRSet. */ + + /* Get RRs to remove from zone. */ + knot_rrset_t *to_remove = NULL; + if (rrset1 != NULL && rrset2 == NULL) { + assert(rrset1->type == KNOT_RRTYPE_RRSIG); + dbg_zonediff_detail("zone_diff: diff_rdata: RRSIG will be " + "removed.\n"); + int ret = knot_rrset_deep_copy(rrset1, &to_remove, 1); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_rdata: Could not copy rrset. " + "Error: %s.\n", knot_strerror(ret)); + return ret; + } + } else if (rrset1 != NULL && rrset2 != NULL) { + int ret = knot_zone_diff_rdata_return_changes(rrset1, rrset2, + &to_remove); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_rdata: Could not get changes. " + "Error: %s.\n", knot_strerror(ret)); + return ret; + } + } else { + dbg_zonediff("zone_diff: diff_rdata: These are not the diffs you " + "are looking for.\n"); + } + + dbg_zonediff_detail("zone_diff: diff_rdata: To remove:\n"); + knot_rrset_dump(to_remove, 1); + + int ret = knot_zone_diff_changeset_remove_rrset(changeset, + to_remove); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&to_remove, 1, 1, 1); + dbg_zonediff("zone_diff: diff_rdata: Could not remove RRs. " + "Error: %s.\n", knot_strerror(ret)); + return ret; + } + + /* Copy was made in add_rrset function, we can free now. */ + knot_rrset_deep_free(&to_remove, 1, 1, 1); + + /* Get RRs to add to zone. */ + knot_rrset_t *to_add = NULL; + if (rrset2 != NULL && rrset1 == NULL) { + assert(rrset2->type == KNOT_RRTYPE_RRSIG); + dbg_zonediff_detail("zone_diff: diff_rdata: RRSIG will be " + "added.\n"); + int ret = knot_rrset_deep_copy(rrset2, &to_add, 1); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_rdata: Could not copy rrset. " + "Error: %s.\n", knot_strerror(ret)); + return ret; + } + } else if (rrset1 != NULL && rrset2 != NULL) { + ret = knot_zone_diff_rdata_return_changes(rrset2, rrset1, + &to_add); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_rdata: Could not get changes. " + "Error: %s.\n", knot_strerror(ret)); + return ret; + } + } else { + dbg_zonediff("zone_diff: diff_rdata: These are not the diffs you " + "are looking for.\n"); + } + + dbg_zonediff_detail("zone_diff: diff_rdata: To add:\n"); + knot_rrset_dump(to_add, 1); + + ret = knot_zone_diff_changeset_add_rrset(changeset, + to_add); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&to_add, 1, 1, 1); + dbg_zonediff("zone_diff: diff_rdata: Could not remove RRs. " + "Error: %s.\n", knot_strerror(ret)); + return ret; + } + + /* Copy was made in add_rrset function, we can free now. */ + knot_rrset_deep_free(&to_add, 1, 1, 1); + + return KNOT_EOK; +} + +static int knot_zone_diff_rrsets(const knot_rrset_t *rrset1, + const knot_rrset_t *rrset2, + knot_changeset_t *changeset) +{ +// if (rrset1 == NULL || rrset2 == NULL) { +// /* This could happen when diffing RRSIGs. */ +// if (rrset1 == NULL && rrset2 != NULL) { +// dbg_zonediff("zone_diff: diff_rrsets: RRSIG missing in first" +// " rrset1.\n"); +// int ret = +// knot_zone_diff_changeset_add_rrset(changeset, +// rrset2); +// if (ret != KNOT_EOK) { +// dbg_zonediff("zone_diff: diff_rrsets: " +// "Cannot add RRSIG. (%s)\n", +// knot_strerror(ret)); +// } +// } else if (rrset1 != NULL && rrset2 == NULL) { +// dbg_zonediff("zone_diff: diff_rrsets: RRSIG missing in second" +// " rrset1.\n"); +// int ret = +// knot_zone_diff_changeset_remove_rrset(changeset, +// rrset1); +// if (ret != KNOT_EOK) { +// dbg_zonediff("zone_diff: diff_rrsets: " +// "Cannot remove RRSIG. (%s)\n", +// knot_strerror(ret)); +// } +// } +// dbg_zonediff_detail("zone_diff: diff_rrsets: " +// "NULL arguments (RRSIGs?). (%p) (%p)\n", +// rrset1, rrset2); +// return KNOT_EOK; +// } + + assert(knot_dname_compare(knot_rrset_owner(rrset1), + knot_rrset_owner(rrset2)) == 0); + assert(knot_rrset_type(rrset1) == knot_rrset_type(rrset2)); + + int ret = knot_zone_diff_rdata(knot_rrset_rrsigs(rrset1), + knot_rrset_rrsigs(rrset2), changeset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_rrsets (%s:%s): Failed to diff RRSIGs. " + "They were: %p %p. (%s).\n", + knot_dname_to_str(rrset1->owner), + knot_rrtype_to_string(rrset1->type), + rrset1->rrsigs, + rrset2->rrsigs, knot_strerror(ret)); + } + + /* RRs (=rdata) have to be cross-compared, unfortunalely. */ + return knot_zone_diff_rdata(rrset1, rrset2, changeset); +} + +/*!< \todo this could be generic function for adding / removing. */ +static void knot_zone_diff_node(knot_node_t *node, void *data) +{ + if (node == NULL || data == NULL) { + dbg_zonediff("zone_diff: diff_node: NULL arguments.\n"); + return; + } + + struct zone_diff_param *param = (struct zone_diff_param *)data; + if (param->changeset == NULL || param->contents == NULL) { + dbg_zonediff("zone_diff: diff_node: NULL arguments.\n"); + param->ret = KNOT_EBADARG; + return; + } + + if (param->ret != KNOT_EOK) { + /* Error occured before, no point in continuing. */ + dbg_zonediff_detail("zone_diff: diff_node: error: %s\n", + knot_strerror(param->ret)); + return; + } + + /* + * First, we have to search the second tree to see if there's according + * node, if not, the whole node has been removed. + */ + const knot_node_t *node_in_second_tree = NULL; + const knot_dname_t *node_owner = knot_node_owner(node); + assert(node_owner); + if (!param->nsec3) { + node_in_second_tree = + knot_zone_contents_find_node(param->contents, + node_owner); + } else { + dbg_zonediff_verb("zone_diff: diff_node: NSEC3 zone.\n"); + node_in_second_tree = + knot_zone_contents_find_nsec3_node(param->contents, + node_owner); + } + + if (node_in_second_tree == NULL) { + dbg_zonediff_detail("zone_diff: diff_node: Node %s is not " + "in the second tree.\n", + knot_dname_to_str(node_owner)); + int ret = knot_zone_diff_remove_node(param->changeset, + node); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: failed to remove node.\n"); + param->ret = ret; + return; + } + param->ret = KNOT_EOK; + return; + } + + assert(node_in_second_tree != node); + + dbg_zonediff_detail("zone_diff: diff_node: Node %s is present in " + "both trees.\n", knot_dname_to_str(node_owner)); + /* The nodes are in both trees, we have to diff each RRSet. */ + const knot_rrset_t **rrsets = knot_node_rrsets(node); + if (rrsets == NULL) { + dbg_zonediff("zone_diff: Node in first tree has no RRSets.\n"); + /* + * If there are no RRs in the first tree, all of the RRs + * in the second tree will have to be inserted to ADD section. + */ + int ret = knot_zone_diff_add_node(node_in_second_tree, + param->changeset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_node: " + "Could not add node from second tree. " + "Reason: %s.\n", knot_strerror(ret)); + } + param->ret = ret; + return; + } + + for (uint i = 0; i < knot_node_rrset_count(node); i++) { + /* Search for the RRSet in the node from the second tree. */ + const knot_rrset_t *rrset = rrsets[i]; + assert(rrset); + + /* SOAs are handled explicitly. */ + if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA) { + continue; + } + + const knot_rrset_t *rrset_from_second_node = + knot_node_rrset(node_in_second_tree, + knot_rrset_type(rrset)); + if (rrset_from_second_node == NULL) { + dbg_zonediff("zone_diff: diff_node: There is no counterpart " + "for RRSet of type %s in second tree.\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); + /* RRSet has been removed. Make a copy and remove. */ + assert(rrset); + int ret = knot_zone_diff_changeset_remove_rrset( + param->changeset, + rrset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_node: " + "Failed to remove RRSet.\n"); + param->ret = ret; + free(rrsets); + return; + } + } else { + dbg_zonediff("zone_diff: diff_node: There is a counterpart " + "for RRSet of type %s in second tree.\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); + /* Diff RRSets. */ + int ret = knot_zone_diff_rrsets(rrset, + rrset_from_second_node, + param->changeset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: " + "Failed to diff RRSets.\n"); + param->ret = ret; + free(rrsets); + return; + } + +// dbg_zonediff_verb("zone_diff: diff_node: Changes in " +// "RRSIGs.\n"); +// /*! \todo There is ad-hoc solution in the function, maybe handle here. */ +// ret = knot_zone_diff_rrsets(rrset->rrsigs, +// rrset_from_second_node->rrsigs, +// param->changeset); +// if (ret != KNOT_EOK) { +// dbg_zonediff("zone_diff: " +// "Failed to diff RRSIGs.\n"); +// param->ret = ret; +// return; +// } + } + } + + free(rrsets); + + /*! \todo move to one function with the code above. */ + rrsets = knot_node_rrsets(node_in_second_tree); + if (rrsets == NULL) { + dbg_zonediff("zone_diff: Node in second tree has no RRSets.\n"); + /* + * This can happen when node in second + * tree is empty non-terminal and as such has no RRs. + * Whole node from the first tree has to be removed. + */ + // TODO following code creates duplicated RR in diff. + // IHMO such case should be handled here +// int ret = knot_zone_diff_remove_node(param->changeset, +// node); +// if (ret != KNOT_EOK) { +// dbg_zonediff("zone_diff: diff_node: " +// "Cannot remove node. Reason: %s.\n", +// knot_strerror(ret)); +// } + param->ret = KNOT_EOK; + return; + } + + for (uint i = 0; i < knot_node_rrset_count(node_in_second_tree); i++) { + /* Search for the RRSet in the node from the second tree. */ + const knot_rrset_t *rrset = rrsets[i]; + assert(rrset); + + /* SOAs are handled explicitly. */ + if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA) { + continue; + } + + const knot_rrset_t *rrset_from_first_node = + knot_node_rrset(node, + knot_rrset_type(rrset)); + if (rrset_from_first_node == NULL) { + dbg_zonediff("zone_diff: diff_node: There is no counterpart " + "for RRSet of type %s in first tree.\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); + /* RRSet has been added. Make a copy and add. */ + assert(rrset); + int ret = knot_zone_diff_changeset_add_rrset( + param->changeset, + rrset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_node: " + "Failed to add RRSet.\n"); + param->ret = ret; + free(rrsets); + return; + } + } else { + /* Already handled. */ + ; + } + } + + free(rrsets); + + assert(param->ret == KNOT_EOK); +} + +/*!< \todo possibly not needed! */ +static void knot_zone_diff_add_new_nodes(knot_node_t *node, void *data) +{ + assert(node); + if (node == NULL || data == NULL) { + dbg_zonediff("zone_diff: add_new_nodes: NULL arguments.\n"); + return; + } + + struct zone_diff_param *param = (struct zone_diff_param *)data; + if (param->changeset == NULL || param->contents == NULL) { + dbg_zonediff("zone_diff: add_new_nodes: NULL arguments.\n"); + param->ret = KNOT_EBADARG; + return; + } + + if (param->ret != KNOT_EOK) { + /* Error occured before, no point in continuing. */ + dbg_zonediff_detail("zone_diff: add_new_nodes: error: %s\n", + knot_strerror(param->ret)); + return; + } + + /* + * If a node is not present in the second zone, it is a new node + * and has to be added to changeset. Differencies on the RRSet level are + * already handled. + */ + const knot_zone_contents_t *other_zone = param->contents; + assert(other_zone); + + const knot_dname_t *node_owner = knot_node_owner(node); + /* + * Node should definitely have an owner, otherwise it would not be in + * the tree. + */ + assert(node_owner); + + knot_node_t *new_node = NULL; + if (!param->nsec3) { + new_node = knot_zone_contents_get_node(other_zone, node_owner); + } else { + new_node = knot_zone_contents_get_nsec3_node(other_zone, + node_owner); + } + + if (!new_node) { + assert(node); + int ret = knot_zone_diff_add_node(node, param->changeset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: add_new_nodes: Cannot add " + "node: %s to changeset. Reason: %s.\n", + knot_dname_to_str(node->owner), + knot_strerror(ret)); + } + } + + assert(param->ret == KNOT_EOK); +} + +int knot_zone_contents_diff(const knot_zone_contents_t *zone1, + const knot_zone_contents_t *zone2, + knot_changeset_t *changeset) +{ + if (zone1 == NULL || zone2 == NULL) { + dbg_zonediff("zone_diff: NULL argument(s).\n"); + return KNOT_EBADARG; + } + +// /* Create changeset structure. */ +// *changeset = malloc(sizeof(knot_changeset_t)); +// if (*changeset == NULL) { +// ERR_ALLOC_FAILED; +// return KNOT_ENOMEM; +// } + memset(changeset, 0, sizeof(knot_changeset_t)); + + /* Settle SOAs first. */ + int ret = knot_zone_diff_load_soas(zone1, zone2, changeset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: loas_SOAs failed with error: %s\n", + knot_strerror(ret)); + return ret; + } + + dbg_zonediff("zone_diff: SOAs loaded.\n"); + + /* Traverse one tree, compare every node, each RRSet with its rdata. */ + struct zone_diff_param param; + param.contents = zone2; + param.nsec3 = 0; + param.changeset = changeset; + param.ret = KNOT_EOK; + ret = knot_zone_contents_tree_apply_inorder( + (knot_zone_contents_t *)zone1, + knot_zone_diff_node, + ¶m); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: Tree traversal failed " + "with error: %s. Error from inner function: %s\n", + knot_strerror(ret), + knot_strerror(param.ret)); + return ret; + } + + /* Do the same for NSEC3 nodes. */ + param.nsec3 = 1; + ret = knot_zone_contents_nsec3_apply_inorder((knot_zone_contents_t *)zone1, knot_zone_diff_node, + ¶m); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: Tree traversal failed " + "with error: %s\n", + knot_strerror(ret)); + return ret; + } + + /* + * Some nodes may have been added. The code above will not notice, + * we have to go through the second tree and add missing nodes to + * changeset. + */ + param.nsec3 = 0; + param.contents = zone1; + ret = knot_zone_contents_tree_apply_inorder((knot_zone_contents_t *)zone2, + knot_zone_diff_add_new_nodes, + ¶m); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: Tree traversal failed " + "with error: %s. Error from inner function: %s\n", + knot_strerror(ret), + knot_strerror(param.ret)); + return ret; + } + + /* NSEC3 nodes. */ + param.nsec3 = 1; + param.contents = zone1; + ret = knot_zone_contents_nsec3_apply_inorder((knot_zone_contents_t *)zone2, + knot_zone_diff_add_new_nodes, + ¶m); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: Tree traversal failed " + "with error: %s\n", + knot_strerror(ret)); + return ret; + } + + return KNOT_EOK; +} + +#ifdef KNOT_ZONEDIFF_DEBUG +#ifdef DEBUG_ENABLE_DETAILS +static void knot_zone_diff_dump_changeset(knot_changeset_t *ch) +{ + dbg_zonediff_detail("Changeset FROM: %d\n", ch->serial_from); + rrset_dump_text(ch->soa_from, stderr); + dbg_zonediff_detail("\n"); + dbg_zonediff_detail("Changeset TO: %d\n", ch->serial_to); + rrset_dump_text(ch->soa_to, stderr); + dbg_zonediff_detail("\n"); + dbg_zonediff_detail("Adding %d RRs.\n", ch->add_count); + dbg_zonediff_detail("Removing %d RRs.\n", ch->remove_count); + + dbg_zonediff_detail("ADD section:\n"); + dbg_zonediff_detail("**********************************************\n"); + for (int i = 0; i < ch->add_count; i++) { + rrset_dump_text(ch->add[i], stderr); + dbg_zonediff_detail("\n"); + } + dbg_zonediff_detail("REMOVE section:\n"); + dbg_zonediff_detail("**********************************************\n"); + for (int i = 0; i < ch->remove_count; i++) { + rrset_dump_text(ch->remove[i], stderr); + dbg_zonediff_detail("\n"); + } +} +#endif +#endif + +int knot_zone_diff_create_changesets(const knot_zone_contents_t *z1, + const knot_zone_contents_t *z2, + knot_changesets_t **changesets) +{ + if (z1 == NULL || z2 == NULL) { + dbg_zonediff("zone_diff: create_changesets: NULL arguments.\n"); + return KNOT_EBADARG; + } + /* Create changesets. */ + int ret = knot_changeset_allocate(changesets); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: create_changesets: " + "Could not allocate changesets." + "Reason: %s.\n", knot_strerror(ret)); + return ret; + } + + memset((*changesets)->sets, 0, sizeof(knot_changeset_t)); + + ret = knot_zone_contents_diff(z1, z2, (*changesets)->sets); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: create_changesets: " + "Could not diff zones. " + "Reason: %s.\n", knot_strerror(ret)); + return ret; + } + + (*changesets)->count = 1; + + dbg_zonediff("Changesets created successfully!\n"); + dbg_zonediff_detail("Changeset dump:\n"); +dbg_zonediff_exec_detail( + knot_zone_diff_dump_changeset((*changesets)->sets); +); + + return KNOT_EOK; +} + +/* Mostly just for testing. We only shall diff zones in memory later. */ +//int knot_zone_diff_zones(const char *zonefile1, const char *zonefile2) +//{ + /* Compile test zones. */ +// int ret = zone_read("example.com.", "/home/jan/test/testzone1", "tmpzone1.db", 0); +// assert(ret == KNOT_EOK); +// ret = zone_read("example.com.", "/home/jan/test/testzone2", "tmpzone2.db", 0); +// assert(ret == KNOT_EOK); +// /* Load test zones. */ +// zloader_t *loader = NULL; +// int ret = knot_zload_open(&loader, "tmpzone1.db"); +// assert(ret == KNOT_EOK); +// knot_zone_t *z1 = knot_zload_load(loader); +// ret = knot_zload_open(&loader, "tmpzone2.db"); +// assert(ret == KNOT_EOK); +// knot_zone_t *z2 = knot_zload_load(loader); +// assert(z1 && z2); +// knot_changeset_t *changeset = malloc(sizeof(knot_changeset_t)); +// memset(changeset, 0, sizeof(knot_changeset_t)); +// assert(knot_zone_contents_diff(z1->contents, z2->contents, +// changeset) == KNOT_EOK); +// dbg_zonediff("Changeset created: From=%d to=%d.\n", changeset.serial_from, +// changeset.serial_to); +//// knot_changesets_t chngsets; +//// chngsets->sets = malloc(sizeof(knot_changeset_t)); +//// chngsets->sets[0] = changeset; +//// chngsets->count = 1; +//// chngsets->allocated = 1; +//// knot_zone_contents_t *new_zone = NULL; +//// ret = xfrin_apply_changesets(z1, chngsets, &new_zone); +//// if (ret != KNOT_EOK) { +//// dbg_zonediff("Application of changesets failed. (%s)\n", +//// knot_strerror(ret)); +//// } + +//// assert(new_zone); + +// /* Dump creted zone. */ +//// FILE *f = fopen("testovani", "w"); +//// zone_dump_text(new_zone, f); + +// knot_zone_deep_free(&z2, 0); +// knot_zone_deep_free(&z1, 0); +//// knot_zone_contents_deep_free(&new_zone, 1); +//// knot_zone_free(&z1); + +// knot_free_changeset(&changeset); +// exit(0); +//} + diff --git a/src/libknot/zone/zone-diff.h b/src/libknot/zone/zone-diff.h new file mode 100755 index 0000000..6e0eb1d --- /dev/null +++ b/src/libknot/zone/zone-diff.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KNOT_ZONE_DIFF_H_ +#define _KNOT_ZONE_DIFF_H_ + +#include "libknot/zone/zone-contents.h" +#include "libknot/updates/changesets.h" + +/*! \brief zone1 -> zone2 */ +int knot_zone_diff_create_changesets(const knot_zone_contents_t *z1, + const knot_zone_contents_t *z2, + knot_changesets_t **changesets); + +#endif // _KNOT_ZONE_DIFF_H_ diff --git a/src/libknot/zone/zone-tree.c b/src/libknot/zone/zone-tree.c index 2b79f86..7de460a 100644..100755 --- a/src/libknot/zone/zone-tree.c +++ b/src/libknot/zone/zone-tree.c @@ -110,7 +110,7 @@ static void knot_zone_tree_free_node(knot_zone_tree_node_t *node, knot_zone_tree_free_node(node->avl.avl_right, free_data); if (free_data) { - knot_node_free(&node->node, 0); + knot_node_free(&node->node); } free(node); @@ -132,8 +132,7 @@ static int knot_zone_tree_deep_copy_node(knot_zone_tree_node_t *from, } int ret = knot_node_shallow_copy(from->node, &(*to)->node); -// printf("Copied node: %p to node %p. New node1: %p, new node 2: %p\n", -// from->node, (*to)->node, from->node->new_node, (*to)->node->new_node); + if (ret != KNOT_EOK) { dbg_zone_verb("Failed to do shallow copy of node.\n"); free(*to); @@ -155,7 +154,7 @@ static int knot_zone_tree_deep_copy_node(knot_zone_tree_node_t *from, dbg_zone_verb("Failed to do shallow copy of right subtree.\n"); knot_zone_tree_free_node((*to)->avl.avl_left, 1); (*to)->avl.avl_left = NULL; - knot_node_free(&(*to)->node, 0); + knot_node_free(&(*to)->node); free(*to); *to = NULL; return ret; @@ -250,7 +249,7 @@ int knot_zone_tree_get(knot_zone_tree_t *tree, const knot_dname_t *owner, knot_zone_tree_node_t *n = TREE_FIND(tree, knot_zone_tree_node, avl, tmp); - knot_node_free(&tmp_data, 0); + knot_node_free(&tmp_data); free(tmp); if (n != NULL) { @@ -313,7 +312,7 @@ int knot_zone_tree_get_less_or_equal(knot_zone_tree_t *tree, int exact_match = TREE_FIND_LESS_EQUAL( tree, knot_zone_tree_node, avl, tmp, &f, &prev); - knot_node_free(&tmp_data, 0); + knot_node_free(&tmp_data); free(tmp); *found = (exact_match > 0) ? f->node : NULL; @@ -356,9 +355,17 @@ dbg_zone_exec_detail( /*! \todo Here we assume that the 'prev' pointer always points * to an empty non-terminal. */ + /*! \todo What did I mean by the previous TODO?? + * Nevertheless, it seems to me that node->prev can be + * an empty non-terminal too, cannot it? + */ + dbg_zone_detail("Previous: %p\n", prev->node); *previous = (knot_node_rrset_count(prev->node) == 0) ? knot_node_get_previous(prev->node) : prev->node; + dbg_zone_detail("Previous: %p, is empty: %d\n", *previous, + (*previous) ? knot_node_is_empty(*previous) + : -1); } assert(exact_match >= 0); @@ -399,11 +406,9 @@ int knot_zone_tree_remove(knot_zone_tree_t *tree, /*! \todo How to know if this was successful? */ TREE_REMOVE(tree, knot_zone_tree_node, avl, tmp); - knot_node_free(&tmp_data, 0); + knot_node_free(&tmp_data); free(tmp); -// *removed = (n) ? n->node : NULL; -// free(n); *removed = n; return KNOT_EOK; diff --git a/src/libknot/zone/zone-tree.h b/src/libknot/zone/zone-tree.h index ca65fe6..95b4e23 100644..100755 --- a/src/libknot/zone/zone-tree.h +++ b/src/libknot/zone/zone-tree.h @@ -39,8 +39,6 @@ typedef struct knot_zone_tree_node { TREE_ENTRY(knot_zone_tree_node) avl; /*! \brief Zone tree data. */ knot_node_t *node; - /*! \brief Owner of the node. */ -// knot_dname_t *owner; } knot_zone_tree_node_t; /*----------------------------------------------------------------------------*/ diff --git a/src/libknot/zone/zone.c b/src/libknot/zone/zone.c index 122b014..65f810d 100644..100755 --- a/src/libknot/zone/zone.c +++ b/src/libknot/zone/zone.c @@ -33,6 +33,12 @@ #include "hash/cuckoo-hash-table.h" #include "zone/zone-contents.h" +/*! \brief Adaptor for knot_zone_deep_free() */ +static void knot_zone_dtor(struct ref_t *p) { + knot_zone_t *z = (knot_zone_t *)p; + knot_zone_deep_free(&z, 0); +} + /*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -55,6 +61,13 @@ knot_zone_t *knot_zone_new_empty(knot_dname_t *name) // save the zone name dbg_zone("Setting zone name.\n"); zone->name = name; + + /* Initialize reference counting. */ + ref_init(&zone->ref, knot_zone_dtor); + + /* Set reference counter to 1, caller should release it after use. */ + knot_zone_retain(zone); + return zone; } @@ -133,14 +146,18 @@ void knot_zone_set_version(knot_zone_t *zone, time_t version) short knot_zone_is_master(const knot_zone_t *zone) { - return zone->master; + return zone->flags & KNOT_ZONE_MASTER; } /*----------------------------------------------------------------------------*/ void knot_zone_set_master(knot_zone_t *zone, short master) { - zone->master = master; + if (master) { + zone->flags |= KNOT_ZONE_MASTER; + } else { + zone->flags &= ~KNOT_ZONE_MASTER; + } } /*----------------------------------------------------------------------------*/ @@ -175,6 +192,7 @@ knot_zone_contents_t *knot_zone_switch_contents(knot_zone_t *zone, knot_zone_contents_t *old_contents = rcu_xchg_pointer(&zone->contents, new_contents); + return old_contents; } @@ -192,7 +210,7 @@ void knot_zone_free(knot_zone_t **zone) && !knot_zone_contents_gen_is_old((*zone)->contents)) { // zone is in the middle of an update, report dbg_zone("Destroying zone that is in the middle of an " - "update.\n"); + "update.\n"); } knot_dname_release((*zone)->name); @@ -221,7 +239,7 @@ void knot_zone_deep_free(knot_zone_t **zone, int destroy_dname_table) && !knot_zone_contents_gen_is_old((*zone)->contents)) { // zone is in the middle of an update, report dbg_zone("Destroying zone that is in the middle of an " - "update.\n"); + "update.\n"); } dbg_zone_exec( @@ -241,3 +259,21 @@ dbg_zone_exec( free(*zone); *zone = NULL; } + +void knot_zone_set_dtor(knot_zone_t *zone, int (*dtor)(struct knot_zone *)) +{ + if (zone != NULL) { + zone->dtor = dtor; + } +} + +void knot_zone_set_flag(knot_zone_t *zone, knot_zone_flag_t flag, unsigned on) +{ + if (zone != NULL) { + if (on) { + zone->flags |= flag; + } else { + zone->flags &= ~flag; + } + } +} diff --git a/src/libknot/zone/zone.h b/src/libknot/zone/zone.h index 331ef1f..31ff2ac 100644..100755 --- a/src/libknot/zone/zone.h +++ b/src/libknot/zone/zone.h @@ -34,6 +34,7 @@ #include "nsec3.h" #include "zone/dname-table.h" #include "common/tree.h" +#include "common/ref.h" #include "hash/cuckoo-hash-table.h" #include "zone-tree.h" @@ -41,11 +42,6 @@ #include "zone/zone-contents.h" /*----------------------------------------------------------------------------*/ - -//typedef TREE_HEAD(avl_tree, knot_node) avl_tree_t; -//struct event_t; - -/*----------------------------------------------------------------------------*/ /*! * \brief Return values for search functions. * @@ -58,6 +54,15 @@ enum knot_zone_retvals { typedef enum knot_zone_retvals knot_zone_retvals_t; +/*! + * \brief Zone flags. + */ +typedef enum knot_zone_flag_t { + KNOT_ZONE_SLAVE = 0 << 0, /*! Slave zone */ + KNOT_ZONE_MASTER = 1 << 0, /*! Master zone. */ + KNOT_ZONE_DISCARDED = 1 << 1 /*! Zone waiting to be discarded. */ +} knot_zone_flag_t; + /*----------------------------------------------------------------------------*/ /*! @@ -68,14 +73,14 @@ typedef enum knot_zone_retvals knot_zone_retvals_t; * double-free errors when destroying the zone. */ struct knot_zone { + ref_t ref; /*!< Reference counting. */ knot_dname_t *name; knot_zone_contents_t *contents; time_t version; - /*! \todo Set when loading zone. */ - short master; + unsigned flags; void *data; /*!< Pointer to generic zone-related data. */ int (*dtor)(struct knot_zone *); /*!< Data destructor. */ @@ -88,7 +93,7 @@ typedef struct knot_zone knot_zone_t; /*! * \brief Creates new empty DNS zone. * - * \notice Zone will be created without contents. + * \note Zone will be created without contents. * * \param name Zone owner. * @@ -152,6 +157,54 @@ void knot_zone_free(knot_zone_t **zone); */ void knot_zone_deep_free(knot_zone_t **zone, int destroy_dname_table); +/*! + * \brief Set destructor and initialize reference counter to 1. + * + * \param zone Related zone. + * \param dtor Destructor. + */ +void knot_zone_set_dtor(knot_zone_t *zone, int (*dtor)(struct knot_zone *)); + +/*! + * \brief Increment reference counter for dname. + * + * \param zone Referenced zone. + */ + static inline void knot_zone_retain(knot_zone_t *zone) { + if (zone != NULL) { + ref_retain(&zone->ref); + } +} + +/*! + * \brief Decrement reference counter for dname. + * + * \param zone Referenced zone. + */ + static inline void knot_zone_release(knot_zone_t *zone) { + if (zone != NULL) { + ref_release(&zone->ref); + } +} + +/*! + * \brief Return zone flags. + * + * \param zone Zone. + */ +static inline unsigned knot_zone_flags(knot_zone_t *zone) { + return zone->flags; +} + +/*! + * \brief Set zone flag. + * + * \param zone Zone. + * \param flag Respected flag. + * \param on 1 to set, 0 to unset flag. + */ +void knot_zone_set_flag(knot_zone_t *zone, knot_zone_flag_t flag, unsigned on); + #endif /*! @} */ diff --git a/src/libknot/zone/zonedb.c b/src/libknot/zone/zonedb.c index a9b6545..43b4489 100644..100755 --- a/src/libknot/zone/zonedb.c +++ b/src/libknot/zone/zonedb.c @@ -51,11 +51,11 @@ static int knot_zonedb_compare_zone_names(void *p1, void *p2) int ret = knot_dname_compare(zone1->name, zone2->name); -dbg_zonedb_exec( +dbg_zonedb_exec_detail( char *name1 = knot_dname_to_str(zone1->name); char *name2 = knot_dname_to_str(zone2->name); - dbg_zonedb("Compared names %s and %s, result: %d.\n", - name1, name2, ret); + dbg_zonedb_detail("Compared names %s and %s, result: %d.\n", + name1, name2, ret); free(name1); free(name2); ); @@ -64,23 +64,6 @@ dbg_zonedb_exec( } /*----------------------------------------------------------------------------*/ - -//static int knot_zonedb_replace_zone_in_list(void **list_item, void **new_zone) -//{ -// assert(list_item != NULL); -// assert(*list_item != NULL); -// assert(new_zone != NULL); -// assert(*new_zone != NULL); - -// dbg_zonedb("Replacing list item %p with new zone %p\n", -// *list_item, *new_zone); - -// *list_item = *new_zone; - -// return 0; -//} - -/*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -152,63 +135,13 @@ knot_zone_t *knot_zonedb_remove_zone(knot_zonedb_t *db, // remove the zone from the skip list, but do not destroy it gen_tree_remove(db->zone_tree, &dummy_zone); -// if (destroy_zone) { -// // properly destroy the zone and all its contents -// knot_zone_deep_free(&z, 0); -// } - db->zone_count--; - //return KNOT_EOK; return z; } /*----------------------------------------------------------------------------*/ -//knot_zone_t *knot_zonedb_replace_zone(knot_zonedb_t *db, -// knot_zone_t *zone) -//{ -// knot_zone_t *z = knot_zonedb_find_zone(db, -// knot_node_owner(knot_zone_apex(zone))); -// if (z == NULL) { -// return NULL; -// } - -// /*! \todo The replace should be atomic!!! */ - -// dbg_zonedb("Found zone: %p\n", z); - -// int ret = skip_remove(db->zones, -// (void *)knot_node_owner(knot_zone_apex(zone)), -// NULL, NULL); -// if (ret != 0) { -// return NULL; -// } - -// dbg_zonedb("Removed zone, return value: %d\n", ret); -// dbg_zonedb("Old zone: %p\n", z); - -// ret = skip_insert(db->zones, -// (void *)knot_node_owner(knot_zone_apex(zone)), -// (void *)zone, NULL); - -// dbg_zonedb("Inserted zone, return value: %d\n", ret); - -// if (ret != 0) { -// // return the removed zone back -// skip_insert(db->zones, -// (void *)knot_node_owner(knot_zone_apex(z)), -// (void *)z, NULL); -// /*! \todo There may be problems and the zone may remain -// removed. */ -// return NULL; -// } - -// return z; -//} - -/*----------------------------------------------------------------------------*/ - knot_zone_t *knot_zonedb_find_zone(const knot_zonedb_t *db, const knot_dname_t *zone_name) { @@ -229,11 +162,7 @@ const knot_zone_t *knot_zonedb_find_zone_for_name(knot_zonedb_t *db, knot_zone_t dummy_zone; dummy_zone.name = knot_dname_deep_copy(dname); void *found = NULL; - -// int exact_match = gen_tree_find_less_or_equal(db->zone_tree, -// &dummy_zone, -// &found); -// UNUSED(exact_match); + found = gen_tree_find(db->zone_tree, &dummy_zone); while (found == NULL && knot_dname_label_count(dummy_zone.name) > 0) { knot_dname_left_chop_no_copy(dummy_zone.name); @@ -351,54 +280,16 @@ static void delete_zone_from_db(void *node, void *data) knot_zone_t *zone = (knot_zone_t *)node; assert(zone); synchronize_rcu(); - knot_zone_deep_free(&zone, 0); + knot_zone_set_flag(zone, KNOT_ZONE_DISCARDED, 1); + knot_zone_release(zone); + zone = NULL; } void knot_zonedb_deep_free(knot_zonedb_t **db) { dbg_zonedb("Deleting zone db (%p).\n", *db); -// dbg_zonedb("Is it empty (%p)? %s\n", -// (*db)->zones, skip_is_empty((*db)->zones) ? "yes" : "no"); - -//dbg_zonedb_exec( -// int i = 1; -// char *name = NULL; -// while (zn != NULL) { -// dbg_zonedb("%d. zone: %p, key: %p\n", i, zn->value, -// zn->key); -// assert(zn->key == ((knot_zone_t *)zn->value)->apex->owner); -// name = knot_dname_to_str((knot_dname_t *)zn->key); -// dbg_zonedb(" zone name: %s\n", name); -// free(name); - -// zn = skip_next(zn); -// } - -// zn = skip_first((*db)->zones); -//); - -// while (zn != NULL) { -// zone = (knot_zone_t *)zn->value; -// assert(zone != NULL); - -// // remove the zone from the database -// skip_remove((*db)->zones, zn->key, NULL, NULL); -// // wait for all readers to finish -// synchronize_rcu; -// // destroy the zone -// knot_zone_deep_free(&zone, 0); - -// zn = skip_first((*db)->zones); -// } - -// assert(skip_is_empty((*db)->zones)); - -// skip_destroy_list(&(*db)->zones, NULL, NULL); gen_tree_destroy(&((*db)->zone_tree), delete_zone_from_db, NULL); assert((*db)->zone_tree == NULL); free(*db); *db = NULL; } - -/*----------------------------------------------------------------------------*/ - diff --git a/src/libknot/zone/zonedb.h b/src/libknot/zone/zonedb.h index d5a4992..81326bf 100644..100755 --- a/src/libknot/zone/zonedb.h +++ b/src/libknot/zone/zonedb.h @@ -85,9 +85,6 @@ int knot_zonedb_add_zone(knot_zonedb_t *db, knot_zone_t *zone); knot_zone_t * knot_zonedb_remove_zone(knot_zonedb_t *db, const knot_dname_t *zone_name); -//knot_zone_t *knot_zonedb_replace_zone(knot_zonedb_t *db, -// knot_zone_t *zone); - /*! * \brief Finds zone exactly matching the given zone name. * |