diff --git a/Knot.files b/Knot.files
index 2a81474a3d324065013e8574cd2b3ef7cf85e9b3..ead382f77cc630cd51b4a373840cad7c42f3e9f1 100644
--- a/Knot.files
+++ b/Knot.files
@@ -291,8 +291,6 @@ src/zscanner/error.c
 src/zscanner/error.h
 src/zscanner/functions.c
 src/zscanner/functions.h
-src/zscanner/loader.c
-src/zscanner/loader.h
 src/zscanner/scanner.h
 src/zscanner/scanner.rl
 src/zscanner/scanner_body.rl
@@ -301,7 +299,6 @@ src/zscanner/tests/processing.h
 src/zscanner/tests/tests.c
 src/zscanner/tests/tests.h
 src/zscanner/tests/zscanner-tool.c
-src/zscanner/zscanner.h
 tests/Makefile.am
 tests/acl.c
 tests/base32hex.c
diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c
index bd4aa5e3692eb93a7353659f4b195d8109608a17..cdb45aac7fedc5feda93ac444a36b0dc2d9a649a 100644
--- a/src/knot/ctl/knotc_main.c
+++ b/src/knot/ctl/knotc_main.c
@@ -715,7 +715,6 @@ static int cmd_memstats(int argc, char *argv[], unsigned flags)
 	UNUSED(flags);
 
 	/* Zone checking */
-	int rc = 0;
 	double total_size = 0;
 
 	/* Generate databases for all zones */
@@ -760,7 +759,7 @@ static int cmd_memstats(int argc, char *argv[], unsigned flags)
 		                    .record_count = 0 };
 		if (est.node_table == NULL) {
 			log_error("not enough memory");
-			continue;
+			break;
 		}
 
 		/* Create zone scanner. */
