From fb5099c5dc6b8e7b632c2ac64cc01abc80838859 Mon Sep 17 00:00:00 2001
From: Lubos Slovak <lubos.slovak@nic.cz>
Date: Thu, 18 Nov 2010 13:31:32 +0100
Subject: [PATCH] RDATA modifications.

The previous approach made converting RDATA  to wire format too
  complex. Now RDATA items distinguish only between domain name
  and other data. The format is given by a descriptor.

TODO: Consider saving the length of the data to the byte array
      always, so getting it would not require that huge switch.

refs #119
---
 src/dnslib/rdata.c | 148 ++++++++++++++++-----------------------------
 src/dnslib/rdata.h |  14 ++---
 2 files changed, 59 insertions(+), 103 deletions(-)

diff --git a/src/dnslib/rdata.c b/src/dnslib/rdata.c
index 51ac0b1cd..948c4cf90 100644
--- a/src/dnslib/rdata.c
+++ b/src/dnslib/rdata.c
@@ -142,34 +142,8 @@ uint dnslib_rdata_wire_size( const dnslib_rdata_t *rdata,
 		case DNSLIB_RDATA_WF_LITERAL_DNAME:
 			size += dnslib_dname_size(rdata->items[i].dname);
 			break;
-		case DNSLIB_RDATA_WF_BYTE:
-			size += 1;
-			break;
-		case DNSLIB_RDATA_WF_SHORT:
-			size += 2;
-			break;
-		case DNSLIB_RDATA_WF_LONG:
-			size += 4;
-			break;
-		case DNSLIB_RDATA_WF_A:
-			size += 4;
-			break;
-		case DNSLIB_RDATA_WF_AAAA:
-			size += 16;
-			break;
-		case DNSLIB_RDATA_WF_TEXT:
-		case DNSLIB_RDATA_WF_BINARYWITHLENGTH:
-			// size stored in the first byte, but the first byte also counts
-			size += rdata->items[i].raw_data[0] + 1;
-			break;
-		case DNSLIB_RDATA_WF_BINARY:
-		case DNSLIB_RDATA_WF_APL:			// saved as binary
-		case DNSLIB_RDATA_WF_IPSECGATEWAY:	// saved as binary
-			// size stored in the first byte, first byte doesn't count
-			size += rdata->items[i].raw_data[0];
-			break;
 		default:
-			assert(0);
+			size += rdata->items[i].raw_data[0];
 		}
 	}
 	return size;
