From cfe80a2c4f8fb21f2af011a15b4b1923643be2b1 Mon Sep 17 00:00:00 2001
From: Lubos Slovak <lubos.slovak@nic.cz>
Date: Fri, 5 Nov 2010 16:54:40 +0100
Subject: [PATCH] Fixed dname API, added 3 functions, fixed impl.

dname and node were referencing each other. Used
  forward-declaration of node in dname.
Added API getter functions (with implementation):
  - dnslib_dname_name()
  - dnslib_dname_size()
  - dnslib_dname_node()
Fixed dname implementation:
  - str_to_wire() was replacing chars by label lengths
  - new_from_str() bad assert
  - new_from_wire() was not allocating space for the name
  - to_str() was de facto copying the wire format

Added some debug output to dname

refs #5, #88
---
 src/dnslib/dname.c | 109 ++++++++++++++++++++++++++++++++++++++-------
 src/dnslib/dname.h |  45 ++++++++++++++++---
 2 files changed, 131 insertions(+), 23 deletions(-)

diff --git a/src/dnslib/dname.c b/src/dnslib/dname.c
index 3eab23b3e5..5fcdc87ec0 100644
--- a/src/dnslib/dname.c
+++ b/src/dnslib/dname.c
@@ -1,4 +1,7 @@
 #include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
 #include "common.h"
 #include "consts.h"
 #include "dname.h"
@@ -6,48 +9,84 @@
 /*----------------------------------------------------------------------------*/
 /* Non-API functions                                                          */
 /*----------------------------------------------------------------------------*/
+/*!
+ *	\brief Returns the size of the wire format of domain name which has
+ *         \a str_size characters in presentation format.
+ */
+static inline uint dnslib_dname_wire_size( uint str_size )
+{
+	return str_size + 1;
+}
 
+/*----------------------------------------------------------------------------*/
 /*!
+ * \brief Converts domain name from string representation to wire format.
+ *
+ * \param name Domain name in string representation (presentation format).
+ * \param size Size of the given domain name in characters (not counting the
+ *             terminating 0 character.
+ * \param wire [in/out] Pointer to position where the wire format of the domain
+ *             name will be stored.
+ *
+ * This function also allocates the space for the wire format.
+ *
+ * \return Size of the wire format of the domain name in octets. If 0, no
+ *         space has been allocated.
+ *
  * \todo handle \X and \DDD (RFC 1035 5.1) or it can be handled by the parser?
  */
