From d0aaffe65fa12a59c2ab29deee4470efb2fab333 Mon Sep 17 00:00:00 2001
From: Marek Vavrusa <marek.vavrusa@nic.cz>
Date: Wed, 15 Aug 2012 13:21:41 +0200
Subject: [PATCH] Zone data takes ownership of the zone config, which is
 removed from the global conf().

This way it retains a valid pointer to it's configuration when server reloads and
zone gets discarded.

refs #1976
---
 src/common/lists.h      |   1 +
 src/knot/conf/conf.c    | 138 +++++++++++++++++++---------------------
 src/knot/conf/conf.h    |  12 ++++
 src/knot/server/zones.c |  26 +++++++-
 4 files changed, 102 insertions(+), 75 deletions(-)

diff --git a/src/common/lists.h b/src/common/lists.h
index 972ea49efb..897b1a9407 100644
--- a/src/common/lists.h
+++ b/src/common/lists.h
@@ -71,6 +71,7 @@ typedef struct list {			/* In fact two overlayed nodes */
 	WALK_LIST_DELSAFE(n,nxt,list) { \
 	    free(n); \
 	} \
+	init_list(&list); \
 	} while(0)
 
 void add_tail(list *, node *);
diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c
index 447f59a8aa..e0bd0ea5ce 100644
--- a/src/knot/conf/conf.c
+++ b/src/knot/conf/conf.c
@@ -73,74 +73,6 @@ void cf_error(void *scanner, const char *msg)
 	_parser_res = KNOTD_EPARSEFAIL;
 }
 
-/*
- * Config helper functions.
- */
-
-/*! \brief Free TSIG key. */
-static void key_free(conf_key_t *k)
-{
-	/* Secure erase. */
-	if (k->k.secret) {
-		memset(k->k.secret, 0, strlen(k->k.secret));
-	}
-	free(k->k.secret);
-	knot_dname_free(&k->k.name);
-	free(k);
-}
-
-/*! \brief Free config interfaces. */
-static void iface_free(conf_iface_t *iface)
-{
-	if (!iface) {
-		return;
-	}
-
-	free(iface->name);
-	free(iface->address);
-	free(iface);
-}
-
-/*! \brief Free config logs. */
-static void log_free(conf_log_t *log)
-{
-	if (!log) {
-		return;
-	}
-
-	if (log->file) {
-		free(log->file);
-	}
-
-	/* Free loglevel mapping. */
-	node *n = 0, *nxt = 0;
-	WALK_LIST_DELSAFE(n, nxt, log->map) {
-		free((conf_log_map_t*)n);
-	}
-
-	free(log);
-}
-
-/*! \brief Free config zones. */
-static void zone_free(conf_zone_t *zone)
-{
-	if (!zone) {
-		return;
-	}
-
-	/* Free ACL lists. */
-	WALK_LIST_FREE(zone->acl.xfr_in);
-	WALK_LIST_FREE(zone->acl.xfr_out);
-	WALK_LIST_FREE(zone->acl.notify_in);
-	WALK_LIST_FREE(zone->acl.notify_out);
-
-	free(zone->name);
-	free(zone->file);
-	free(zone->db);
-	free(zone->ixfr_db);
-	free(zone);
-}
-
 /*!
  * \brief Call config hooks that need updating.
  *
@@ -574,33 +506,33 @@ void conf_truncate(conf_t *conf, int unload_hooks)
 
 	// Free keys
 	WALK_LIST_DELSAFE(n, nxt, conf->keys) {
-		key_free((conf_key_t *)n);
+		conf_free_key((conf_key_t *)n);
 	}
 
 	// Free interfaces
 	WALK_LIST_DELSAFE(n, nxt, conf->ifaces) {
-		iface_free((conf_iface_t*)n);
+		conf_free_iface((conf_iface_t*)n);
 	}
 	conf->ifaces_count = 0;
 	init_list(&conf->ifaces);
 
 	// Free logs
 	WALK_LIST_DELSAFE(n, nxt, conf->logs) {
-		log_free((conf_log_t*)n);
+		conf_free_log((conf_log_t*)n);
 	}
 	conf->logs_count = 0;
 	init_list(&conf->logs);
 
 	// Free remotes
 	WALK_LIST_DELSAFE(n, nxt, conf->remotes) {
-		iface_free((conf_iface_t*)n);
+		conf_free_iface((conf_iface_t*)n);
 	}
 	conf->remotes_count = 0;
 	init_list(&conf->remotes);
 
 	// Free zones
 	WALK_LIST_DELSAFE(n, nxt, conf->zones) {
-		zone_free((conf_zone_t*)n);
+		conf_free_zone((conf_zone_t*)n);
 	}
 	conf->zones_count = 0;
 	init_list(&conf->zones);
@@ -805,3 +737,63 @@ char* strcpath(char *path)
 	return path;
 }
 
+void conf_free_zone(conf_zone_t *zone)
+{
+	if (!zone) {
+		return;
+	}
+
+	/* Free ACL lists. */
+	WALK_LIST_FREE(zone->acl.xfr_in);
+	WALK_LIST_FREE(zone->acl.xfr_out);
+	WALK_LIST_FREE(zone->acl.notify_in);
+	WALK_LIST_FREE(zone->acl.notify_out);
+
+	free(zone->name);
+	free(zone->file);
+	free(zone->db);
+	free(zone->ixfr_db);
+	free(zone);
+}
+
+void conf_free_key(conf_key_t *k)
+{
+	/* Secure erase. */
+	if (k->k.secret) {
+		memset(k->k.secret, 0, strlen(k->k.secret));
+	}
+	free(k->k.secret);
+	knot_dname_free(&k->k.name);
+	free(k);
+}
+
+void conf_free_iface(conf_iface_t *iface)
+{
+	if (!iface) {
+		return;
+	}
+
+	free(iface->name);
+	free(iface->address);
+	free(iface);
+}
+
+void conf_free_log(conf_log_t *log)
+{
+	if (!log) {
+		return;
+	}
+
+	if (log->file) {
+		free(log->file);
+	}
+
+	/* Free loglevel mapping. */
+	node *n = 0, *nxt = 0;
+	WALK_LIST_DELSAFE(n, nxt, log->map) {
+		free((conf_log_map_t*)n);
+	}
+
+	free(log);
+}
+
diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h
index 3712e4b6b4..ae41454a53 100644
--- a/src/knot/conf/conf.h
+++ b/src/knot/conf/conf.h
@@ -349,6 +349,18 @@ char* strcdup(const char *s1, const char *s2);
  */
 char* strcpath(char *path);
 
