From 76c3923a9f832dcd0a1952633c2a5a6eecd4646d Mon Sep 17 00:00:00 2001
From: Lubos Slovak <lubos.slovak@nic.cz>
Date: Wed, 4 May 2011 14:50:14 +0200
Subject: [PATCH] Dname parsing from wire format implemented.

- Added functions for checking and getting dname pointer.

refs #816 @0:45
---
 src/dnslib/dname.c | 71 ++++++++++++++++++++++++++++++++++++++++++++--
 src/dnslib/wire.h  | 15 ++++++++++
 2 files changed, 83 insertions(+), 3 deletions(-)

diff --git a/src/dnslib/dname.c b/src/dnslib/dname.c
index 622633e2fd..8dcb9c31ba 100644
--- a/src/dnslib/dname.c
+++ b/src/dnslib/dname.c
@@ -12,6 +12,7 @@
 #include "dnslib/tolower.h"
 #include "dnslib/debug.h"
 #include "dnslib/utils.h"
+#include "dnslib/wire.h"
 
 /*
  * Memory cache.
@@ -432,10 +433,74 @@ dnslib_dname_t *dnslib_dname_new_from_wire(const uint8_t *name, uint size,
 
 dnslib_dname_t *dnslib_dname_parse_from_wire(const uint8_t *wire,
                                              size_t *pos, size_t size,
-                                             struct dnslib_node *node)
+                                             dnslib_node_t *node)
 {
-	/*! @todo Implement! */
-	return NULL;
+	uint8_t name[DNSLIB_MAX_DNAME_LENGTH];
+	uint8_t labels[DNSLIB_MAX_DNAME_LABELS];
+
+	short l = 0;
+	size_t i = 0, p = *pos;
+	int pointer_used = 0;
+
+	while (p < size && wire[p] != 0) {
+		labels[l] = i;
+
+		if (dnslib_wire_is_pointer(wire + p)) {
+			// pointer.
+			p = dnslib_wire_get_pointer(wire + p);
+			*pos += 2;
+			pointer_used = 1;
+			if (p >= size) {
+				return NULL;
+			}
+		} else {
+			// label; first byte is label length
+			uint8_t length = *(wire + p);
+			memcpy(name + i, wire + p, length + 1);
+			p += length + 1;
+			i += length + 1;
+			if (!pointer_used) {
+				*pos += length + 1;
+			}
+			++l;
+		}
+	}
+	if (p >= size) {
+		return NULL;
+	}
+
+	name[i] = 0;
+
+	dnslib_dname_t *dname = dnslib_dname_alloc();
+
+	if (dname == NULL) {
+		ERR_ALLOC_FAILED;
+		return NULL;
+	}
+
+	dname->name = (uint8_t *)malloc((i + 1) * sizeof(uint8_t));
+	if (dname->name == NULL) {
+		ERR_ALLOC_FAILED;
+		dnslib_dname_free(&dname);
+		return NULL;
+	}
+
+	memcpy(dname->name, name, i + 1);
+	dname->size = i + 1;
+
+	dname->labels = (uint8_t *)malloc(l * sizeof(uint8_t));
+	if (dname->labels == NULL) {
+		ERR_ALLOC_FAILED;
+		dnslib_dname_free(&dname);
+		return NULL;
+	}
+	memcpy(dname->labels, labels, l);
+
+	dname->label_count = l - 1;
+
+	dname->node = node;
+
+	return dname;
 }
 
 /*----------------------------------------------------------------------------*/
diff --git a/src/dnslib/wire.h b/src/dnslib/wire.h
index 6affd7c352..3e0eff04bd 100644
--- a/src/dnslib/wire.h
+++ b/src/dnslib/wire.h
@@ -890,6 +890,21 @@ static inline void dnslib_wire_put_pointer(uint8_t *pos, size_t ptr)
 	pos[0] |= DNSLIB_WIRE_PTR;
 }
 
+static inline int dnslib_wire_is_pointer(const uint8_t *pos)
+{
+	return ((pos[0] & DNSLIB_WIRE_PTR) != 0);
+}
+
+static inline size_t dnslib_wire_get_pointer(const uint8_t *pos)
+{
+	uint16_t p = 0;
+	memcpy(&p, pos, 2);
+	p &= ~DNSLIB_WIRE_PTR;
+
+	uint16_t p2 = dnslib_wire_read_u16(&p);
+	return p2;
+}
+
 #endif /* _KNOT_DNSLIB_WIRE_H_ */
 
 /*! @} */
-- 
GitLab