-int dnslib_dname_str_to_wire( const char *name, uint size, uint8_t **wire )
+static uint dnslib_dname_str_to_wire( const char *name, uint size,
+									 uint8_t **wire )
 {
 	if (size > DNSLIB_MAX_DNAME_LENGTH) {
 		return 0;
 	}
 
+	uint wire_size = dnslib_dname_wire_size(size);
+
 	// signed / unsigned issues??
-	*wire = (uint8_t *)malloc((size + 1) * sizeof(uint8_t));
+	*wire = (uint8_t *)malloc(wire_size * sizeof(uint8_t));
 	if (*wire == NULL) {
 		return 0;
 	}
 
+	debug_dnslib_dname("Allocated space for wire format of dname: %p\n",
+					   *wire);
+
 	const uint8_t *ch = (const uint8_t *)name;
 	uint8_t *label_start = *wire;
-	uint8_t *w = *wire;
+	uint8_t *w = *wire + 1;
 	uint8_t label_length = 0;
 
-	while (ch - name < size) {
-		assert(w - *wire < size);
-		assert(w - *wire == ch - name);
+	while (ch - (const uint8_t *)name < size) {
+		assert(w - *wire < wire_size);
+		assert(w - *wire - 1 == ch - (const uint8_t *)name);
 
 		if (*ch == '.' ) {
+			debug_dnslib_dname("Position %u (%p): label length: %u\n",
+							   label_start - *wire, label_start, label_length);
 			*label_start = label_length;
 			label_start = w;
+			label_length = 0;
 		} else {
+			debug_dnslib_dname("Position %u (%p): character: %c\n",
+							   w - *wire, w, *ch);
 			*w = *ch;
+			++label_length;
 		}
 
 		++w;
 		++ch;
-		assert(ch >= name);
+		assert(ch >= (const uint8_t *)name);
 	}
 
 	// put 0 for root label regardless whether the name ended with .
+	--w;
+	debug_dnslib_dname("Position %u (%p): character: (null)\n", w - *wire, w);
 	*w = 0;
 
 	//memcpy(*wire, name, size);
-	return size;
+	return wire_size;
 }
 
 /*----------------------------------------------------------------------------*/
@@ -57,7 +96,7 @@ int dnslib_dname_str_to_wire( const char *name, uint size, uint8_t **wire )
 dnslib_dname_t *dnslib_dname_new()
 {
 	dnslib_dname_t *dname = (dnslib_dname_t *)malloc(sizeof(dnslib_dname_t));
-	if (name == NULL) {
+	if (dname == NULL) {
 		ERR_ALLOC_FAILED;
 		return NULL;
 	}
@@ -72,7 +111,7 @@ dnslib_dname_t *dnslib_dname_new()
 /*----------------------------------------------------------------------------*/
 
 dnslib_dname_t *dnslib_dname_new_from_str( char *name, uint size,
-										   dnslib_node_t *node )
+										   struct dnslib_node *node )
 {
 	if (name == NULL || size == 0) {
 		return NULL;
@@ -89,6 +128,8 @@ dnslib_dname_t *dnslib_dname_new_from_str( char *name, uint size,
 		log_warning("Could not parse domain name from string: '%.*s'\n",
 					size, name);
 	}
+	assert(dname->name != NULL);
+
 	dname->node = node;
 
 	return dname;
@@ -97,14 +138,26 @@ dnslib_dname_t *dnslib_dname_new_from_str( char *name, uint size,
 /*----------------------------------------------------------------------------*/
 
 dnslib_dname_t *dnslib_dname_new_from_wire( uint8_t *name, uint size,
-											dnslib_node_t *node )
+											struct dnslib_node *node )
 {
+	if (name == NULL && size != 0) {
+		printf("No name given!\n");
+		return NULL;
+	}
+
 	dnslib_dname_t *dname = (dnslib_dname_t *)malloc(sizeof(dnslib_dname_t));
-	if (name == NULL) {
+	if (dname == NULL) {
 		ERR_ALLOC_FAILED;
 		return NULL;
 	}
 
+	dname->name = (uint8_t *)malloc(size * sizeof(uint8_t));
+	if (dname->name == NULL) {
+		ERR_ALLOC_FAILED;
+		free(dname);
+		return NULL;
+	}
+
 	memcpy(dname->name, name, size);
 	dname->size = size;
 	dname->node = node;
@@ -114,7 +167,7 @@ dnslib_dname_t *dnslib_dname_new_from_wire( uint8_t *name, uint size,
 
 /*----------------------------------------------------------------------------*/
 
-char *dnslib_dname_to_str( dnslib_dname_t *dname )
+char *dnslib_dname_to_str( const dnslib_dname_t *dname )
 {
 	char *name = (char *)malloc(dname->size * sizeof(char));
 
@@ -122,22 +175,46 @@ char *dnslib_dname_to_str( dnslib_dname_t *dname )
 	char *ch = name;
 
 	while (*w != 0) {
-		// skip label length
 		uint8_t *next = w + *w + 1;
+		// skip label length
+		++w;
 		while (w != next) {
 			*(ch++) = *(w++);
 		}
+		// insert . at the end of label
+		*(ch++) = '.';
 	}
 
 	*ch = 0;
-	assert(ch - name == dname->size);
+	assert(ch - name == dname->size - 1);
 
 	return name;
 }
 
 /*----------------------------------------------------------------------------*/
 
-void dnslib_dname_free( dnslib_dname *dname )
+const uint8_t *dnslib_dname_name( const dnslib_dname_t *dname )
+{
+	return dname->name;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint dnslib_dname_size( const dnslib_dname_t *dname )
+{
+	return dname->size;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const struct dnslib_node *dnslib_dname_node( const dnslib_dname_t *dname )
+{
+	return dname->node;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void dnslib_dname_free( dnslib_dname_t *dname )
 {
 	free(dname->name);
 	free(dname);
diff --git a/src/dnslib/dname.h b/src/dnslib/dname.h
index 0902dc766b..6081f4f36f 100644
--- a/src/dnslib/dname.h
+++ b/src/dnslib/dname.h
@@ -3,7 +3,8 @@
 
 #include <stdint.h>
 #include "common.h"
-#include "node.h"
+
+struct dnslib_node;
 
 /*----------------------------------------------------------------------------*/
 /*!
@@ -20,10 +21,10 @@ struct dnslib_dname {
 	 * \todo Is this needed? Every dname should end with \0 or pointer.
 	 */
 	uint size;
-	dnslib_node_t *node;	/*!< Zone node the domain name belongs to. */
+	struct dnslib_node *node;	/*!< Zone node the domain name belongs to. */
 };
 
-typedef struct dname dnslib_dname_t;
+typedef struct dnslib_dname dnslib_dname_t;
 
 /*----------------------------------------------------------------------------*/
 
@@ -53,13 +54,15 @@ dnslib_dname_t *dnslib_dname_new();
  * \todo Check if the FQDN issue is OK.
  */
 dnslib_dname_t *dnslib_dname_new_from_str( char *name, uint size,
-										   dnslib_node_t *node );
+										   struct dnslib_node *node );
 
 /*!
  * \brief Creates a dname structure from domain name given in wire format.
  *
  * \param name Domain name in wire format.
  * \param size Size of the domain name in octets.
+ * \param node Zone node the domain name belongs to. Set to NULL if not
+ *             applicable.
  *
  * \return Newly allocated and initialized dname structure representing the
  *         given domain name.
@@ -69,7 +72,8 @@ dnslib_dname_t *dnslib_dname_new_from_str( char *name, uint size,
  *       does not correspond to the behaviour of dnslib_dname_new_from_str().
  * \todo Address the FQDN issue.
  */
-dnslib_dname_t *dnslib_dname_new_from_wire( uint8_t *name, uint size );
+dnslib_dname_t *dnslib_dname_new_from_wire( uint8_t *name, uint size,
+											struct dnslib_node *node );
 
 /*!
  * \brief Converts the given domain name to string representation.
@@ -80,7 +84,34 @@ dnslib_dname_t *dnslib_dname_new_from_wire( uint8_t *name, uint size );
  *         presentation format.
  * \note Allocates new memory, remember to free it.
  */
-char *dnslib_dname_to_str( dnslib_dname_t *dname );
+char *dnslib_dname_to_str( const dnslib_dname_t *dname );
+
+/*!
+ * \brief Returns the domain name in wire format.
+ *
+ * \param dname Domain name.
+ *
+ * \return Wire format of the domain name.
+ */
+const uint8_t *dnslib_dname_name( const dnslib_dname_t *dname );
+
+/*!
+ * \brief Returns size of the given domain name.
+ *
+ * \param dname Domain name to get the size of.
+ *
+ * \return Size of the domain name in wire format in octets.
+ */
+uint dnslib_dname_size( const dnslib_dname_t *dname );
+
+/*!
+ * \brief Returns the zone node the domain name belongs to.
+ *
+ * \param dname Domain name to get the zone node of.
+ *
+ * \return Zone node the domain name belongs to or NULL if none.
+ */
+const struct dnslib_node *dnslib_dname_node( const dnslib_dname_t *dname );
 
 /*!
  * \brief Destroys the given domain name.
@@ -89,6 +120,6 @@ char *dnslib_dname_to_str( dnslib_dname_t *dname );
  *
  * \note Frees also the data within the struct.
  */
-void dnslib_dname_free( dnslib_dname *dname );
+void dnslib_dname_free( dnslib_dname_t *dname );
 
 #endif /* _CUTEDNS_DNAME_H */
-- 
GitLab