From b5144390fe90bc651a54aac13cfb49e31dcc2066 Mon Sep 17 00:00:00 2001
From: Jan Kadlec <jan.kadlec@nic.cz>
Date: Mon, 24 Feb 2014 12:32:14 +0100
Subject: [PATCH] Parse RRs with 0 length and store TTL into them.

- Most changes were in ddns.c: Empty checks used rr_count == 0
---
 src/knot/updates/ddns.c  | 38 ++++++++++++++++----------------------
 src/libknot/edns.c       | 18 ++++++++----------
 src/libknot/edns.h       |  3 +--
 src/libknot/packet/pkt.c | 14 ++++++--------
 src/libknot/rrset.c      | 10 ++--------
 5 files changed, 33 insertions(+), 50 deletions(-)

diff --git a/src/knot/updates/ddns.c b/src/knot/updates/ddns.c
index 540919317..714e55d9b 100644
--- a/src/knot/updates/ddns.c
+++ b/src/knot/updates/ddns.c
@@ -30,6 +30,18 @@
 #include "knot/updates/xfr-in.h"
 #include "common/descriptor.h"
 
+static bool rrset_empty(const knot_rrset_t *rrset)
+{
+	uint16_t rr_count = knot_rrset_rr_count(rrset);
+	if (rr_count == 0) {
+		return true;
+	}
+	if (rr_count == 1) {
+		return knot_rrset_rr_size(rrset, 0) == 0;
+	}
+	return false;
+}
+
 /*----------------------------------------------------------------------------*/
 // Copied from XFR - maybe extract somewhere else
 static int knot_ddns_prereq_check_rrsets(knot_rrset_t ***rrsets,
@@ -143,7 +155,7 @@ static int knot_ddns_add_prereq(knot_ddns_prereq_t *prereqs,
 	int ret;
 
 	if (knot_rrset_class(rrset) == KNOT_CLASS_ANY) {
-		if (knot_rrset_rr_count(rrset)) {
+		if (!rrset_empty(rrset)) {
 			dbg_ddns("ddns: add_prereq: Extra data\n");
 			return KNOT_EMALF;
 		}
@@ -159,7 +171,7 @@ static int knot_ddns_add_prereq(knot_ddns_prereq_t *prereqs,
 			                                &prereqs->exist_allocd);
 		}
 	} else if (knot_rrset_class(rrset) == KNOT_CLASS_NONE) {
-		if (knot_rrset_rr_count(rrset)) {
+		if (!rrset_empty(rrset)) {
 			dbg_ddns("ddns: add_prereq: Extra data\n");
 			return KNOT_EMALF;
 		}
@@ -195,7 +207,6 @@ static int knot_ddns_check_exist(const knot_zone_contents_t *zone,
 	assert(zone != NULL);
 	assert(rrset != NULL);
 	assert(rcode != NULL);
-	assert(knot_rrset_rr_count(rrset) == 0);
 	assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY);
 	assert(knot_rrset_class(rrset) == KNOT_CLASS_ANY);
 
@@ -269,7 +280,6 @@ static int knot_ddns_check_not_exist(const knot_zone_contents_t *zone,
 	assert(zone != NULL);
 	assert(rrset != NULL);
 	assert(rcode != NULL);
-	assert(knot_rrset_rr_count(rrset) == 0);
 	assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY);
 	assert(knot_rrset_class(rrset) == KNOT_CLASS_NONE);
 
@@ -505,7 +515,7 @@ static int knot_ddns_check_update(const knot_rrset_t *rrset,
 			return KNOT_EMALF;
 		}
 	} else if (knot_rrset_class(rrset) == KNOT_CLASS_ANY) {
-		if (knot_rrset_rr_count(rrset)
+		if (!rrset_empty(rrset)
 		    || (knot_rrtype_is_metatype(knot_rrset_type(rrset))
 		        && knot_rrset_type(rrset) != KNOT_RRTYPE_ANY)) {
 			*rcode = KNOT_RCODE_FORMERR;
@@ -607,7 +617,7 @@ dbg_ddns_exec_detail(
 );
 		if (knot_dname_is_equal(knot_rrset_owner(rrset), owner)) {
 			// Removing one or all RRSets
-			if ((knot_rrset_rr_count(rr) == 0)
+			if (rrset_empty(rr)
 			    && (knot_rrset_type(rr) == knot_rrset_type(rrset)
 			        || knot_rrset_type(rr) == KNOT_RRTYPE_ANY)) {
 				dbg_ddns_detail("Removing one or all RRSets\n");
@@ -719,21 +729,6 @@ static int knot_ddns_process_add_cname(knot_node_t *node,
 			return ret;
 		}
 
-		/* TODO: signing will take care of this. If signing is off, then, oh well. */
-//		if (knot_node_rrtype_is_signed(node, removed->type)) {
-//			assert(0);
-//			ret = knot_changes_add_rrset(changes,
-//			                             removed->rrsigs,
-//			                             KNOT_CHANGES_OLD);
-//			if (ret != KNOT_EOK) {
-//				dbg_ddns("Failed to add removed RRSIGs to "
-//				         "'changes': %s\n", knot_strerror(ret));
-//				return ret;
-//			}
-//			/* Disconnect RRsigs from rrset. */
-//			knot_rrset_set_rrsigs(removed, NULL);
-//		}
-
 		/* c) And remove it from the node. */
 		UNUSED(knot_node_remove_rrset(node, KNOT_RRTYPE_CNAME));
 
@@ -1633,7 +1628,6 @@ static int knot_ddns_process_rr(const knot_rrset_t *rr,
 			                                   changes);
 		}
 	} else {
-		assert(0);
 		return KNOT_ERROR;
 	}
 }
diff --git a/src/libknot/edns.c b/src/libknot/edns.c
index 5a82f9ab2..2df9efa0e 100644
--- a/src/libknot/edns.c
+++ b/src/libknot/edns.c
@@ -52,11 +52,11 @@ knot_opt_rr_t *knot_edns_new()
 
 /*----------------------------------------------------------------------------*/
 
-int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, const knot_rrset_t *rrset,
-                          uint32_t rr_ttl)
+int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, const knot_rrset_t *rrset)
 {
 	if (opt_rr == NULL || rrset == NULL
-	    || knot_rrset_type(rrset) != KNOT_RRTYPE_OPT) {
+	    || knot_rrset_type(rrset) != KNOT_RRTYPE_OPT ||
+	    knot_rrset_rr_count(rrset) == 0) {
 		return KNOT_EINVAL;
 	}
 
@@ -68,10 +68,10 @@ int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, const knot_rrset_t *rrset,
 		opt_rr->payload = EDNS_MIN_UDP_PAYLOAD;
 	}
 
-	// the TTL has switched bytes
+	// TTL has switched bytes
 	uint32_t ttl;
-	dbg_edns_detail("TTL: %u\n", rr_ttl);
-	knot_wire_write_u32((uint8_t *)&ttl, rr_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));
 	// first byte of TTL is extended RCODE
 	dbg_edns_detail("TTL: %u\n", ttl);
 	memcpy(&opt_rr->ext_rcode, &ttl, 1);
@@ -87,12 +87,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");
-	uint8_t *raw = knot_rrset_rr_rdata(rrset, 0);
 	uint16_t size = knot_rrset_rr_size(rrset, 0);
-
-	if (raw != NULL) {
+	if (size > 0) {
+		uint8_t *raw = knot_rrset_rr_rdata(rrset, 0);
 		size_t pos = 0;
-		assert(size > 0);
 		while (pos < size) {
 			// ensure there is enough data to parse the OPTION CODE
 			// and OPTION LENGTH
diff --git a/src/libknot/edns.h b/src/libknot/edns.h
index cc7cfc943..1518080b5 100644
--- a/src/libknot/edns.h
+++ b/src/libknot/edns.h
@@ -110,8 +110,7 @@ knot_opt_rr_t *knot_edns_new();
  * \retval KNOT_EINVAL
  * \retval KNOT_EMALF
  */
-int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, const knot_rrset_t *rrset,
-                          uint32_t rr_ttl);
+int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, const knot_rrset_t *rrset);
 
 /*!
  * \brief Returns the UDP payload stored in the OPT RR.
diff --git a/src/libknot/packet/pkt.c b/src/libknot/packet/pkt.c
index d10512e9a..bbcd5dba1 100644
--- a/src/libknot/packet/pkt.c
+++ b/src/libknot/packet/pkt.c
@@ -670,8 +670,7 @@ static int knot_pkt_merge_rr(knot_pkt_t *pkt, knot_rrset_t *rr, unsigned flags)
  *        should be copied if they are supposed to be stored in zone permanently.
  */
 static knot_rrset_t *knot_pkt_rr_from_wire(const uint8_t *wire, size_t *pos,
-                                           size_t size, uint32_t *ttl,
-                                           mm_ctx_t *mm)
+                                           size_t size, mm_ctx_t *mm)
 {
 	dbg_packet("%s(%p, %zu, %zu)\n", __func__, wire, *pos, size);
 	assert(wire);
@@ -691,7 +690,7 @@ static knot_rrset_t *knot_pkt_rr_from_wire(const uint8_t *wire, size_t *pos,
 
 	uint16_t type = knot_wire_read_u16(wire + *pos);
 	uint16_t rclass = knot_wire_read_u16(wire + *pos + sizeof(uint16_t));
-	*ttl = knot_wire_read_u32(wire + *pos + 2 * sizeof(uint16_t));
+	uint32_t ttl = knot_wire_read_u32(wire + *pos + 2 * sizeof(uint16_t));
 	uint16_t rdlength = knot_wire_read_u16(wire + *pos + 4 * sizeof(uint16_t));
 
 	knot_rrset_t *rrset = knot_rrset_new(owner, type, rclass, mm);
@@ -702,7 +701,7 @@ static knot_rrset_t *knot_pkt_rr_from_wire(const uint8_t *wire, size_t *pos,
 	*pos += KNOT_RR_HEADER_SIZE;
 
 	dbg_packet_verb("%s: read type %u, class %u, ttl %u, rdlength %u\n",
-	                __func__, rrset->type, rrset->rclass, *ttl, rdlength);
+	                __func__, rrset->type, rrset->rclass, ttl, rdlength);
 
 	if (size - *pos < rdlength) {
 		dbg_packet("%s: not enough data to parse RDATA\n", __func__);
@@ -713,7 +712,7 @@ static knot_rrset_t *knot_pkt_rr_from_wire(const uint8_t *wire, size_t *pos,
 	// parse RDATA
 	/*! \todo Merge with add_rdata_to_rr in zcompile, should be a rrset func
 	 *        probably. */
-	int ret = knot_rrset_rdata_from_wire_one(rrset, wire, pos, size, *ttl,
+	int ret = knot_rrset_rdata_from_wire_one(rrset, wire, pos, size, ttl,
 	                                         rdlength, mm);
 	if (ret != KNOT_EOK) {
 		dbg_packet("%s: couldn't parse RDATA (%d)\n", __func__, ret);
@@ -745,9 +744,8 @@ int knot_pkt_parse_rr(knot_pkt_t *pkt, unsigned flags)
 	/* Parse wire format. */
 	size_t rr_size = pkt->parsed;
 	knot_rrset_t *rr = NULL;
-	uint32_t rr_ttl = 0;
 	rr = knot_pkt_rr_from_wire(pkt->wire, &pkt->parsed, pkt->max_size,
-	                           &rr_ttl, &pkt->mm);
+	                           &pkt->mm);
 	if (rr == NULL) {
 		dbg_packet("%s: failed to parse RR\n", __func__);
 		return KNOT_EMALF;
@@ -790,7 +788,7 @@ int knot_pkt_parse_rr(knot_pkt_t *pkt, unsigned flags)
 		pkt->tsig_rr = rr;
 		break;
 	case KNOT_RRTYPE_OPT:
-		ret = knot_edns_new_from_rr(&pkt->opt_rr, rr, rr_ttl);
+		ret = knot_edns_new_from_rr(&pkt->opt_rr, rr);
 		if (ret != KNOT_EOK) {
 			dbg_packet("%s: couldn't parse OPT RR = %d\n",
 				   __func__, ret);
diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c
index cfb2be7a8..15f1385e7 100644
--- a/src/libknot/rrset.c
+++ b/src/libknot/rrset.c
@@ -852,14 +852,8 @@ int knot_rrset_rdata_from_wire_one(knot_rrset_t *rrset,
 	}
 
 	if (rdlength == 0) {
-		/* Nothing to parse, APLs can have 0 RDLENGTH, but only APLs. */
-		if (rrset->type == KNOT_RRTYPE_APL) {
-			// Add empty RDATA
-			return knot_rrset_create_rr(rrset, 0, ttl, mm) == NULL ?
-			       KNOT_ENOMEM : KNOT_EOK;
-		} else {
-			return KNOT_EOK;
-		}
+		return knot_rrset_create_rr(rrset, 0, ttl, mm) == NULL ?
+		       KNOT_ENOMEM : KNOT_EOK;
 	}
 
 	dbg_rrset_detail("rr: parse_rdata_wire: Parsing RDATA of size=%zu,"
-- 
GitLab