diff --git a/Makefile.am b/Makefile.am
index 982da2d8f454db81761f704ee51d6e7f8632946f..4885799b9aee1c38a7963c5fd68e5ab5bbcd4d0a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,6 @@ ACLOCAL_AMFLAGS = -I m4
 SUBDIRS = libtap src tests samples doc man patches
 
 AM_DISTCHECK_CONFIGURE_FLAGS =		\
-	--without-ragel			\
 	--disable-code-coverage
 
 code_coverage_quiet = --quiet
diff --git a/configure.ac b/configure.ac
index 00a2e84b184c5cf8bc7ce5649d0d92dbb67cd6b3..e075bb06c1884870bf7cf499b2fc3fadd61ab91f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -64,36 +64,11 @@ AS_IF([test "x$YACC_BISON" != "xbison"],
     [AC_MSG_ERROR([GNU bison needed for reentrant parsers, set the \$YACC variable before running configure])])
 AC_PROG_INSTALL
 
-# Check for Ragel
-AC_ARG_WITH([ragel],
-    AC_HELP_STRING([--with-ragel=path], [Path to Ragel binary. [default=auto]]),
-    [with_ragel=$withval],
-    [with_ragel=auto])
-
-AS_CASE([$with_ragel],
-    [yes|auto], [AC_PATH_PROG([RAGEL], [ragel], [false])],
-    [no], [RAGEL=false],
-    [*], [RAGEL=$with_ragel],
-)
-
-AM_CONDITIONAL([HAVE_RAGEL], test "$RAGEL" != "false")
-
-# Set FSM type for Ragel
+# Set zone parser type
 AC_ARG_ENABLE([fastparser],
-    AS_HELP_STRING([--disable-fastparser], [Don't use faster zone parser]),
-    [],
-    [enable_fastparser=yes])
-
-AS_CASE([$enable_fastparser],
-    [no], [AC_SUBST([FSM_TYPE], [-T0])],
-    [yes], [AC_SUBST([FSM_TYPE], [-G2])],
-    [*], [
-        AS_IF([test "$RAGEL" = "false"],
-	    [AC_MSG_ERROR([Ragel is needed to generate different parsers])])
-        AC_SUBST([FSM_TYPE], [$enable_fastparser])
-    ])
-AM_CONDITIONAL([G2_PARSER], test "$enable_fastparser" = "yes")
-AM_CONDITIONAL([T0_PARSER], test "$enable_fastparser" = "no")
+    AS_HELP_STRING([--disable-fastparser], [Use slower zone parser]),
+    [], [enable_fastparser=yes])
+AM_CONDITIONAL([FAST_PARSER], [test "$enable_fastparser" = yes])
 
 # Systemd integration
 AC_ARG_ENABLE([systemd],
@@ -398,9 +373,9 @@ echo "
   CFlags: ${CFLAGS} ${CPPFLAGS}
   LDFlags: ${LDFLAGS}
   Libs: ${LIBS}
-  Ragel: ${RAGEL} ${FSM_TYPE}
+  Fast zone parser: ${enable_fastparser}
   Utils with IDN: ${libidn}
-  Use systemd notifications: ${enable_systemd}
+  Systemd notifications: ${enable_systemd}
   Code coverage: ${enable_code_coverage}
 
   Continue with 'make' command"
diff --git a/man/kdig.1.in b/man/kdig.1.in
index c313411bf27f5a64507375715d6767f9e0836003..fa6893d71e951061a84110d3c11fa8c6670d75e0 100644
--- a/man/kdig.1.in
+++ b/man/kdig.1.in
@@ -138,6 +138,9 @@ Show authority section.
 .BR + [ no ] additional
 Show additional section.
 .TP
+.BR + [ no ] tsig
+Show TSIG pseudosection.
+.TP
 .BR + [ no ] stats
 Show trailing packet statistics.
 .TP
diff --git a/scripts/update-parser.sh b/scripts/update-parser.sh
index e1fe5b68f4991950e2494a2c81188dda1867184f..bc965c9444e920387054adc284bea85fd75f5eb2 100755
--- a/scripts/update-parser.sh
+++ b/scripts/update-parser.sh
@@ -1,11 +1,16 @@
 #!/bin/bash
 
+IN="./scanner.rl"
+OUT="./scanner.c"
+
 pushd ../src/zscanner/
 
-ragel -T0 -s -o ./scanner.c ./scanner.rl
-sed '/#line/d' ./scanner.c > ./scanner.c.t0
+ragel -T0 -s -o $OUT $IN
+sed '/#line/d' $OUT > $OUT.t0
+rm $OUT
 
-ragel -G2 -s -o ./scanner.c ./scanner.rl
-sed '/#line/d' ./scanner.c > ./scanner.c.g2
+ragel -G2 -s -o $OUT $IN
+sed '/#line/d' $OUT > $OUT.g2
+rm $OUT
 
 popd
diff --git a/src/common/descriptor.c b/src/common/descriptor.c
index ace5623c897b209dfcb39787dee32ed090e274d5..2dc416bd2b4339d6d90c6ed07d998ed16eec32d2 100644
--- a/src/common/descriptor.c
+++ b/src/common/descriptor.c
@@ -319,15 +319,15 @@ int knot_rrtype_is_metatype(const uint16_t type)
 
 int knot_rrtype_is_ddns_forbidden(const uint16_t type)
 {
-	return type == KNOT_RRTYPE_RRSIG      ||
-	       type == KNOT_RRTYPE_NSEC       ||
+	return type == KNOT_RRTYPE_RRSIG ||
+	       type == KNOT_RRTYPE_NSEC  ||
 	       type == KNOT_RRTYPE_NSEC3;
 }
 
-int knot_rrtype_additional_needed(const uint16_t rrtype)
+int knot_rrtype_additional_needed(const uint16_t type)
 {
-	return (rrtype == KNOT_RRTYPE_NS ||
-		rrtype == KNOT_RRTYPE_MX ||
-		rrtype == KNOT_RRTYPE_SRV);
+	return type == KNOT_RRTYPE_NS ||
+	       type == KNOT_RRTYPE_MX ||
+	       type == KNOT_RRTYPE_SRV;
 }
 
diff --git a/src/common/descriptor.h b/src/common/descriptor.h
index 6e1cb999868f57cc5012cc9dd97ad3ffd4113937..ec2ae8eeea0a9745f177593e84f1c15c28c3f38c 100644
--- a/src/common/descriptor.h
+++ b/src/common/descriptor.h
@@ -292,12 +292,12 @@ int knot_rrtype_is_ddns_forbidden(const uint16_t type);
  *
  * Only MX, NS and SRV types require additional processing.
  *
- * \param rrtype Type to check.
+ * \param type Type to check.
  *
  * \retval <> 0 if additional processing is needed for \a qtype.
  * \retval 0 otherwise.
  */
-int knot_rrtype_additional_needed(const uint16_t rrtype);
+int knot_rrtype_additional_needed(const uint16_t type);
 
 #endif // _KNOT_DESCRIPTOR_H_
 
diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c
index 19bb5325d71447c2361e546e72942a404bc93262..9f7b05f96f1ee587211e8f1a3174da78716cd361 100644
--- a/src/knot/ctl/remote.c
+++ b/src/knot/ctl/remote.c
@@ -967,8 +967,9 @@ int remote_print_txt(const knot_rrset_t *rr, uint16_t i)
 	/* Packet parser should have already checked the packet validity. */
 	char buf[256];
 	uint16_t parsed = 0;
-	uint16_t rlen = knot_rrset_rr_size(rr, i);
-	uint8_t *p = knot_rrset_rr_rdata(rr, i);
+	const knot_rdata_t *rdata = knot_rdataset_at(&rr->rrs, i);
+	uint8_t *p = knot_rdata_data(rdata);
+	uint16_t rlen = knot_rdata_rdlen(rdata);
 	while (parsed < rlen) {
 		memcpy(buf, (const char*)(p+1), *p);
 		buf[*p] = '\0';
diff --git a/src/knot/dnssec/nsec3-chain.c b/src/knot/dnssec/nsec3-chain.c
index e391ace3202394af6b50e32caf325e59d9c84cac..1495e48cf80f4006a1bca2c5e4379f4f9444488c 100644
--- a/src/knot/dnssec/nsec3-chain.c
+++ b/src/knot/dnssec/nsec3-chain.c
@@ -121,7 +121,7 @@ static int shallow_copy_signature(const zone_node_t *from, zone_node_t *to)
 	if (knot_rrset_empty(&from_sig)) {
 		return KNOT_EOK;
 	}
-	return node_add_rrset(to, &from_sig, NULL);
+	return node_add_rrset(to, &from_sig);
 }
 
 /*!
@@ -298,7 +298,7 @@ static zone_node_t *create_nsec3_node(knot_dname_t *owner,
 		return NULL;
 	}
 
-	ret = node_add_rrset(new_node, &nsec3_rrset, NULL);
+	ret = node_add_rrset(new_node, &nsec3_rrset);
 	knot_rrset_clear(&nsec3_rrset, NULL);
 	if (ret != KNOT_EOK) {
 		node_free(&new_node);
diff --git a/src/knot/dnssec/zone-sign.c b/src/knot/dnssec/zone-sign.c
index 2e1e373da7564ccf11abadfb88b130a6c8578028..d92bd3035d561db5e43e3fca0a7e5f7fc1ead2a4 100644
--- a/src/knot/dnssec/zone-sign.c
+++ b/src/knot/dnssec/zone-sign.c
@@ -698,8 +698,9 @@ static bool dnskey_exists_in_zone(const knot_rrset_t *dnskeys,
 
 	uint16_t dnskeys_rdata_count = dnskeys->rrs.rr_count;
 	for (uint16_t i = 0; i < dnskeys_rdata_count; i++) {
-		uint8_t *rdata = knot_rrset_rr_rdata(dnskeys, i);
-		uint16_t rdata_size = knot_rrset_rr_size(dnskeys, i);
+		const knot_rdata_t *rr_data = knot_rdataset_at(&dnskeys->rrs, i);
+		uint8_t *rdata = knot_rdata_data(rr_data);
+		uint16_t rdata_size = knot_rdata_rdlen(rr_data);
 		if (dnskey_rdata_match(key, rdata, rdata_size)) {
 			return true;
 		}
@@ -750,7 +751,9 @@ static int remove_invalid_dnskeys(const knot_rrset_t *soa,
 	knot_rrset_t *to_remove = NULL;
 	int result = KNOT_EOK;
 
-	if (knot_rrset_rr_ttl(dnskeys, 0) != knot_rrset_rr_ttl(soa, 0)) {
+	const knot_rdata_t *dnskeys_data = knot_rdataset_at(&dnskeys->rrs, 0);
+	const knot_rdata_t *soa_data = knot_rdataset_at(&soa->rrs, 0);
+	if (knot_rdata_ttl(dnskeys_data) != knot_rdata_ttl(soa_data)) {
 		dbg_dnssec_detail("removing DNSKEYs (SOA TTL differs)\n");
 		to_remove = knot_rrset_copy(dnskeys, NULL);
 		result = to_remove ? KNOT_EOK : KNOT_ENOMEM;
@@ -759,8 +762,9 @@ static int remove_invalid_dnskeys(const knot_rrset_t *soa,
 
 	uint16_t dnskeys_rdata_count = dnskeys->rrs.rr_count;
 	for (uint16_t i = 0; i < dnskeys_rdata_count; i++) {
-		uint8_t *rdata = knot_rrset_rr_rdata(dnskeys, i);
-		uint16_t rdata_size = knot_rrset_rr_size(dnskeys, i);
+		dnskeys_data = knot_rdataset_at(&dnskeys->rrs, i);
+		uint8_t *rdata = knot_rdata_data(dnskeys_data);
+		uint16_t rdata_size = knot_rdata_rdlen(dnskeys_data);
 		uint16_t keytag = knot_keytag(rdata, rdata_size);
 		const knot_zone_key_t *key = knot_get_zone_key(zone_keys, keytag);
 		if (key == NULL) {
@@ -846,8 +850,10 @@ static int add_missing_dnskeys(const knot_rrset_t *soa,
 
 	knot_rrset_t *to_add = NULL;
 	int result = KNOT_EOK;
+	const knot_rdata_t *dnskeys_data = knot_rdataset_at(&dnskeys->rrs, 0);
+	const knot_rdata_t *soa_data = knot_rdataset_at(&soa->rrs, 0);
 	bool add_all = (knot_rrset_empty(dnskeys) ||
-	                knot_rrset_rr_ttl(dnskeys, 0) != knot_rrset_rr_ttl(soa, 0));
+	                knot_rdata_ttl(dnskeys_data) != knot_rdata_ttl(soa_data));
 
 	for (int i = 0; i < zone_keys->count; i++) {
 		const knot_zone_key_t *key = &zone_keys->keys[i];
@@ -870,8 +876,7 @@ static int add_missing_dnskeys(const knot_rrset_t *soa,
 			}
 		}
 
-		result = rrset_add_zone_key(to_add, key,
-		                            knot_rrset_rr_ttl(soa, 0));
+		result = rrset_add_zone_key(to_add, key, knot_rdata_ttl(soa_data));
 		if (result != KNOT_EOK) {
 			break;
 		}
@@ -923,8 +928,9 @@ static int update_dnskeys_rrsigs(const knot_rrset_t *dnskeys,
 	// add unknown keys from zone
 	uint16_t dnskeys_rdata_count = dnskeys->rrs.rr_count;
 	for (uint16_t i = 0; i < dnskeys_rdata_count; i++) {
-		uint8_t *rdata = knot_rrset_rr_rdata(dnskeys, i);
-		uint16_t rdata_size = knot_rrset_rr_size(dnskeys, i);
+		const knot_rdata_t *rr_data = knot_rdataset_at(&dnskeys->rrs, i);
+		uint8_t *rdata = knot_rdata_data(rr_data);
+		uint16_t rdata_size = knot_rdata_rdlen(rr_data);
 		uint16_t keytag = knot_keytag(rdata, rdata_size);
 		if (knot_get_zone_key(zone_keys, keytag) != NULL) {
 			continue;
@@ -944,8 +950,9 @@ static int update_dnskeys_rrsigs(const knot_rrset_t *dnskeys,
 			continue;
 		}
 
+		const knot_rdata_t *soa_data = knot_rdataset_at(&soa->rrs, 0);
 		result = rrset_add_zone_key(new_dnskeys, key,
-		                            knot_rrset_rr_ttl(soa, 0));
+		                            knot_rdata_ttl(soa_data));
 		if (result != KNOT_EOK) {
 			goto fail;
 		}
diff --git a/src/knot/nameserver/internet.c b/src/knot/nameserver/internet.c
index d9d6b7e38269e481c1bd532a0ff96b7f371b2c62..ffecb0aa5a87abe0647ae0a4ca80ece92ce433bc 100644
--- a/src/knot/nameserver/internet.c
+++ b/src/knot/nameserver/internet.c
@@ -90,8 +90,9 @@ static int dname_cname_synth(const knot_rrset_t *dname_rr,
 	memcpy(cname_rdata, cname, cname_size);
 	knot_dname_free(&cname, NULL);
 
+	const knot_rdata_t *dname_data = knot_rdataset_at(&dname_rr->rrs, 0);
 	int ret = knot_rrset_add_rdata(cname_rrset, cname_rdata, cname_size,
-	                            knot_rrset_rr_ttl(dname_rr, 0), mm);
+	                               knot_rdata_ttl(dname_data), mm);
 	if (ret != KNOT_EOK) {
 		knot_dname_free(&owner_copy, mm);
 		return ret;
@@ -255,7 +256,8 @@ static int put_authority_soa(knot_pkt_t *pkt, struct query_data *qdata,
 	int ret = KNOT_EOK;
 	uint32_t flags = KNOT_PF_NOTRUNC;
 	uint32_t min = knot_soa_minimum(&soa_rrset.rrs);
-	if (min < knot_rrset_rr_ttl(&soa_rrset, 0)) {
+	const knot_rdata_t *soa_data = knot_rdataset_at(&soa_rrset.rrs, 0);
+	if (min < knot_rdata_ttl(soa_data)) {
 		knot_rrset_t copy;
 		knot_dname_t *dname_cpy = knot_dname_copy(soa_rrset.owner, &pkt->mm);
 		if (dname_cpy == NULL) {
@@ -267,7 +269,8 @@ static int put_authority_soa(knot_pkt_t *pkt, struct query_data *qdata,
 			knot_dname_free(&dname_cpy, &pkt->mm);
 			return ret;
 		}
-		knot_rrset_rr_set_ttl(&copy, 0, min);
+		knot_rdata_t *copy_data = knot_rdataset_at(&copy.rrs, 0);
+		knot_rdata_set_ttl(copy_data, min);
 
 		flags |= KNOT_PF_FREE;
 		soa_rrset = copy;
diff --git a/src/knot/nameserver/update.c b/src/knot/nameserver/update.c
index 9314b96f0e2396756edf7963cb19c6a9aa196cfb..d5f61dc5616074c0a2ec1b409b022512d2552a87 100644
--- a/src/knot/nameserver/update.c
+++ b/src/knot/nameserver/update.c
@@ -308,7 +308,11 @@ static int zones_process_update_auth(struct query_data *qdata)
 		ret = xfrin_apply_changesets(zone, chgsets, &new_contents);
 		if (ret != KNOT_EOK) {
 			log_zone_notice("%s: Failed to process: %s.\n", msg, knot_strerror(ret));
-			qdata->rcode = KNOT_RCODE_SERVFAIL;
+			if (ret == KNOT_ETTL) {
+				qdata->rcode = KNOT_RCODE_REFUSED;
+			} else {
+				qdata->rcode = KNOT_RCODE_SERVFAIL;
+			}
 			knot_changesets_free(&chgsets);
 			free(msg);
 			return ret;
@@ -326,6 +330,7 @@ static int zones_process_update_auth(struct query_data *qdata)
 		if (sec_chs == NULL) {
 			xfrin_rollback_update(chgsets, &new_contents);
 			knot_changesets_free(&chgsets);
+			knot_changesets_free(&sec_chs);
 			free(msg);
 			return KNOT_ENOMEM;
 		}
diff --git a/src/knot/updates/ddns.c b/src/knot/updates/ddns.c
index 62d2c21fe0deebaea9c09e6f080d81fe81b72331..c9406a186b7d1bd511e81f3126b5c022c20c39d9 100644
--- a/src/knot/updates/ddns.c
+++ b/src/knot/updates/ddns.c
@@ -203,7 +203,8 @@ static bool rrset_empty(const knot_rrset_t *rrset)
 		return true;
 	}
 	if (rr_count == 1) {
-		return knot_rrset_rr_size(rrset, 0) == 0;
+		const knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, 0);
+		return knot_rdata_rdlen(rr) == 0;
 	}
 	return false;
 }
@@ -213,7 +214,7 @@ static int process_prereq(const knot_rrset_t *rrset, uint16_t qclass,
                           const zone_contents_t *zone, uint16_t *rcode,
                           list_t *rrset_list)
 {
-	if (knot_rrset_rr_ttl(rrset, 0) != 0) {
+	if (knot_rdata_ttl(knot_rdataset_at(&rrset->rrs, 0)) != 0) {
 		return KNOT_EMALF;
 	}
 
@@ -252,7 +253,7 @@ static int process_prereq(const knot_rrset_t *rrset, uint16_t qclass,
 
 /* ----------------------- changeset lists helpers -------------------------- */
 
-#warning TODO: Store changesets as a lookup structure
+/*! \todo Store changesets as a lookup structure. */
 
 /*!< \brief Returns true if \a cmp code returns true for one RR in list. */
 #define LIST_MATCH(l, cmp) \
@@ -670,15 +671,6 @@ static int process_add_normal(const zone_node_t *node,
 		return KNOT_EOK;
 	}
 
-	/* First check if the TTL of the new RR is equal to that of the first
-	 * RR in the node's RRSet. If not, refuse the UPDATE.
-	 */
-	knot_rrset_t rr_in_zone = node_rrset(node, rr->type);
-	if (node_rrtype_exists(node, rr->type) &&
-	    knot_rrset_rr_ttl(rr, 0) != knot_rrset_rr_ttl(&rr_in_zone, 0)) {
-		return KNOT_ETTL;
-	}
-
 	const bool apex_ns = node_rrtype_exists(node, KNOT_RRTYPE_SOA) &&
 	                     rr->type == KNOT_RRTYPE_NS;
 	return add_rr_to_chgset(rr, changeset, apex_ns ? apex_ns_rem : NULL);
@@ -894,7 +886,7 @@ static int check_update(const knot_rrset_t *rrset, const knot_pkt_t *query,
 			return KNOT_EMALF;
 		}
 	} else if (rrset->rclass == KNOT_CLASS_NONE) {
-		if (knot_rrset_rr_ttl(rrset, 0) != 0
+		if (knot_rdata_ttl(knot_rdataset_at(&rrset->rrs, 0)) != 0
 		    || knot_rrtype_is_metatype(rrset->type)) {
 			*rcode = KNOT_RCODE_FORMERR;
 			return KNOT_EMALF;
diff --git a/src/knot/updates/xfr-in.c b/src/knot/updates/xfr-in.c
index f841e2aba3ecd30af2ebc37dc2bbff34da59dffc..a5c3bb99ff336134a4e1f8cc415c2ebb57c39cac 100644
--- a/src/knot/updates/xfr-in.c
+++ b/src/knot/updates/xfr-in.c
@@ -678,9 +678,7 @@ static bool can_remove(const zone_node_t *node, const knot_rrset_t *rr)
 		// Node does not exist, cannot remove anything.
 		return false;
 	}
-
 	const knot_rdataset_t *node_rrs = node_rdataset(node, rr->type);
-
 	if (node_rrs == NULL) {
 		// Node does not have this type at all.
 		return false;
@@ -781,7 +779,7 @@ static int xfrin_apply_remove(zone_contents_t *contents, knot_changeset_t *chset
 }
 
 static int add_rr(zone_node_t *node, const knot_rrset_t *rr,
-                  knot_changeset_t *chset)
+                  knot_changeset_t *chset, bool master)
 {
 	knot_rrset_t changed_rrset = node_rrset(node, rr->type);
 	if (!knot_rrset_empty(&changed_rrset)) {
@@ -798,47 +796,34 @@ static int add_rr(zone_node_t *node, const knot_rrset_t *rr,
 			clear_new_rrs(node, rr->type);
 			return ret;
 		}
+	}
 
-		// Extract copy, merge into it
-		knot_rdataset_t *changed_rrs = node_rdataset(node, rr->type);
-		ret = knot_rdataset_merge(changed_rrs, &rr->rrs, NULL);
-		if (ret != KNOT_EOK) {
-			clear_new_rrs(node, rr->type);
-			return ret;
-		}
-	} else {
-		// Inserting new RRSet, data will be copied.
-		bool ttl_err = false;
-		int ret = node_add_rrset(node, rr, &ttl_err);
-		if (ret != KNOT_EOK) {
-			return ret;
+	// Insert new RR to RRSet, data will be copied.
+	int ret = node_add_rrset(node, rr);
+	if (ret == KNOT_EOK || ret == KNOT_ETTL) {
+		// RR added, store for possible rollback.
+		knot_rdataset_t *rrs = node_rdataset(node, rr->type);
+		int data_ret = add_new_data(chset, rrs->data);
+		if (data_ret != KNOT_EOK) {
+			knot_rdataset_clear(rrs, NULL);
+			return data_ret;
 		}
 
-		if (ttl_err) {
-			char type_str[16] = { '\0' };
-			knot_rrtype_to_string(rr->type, type_str, sizeof(type_str));
-			char *name = knot_dname_to_str(rr->owner);
-			char *zname = knot_dname_to_str(chset->soa_from->owner);
-			log_zone_warning("Changes application to zone %s: TTL mismatch"
-			                 " in %s, type %s\n", zname, name, type_str);
-			free(name);
-			free(zname);
+		if (ret == KNOT_ETTL) {
+			// Handle possible TTL errors.
+			log_ttl_error(node, rr);
+			if (!master) {
+				// TTL errors fatal only for master.
+				return KNOT_EOK;
+			}
 		}
 	}
 
-	// Get changed RRS and store for possible rollback.
-	knot_rdataset_t *rrs = node_rdataset(node, rr->type);
-	int ret = add_new_data(chset, rrs->data);
-	if (ret != KNOT_EOK) {
-		knot_rdataset_clear(rrs, NULL);
-		return ret;
-	}
-
-	return KNOT_EOK;
+	return ret;
 }
 
 static int xfrin_apply_add(zone_contents_t *contents,
-                           knot_changeset_t *chset)
+                           knot_changeset_t *chset, bool master)
 {
 	knot_rr_ln_t *rr_node = NULL;
 	WALK_LIST(rr_node, chset->add) {
@@ -850,7 +835,7 @@ static int xfrin_apply_add(zone_contents_t *contents,
 			return KNOT_ENOMEM;
 		}
 
-		int ret = add_rr(node, rr, chset);
+		int ret = add_rr(node, rr, chset, master);
 		if (ret != KNOT_EOK) {
 			return ret;
 		}
@@ -872,14 +857,13 @@ static int xfrin_apply_replace_soa(zone_contents_t *contents,
 
 	assert(!node_rrtype_exists(contents->apex, KNOT_RRTYPE_SOA));
 
-	return add_rr(contents->apex, chset->soa_to, chset);
+	return add_rr(contents->apex, chset->soa_to, chset, false);
 }
 
 /*----------------------------------------------------------------------------*/
 
-static int xfrin_apply_changeset(list_t *old_rrs, list_t *new_rrs,
-                                 zone_contents_t *contents,
-                                 knot_changeset_t *chset)
+static int xfrin_apply_changeset(zone_contents_t *contents,
+                                 knot_changeset_t *chset, bool master)
 {
 	/*
 	 * Applies one changeset to the zone. Checks if the changeset may be
@@ -902,7 +886,7 @@ static int xfrin_apply_changeset(list_t *old_rrs, list_t *new_rrs,
 		return ret;
 	}
 
-	ret = xfrin_apply_add(contents, chset);
+	ret = xfrin_apply_add(contents, chset, master);
 	if (ret != KNOT_EOK) {
 		return ret;
 	}
@@ -1112,25 +1096,26 @@ int xfrin_apply_changesets_directly(zone_contents_t *contents,
 
 	knot_changeset_t *set = NULL;
 	WALK_LIST(set, chsets->sets) {
-		int ret = xfrin_apply_changeset(&set->old_data,
-		                                &set->new_data,
-		                                contents, set);
+		const bool master = true; // Only DNSSEC changesets are applied directly.
+		int ret = xfrin_apply_changeset(contents, set, master);
 		if (ret != KNOT_EOK) {
 			return ret;
 		}
 	}
 
-	return KNOT_EOK;
+	return xfrin_finalize_updated_zone(contents, true);
 }
 
 /*----------------------------------------------------------------------------*/
 
 /* Post-DDNS application, no need to shallow copy. */
-int xfrin_apply_changesets_dnssec_ddns(zone_contents_t *z_new,
+int xfrin_apply_changesets_dnssec_ddns(zone_t *zone,
+                                       zone_contents_t *z_new,
                                        knot_changesets_t *sec_chsets,
                                        knot_changesets_t *chsets)
 {
-	if (z_new == NULL || sec_chsets == NULL || chsets == NULL) {
+	if (zone == NULL || z_new == NULL ||
+	    sec_chsets == NULL || chsets == NULL) {
 		return KNOT_EINVAL;
 	}
 
@@ -1146,15 +1131,6 @@ int xfrin_apply_changesets_dnssec_ddns(zone_contents_t *z_new,
 		return ret;
 	}
 
-	const bool handle_nsec3 = true;
-	ret = xfrin_finalize_updated_zone(z_new, handle_nsec3);
-	if (ret != KNOT_EOK) {
-		dbg_xfrin("Failed to finalize updated zone: %s\n",
-		          knot_strerror(ret));
-		xfrin_rollback_update(sec_chsets, &z_new);
-		return ret;
-	}
-
 	return ret;
 }
 
@@ -1193,10 +1169,9 @@ int xfrin_apply_changesets(zone_t *zone,
 	dbg_xfrin_verb("Old contents apex: %p, new apex: %p\n",
 		       old_contents->apex, contents_copy->apex);
 	knot_changeset_t *set = NULL;
+	const bool master = (zone_master(zone) == NULL);
 	WALK_LIST(set, chsets->sets) {
-		ret = xfrin_apply_changeset(&set->old_data,
-		                            &set->new_data,
-		                            contents_copy, set);
+		ret = xfrin_apply_changeset(contents_copy, set, master);
 		if (ret != KNOT_EOK) {
 			xfrin_rollback_update(chsets, &contents_copy);
 			dbg_xfrin("Failed to apply changesets to zone: "
diff --git a/src/knot/zone/contents.c b/src/knot/zone/contents.c
index 08dd0239a8a77fa67f40b10ffd914bc239cd2367..f7ffd9e502a8dd11a0a7a80b10d998c5cb0c2dd3 100644
--- a/src/knot/zone/contents.c
+++ b/src/knot/zone/contents.c
@@ -636,8 +636,9 @@ static zone_node_t *zone_contents_get_nsec3_node(const zone_contents_t *zone,
 	return n;
 }
 
-static int insert_rr(zone_contents_t *z, const knot_rrset_t *rr, zone_node_t **n,
-                     bool nsec3, bool *ttl_err)
+static int insert_rr(knot_zone_contents_t *z,
+                     const knot_rrset_t *rr, zone_node_t **n,
+                     bool nsec3)
 {
 	if (z == NULL || knot_rrset_empty(rr) || n == NULL) {
 		return KNOT_EINVAL;
@@ -667,7 +668,7 @@ static int insert_rr(zone_contents_t *z, const knot_rrset_t *rr, zone_node_t **n
 		}
 	}
 
-	return node_add_rrset(*n, rr, ttl_err);
+	return node_add_rrset(*n, rr);
 }
 
 static int recreate_normal_tree(const zone_contents_t *z, zone_contents_t *out)
@@ -770,10 +771,10 @@ static bool rrset_is_nsec3rel(const knot_rrset_t *rr)
 	            == KNOT_RRTYPE_NSEC3));
 }
 
-int zone_contents_add_rr(zone_contents_t *z, const knot_rrset_t *rr,
-                         zone_node_t **n, bool *ttl_err)
+int knot_zone_contents_add_rr(knot_zone_contents_t *z,
+                              const knot_rrset_t *rr, zone_node_t **n)
 {
-	return insert_rr(z, rr, n, rrset_is_nsec3rel(rr), ttl_err);
+	return insert_rr(z, rr, n, rrset_is_nsec3rel(rr));
 }
 
 /*----------------------------------------------------------------------------*/
diff --git a/src/knot/zone/contents.h b/src/knot/zone/contents.h
index 9e3e658e8f4c0f38c3f26c63470ac2d42e9bc4fc..240cfb271898d3cbef064e785ea4d69f0f0c6ab8 100644
--- a/src/knot/zone/contents.h
+++ b/src/knot/zone/contents.h
@@ -91,8 +91,8 @@ int zone_contents_gen_is_new(const zone_contents_t *contents);
 void zone_contents_set_gen_old(zone_contents_t *contents);
 void zone_contents_set_gen_new(zone_contents_t *contents);
 
-int zone_contents_add_rr(zone_contents_t *z, const knot_rrset_t *rr,
-                         zone_node_t **n, bool *ttl_err);
+int knot_zone_contents_add_rr(knot_zone_contents_t *z,
+                              const knot_rrset_t *rr, zone_node_t **n);
 
 int zone_contents_remove_node(zone_contents_t *contents, const knot_dname_t *owner);
 
diff --git a/src/knot/zone/estimator.c b/src/knot/zone/estimator.c
index 4dc289fe4506eca37f787665aba2cda81b76c3b9..e9c1d33567b03b7b4f0f0e15ee8dae69c58773f1 100644
--- a/src/knot/zone/estimator.c
+++ b/src/knot/zone/estimator.c
@@ -165,7 +165,7 @@ size_t estimator_trie_htable_memsize(hattrie_t *table)
 	return size;
 }
 
-void estimator_rrset_memsize_wrap(const zs_scanner_t *scanner)
+void estimator_rrset_memsize_wrap(zs_scanner_t *scanner)
 {
 	rrset_memsize(scanner->data, scanner);
 }
diff --git a/src/knot/zone/estimator.h b/src/knot/zone/estimator.h
index 4a5300799dd21d4f67efe3a0573cacfcb4f2c74e..1374a717f4a0e2d29234e54853238b5f915d17ef 100644
--- a/src/knot/zone/estimator.h
+++ b/src/knot/zone/estimator.h
@@ -75,7 +75,7 @@ size_t estimator_trie_htable_memsize(hattrie_t *table);
  *
  * \param scanner Scanner context.
  */
-void estimator_rrset_memsize_wrap(const zs_scanner_t *scanner);
+void estimator_rrset_memsize_wrap(zs_scanner_t *scanner);
 
 /*!
  * \brief Cleanup function for use with hattrie.
diff --git a/src/knot/zone/node.c b/src/knot/zone/node.c
index 1b38cf7ea49b913df9ad1d40dc244a346b9f51aa..c7a8db120cde0f5ec6e4a844aae9406cadedf210 100644
--- a/src/knot/zone/node.c
+++ b/src/knot/zone/node.c
@@ -70,11 +70,11 @@ static int add_rrset_no_merge(zone_node_t *node, const knot_rrset_t *rrset)
 /*! \brief Checks if the added RR has the same TTL as the first RR in the node. */
 static bool ttl_error(struct rr_data *node_data, const knot_rrset_t *rrset)
 {
-	if (rrset->type == KNOT_RRTYPE_RRSIG) {
+	if (rrset->type == KNOT_RRTYPE_RRSIG || node_data->rrs.rr_count == 0) {
 		return false;
 	}
 
-	const uint32_t inserted_ttl = knot_rrset_rr_ttl(rrset, 0);
+	const uint32_t inserted_ttl = knot_rdata_ttl(knot_rdataset_at(&rrset->rrs, 0));
 	// Get first RR from node.
 	const knot_rdata_t *node_rdata = knot_rdataset_at(&node_data->rrs, 0);
 	const uint32_t node_ttl = knot_rdata_ttl(node_rdata);
@@ -164,7 +164,7 @@ zone_node_t *node_shallow_copy(const zone_node_t *src)
 	return dst;
 }
 
-int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset,  bool *ttl_err)
+int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset)
 {
 	if (node == NULL || rrset == NULL) {
 		return KNOT_EINVAL;
@@ -173,13 +173,14 @@ int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset,  bool *ttl_err)
 	for (uint16_t i = 0; i < node->rrset_count; ++i) {
 		if (node->rrs[i].type == rrset->type) {
 			struct rr_data *node_data = &node->rrs[i];
-			if (ttl_err) {
-				// Do TTL check.
-				*ttl_err = ttl_error(node_data, rrset);
+			const bool ttl_err = ttl_error(node_data, rrset);
+			int ret = knot_rdataset_merge(&node_data->rrs,
+			                              &rrset->rrs, NULL);
+			if (ret != KNOT_EOK) {
+				return ret;
+			} else {
+				return ttl_err ? KNOT_ETTL : KNOT_EOK;
 			}
-
-			return knot_rdataset_merge(&node_data->rrs,
-			                           &rrset->rrs, NULL);
 		}
 	}
 
diff --git a/src/knot/zone/node.h b/src/knot/zone/node.h
index 65e4ff22629cf80e782d8a76cb20ca23c70de857..e49f88048935e4a6f6ad59bf6aee1a945f670b95 100644
--- a/src/knot/zone/node.h
+++ b/src/knot/zone/node.h
@@ -126,12 +126,10 @@ zone_node_t *node_shallow_copy(const zone_node_t *src);
  *
  * \param node     Node to add the RRSet to.
  * \param rrset    RRSet to add.
- * \param ttl_err  Set to true if TTL error occured when inserting. New zone API
- *                 will obsolete this parameter.
  *
  * \return KNOT_E*
  */
-int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset, bool *ttl_err);
+int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset);
 
 /*!
  * \brief Removes data for given RR type from node.
diff --git a/src/knot/zone/semantic-check.c b/src/knot/zone/semantic-check.c
index 38b4e744b703faf8993176714ad38bd1d42d1de6..489ad931d0492a8a48c782fea23c77bbaf863b40 100644
--- a/src/knot/zone/semantic-check.c
+++ b/src/knot/zone/semantic-check.c
@@ -264,9 +264,8 @@ static int check_dnskey_rdata(const knot_rrset_t *rrset, size_t rdata_pos)
 	/* check that Zone key bit it set - position 7 in net order */
 	const uint16_t mask = 1 << 8; //0b0000000100000000;
 
-	uint16_t flags =
-		knot_wire_read_u16(knot_rrset_rr_rdata(rrset, rdata_pos));
-
+	const knot_rdata_t *rr_data = knot_rdataset_at(&rrset->rrs, rdata_pos);
+	uint16_t flags = knot_wire_read_u16(knot_rdata_data(rr_data));
 	if (flags & mask) {
 		return KNOT_EOK;
 	} else {
@@ -334,7 +333,7 @@ static int check_rrsig_rdata(err_handler_t *handler,
 
 	uint16_t rr_count = rrset->rrs.rr_count;
 	for (uint16_t i = 0; i < rr_count; ++i) {
-		if (original_ttl != knot_rrset_rr_ttl(rrset, i)) {
+		if (original_ttl != knot_rdata_ttl(knot_rdataset_at(&rrset->rrs, i))) {
 			err_handler_handle_error(handler, node,
 			                         ZC_ERR_RRSIG_RDATA_TTL,
 			                         info_str);
@@ -382,9 +381,9 @@ static int check_rrsig_rdata(err_handler_t *handler,
 		}
 
 		/* Calculate keytag. */
+		const knot_rdata_t *rr_data = knot_rdataset_at(&dnskey_rrset->rrs, i);
 		uint16_t dnskey_key_tag =
-			knot_keytag(knot_rrset_rr_rdata(dnskey_rrset, i),
-		                    knot_rrset_rr_size(dnskey_rrset, i));
+			knot_keytag(knot_rdata_data(rr_data), knot_rdata_rdlen(rr_data));
 		if (key_tag_rrsig != dnskey_key_tag) {
 			continue;
 		}
@@ -462,7 +461,7 @@ static int check_rrsig_in_rrset(err_handler_t *handler,
 	}
 
 	const knot_rdata_t *sig_rr = knot_rdataset_at(&rrsigs, 0);
-	if (knot_rrset_rr_ttl(rrset, 0) != knot_rdata_ttl(sig_rr)) {
+	if (knot_rdata_ttl(knot_rdataset_at(&rrset->rrs, 0)) != knot_rdata_ttl(sig_rr)) {
 		err_handler_handle_error(handler, node,
 		                         ZC_ERR_RRSIG_TTL,
 		                         info_str);
diff --git a/src/knot/zone/zone-tree.c b/src/knot/zone/zone-tree.c
index 32d9189eea4085b829ac45c3ec44605ff73ffa35..77b90c5a715305d42b4c88e02213298f5bb6dd35 100644
--- a/src/knot/zone/zone-tree.c
+++ b/src/knot/zone/zone-tree.c
@@ -138,10 +138,14 @@ int knot_zone_tree_get_less_or_equal(knot_zone_tree_t *tree,
 
 	value_t *fval = NULL;
 	int ret = hattrie_find_leq(tree, (char*)lf+1, *lf, &fval);
-	if (fval) *found = (zone_node_t *)(*fval);
+	if (fval) {
+		*found = (zone_node_t *)(*fval);
+	}
 	int exact_match = 0;
 	if (ret == 0) {
-		*previous = (*found)->prev;
+		if (fval) {
+			*previous = (*found)->prev;
+		}
 		exact_match = 1;
 	} else if (ret < 0) {
 		*previous = *found;
@@ -160,7 +164,8 @@ int knot_zone_tree_get_less_or_equal(knot_zone_tree_t *tree,
 	}
 
 	/* Previous node for proof must be non-empty and authoritative. */
-	if ((*previous)->rrset_count == 0 || (*previous)->flags & NODE_FLAGS_NONAUTH) {
+	if (*previous &&
+	    ((*previous)->rrset_count == 0 || (*previous)->flags & NODE_FLAGS_NONAUTH)) {
 		*previous = (*previous)->prev;
 	}
 
diff --git a/src/knot/zone/zonefile.c b/src/knot/zone/zonefile.c
index feca0b90aabe6e05117c3803941c2d16099c517a..5a9f211cf491f157c765867da5aab1e3dbe40713 100644
--- a/src/knot/zone/zonefile.c
+++ b/src/knot/zone/zonefile.c
@@ -57,9 +57,8 @@ static int add_rdata_to_rr(knot_rrset_t *rrset, const zs_scanner_t *scanner)
 	                         scanner->r_ttl, NULL);
 }
 
-static bool handle_err(zcreator_t *zc,
-                       const knot_rrset_t *rr,
-                       int ret)
+static bool handle_err(zcreator_t *zc, const zone_node_t *node,
+                       const knot_rrset_t *rr, int ret, bool master)
 {
 	char *zname = zc->z ? knot_dname_to_str(zc->z->apex->owner) : NULL;
 	char *rrname = rr ? knot_dname_to_str(rr->owner) : NULL;
@@ -69,6 +68,13 @@ static bool handle_err(zcreator_t *zc,
 		free(zname);
 		free(rrname);
 		return true;
+	} else if (ret == KNOT_ETTL) {
+		free(zname);
+		free(rrname);
+		assert(node);
+		log_ttl_error(node, rr);
+		// Fail if we're the master for this zone.
+		return !master;
 	} else {
 		log_zone_error("Zone %s: Cannot process record %s, stopping.\n",
 		               zname ? zname : "unknown", rrname ? rrname : "unknown");
@@ -78,8 +84,7 @@ static bool handle_err(zcreator_t *zc,
 	}
 }
 
-static int log_ttl(const zcreator_t *zc, const zone_node_t *node,
-                   const knot_rrset_t *rr)
+void log_ttl_error(const zone_node_t *node, const knot_rrset_t *rr)
 {
 	err_handler_t err_handler;
 	err_handler_init(&err_handler);
@@ -87,19 +92,15 @@ static int log_ttl(const zcreator_t *zc, const zone_node_t *node,
 	char info_str[64] = { '\0' };
 	char type_str[16] = { '\0' };
 	knot_rrtype_to_string(rr->type, type_str, sizeof(type_str));
-	snprintf(info_str, sizeof(info_str), "Record type: %s.",
-	         type_str);
-
-	if (zc->master) {
-		/*!< \todo REPLACE WITH FATAL ERROR */
-		err_handler_handle_error(&err_handler, node,
-		                         ZC_ERR_TTL_MISMATCH, info_str);
-		return KNOT_EMALF;
-	} else {
-		err_handler_handle_error(&err_handler, node,
-		                         ZC_ERR_TTL_MISMATCH, info_str);
-		return KNOT_EOK;
+	int ret = snprintf(info_str, sizeof(info_str), "Record type: %s.",
+	                   type_str);
+	if (ret <= 0 || ret >= sizeof(info_str)) {
+		*info_str = '\0';
 	}
+
+	/*!< \todo REPLACE WITH FATAL ERROR for master. */
+	err_handler_handle_error(&err_handler, node,
+	                         ZC_ERR_TTL_MISMATCH, info_str);
 }
 
 int zcreator_step(zcreator_t *zc, const knot_rrset_t *rr)
@@ -114,25 +115,19 @@ int zcreator_step(zcreator_t *zc, const knot_rrset_t *rr)
 		return KNOT_EOK;
 	}
 
-	bool ttl_err = false;
 	zone_node_t *node = NULL;
-	int ret = zone_contents_add_rr(zc->z, rr, &node, &ttl_err);
-	if (ret < 0) {
-		if (!handle_err(zc, rr, ret)) {
+	int ret = knot_zone_contents_add_rr(zc->z, rr, &node);
+	if (ret != KNOT_EOK) {
+		if (!handle_err(zc, node, rr, ret, zc->master)) {
 			// Fatal error
 			return ret;
 		}
-		// Recoverable error, skip record
-		return KNOT_EOK;
-	}
-	assert(node);
-
-	if (ttl_err) {
-		ret = log_ttl(zc, node, rr);
-		if (ret != KNOT_EOK) {
-			return ret;
+		if (ret == KNOT_EOUTOFZONE) {
+			// Skip out-of-zone record
+			return KNOT_EOK;
 		}
 	}
+	assert(node);
 
 	// Do node semantic checks
 	err_handler_t err_handler;
diff --git a/src/knot/zone/zonefile.h b/src/knot/zone/zonefile.h
index 81511ef0eff653bcc6aa07d442ca20afaa9896de..72c09528a996ebf4e39c6a7e0f696802ea6e4163 100644
--- a/src/knot/zone/zonefile.h
+++ b/src/knot/zone/zonefile.h
@@ -95,9 +95,29 @@ int zonefile_write(const char *path, zone_contents_t *zone,
  */
 void zonefile_close(zloader_t *loader);
 
+/*!
+ * \brief Adds one RR into zone.
+ *
+ * \param zl  Zone loader.
+ * \param rr  RR to add.
+ *
+ * \return KNOT_E*
+ */
 int zcreator_step(zcreator_t *zl, const knot_rrset_t *rr);
 
-void process_error(const zs_scanner_t *scanner);
+/*!
+ * \brief Scanner error processing function.
+ * \param scanner  Scanner to use.
+ */
+void process_error(zs_scanner_t *scanner);
+
+/*!
+ * \brief Logs TTL mismatch error.
+ *
+ * \param node    Node with TTL mismatch.
+ * \param rr      RR that caused the mismatch.
+ */
+void log_ttl_error(const zone_node_t *node, const knot_rrset_t *rr);
 
 #endif /* _KNOTD_ZONELOAD_H_ */
 
diff --git a/src/libknot/dnssec/key.c b/src/libknot/dnssec/key.c
index ce0438e431d201800342992d224062c13bf56c31..548e32a52ec31173676ea8888e55f56d0de31a6f 100644
--- a/src/libknot/dnssec/key.c
+++ b/src/libknot/dnssec/key.c
@@ -93,7 +93,7 @@ static char *strndup_with_suffix(const char *base, int length, char *suffix)
 	return result;
 }
 
-static void key_scan_set_done(const zs_scanner_t *s)
+static void key_scan_set_done(zs_scanner_t *s)
 {
 	*((bool *)s->data) = true;
 }
diff --git a/src/libknot/dnssec/rrset-sign.c b/src/libknot/dnssec/rrset-sign.c
index 161cb4c6a25b620222d346469ac28790c912aaab..e15acada9a71e9f1e7668dee6c40ef6021810404 100644
--- a/src/libknot/dnssec/rrset-sign.c
+++ b/src/libknot/dnssec/rrset-sign.c
@@ -218,8 +218,9 @@ static int rrsigs_create_rdata(knot_rrset_t *rrsigs,
 	}
 
 	uint8_t result[size];
+	const knot_rdata_t *covered_data = knot_rdataset_at(&covered->rrs, 0);
 	int res = knot_rrsig_write_rdata(result, key, covered->type, owner_labels,
-	                                 knot_rrset_rr_ttl(covered, 0),
+	                                 knot_rdata_ttl(covered_data),
 	                                 sig_incepted, sig_expires);
 	assert(res == KNOT_EOK);
 
@@ -243,7 +244,7 @@ static int rrsigs_create_rdata(knot_rrset_t *rrsigs,
 	}
 
 	return knot_rrset_add_rdata(rrsigs, result, size,
-	                         knot_rrset_rr_ttl(covered, 0), NULL);
+	                            knot_rdata_ttl(covered_data), NULL);
 }
 
 /*!
@@ -336,7 +337,8 @@ int knot_is_valid_signature(const knot_rrset_t *covered,
 
 	// identify fields in the signature being validated
 
-	uint8_t *rdata = knot_rrset_rr_rdata(rrsigs, pos);
+	const knot_rdata_t *rr_data = knot_rdataset_at(&rrsigs->rrs, pos);
+	uint8_t *rdata = knot_rdata_data(rr_data);
 	if (!rdata) {
 		return KNOT_EINVAL;
 	}
diff --git a/src/libknot/dnssec/sig0.c b/src/libknot/dnssec/sig0.c
index c16cc6a73c94cc5806d0fcbdb1fb162375279470..a8df423d77eeb412e0bc1de478d07495c694c81b 100644
--- a/src/libknot/dnssec/sig0.c
+++ b/src/libknot/dnssec/sig0.c
@@ -74,7 +74,8 @@ static uint8_t *sig0_create_rdata(knot_rrset_t *rrset, knot_dnssec_key_t *key)
 		return NULL;
 	}
 
-	return knot_rrset_rr_rdata(rrset, 0);
+	const knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, 0);
+	return knot_rdata_data(rr);
 }
 
 /*!
diff --git a/src/libknot/edns.c b/src/libknot/edns.c
index 855d51d54a32766b49c27283fcce7484af2caf04..faf6c8dd3e81036281e83c758155854b47de4635 100644
--- a/src/libknot/edns.c
+++ b/src/libknot/edns.c
@@ -69,8 +69,7 @@ int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, const knot_rrset_t *rrset)
 
 	// TTL has switched bytes
 	uint32_t ttl;
-	dbg_edns_detail("TTL: %u\n", knot_rrset_rr_ttl(rrset, 0));
-	knot_wire_write_u32((uint8_t *)&ttl, knot_rrset_rr_ttl(rrset, 0));
+	knot_wire_write_u32((uint8_t *)&ttl, knot_rdata_ttl(knot_rdataset_at(&rrset->rrs, 0)));
 	// first byte of TTL is extended RCODE
 	dbg_edns_detail("TTL: %u\n", ttl);
 	memcpy(&opt_rr->ext_rcode, &ttl, 1);
@@ -86,9 +85,10 @@ int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, const knot_rrset_t *rrset)
 
 	int rc = 0;
 	dbg_edns_verb("Parsing options.\n");
-	uint16_t size = knot_rrset_rr_size(rrset, 0);
+	const knot_rdata_t *rr_data = knot_rdataset_at(&rrset->rrs, 0);
+	uint16_t size = knot_rdata_rdlen(rr_data);
 	if (size > 0) {
-		uint8_t *raw = knot_rrset_rr_rdata(rrset, 0);
+		uint8_t *raw = knot_rdata_data(rr_data);
 		size_t pos = 0;
 		while (pos < size) {
 			// ensure there is enough data to parse the OPTION CODE
diff --git a/src/libknot/packet/pkt.h b/src/libknot/packet/pkt.h
index ec4b16202de2da7ec24999b7f42677b3e851d5a8..0adb73b0d038a9e57ad9a837ef392076e22c7182 100644
--- a/src/libknot/packet/pkt.h
+++ b/src/libknot/packet/pkt.h
@@ -299,7 +299,7 @@ static inline bool knot_pkt_have_edns(const knot_pkt_t *pkt)
 }
 
 /*!
- * \brief Checks if EDNS is supported (i.e. has EDNS VERSION != UNSUPPORTED).
+ * \brief Checks if TSIG is present.
  */
 static inline bool knot_pkt_have_tsig(const knot_pkt_t *pkt)
 {
diff --git a/src/libknot/rdata/tsig.c b/src/libknot/rdata/tsig.c
index 0f8832ccd88c7d1886f070ad4d6076e2aeac31dc..66229c82e1f7b5b744e27b7eab6804868e47b2e9 100644
--- a/src/libknot/rdata/tsig.c
+++ b/src/libknot/rdata/tsig.c
@@ -57,14 +57,15 @@ typedef enum tsig_off_t {
  */
 static uint8_t* tsig_rdata_seek(const knot_rrset_t *rr, tsig_off_t id, size_t nb)
 {
-	uint8_t *rd = knot_rrset_rr_rdata(rr, 0);
+	const knot_rdata_t *rr_data = knot_rdataset_at(&rr->rrs, 0);
+	uint8_t *rd = knot_rdata_data(rr_data);
 	if (rd == NULL) {
 		return NULL;
 	}
 
 	/* TSIG RR names should be already sanitized on parse. */
 	int alg_len = knot_dname_size(rd);
-	uint16_t lim = knot_rrset_rr_size(rr, 0);
+	uint16_t lim = knot_rdata_rdlen(rr_data);
 	if (lim < alg_len + 5 * sizeof(uint16_t)) {
 		dbg_tsig("TSIG: rdata: not enough items "
 		         "(has %"PRIu16", min %zu).\n",
@@ -224,7 +225,8 @@ int tsig_rdata_set_other_data(knot_rrset_t *tsig, uint16_t len,
 
 const knot_dname_t *tsig_rdata_alg_name(const knot_rrset_t *tsig)
 {
-	return knot_rrset_rr_rdata(tsig, 0);
+	const knot_rdata_t *rr_data = knot_rdataset_at(&tsig->rrs, 0);
+	return knot_rdata_data(rr_data);
 }
 
 knot_tsig_algorithm_t tsig_rdata_alg(const knot_rrset_t *tsig)
@@ -467,8 +469,9 @@ size_t tsig_wire_actsize(const knot_rrset_t *tsig)
 int tsig_rdata_is_ok(const knot_rrset_t *tsig)
 {
 	/*! \todo Check size, needs to check variable-length fields. */
+	const knot_rdata_t *rr_data = knot_rdataset_at(&tsig->rrs, 0);
 	return (tsig
-	        && knot_rrset_rr_rdata(tsig, 0) != NULL
+	        && knot_rdata_data(rr_data) != NULL
 	        && tsig_rdata_seek(tsig, TSIG_OTHER_O, 0) != NULL
 	        && tsig_rdata_alg_name(tsig) != NULL
 	        && tsig_rdata_time_signed(tsig) != 0);
diff --git a/src/libknot/rrset-dump.c b/src/libknot/rrset-dump.c
index 41e4c2071bb50388998cfaf4def56833cfd6b784..0e7ad37f8e9b969985a5faf800d90d8ddcd7cab7 100644
--- a/src/libknot/rrset-dump.c
+++ b/src/libknot/rrset-dump.c
@@ -57,6 +57,7 @@ const knot_dump_style_t KNOT_DUMP_STYLE_DEFAULT = {
 	.show_class = false,
 	.show_ttl = true,
 	.verbose = false,
+	.empty_ttl = false,
 	.human_ttl = false,
 	.human_tmstamp = true,
 	.ascii_to_idn = NULL
@@ -1791,8 +1792,9 @@ int knot_rrset_txt_dump_data(const knot_rrset_t      *rrset,
 		return KNOT_EINVAL;
 	}
 
-	uint8_t   *data = knot_rrset_rr_rdata(rrset, pos);
-	uint16_t  data_len = knot_rrset_rr_size(rrset, pos);
+	const knot_rdata_t *rr_data = knot_rdataset_at(&rrset->rrs, pos);
+	uint8_t *data = knot_rdata_data(rr_data);
+	uint16_t data_len = knot_rdata_rdlen(rr_data);
 
 	int ret = 0;
 
@@ -1904,7 +1906,7 @@ int knot_rrset_txt_dump_data(const knot_rrset_t      *rrset,
 	}
 
 int knot_rrset_txt_dump_header(const knot_rrset_t      *rrset,
-                               uint32_t                ttl,
+                               const uint32_t          ttl,
                                char                    *dst,
                                const size_t            maxlen,
                                const knot_dump_style_t *style)
@@ -1933,7 +1935,9 @@ int knot_rrset_txt_dump_header(const knot_rrset_t      *rrset,
 
 	// Dump rrset ttl.
 	if (style->show_ttl) {
-		if (style->human_ttl) {
+		if (style->empty_ttl) {
+			ret = snprintf(dst + len, maxlen - len, "%c", sep);
+		} else if (style->human_ttl) {
 			// Create human readable ttl string.
 			if (time_to_human_str(buf, sizeof(buf), ttl) < 0) {
 				return KNOT_ESPACE;
@@ -2006,8 +2010,8 @@ int knot_rrset_txt_dump(const knot_rrset_t      *rrset,
 	uint16_t rr_count = rrset->rrs.rr_count;
 	for (uint16_t i = 0; i < rr_count; i++) {
 		// Dump rdata owner, class, ttl and type.
-		ret = knot_rrset_txt_dump_header(rrset,
-		                                 knot_rrset_rr_ttl(rrset, i),
+		const knot_rdata_t *rr_data = knot_rdataset_at(&rrset->rrs, i);
+		ret = knot_rrset_txt_dump_header(rrset, knot_rdata_ttl(rr_data),
 		                                 dst + len, maxlen - len, style);
 		if (ret < 0) {
 			return KNOT_ESPACE;
diff --git a/src/libknot/rrset-dump.h b/src/libknot/rrset-dump.h
index 0e2b394e498f3dc2ad373382b1d5bfa2c84bd054..57de3f89f374dcbb6bb6baa0af3adb5ee1b90694 100644
--- a/src/libknot/rrset-dump.h
+++ b/src/libknot/rrset-dump.h
@@ -37,10 +37,12 @@ typedef struct {
 	bool	wrap;
 	/*!< Show class. */
 	bool	show_class;
-	/*!< Show ttl. */
+	/*!< Show TTL. */
 	bool	show_ttl;
 	/*!< Print extra information. */
 	bool	verbose;
+	/*!< Show empty TTL value (keep indentation). */
+	bool	empty_ttl;
 	/*!< Format TTL as DHMS. */
 	bool	human_ttl;
 	/*!< Format timestamp as YYYYMMDDHHmmSS. */
@@ -58,14 +60,14 @@ extern const knot_dump_style_t KNOT_DUMP_STYLE_DEFAULT;
  * \param rrset		RRset to dump.
  * \param ttl		TTL to dump.
  * \param dst		Output buffer.
- * \param maxlen	Otuput buffer size.
+ * \param maxlen	Output buffer size.
  * \param style		Output style.
  *
  * \retval output length	if success.
  * \retval < 0			if error.
  */
 int knot_rrset_txt_dump_header(const knot_rrset_t      *rrset,
-                               uint32_t                ttl,
+                               const uint32_t          ttl,
                                char                    *dst,
                                const size_t            maxlen,
                                const knot_dump_style_t *style);
@@ -76,7 +78,7 @@ int knot_rrset_txt_dump_header(const knot_rrset_t      *rrset,
  * \param rrset		RRset to dump.
  * \param pos		Position of the record to dump.
  * \param dst		Output buffer.
- * \param maxlen	Otuput buffer size.
+ * \param maxlen	Output buffer size.
  * \param style		Output style.
  *
  * \retval output length	if success.
@@ -93,7 +95,7 @@ int knot_rrset_txt_dump_data(const knot_rrset_t      *rrset,
  *
  * \param rrset		RRset to dump.
  * \param dst		Output buffer.
- * \param maxlen	Otuput buffer size.
+ * \param maxlen	Output buffer size.
  * \param style		Output style.
  *
  * \retval output length	if success.
diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c
index fea075576533023085375cdb9e39104ea842d933..f5144783d651ae1951e2a4abca5767f15e405f92 100644
--- a/src/libknot/rrset.c
+++ b/src/libknot/rrset.c
@@ -41,7 +41,8 @@ static uint16_t rrset_rdata_naptr_bin_chunk_size(const knot_rrset_t *rrset,
 	}
 
 	size_t size = 0;
-	uint8_t *rdata = knot_rrset_rr_rdata(rrset, pos);
+	const knot_rdata_t *rr_data = knot_rdataset_at(&rrset->rrs, pos);
+	uint8_t *rdata = knot_rdata_data(rr_data);
 	assert(rdata);
 
 	/* Two shorts at the beginning. */
@@ -60,10 +61,10 @@ static uint16_t rrset_rdata_naptr_bin_chunk_size(const knot_rrset_t *rrset,
 }
 
 static size_t rrset_rdata_remainder_size(const knot_rrset_t *rrset,
-                                         size_t offset, size_t pos)
+                                         uint16_t offset, size_t pos)
 {
-	size_t ret = knot_rrset_rr_size(rrset, pos) - offset;
-	return ret;
+	const knot_rdata_t *rr_data = knot_rdataset_at(&rrset->rrs, pos);
+	return knot_rdata_rdlen(rr_data) - offset;
 }
 
 static int knot_rrset_header_to_wire(const knot_rrset_t *rrset, uint32_t ttl,
@@ -148,7 +149,8 @@ static int knot_rrset_rdata_to_wire_one(const knot_rrset_t *rrset,
 
 	/* Put RR header to wire. */
 	size_t size = 0;
-	int ret = knot_rrset_header_to_wire(rrset, knot_rrset_rr_ttl(rrset, rdata_pos),
+	int ret = knot_rrset_header_to_wire(rrset,
+	                                    knot_rdata_ttl(knot_rdataset_at(&rrset->rrs, rdata_pos)),
 	                                    pos, max_size,
 	                                    compr, &size);
 	if (ret != KNOT_EOK) {
@@ -167,7 +169,8 @@ static int knot_rrset_rdata_to_wire_one(const knot_rrset_t *rrset,
 	}
 
 	/* Get pointer into RDATA array. */
-	uint8_t *rdata = knot_rrset_rr_rdata(rrset, rdata_pos);
+	const knot_rdata_t *rr_data = knot_rdataset_at(&rrset->rrs, rdata_pos);
+	uint8_t *rdata = knot_rdata_data(rr_data);
 	assert(rdata);
 	/* Offset into one RDATA array. */
 	size_t offset = 0;
@@ -416,44 +419,6 @@ void knot_rrset_clear(knot_rrset_t *rrset, mm_ctx_t *mm)
 	}
 }
 
-uint8_t *knot_rrset_rr_rdata(const knot_rrset_t *rrset, size_t pos)
-{
-	knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, pos);
-	if (rr) {
-		return knot_rdata_data(rr);
-	} else {
-		return NULL;
-	}
-}
-
-uint16_t knot_rrset_rr_size(const knot_rrset_t *rrset, size_t pos)
-{
-	const knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, pos);
-	if (rr) {
-		return knot_rdata_rdlen(rr);
-	} else {
-		return 0;
-	}
-}
-
-uint32_t knot_rrset_rr_ttl(const knot_rrset_t *rrset, size_t pos)
-{
-	const knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, pos);
-	if (rr) {
-		return knot_rdata_ttl(rr);
-	} else {
-		return 0;
-	}
-}
-
-void knot_rrset_rr_set_ttl(const knot_rrset_t *rrset, size_t pos, uint32_t ttl)
-{
-	knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, pos);
-	if (rr) {
-		knot_rdata_set_ttl(rr, ttl);
-	}
-}
-
 int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, size_t *size,
                        size_t max_size, uint16_t *rr_count, knot_compr_t *compr)
 {
diff --git a/src/libknot/rrset.h b/src/libknot/rrset.h
index 1e95aeee851907f1e79ae1e4095126a6c8678a2a..efe9fafd5320d4668c3e1a0f6c53bd66f7bc6019 100644
--- a/src/libknot/rrset.h
+++ b/src/libknot/rrset.h
@@ -124,48 +124,6 @@ void knot_rrset_free(knot_rrset_t **rrset, mm_ctx_t *mm);
  */
 void knot_rrset_clear(knot_rrset_t *rrset, mm_ctx_t *mm);
 
-/* ----------- Getters / Setters (legacy, functionality in rdata_t) ------------ */
-
-/*!
- * \brief Returns RDATA of RR on given position.
- *
- * \param rrset  RRSet to get the RDATA from.
- * \param pos    Position of RR to get.
- *
- * \retval  NULL if no RDATA on rdata_pos exist.
- * \retval  Pointer to RDATA on given position if successfull.
- */
-uint8_t *knot_rrset_rr_rdata(const knot_rrset_t *rrset, size_t pos);
-
-/*!
- * \brief Returns size of an RR RDATA on a given position.
- *
- * \param rrset  RRSet holding RR RDATA.
- * \param pos    RR position.
- *
- * \return Item size.
- */
-uint16_t knot_rrset_rr_size(const knot_rrset_t *rrset, size_t pos);
-
-/*!
- * \brief Returns TTL of an RR on a given position.
- *
- * \param rrset  RRSet holding RR RDATA.
- * \param pos    RR position.
- *
- * \return TTL.
- */
-uint32_t knot_rrset_rr_ttl(const knot_rrset_t *rrset, size_t pos);
-
-/*!
- * \brief Sets TTL for RR on a given position.
- *
- * \param rrset  RRSet containing RR.
- * \param pos    RR position.
- * \param ttl    TTL to be set.
- */
-void knot_rrset_rr_set_ttl(const knot_rrset_t *rrset, size_t pos, uint32_t ttl);
-
 /* ---------- Wire conversions (legacy, to be done in knot_pkt_t) ----------- */
 
 /*!
diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c
index 86c45e941fe5f961c5a35285842eaa1f6c7f5955..6980b94659e9de9b9624f8724c6ffc58231b1a17 100644
--- a/src/libknot/tsig-op.c
+++ b/src/libknot/tsig-op.c
@@ -215,9 +215,7 @@ static int knot_tsig_write_tsig_variables(uint8_t *wire,
 	offset += sizeof(uint16_t);
 
 	/* Copy TTL - always 0. */
-	knot_wire_write_u32(wire + offset, knot_rrset_rr_ttl(tsig_rr, 0));
-	dbg_tsig_verb("TSIG: write variables: written TTL: %u - \n",
-	              knot_rrset_rr_ttl(tsig_rr, 0));
+	knot_wire_write_u32(wire + offset, knot_rdata_ttl(knot_rdataset_at(&tsig_rr->rrs, 0)));
 	dbg_tsig_hex_detail((char *)(wire + offset), sizeof(uint32_t));
 	offset += sizeof(uint32_t);
 
diff --git a/src/utils/common/exec.c b/src/utils/common/exec.c
index 92af2dfe537110110ba374d620b7a49164609df5..fda356f85cf94670e2e21d48c20861135d2a2dfc 100644
--- a/src/utils/common/exec.c
+++ b/src/utils/common/exec.c
@@ -95,28 +95,31 @@ static void print_header(const knot_pkt_t *packet, const style_t *style)
 		strcat(flags, " cd");
 	}
 
-	// Print formated info.
+	uint16_t id = knot_wire_get_id(packet->wire);
+	uint16_t qdcount = knot_wire_get_qdcount(packet->wire);
+	uint16_t ancount = knot_wire_get_ancount(packet->wire);
+	uint16_t nscount = knot_wire_get_nscount(packet->wire);
+	uint16_t arcount = knot_wire_get_arcount(packet->wire);
+
+	if (knot_pkt_have_tsig(packet)) {
+		arcount++;
+	}
+
+	// Print formatted info.
 	switch (style->format) {
 	case FORMAT_NSUPDATE:
 		printf(";; ->>HEADER<<- opcode: %s; status: %s; id: %u\n"
 		       ";; Flags:%1s; "
 		       "ZONE: %u; PREREQ: %u; UPDATE: %u; ADDITIONAL: %u\n",
-		       opcode_str, rcode_str, knot_wire_get_id(packet->wire),
-		       flags, knot_wire_get_qdcount(packet->wire),
-		       knot_wire_get_ancount(packet->wire),
-		       knot_wire_get_nscount(packet->wire),
-		       knot_wire_get_arcount(packet->wire));
-
+		       opcode_str, rcode_str, id, flags, qdcount, ancount,
+		       nscount, arcount);
 		break;
 	default:
 		printf(";; ->>HEADER<<- opcode: %s; status: %s; id: %u\n"
 		       ";; Flags:%1s; "
 		       "QUERY: %u; ANSWER: %u; AUTHORITY: %u; ADDITIONAL: %u\n",
-		       opcode_str, rcode_str, knot_wire_get_id(packet->wire),
-		       flags, knot_wire_get_qdcount(packet->wire),
-		       knot_wire_get_ancount(packet->wire),
-		       knot_wire_get_nscount(packet->wire),
-		       knot_wire_get_arcount(packet->wire));
+		       opcode_str, rcode_str, id, flags, qdcount, ancount,
+		       nscount, arcount);
 		break;
 	}
 }
@@ -170,7 +173,7 @@ static void print_footer(const size_t total_len,
 	}
 }
 
-static void print_opt_section(const knot_opt_rr_t *rr)
+static void print_section_opt(const knot_opt_rr_t *rr)
 {
 	printf("Version: %u; flags: %s; UDP size: %u B\n",
 	       knot_edns_get_version(rr),
@@ -199,10 +202,14 @@ static void print_section_question(const knot_dname_t *owner,
 {
 	size_t buflen = 8192;
 	char   *buf = calloc(buflen, 1);
+
+	// Don't print zero TTL.
+	knot_dump_style_t qstyle = style->style;
+	qstyle.empty_ttl = true;
+
 	knot_rrset_t *question = knot_rrset_new(owner, qtype, qclass, NULL);
 
-	if (knot_rrset_txt_dump_header(question, 0, buf, buflen,
-	    &(style->style)) < 0) {
+	if (knot_rrset_txt_dump_header(question, 0, buf, buflen, &qstyle) < 0) {
 		WARN("can't print whole question section\n");
 	}
 
@@ -214,21 +221,28 @@ static void print_section_question(const knot_dname_t *owner,
 
 static void print_section_full(const knot_rrset_t *rrsets,
                                const uint16_t     count,
-                               const style_t      *style)
+                               const style_t      *style,
+                               const bool         no_tsig)
 {
 	size_t buflen = 8192;
 	char   *buf = calloc(buflen, 1);
 
 	for (size_t i = 0; i < count; i++) {
+		// Ignore OPT records.
 		if (rrsets[i].type == KNOT_RRTYPE_OPT) {
 			continue;
 		}
 
+		// Exclude TSIG record.
+		if (no_tsig && rrsets[i].type == KNOT_RRTYPE_TSIG) {
+			continue;
+		}
+
 		while (knot_rrset_txt_dump(&rrsets[i], buf, buflen,
 		                           &(style->style)) < 0) {
 			buflen += 4096;
 			// Oversize protection.
-			if (buflen > 1000000) {
+			if (buflen > 100000) {
 				WARN("can't print whole section\n");
 				break;
 			}
@@ -261,7 +275,7 @@ static void print_section_dig(const knot_rrset_t *rrsets,
 			                                &(style->style)) < 0) {
 				buflen += 4096;
 				// Oversize protection.
-				if (buflen > 1000000) {
+				if (buflen > 100000) {
 					WARN("can't print whole section\n");
 					break;
 				}
@@ -310,7 +324,7 @@ static void print_section_host(const knot_rrset_t *rrsets,
 			                                &(style->style)) < 0) {
 				buflen += 4096;
 				// Oversize protection.
-				if (buflen > 1000000) {
+				if (buflen > 100000) {
 					WARN("can't print whole section\n");
 					break;
 				}
@@ -422,8 +436,8 @@ void print_data_xfr(const knot_pkt_t *packet,
 		return;
 	}
 
-	const knot_pktsection_t *answers = knot_pkt_section(packet, KNOT_ANSWER);
-	const knot_pktsection_t *additional = knot_pkt_section(packet, KNOT_ADDITIONAL);
+	const knot_pktsection_t *answers = knot_pkt_section(packet,
+	                                                    KNOT_ANSWER);
 
 	switch (style->format) {
 	case FORMAT_DIG:
@@ -433,12 +447,11 @@ void print_data_xfr(const knot_pkt_t *packet,
 		print_section_host(answers->rr, answers->count, style);
 		break;
 	case FORMAT_FULL:
-		print_section_full(answers->rr, answers->count, style);
+		print_section_full(answers->rr, answers->count, style, true);
 
-		// Print TSIG record if any.
-		if (style->show_additional) {
-			print_section_full(additional->rr, additional->count,
-			                   style);
+		// Print TSIG record.
+		if (style->show_tsig && knot_pkt_have_tsig(packet)) {
+			print_section_full(packet->tsig_rr, 1, style, false);
 		}
 		break;
 	default:
@@ -465,6 +478,7 @@ void print_footer_xfr(const size_t  total_len,
 
 void print_packet(const knot_pkt_t *packet,
                   const net_t      *net,
+                  const size_t     size,
                   const float      elapsed,
                   const bool       incoming,
                   const style_t    *style)
@@ -474,14 +488,24 @@ void print_packet(const knot_pkt_t *packet,
 		return;
 	}
 
-	const knot_pktsection_t *answers = knot_pkt_section(packet, KNOT_ANSWER);
-	const knot_pktsection_t *authority = knot_pkt_section(packet, KNOT_AUTHORITY);
-	const knot_pktsection_t *additional = knot_pkt_section(packet, KNOT_ADDITIONAL);
+	const knot_pktsection_t *answers = knot_pkt_section(packet,
+	                                                    KNOT_ANSWER);
+	const knot_pktsection_t *authority = knot_pkt_section(packet,
+	                                                      KNOT_AUTHORITY);
+	const knot_pktsection_t *additional = knot_pkt_section(packet,
+	                                                       KNOT_ADDITIONAL);
 
 	uint8_t rcode = knot_wire_get_rcode(packet->wire);
 	uint16_t qdcount = knot_wire_get_qdcount(packet->wire);
-	uint16_t arcount = additional->count;
-	uint16_t ancount = answers->count;
+	uint16_t ancount = knot_wire_get_ancount(packet->wire);
+	uint16_t nscount = knot_wire_get_nscount(packet->wire);
+	uint16_t arcount = knot_wire_get_arcount(packet->wire);
+
+	// Disable additionals printing if there are no other records.
+	// OPT record may be placed anywhere within additionals!
+	if (knot_pkt_have_edns(packet) && arcount == 1) {
+		arcount = 0;
+	}
 
 	// Print packet information header.
 	if (style->show_header) {
@@ -489,13 +513,9 @@ void print_packet(const knot_pkt_t *packet,
 	}
 
 	// Print EDNS section.
-	if (knot_pkt_have_edns(packet)) {
-		if (style->show_edns) {
-			printf("\n;; EDNS PSEUDOSECTION:\n;; ");
-			print_opt_section(&packet->opt_rr);
-		}
-
-		arcount--;
+	if (style->show_edns && knot_pkt_have_edns(packet)) {
+		printf("\n;; EDNS PSEUDOSECTION:\n;; ");
+		print_section_opt(&packet->opt_rr);
 	}
 
 	// Print DNS sections.
@@ -521,25 +541,19 @@ void print_packet(const knot_pkt_t *packet,
 			                       style);
 		}
 
-		if (style->show_answer && answers->count > 0) {
+		if (style->show_answer && ancount > 0) {
 			printf("\n;; PREREQUISITE SECTION:\n");
-			print_section_full(answers->rr,
-			                   answers->count,
-			                   style);
+			print_section_full(answers->rr, ancount, style, true);
 		}
 
-		if (style->show_authority && authority->count > 0) {
+		if (style->show_authority && nscount > 0) {
 			printf("\n;; UPDATE SECTION:\n");
-			print_section_full(authority->rr,
-			                   authority->count,
-			                   style);
+			print_section_full(authority->rr, nscount, style, true);
 		}
 
-		if (style->show_additional && additional->count > 0) {
+		if (style->show_additional && arcount > 0) {
 			printf("\n;; ADDITIONAL DATA:\n");
-			print_section_full(additional->rr,
-			                   additional->count,
-			                   style);
+			print_section_full(additional->rr, arcount, style, true);
 		}
 		break;
 	case FORMAT_FULL:
@@ -551,35 +565,35 @@ void print_packet(const knot_pkt_t *packet,
 			                       style);
 		}
 
-		if (style->show_answer && answers->count > 0) {
+		if (style->show_answer && ancount > 0) {
 			printf("\n;; ANSWER SECTION:\n");
-			print_section_full(answers->rr,
-			                   answers->count,
-			                   style);
+			print_section_full(answers->rr, ancount, style, true);
 		}
 
-		if (style->show_authority && authority->count > 0) {
+		if (style->show_authority && nscount > 0) {
 			printf("\n;; AUTHORITY SECTION:\n");
-			print_section_full(authority->rr,
-			                   authority->count,
-			                   style);
+			print_section_full(authority->rr, nscount, style, true);
 		}
 
-		if (style->show_additional && additional->count > 0) {
+		if (style->show_additional && arcount > 0) {
 			printf("\n;; ADDITIONAL SECTION:\n");
-			print_section_full(additional->rr,
-			                   arcount,
-			                   style);
+			print_section_full(additional->rr, arcount, style, true);
 		}
 		break;
 	default:
 		break;
 	}
 
+	// Print TSIG section.
+	if (style->show_tsig && knot_pkt_have_tsig(packet)) {
+		printf("\n;; TSIG PSEUDOSECTION:\n");
+		print_section_full(packet->tsig_rr, 1, style, false);
+	}
+
 	// Print packet statistics.
 	if (style->show_footer) {
 		printf("\n");
-		print_footer(packet->size, 0, 0, net, elapsed, incoming);
+		print_footer(size, 0, 0, net, elapsed, incoming);
 	}
 }
 
diff --git a/src/utils/common/exec.h b/src/utils/common/exec.h
index 035d427848744c507815d12b60cfcc1c73f76300..62cab9df40828b6bb04262a5d78f29d5ba5302dc 100644
--- a/src/utils/common/exec.h
+++ b/src/utils/common/exec.h
@@ -65,8 +65,7 @@ void print_header_xfr(const knot_pkt_t *packet, const style_t *style);
  * \param packet	Response packet.
  * \param style		Style of the output.
  */
-void print_data_xfr(const knot_pkt_t *packet,
-                    const style_t       *style);
+void print_data_xfr(const knot_pkt_t *packet, const style_t *style);
 
 /*!
  * \brief Prints trailing statistics for transfer.
@@ -75,31 +74,32 @@ void print_data_xfr(const knot_pkt_t *packet,
  * \param msg_count	Number of messages.
  * \param rr_count	Total number of answer records.
  * \param net		Connection information.
- * \param elapse	Total elapsed time.
+ * \param elapsed	Total elapsed time.
  * \param style		Style of the otput.
  */
-void print_footer_xfr(const size_t   total_len,
-                      const size_t   msg_count,
-                      const size_t   rr_count,
-                      const net_t    *net,
-                      const float    elapsed,
-                      const style_t  *style);
+void print_footer_xfr(const size_t  total_len,
+                      const size_t  msg_count,
+                      const size_t  rr_count,
+                      const net_t   *net,
+                      const float   elapsed,
+                      const style_t *style);
 
 /*!
  * \brief Prints one response packet.
  *
  * \param packet	Response packet.
- * \param total_len	Total reply size (all messages).
  * \param net		Connection information.
- * \param elapse	Total elapsed time.
+ * \param size		Original packet wire size.
+ * \param elapsed	Total elapsed time.
  * \param incoming	Indicates if the packet is input.
  * \param style		Style of the otput.
  */
 void print_packet(const knot_pkt_t *packet,
-                  const net_t         *net,
-                  const float         elapsed,
-                  const bool          incoming,
-                  const style_t       *style);
+                  const net_t      *net,
+                  const size_t     size,
+                  const float      elapsed,
+                  const bool       incoming,
+                  const style_t    *style);
 
 /*!
  * \brief Cleans up sign context.
@@ -118,7 +118,7 @@ void free_sign_context(sign_context_t *ctx);
  * \retval KNOT_EOK	if success.
  * \retval error code	if error.
  */
-int sign_packet(knot_pkt_t           *pkt,
+int sign_packet(knot_pkt_t              *pkt,
                 sign_context_t          *sign_ctx,
                 const knot_key_params_t *key_params);
 
@@ -132,7 +132,7 @@ int sign_packet(knot_pkt_t           *pkt,
  * \retval KNOT_EOK	if success.
  * \retval error code	if error.
  */
-int verify_packet(const knot_pkt_t     *pkt,
+int verify_packet(const knot_pkt_t        *pkt,
                   const sign_context_t    *sign_ctx,
                   const knot_key_params_t *key_params);
 
diff --git a/src/utils/common/params.c b/src/utils/common/params.c
index 668847b6dbf4008dc3bd73b5250a722c1f71c346..b3b5336121f272ef5518622d8dd448cec78c112b 100644
--- a/src/utils/common/params.c
+++ b/src/utils/common/params.c
@@ -103,17 +103,6 @@ static int cmp_prefix(const char *pref, const size_t pref_len,
 	}
 }
 
-/*!
- * \brief Find the best parameter match in table based on prefix equality.
- *
- * \param str		Parameter name to look up.
- * \param str_len	Parameter name length.
- * \param tbl		Parameter table.
- * \param unique	Indication if output is unique result.
- *
- * \retval >=0		looked up parameter position in \a tbl.
- * \retval err		if error.
- */
 int best_param(const char *str, const size_t str_len, const param_t *tbl,
                bool *unique)
 {
diff --git a/src/utils/common/params.h b/src/utils/common/params.h
index d7c34c63bfa74b4ad9dd924e1ae50c612db0659a..efd4e5f61a33962697e70bed2d8b09d5016a9386 100644
--- a/src/utils/common/params.h
+++ b/src/utils/common/params.h
@@ -81,7 +81,7 @@ typedef struct {
 	bool	show_query;
 	/*!< Show header info. */
 	bool	show_header;
-	/*!< Show EDNS info. */
+	/*!< Show EDNS pseudosection. */
 	bool	show_edns;
 	/*!< Show QUERY/ZONE section. */
 	bool	show_question;
@@ -91,6 +91,8 @@ typedef struct {
 	bool	show_authority;
 	/*!< Show ADDITIONAL section. */
 	bool	show_additional;
+	/*!< Show TSIG pseudosection. */
+	bool	show_tsig;
 	/*!< Show footer info. */
 	bool	show_footer;
 
@@ -134,6 +136,17 @@ char* name_from_idn(const char *idn_name);
  */
 void name_to_idn(char **name);
 
+/*!
+ * \brief Find the best parameter match in table based on prefix equality.
+ *
+ * \param str		Parameter name to look up.
+ * \param str_len	Parameter name length.
+ * \param tbl		Parameter table.
+ * \param unique	Indication if output is unique result.
+ *
+ * \retval >=0		looked up parameter position in \a tbl.
+ * \retval err		if error.
+ */
 int best_param(const char *str, const size_t str_len, const param_t *tbl,
                bool *unique);
 
diff --git a/src/utils/dig/dig_exec.c b/src/utils/dig/dig_exec.c
index e634cfbf3de17f411e88123879c5a71891364fd4..f7160051093bf9b342b84c894117f814f8276d00 100644
--- a/src/utils/dig/dig_exec.c
+++ b/src/utils/dig/dig_exec.c
@@ -291,9 +291,21 @@ static int process_query_packet(const knot_pkt_t        *query,
 
 	// Print query packet if required.
 	if (style->show_query) {
-		print_packet(query, net,
-		             time_diff(&t_start, &t_query),
-		             false, style);
+		// Create copy of query packet for parsing.
+		knot_pkt_t *q = knot_pkt_new(query->wire, query->size, NULL);
+		if (q != NULL) {
+			if (knot_pkt_parse(q, 0) == KNOT_EOK) {
+				print_packet(q, net, query->size,
+					     time_diff(&t_start, &t_query),
+					     false, style);
+			} else {
+				ERR("can't print query packet\n");
+			}
+			knot_pkt_free(&q);
+		} else {
+			ERR("can't print query packet\n");
+		}
+
 		printf("\n");
 	}
 
@@ -367,7 +379,7 @@ static int process_query_packet(const knot_pkt_t        *query,
 	}
 
 	// Print reply packet.
-	print_packet(reply, net, time_diff(&t_query, &t_end),
+	print_packet(reply, net, in_len, time_diff(&t_query, &t_end),
 	             true, style);
 
 	knot_pkt_free(&reply);
@@ -474,7 +486,7 @@ static void process_query(const query_t *query)
 	knot_pkt_free(&out_packet);
 }
 
-static int process_packet_xfr(const knot_pkt_t     *query,
+static int process_packet_xfr(const knot_pkt_t        *query,
                               net_t                   *net,
                               const sign_context_t    *sign_ctx,
                               const knot_key_params_t *key_params,
@@ -511,7 +523,7 @@ static int process_packet_xfr(const knot_pkt_t     *query,
 
 	// Print query packet if required.
 	if (style->show_query) {
-		print_packet(query, net,
+		print_packet(query, net, query->size,
 		             time_diff(&t_start, &t_query),
 		             false, style);
 		printf("\n");
diff --git a/src/utils/dig/dig_params.c b/src/utils/dig/dig_params.c
index a38714f62f3998fd0936b0af59fd13c7189f649d..ef09085a7e926506eb6223aead1638a5e2aa05b8 100644
--- a/src/utils/dig/dig_params.c
+++ b/src/utils/dig/dig_params.c
@@ -50,6 +50,7 @@ static const style_t DEFAULT_STYLE_DIG = {
 		.show_class = true,
 		.show_ttl = true,
 		.verbose = false,
+		.empty_ttl = false,
 		.human_ttl = false,
 		.human_tmstamp = true,
 		.ascii_to_idn = name_to_idn
@@ -61,6 +62,7 @@ static const style_t DEFAULT_STYLE_DIG = {
 	.show_answer = true,
 	.show_authority = true,
 	.show_additional = true,
+	.show_tsig = true,
 	.show_footer = true
 };
 
@@ -405,6 +407,26 @@ static int opt_noadditional(const char *arg, void *query)
 	query_t *q = query;
 
 	q->style.show_additional = false;
+	q->style.show_edns = false;
+	q->style.show_tsig = false;
+
+	return KNOT_EOK;
+}
+
+static int opt_tsig(const char *arg, void *query)
+{
+	query_t *q = query;
+
+	q->style.show_tsig = true;
+
+	return KNOT_EOK;
+}
+
+static int opt_notsig(const char *arg, void *query)
+{
+	query_t *q = query;
+
+	q->style.show_tsig = false;
 
 	return KNOT_EOK;
 }
@@ -690,6 +712,9 @@ static const param_t dig_opts2[] = {
 	{ "additional",   ARG_NONE,     opt_additional },
 	{ "noadditional", ARG_NONE,     opt_noadditional },
 
+	{ "tsig",         ARG_NONE,     opt_tsig },
+	{ "notsig",       ARG_NONE,     opt_notsig },
+
 	{ "stats",        ARG_NONE,     opt_stats },
 	{ "nostats",      ARG_NONE,     opt_nostats },
 
@@ -1190,6 +1215,7 @@ static void dig_help(void)
 	       "       +[no]answer     Show answer section.\n"
 	       "       +[no]authority  Show authority section.\n"
 	       "       +[no]additional Show additional section.\n"
+	       "       +[no]tsig       Show TSIG pseudosection.\n"
 	       "       +[no]stats      Show trailing packet statistics.\n"
 	       "       +[no]class      Show DNS class.\n"
 	       "       +[no]ttl        Show TTL value.\n"
diff --git a/src/utils/host/host_params.c b/src/utils/host/host_params.c
index 8cdd0d1f864fbf799a545e17ef903a1b43c3c619..c7d5f61733062487e6e2217d927991106b163b12 100644
--- a/src/utils/host/host_params.c
+++ b/src/utils/host/host_params.c
@@ -40,6 +40,7 @@ static const style_t DEFAULT_STYLE_HOST = {
 		.show_class = true,
 		.show_ttl = true,
 		.verbose = false,
+		.empty_ttl = false,
 		.human_ttl = false,
 		.human_tmstamp = true,
 		.ascii_to_idn = name_to_idn
@@ -51,7 +52,8 @@ static const style_t DEFAULT_STYLE_HOST = {
 	.show_answer = true,
 	.show_authority = true,
 	.show_additional = true,
-	.show_footer = false,
+	.show_tsig = false,
+	.show_footer = false
 };
 
 static int host_init(dig_params_t *params)
diff --git a/src/utils/nsupdate/nsupdate_exec.c b/src/utils/nsupdate/nsupdate_exec.c
index fefb721d991fd0f35b81420ef610def67f22ec34..b6e760f6a2d9359b05c02c69f2a052f7152cf28d 100644
--- a/src/utils/nsupdate/nsupdate_exec.c
+++ b/src/utils/nsupdate/nsupdate_exec.c
@@ -800,7 +800,7 @@ int cmd_show(const char* lp, nsupdate_params_t *params)
 	if (!params->query) return KNOT_EOK;
 	printf("Update query:\n");
 	build_query(params);
-	print_packet(params->query, NULL, -1, false, &params->style);
+	print_packet(params->query, NULL, 0, -1, false, &params->style);
 	printf("\n");
 	return KNOT_EOK;
 }
@@ -812,7 +812,7 @@ int cmd_answer(const char* lp, nsupdate_params_t *params)
 	/* Show current answer. */
 	if (!params->answer) return KNOT_EOK;
 	printf("\nAnswer:\n");
-	print_packet(params->answer, NULL, -1, true, &params->style);
+	print_packet(params->answer, NULL, 0, -1, true, &params->style);
 	return KNOT_EOK;
 }
 
diff --git a/src/utils/nsupdate/nsupdate_params.c b/src/utils/nsupdate/nsupdate_params.c
index 6b581fedfebf110b9d3a9d6616457bc8dccf6774..bb141af699727aae201289e28e5587b119f68f60 100644
--- a/src/utils/nsupdate/nsupdate_params.c
+++ b/src/utils/nsupdate/nsupdate_params.c
@@ -39,6 +39,7 @@ static const style_t DEFAULT_STYLE_NSUPDATE = {
 		.show_class = true,
 		.show_ttl = true,
 		.verbose = false,
+		.empty_ttl = false,
 		.human_ttl = false,
 		.human_tmstamp = true,
 		.ascii_to_idn = NULL
@@ -50,10 +51,11 @@ static const style_t DEFAULT_STYLE_NSUPDATE = {
 	.show_answer = true,
 	.show_authority = true,
 	.show_additional = true,
-	.show_footer = false,
+	.show_tsig = true,
+	.show_footer = false
 };
 
-static void parse_err(const zs_scanner_t *s) {
+static void parse_err(zs_scanner_t *s) {
 	ERR("failed to parse RR: %s\n", zs_strerror(s->error_code));
 }
 
diff --git a/src/zscanner/Makefile.am b/src/zscanner/Makefile.am
index e8cfdf48441a099d122aa6963d335848f4648016..65c9b9d7b5aa97efd5e3486decfccfb8df3d8d99 100644
--- a/src/zscanner/Makefile.am
+++ b/src/zscanner/Makefile.am
@@ -14,27 +14,15 @@ EXTRA_DIST =				\
 BUILT_SOURCES = scanner.c
 CLEANFILES = scanner.c
 
-if HAVE_RAGEL
-scanner.c: scanner.rl scanner_body.rl
-	$(RAGEL) $(FSM_TYPE) -o $@ $(srcdir)/scanner.rl
-else
-
-if G2_PARSER
+if FAST_PARSER
 scanner.c: scanner.c.g2
 	cp $(srcdir)/$@.g2 $@
-endif
-
-if T0_PARSER
+	@echo "NOTE: Compilation of scanner.c can take several minutes!"
+else
 scanner.c: scanner.c.t0
 	cp $(srcdir)/$@.t0 $@
 endif
 
-endif #HAVE_RAGEL
-
-if G2_PARSER
-	@echo "NOTE: Compilation of scanner.c can take several minutes!"
-endif
-
 libzscanner_la_SOURCES =		\
 	zscanner.h			\
 	scanner.h			\
diff --git a/src/zscanner/loader.c b/src/zscanner/loader.c
index 9c8fd80e1dd55544610adf2e59a7c03657d0972c..fc39a336fab443d79cbf34e10af73c58ddbb8e40 100644
--- a/src/zscanner/loader.c
+++ b/src/zscanner/loader.c
@@ -36,8 +36,8 @@ zs_loader_t* zs_loader_create(const char     *file_name,
                               const char     *origin,
                               const uint16_t rclass,
                               const uint32_t ttl,
-                              void (*process_record)(const zs_scanner_t *),
-                              void (*process_error)(const zs_scanner_t *),
+                              void (*process_record)(zs_scanner_t *),
+                              void (*process_error)(zs_scanner_t *),
                               void *data)
 {
 	// Creating zeroed structure.
diff --git a/src/zscanner/loader.h b/src/zscanner/loader.h
index e2a2ee94f6f23d5d29c49b6e05d43c516adae605..8a663b152610a21755b5e3dea9ed2b16d97b349b 100644
--- a/src/zscanner/loader.h
+++ b/src/zscanner/loader.h
@@ -59,8 +59,8 @@ zs_loader_t* zs_loader_create(const char     *file_name,
                               const char     *origin,
                               const uint16_t rclass,
                               const uint32_t ttl,
-                              void (*process_record)(const zs_scanner_t *),
-                              void (*process_error)(const zs_scanner_t *),
+                              void (*process_record)(zs_scanner_t *),
+                              void (*process_error)(zs_scanner_t *),
                               void *data);
 
 /*!
diff --git a/src/zscanner/scanner.c.g2 b/src/zscanner/scanner.c.g2
index 3fac8c5d36a2ee72c4276fad9c09d361e4695b72..d3632ba002a03e92afaa41f7b07fb236df9ff7ea 100644
--- a/src/zscanner/scanner.c.g2
+++ b/src/zscanner/scanner.c.g2
@@ -42,7 +42,7 @@
 /*!
  * \brief Empty function which is called if no callback function is specified.
  */
-static inline void noop(const zs_scanner_t *s)
+static inline void noop(zs_scanner_t *s)
 {
 	(void)s;
 }
@@ -135,8 +135,8 @@ zs_scanner_t* zs_scanner_create(const char     *file_name,
                                 const char     *origin,
                                 const uint16_t rclass,
                                 const uint32_t ttl,
-                                void (*process_record)(const zs_scanner_t *),
-                                void (*process_error)(const zs_scanner_t *),
+                                void (*process_record)(zs_scanner_t *),
+                                void (*process_error)(zs_scanner_t *),
                                 void *data)
 {
 	char settings[1024];
@@ -1412,6 +1412,11 @@ tr81:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	{
 		s->line_counter++;
@@ -11588,6 +11593,11 @@ tr93:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1057;
 tr657:
@@ -11606,6 +11616,11 @@ tr657:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1057;
 st1057:
@@ -17745,6 +17760,11 @@ tr129:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1058;
 tr123:
@@ -17767,6 +17787,11 @@ tr123:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1058;
 st1058:
@@ -18454,6 +18479,11 @@ tr706:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1059;
 tr701:
@@ -18479,6 +18509,11 @@ tr701:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1059;
 tr3170:
@@ -18907,6 +18942,11 @@ tr670:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1061;
 tr695:
@@ -18924,6 +18964,11 @@ tr695:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1061;
 tr3140:
@@ -18971,6 +19016,11 @@ tr3204:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	{
 		s->line_counter++;
@@ -18994,6 +19044,11 @@ tr3227:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	{
 		if (s->r_owner_length == 0) {
@@ -20098,6 +20153,11 @@ tr90:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	{
 		s->line_counter++;
@@ -20267,6 +20327,11 @@ tr659:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	{
 		s->line_counter++;
@@ -20829,6 +20894,11 @@ tr661:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1063;
 tr666:
@@ -20916,6 +20986,11 @@ tr666:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1063;
 st1063:
@@ -22806,6 +22881,11 @@ tr680:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1064;
 tr712:
@@ -22827,6 +22907,11 @@ tr712:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1064;
 tr3148:
@@ -23984,6 +24069,11 @@ tr719:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1065;
 tr714:
@@ -24078,6 +24168,11 @@ tr714:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	goto st1065;
 tr3150:
diff --git a/src/zscanner/scanner.c.t0 b/src/zscanner/scanner.c.t0
index 07ea919c1e03dd4098398171d074a4f6fb14bec2..804c73fd2f080223fa66c241866dd77fceb4a5d1 100644
--- a/src/zscanner/scanner.c.t0
+++ b/src/zscanner/scanner.c.t0
@@ -42,7 +42,7 @@
 /*!
  * \brief Empty function which is called if no callback function is specified.
  */
-static inline void noop(const zs_scanner_t *s)
+static inline void noop(zs_scanner_t *s)
 {
 	(void)s;
 }
@@ -4926,8 +4926,8 @@ zs_scanner_t* zs_scanner_create(const char     *file_name,
                                 const char     *origin,
                                 const uint16_t rclass,
                                 const uint32_t ttl,
-                                void (*process_record)(const zs_scanner_t *),
-                                void (*process_error)(const zs_scanner_t *),
+                                void (*process_record)(zs_scanner_t *),
+                                void (*process_error)(zs_scanner_t *),
                                 void *data)
 {
 	char settings[1024];
@@ -7155,6 +7155,11 @@ _match:
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 	break;
 		}
diff --git a/src/zscanner/scanner.h b/src/zscanner/scanner.h
index 622d428bf36d46cc83808a8ccfd23193ea832b7a..b55af21c6af7a76ce6a03ba60030865f20b16351 100644
--- a/src/zscanner/scanner.h
+++ b/src/zscanner/scanner.h
@@ -163,9 +163,9 @@ struct scanner {
 	uint32_t default_ttl;
 
 	/*! Callback function for correct zone record. */
-	void (*process_record)(const zs_scanner_t *);
+	void (*process_record)(zs_scanner_t *);
 	/*! Callback function for wrong situations. */
-	void (*process_error)(const zs_scanner_t *);
+	void (*process_error)(zs_scanner_t *);
 	/*! Arbitrary data useful inside callback functions. */
 	void *data;
 
@@ -237,8 +237,8 @@ zs_scanner_t* zs_scanner_create(const char     *file_name,
                                 const char     *origin,
                                 const uint16_t rclass,
                                 const uint32_t ttl,
-                                void (*process_record)(const zs_scanner_t *),
-                                void (*process_error)(const zs_scanner_t *),
+                                void (*process_record)(zs_scanner_t *),
+                                void (*process_error)(zs_scanner_t *),
                                 void *data);
 
 /*!
diff --git a/src/zscanner/scanner.rl b/src/zscanner/scanner.rl
index af38167116a3b6afde54b84a9caa210f80a67b5e..653848aba40666cd5ced82ffac31de91e7651976 100644
--- a/src/zscanner/scanner.rl
+++ b/src/zscanner/scanner.rl
@@ -41,7 +41,7 @@
 /*!
  * \brief Empty function which is called if no callback function is specified.
  */
-static inline void noop(const zs_scanner_t *s)
+static inline void noop(zs_scanner_t *s)
 {
 	(void)s;
 }
@@ -93,8 +93,8 @@ zs_scanner_t* zs_scanner_create(const char     *file_name,
                                 const char     *origin,
                                 const uint16_t rclass,
                                 const uint32_t ttl,
-                                void (*process_record)(const zs_scanner_t *),
-                                void (*process_error)(const zs_scanner_t *),
+                                void (*process_record)(zs_scanner_t *),
+                                void (*process_error)(zs_scanner_t *),
                                 void *data)
 {
 	char settings[1024];
diff --git a/src/zscanner/scanner_body.rl b/src/zscanner/scanner_body.rl
index 295e13d4d691991a3e03708ed1d4e77bc63e6d6b..31500f9c59d3e1cc6e1b883891c7d3c8249afb1d 100644
--- a/src/zscanner/scanner_body.rl
+++ b/src/zscanner/scanner_body.rl
@@ -1904,6 +1904,11 @@
 		s->r_data_length = rdata_tail - s->r_data;
 
 		s->process_record(s);
+
+		// Stop scanner if required.
+		if (s->stop == true) {
+			return -1;
+		}
 	}
 
 	# Resource record.
diff --git a/src/zscanner/tests/processing.c b/src/zscanner/tests/processing.c
index 2a8ea7b04cba618ba9ee0d52288c4a0cf1354fc6..cd7e30855c09db659f7d08425c642448434d9f42 100644
--- a/src/zscanner/tests/processing.c
+++ b/src/zscanner/tests/processing.c
@@ -39,7 +39,7 @@ static void print_wire_dname(const uint8_t *dname, uint32_t dname_length)
 	}
 }
 
-void debug_process_error(const zs_scanner_t *s)
+void debug_process_error(zs_scanner_t *s)
 {
 	if (s->stop == true) {
 		printf("LINE(%03"PRIu64") ERROR(%s) FILE(%s) NEAR(%s)\n",
@@ -57,7 +57,7 @@ void debug_process_error(const zs_scanner_t *s)
 	fflush(stdout);
 }
 
-void debug_process_record(const zs_scanner_t *s)
+void debug_process_record(zs_scanner_t *s)
 {
 	uint32_t i;
 
@@ -84,7 +84,7 @@ void debug_process_record(const zs_scanner_t *s)
 	fflush(stdout);
 }
 
-void test_process_error(const zs_scanner_t *s)
+void test_process_error(zs_scanner_t *s)
 {
 	if (s->stop == true) {
 		printf("ERROR=%s\n%s", zs_errorname(s->error_code), separator);
@@ -94,7 +94,7 @@ void test_process_error(const zs_scanner_t *s)
 	fflush(stdout);
 }
 
-void test_process_record(const zs_scanner_t *s)
+void test_process_record(zs_scanner_t *s)
 {
 	uint32_t i;
 
diff --git a/src/zscanner/tests/processing.h b/src/zscanner/tests/processing.h
index 5a6e185b161328c4b2159297054b0136b76e0987..4d2a88eb1e67bb3571f5bcf72b3df273f03c79ff 100644
--- a/src/zscanner/tests/processing.h
+++ b/src/zscanner/tests/processing.h
@@ -29,13 +29,13 @@
 
 #include "zscanner/scanner.h"
 
-void debug_process_error(const zs_scanner_t *scanner);
+void debug_process_error(zs_scanner_t *scanner);
 
-void debug_process_record(const zs_scanner_t *scanner);
+void debug_process_record(zs_scanner_t *scanner);
 
-void test_process_error(const zs_scanner_t *scanner);
+void test_process_error(zs_scanner_t *scanner);
 
-void test_process_record(const zs_scanner_t *scanner);
+void test_process_record(zs_scanner_t *scanner);
 
 #endif // _ZSCANNER__PROCESSING_H_
 
diff --git a/tests-extra/tests/chaos/ident/test.py b/tests-extra/tests/chaos/ident/test.py
index 7ec288e91b7207be20d92653a921f2755bfc59b3..2f073ddabdde692ef2cf5d381b522ef7514da3a2 100644
--- a/tests-extra/tests/chaos/ident/test.py
+++ b/tests-extra/tests/chaos/ident/test.py
@@ -3,7 +3,6 @@
 '''Test for server identification over CH/TXT'''
 
 from dnstest.test import Test
-import socket
 
 t = Test()
 
@@ -25,7 +24,7 @@ resp.check('"' + name + '"')
 
 # 2) FQDN hostname.
 resp = server2.dig("id.server", "TXT", "CH")
-resp.check(socket.gethostname())
+resp.check(t.hostname)
 
 # 3) Explicitly disabled.
 resp = server3.dig("id.server", "TXT", "CH")
diff --git a/tests-extra/tests/ddns/ttl/test.py b/tests-extra/tests/ddns/ttl/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..8dc5c462f052cc78980bb1663ff57f8fd79656b6
--- /dev/null
+++ b/tests-extra/tests/ddns/ttl/test.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+
+'''TTL mismatch test'''
+
+from dnstest.utils import *
+from dnstest.test import Test
+
+t = Test()
+
+zone = t.zone("example.com.")
+
+master = t.server("knot")
+t.link(zone, master, ddns=True)
+
+t.start()
+
+# Add new RR with different TTL to a RRSet that is already in the zone
+# The UPDATE should be REFUSED
+
+check_log("Add RR with different TTL")
+up = master.update(zone)
+up.add("mail.example.com.", 1000, "A", "1.2.3.4")
+up.send("REFUSED")
+resp = master.dig("mail.example.com.", "A")
+resp.check_record(section="answer", rtype="A", ttl="3600", rdata="192.0.2.3")
+resp.check_record(section="answer", rtype="A", nordata="1.2.3.4")
+
+# Try to add two RRs belonging to one RRSet, but with different TTLs
+# The UPDATE should be REFUSED
+# This also tests rollback in case of addition
+
+check_log("Add RRSet with incoherent TTLs")
+up = master.update(zone)
+up.add("test.example.com.", 1000, "A", "1.2.3.4")
+up.add("test.example.com.", 2000, "A", "2.3.4.5")
+up.send("REFUSED")
+resp = master.dig("test.example.com.", "A")
+resp.check(rcode="NXDOMAIN")
+
+# First, delete RRSet already in zone, then add new RR with different TTL
+# The UPDATE should be accepted and the new RR should be present in the zone
+
+check_log("Delete RRSet from zone + add new RR with different TTL instead")
+up = master.update(zone)
+up.delete("mail.example.com.", "A")
+up.add("mail.example.com.", 1000, "A", "1.2.3.4")
+up.send("NOERROR")
+resp = master.dig("mail.example.com.", "ANY")
+resp.check_record(section="answer", rtype="A", ttl="1000", rdata="1.2.3.4")
+resp.check_record(section="answer", rtype="A", nordata="192.0.2.3")
+resp.check_record(section="answer", rtype="AAAA", ttl="3600", rdata="2001:db8::3")
+
+# Some prerequisities for the next test
+up = master.update(zone)
+up.add("test2.example.com.", 3600, "A", "1.2.3.4")
+up.add("test2.example.com.", 3600, "A", "2.3.4.5")
+up.send("NOERROR")
+
+# Delete one of RRs in a zone RRSet, then add new RR with different TTL
+# The UPDATE should be REFUSED
+# This also tests rollback in case of deletion
+
+check_log("Delete one RR from a RRSet + try to add RR with different TTL instead")
+up = master.update(zone)
+up.delete("test2.example.com.", "A", "1.2.3.4")
+up.add("test2.example.com.", 1000, "A", "3.4.5.6")
+up.send("REFUSED")
+resp = master.dig("test2.example.com.", "A")
+resp.check_record(section="answer", rtype="A", ttl="3600", rdata="1.2.3.4")
+resp.check_record(section="answer", rtype="A", nordata="3.4.5.6")
+
+# Test for rollback - a lot of changes and a invalid RR
+
+check_log("Rollback test: a lot of changes")
+up = master.update(zone)
+# Add to existing RRSet
+up.add("test2.example.com.", 3600 , "A", "3.4.5.6")
+up.add("test2.example.com.", 3600 , "A", "3.4.5.7")
+# Add new RRSet to an existing node
+up.add("test2.example.com.", 1000, "MX", "10 somewhere.com.");
+# Add new node
+up.add("test3.example.com.", 2000, "A", "5.6.7.8")
+# Remove specific RR
+up.delete("test2.example.com.", "A", "1.2.3.4")
+# Remove whole RRSet
+up.delete("mail.example.com.", "A")
+# Remove whole node
+up.delete("dns1.example.com.", "ANY")
+# Add invalid RR so that the UPDATE is refused
+up.add("test2.example.com.", 1000, "A", "7.8.9.0")
+up.send("REFUSED")
+
+resp = master.dig("test2.example.com.", "ANY")
+resp.check_record(section="answer", rtype="A", ttl="3600", rdata="1.2.3.4")
+resp.check_record(section="answer", rtype="A", ttl="3600", rdata="2.3.4.5")
+resp.check_record(section="answer", rtype="MX", nordata="10 somewhere.com.")
+resp.check_record(section="answer", rtype="A", nordata="7.8.9.0")
+
+resp = master.dig("test3.example.com", "ANY")
+resp.check(rcode="NXDOMAIN")
+
+resp = master.dig("mail.example.com.", "ANY")
+resp.check_record(section="answer", rtype="A", ttl="1000", rdata="1.2.3.4")
+resp.check_record(section="answer", rtype="AAAA", ttl="3600", rdata="2001:db8::3")
+
+resp = master.dig("dns1.example.com.", "ANY")
+resp.check_record(section="answer", rtype="A", ttl="3600", rdata="192.0.2.1")
+resp.check_record(section="answer", rtype="AAAA", ttl="3600", rdata="2001:db8::1")
+
+t.end()
+
diff --git a/tests-extra/tests/edns/nsid/test.py b/tests-extra/tests/edns/nsid/test.py
index d55b37dfc8d38d44040c8eb9dd54fae8f66adc12..cd5e0897909849fdf432ec1377c2bb355ebd19c0 100644
--- a/tests-extra/tests/edns/nsid/test.py
+++ b/tests-extra/tests/edns/nsid/test.py
@@ -3,7 +3,6 @@
 '''Test for EDNS0/NSID identification'''
 
 from dnstest.test import Test
-import socket
 
 t = Test()
 
@@ -30,7 +29,7 @@ resp.check_edns(nsid=name)
 
 # 2) FQDN hostname.
 resp = server2.dig("example.com", "SOA", nsid=True)
-resp.check_edns(nsid=socket.gethostname())
+resp.check_edns(nsid=t.hostname)
 
 # 3) Explicitly disabled.
 resp = server3.dig("example.com", "SOA", nsid=True)
diff --git a/tests-extra/tests/ixfr/from_differences/06_add_rm_delegation/example.com.zone b/tests-extra/tests/ixfr/from_differences/06_add_rm_delegation/example.com.zone
new file mode 100644
index 0000000000000000000000000000000000000000..8a1af1e3ce59d11842d931232be145137267007d
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/06_add_rm_delegation/example.com.zone
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@	SOA	dns1 hostmaster 2010111201 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+	MX	10 mail
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+mail	A	192.0.2.3
+	AAAA	2001:DB8::3
diff --git a/tests-extra/tests/ixfr/from_differences/06_add_rm_delegation/example.com.zone.1 b/tests-extra/tests/ixfr/from_differences/06_add_rm_delegation/example.com.zone.1
new file mode 100644
index 0000000000000000000000000000000000000000..b17d89d54d7287d441fea7dad007331a8a349a13
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/06_add_rm_delegation/example.com.zone.1
@@ -0,0 +1,19 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@	SOA	dns1 hostmaster 2010111202 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+	MX	10 mail
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+mail	A	192.0.2.3
+	AAAA	2001:DB8::3
+
+deleg	NS	n.deleg
+n.deleg	A	1.2.3.4
diff --git a/tests-extra/tests/ixfr/from_differences/06_add_rm_delegation/example.com.zone.2 b/tests-extra/tests/ixfr/from_differences/06_add_rm_delegation/example.com.zone.2
new file mode 100644
index 0000000000000000000000000000000000000000..02b1436de6ea275b824bc046b5f3c92fe8f9f816
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/06_add_rm_delegation/example.com.zone.2
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@	SOA	dns1 hostmaster 2010111203 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+	MX	10 mail
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+mail	A	192.0.2.3
+	AAAA	2001:DB8::3
diff --git a/tests-extra/tests/ixfr/from_differences/06_add_rm_delegation/step.py b/tests-extra/tests/ixfr/from_differences/06_add_rm_delegation/step.py
new file mode 100644
index 0000000000000000000000000000000000000000..830c2cdafe857ad037d25b83d88794b840f39fbe
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/06_add_rm_delegation/step.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+
+'''Add and remove zone delegation.'''
+
+def run(i):
+    i.test.start()
+
+    i.check()
+    i.check_rec("deleg", "NS", rcode="NXDOMAIN")
+    i.check_rec("n.deleg", "A", rcode="NXDOMAIN")
+
+    i.check(1)
+    i.check_rec("deleg", "NS", rcode="NOERROR", nordata="n.deleg.example.com.")
+    i.check_rec("n.deleg", "A", rcode="NOERROR", nordata="1.2.3.4")
+
+    i.check(2)
+    i.check_rec("deleg", "NS", rcode="NXDOMAIN")
+    i.check_rec("n.deleg", "A", rcode="NXDOMAIN")
+
+    i.test.end()
diff --git a/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/example.com.zone b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/example.com.zone
new file mode 100644
index 0000000000000000000000000000000000000000..50847b6f471146984856d76e7d812c2aa46817d6
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/example.com.zone
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@	SOA	dns1 hostmaster 1 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+	MX	10 mail
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+mail	A	192.0.2.3
+	AAAA	2001:DB8::3
diff --git a/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/example.com.zone.1 b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/example.com.zone.1
new file mode 100644
index 0000000000000000000000000000000000000000..04a7405b02440b7d3036e7d79ebb263da2606812
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/example.com.zone.1
@@ -0,0 +1,33 @@
+; File written on Thu Apr 24 15:36:15 2014
+; dnssec_signzone version 9.9.3-rpz2+rl.13214.22-P2-Ubuntu-1:9.9.3.dfsg.P2-4ubuntu1.1
+example.com.				      3600 IN SOA	dns1.example.com. hostmaster.example.com. 2 10800 3600 1209600 7200
+example.com.				      3600 IN RRSIG	SOA 5 2 3600 20500101000000 20140424123615 48270 example.com. gQGAbBtUeCMVS/3vvWI7wcAt/Bp0vB8G0Bn8D0NxEQli66pWACaYWNYF 6zvsGq2pXdIJ+7GwvYsW6bEZWdWK4JwycT1ttagZEPGgpvJbZ2t+q7QM OeiwsnQhIdkLe+VElnWKOQvlwZ4lcJB3ohJpUiPGIGX7PMOb1WExwgK7 vuk=
+example.com.				      3600 IN NS	dns1.example.com.
+example.com.				      3600 IN NS	dns2.example.com.
+example.com.				      3600 IN RRSIG	NS 5 2 3600 20500101000000 20140424123615 48270 example.com. kf9lGUN7Q7U9IXgioaXFVc4R2neyl8vEZVhr6oH0OAS+KcBp3mdkGril uyHh8TzzaU3DKUVnzZ3VDh2UXHDEHm2Eford50uv6qwUNinsihz27eDs YoWeNb9GEJHBQuiqJVnTtus3Ky7/Zy6ZW0cHsSew30ZDW1hEhkCvxJsg i/w=
+example.com.				      3600 IN MX	10 mail.example.com.
+example.com.				      3600 IN RRSIG	MX 5 2 3600 20500101000000 20140424123615 48270 example.com. PqZSV2LBI/qZUQIHCiwyNWPbll35kDSvXp//663PIqYWRatgapgsSz03 xwcbELsDLExyWQLKHF5X3tSAnLM2OJRSjqIUxE38igwOLHUgHt80X7wW vTlneO03RlvueawqpUTh28IkV2XeY7ce8yt26Wn5EgxJAgsZixQhGCgh R9s=
+example.com.				      7200 IN NSEC	dns1.example.com. NS SOA MX RRSIG NSEC DNSKEY
+example.com.				      7200 IN RRSIG	NSEC 5 2 7200 20500101000000 20140424123615 48270 example.com. UiaiqUSvkWJRESjo3swSxG2RnvPOSpuI1AwGD+ioBAAuc7PfjtSl1fsw jr3WCLzkbWQ/5EtUyMSWcBRzhJ+Lwf3jWD63HoxMH2eu1+3kCDv0zuKX /vx1edAMkj3WFYaJeyG63uU8d0Ki67HF2XXsFVjHoasTdAtByGTP/EJh 9RA=
+example.com.				      3600 IN DNSKEY	256 3 5 AwEAAZ6S/hD++6IvF+3J+SsG3gAPAzkvsoCfmrlbW/O2Vl2lE41KcUi2 gnanCQnd2c626UMu8HUP/LChnshuryyI3OIVqPl5tkTO6lQIsI0zrgTg X0W+qrZy2ScbJzX3Q8DX2Rc6Fvv6FrH3STjEbTRG3/S2S3Fjej/9hHfA ZZkhg80T
+example.com.				      3600 IN DNSKEY	257 3 5 AwEAAbJGcGQXbTcHfb8iHLl6vVcl9kIqSkATG3h/ea77o7Dvb2Se77Bd wscYTTsydX0s6LEO6cfaknupcYRoOY5lRFHPBOT87dyA7+REmdM2yEZB dWDkXJi6px0k30Md6aY1t1dHLOj3Vgmmf9nGgkCH4rsx3lpsG+GGz0gb 8mqDKxNav4iB9muqnQhb6ar1KEHT23bqrbyq+w8EnOd7sjrGE6Jc46Q+ qH1ppIs2MupDEtYSJvdfEzF+FIo/ET5xKjJsdSf0RlTGFyCQYCHcQOxJ 5vvaczhrvg6rLPdYBD4vpUlvP6JaBrEzSVu1JKewloFCD472bLsLuMBd rew16iFvvik=
+example.com.				      3600 IN RRSIG	DNSKEY 5 2 3600 20500101000000 20140424123615 15742 example.com. qhDj7xaAlrfxufWAZpg6123znruaVYeTIVE1QCpjUmGUYl8Q3B8EEogl J6RRMuG6f3qMr9VO9wsNyG5vbNvHywdto9S11WrLK9w93ECvXJd6/Sx5 0cdnOOM7HQCyp7r1+OjreDOq09knLjz80hVsA19dtTax0rBW8pg6v7Eo JKzzPw/Yb8G/HCkKtjgObnhYEuQ5U+3WVopgIFONlBm2zjyEJHFSxFEo o4SMXrkcScOPGAI3i9lHkkzdOaVN2v+3h6JjB9BrtOuo3IxpOKBq3ZiT QMKH3Ht2SCbLwwg3AHtmQbj3w31V3kOIw/2AFzfJ7PSPifBC+yNps1AN U9WjxQ==
+example.com.				      3600 IN RRSIG	DNSKEY 5 2 3600 20500101000000 20140424123615 48270 example.com. Cmeefl4s85b2nWTF5Dvkehe52CnrJWsVaZ2mYzlGfxwlAwOSrrdAJ11p DZgvpKJO5csnj8wrM47s7Rpab+X/RvssoTa99d/1jNSwV9eNqL5bN3t9 55XW6NDZNxnWWo2hYWdm424S25f9UISW6/IMYJfAqw89KfB3gLysCOBC wLY=
+dns2.example.com.			      3600 IN A		192.0.2.2
+dns2.example.com.			      3600 IN RRSIG	A 5 3 3600 20500101000000 20140424123615 48270 example.com. l9QHTA3h6aGJ20bLkwMq+oIkir/6PJFZeAf8E4TpIDj5LvhCB6cDCF54 L4LsYI+whCI6tTKNblI8oEEPQX5pS73qCpmokZj91p1qtnfJZB7rQ4dq vrr58qMu/3QkIXwgbunGShiH1XDxvAQ3KKNjbKd6SrkDEvD2NwjOvjDG laY=
+dns2.example.com.			      3600 IN AAAA	2001:db8::2
+dns2.example.com.			      3600 IN RRSIG	AAAA 5 3 3600 20500101000000 20140424123615 48270 example.com. Vezum4H/yCj7V9TsUwF2Es4YRC+JhpWe0i8g24ivtAY4W6g+0rIX0Eeg PP1bI8/Flcn6OGVJScwBLYCt68RldFaBkmZzUTwkvrBU07qUFPK3e8bW yVVYyBJRps0DElhiycxS+EM4NXPo3ZlpbfFLGAsERhuOOZJTCoXop3ME 530=
+dns2.example.com.			      7200 IN NSEC	mail.example.com. A AAAA RRSIG NSEC
+dns2.example.com.			      7200 IN RRSIG	NSEC 5 3 7200 20500101000000 20140424123615 48270 example.com. LYuUHK1flf+YAnyufmTE2C/sbBQkPeirKuU6G4ZYQAZEkKtbj69ai33N O/FvSZJk3CuVXZPPepDEkDgqfUYFLovnA9LWNyA+M+DwLTqlym6cheDo NJDyu1Tlk8S8RviajExkGzNgFrcH3Y7ir1WV13KE4tyDcqZttQu0/GCa dn0=
+dns1.example.com.			      3600 IN A		192.0.2.1
+dns1.example.com.			      3600 IN RRSIG	A 5 3 3600 20500101000000 20140424123615 48270 example.com. geHqQ+BblAWCUIsrU2tmhTQB7Aq4c7wS9A0XrKI/vNfe4KTx7fohByR4 yZ0vqyRkcrCOdJXCCSqGNHoiw9aSVOlG7Wf0ZQjSbMDL5qyX72IbbHId 5XfUVf9l6ioAFu0j3aq6iJnVdNTYAwbVrwE2+bUVqkFRshkddLHm8LVb a90=
+dns1.example.com.			      3600 IN AAAA	2001:db8::1
+dns1.example.com.			      3600 IN RRSIG	AAAA 5 3 3600 20500101000000 20140424123615 48270 example.com. SjVTNc9/haQy7vLcmPfZePxgkNEiiBcTBIN+v42O3ZStW99tfBv7vGOp RJaJRFRuofUXE8qgRB/5nZD3Qcfu3a0auGUQnPQlshHZcIK0i7V9R3Oz Id/p/daQ+LNioh4Pwgn42Gs/yjxoEQSyKQpdq1G0l6nVEcehrNPmTy9l cUo=
+dns1.example.com.			      7200 IN NSEC	dns2.example.com. A AAAA RRSIG NSEC
+dns1.example.com.			      7200 IN RRSIG	NSEC 5 3 7200 20500101000000 20140424123615 48270 example.com. VKhFCmX5VWwjMxFl+//VI/Te8e6QnDKDKmu342y0KXojqJAXVGjwJR6T B0VwHk/cp2VfU4P/nUeD8TZdHAXTlsqntYBezYCAyZ6EDIBnIxFeIqPa SJlv2br5y6LEfxaqc+ulKuWebcHNG2NWGu4hlcD7/9gQ8G8g6fsH1hnU kJY=
+mail.example.com.			      3600 IN A		192.0.2.3
+mail.example.com.			      3600 IN RRSIG	A 5 3 3600 20500101000000 20140424123615 48270 example.com. TU/fAAKwjoRwOruCjI225l8wQ4I1HabvR4nyUB86N4a9O5Y4RVVnCx7h uFGZiTW9uiaFple1393vKbTUWgzLXlorIo5YkLmiGezSVFf0nCUXRu1Y pjqi2FCS3iSPT7E3S+jyhxvhNR5Tqy/LCTnlXyy+M0RdijfAGkHcK19Y bjI=
+mail.example.com.			      3600 IN AAAA	2001:db8::3
+mail.example.com.			      3600 IN RRSIG	AAAA 5 3 3600 20500101000000 20140424123615 48270 example.com. k3VAHqhLGLyujQPLivud2BZsDUD4jra5RJgSb0G1j9uWCmkZpjRkyn0h HsZlZYD5RnFtxBf992c3pU/+xcTZJRcW2UOJxllJ1xeCPxxUmZwI5Cse lgRSGLelCtsJKaU3K/1jkDAStJ6KI2b1c4Hcnw7Rhb6T/zzRQNz3X9vJ WWo=
+mail.example.com.			      7200 IN NSEC	example.com. A AAAA RRSIG NSEC
+mail.example.com.			      7200 IN RRSIG	NSEC 5 3 7200 20500101000000 20140424123615 48270 example.com. iULIfXN4JjJlXFsBBLgoi3q2Dfopn+J3wZbgYmw3JguUFF1rZKWNhlQH BAhOUyBk0nCFcrp1YsidG4JMKICF4DTza7xBPODcp/7pIXdm65Mjrtop yS/pfXBeROePsYKqwCVOGDPgb2PUZCqSFNeCbluDGMGC/mn5mDfCN5Gx 8HQ=
diff --git a/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/example.com.zone.2 b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/example.com.zone.2
new file mode 100644
index 0000000000000000000000000000000000000000..1284bc83801432aa89f5aeb6c947e288a7317dfd
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/example.com.zone.2
@@ -0,0 +1,35 @@
+; File written on Thu Apr 24 15:36:15 2014
+; dnssec_signzone version 9.9.3-rpz2+rl.13214.22-P2-Ubuntu-1:9.9.3.dfsg.P2-4ubuntu1.1
+example.com.				      3600 IN SOA	dns1.example.com. hostmaster.example.com. 3 10800 3600 1209600 7200
+example.com.				      3600 IN RRSIG	SOA 7 2 3600 20500101000000 20140424123615 13445 example.com. QVisesjkna1TQg84g9jqKaiybtqeDR3KYuSQS02pIKqvFpun7Uw9Qgqd f6Lb+EqsAAAqoKTIrSjEDJokOdybR1ke3FSv4RyrTRFJjIrsjUo1M1PE NPtONcT07dhhg9tO6vlvLns+Iy6BDnZ8WlT9Uwn6XiZzSrER5hSUAIBV OTE=
+example.com.				      3600 IN NS	dns1.example.com.
+example.com.				      3600 IN NS	dns2.example.com.
+example.com.				      3600 IN RRSIG	NS 7 2 3600 20500101000000 20140424123615 13445 example.com. TmYITTUgzVKGWhdOv1mks3Fvr18IB367KHgx8dGUON0Q89cVp8rM6Kcm GuF/I/Y9pa9xOD/U/5BCuEFVVNRiRxFCK/ILHR0wX099zMktACkDGp3I FVtvKzK7BubrQDDTWwTdbCGUlS24SPGoWJ2yzxy8NwLxlG0WM77bezhh 5Dk=
+example.com.				      3600 IN MX	10 mail.example.com.
+example.com.				      3600 IN RRSIG	MX 7 2 3600 20500101000000 20140424123615 13445 example.com. MNGw/1V4n3lDxijjiJcrkkZ+JdlvbcekNjrWQ4D8uxsy4H6w8YMvj6nm 2zNRixjJMgFl7dp679XfIpYxQG3nh+ck5WsdP2orHqGGGfb/m84K8I3r wv8wUXPiNnE4Ow4XryXdGIYh/BSAS5Ao0s0sBw8wmp2Xqrd0W/TwQkwF qcQ=
+example.com.				      3600 IN DNSKEY	256 3 7 AwEAAd1rM20j3Y/fMAPdLuPLtDMhp987OKadgj8PihVNK7+tnTkxgSxY iRXnTGguHPmabF8iCBm9lHMyDl0L1R3OiWIhbCeMpzK/Tzb5DWBy2eYn 7zSxkfJJj09kQApVrgTlCFhB6MP3hZLm54vMyaNTJ4PKuvNSEyLFRSmx 8gIRdrMl
+example.com.				      3600 IN DNSKEY	257 3 7 AwEAAey7ObNwBcGmTIvspCWlS4xmOdqzZJ5JyYJXHXyxzrQf8lxB56Xc YXvWQEBjpYC7gAHr4QFKdvnGjnbYUNBFDvktF9inm3aSxC0NiuUHMS/R jmCJaiQrHZqCprY8kngEx5RIZ69sw61lFYX3O5b1TloG3b1GlgWCsspf ff5/qStH2HXFAxVUrCx3mkCDapCnz3hHkvbtKqWYH77cLhgR2XM8y6Of ix2M0jNoPzMe81UtvfdgQ5ad32CkpwRZt5hpSnU5G2737KHgfjyGSbZC SoOrCcQVhl+CF3lLwVLejFxz5VWMd7xUueqwewSdVQtoNHVzjhbPcpV/ J2HOiPxX0sM=
+example.com.				      3600 IN RRSIG	DNSKEY 7 2 3600 20500101000000 20140424123615 13445 example.com. DFU5tG1lCbeHg6c4phyyqA+PIIlQf6Rf13uriDr6sp4EDaR31uE/MrZA O0CP4bI24VfKIakE0nJ4gtZNWSZQgiaOAoCk7b/EVIuVT+S9BnWM7nBB ddxguKq2WW1hZJWa6txUSwcrxFF+hatnCIfm+g8qg6cLHdoLGQSIqMvU QFE=
+example.com.				      3600 IN RRSIG	DNSKEY 7 2 3600 20500101000000 20140424123615 56076 example.com. mkzQXYr/sgk+PkfBJe+91TQrRsLNGdiKO6XIKb/nVSncqyjeCWhMBMcF FS/EPWkBiXf2iffVyjl1e/8Yqm5knFx2P4MK9CuUhYUC5c7kLgnkwcta WvOW+WUOgUq5B5pfGeWvveJqng7JLipHEHg0MRRSKJoRFNhuMPggIEHV /NZ1jTbCzrY+xZekZUzKfEJdTOnCPCixaPuzF4eyQDz4cNRWsn9LVEJQ 48vPdKFP25nke+NViwchZQFBn64UUieBYgvPIGU20QyvanHy6L0QVIdG LNzKlXvbBkdCeKkN/IXfYWDXNV3Z/OT41LIm6i3mVs4oi2tJbS4YXjBM +4BSvg==
+example.com.				      0	IN NSEC3PARAM	1 0 10 DEADBEEF
+example.com.				      0	IN RRSIG	NSEC3PARAM 7 2 0 20500101000000 20140424123615 13445 example.com. bcJljy+HkAyBjEaskUocFfKJrnyCFbVDvJhov7j1RlvqR2Ez1L4CqYhG R1GWxegYZy3xg6Dez0WmX4Q/N6PSm8N7mQMOzeHJYK6WhpW5jSiG+S5v 5yXCO/fhrifNGCDRW9cs7rGCeo6HA9j2WtrPxEP6f7rjXLDFpw5H2qA0 Dvc=
+dns1.example.com.			      3600 IN A		192.0.2.1
+dns1.example.com.			      3600 IN RRSIG	A 7 3 3600 20500101000000 20140424123615 13445 example.com. iScDKbY/Rljo6xeval4GSXy7RudSqA7EddpLmz7GDDq3gP/EYnNeAFgT eiSqibV8yXdGSHWFNtccSEa5yxpgsD0RJA7Zn2cy4PEKN9igXWFkScTs yAbBaUXI59j0odf3ugJ+1zwvu27MlS7MC+bCTsT6NcpogFolY8ncd+Yg MWg=
+dns1.example.com.			      3600 IN AAAA	2001:db8::1
+dns1.example.com.			      3600 IN RRSIG	AAAA 7 3 3600 20500101000000 20140424123615 13445 example.com. zqfpY0fh9CWb1t5b7+tRl7VBrZTfN4B2fUkT5jmNKDlGN91KK+aYB28C iBAFzHgjAh03H1oiIePjC8XTHoodDm/JufuIa5jCvjtsj+kQ9appaoYq +FuZqjj1bh5sl57UuJplEEunxYpi5w7D1r+TOHxl00uWSOBimAxCu4q9 fWM=
+dns2.example.com.			      3600 IN A		192.0.2.2
+dns2.example.com.			      3600 IN RRSIG	A 7 3 3600 20500101000000 20140424123615 13445 example.com. kKfg8ozccGwbXupYMr57icdnbFc496P2aR0w9U/Ys/WfbfKbvR8VUZKT qt9loHd1aW/LqqkPMXJpIhI97vPG+uQ/gb51OkcmBQxV3QwPQm7VybC+ eov+JTTGq/n+4UtMTd1aIN7IHtFsn8wuNB90obthM98HBh417csOJc+G sGs=
+dns2.example.com.			      3600 IN AAAA	2001:db8::2
+dns2.example.com.			      3600 IN RRSIG	AAAA 7 3 3600 20500101000000 20140424123615 13445 example.com. Dk+7+1s1Qzk5XVobZ4i8LvugMC+a+4TaWNrNuunI5OPAjJy4JG43A2h2 NZaHRcK0Fr0vW7JvYn3grdiciLaY9lWhZo6ABUE3J1CvzMWWFlAe8j0G v83YwQwXqZEhYt8HivbSZepdBRYlhruY0Spgjzj/0KtxM7f/9JhFkTlX PgA=
+8A5V7AUAVJA88G1DP716TS1HLVBCNJO7.example.com. 7200 IN NSEC3	1 0 10 DEADBEEF GR0GCFJEUNHRE7346DGPJJ5APHRUAT49 NS SOA MX RRSIG DNSKEY NSEC3PARAM
+8A5V7AUAVJA88G1DP716TS1HLVBCNJO7.example.com. 7200 IN RRSIG	NSEC3 7 3 7200 20500101000000 20140424123615 13445 example.com. Fj+2ZPQG43ExzS3eYio6jRUUQbJegtFzqpf/2PAjWDRy2+P7/58XbeGp A6EavaxUbD7zkahGo1gs/84CeACpTeTAAG8HY5hWnQi0E6QycThww/w1 YLU93Ih3al580KpgJ3+eeNL7yudsnr5+w9/XBMR5BuL6aRjCuCrOKrzY r9c=
+GR0GCFJEUNHRE7346DGPJJ5APHRUAT49.example.com. 7200 IN NSEC3	1 0 10 DEADBEEF PBHK2DUPRJPKJABURDKKDCMLII36OM3J A AAAA RRSIG
+GR0GCFJEUNHRE7346DGPJJ5APHRUAT49.example.com. 7200 IN RRSIG	NSEC3 7 3 7200 20500101000000 20140424123615 13445 example.com. L8BxH0+jf+0yzZ4IKkLeEtd+EEj5aC2afTnXHjrj6LMdfYyTcMM6gtzE fd47u60Ybe8E2GE0YC4PrQvBO9iLhB+3gs80zo+rK+ts9Mc9jwzGBqcP 5ZPjbkXjoKfHR0f0faERG6Ve7GOENon4WSh3t8k9OVlVRAhezNhPRrF4 J8c=
+mail.example.com.			      3600 IN A		192.0.2.3
+mail.example.com.			      3600 IN RRSIG	A 7 3 3600 20500101000000 20140424123615 13445 example.com. IFAYWzpCj4rCxrtpojBAypklZe9Zvc67bNauwn9mSLvBew3UM0Nf+4c/ qJFUQLOkOnbUICRcw3sBBWl6ksVUnNcgw3cwDLnDhSeq3GnTpbTh6IxG 0szpCXuQlFw0zi67xL77iJO+jc9u/d1iBt/0KjKL7S6F/fV+Pm/Z6QF2 xTg=
+mail.example.com.			      3600 IN AAAA	2001:db8::3
+mail.example.com.			      3600 IN RRSIG	AAAA 7 3 3600 20500101000000 20140424123615 13445 example.com. wf9usf+KohXXxGpzX10STp03gM2edf+NOa0qs9Co3uSg3udO35tH5+4K +JcYPep3bpU6bAO6xfUlE/6u/ZbewpQ3nwDeWTgTQmIho7thfacKl+Bb PHQxUXuV8N/+4ATLMiW1+Bf/6F397hzNHh8vg50uIa1h4cxh0WicGb4m Dr8=
+PBHK2DUPRJPKJABURDKKDCMLII36OM3J.example.com. 7200 IN NSEC3	1 0 10 DEADBEEF 46BRGPLB7MVA8KQDD8P2MORSKF2OMQOH A AAAA RRSIG
+PBHK2DUPRJPKJABURDKKDCMLII36OM3J.example.com. 7200 IN RRSIG	NSEC3 7 3 7200 20500101000000 20140424123615 13445 example.com. OUn0Hf+Ppo3uA+ycJpTRK8TDKwxnmwMKwuF5cMSqTH3B6b8pSCOcB2pl V9S2l5UbP6gXgLzz1wbJaQHgGD3efLk0a5D2oks5SSbNcc4lM2rpEoFU MY1Ulwh4qSDe0FskzQeRpnOn1gFoBeTyDzWvoqXV9Fdt90IzKe36y+yg esg=
+46BRGPLB7MVA8KQDD8P2MORSKF2OMQOH.example.com. 7200 IN NSEC3	1 0 10 DEADBEEF 8A5V7AUAVJA88G1DP716TS1HLVBCNJO7 A AAAA RRSIG
+46BRGPLB7MVA8KQDD8P2MORSKF2OMQOH.example.com. 7200 IN RRSIG	NSEC3 7 3 7200 20500101000000 20140424123615 13445 example.com. bghOeySB6Zw/EoDCBRE2DnpIGTj0CtrqQ24LZx6Po5aZKCOUp83AGtcR +erRYpsU1xSOlXddKMSnA9n9pdJhw7DAWyW6FfDXsZn/QFHT1PCeTepL 6uDLJ4mW8PZF0Mzi5Xx36hyVtY47n7G56NPysVALmjukKpMKQDL61ZEa T60=
diff --git a/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/example.com.zone.3 b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/example.com.zone.3
new file mode 100644
index 0000000000000000000000000000000000000000..4a35c30b71eec527756811aa287ce88e6b86aebd
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/example.com.zone.3
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@	SOA	dns1 hostmaster 4 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+	MX	10 mail
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+mail	A	192.0.2.3
+	AAAA	2001:DB8::3
diff --git a/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/step.py b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/step.py
new file mode 100644
index 0000000000000000000000000000000000000000..5062be40689fa7a86cf0a8296512a14ed0516b09
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/step.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python3
+
+'''Unsigned -> signed(NSEC) -> signed(NSEC3) -> unsigned transitions.'''
+
+def run(i):
+    i.test.start()
+
+    i.check()
+
+    i.check(1)
+
+    i.check(2)
+
+    i.check(3)
+
+    i.test.end()
diff --git a/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/update/example.com.zone.template b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/update/example.com.zone.template
new file mode 100644
index 0000000000000000000000000000000000000000..29c6f4b441dfa62653103283679f681492420e2e
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/update/example.com.zone.template
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@	SOA	dns1 hostmaster #SERIAL# 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+	MX	10 mail
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+mail	A	192.0.2.3
+	AAAA	2001:DB8::3
diff --git a/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/update/update.sh b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/update/update.sh
new file mode 100755
index 0000000000000000000000000000000000000000..6aac48cc67cb23747a786833c882dc41e61e6790
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/07_none_nsec_nsec3_none/update/update.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+SIGN="../../../../../tools/zone_sign.sh"
+TPL="./example.com.zone.template"
+ZFIN="../example.com.zone.in"
+ZF="../example.com.zone"
+
+# 0.
+SERIAL=1
+sed "s/#SERIAL#/${SERIAL}/" $TPL > $ZFIN
+mv $ZFIN $ZF
+
+# 1.
+SERIAL=2
+sed "s/#SERIAL#/${SERIAL}/" $TPL > $ZFIN
+export BASEDIR=`mktemp -d "/tmp/zone_sign-XXX"`
+$SIGN example.com. $ZFIN nsec
+mv $ZFIN.signed $ZF.1
+
+# 2.
+SERIAL=3
+sed "s/#SERIAL#/${SERIAL}/" $TPL > $ZFIN
+export BASEDIR=`mktemp -d "/tmp/zone_sign-XXX"`
+$SIGN example.com. $ZFIN
+mv $ZFIN.signed $ZF.2
+
+# 3.
+SERIAL=4
+sed "s/#SERIAL#/${SERIAL}/" $TPL > $ZFIN
+mv $ZFIN $ZF.3
diff --git a/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/example.com.zone b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/example.com.zone
new file mode 100644
index 0000000000000000000000000000000000000000..50847b6f471146984856d76e7d812c2aa46817d6
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/example.com.zone
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@	SOA	dns1 hostmaster 1 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+	MX	10 mail
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+mail	A	192.0.2.3
+	AAAA	2001:DB8::3
diff --git a/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/example.com.zone.1 b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/example.com.zone.1
new file mode 100644
index 0000000000000000000000000000000000000000..2552bc358c3f1663a1b8595c5f8c82c4bdae0407
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/example.com.zone.1
@@ -0,0 +1,35 @@
+; File written on Thu Apr 24 15:36:29 2014
+; dnssec_signzone version 9.9.3-rpz2+rl.13214.22-P2-Ubuntu-1:9.9.3.dfsg.P2-4ubuntu1.1
+example.com.				      3600 IN SOA	dns1.example.com. hostmaster.example.com. 2 10800 3600 1209600 7200
+example.com.				      3600 IN RRSIG	SOA 7 2 3600 20500101000000 20140424123629 51155 example.com. PQ8cpTvs4mZGHoy2XHQLZdeiVGRTPsJqDD92hFMVJ1Inl5R2CrQatHO7 HOLtbj6aiyFWSHKqscPVsBb1zT70uOfAyu3E4VgsjNWcSKuXjLD6aZ82 qI1WLown0Q3g2TBbAoTTJn3pRlyPWTlHek/KKMrBqZvwDF7wL/R7qZ+E 36Q=
+example.com.				      3600 IN NS	dns1.example.com.
+example.com.				      3600 IN NS	dns2.example.com.
+example.com.				      3600 IN RRSIG	NS 7 2 3600 20500101000000 20140424123629 51155 example.com. RmlV5r9G9TEEOUBSmlXXgcRbziKFSi2jpcqGWiZ3UL3x5XfTKO9GQgFi ycmKJYRadnMbwdTWSlRZAzLmLNcMpALNE6+sxs7GNV0RhHhP+jHTh7NW 183YCPDb85U24BHS8jMS4yMFIMi9gxRiR8J+3+1pMbnsMXAyaTYwvvEH B4I=
+example.com.				      3600 IN MX	10 mail.example.com.
+example.com.				      3600 IN RRSIG	MX 7 2 3600 20500101000000 20140424123629 51155 example.com. R24pdpnrXrEjdtBrxOoauvf9KPGJnZiAEwPmyxXcGR7592Aho+yJwucX S+mZse/n2VQeUxCWVwBx5Bzpjr/+1LfTrLKPgOM+IWKrKnaalMlzOEEZ EGlrxcEHp29uNrOLKuNfa6rhFWEO2ZwexXcRm0nAFmOvOpHD3VXvJyGH bNE=
+example.com.				      3600 IN DNSKEY	256 3 7 AwEAAaMt9XXhtxM1V+SsixwTOcPeEOlvR4Ld7HA52bodbDe/yDEWpk65 O08Hjgf/UK4DGHWGVpXWp+Ch7WN/squv40mcaODf2socVwm2c0xVEgrU xI70ORPm3mIyNZxoBJCQ6Y9fECp/rzB0teoUU9r9JcwpTBXZ4I5L+9Jn ReyWSGu9
+example.com.				      3600 IN DNSKEY	257 3 7 AwEAAdXa1lZM92PJxqNys90jatrmvpwmrBW4NSUJeC1aOptOFYynkatk /vns9Kw0ZbyaDrm6eLODjFAwR0Vv2BqBZQikdFk0jaQoIcyTS0kwVEvJ hSpQpIykPp9YKc2176++e5VTrLttwlJaeghnfe+e6ymn+K6fTqoyH3pp nHRMjrDQmvtIJNuXO0tnoZepgGu0GY5x+s7wzYV6e2vmK+O74eyD9m3K +EHQ3BK5fdGMgNiMNqYdjcKC9IdB8gN0vd5h3e/fJDwvNyTjn2K2vm+4 uHyo5re2QwjwoguH7Cq+8mWiu/eN40drr7R8t2Ck65jVl8i3Y1yQLj06 a0vTFWyWkKM=
+example.com.				      3600 IN RRSIG	DNSKEY 7 2 3600 20500101000000 20140424123629 9303 example.com. L+dEuRjOXgPEGxztW0Iw1LW+awP+giTBqYSiWRXuZ8xJVL++OBxNJVN2 MJY3edjEQXMvtahC3Qvt+P9uQU5BSSN5jvNY9IV7ROTMHXYlXefDZfiT UR+Hq7HKD28pTJyqfmBJ4Vfm+zRGRDcLQCVwv+JtqQqLtuXH4Xp6rxDc B6J9a4/mondwo1BVUHqbIh5F4TvJ4c5caASTE0IwWTXrx46+zT/Dn+Z7 ZWAj7kk18b1JkG+pHscajFZWka8MKe+g+2sIS4F/4fKqgY8HLyrKAiM9 eKD4v/I/y2q7EIsuo0xt0Pad+p+ToeOgL6xagQ99Bn9AnWwugzqbHPYk ZKD3LQ==
+example.com.				      3600 IN RRSIG	DNSKEY 7 2 3600 20500101000000 20140424123629 51155 example.com. c5jmhniQswa0U5H4Dbs7hzvRpW0m5oJZ+CUEdwStiluH37j+QSiiJShi 05ecYzGwpZsCfoqRBqgguPnnb49SOQ8FGtiSkBsnqMZXJro8dROo10PG 9RpGwMkq7ORZV4d+anlX6eK/cUsitH6BHsdJSb+RC7+zDecHdp5953Do u6s=
+example.com.				      0	IN NSEC3PARAM	1 0 10 DEADBEEF
+example.com.				      0	IN RRSIG	NSEC3PARAM 7 2 0 20500101000000 20140424123629 51155 example.com. UEcOeHVD+mGkdapMDhnMeZPYlTTcTos9DGY9v/QKbtGrEalC3LbiIC2E E3BkdxoNqla5XrZ+MHkok4rGqIcJxMvPyh99p/6DPivC1B1J05M/lbAT 53LGhkEQ9lOUmT2TNwBpDesNTxsUkRa2+skHEfjeoqvAibTqTTEohJsv jUM=
+dns2.example.com.			      3600 IN A		192.0.2.2
+dns2.example.com.			      3600 IN RRSIG	A 7 3 3600 20500101000000 20140424123629 51155 example.com. VJncJWzMCMFNX+Kfdvo5s5opBX21bLs3p8WDWjCYHqTHVILNRIf2XJ9z cgOuW0J8QCr552ComjZvMO5cTHwYQ/XF+sbPiIlsrqJfd5SOClLuJUmy fbG7KsOKkcdsTDal0ZxAJF1McBVweOs0gwruRWjjp5ray7S3Hv7D4iUw 2Ig=
+dns2.example.com.			      3600 IN AAAA	2001:db8::2
+dns2.example.com.			      3600 IN RRSIG	AAAA 7 3 3600 20500101000000 20140424123629 51155 example.com. fNqPpG4wLL7BfuF4ApRTGFRacTNhT7aZ3E/suskuRhuqcWFCsqA+0GCM kt14N+SeisqPzmkwCVhfqvz/ODVW9i7h2vG3dwulPnK8d3IXeE/E1uJk 1stBGVEqp5S1LcFh4bwRQtifFKM/H9lfmjgcGe33JYzeVK5YIH3Kyoqm uOQ=
+dns1.example.com.			      3600 IN A		192.0.2.1
+dns1.example.com.			      3600 IN RRSIG	A 7 3 3600 20500101000000 20140424123629 51155 example.com. PpuXCe9hPC/HcxefhCK37eu0ceVchHCDFo94PflgRi/IYFfA0Xuqj9cE RMViVb8hP6GSqNoo8EUzbp+L1o6DmhQZ8JCSUQW+anGzKdwHjYEyTrQD 7MqMGQm1ywHusGhtbvdHmqEccYN3HslRcSc7QzUOfSy2n1AC2aMeA8jn L20=
+dns1.example.com.			      3600 IN AAAA	2001:db8::1
+dns1.example.com.			      3600 IN RRSIG	AAAA 7 3 3600 20500101000000 20140424123629 51155 example.com. X/JWig1FZWKfHMbZADpE8AUrVGdqh291hhGIzQGPsJ++S234w+y3bdHg shieg2BLfbpBeCtZIvDXQE5A89cODCTz3HJeJnkQjHGSKauGft54HPks XmA5GloJ7mOuOH10NmlvAHmP0yQIiSVElvsyP1HC5ED3Hwz6l8Fnms38 fk8=
+8A5V7AUAVJA88G1DP716TS1HLVBCNJO7.example.com. 7200 IN NSEC3	1 0 10 DEADBEEF GR0GCFJEUNHRE7346DGPJJ5APHRUAT49 NS SOA MX RRSIG DNSKEY NSEC3PARAM
+8A5V7AUAVJA88G1DP716TS1HLVBCNJO7.example.com. 7200 IN RRSIG	NSEC3 7 3 7200 20500101000000 20140424123629 51155 example.com. f4D12PiwLLSdksr0RzkNvbpk61eY7g71qOW+y25wbqWnJJHfgAj0+6mR q8sYcDmBv2uanpd+8JGuOWBC+lJerZpgaDU+2BVHAWr7Kv5f6gDYzpPd nHyVoff3b9hH3YNrKK7XnJoeMBX2a5yWhlt90nA3bJLeVKt6tVxlbbl6 ZYY=
+mail.example.com.			      3600 IN A		192.0.2.3
+mail.example.com.			      3600 IN RRSIG	A 7 3 3600 20500101000000 20140424123629 51155 example.com. CUmYE7cqA36d3qWcLqFvwmz/3XG58ULVA4Sydbm8C+x28c5zYlf1kEi0 zyCCwZSu+aMZNyrXHoIi4ShCBbUHXEjZcGLdY3a83hQ1sI4/ILLuot0F B8sN6YA2FTHAgD+S35CnIiXiP5yAuK4S9GMHJQHtCwbavj7O1DxAv5db xdk=
+mail.example.com.			      3600 IN AAAA	2001:db8::3
+mail.example.com.			      3600 IN RRSIG	AAAA 7 3 3600 20500101000000 20140424123629 51155 example.com. AIAeQ6mdX53Dl5Rs5h6beuHR1SA2srhQ8bR9E3zUPPjmoW6agAh4Fr6t r3ys0h5FLlHBBX5ow8PA+6dOP73UmwVNFTPhRJPlP/MXf7VliN/IZAVD /ulus1FH9W4sbjOhqGerPT9w/bIy2xms4KRr4ETKvt1tsoGZ6Fa3Lqbz n4g=
+PBHK2DUPRJPKJABURDKKDCMLII36OM3J.example.com. 7200 IN NSEC3	1 0 10 DEADBEEF 46BRGPLB7MVA8KQDD8P2MORSKF2OMQOH A AAAA RRSIG
+PBHK2DUPRJPKJABURDKKDCMLII36OM3J.example.com. 7200 IN RRSIG	NSEC3 7 3 7200 20500101000000 20140424123629 51155 example.com. BAHLHBu7+0T0ToKAzGTOe5mX8zzBvcPBLaMvEISvyBJKFT5c0YRL2iYX z/xK1aWloiPVFxYho2gUf/BNGuDLpr8oCvckGTs2Lms8qwXqlAWGmdGA LUv6tsPmna64QLUxyjTfoXYInGtQSCalvoKRgAczWxxTukXYVRPXobrb JNs=
+46BRGPLB7MVA8KQDD8P2MORSKF2OMQOH.example.com. 7200 IN NSEC3	1 0 10 DEADBEEF 8A5V7AUAVJA88G1DP716TS1HLVBCNJO7 A AAAA RRSIG
+46BRGPLB7MVA8KQDD8P2MORSKF2OMQOH.example.com. 7200 IN RRSIG	NSEC3 7 3 7200 20500101000000 20140424123629 51155 example.com. fqAEJ/ikXrfUJL/aAlxIWTcMs5J2e5gq6KrjeRt+IsSBe5pPzb5ZKTUL Mxl7xvKNk2BaDqd9UWFnUom2dPkCmCNiS1Vs8MBCdkJHM3tuWqQXiZXG 8RMKX9wNkQ5rGJMgOO+FO3dCdEfI+cZg9xLqwN3rjp5RpAv+Px+zA0lm thc=
+GR0GCFJEUNHRE7346DGPJJ5APHRUAT49.example.com. 7200 IN NSEC3	1 0 10 DEADBEEF PBHK2DUPRJPKJABURDKKDCMLII36OM3J A AAAA RRSIG
+GR0GCFJEUNHRE7346DGPJJ5APHRUAT49.example.com. 7200 IN RRSIG	NSEC3 7 3 7200 20500101000000 20140424123629 51155 example.com. nI3HVCBJRMAyxxBDGEac0S73xfj4RFm2FExztpxaKoWaJZX7UV84bnc/ lkjtizO3GVdm52LdxXzYQiEMxh27SosayZ2UUROgoj0kKAcEElFoGO3e CIE8jE5x+qqlZNMVRE/b56bNaBeknGThwx4B4vfD019ARq15ZAOfEX2e HSY=
diff --git a/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/example.com.zone.2 b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/example.com.zone.2
new file mode 100644
index 0000000000000000000000000000000000000000..cb606bd639971c5a5164d83f6a3b2571972b79e4
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/example.com.zone.2
@@ -0,0 +1,33 @@
+; File written on Thu Apr 24 15:36:29 2014
+; dnssec_signzone version 9.9.3-rpz2+rl.13214.22-P2-Ubuntu-1:9.9.3.dfsg.P2-4ubuntu1.1
+example.com.				      3600 IN SOA	dns1.example.com. hostmaster.example.com. 3 10800 3600 1209600 7200
+example.com.				      3600 IN RRSIG	SOA 5 2 3600 20500101000000 20140424123629 26931 example.com. EhKJox6H7CkP3MaazA/h8Er0MPLkag8MZ3XI2LpKoEXL1bB/veP7dkHI ZNlUU8o/VMFnuTU31lnpGK55Mjdl+bcvTyFYa+rf+WVYLf+wvq18ClN/ OjquqXCSZG1PZ8EO7ehj6pwRrtFpM42wjhU2J55U8HH4giUCCXtrawCg JwA=
+example.com.				      3600 IN NS	dns1.example.com.
+example.com.				      3600 IN NS	dns2.example.com.
+example.com.				      3600 IN RRSIG	NS 5 2 3600 20500101000000 20140424123629 26931 example.com. efXIzAKSk9l0M9x8XSrDrnJ4QdBkiunsfSsXgA7aZKzSk0klj3Nzs8e4 NTHmwAxLIirRiCEzQcoYeHEbrzZbxxp4k8PUE/CfhttlANF2m/amJk7a JiOwetdNAO7xULIDjzdxbuKVfqF/IzGFgDpsG662fl2fGjUjlK2gWr62 pNM=
+example.com.				      3600 IN MX	10 mail.example.com.
+example.com.				      3600 IN RRSIG	MX 5 2 3600 20500101000000 20140424123629 26931 example.com. jPp0ZZ5ekaNEkOb9SBgTcTwqDLuTyUMnk2gzX1wCpznk99c1ydAexB3D aveKTdWzqble/w6/JIcWVgkdFLYJt1LMpZ9m0dwuAJkYB9h2ITEVdAG5 rLG5cB9hHhqIrCuIB95VaGN87cQSCUCq/2zkhff7X/uNUKJwBMHDlSQG M0g=
+example.com.				      7200 IN NSEC	dns1.example.com. NS SOA MX RRSIG NSEC DNSKEY
+example.com.				      7200 IN RRSIG	NSEC 5 2 7200 20500101000000 20140424123629 26931 example.com. YYD6j7NY2ibe2AfyfMHgB/87budXM5fH3h8Erzy+G/4yQVX7AxyVRP10 EoKSSO3ydJvTjdqYLt+uAm0TnsOIs6OufT5uW+dzLGblMwubYkItvgQ1 qDEXjuZqGjlxcJ59VjuGII00WyeN4bqUjrJ5JGyY62QH3nnaoShQhYGg vps=
+example.com.				      3600 IN DNSKEY	256 3 5 AwEAAceip6n1xgT5vUutYA+5Rf6xnLinPztKytdhCGHspOFd/EHN9t36 EDB0xBHBKR5WEKv8NMk6uF8QXZI7PUFzQ2gPOsnr6ezY54MRDY/tb/sv wVFLSR6yzdb+9MYofWPTaAqBNqxnhnn18aib6xvPVsebquprIfpKuUrg aFkqKygP
+example.com.				      3600 IN DNSKEY	257 3 5 AwEAAbGn7Ws42gRgmNmqZoZrdMUm7bzhDyNg3IfaAwXeV+kgm2C/WBsn u8TUpZrV5fi0b0duywPFCRXZsJtSBSWDjoI5wD8HNUQ+TgTPWkkzACMm BU21RXPeoBYbRBx7TvN1TyBRfXZO7pldWv5r7ax6HQ1XQtEjIJyQsc2g lQ+YR2feVN76rGiBCeJshFJQk4MZx6pyJdMgWf9gBSp/bZ4Cezy4AtlL mSQyM6oWX/N7lVDKid2gV3V13Pot0DQSn0ZLIHRcbxDup/ztOtLKMYgN VU2AdleuORgBuxJgeJWOfS48mJexdRm4fmJu9dYZGbcWsZfpybQAlS4b 7QxhO6kel9c=
+example.com.				      3600 IN RRSIG	DNSKEY 5 2 3600 20500101000000 20140424123629 26931 example.com. W8CTd9ddCWSVINhz1no+A9APclnSXthsR7h2D2cMUVF6umsxtKnsvvtA wu3+3grGcnglek9qW5RzbgFYzxwpNuNxRsTZbEjx/K+lUd0+DIcp5lG9 A75l53vD52doT2IW5/iU8ioRHDGnJ3+tYL3pdkpnV7AdBjwcLqdfgn4W bB0=
+example.com.				      3600 IN RRSIG	DNSKEY 5 2 3600 20500101000000 20140424123629 41407 example.com. ouIQC+v1aZXrMSFigm7qYndCgnMxdEaZpOK2IanVIzO/LHQrFPED/+cC eKHCpVFM+5rntq30ZD2EN/8X0CZh51sLkwraInVjgbGQV9RH6XcPpgcB Qe0T39dJyVivmMN6/tsSJtti+Cid3ReCicgAzToAsDk2leDeudkpqYU2 cRRcUYF5vMSdlzTEUKiWpffiJFL0d1AGsAYKcJbyb1tBe6d6F3GJYu2C WHyPQ82S2iC/ySY6I9TWf63INftggE1hcmJEc6WvclVpJk2o5RCLWdDR 872EqpZIW9mUcLJOf/Yyylbydj79uCNk6m3ScHpmoDr23NyxonWns4aY qXUbMg==
+dns1.example.com.			      3600 IN A		192.0.2.1
+dns1.example.com.			      3600 IN RRSIG	A 5 3 3600 20500101000000 20140424123629 26931 example.com. e3grqrfNoO3QfRHf8Y/968yauetK5U8dkMwU3zUNG+AHMObf+oJH0nz5 Glurzswk3nl/71ShYM4ZR10MuJ3cAyCeMQ+T8aRz8lTw87auLkKPjncr 4sQM8Jtg88/o4Ih3KkvfvTpnydC6jA5QS2eSCXS6eIcBZdp3n0R/BGMk I44=
+dns1.example.com.			      3600 IN AAAA	2001:db8::1
+dns1.example.com.			      3600 IN RRSIG	AAAA 5 3 3600 20500101000000 20140424123629 26931 example.com. tOC096uezc6wMiCa1aEqz7maWQBknahy0RbapJHxmXRLFyY+l2C9h8nZ EsBPJjwO33xu1YgYUIl3SZm+u8VYonoiRJJfnpIqUkHerFK1j2mViOva ZEi7Du2uWq2ZmLBsiSKQucWhi9pcS1q2SsPaVBImtdY8sfMOQhG1gXSR jMs=
+dns1.example.com.			      7200 IN NSEC	dns2.example.com. A AAAA RRSIG NSEC
+dns1.example.com.			      7200 IN RRSIG	NSEC 5 3 7200 20500101000000 20140424123629 26931 example.com. KbvO11Z0jy5Tk5JJkNZuLnV3HaDTk13dWebVE7SggWHDFUTeV/G8MsFx eO+SepdVgpp3qUqjF5rNhuZqThhFLwOjZtXoWITiyKtEAWsPnLGcfA+t 1oA6pD9nAds3AkKIRIZe8LnCAh05hki54bhA1ikx2ApkwEzpp4WGAr00 mRI=
+dns2.example.com.			      3600 IN A		192.0.2.2
+dns2.example.com.			      3600 IN RRSIG	A 5 3 3600 20500101000000 20140424123629 26931 example.com. QhzIfYDeidYQw0yvRsGVszHttZGHRT+52woPQFS4urAPQbDlTqzArt+4 qbDLgTZ7IjSyb0CRhiEm/FC9rg6LaxKKzJK84QrIR8gIDsHfvV2O6nBq 0oPfxXA807i6XclJHEn0+Pkx+hS5C63rkaK0HMwQuZ4l9Bn9OC4Gp3DB UD4=
+dns2.example.com.			      3600 IN AAAA	2001:db8::2
+dns2.example.com.			      3600 IN RRSIG	AAAA 5 3 3600 20500101000000 20140424123629 26931 example.com. Ehzzvbg47XCUWe17Pvh60GHZ6nBK0AF+qVD0dYVN1XchOcvnnQyH1GSz S+EPaB1/CnsMGK/Oy+sk6dvFhL5BJTbU5wL5Xfge5ap5jUe9xBvDWp7W 22dsvE2vlfSeiQ3EMN5J/MSFeD6H31uhIMY6+Z2LmtgY6aY0/NiFSJIX rrc=
+dns2.example.com.			      7200 IN NSEC	mail.example.com. A AAAA RRSIG NSEC
+dns2.example.com.			      7200 IN RRSIG	NSEC 5 3 7200 20500101000000 20140424123629 26931 example.com. daI7+KJchAnoZEnW10ruxVsZrXU4oSaL/XLxp77Fi1Ic3toNnL+wcxWu gtcVm+0YEJdbzONAQPehv8uhKCflQERK0zfiju+t4Mm0dG7S/wngiHgA vHe2a9IZXDud2F7+I4id+5Q4KP02NI3F5Q7jRyRdNIvHnFgZORUN+VTR NjY=
+mail.example.com.			      3600 IN A		192.0.2.3
+mail.example.com.			      3600 IN RRSIG	A 5 3 3600 20500101000000 20140424123629 26931 example.com. sbVd/0ZWWhAP16JwsS5ixVYZIrF2hPvZWx+PJLVQmbKqmo6w4lmCNWXp SEyJuco0wnWG5cMGayH/lqWGefgt2u2MH3VfD5eUXNO2mPUtW6QyvP6U rP1jvxiDclRr2e3lPTt8cPy4RJb3F0jNQFolOrNkMpKnzbSqC3RevC3W hgM=
+mail.example.com.			      3600 IN AAAA	2001:db8::3
+mail.example.com.			      3600 IN RRSIG	AAAA 5 3 3600 20500101000000 20140424123629 26931 example.com. Sov5oJswCrcHjIc+X7AoRgaPtMmJsYfCnWj7B0WLmyx5Az1jfkMgiLNP YR8JbgvGwsc93HnRYEnK8STvSGLV6X9+XT/38Rvm78bIY5ZFF6mf7te3 puMX6UvAsb2UZZrov/lrw5YYNeSDnGLhHMUxXEInXMAhnoZ2bZQs8gHp xgI=
+mail.example.com.			      7200 IN NSEC	example.com. A AAAA RRSIG NSEC
+mail.example.com.			      7200 IN RRSIG	NSEC 5 3 7200 20500101000000 20140424123629 26931 example.com. n4WOxjhZFrRxV00qZE6nlQ7DR56TjJR90WzBZQ+cj/P3tVTnV/OMmlPj r5Kl0fo8iWl1sWaxA81T2+HmDqaB+qlkOQdFi2rF9iuiYs/FeiJ83RY6 7opwsmrkUHPPv5WGyw3L4wFx7cOgkWHuEF1KGtakYoTSoAGCiFjsxeEU MK4=
diff --git a/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/example.com.zone.3 b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/example.com.zone.3
new file mode 100644
index 0000000000000000000000000000000000000000..4a35c30b71eec527756811aa287ce88e6b86aebd
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/example.com.zone.3
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@	SOA	dns1 hostmaster 4 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+	MX	10 mail
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+mail	A	192.0.2.3
+	AAAA	2001:DB8::3
diff --git a/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/step.py b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/step.py
new file mode 100644
index 0000000000000000000000000000000000000000..e327d8e2b007e0bdaea018ba4597ca870d396eea
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/step.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python3
+
+'''Unsigned -> signed(NSEC3) -> signed(NSEC) -> unsigned transitions.'''
+
+def run(i):
+    i.test.start()
+
+    i.check()
+
+    i.check(1)
+
+    i.check(2)
+
+    i.check(3)
+
+    i.test.end()
diff --git a/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/update/example.com.zone.template b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/update/example.com.zone.template
new file mode 100644
index 0000000000000000000000000000000000000000..29c6f4b441dfa62653103283679f681492420e2e
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/update/example.com.zone.template
@@ -0,0 +1,16 @@
+$ORIGIN example.com.
+$TTL 3600
+
+@	SOA	dns1 hostmaster #SERIAL# 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+	MX	10 mail
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+mail	A	192.0.2.3
+	AAAA	2001:DB8::3
diff --git a/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/update/update.sh b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/update/update.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7a8495b44a237d4ea877bc7e5e5b1600b9a17f5c
--- /dev/null
+++ b/tests-extra/tests/ixfr/from_differences/08_none_nsec3_nsec_none/update/update.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+SIGN="../../../../../tools/zone_sign.sh"
+TPL="./example.com.zone.template"
+ZFIN="../example.com.zone.in"
+ZF="../example.com.zone"
+
+# 0.
+SERIAL=1
+sed "s/#SERIAL#/${SERIAL}/" $TPL > $ZFIN
+mv $ZFIN $ZF
+
+# 1.
+SERIAL=2
+sed "s/#SERIAL#/${SERIAL}/" $TPL > $ZFIN
+export BASEDIR=`mktemp -d "/tmp/zone_sign-XXX"`
+$SIGN example.com. $ZFIN
+mv $ZFIN.signed $ZF.1
+
+# 2.
+SERIAL=3
+sed "s/#SERIAL#/${SERIAL}/" $TPL > $ZFIN
+export BASEDIR=`mktemp -d "/tmp/zone_sign-XXX"`
+$SIGN example.com. $ZFIN nsec
+mv $ZFIN.signed $ZF.2
+
+# 3.
+SERIAL=4
+sed "s/#SERIAL#/${SERIAL}/" $TPL > $ZFIN
+mv $ZFIN $ZF.3
diff --git a/tests-extra/tools/dnstest/server.py b/tests-extra/tools/dnstest/server.py
index c1254f53d6c7ec96d4403c43ccb8cb72931c7311..951abb62707f99b15b90a215087e29b1083d4383 100644
--- a/tests-extra/tools/dnstest/server.py
+++ b/tests-extra/tools/dnstest/server.py
@@ -661,6 +661,10 @@ class Bind(Server):
         s.item("auth-nxdomain", "no")
         s.item("recursion", "no")
         s.item("masterfile-format", "text")
+        s.item("max-refresh-time", "2")
+        s.item("max-retry-time", "2")
+        s.item("transfers-in", "30")
+        s.item("transfers-out", "30")
         s.end()
 
         s.begin("key", self.ctlkey.name)
diff --git a/tests-extra/tools/dnstest/test.py b/tests-extra/tools/dnstest/test.py
index 3d9192712c0d290074fe5e7fc9033022e87a4d37..4b59c5102e941c1c121c0ede42ea605171c567cb 100644
--- a/tests-extra/tools/dnstest/test.py
+++ b/tests-extra/tools/dnstest/test.py
@@ -88,6 +88,13 @@ class Test(object):
         Test.last_port = port
         return port
 
+    @property
+    def hostname(self):
+        hostname = socket.gethostname()
+        addrinfo = socket.getaddrinfo(hostname, 0, socket.AF_UNSPEC,
+                                      socket.SOCK_DGRAM, 0, socket.AI_CANONNAME)
+        return addrinfo[0][3] if addrinfo else hostname
+
     def server(self, server, nsid=None, ident=None, version=None, \
                valgrind=None):
         if server == "knot":
diff --git a/tests/descriptor.c b/tests/descriptor.c
index 1fd576bea75be64c933cf0843f3b58a3dcea4b52..85a98351bb52d8ab937f4fb4acaae7355107e5b5 100644
--- a/tests/descriptor.c
+++ b/tests/descriptor.c
@@ -26,7 +26,7 @@
 
 int main(int argc, char *argv[])
 {
-	plan(81);
+	plan(108);
 
 	const    rdata_descriptor_t *descr;
 	char     name[BUF_LEN];
@@ -38,9 +38,9 @@ int main(int argc, char *argv[])
 	descr = get_rdata_descriptor(0);
 	ok(descr->type_name == 0, "get TYPE0 descriptor name");
 	ok(descr->block_types[0] == KNOT_RDATA_WF_REMAINDER,
-	       "get TYPE0 descriptor 1. item type");
+	   "get TYPE0 descriptor 1. item type");
 	ok(descr->block_types[1] == KNOT_RDATA_WF_END,
-	       "get TYPE0 descriptor 2. item type");
+	   "get TYPE0 descriptor 2. item type");
 
 	ret = knot_rrtype_to_string(0, name, BUF_LEN);
 	ok(ret != -1, "get TYPE0 ret");
@@ -50,9 +50,9 @@ int main(int argc, char *argv[])
 	descr = get_rdata_descriptor(1);
 	ok(strcmp(descr->type_name, "A") == 0, "get A descriptor name");
 	ok(descr->block_types[0] == 4,
-	       "get A descriptor 1. item type");
+	   "get A descriptor 1. item type");
 	ok(descr->block_types[1] == KNOT_RDATA_WF_END,
-	       "get A descriptor 2. item type");
+	   "get A descriptor 2. item type");
 
 	ret = knot_rrtype_to_string(1, name, BUF_LEN);
 	ok(ret != -1, "get A ret");
@@ -62,9 +62,9 @@ int main(int argc, char *argv[])
 	descr = get_rdata_descriptor(5);
 	ok(strcmp(descr->type_name, "CNAME") == 0, "get CNAME descriptor name");
 	ok(descr->block_types[0] == KNOT_RDATA_WF_COMPRESSED_DNAME,
-	       "get CNAME descriptor 1. item type");
+	   "get CNAME descriptor 1. item type");
 	ok(descr->block_types[1] == KNOT_RDATA_WF_END,
-	       "get CNAME descriptor 2. item type");
+	   "get CNAME descriptor 2. item type");
 
 	ret = knot_rrtype_to_string(5, name, BUF_LEN);
 	ok(ret != -1, "get CNAME ret");
@@ -74,9 +74,9 @@ int main(int argc, char *argv[])
 	descr = get_rdata_descriptor(38);
 	ok(descr->type_name == 0, "get TYPE38 descriptor name");
 	ok(descr->block_types[0] == KNOT_RDATA_WF_REMAINDER,
-	       "get TYPE38 descriptor 1. item type");
+	   "get TYPE38 descriptor 1. item type");
 	ok(descr->block_types[1] == KNOT_RDATA_WF_END,
-	       "get TYPE38 descriptor 2. item type");
+	   "get TYPE38 descriptor 2. item type");
 
 	ret = knot_rrtype_to_string(38, name, BUF_LEN);
 	ok(ret != -1, "get TYPE38 ret");
@@ -86,9 +86,9 @@ int main(int argc, char *argv[])
 	descr = get_rdata_descriptor(255);
 	ok(strcmp(descr->type_name, "ANY") == 0, "get ANY descriptor name");
 	ok(descr->block_types[0] == KNOT_RDATA_WF_REMAINDER,
-	       "get ANY descriptor 1. item type");
+	   "get ANY descriptor 1. item type");
 	ok(descr->block_types[1] == KNOT_RDATA_WF_END,
-	       "get ANY descriptor 2. item type");
+	   "get ANY descriptor 2. item type");
 
 	ret = knot_rrtype_to_string(255, name, BUF_LEN);
 	ok(ret != -1, "get ANY ret");
@@ -98,9 +98,9 @@ int main(int argc, char *argv[])
 	descr = get_rdata_descriptor(256);
 	ok(descr->type_name == 0, "get TYPE256 descriptor name");
 	ok(descr->block_types[0] == KNOT_RDATA_WF_REMAINDER,
-	       "get TYPE256 descriptor 1. item type");
+	   "get TYPE256 descriptor 1. item type");
 	ok(descr->block_types[1] == KNOT_RDATA_WF_END,
-	       "get TYPE256 descriptor 2. item type");
+	   "get TYPE256 descriptor 2. item type");
 
 	ret = knot_rrtype_to_string(256, name, BUF_LEN);
 	ok(ret != -1, "get TYPE256 ret");
@@ -222,35 +222,107 @@ int main(int argc, char *argv[])
 	descr = get_obsolete_rdata_descriptor(0);
 	ok(descr->type_name == 0, "get TYPE0 descriptor name");
 	ok(descr->block_types[0] == KNOT_RDATA_WF_REMAINDER,
-	       "get TYPE0 descriptor 1. item type");
+	   "get TYPE0 descriptor 1. item type");
 	ok(descr->block_types[1] == KNOT_RDATA_WF_END,
-	       "get TYPE0 descriptor 2. item type");
+	   "get TYPE0 descriptor 2. item type");
 
 	// 31. MD
 	descr = get_obsolete_rdata_descriptor(3);
 	ok(strcmp(descr->type_name, "MD") == 0, "get MD descriptor name");
 	ok(descr->block_types[0] == KNOT_RDATA_WF_COMPRESSED_DNAME,
-	       "get A descriptor 1. item type");
+	   "get A descriptor 1. item type");
 	ok(descr->block_types[1] == KNOT_RDATA_WF_END,
-	       "get A descriptor 2. item type");
+	   "get A descriptor 2. item type");
 
 	// 32. NXT
 	descr = get_obsolete_rdata_descriptor(30);
 	ok(strcmp(descr->type_name, "NXT") == 0, "get NXT descriptor name");
 	ok(descr->block_types[0] == KNOT_RDATA_WF_COMPRESSED_DNAME,
-	       "get CNAME descriptor 1. item type");
+	   "get CNAME descriptor 1. item type");
 	ok(descr->block_types[1] == KNOT_RDATA_WF_REMAINDER,
-	       "get CNAME descriptor 2. item type");
+	   "get CNAME descriptor 2. item type");
 	ok(descr->block_types[2] == KNOT_RDATA_WF_END,
-	       "get CNAME descriptor 3. item type");
+	   "get CNAME descriptor 3. item type");
 
 	// 33. TYPE38 (A6)
 	descr = get_obsolete_rdata_descriptor(38);
 	ok(descr->type_name == 0, "get TYPE38 descriptor name");
 	ok(descr->block_types[0] == KNOT_RDATA_WF_REMAINDER,
-	       "get TYPE38 descriptor 1. item type");
+	   "get TYPE38 descriptor 1. item type");
 	ok(descr->block_types[1] == KNOT_RDATA_WF_END,
-	       "get TYPE38 descriptor 2. item type");
+	   "get TYPE38 descriptor 2. item type");
+
+	// knot_rrtype_to_string invalid output buffer size
+	ret = knot_rrtype_to_string(1, NULL, 0);
+	ok(ret == -1, "knot_rrtype_to_string: invalid output buffer size");
+
+	// knot_rrclass_to_string invalid output buffer size
+	ret = knot_rrclass_to_string(1, NULL, 0);
+	ok(ret == -1, "knot_rrclass_to_string: invalid output buffer size");
+
+	// descriptor_item_is_dname
+	ok(descriptor_item_is_dname(KNOT_RDATA_WF_END) == 0,
+	   "descriptor is not dname");
+	ok(descriptor_item_is_dname(KNOT_RDATA_WF_COMPRESSED_DNAME) != 0,
+	   "descriptor is compressed dname");
+	ok(descriptor_item_is_dname(KNOT_RDATA_WF_UNCOMPRESSED_DNAME) != 0,
+	   "descriptor is uncompressed dname");
+
+	// descriptor_item_is_compr_dname
+	ok(descriptor_item_is_compr_dname(KNOT_RDATA_WF_END) == 0,
+	   "descriptor is not compressed dname");
+	ok(descriptor_item_is_compr_dname(KNOT_RDATA_WF_COMPRESSED_DNAME) != 0,
+	   "descriptor is compressed dname");
+
+	// descriptor_item_is_fixed
+	ok(descriptor_item_is_fixed(0) == 0,
+	   "descriptor is not fixed");
+	ok(descriptor_item_is_fixed(1) != 0,
+	   "descriptor is fixed");
+
+	// descriptor_item_is_remainder
+	ok(descriptor_item_is_remainder(0) == 0,
+	   "descriptor is not remainder");
+	ok(descriptor_item_is_remainder(KNOT_RDATA_WF_REMAINDER) != 0,
+	   "descriptor is remainder");
+
+	// knot_rrtype_is_metatype
+	ok(knot_rrtype_is_metatype(0) == 0,
+	   "rrtype is not metatype");
+	ok(knot_rrtype_is_metatype(KNOT_RRTYPE_SIG) != 0,
+	   "rrtype is SIG");
+	ok(knot_rrtype_is_metatype(KNOT_RRTYPE_OPT) != 0,
+	   "rrtype is OPT");
+	ok(knot_rrtype_is_metatype(KNOT_RRTYPE_TKEY) != 0,
+	   "rrtype is TKEY");
+	ok(knot_rrtype_is_metatype(KNOT_RRTYPE_TSIG) != 0,
+	   "rrtype is TSIG");
+	ok(knot_rrtype_is_metatype(KNOT_RRTYPE_IXFR) != 0,
+	   "rrtype is IXFR");
+	ok(knot_rrtype_is_metatype(KNOT_RRTYPE_AXFR) != 0,
+	   "rrtype is AXFR");
+	ok(knot_rrtype_is_metatype(KNOT_RRTYPE_ANY) != 0,
+	   "rrtype is ANY");
+
+	// knot_rrtype_is_ddns_forbidden
+	ok(knot_rrtype_is_ddns_forbidden(0) == 0,
+	   "rrtype is not ddns forbidden");
+	ok(knot_rrtype_is_ddns_forbidden(KNOT_RRTYPE_RRSIG) != 0,
+	   "rrtype is RRSIG");
+	ok(knot_rrtype_is_ddns_forbidden(KNOT_RRTYPE_NSEC) != 0,
+	   "rrtype is NSEC");
+	ok(knot_rrtype_is_ddns_forbidden(KNOT_RRTYPE_NSEC3) != 0,
+	   "rrtype is NSEC3");
+
+	// knot_rrtype_additional_needed
+	ok(knot_rrtype_additional_needed(0) == 0,
+	   "rrtype is not additional needed");
+	ok(knot_rrtype_additional_needed(KNOT_RRTYPE_NS) != 0,
+	   "rrtype is NS");
+	ok(knot_rrtype_additional_needed(KNOT_RRTYPE_MX) != 0,
+	   "rrtype is MX");
+	ok(knot_rrtype_additional_needed(KNOT_RRTYPE_SRV) != 0,
+	   "rrtype is SRV");
 
 	return 0;
 }
diff --git a/tests/process_query.c b/tests/process_query.c
index 318b8fbd5e1317d69a76d1b225cb1a643dc84dea..37b8832cf63bb6ba4edbbcd4b62b3b81939cdc83 100644
--- a/tests/process_query.c
+++ b/tests/process_query.c
@@ -173,4 +173,4 @@ int main(int argc, char *argv[])
 	return 0;
 }
 
-#undef WIRE_COPY
+#undef WIRE_COPY
\ No newline at end of file