summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2012-06-13 15:30:32 +0200
committerOndřej Surý <ondrej@sury.org>2012-06-13 15:30:32 +0200
commitc5832c95020769a610cfb9471c9275b291060c09 (patch)
tree1251aee07e6c941bf592fae3eed8ffa0724d3965
parent9a89122bfbf36d951b142449fce6816e4d3871b4 (diff)
parent4355eafde2b6a80d2b8feaba30b6a884aff070d9 (diff)
downloadknot-c5832c95020769a610cfb9471c9275b291060c09.tar.gz
Merge commit 'upstream/1.0.6' into debian-sid
-rw-r--r--KNOWN_ISSUES2
-rw-r--r--RELNOTES8
-rwxr-xr-xconfigure20
-rw-r--r--configure.ac2
-rw-r--r--src/common/dynamic-array.c4
-rw-r--r--src/knot/server/xfr-handler.c4
-rw-r--r--src/knot/server/zones.c71
-rw-r--r--src/libknot/hash/cuckoo-hash-table.c2
-rw-r--r--src/libknot/nameserver/name-server.c89
-rw-r--r--src/libknot/packet/packet.c21
-rw-r--r--src/libknot/packet/packet.h27
-rw-r--r--src/libknot/packet/response.c88
-rw-r--r--src/libknot/packet/response.h4
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.
diff --git a/RELNOTES b/RELNOTES
index 03f53b2..01614be 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -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
---------------------
diff --git a/configure b/configure
index 66d2c21..7404088 100755
--- a/configure
+++ b/configure
@@ -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_ */
/*! @} */