+/*! \brief Free zone config. */
+void conf_free_zone(conf_zone_t *zone);
+
+/*! \brief Free TSIG key config. */
+void conf_free_key(conf_key_t *k);
+
+/*! \brief Free interface config. */
+void conf_free_iface(conf_iface_t *iface);
+
+/*! \brief Free log config. */
+void conf_free_log(conf_log_t *log);
+
 #endif /* _KNOTD_CONF_H_ */
 
 /*! @} */
diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c
index 2e9ff9100e..20a859e51d 100644
--- a/src/knot/server/zones.c
+++ b/src/knot/server/zones.c
@@ -118,6 +118,9 @@ static int zonedata_destroy(knot_zone_t *zone)
 
 	/* Close IXFR db. */
 	journal_release(zd->ixfr_db);
+	
+	/* Free assigned config. */
+	conf_free_zone(zd->conf);
 
 	free(zd);
 	
@@ -1490,7 +1493,10 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst,
 		assert(zd != NULL);
 
 		/* Update refs. */
-		zd->conf = z;
+		if (zd->conf != z) {
+			conf_free_zone(zd->conf);
+			zd->conf = z;
+		}
 
 		/* Update ACLs. */
 		dbg_zones("Updating zone ACLs.\n");
@@ -1664,11 +1670,15 @@ static int zonewalker(dthread_t *thread)
 	pthread_mutex_lock(&zw->lock);
 	zw->inserted += inserted;
 	for (int i = 0; i < inserted; ++i) {
+		zonedata_t *zd = (zonedata_t *)knot_zone_data(zones[i]);
 		if (knot_zonedb_add_zone(zw->db_new, zones[i]) != KNOT_EOK) {
-			zonedata_t *zd = (zonedata_t *)knot_zone_data(zones[i]);
 			log_server_error("Failed to insert zone '%s' "
 			                 "into database.\n", zd->conf->name);
 			knot_zone_deep_free(zones + i, 0);
+		} else {
+			/* Unlink zone config from conf(),
+			 * transferring ownership to zonedata. */
+			rem_node(&zd->conf->n);
 		}
 	}
 	pthread_mutex_unlock(&zw->lock);
@@ -1782,6 +1792,18 @@ dbg_zones_exec(
                                        "from database.\n", name);
 			free(name);
 );
+			/* Invalidate ACLs - since we would need to copy each
+			 * remote data and keep ownership, I think it's no harm
+			 * to drop all ACLs for the discarded zone.
+			 * refs #1976 */
+			zonedata_t *zd = (zonedata_t*)knot_zone_data(old_zone);
+			conf_zone_t *zconf = zd->conf;
+			WALK_LIST_FREE(zconf->acl.xfr_in);
+			WALK_LIST_FREE(zconf->acl.xfr_out);
+			WALK_LIST_FREE(zconf->acl.notify_in);
+			WALK_LIST_FREE(zconf->acl.notify_out);
+			
+			/* Remove from zone db. */
 			knot_zone_t * rm = knot_zonedb_remove_zone(db_old,
 			                              knot_zone_name(old_zone));
 			assert(rm == old_zone);
-- 
GitLab