diff options
-rw-r--r-- | KNOWN_ISSUES | 2 | ||||
-rw-r--r-- | RELNOTES | 8 | ||||
-rwxr-xr-x | configure | 20 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/common/dynamic-array.c | 4 | ||||
-rw-r--r-- | src/knot/server/xfr-handler.c | 4 | ||||
-rw-r--r-- | src/knot/server/zones.c | 71 | ||||
-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 |
13 files changed, 296 insertions, 46 deletions
diff --git a/KNOWN_ISSUES b/KNOWN_ISSUES index 30ced5e..b10e4a3 100644 --- a/KNOWN_ISSUES +++ b/KNOWN_ISSUES @@ -11,3 +11,5 @@ Known bugs ========== * Slow start with too many zones. +* IXFR is still quite slow with large transfers (more than 50 000 RRs + changed), despite the previous improvements. @@ -1,3 +1,11 @@ +v1.0.6 - Jun 13, 2012 +--------------------- + +Bugfixes + * Fixed potential problems with RCU synchronization. + * Adding NSEC/NSEC3 for all wildcard CNAMEs in the response. + + v1.0.5 - May 17, 2012 --------------------- @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for knot 1.0.5. +# Generated by GNU Autoconf 2.68 for knot 1.0.6. # # Report bugs to <knot-dns@labs.nic.cz>. # @@ -570,8 +570,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='knot' PACKAGE_TARNAME='knot' -PACKAGE_VERSION='1.0.5' -PACKAGE_STRING='knot 1.0.5' +PACKAGE_VERSION='1.0.6' +PACKAGE_STRING='knot 1.0.6' PACKAGE_BUGREPORT='knot-dns@labs.nic.cz' PACKAGE_URL='' @@ -1303,7 +1303,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures knot 1.0.5 to adapt to many kinds of systems. +\`configure' configures knot 1.0.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1373,7 +1373,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of knot 1.0.5:";; + short | recursive ) echo "Configuration of knot 1.0.6:";; esac cat <<\_ACEOF @@ -1491,7 +1491,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -knot configure 1.0.5 +knot configure 1.0.6 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. @@ -2041,7 +2041,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by knot $as_me 1.0.5, which was +It was created by knot $as_me 1.0.6, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2859,7 +2859,7 @@ fi # Define the identity of the package. PACKAGE='knot' - VERSION='1.0.5' + VERSION='1.0.6' cat >>confdefs.h <<_ACEOF @@ -15070,7 +15070,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by knot $as_me 1.0.5, which was +This file was extended by knot $as_me 1.0.6, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -15136,7 +15136,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -knot config.status 1.0.5 +knot config.status 1.0.6 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 2410e0a..5875517 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # -*- Autoconf -*- AC_PREREQ([2.65]) -AC_INIT([knot], [1.0.5], [knot-dns@labs.nic.cz]) +AC_INIT([knot], [1.0.6], [knot-dns@labs.nic.cz]) AM_INIT_AUTOMAKE([gnu -Wall -Werror]) AC_CONFIG_SRCDIR([src/knot/main.c]) AC_CONFIG_HEADERS([src/config.h]) diff --git a/src/common/dynamic-array.c b/src/common/dynamic-array.c index e948821..24f2aaa 100644 --- a/src/common/dynamic-array.c +++ b/src/common/dynamic-array.c @@ -81,7 +81,7 @@ static int da_resize(da_array_t *array, da_resize_type_t type) dbg_da("Old items pointer: %p\n", old_items); // wait for readers to finish - synchronize_rcu(); + //synchronize_rcu(); // deallocate the old array dbg_da("RCU synchronized, deallocating old items array at address %p." "\n", old_items); @@ -205,7 +205,7 @@ void da_destroy(da_array_t *array) rcu_set_pointer(&array->items, NULL); pthread_mutex_unlock(&array->mtx); - synchronize_rcu(); + //synchronize_rcu(); free(old_items); pthread_mutex_destroy(&array->mtx); } diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c index f850642..a77f1f1 100644 --- a/src/knot/server/xfr-handler.c +++ b/src/knot/server/xfr-handler.c @@ -698,11 +698,11 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, "in %d seconds.\n", data->msgpref, tmr_s / 1000); } - rcu_read_unlock(); /* Update timers. */ server_t *server = (server_t *)knot_ns_get_data(w->ns); zones_timers_update(zone, zd->conf, server->sched); + rcu_read_unlock(); } else { /* Cleanup */ @@ -866,6 +866,7 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) /* Handle errors. */ if (ret != KNOT_EOK) { pthread_mutex_unlock(&zd->xfr_in.lock); + rcu_read_unlock(); dbg_xfr("xfr: failed to create XFR query type %d: %s\n", data->type, knot_strerror(ret)); close(data->session); @@ -1018,6 +1019,7 @@ static int xfr_update_msgpref(knot_ns_xfr_t *req, const char *keytag) zonedata_t *zd = (zonedata_t *)knot_zone_data(req->zone); if (zd == NULL) { free(r_key); + conf_read_unlock(); return KNOTD_EINVAL; } else { zname = zd->conf->name; diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index 6a710d4..37c1316 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -237,8 +237,12 @@ static uint32_t zones_soa_timer(knot_zone_t *zone, /* Retrieve SOA RDATA. */ const knot_rrset_t *soa_rrs = 0; const knot_rdata_t *soa_rr = 0; + + rcu_read_lock(); + knot_zone_contents_t * zc = knot_zone_get_contents((zone)); if (!zc) { + rcu_read_unlock(); return 0; } @@ -248,6 +252,8 @@ static uint32_t zones_soa_timer(knot_zone_t *zone, soa_rr = knot_rrset_rdata(soa_rrs); ret = rr_func(soa_rr); + rcu_read_unlock(); + /* Convert to miliseconds. */ return ret * 1000; } @@ -290,7 +296,6 @@ static uint32_t zones_soa_expire(knot_zone_t *zone) */ static int zones_expire_ev(event_t *e) { - rcu_read_lock(); dbg_zones("zones: EXPIRE timer event\n"); knot_zone_t *zone = (knot_zone_t *)e->data; if (zone == NULL || zone->data == NULL) { @@ -589,6 +594,8 @@ static int zones_notify_send(event_t *e) return KNOTD_EINVAL; } + rcu_read_lock(); + /* Check for answered/cancelled query. */ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); knot_zone_contents_t *contents = knot_zone_get_contents(zone); @@ -601,6 +608,7 @@ static int zones_notify_send(event_t *e) log_server_notice("NOTIFY query maximum number of retries " "for zone '%s' exceeded.\n", zd->conf->name); + rcu_read_unlock(); pthread_mutex_lock(&zd->lock); rem_node(&ev->n); evsched_event_free(e->parent, e); @@ -609,20 +617,19 @@ static int zones_notify_send(event_t *e) return KNOTD_EMALF; } - /* RFC suggests 60s, but it is configurable. */ - int retry_tmr = ev->timeout * 1000; + /* RFC suggests 60s, but it is configurable. */ + int retry_tmr = ev->timeout * 1000; - /* Reschedule. */ - conf_read_lock(); - evsched_schedule(e->parent, e, retry_tmr); - dbg_notify("notify: Query RETRY after %u secs (zone '%s')\n", - retry_tmr / 1000, zd->conf->name); - conf_read_unlock(); + /* Reschedule. */ + evsched_schedule(e->parent, e, retry_tmr); + dbg_notify("notify: Query RETRY after %u secs (zone '%s')\n", + retry_tmr / 1000, zd->conf->name); /* Prepare buffer for query. */ uint8_t *qbuf = malloc(SOCKET_MTU_SZ); if (qbuf == NULL) { log_zone_error("Not enough memory to allocate NOTIFY query.\n"); + rcu_read_unlock(); return KNOTD_ENOMEM; } @@ -632,9 +639,6 @@ static int zones_notify_send(event_t *e) int ret = notify_create_request(contents, qbuf, &buflen); if (ret == KNOTD_EOK && zd->server) { - /* Lock RCU. */ - rcu_read_lock(); - /* Create socket on random port. */ int sock = socket_create(ev->addr.family, SOCK_DGRAM); @@ -659,9 +663,6 @@ static int zones_notify_send(event_t *e) } - /* Unlock RCU */ - rcu_read_unlock(); - /* Mark as finished to prevent stalling. */ evsched_event_finished(e->parent); @@ -679,6 +680,8 @@ static int zones_notify_send(event_t *e) free(qbuf); + rcu_read_unlock(); + return ret; } @@ -1244,9 +1247,12 @@ static int zones_journal_apply(knot_zone_t *zone) return KNOTD_EINVAL; } + rcu_read_lock(); + knot_zone_contents_t *contents = knot_zone_get_contents(zone); zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); if (!contents || !zd) { + rcu_read_unlock(); return KNOTD_ENOENT; } @@ -1259,6 +1265,7 @@ static int zones_journal_apply(knot_zone_t *zone) soa_rr = knot_rrset_rdata(soa_rrs); int64_t serial_ret = knot_rdata_soa_serial(soa_rr); if (serial_ret < 0) { + rcu_read_unlock(); return KNOTD_EINVAL; } uint32_t serial = (uint32_t)serial_ret; @@ -1293,8 +1300,10 @@ static int zones_journal_apply(knot_zone_t *zone) } /* Switch zone immediately. */ + rcu_read_unlock(); apply_ret = xfrin_switch_zone(zone, contents, XFR_TYPE_IIN); + rcu_read_lock(); if (apply_ret == KNOT_EOK) { xfrin_cleanup_successful_update( &chsets->changes); @@ -1317,6 +1326,7 @@ static int zones_journal_apply(knot_zone_t *zone) } /* Free changesets and return. */ + rcu_read_unlock(); knot_free_changesets(&chsets); return ret; } @@ -1503,11 +1513,18 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, /* Update ANY queries policy */ if (zd->conf->disable_any) { + rcu_read_lock(); knot_zone_contents_t *contents = knot_zone_get_contents(zone); + + /*! \todo This is actually updating zone contents. + * It should be done in thread-safe way. + */ if (contents) { knot_zone_contents_disable_any(contents); } + + rcu_read_unlock(); } } @@ -1902,12 +1919,14 @@ int zones_update_db_from_config(const conf_t *conf, knot_nameserver_t *ns, if (*db_old == NULL) { log_server_error("Missing zone database in nameserver structure" ".\n"); + rcu_read_unlock(); return KNOTD_ERROR; } /* Create new zone DB */ knot_zonedb_t *db_new = knot_zonedb_new(); if (db_new == NULL) { + rcu_read_unlock(); return KNOTD_ERROR; } @@ -1941,13 +1960,14 @@ int zones_update_db_from_config(const conf_t *conf, knot_nameserver_t *ns, * All other have been loaded again so that the old must be destroyed. */ int ret = zones_remove_zones(db_new, *db_old); + + /* Unlock RCU, messing with any data will not affect us now */ + rcu_read_unlock(); + if (ret != KNOTD_EOK) { return ret; } - /* Unlock RCU, messing with any data will not affect us now */ - rcu_read_unlock(); - return KNOTD_EOK; } @@ -1970,9 +1990,13 @@ int zones_zonefile_sync(knot_zone_t *zone, journal_t *journal) /* Lock zone data. */ pthread_mutex_lock(&zd->lock); + /* Lock RCU for zone contents. */ + rcu_read_lock(); + knot_zone_contents_t *contents = knot_zone_get_contents(zone); if (!contents) { pthread_mutex_unlock(&zd->lock); + rcu_read_unlock(); return KNOTD_EINVAL; } @@ -1987,6 +2011,7 @@ int zones_zonefile_sync(knot_zone_t *zone, journal_t *journal) int64_t serial_ret = knot_rdata_soa_serial(soa_rr); if (serial_ret < 0) { pthread_mutex_unlock(&zd->lock); + rcu_read_unlock(); return KNOTD_EINVAL; } uint32_t serial_to = (uint32_t)serial_ret; @@ -2004,9 +2029,9 @@ int zones_zonefile_sync(knot_zone_t *zone, journal_t *journal) dbg_zones("zones: failed to sync '%s' to '%s'\n", zd->conf->name, zd->conf->file); pthread_mutex_unlock(&zd->lock); + rcu_read_unlock(); return ret; } - conf_read_unlock(); /* Update journal entries. */ @@ -2028,6 +2053,9 @@ int zones_zonefile_sync(knot_zone_t *zone, journal_t *journal) /* Unlock zone data. */ pthread_mutex_unlock(&zd->lock); + /* Unlock RCU. */ + rcu_read_unlock(); + return ret; } @@ -2401,10 +2429,10 @@ int zones_process_response(knot_nameserver_t *nameserver, log_zone_info("SOA query of '%s' to '%s@%d': Answered, no " "transfer needed.\n", zd->conf->name, r_addr, r_port); - rcu_read_unlock(); - + /* Reinstall timers. */ zones_timers_update(zone, zd->conf, sched); + rcu_read_unlock(); return KNOTD_EOK; } @@ -3152,6 +3180,7 @@ int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch) pthread_mutex_unlock(&zd->lock); /* Check XFR/IN master server. */ + conf_read_lock(); if (zd->xfr_in.master.ptr) { /* Schedule REFRESH timer. */ 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_ */ /*! @} */ |