diff options
Diffstat (limited to 'src/libknot')
-rw-r--r-- | src/libknot/hash/cuckoo-hash-table.c | 2 | ||||
-rw-r--r-- | src/libknot/nameserver/name-server.c | 89 | ||||
-rw-r--r-- | src/libknot/packet/packet.c | 21 | ||||
-rw-r--r-- | src/libknot/packet/packet.h | 27 | ||||
-rw-r--r-- | src/libknot/packet/response.c | 88 | ||||
-rw-r--r-- | src/libknot/packet/response.h | 4 |
6 files changed, 220 insertions, 11 deletions
diff --git a/src/libknot/hash/cuckoo-hash-table.c b/src/libknot/hash/cuckoo-hash-table.c index 50a7a0f..9db32bf 100644 --- a/src/libknot/hash/cuckoo-hash-table.c +++ b/src/libknot/hash/cuckoo-hash-table.c @@ -1037,6 +1037,7 @@ int ck_update_item(const ck_hash_table_t *table, const char *key, size_t length, ck_hash_table_item_t **item = ck_find_item_nc(table, key, length); if (item == NULL || (*item) == NULL) { + rcu_read_unlock(); return -1; } @@ -1060,6 +1061,7 @@ int ck_delete_item(const ck_hash_table_t *table, const char *key, size_t length, ck_hash_table_item_t **place = ck_find_item_nc(table, key, length); if (place == NULL) { + rcu_read_unlock(); return -1; } diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c index d938683..7a6bc4d 100644 --- a/src/libknot/nameserver/name-server.c +++ b/src/libknot/nameserver/name-server.c @@ -298,6 +298,14 @@ static void ns_follow_cname(const knot_node_t **node, add_rrset_to_resp(resp, rrset, tc, 0, 0, 1); ns_add_rrsigs(cname_rrset, resp, *qname, add_rrset_to_resp, tc); + + int ret = knot_response_add_wildcard_node( + resp, *node, *qname); + + /*! \todo Fix when return values are handled! */ + if (ret != KNOT_EOK) { + assert(0); + } } else { add_rrset_to_resp(resp, rrset, tc, 0, 0, 1); ns_add_rrsigs(rrset, resp, *qname, add_rrset_to_resp, @@ -1346,6 +1354,32 @@ static int ns_put_nsec_nsec3_wildcard_answer(const knot_node_t *node, } /*----------------------------------------------------------------------------*/ + +static int ns_put_nsec_nsec3_wildcard_nodes(knot_packet_t *response, + const knot_zone_contents_t *zone) +{ + assert(response != NULL); + assert(zone != NULL); + + int ret = 0; + + for (int i = 0; i < response->wildcard_nodes.count; ++i) { + ret = ns_put_nsec_nsec3_wildcard_answer( + response->wildcard_nodes.nodes[i], + knot_node_parent( + response->wildcard_nodes.nodes[i]), + NULL, zone, + response->wildcard_nodes.snames[i], + response); + if (ret != KNOT_EOK) { + return ret; + } + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ /*! * \brief Creates a referral response. * @@ -1470,7 +1504,7 @@ static inline int ns_referral(const knot_node_t *node, } if (ret == KNOT_EOK) { - ns_put_additional(resp); +// ns_put_additional(resp); knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); } return ret; @@ -1536,14 +1570,35 @@ static int ns_answer_from_node(const knot_node_t *node, } 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); +// } + 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) { - ns_put_additional(resp); - } +// if (ret == KNOT_EOK) { +// ns_put_additional(resp); +// } return ret; } @@ -1740,10 +1795,10 @@ dbg_ns_exec( char *name; if (node) { name = knot_dname_to_str(node->owner); - dbg_ns("zone_find_dname() returned node %s ", name); + dbg_ns("zone_find_dname() returned node %s \n", name); free(name); } else { - dbg_ns("zone_find_dname() returned no node,"); + dbg_ns("zone_find_dname() returned no node,\n"); } if (closest_encloser != NULL) { @@ -1806,14 +1861,15 @@ have_node: // return NXDOMAIN knot_response_set_rcode(resp, KNOT_RCODE_NXDOMAIN); - if (ns_put_nsec_nsec3_nxdomain(zone, previous, - closest_encloser, qname, resp) != 0) { - return NS_ERR_SERVFAIL; - } } else { knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); } + + if (ns_put_nsec_nsec3_nxdomain(zone, previous, + closest_encloser, qname, resp) != 0) { + return NS_ERR_SERVFAIL; + } knot_response_set_aa(resp); goto finalize; } @@ -1896,6 +1952,13 @@ finalize: ns_put_authority_soa(zone, resp); } + // add all missing NSECs/NSEC3s for wildcard nodes + ret = ns_put_nsec_nsec3_wildcard_nodes(resp, zone); + + if (ret == KNOT_EOK) { + ns_put_additional(resp); + } + return ret; } @@ -2468,6 +2531,8 @@ static int ns_ixfr_from_zone(knot_ns_xfr_t *xfr) assert(xfr->response != NULL); assert(knot_packet_authority_rrset_count(xfr->query) > 0); assert(xfr->data != NULL); + + rcu_read_lock(); knot_changesets_t *chgsets = (knot_changesets_t *)xfr->data; knot_zone_contents_t *contents = knot_zone_get_contents(xfr->zone); @@ -2487,6 +2552,7 @@ static int ns_ixfr_from_zone(knot_ns_xfr_t *xfr) /*! \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; } @@ -2495,6 +2561,7 @@ static int ns_ixfr_from_zone(knot_ns_xfr_t *xfr) res = ns_ixfr_put_changeset(xfr, &chgsets->sets[i]); if (res != KNOT_EOK) { // answer is sent + rcu_read_unlock(); return res; } } @@ -2510,6 +2577,8 @@ static int ns_ixfr_from_zone(knot_ns_xfr_t *xfr) // return 1; } + rcu_read_unlock(); + return KNOT_EOK; } diff --git a/src/libknot/packet/packet.c b/src/libknot/packet/packet.c index ed73afa..82b65c6 100644 --- a/src/libknot/packet/packet.c +++ b/src/libknot/packet/packet.c @@ -112,6 +112,18 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) pkt->compression.max = DEFAULT_DOMAINS_IN_RESPONSE; pkt->compression.default_count = DEFAULT_DOMAINS_IN_RESPONSE; + // wildcard nodes and SNAMEs associated with them + pkt->wildcard_nodes.nodes = (const knot_node_t **)pos; + pos += DEFAULT_WILDCARD_NODES * sizeof(const knot_node_t *); + 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); + + pkt->wildcard_nodes.default_count = DEFAULT_WILDCARD_NODES; + pkt->wildcard_nodes.max = DEFAULT_WILDCARD_NODES; + pkt->tmp_rrsets = (const knot_rrset_t **)pos; pos += DEFAULT_TMP_RRSETS * sizeof(const knot_rrset_t *); @@ -639,6 +651,11 @@ static void knot_packet_free_allocated_space(knot_packet_t *pkt) free(pkt->compression.offsets); } + if (pkt->wildcard_nodes.max > pkt->wildcard_nodes.default_count) { + free(pkt->wildcard_nodes.nodes); + free(pkt->wildcard_nodes.snames); + } + if (pkt->tmp_rrsets_max > DEFAULT_RRSET_COUNT(TMP_RRSETS, pkt)) { free(pkt->tmp_rrsets); } @@ -1460,6 +1477,10 @@ void knot_packet_free(knot_packet_t **packet) dbg_packet("Freeing tmp RRSets...\n"); knot_packet_free_tmp_rrsets(*packet); + /*! \note The above code will free the domain names pointed to by + * the list of wildcard nodes. It should not matter, however. + */ + // check if some additional space was allocated for the packet dbg_packet("Freeing additional allocated space...\n"); knot_packet_free_allocated_space(*packet); diff --git a/src/libknot/packet/packet.h b/src/libknot/packet/packet.h index c798133..9e37c12 100644 --- a/src/libknot/packet/packet.h +++ b/src/libknot/packet/packet.h @@ -33,6 +33,7 @@ #include "dname.h" #include "rrset.h" #include "edns.h" +#include "zone/node.h" /*----------------------------------------------------------------------------*/ /*! @@ -53,6 +54,16 @@ struct knot_compressed_dnames { typedef struct knot_compressed_dnames knot_compressed_dnames_t; +struct knot_wildcard_nodes { + const knot_node_t **nodes; /*!< Wildcard nodes from CNAME processing. */ + const knot_dname_t **snames; /*!< SNAMEs related to the nodes. */ + short count; /*!< Count of items in the previous arrays. */ + short max; /*!< Capacity of the structure (allocated). */ + short default_count; +}; + +typedef struct knot_wildcard_nodes knot_wildcard_nodes_t; + /*----------------------------------------------------------------------------*/ /*! * \brief Structure representing the DNS packet header. @@ -134,6 +145,9 @@ struct knot_packet { /*! \brief Information needed for compressing domain names in packet. */ knot_compressed_dnames_t compression; + /*! \brief Wildcard nodes to be processed for NSEC/NSEC3. */ + knot_wildcard_nodes_t wildcard_nodes; + /*! \brief RRSets to be destroyed with the packet structure. */ const knot_rrset_t **tmp_rrsets; short tmp_rrsets_count; /*!< Count of temporary RRSets. */ @@ -172,6 +186,9 @@ enum { /*! \brief Default count of temporary RRSets stored in response. */ DEFAULT_TMP_RRSETS = 5, + /*! \brief Default count of wildcard nodes saved for later processing.*/ + DEFAULT_WILDCARD_NODES = 1, + /*! \brief Default count of temporary RRSets stored in query. */ DEFAULT_TMP_RRSETS_QUERY = 2, @@ -179,7 +196,8 @@ enum { STEP_NSCOUNT = 8, /*!< Step for increasing space for Authority RRSets.*/ STEP_ARCOUNT = 8,/*!< Step for increasing space for Additional RRSets.*/ STEP_DOMAINS = 10, /*!< Step for resizing compression table. */ - STEP_TMP_RRSETS = 5 /*!< Step for increasing temorary RRSets count. */ + STEP_TMP_RRSETS = 5, /*!< Step for increasing temorary RRSets count. */ + STEP_WILDCARD_NODES = 2 }; /*----------------------------------------------------------------------------*/ @@ -214,6 +232,12 @@ enum { DEFAULT_DOMAINS_IN_RESPONSE * sizeof(size_t), PREALLOC_COMPRESSION = PREALLOC_DOMAINS + PREALLOC_OFFSETS, + PREALLOC_WC_NODES = + DEFAULT_WILDCARD_NODES * sizeof(knot_node_t *), + PREALLOC_WC_SNAMES = + DEFAULT_WILDCARD_NODES * sizeof(knot_dname_t *), + PREALLOC_WC = PREALLOC_WC_NODES + PREALLOC_WC_SNAMES, + PREALLOC_QUERY = PREALLOC_PACKET + PREALLOC_QNAME + PREALLOC_RRSETS(DEFAULT_ANCOUNT_QUERY) @@ -229,6 +253,7 @@ enum { + PREALLOC_RRSETS(DEFAULT_NSCOUNT) + PREALLOC_RRSETS(DEFAULT_ARCOUNT) + PREALLOC_COMPRESSION + + PREALLOC_WC + PREALLOC_RRSETS(DEFAULT_TMP_RRSETS) }; diff --git a/src/libknot/packet/response.c b/src/libknot/packet/response.c index d113cdf..9f6277c 100644 --- a/src/libknot/packet/response.c +++ b/src/libknot/packet/response.c @@ -814,6 +814,53 @@ static int knot_response_realloc_rrsets(const knot_rrset_t ***rrsets, } /*----------------------------------------------------------------------------*/ +/*! + * \brief Reallocate space for Wildcard nodes. + * + * \retval KNOT_EOK + * \retval KNOT_ENOMEM + */ +static int knot_response_realloc_wc_nodes(const knot_node_t ***nodes, + const knot_dname_t ***snames, + short *max_count, + short default_max_count, short step) +{ + dbg_packet("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; + const knot_dname_t **old_snames = *snames; + + short new_max_count = *max_count + step; + + const knot_node_t **new_nodes = (const knot_node_t **)malloc( + new_max_count * sizeof(knot_node_t *)); + CHECK_ALLOC_LOG(new_nodes, KNOT_ENOMEM); + + const knot_dname_t **new_snames = (const knot_dname_t **)malloc( + new_max_count * sizeof(knot_dname_t *)); + if (new_snames == NULL) { + free(new_nodes); + return KNOT_ENOMEM; + } + + memcpy(new_nodes, *nodes, (*max_count) * sizeof(knot_node_t *)); + memcpy(new_snames, *snames, (*max_count) * sizeof(knot_dname_t *)); + + *nodes = new_nodes; + *snames = new_snames; + *max_count = new_max_count; + + if (free_old) { + free(old_nodes); + free(old_snames); + } + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -915,9 +962,20 @@ void knot_response_clear(knot_packet_t *resp, int clear_question) resp->an_rrsets = 0; resp->ns_rrsets = 0; resp->ar_rrsets = 0; + resp->compression.count = 0; + + /*! \todo Temporary RRSets are not deallocated, which may potentially + * lead to memory leaks should this function be used in other + * cases than with XFR-out. + */ knot_packet_free_tmp_rrsets(resp); resp->tmp_rrsets_count = 0; + + /*! \todo If this function is used in other cases than with XFR-out, + * the list of wildcard nodes should be cleared here. + */ + resp->header.ancount = 0; resp->header.nscount = 0; resp->header.arcount = 0; @@ -1201,3 +1259,33 @@ int knot_response_add_nsid(knot_packet_t *response, const uint8_t *data, return knot_edns_add_option(&response->opt_rr, EDNS_OPTION_NSID, length, data); } + +/*----------------------------------------------------------------------------*/ + +int knot_response_add_wildcard_node(knot_packet_t *response, + const knot_node_t *node, + const knot_dname_t *sname) +{ + if (response == NULL || node == NULL || sname == NULL) { + return KNOT_EBADARG; + } + + if (response->wildcard_nodes.count == response->wildcard_nodes.max + && knot_response_realloc_wc_nodes(&response->wildcard_nodes.nodes, + &response->wildcard_nodes.snames, + &response->wildcard_nodes.max, + DEFAULT_WILDCARD_NODES, + STEP_WILDCARD_NODES) != KNOT_EOK) { + return KNOT_ENOMEM; + } + + response->wildcard_nodes.nodes[response->wildcard_nodes.count] = node; + response->wildcard_nodes.snames[response->wildcard_nodes.count] = sname; + ++response->wildcard_nodes.count; + + dbg_response("Current wildcard nodes count: %d, max count: %d\n", + response->wildcard_nodes.count, + response->wildcard_nodes.max); + + return KNOT_EOK; +} diff --git a/src/libknot/packet/response.h b/src/libknot/packet/response.h index d522f82..d3e66f3 100644 --- a/src/libknot/packet/response.h +++ b/src/libknot/packet/response.h @@ -197,6 +197,10 @@ void knot_response_set_tc(knot_packet_t *response); int knot_response_add_nsid(knot_packet_t *response, const uint8_t *data, uint16_t length); +int knot_response_add_wildcard_node(knot_packet_t *response, + const knot_node_t *node, + const knot_dname_t *sname); + #endif /* _KNOT_response_H_ */ /*! @} */ |