@@ -187,74 +161,55 @@ int dnslib_rdata_to_wire( const dnslib_rdata_t *rdata, const uint8_t *format,
 	for (int i = 0; i < rdata->count; ++i) {
 		assert(copied < MAX_RDATA_WIRE_SIZE);
 
+		const uint8_t *from = rdata->items[i].raw_data;
+		uint size = 0;
+
 		switch (format[i]) {
 		case DNSLIB_RDATA_WF_COMPRESSED_DNAME:
 		case DNSLIB_RDATA_WF_UNCOMPRESSED_DNAME:
-		case DNSLIB_RDATA_WF_LITERAL_DNAME: {
-			uint size = dnslib_dname_size(rdata->items[i].dname);
-			memcpy(to, dnslib_dname_name(rdata->items[i].dname), size);
-			to += size;
-			copied += size;
-		} break;
+		case DNSLIB_RDATA_WF_LITERAL_DNAME:
+			size = dnslib_dname_size(rdata->items[i].dname);
+			from = dnslib_dname_name(rdata->items[i].dname);
+
+			break;
 		case DNSLIB_RDATA_WF_BYTE:
-			*(to++) = rdata->items[i].int8;
-			++copied;
+			size = 1;
+			break;
+		case DNSLIB_RDATA_WF_SHORT:
+			size = 2;
+			break;
+		case DNSLIB_RDATA_WF_LONG:
+			size = 4;
+			break;
+		case DNSLIB_RDATA_WF_A:
+			size = 4;
+			break;
+		case DNSLIB_RDATA_WF_AAAA:
+			size = 16;
 			break;
-		case DNSLIB_RDATA_WF_SHORT: {
-			const uint8_t *from = (uint8_t *)(&rdata->items[i].int16);
-			// copy from last byte to first (little to big endian)
-			// TODO: check endianness of the machine
-			from += 1;
-			for (int i = 0; i < 2; ++i) {
-				*(to++) = *(from--);
-				++copied;
-			}
-		} break;
-		case DNSLIB_RDATA_WF_LONG: {
-			const uint8_t *from = (uint8_t *)(&rdata->items[i].int32);
-			// copy from last byte to first (little to big endian)
-			// TODO: check endianness of the machine
-			from += 3;
-			for (int i = 0; i < 4; ++i) {
-				*(to++) = *(from--);
-				++copied;
-			}
-		} break;
-		case DNSLIB_RDATA_WF_A: {
-			const uint8_t *from = rdata->items[i].a;
-			for (int i = 0; i < 4; ++i) {
-				*(to++) = *(from++);
-				++copied;
-			}
-		} break;
-		case DNSLIB_RDATA_WF_AAAA: {
-			const uint8_t *from = rdata->items[i].raw_data;
-			for (int i = 0; i < 16; ++i) {
-				*(to++) = *(from++);
-				++copied;
-			}
-		} break;
 		case DNSLIB_RDATA_WF_TEXT:
 		case DNSLIB_RDATA_WF_BINARYWITHLENGTH:
 			// size stored in the first byte, but the first byte also needs to
 			// be copied
-			memcpy(to, rdata->items[i].raw_data,
-				   rdata->items[i].raw_data[0] + 1);
-			copied += rdata->items[i].raw_data[0] + 1;
-			to += rdata->items[i].raw_data[0] + 1;
+			size = rdata->items[i].raw_data[0] + 1;
 			break;
 		case DNSLIB_RDATA_WF_BINARY:
 		case DNSLIB_RDATA_WF_APL:			// saved as binary
 		case DNSLIB_RDATA_WF_IPSECGATEWAY:	// saved as binary
 			// size stored in the first byte, first byte must not be copied
-			memcpy(to, &(rdata->items[i].raw_data[1]),
-				   rdata->items[i].raw_data[0]);
-			copied += rdata->items[i].raw_data[0];
-			to += rdata->items[i].raw_data[0];
+			size = rdata->items[i].raw_data[0];
+			++to;
 			break;
 		default:
 			assert(0);
 		}
+
+		assert(size != 0);
+		assert(copied + size < MAX_RDATA_WIRE_SIZE);
+
+		memcpy(to, from, size);
+		to += size;
+		copied += size;
 	}
 
 	if (copied > buf_size) {
@@ -278,53 +233,54 @@ int dnslib_rdata_compare( const dnslib_rdata_t *r1, const dnslib_rdata_t *r2,
 	int cmp = 0;
 
 	for (int i = 0; i < count; ++i) {
-		dnslib_rdata_item_t *item1 = &r2->items[i];
+		dnslib_rdata_item_t *item1 = &r1->items[i];
 		dnslib_rdata_item_t *item2 = &r2->items[i];
 
+		const uint8_t *data1 = r1->items[i].raw_data;
+		const uint8_t *data2 = r2->items[i].raw_data;
+		int size1, size2;
+
 		switch (format[i]) {
 		case DNSLIB_RDATA_WF_COMPRESSED_DNAME:
 		case DNSLIB_RDATA_WF_UNCOMPRESSED_DNAME:
 		case DNSLIB_RDATA_WF_LITERAL_DNAME:
-			cmp = dnslib_rdata_compare_binary(
-					dnslib_dname_name(item1->dname),
-					dnslib_dname_name(item2->dname),
-					dnslib_dname_size(item1->dname),
-					dnslib_dname_size(item2->dname));
+			data1 = dnslib_dname_name(item1->dname);
+			size1 = dnslib_dname_size(item1->dname);
+			data2 = dnslib_dname_name(item2->dname);
+			size2 = dnslib_dname_size(item2->dname);
 			break;
 		case DNSLIB_RDATA_WF_BYTE:
-			cmp = (item1->int8 == item2->int8) ? 0 : (
-					(r1->items[i].int8 < item2->int8) ? -1 : 1);
+			size1 = size2 = 1;
 			break;
 		case DNSLIB_RDATA_WF_SHORT:
-			cmp = (item1->int16 == item2->int16) ? 0 : (
-					(item1->int16 < item2->int16) ? -1 : 1);
+			size1 = size2 = 2;
 			break;
 		case DNSLIB_RDATA_WF_LONG:
-			cmp = (item1->int32 == item2->int32) ? 0 : (
-					(item1->int32 < item2->int32) ? -1 : 1);
+			size1 = size2 = 4;
 			break;
 		case DNSLIB_RDATA_WF_A:
-			cmp = dnslib_rdata_compare_binary(item1->a, item2->a, 4, 4);
+			size1 = size2 = 4;
 			break;
 		case DNSLIB_RDATA_WF_AAAA:
-			cmp = dnslib_rdata_compare_binary(item1->raw_data, item2->raw_data,
-											  16, 16);
+			size1 = size2 = 16;
 			break;
 		case DNSLIB_RDATA_WF_TEXT:
 		case DNSLIB_RDATA_WF_BINARYWITHLENGTH:
-			cmp = dnslib_rdata_compare_binary(&item1->raw_data[1],
-					&item2->raw_data[1], (int)item1->raw_data[0],
-					(int)item2->raw_data[0]);
+			size1 = (int)item1->raw_data[0] + 1;
+			size2 = (int)item1->raw_data[0] + 1;
 			break;
 		case DNSLIB_RDATA_WF_BINARY:
 		case DNSLIB_RDATA_WF_APL:			// saved as binary
 		case DNSLIB_RDATA_WF_IPSECGATEWAY:	// saved as binary
-			cmp = dnslib_rdata_compare_binary(item1->a, item2->a, -1, -1);
+			size1 = -1;
+			size2 = -1;
 			break;
 		default:
 			assert(0);
 		}
 
+		cmp = dnslib_rdata_compare_binary(data1, data2, size1, size2);
+
 		if (cmp != 0) {
 			return cmp;
 		}
diff --git a/src/dnslib/rdata.h b/src/dnslib/rdata.h
index 1523f8e70..e73063e8c 100644
--- a/src/dnslib/rdata.h
+++ b/src/dnslib/rdata.h
@@ -27,16 +27,16 @@
  */
 union dnslib_rdata_item {
 	dnslib_dname_t *dname; /*!< RDATA item represented as a domain name. */
-	uint8_t int8;	/*!< 8bit unsigned integer */
-	uint16_t int16;		/*!< 16bit unsigned integer */
-	uint32_t int32;		/*!< 32bit unsigned integer */
-	uint8_t a[4];		/*!< A address - four 8bit integers */
+
 	/*!
 	 * \brief RDATA item represented as raw array of octets.
 	 *
-	 * In most cases the first octet will be the length of the array. The only
-	 * now known exception will be when storing AAAA address which has known
-	 * length (sixteen 8bit integers), so there is no need to store the lenght.
+	 * In some cases the first octet will be the length of the array.
+	 * In other, the size is determined by the type (i.e. 4 bytes in case of
+	 * IPv4 address).
+	 *
+	 * In some cases this length is also used in the wire format of RDATA
+	 * (e.g. character-data as defined in RFC1035).
 	 */
 	uint8_t *raw_data;
 };
-- 
GitLab