@@ -770,7 +769,6 @@ static int cmd_memstats(int argc, char *argv[], unsigned flags)
 		                                     process_error,
 		                                     &est);
 		if (zs == NULL) {
-			rc = 1;
 			log_zone_str_error(zone->name, "could not load zone");
 			hattrie_free(est.node_table);
 			continue;
@@ -779,7 +777,6 @@ static int cmd_memstats(int argc, char *argv[], unsigned flags)
 		/* Do a parser run, but do not actually create the zone. */
 		int ret = zs_scanner_parse_file(zs, zone->file);
 		if (ret != 0) {
-			rc = 1;
 			log_zone_str_error(zone->name, "failed to parse zone");
 			hattrie_apply_rev(est.node_table, estimator_free_trie_node, NULL);
 			hattrie_free(est.node_table);
@@ -809,10 +806,10 @@ static int cmd_memstats(int argc, char *argv[], unsigned flags)
 	}
 	hattrie_iter_free(z_iter);
 
-	if (rc == 0 && argc == 0) { // for all zones
+	if (argc == 0) { // for all zones
 		log_info("estimated memory consumption for all zones is %zu MB",
 		         (size_t)total_size);
 	}
 
-	return rc;
+	return 0;
 }
diff --git a/src/knot/nameserver/internet.c b/src/knot/nameserver/internet.c
index 11cb312ca1de128d77859bff3357bd6825c2460f..0dd6214ce5d528471ab26fe8c7b1bebcbd70ee98 100644
--- a/src/knot/nameserver/internet.c
+++ b/src/knot/nameserver/internet.c
@@ -19,7 +19,6 @@
 #include "libknot/common.h"
 #include "libknot/rrtype/rdname.h"
 #include "libknot/rrtype/soa.h"
-#include "libknot/rrtype/opt.h"
 #include "libknot/dnssec/rrset-sign.h"
 #include "knot/nameserver/internet.h"
 #include "knot/nameserver/nsec_proofs.h"
@@ -167,50 +166,6 @@ static int put_rrsig(const knot_dname_t *sig_owner, uint16_t type,
 	return KNOT_EOK;
 }
 
-/*! \brief Put OPT RR to packet. */
-static int put_opt_rr(knot_pkt_t *pkt, struct query_data *qdata)
-{
-	/* Copy OPT RR from server. */
-	dbg_ns("%s: adding OPT RR to the response\n", __func__);
-	const knot_pkt_t *query = qdata->query;
-	knot_rrset_t opt_rr;
-	int ret = knot_edns_init(&opt_rr, conf()->max_udp_payload,
-	                         qdata->rcode_ext, KNOT_EDNS_VERSION, &pkt->mm);
-	if (ret != KNOT_EOK) {
-		return ret;
-	}
-
-	/* Append NSID if requested and available. */
-	if (knot_edns_has_nsid(query->opt_rr) && conf()->nsid_len > 0) {
-		ret = knot_edns_add_option(&opt_rr,
-		                           KNOT_EDNS_OPTION_NSID, conf()->nsid_len,
-		                           (const uint8_t*)conf()->nsid, &pkt->mm);
-		if (ret != KNOT_EOK) {
-			knot_rrset_clear(&opt_rr, &pkt->mm);
-			return ret;
-		}
-	}
-
-	/* Set DO bit if set (DNSSEC requested). */
-	if (knot_pkt_has_dnssec(query)) {
-		dbg_ns("%s: setting DO=1 in OPT RR\n", __func__);
-		knot_edns_set_do(&opt_rr);
-	}
-
-	/* Reclaim reserved size. */
-	ret = knot_pkt_reclaim(pkt, knot_edns_wire_size(&opt_rr));
-	if (ret == KNOT_EOK) {
-		/* Write to packet. */
-		ret = knot_pkt_put(pkt, COMPR_HINT_NONE, &opt_rr, KNOT_PF_FREE);
-	}
-
-	if (ret != KNOT_EOK) {
-		knot_rrset_clear(&opt_rr, &pkt->mm);
-	}
-
-	return ret;
-}
-
 /*! \brief This is a wildcard-covered or any other terminal node for QNAME.
  *         e.g. positive answer.
  */
@@ -700,14 +655,7 @@ static int solve_authority_dnssec(int state, knot_pkt_t *pkt, struct query_data
 static int solve_additional(int state, knot_pkt_t *pkt,
                             struct query_data *qdata, void *ctx)
 {
-	/* Put OPT RR to the additional section. */
 	int ret = KNOT_EOK;
-	if (knot_pkt_has_edns(qdata->query)) {
-		ret = put_opt_rr(pkt, qdata);
-		if (ret != KNOT_EOK) {
-			return ERROR;
-		}
-	}
 
 	/* Scan all RRs in ANSWER/AUTHORITY. */
 	for (uint16_t i = 0; i < pkt->rrset_count; ++i) {
diff --git a/src/knot/nameserver/process_query.c b/src/knot/nameserver/process_query.c
index 07cf1da8ce35fc95d6aa935ee83641b5107812c4..96127bec862bae5e9ea4a635b2152b034c10fc7d 100644
--- a/src/knot/nameserver/process_query.c
+++ b/src/knot/nameserver/process_query.c
@@ -60,6 +60,7 @@ static int process_query_reset(knot_process_t *ctx)
 	knot_pkt_free(&qdata->query);
 	ptrlist_free(&qdata->wildcards, qdata->mm);
 	nsec_clear_rrsigs(qdata);
+	knot_rrset_clear(&qdata->opt_rr, qdata->mm);
 	if (qdata->ext_cleanup != NULL) {
 		qdata->ext_cleanup(qdata);
 	}
@@ -260,6 +261,70 @@ static const zone_t *answer_zone_find(const knot_pkt_t *query, knot_zonedb_t *zo
 	return zone;
 }
 
+static int answer_edns_reserve(knot_pkt_t *resp, struct query_data *qdata)
+{
+	if (knot_rrset_empty(&qdata->opt_rr)) {
+		return KNOT_EOK;
+	}
+
+	/* Reserve size in the response. */
+	return knot_pkt_reserve(resp, knot_edns_wire_size(&qdata->opt_rr));
+}
+
+static int answer_edns_init(const knot_pkt_t *query, knot_pkt_t *resp,
+                            struct query_data *qdata)
+{
+	if (!knot_pkt_has_edns(query)) {
+		return KNOT_EOK;
+	}
+
+	/* Initialize OPT record. */
+	int ret = knot_edns_init(&qdata->opt_rr, conf()->max_udp_payload, 0,
+	                     KNOT_EDNS_VERSION, qdata->mm);
+	if (ret != KNOT_EOK) {
+		return ret;
+	}
+
+	/* Check supported version. */
+	if (knot_edns_get_version(query->opt_rr) != KNOT_EDNS_VERSION) {
+		qdata->rcode_ext = KNOT_EDNS_RCODE_BADVERS;
+	}
+
+	/* Set DO bit if set (DNSSEC requested). */
+	if (knot_pkt_has_dnssec(query)) {
+		knot_edns_set_do(&qdata->opt_rr);
+	}
+
+	/* Append NSID if requested and available. */
+	if (knot_edns_has_nsid(query->opt_rr) && conf()->nsid_len > 0) {
+		ret = knot_edns_add_option(&qdata->opt_rr,
+		                           KNOT_EDNS_OPTION_NSID, conf()->nsid_len,
+		                           (const uint8_t*)conf()->nsid, qdata->mm);
+		if (ret != KNOT_EOK) {
+			return ret;
+		}
+	}
+
+	return answer_edns_reserve(resp, qdata);
+}
+
+static int answer_edns_put(knot_pkt_t *resp, struct query_data *qdata)
+{
+	if (knot_rrset_empty(&qdata->opt_rr)) {
+		return KNOT_EOK;
+	}
+
+	/* Reclaim reserved size. */
+	int ret = knot_pkt_reclaim(resp, knot_edns_wire_size(&qdata->opt_rr));
+	if (ret != KNOT_EOK) {
+		return ret;
+	}
+
+	/* Write to packet. */
+	assert(resp->current == KNOT_ADDITIONAL);
+	return knot_pkt_put(resp, COMPR_HINT_NONE, &qdata->opt_rr, 0);
+}
+
 /*! \brief Initialize response, sizes and find zone from which we're going to answer. */
 static int prepare_answer(const knot_pkt_t *query, knot_pkt_t *resp, knot_process_t *ctx)
 {
@@ -294,49 +359,26 @@ static int prepare_answer(const knot_pkt_t *query, knot_pkt_t *resp, knot_proces
 	/* Find zone for QNAME. */
 	qdata->zone = answer_zone_find(query, server->zone_db);
 
-	/* Update maximal answer size. */
-	if (qdata->param->proc_flags & NS_QUERY_LIMIT_SIZE) {
-		resp->max_size = KNOT_WIRE_MIN_PKTSIZE;
-	}
-
-	/* Check if EDNS is supported. */
-	if (!knot_pkt_has_edns(query)) {
-		return KNOT_EOK;
-	}
-
-	/* Check EDNS version and return BADVERS if not supported. */
-	if (knot_edns_get_version(query->opt_rr) != KNOT_EDNS_VERSION) {
-		dbg_ns("%s: unsupported EDNS version required.\n", __func__);
-		qdata->rcode_ext = KNOT_EDNS_RCODE_BADVERS;
-	}
-
-	/* Reserve space for OPT RR in the packet. Using size of the server's
-	 * OPT RR, because that's the maximum size (RDATA may or may not be
-	 * used).
-	 */
-	uint16_t reserve_size = KNOT_EDNS_MIN_SIZE;
-	if (knot_edns_has_nsid(query->opt_rr) && conf()->nsid_len > 0) {
-		reserve_size += KNOT_EDNS_OPTION_HDRLEN + conf()->nsid_len;
-	}
-	ret = knot_pkt_reserve(resp, reserve_size);
+	/* Setup EDNS. */
+	ret = answer_edns_init(query, resp, qdata);
 	if (ret != KNOT_EOK) {
-		dbg_ns("%s: can't reserve OPT RR in response (%d)\n", __func__, ret);
 		return ret;
 	}
 
-	/* Get minimal supported size from EDNS(0). */
-	uint16_t client_maxlen = knot_edns_get_payload(query->opt_rr);
-	uint16_t server_maxlen = conf()->max_udp_payload;
-	uint16_t min_edns = MIN(client_maxlen, server_maxlen);
-
-	/* Update packet size limit. */
-	if (qdata->param->proc_flags & NS_QUERY_LIMIT_SIZE) {
-		resp->max_size =  MAX(resp->max_size, min_edns);
-		dbg_ns("%s: packet size limit <= %zuB\n", __func__, resp->max_size);
+	/* Update maximal answer size. */
+	bool has_limit = qdata->param->proc_flags & NS_QUERY_LIMIT_SIZE;
+	if (has_limit) {
+		resp->max_size = KNOT_WIRE_MIN_PKTSIZE;
+		if (knot_pkt_has_edns(query)) {
+			uint16_t client = knot_edns_get_payload(query->opt_rr);
+			uint16_t server = conf()->max_udp_payload;
+			uint16_t transfer = MIN(client, server);
+			resp->max_size = MAX(resp->max_size, transfer);
+		}
+	} else {
+		resp->max_size = KNOT_WIRE_MAX_PKTSIZE;
 	}
 
-	/* In the response, always advertise server's maximum UDP payload. */
-
 	return ret;
 }
 
@@ -361,11 +403,21 @@ static int process_query_err(knot_pkt_t *pkt, knot_process_t *ctx)
 	/* Set RCODE. */
 	knot_wire_set_rcode(pkt->wire, qdata->rcode);
 
-	/* Transaction security (if applicable). */
-	if (process_query_sign_response(pkt, qdata) != KNOT_EOK) {
-		return NS_PROC_FAIL;
+
+	/* Add OPT and TSIG (best effort, send reply anyway if fails). */
+	if (pkt->current != KNOT_ADDITIONAL) {
+		knot_pkt_begin(pkt, KNOT_ADDITIONAL);
+	}
+
+	/* Put OPT RR to the additional section. */
+	int ret = answer_edns_reserve(pkt, qdata);
+	if (ret == KNOT_EOK) {
+		(void) answer_edns_put(pkt, qdata);
 	}
 
+	/* Transaction security (if applicable). */
+	(void) process_query_sign_response(pkt, qdata);
+
 	return NS_PROC_DONE;
 }
 
@@ -464,8 +516,19 @@ static int process_query_out(knot_pkt_t *pkt, knot_process_t *ctx)
 	 * Postprocessing.
 	 */
 
-	/* Transaction security (if applicable). */
 	if (next_state == NS_PROC_DONE || next_state == NS_PROC_FULL) {
+		if (pkt->current != KNOT_ADDITIONAL) {
+			knot_pkt_begin(pkt, KNOT_ADDITIONAL);
+		}
+
+		/* Put OPT RR to the additional section. */
+		ret = answer_edns_put(pkt, qdata);
+		if (ret != KNOT_EOK) {
+			next_state = NS_PROC_FAIL;
+			goto finish;
+		}
+
+		/* Transaction security (if applicable). */
 		if (process_query_sign_response(pkt, qdata) != KNOT_EOK) {
 			next_state = NS_PROC_FAIL;
 		}
diff --git a/src/knot/nameserver/process_query.h b/src/knot/nameserver/process_query.h
index a5bf96ca9b48708f3605a12007d0d807b36939bc..27ca16847d9cb754465af16c3500ae346a15fc6e 100644
--- a/src/knot/nameserver/process_query.h
+++ b/src/knot/nameserver/process_query.h
@@ -84,6 +84,9 @@ struct query_data {
 	/* Original QNAME case. */
 	uint8_t orig_qname[KNOT_DNAME_MAXLEN];
 
+	/* EDNS */
+	knot_rrset_t opt_rr;
+
 	/* Extensions. */
 	void *ext;
 	void (*ext_cleanup)(struct query_data*); /*!< Extensions cleanup callback. */
diff --git a/src/knot/zone/events.c b/src/knot/zone/events.c
index 2ee5c77c545b66e17f8c00ef5aee06ad229d9598..eb1f8d94471e57148dca26cff246c7cc177e9713 100644
--- a/src/knot/zone/events.c
+++ b/src/knot/zone/events.c
@@ -212,7 +212,7 @@ static void schedule_dnssec(zone_t *zone, time_t refresh_at)
 	struct tm time_gm = { 0 };
 	localtime_r(&refresh_at, &time_gm);
 	strftime(time_str, sizeof(time_str), KNOT_LOG_TIME_FORMAT, &time_gm);
-	log_zone_info(zone->name, "DNSSEC, next event on %s", time_str);
+	log_zone_info(zone->name, "DNSSEC: next signing on %s", time_str);
 
 	// schedule
 
@@ -494,14 +494,14 @@ static int event_dnssec(zone_t *zone)
 
 	uint32_t refresh_at = time(NULL);
 	if (zone->flags & ZONE_FORCE_RESIGN) {
-		log_zone_info(zone->name, "DNSSEC, dropping previous "
+		log_zone_info(zone->name, "DNSSEC: dropping previous "
 		              "signatures, resigning zone");
 
 		zone->flags &= ~ZONE_FORCE_RESIGN;
 		ret = knot_dnssec_zone_sign_force(zone->contents, zone->conf,
 		                                  &ch, &refresh_at);
 	} else {
-		log_zone_info(zone->name, "DNSSEC, signing zone");
+		log_zone_info(zone->name, "DNSSEC: signing zone");
 		ret = knot_dnssec_zone_sign(zone->contents, zone->conf,
 		                            &ch, KNOT_SOA_SERIAL_UPDATE,
 		                            &refresh_at);
@@ -515,7 +515,7 @@ static int event_dnssec(zone_t *zone)
 		zone_contents_t *new_contents = NULL;
 		int ret = apply_changeset(zone, &ch, &new_contents);
 		if (ret != KNOT_EOK) {
-			log_zone_error(zone->name, "DNSSEC, could not sign zone (%s)",
+			log_zone_error(zone->name, "DNSSEC: could not sign zone (%s)",
 				       knot_strerror(ret));
 			goto done;
 		}
@@ -523,7 +523,7 @@ static int event_dnssec(zone_t *zone)
 		/* Write change to journal. */
 		ret = zone_change_store(zone, &ch);
 		if (ret != KNOT_EOK) {
-			log_zone_error(zone->name, "DNSSEC, could not sign zone (%s)",
+			log_zone_error(zone->name, "DNSSEC: could not sign zone (%s)",
 				       knot_strerror(ret));
 			update_rollback(&ch);
 			update_free_zone(&new_contents);
diff --git a/src/libknot/packet/pkt.c b/src/libknot/packet/pkt.c
index 13a702d170c05e5298c2d929d24e190585661168..00f3e099855fa948afbc5924a1d3fb05b75f6d6a 100644
--- a/src/libknot/packet/pkt.c
+++ b/src/libknot/packet/pkt.c
@@ -655,6 +655,49 @@ static int knot_pkt_rr_from_wire(const uint8_t *wire, size_t *pos,
 	return KNOT_EOK;
 }
 
+/* \note Private for check_rr_constraints(). */
+#define CHECK_AR_CONSTRAINTS(pkt, rr, var, check_func) \
+	if ((pkt)->current != KNOT_ADDITIONAL) { \
+		dbg_packet("%s: RRTYPE%u not in AR\n", __func__, rr->type); \
+		return KNOT_EMALF; \
+	} else if ((pkt)->var != NULL) { \
+		dbg_packet("%s: found 2nd RRTYPE%u\n", __func__, rr->type); \
+		return KNOT_EMALF; \
+	} else if (!check_func(rr)) { \
+		dbg_packet("%s: bad RRTYPE%u RDATA\n", __func__, rr->type); \
+		return KNOT_EMALF; \
+	} else { \
+		(pkt)->var = rr; \
+	}
+
+/*! \brief Check constraints (position, uniqueness, validity) for special types (TSIG, OPT). */
+static int check_rr_constraints(knot_pkt_t *pkt, knot_rrset_t *rr, size_t rr_size, unsigned flags)
+{
+	/* Check RR constraints. */
+	switch(rr->type) {
+	case KNOT_RRTYPE_TSIG:
+		CHECK_AR_CONSTRAINTS(pkt, rr, tsig_rr, tsig_rdata_is_ok);
+
+		/* Strip TSIG RR from wireformat and decrease ARCOUNT. */
+		if (!(flags & KNOT_PF_KEEPWIRE)) {
+			pkt->parsed -= rr_size;
+			pkt->size -= rr_size;
+			knot_wire_set_id(pkt->wire, tsig_rdata_orig_id(rr));
+			knot_wire_set_arcount(pkt->wire, knot_wire_get_arcount(pkt->wire) - 1);
+		}
+		break;
+	case KNOT_RRTYPE_OPT:
+		CHECK_AR_CONSTRAINTS(pkt, rr, opt_rr, knot_edns_check_record);
+		break;
+	default:
+		break;
+	}
+
+	return KNOT_EOK;
+}
+
+#undef CHECK_AR_RECORD
+
 int knot_pkt_parse_rr(knot_pkt_t *pkt, unsigned flags)
 {
 	dbg_packet("%s(%p, %u)\n", __func__, pkt, flags);
@@ -688,53 +731,10 @@ int knot_pkt_parse_rr(knot_pkt_t *pkt, unsigned flags)
 
 	/* Update packet RRSet count. */
 	++pkt->rrset_count;
-
-	/* Update section RRSet count. */
 	++pkt->sections[pkt->current].count;
 
-	/* Check RR constraints. */
-	switch(rr->type) {
-	case KNOT_RRTYPE_TSIG:
-		// if there is some TSIG already, treat as malformed
-		if (pkt->tsig_rr != NULL) {
-			dbg_packet("%s: found 2nd TSIG\n", __func__);
-			return KNOT_EMALF;
-		} else if (!tsig_rdata_is_ok(rr)) {
-			dbg_packet("%s: bad TSIG RDATA\n", __func__);
-			return KNOT_EMALF;
-		}
-
-		/* Strip TSIG RR from wireformat and decrease ARCOUNT. */
-		if (!(flags & KNOT_PF_KEEPWIRE)) {
-			pkt->parsed -= rr_size;
-			pkt->size -= rr_size;
-			knot_wire_set_id(pkt->wire, tsig_rdata_orig_id(rr));
-			knot_wire_set_arcount(pkt->wire, knot_wire_get_arcount(pkt->wire) - 1);
-		}
-
-		/* Remember TSIG RR. */
-		pkt->tsig_rr = rr;
-		break;
-	case KNOT_RRTYPE_OPT:
-		/* If there is some OPT already, treat as malformed. */
-		if (pkt->opt_rr != NULL) {
-			dbg_packet("%s: found 2nd OPT\n", __func__);
-			return KNOT_EMALF;
-		}
-
-		/* Semantic checks for the OPT. */
-		if (!knot_edns_check_record(rr)) {
-			dbg_packet("%s: OPT RR check failed\n", __func__);
-			return KNOT_EMALF;
-		}
-
-		pkt->opt_rr = rr;
-		break;
-	default:
-		break;
-	}
-
-	return ret;
+	/* Check special RRs (OPT and TSIG). */
+	return check_rr_constraints(pkt, rr, rr_size, flags);
 }
 
 int knot_pkt_parse_section(knot_pkt_t *pkt, unsigned flags)
diff --git a/src/utils/nsupdate/nsupdate_exec.c b/src/utils/nsupdate/nsupdate_exec.c
index faffee39f8f2de166b5b4076f718c365fce5a867..0948812899a39963c302ace01fc35f3742462ea0 100644
--- a/src/utils/nsupdate/nsupdate_exec.c
+++ b/src/utils/nsupdate/nsupdate_exec.c
@@ -141,11 +141,7 @@ static int dname_isvalid(const char *lp, size_t len) {
 /* This is probably redundant, but should be a bit faster so let's keep it. */
 static int parse_full_rr(zs_scanner_t *s, const char* lp)
 {
-	if (zs_scanner_parse(s, lp, lp + strlen(lp), 0) < 0) {
-		return KNOT_EPARSEFAIL;
-	}
-	char nl = '\n'; /* Ensure newline after complete RR */
-	if (zs_scanner_parse(s, &nl, &nl+sizeof(char), 1) < 0) { /* Terminate */
+	if (zs_scanner_parse(s, lp, lp + strlen(lp), true) < 0) {
 		return KNOT_EPARSEFAIL;
 	}
 
@@ -264,7 +260,7 @@ static int parse_partial_rr(zs_scanner_t *s, const char *lp, unsigned flags) {
 	/* Need to parse rdata, synthetize input. */
 	char *rr = sprintf_alloc("%s %u %s %s %s\n",
 	                         owner_s, s->r_ttl, b1, b2, lp);
-	if (rr == NULL || zs_scanner_parse(s, rr, rr + strlen(rr), 1) < 0) {
+	if (rr == NULL || zs_scanner_parse(s, rr, rr + strlen(rr), true) < 0) {
 		ret = KNOT_EPARSEFAIL;
 	}
 
diff --git a/src/utils/nsupdate/nsupdate_params.c b/src/utils/nsupdate/nsupdate_params.c
index 43212b00bd2d7a6be60e003ce01c9ba6ff493433..1a0d4d2fbf5f5e9c31098d6a97dfbbc61dd4ff57 100644
--- a/src/utils/nsupdate/nsupdate_params.c
+++ b/src/utils/nsupdate/nsupdate_params.c
@@ -72,8 +72,8 @@ static int parser_set_default(zs_scanner_t *s, const char *fmt, ...)
 		return KNOT_ESPACE;
 	}
 
-	/* fmt must contain newline */
-	if (zs_scanner_parse(s, buf, buf + n, 1) < 0) {
+	/* Buffer must contain newline */
+	if (zs_scanner_parse(s, buf, buf + n, true) < 0) {
 		return KNOT_EPARSEFAIL;
 	}
 
diff --git a/src/zscanner/scanner.c.g2 b/src/zscanner/scanner.c.g2
index 48340b17b65f67a5b0eb72ba232fe47996e9b5f9..96f2b85401fd8155acb96215b02af1954e09033a 100644
--- a/src/zscanner/scanner.c.g2
+++ b/src/zscanner/scanner.c.g2
@@ -160,15 +160,11 @@ void zs_scanner_free(zs_scanner_t *s)
 	}
 }
 
-int zs_scanner_parse(zs_scanner_t *s,
-                     const char   *start,
-                     const char   *end,
-                     const bool   final_block)
+static void parse_block(zs_scanner_t *s,
+                        const char   *start,
+                        const char   *end,
+                        const bool   is_eof)
 {
-	if (s == NULL || start == NULL || end == NULL) {
-		return -1;
-	}
-
 	// Necessary scanner variables.
 	const char *p = start;
 	const char *pe = end;
@@ -194,7 +190,7 @@ int zs_scanner_parse(zs_scanner_t *s,
 	memcpy(stack, s->stack, sizeof(stack));
 
 	// End of file check.
-	if (final_block == true) {
+	if (is_eof) {
 		eof = (char *)pe;
 	}
 
@@ -1374,7 +1370,7 @@ tr81:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	{
@@ -11555,7 +11551,7 @@ tr93:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1057;
@@ -11578,7 +11574,7 @@ tr657:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1057;
@@ -17722,7 +17718,7 @@ tr129:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1058;
@@ -17749,7 +17745,7 @@ tr123:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1058;
@@ -18441,7 +18437,7 @@ tr706:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1059;
@@ -18471,7 +18467,7 @@ tr701:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1059;
@@ -18904,7 +18900,7 @@ tr670:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1061;
@@ -18926,7 +18922,7 @@ tr695:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1061;
@@ -18978,7 +18974,7 @@ tr3204:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	{
@@ -19006,7 +19002,7 @@ tr3227:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	{
@@ -20115,7 +20111,7 @@ tr90:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	{
@@ -20289,7 +20285,7 @@ tr659:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	{
@@ -20856,7 +20852,7 @@ tr661:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1063;
@@ -20948,7 +20944,7 @@ tr666:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1063;
@@ -22843,7 +22839,7 @@ tr680:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1064;
@@ -22869,7 +22865,7 @@ tr712:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1064;
@@ -24031,7 +24027,7 @@ tr719:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1065;
@@ -24130,7 +24126,7 @@ tr714:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	goto st1065;
@@ -28759,7 +28755,7 @@ tr776:
 
 		// In case of serious error, stop scanner.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	{
@@ -28787,7 +28783,7 @@ tr778:
 
 		// In case of serious error, stop scanner.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	{
@@ -31115,11 +31111,18 @@ tr902:
 		if (ss != NULL) {
 			// Parse included zone file.
 			ret = zs_scanner_parse_file(ss, (char*)(s->buffer));
-			zs_scanner_free(ss);
 			if (ret != 0) {
-				ERR(ZS_UNPROCESSED_INCLUDE);
+				// File internal errors are handled by error callback.
+				if (ss->error_counter > 0) {
+					ERR(ZS_UNPROCESSED_INCLUDE);
+				// General include file error.
+				} else {
+					ERR(ss->error_code);
+				}
+				zs_scanner_free(ss);
 				p--; {goto st246;}
 			}
+			zs_scanner_free(ss);
 		} else {
 			ERR(ZS_UNPROCESSED_INCLUDE);
 			p--; {goto st246;}
@@ -31166,11 +31169,18 @@ tr912:
 		if (ss != NULL) {
 			// Parse included zone file.
 			ret = zs_scanner_parse_file(ss, (char*)(s->buffer));
-			zs_scanner_free(ss);
 			if (ret != 0) {
-				ERR(ZS_UNPROCESSED_INCLUDE);
+				// File internal errors are handled by error callback.
+				if (ss->error_counter > 0) {
+					ERR(ZS_UNPROCESSED_INCLUDE);
+				// General include file error.
+				} else {
+					ERR(ss->error_code);
+				}
+				zs_scanner_free(ss);
 				p--; {goto st246;}
 			}
+			zs_scanner_free(ss);
 		} else {
 			ERR(ZS_UNPROCESSED_INCLUDE);
 			p--; {goto st246;}
@@ -31223,11 +31233,18 @@ tr924:
 		if (ss != NULL) {
 			// Parse included zone file.
 			ret = zs_scanner_parse_file(ss, (char*)(s->buffer));
-			zs_scanner_free(ss);
 			if (ret != 0) {
-				ERR(ZS_UNPROCESSED_INCLUDE);
+				// File internal errors are handled by error callback.
+				if (ss->error_counter > 0) {
+					ERR(ZS_UNPROCESSED_INCLUDE);
+				// General include file error.
+				} else {
+					ERR(ss->error_code);
+				}
+				zs_scanner_free(ss);
 				p--; {goto st246;}
 			}
+			zs_scanner_free(ss);
 		} else {
 			ERR(ZS_UNPROCESSED_INCLUDE);
 			p--; {goto st246;}
@@ -31490,11 +31507,18 @@ tr936:
 		if (ss != NULL) {
 			// Parse included zone file.
 			ret = zs_scanner_parse_file(ss, (char*)(s->buffer));
-			zs_scanner_free(ss);
 			if (ret != 0) {
-				ERR(ZS_UNPROCESSED_INCLUDE);
+				// File internal errors are handled by error callback.
+				if (ss->error_counter > 0) {
+					ERR(ZS_UNPROCESSED_INCLUDE);
+				// General include file error.
+				} else {
+					ERR(ss->error_code);
+				}
+				zs_scanner_free(ss);
 				p--; {goto st246;}
 			}
+			zs_scanner_free(ss);
 		} else {
 			ERR(ZS_UNPROCESSED_INCLUDE);
 			p--; {goto st246;}
@@ -73028,11 +73052,11 @@ case 1140:
 		// Processing error.
 		s->process_error(s);
 
-		return -1;
+		return;
 	}
 
 	// Check unclosed multiline record.
-	if (final_block && s->multiline) {
+	if (is_eof && s->multiline) {
 		ERR(ZS_UNCLOSED_MULTILINE);
 		s->error_counter++;
 		s->process_error(s);
@@ -73045,6 +73069,24 @@ case 1140:
 
 	// Storing r_data pointer.
 	s->r_data_tail = rdata_tail - s->r_data;
+}
+
+int zs_scanner_parse(zs_scanner_t *s,
+                     const char   *start,
+                     const char   *end,
+                     const bool   final_block)
+{
+	if (s == NULL || start == NULL || end == NULL) {
+		return -1;
+	}
+
+	// Parse input block.
+	parse_block(s, start, end, false);
+
+	// Parse trailing artificial block (newline char) if not stop.
+	if (final_block && !s->stop) {
+		parse_block(s, NEWLINE_BLOCK, NEWLINE_BLOCK + 1, true);
+	}
 
 	// Check if any errors has occured.
 	if (s->error_counter > 0) {
@@ -73144,13 +73186,7 @@ int zs_scanner_parse_file(zs_scanner_t *s,
 		}
 
 		// Scan zone file block.
-		zs_scanner_parse(s, data, data + block_size, false);
-
-		// Process the last artificial block (newline char) if not fatal.
-		if (final_block == true && s->stop == 0) {
-			zs_scanner_parse(s, NEWLINE_BLOCK, NEWLINE_BLOCK + 1,
-			                 true);
-		}
+		zs_scanner_parse(s, data, data + block_size, final_block);
 
 		// Zone file block unmapping.
 		if (munmap(data, block_size) == -1) {
@@ -73159,16 +73195,20 @@ int zs_scanner_parse_file(zs_scanner_t *s,
 			free(s->file.name);
 			return -1;
 		}
+
+		// Stop parsing if required.
+		if (s->stop) {
+			break;
+		}
 	}
 
+	close(s->file.descriptor);
+	free(s->file.name);
+
 	// Check for scanner return.
 	if (s->error_counter > 0) {
-		close(s->file.descriptor);
-		free(s->file.name);
 		return -1;
 	}
 
-	close(s->file.descriptor);
-	free(s->file.name);
 	return 0;
 }
diff --git a/src/zscanner/scanner.c.t0 b/src/zscanner/scanner.c.t0
index e94d48e33b97feee79d65ef1563206f3dfcc64a2..44af7e21f9d14f5fd26577bd861a7b44430482ab 100644
--- a/src/zscanner/scanner.c.t0
+++ b/src/zscanner/scanner.c.t0
@@ -4951,15 +4951,11 @@ void zs_scanner_free(zs_scanner_t *s)
 	}
 }
 
-int zs_scanner_parse(zs_scanner_t *s,
-                     const char   *start,
-                     const char   *end,
-                     const bool   final_block)
+static void parse_block(zs_scanner_t *s,
+                        const char   *start,
+                        const char   *end,
+                        const bool   is_eof)
 {
-	if (s == NULL || start == NULL || end == NULL) {
-		return -1;
-	}
-
 	// Necessary scanner variables.
 	const char *p = start;
 	const char *pe = end;
@@ -4985,7 +4981,7 @@ int zs_scanner_parse(zs_scanner_t *s,
 	memcpy(stack, s->stack, sizeof(stack));
 
 	// End of file check.
-	if (final_block == true) {
+	if (is_eof) {
 		eof = (char *)pe;
 	}
 
@@ -5253,7 +5249,7 @@ _match:
 
 		// In case of serious error, stop scanner.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	break;
@@ -5824,11 +5820,18 @@ _match:
 		if (ss != NULL) {
 			// Parse included zone file.
 			ret = zs_scanner_parse_file(ss, (char*)(s->buffer));
-			zs_scanner_free(ss);
 			if (ret != 0) {
-				ERR(ZS_UNPROCESSED_INCLUDE);
+				// File internal errors are handled by error callback.
+				if (ss->error_counter > 0) {
+					ERR(ZS_UNPROCESSED_INCLUDE);
+				// General include file error.
+				} else {
+					ERR(ss->error_code);
+				}
+				zs_scanner_free(ss);
 				p--; {cs = 246; goto _again;}
 			}
+			zs_scanner_free(ss);
 		} else {
 			ERR(ZS_UNPROCESSED_INCLUDE);
 			p--; {cs = 246; goto _again;}
@@ -7115,7 +7118,7 @@ _match:
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 	break;
@@ -7370,11 +7373,11 @@ _again:
 		// Processing error.
 		s->process_error(s);
 
-		return -1;
+		return;
 	}
 
 	// Check unclosed multiline record.
-	if (final_block && s->multiline) {
+	if (is_eof && s->multiline) {
 		ERR(ZS_UNCLOSED_MULTILINE);
 		s->error_counter++;
 		s->process_error(s);
@@ -7387,6 +7390,24 @@ _again:
 
 	// Storing r_data pointer.
 	s->r_data_tail = rdata_tail - s->r_data;
+}
+
+int zs_scanner_parse(zs_scanner_t *s,
+                     const char   *start,
+                     const char   *end,
+                     const bool   final_block)
+{
+	if (s == NULL || start == NULL || end == NULL) {
+		return -1;
+	}
+
+	// Parse input block.
+	parse_block(s, start, end, false);
+
+	// Parse trailing artificial block (newline char) if not stop.
+	if (final_block && !s->stop) {
+		parse_block(s, NEWLINE_BLOCK, NEWLINE_BLOCK + 1, true);
+	}
 
 	// Check if any errors has occured.
 	if (s->error_counter > 0) {
@@ -7486,13 +7507,7 @@ int zs_scanner_parse_file(zs_scanner_t *s,
 		}
 
 		// Scan zone file block.
-		zs_scanner_parse(s, data, data + block_size, false);
-
-		// Process the last artificial block (newline char) if not fatal.
-		if (final_block == true && s->stop == 0) {
-			zs_scanner_parse(s, NEWLINE_BLOCK, NEWLINE_BLOCK + 1,
-			                 true);
-		}
+		zs_scanner_parse(s, data, data + block_size, final_block);
 
 		// Zone file block unmapping.
 		if (munmap(data, block_size) == -1) {
@@ -7501,16 +7516,20 @@ int zs_scanner_parse_file(zs_scanner_t *s,
 			free(s->file.name);
 			return -1;
 		}
+
+		// Stop parsing if required.
+		if (s->stop) {
+			break;
+		}
 	}
 
+	close(s->file.descriptor);
+	free(s->file.name);
+
 	// Check for scanner return.
 	if (s->error_counter > 0) {
-		close(s->file.descriptor);
-		free(s->file.name);
 		return -1;
 	}
 
-	close(s->file.descriptor);
-	free(s->file.name);
 	return 0;
 }
diff --git a/src/zscanner/scanner.rl b/src/zscanner/scanner.rl
index 0e2d9d60e5d8cbae633df73688c6b9e8dfe4eafc..2bcca2a16ed0191a1412a26db63a7ba37de12c73 100644
--- a/src/zscanner/scanner.rl
+++ b/src/zscanner/scanner.rl
@@ -159,15 +159,11 @@ void zs_scanner_free(zs_scanner_t *s)
 	}
 }
 
-int zs_scanner_parse(zs_scanner_t *s,
-                     const char   *start,
-                     const char   *end,
-                     const bool   final_block)
+static void parse_block(zs_scanner_t *s,
+                        const char   *start,
+                        const char   *end,
+                        const bool   is_eof)
 {
-	if (s == NULL || start == NULL || end == NULL) {
-		return -1;
-	}
-
 	// Necessary scanner variables.
 	const char *p = start;
 	const char *pe = end;
@@ -193,7 +189,7 @@ int zs_scanner_parse(zs_scanner_t *s,
 	memcpy(stack, s->stack, sizeof(stack));
 
 	// End of file check.
-	if (final_block == true) {
+	if (is_eof) {
 		eof = (char *)pe;
 	}
 
@@ -224,11 +220,11 @@ int zs_scanner_parse(zs_scanner_t *s,
 		// Processing error.
 		s->process_error(s);
 
-		return -1;
+		return;
 	}
 
 	// Check unclosed multiline record.
-	if (final_block && s->multiline) {
+	if (is_eof && s->multiline) {
 		ERR(ZS_UNCLOSED_MULTILINE);
 		s->error_counter++;
 		s->process_error(s);
@@ -241,6 +237,24 @@ int zs_scanner_parse(zs_scanner_t *s,
 
 	// Storing r_data pointer.
 	s->r_data_tail = rdata_tail - s->r_data;
+}
+
+int zs_scanner_parse(zs_scanner_t *s,
+                     const char   *start,
+                     const char   *end,
+                     const bool   final_block)
+{
+	if (s == NULL || start == NULL || end == NULL) {
+		return -1;
+	}
+
+	// Parse input block.
+	parse_block(s, start, end, false);
+
+	// Parse trailing artificial block (newline char) if not stop.
+	if (final_block && !s->stop) {
+		parse_block(s, NEWLINE_BLOCK, NEWLINE_BLOCK + 1, true);
+	}
 
 	// Check if any errors has occured.
 	if (s->error_counter > 0) {
@@ -340,13 +354,7 @@ int zs_scanner_parse_file(zs_scanner_t *s,
 		}
 
 		// Scan zone file block.
-		zs_scanner_parse(s, data, data + block_size, false);
-
-		// Process the last artificial block (newline char) if not fatal.
-		if (final_block == true && s->stop == 0) {
-			zs_scanner_parse(s, NEWLINE_BLOCK, NEWLINE_BLOCK + 1,
-			                 true);
-		}
+		zs_scanner_parse(s, data, data + block_size, final_block);
 
 		// Zone file block unmapping.
 		if (munmap(data, block_size) == -1) {
@@ -355,16 +363,20 @@ int zs_scanner_parse_file(zs_scanner_t *s,
 			free(s->file.name);
 			return -1;
 		}
+
+		// Stop parsing if required.
+		if (s->stop) {
+			break;
+		}
 	}
 
+	close(s->file.descriptor);
+	free(s->file.name);
+
 	// Check for scanner return.
 	if (s->error_counter > 0) {
-		close(s->file.descriptor);
-		free(s->file.name);
 		return -1;
 	}
 
-	close(s->file.descriptor);
-	free(s->file.name);
 	return 0;
 }
diff --git a/src/zscanner/scanner_body.rl b/src/zscanner/scanner_body.rl
index 774b6a63e2a5bbb7b498a8d0cd6e07ef9e025a09..71bbe0ee6fff5a1a8f7e24bb51ae9216d82451dc 100644
--- a/src/zscanner/scanner_body.rl
+++ b/src/zscanner/scanner_body.rl
@@ -95,7 +95,7 @@
 
 		// In case of serious error, stop scanner.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 
@@ -671,11 +671,18 @@
 		if (ss != NULL) {
 			// Parse included zone file.
 			ret = zs_scanner_parse_file(ss, (char*)(s->buffer));
-			zs_scanner_free(ss);
 			if (ret != 0) {
-				ERR(ZS_UNPROCESSED_INCLUDE);
+				// File internal errors are handled by error callback.
+				if (ss->error_counter > 0) {
+					ERR(ZS_UNPROCESSED_INCLUDE);
+				// General include file error.
+				} else {
+					ERR(ss->error_code);
+				}
+				zs_scanner_free(ss);
 				fhold; fgoto err_line;
 			}
+			zs_scanner_free(ss);
 		} else {
 			ERR(ZS_UNPROCESSED_INCLUDE);
 			fhold; fgoto err_line;
@@ -1905,7 +1912,7 @@
 
 		// Stop scanner if required.
 		if (s->stop == true) {
-			return -1;
+			return;
 		}
 	}
 
diff --git a/src/zscanner/tests/data/06-3_INCLUDE.out b/src/zscanner/tests/data/06-3_INCLUDE.out
index 965597d62c1a81c0d6b08a538dc91bb9e11118d5..8a5289b0bca31bf9482c21fa6ba07290f39d947d 100644
--- a/src/zscanner/tests/data/06-3_INCLUDE.out
+++ b/src/zscanner/tests/data/06-3_INCLUDE.out
@@ -1,2 +1,2 @@
-ERROR=ZS_UNPROCESSED_INCLUDE
+ERROR=ZS_FILE_DIRECTORY
 ------
diff --git a/src/zscanner/tests/data/06-4_INCLUDE.out b/src/zscanner/tests/data/06-4_INCLUDE.out
index 965597d62c1a81c0d6b08a538dc91bb9e11118d5..e09e5d1cfc18ed8606c48a1395e3c7603b9de72d 100644
--- a/src/zscanner/tests/data/06-4_INCLUDE.out
+++ b/src/zscanner/tests/data/06-4_INCLUDE.out
@@ -1,2 +1,2 @@
-ERROR=ZS_UNPROCESSED_INCLUDE
+ERROR=ZS_FILE_OPEN
 ------
diff --git a/tests-extra/tests/dnssec/no_resign/test.py b/tests-extra/tests/dnssec/no_resign/test.py
index 7e344180df5f9770c13125d4e9c26842ebe29d44..b6b7395d179e134a1523c29f39b10a56261e10e7 100644
--- a/tests-extra/tests/dnssec/no_resign/test.py
+++ b/tests-extra/tests/dnssec/no_resign/test.py
@@ -24,6 +24,7 @@ master.dnssec_enable = True
 master.use_keys(nsec_zone)
 master.use_keys(nsec3_zone)
 master.gen_confile()
+t.sleep(2)
 master.reload()
 
 t.sleep(4)
diff --git a/tests-extra/tests/edns/version/test.py b/tests-extra/tests/edns/version/test.py
index 7307567698dacb725507552d0a6095f35a60e8bf..69dacb4b561721a2394f66c4bc88a801297e5af9 100644
--- a/tests-extra/tests/edns/version/test.py
+++ b/tests-extra/tests/edns/version/test.py
@@ -15,10 +15,10 @@ t.start()
 
 # Supported EDNS version 0.
 resp = server.dig("example.com", "SOA", edns=0)
-resp.check(rcode="NOERROR")
+resp.check(rcode="NOERROR", edns_version=0)
 
 # Unsupported EDNS version 1.
 resp = server.dig("example.com", "SOA", edns=1)
-resp.check(rcode="BADVERS")
+resp.check(rcode="BADVERS", edns_version=0)
 
 t.end()
diff --git a/tests-extra/tools/dnstest/response.py b/tests-extra/tools/dnstest/response.py
index 41cebc32515725ece2ea8d4108f1e5791e290bfe..51b014f7fbcf1a6ff693dcc5ba5341e971479fe0 100644
--- a/tests-extra/tools/dnstest/response.py
+++ b/tests-extra/tools/dnstest/response.py
@@ -8,8 +8,9 @@ from dnstest.utils import *
 class Response(object):
     '''Dig output context.'''
 
-    def __init__(self, server, response, args):
+    def __init__(self, server, response, query, args):
         self.resp = response
+        self.query = query
         self.args = args
         self.srv = server
 
@@ -113,13 +114,17 @@ class Response(object):
                         return
 
     def check(self, rdata=None, ttl=None, rcode="NOERROR", nordata=None,
-              flags="", noflags="", eflags="", noeflags=""):
+              edns_version=None, flags="", noflags="", eflags="", noeflags=""):
         '''Flags are text strings separated by whitespace character'''
 
         self._check_flags(flags, noflags)
         self._check_eflags(eflags, noeflags)
         self._check_question()
 
+        # Check EDNS version.
+        edns_ver = int(edns_version) if edns_version != None else self.query.edns
+        compare(edns_ver, self.resp.edns, "EDNS VERSION")
+
         # Check rcode.
         if type(rcode) is not str:
             rc = dns.rcode.to_text(rcode)
diff --git a/tests-extra/tools/dnstest/server.py b/tests-extra/tools/dnstest/server.py
index f362346f590d52ea139f0d5771aa451e5407c270..5fa5adc762f4830820d23056c5e85219a477126c 100644
--- a/tests-extra/tools/dnstest/server.py
+++ b/tests-extra/tools/dnstest/server.py
@@ -525,7 +525,7 @@ class Server(object):
                 if not log_no_sep:
                     detail_log(SEP)
 
-                return dnstest.response.Response(self, resp, args)
+                return dnstest.response.Response(self, resp, query, args)
             except dns.exception.Timeout:
                 pass
             except:
@@ -634,7 +634,7 @@ class Server(object):
 
         src_files = os.listdir(zone.key_dir)
         for file_name in src_files:
-            if zone.name[:-1] in file_name:
+            if (zone.name[:-1]).lower() in file_name:
                 full_file_name = os.path.join(zone.key_dir, file_name)
                 if (os.path.isfile(full_file_name)):
                     shutil.copy(full_file_name, self.keydir)