From cf42a019b3e3a8e1be0d2a07ea6c595f9763454d Mon Sep 17 00:00:00 2001
From: Lubos Slovak <lubos.slovak@nic.cz>
Date: Wed, 4 Sep 2013 18:50:20 +0200
Subject: [PATCH] Always incrementing SOA on zone resign.

Added some more ugly hacks to properly use SOAs from the two
changesets.

refs #4
---
 src/knot/server/zones.c          | 56 +++++++++++++++++++-------------
 src/libknot/updates/changesets.c |  6 ++++
 src/libknot/updates/changesets.h |  4 +++
 3 files changed, 43 insertions(+), 23 deletions(-)

diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c
index 3e9ba1fb0..366faeca4 100644
--- a/src/knot/server/zones.c
+++ b/src/knot/server/zones.c
@@ -1075,10 +1075,16 @@ static void zones_free_merged_changesets(knot_changesets_t *diff_chs,
 			knot_changesets_free(&sec_chs);
 			knot_changesets_free(&diff_chs);
 		} else {
+			/* Ending SOA from the merged changeset was used in
+			 * zone (same as in DNSSEC changeset). It thus must not
+			 * be freed.
+			 */
+			knot_changesets_get_last(diff_chs)->soa_to = NULL;
 			knot_changesets_free(&diff_chs);
 
-			// the "SOA to" from the second changeset is not used,
-			// thus must be freed
+			/* the "SOA from" from the second changeset is not used,
+			 * thus must be freed
+			 */
 			knot_rrset_deep_free_no_sig(
 			  &(knot_changesets_get_last(sec_chs)->soa_from), 1, 1);
 
@@ -1106,24 +1112,28 @@ static int zones_merge_and_store_changesets(knot_zone_t *zone,
 		return zones_store_changesets_to_disk(zone, sec_chs);
 	}
 
-	/*
-	 * Merge changesets (only one in each 'changesets_t' structure),
-	 * use serial from diff (it's user supplied).
+	knot_changeset_t *diff_ch = knot_changesets_get_last(diff_chs);
+	knot_changeset_t *sec_ch =  knot_changesets_get_last(sec_chs);
+
+	/* SOAs in 'sec_chs' shouldn't be the same. */
+	assert(sec_ch->serial_from != sec_ch->serial_to);
+
+	/* But beginning SOA of second changeset should be equal to ending SOA
+	 * of the first changeset.
 	 */
-	int ret = knot_changeset_merge(knot_changesets_get_last(diff_chs),
-	                               knot_changesets_get_last(sec_chs));
+	assert(diff_ch->serial_to == sec_ch->serial_from);
+
+	int ret = knot_changeset_merge(diff_ch, sec_ch);
 	if (ret != KNOT_EOK) {
 		return ret;
 	}
 
-	/* SOAs in 'sec_chs' should be the same. */
-	assert(knot_changesets_get_last(sec_chs)->serial_from ==
-	       knot_changesets_get_last(sec_chs)->serial_to);
-	/* And they should be the same as the 'to' from 'diff_chs'. */
-	assert(knot_changesets_get_last(diff_chs)->serial_to ==
-	       knot_changesets_get_last(sec_chs)->serial_to);
-	/* First SOA should not be set. */
-	assert(sec_chs->first_soa == NULL);
+	/* Now the ending serial of first changeset (the merged one) should be
+	 * equal to the ending serial of second changeset. Also the SOAs should
+	 * be the same.
+	 */
+	assert(diff_ch->serial_to == sec_ch->serial_to);
+	assert(diff_ch->soa_to == sec_ch->soa_to);
 
 	/* Store *ALL* changes to disk. (and only apply 'sec_chs', but not here. */
 	ret = zones_store_changesets_to_disk(zone, diff_chs);
@@ -1421,13 +1431,13 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst,
 				return KNOT_ENOMEM;
 			}
 
-			/* Sign the zone. Do not incr. serial if diff did that. */
-			knot_update_serial_t soa_up = 
-				zones_changesets_empty(diff_chs) ?
-				KNOT_SOA_SERIAL_INC : KNOT_SOA_SERIAL_KEEP;
+			/* Increment serial even if diff did that. This way
+			 * it's always possible to flush the changes to zonefile
+			 * and it's also more correct (change in the zone =
+			 * serial increment).
+			 */
+			knot_update_serial_t soa_up =  KNOT_SOA_SERIAL_INC;
 
-			dbg_zones(stderr, "Signing zone, serial policy: %d\n",
-			          soa_up);
 			int ret = knot_dnssec_zone_sign(zone, sec_ch, soa_up);
 			if (ret != KNOT_EOK) {
 				knot_changesets_free(&diff_chs);
@@ -1438,9 +1448,9 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst,
 		}
 
 		/* Merge changesets created by diff and sign. */
-		int ret = zones_merge_and_store_changesets(zone,
-		                                           diff_chs,
+		int ret = zones_merge_and_store_changesets(zone, diff_chs,
 		                                           sec_chs);
+
 		if (ret != KNOT_EOK) {
 			knot_changesets_free(&diff_chs);
 			knot_changesets_free(&sec_chs);
diff --git a/src/libknot/updates/changesets.c b/src/libknot/updates/changesets.c
index d2c5f8481..81781f75d 100644
--- a/src/libknot/updates/changesets.c
+++ b/src/libknot/updates/changesets.c
@@ -293,6 +293,12 @@ int knot_changeset_merge(knot_changeset_t *ch1, knot_changeset_t *ch2)
 	add_tail_list(&ch1->add, &ch2->add);
 	add_tail_list(&ch1->remove, &ch2->remove);
 
+	// Use soa_to and serial from the second changeset
+	// soa_to from the first changeset is redundant, delete it
+	knot_rrset_deep_free(&ch1->soa_to, 1, 1);
+	ch1->soa_to = ch2->soa_to;
+	ch1->serial_to = ch2->serial_to;
+
 	return KNOT_EOK;
 }
 
diff --git a/src/libknot/updates/changesets.h b/src/libknot/updates/changesets.h
index b19a09ffb..dc09cc6dc 100644
--- a/src/libknot/updates/changesets.h
+++ b/src/libknot/updates/changesets.h
@@ -282,6 +282,10 @@ int knot_changes_add_node(knot_changes_t *ch, knot_node_t *kn_node,
  * \param ch1 Changeset to merge into
  * \param ch2 Changeset to merge
  *
+ * Beginning SOA is used from the first changeset, ending SOA from the second.
+ * Ending SOA from first changeset is deleted. SOAs in the second changeset are
+ * left untouched.
+ *
  * \retval KNOT_EOK on success.
  * \retval Error code on failure.
  */
-- 
GitLab