diff --git a/src/knot/zone/zone-dump.c b/src/knot/zone/zone-dump.c index 4d9f3f56bff9d0bc60c89234c36873f5dc33cd36..f22c19c15f09f1743c5eb5a0c083f8b863477b45 100644 --- a/src/knot/zone/zone-dump.c +++ b/src/knot/zone/zone-dump.c @@ -360,6 +360,11 @@ static int knot_rdata_dump_binary(knot_rdata_t *rdata, rdata->items[i].dname) { wildcard = rdata->items[i].dname->node->owner; } + + dbg_zdump_detail("zdump: dump_rdata: " + "Writing dname: %s.\n", + knot_dname_to_str( + rdata->items[i].dname)); if (use_ids) { /* Write ID. */ @@ -392,6 +397,8 @@ static int knot_rdata_dump_binary(knot_rdata_t *rdata, /*! \todo Does not have to be so complex. * Create extra variable. */ if (rdata->items[i].dname->node != NULL && !wildcard) { + dbg_zdump("zdump: dump_rdata: " + "This dname is in the zone.\n"); if (!write_wrapper((uint8_t *)"\1", sizeof(uint8_t), 1, fd, stream, max_size, @@ -401,6 +408,8 @@ static int knot_rdata_dump_binary(knot_rdata_t *rdata, return KNOT_ERROR; } } else { + dbg_zdump("zdump: dump_rdata: " + "This dname is not in the zone.\n"); if (!write_wrapper((uint8_t *)"\0", sizeof(uint8_t), 1, fd, @@ -423,6 +432,9 @@ static int knot_rdata_dump_binary(knot_rdata_t *rdata, } uint32_t wildcard_id = wildcard->id; + dbg_zdump("zdump: dump_rdata: " + "This dname is covered by wc (%s).\n", + knot_dname_to_str(wildcard)); if (!write_wrapper(&wildcard_id, sizeof(wildcard_id), 1, fd, stream, max_size, diff --git a/src/knot/zone/zone-load.c b/src/knot/zone/zone-load.c index 8832a795a8c1feec9a56d20e86a62ca3a136766c..bd777ccfd0b06d3d9bdbcc52eacc252f7f7234e9 100644 --- a/src/knot/zone/zone-load.c +++ b/src/knot/zone/zone-load.c @@ -285,6 +285,7 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, /*!< \todo #1686 * Refactor these variables, some might be too big. */ + uint32_t dname_id = 0; uint8_t has_wildcard = 0; @@ -306,6 +307,11 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, } else { items[i].dname = read_dname_with_id(f); } + + dbg_zload_detail("zload: load_rdata: " + "Loading dname: %s.\n", + knot_dname_to_str(items[i].dname)); + if(!fread_wrapper(&in_the_zone, sizeof(in_the_zone), 1, f)) { @@ -322,6 +328,23 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, "Cannot read wildcard bit.\n"); return NULL; } + + dbg_zload_detail("zload: load_rdata: Has wildcard: " + "%d\n", has_wildcard); + + if (use_ids && !in_the_zone) { + dbg_zload_detail("zload: load_rdata: " + "Freeing node owned by: %s\n", + knot_dname_to_str( + items[i].dname)); + /* destroy the node */ + assert(!in_the_zone); + if (items[i].dname->node != NULL) { + knot_node_free(&items[i].dname->node, + 0); + } + /* Also sets node to NULL! */ + } if (use_ids && has_wildcard) { if(!fread_wrapper(&dname_id, sizeof(dname_id), @@ -332,16 +355,14 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, "Cannot read wc ID.\n"); return NULL; } + dbg_zload_detail("zload: load_rdata: " + "Wildcard: %s\n", + knot_dname_to_str( + id_array[dname_id])); items[i].dname->node = id_array[dname_id]->node; - } else if (use_ids && !in_the_zone) { - /* destroy the node */ - if (id_array[dname_id]->node != NULL) { - knot_node_free(&id_array[dname_id]-> - node, 0); - } - /* Also sets node to NULL! */ } + assert(items[i].dname); } else { if (!fread_wrapper(&raw_data_length, @@ -1190,6 +1211,9 @@ knot_zone_t *knot_zload_load(zloader_t *loader) for (uint i = 1; i < node_count; i++) { tmp_node = knot_load_node(f, id_array); if (tmp_node != NULL) { + dbg_zload_detail("zload: load: Adding node owned by: " + "%s\n.", + knot_dname_to_str(tmp_node->owner)); if (knot_zone_contents_add_node(contents, tmp_node, 0, 0, 0) != 0) { cleanup_id_array(id_array, 1, @@ -1200,6 +1224,7 @@ knot_zone_t *knot_zload_load(zloader_t *loader) "to zone.\n"); return NULL; } + if (knot_dname_is_wildcard(tmp_node->owner)) { find_and_set_wildcard_child(contents, tmp_node, 0); diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c index b437f1937632b4e0793a438070bae6882db14ca6..cf6522f0ddf9c6e943acc3874fd5cb4d412a32d0 100644 --- a/src/libknot/nameserver/name-server.c +++ b/src/libknot/nameserver/name-server.c @@ -594,14 +594,26 @@ static int ns_put_additional_for_rrset(knot_packet_t *resp, 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); 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))); + +// // 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); } knot_rrset_t *rrset_add; diff --git a/src/libknot/zone/zone-contents.c b/src/libknot/zone/zone-contents.c index abf9c3c9dd856e628e3fac5a6157eaf8a1a16ea9..17ebd340c9d63804a14bb4006c536a27c5ffedf7 100644 --- a/src/libknot/zone/zone-contents.c +++ b/src/libknot/zone/zone-contents.c @@ -260,6 +260,239 @@ dbg_zone_exec_detail( return KNOT_EOK; } +/*----------------------------------------------------------------------------*/ + +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); + + knot_dname_t *wildcard = knot_dname_cat(tmp, knot_node_owner( + closest_encloser)); + if (wildcard == NULL) { + free(tmp); + return NULL; + } + + 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; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adjusts one RDATA item by replacing domain name by one present in the + * zone. + * + * This function tries to find the domain name in the zone. If the name is not + * in the zone, it does nothing. If it is there, it destroys the domain name + * stored in the RDATA item and replaces it by pointer to the domain name from + * the zone. + * + * \warning Call this function only with RDATA items which store domain names, + * otherwise the behaviour is undefined. + * + * \param rdata RDATA where the item is located. + * \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) +{ + 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; + + 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) { + dname->node = (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); + ); + } + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adjusts all RDATA in the given RRSet by replacing domain names by ones + * present in the zone. + * + * This function selects the RDATA items containing a domain name (according to + * RR type descriptor of the RRSet's type and adjusts the item using + * knot_zone_adjust_rdata_item(). + * + * \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); + + 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; + + 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; + } + + 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); + } + } + +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adjusts all RRSets in the given node by replacing domain names in + * RDATA by ones present in the zone. + * + * This function just calls knot_zone_adjust_rdata_in_rrset() for all RRSets + * in the node (including all RRSIG RRSets). + * + * \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) +{ + 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. @@ -288,12 +521,8 @@ dbg_zone_exec_verb( ); // 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_detail( if (knot_node_parent(node)) { @@ -1725,19 +1954,23 @@ dbg_zone_exec_detail( 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(