[svn-commits] mmichelson: branch group/dns_naptr r433196 - in /team/group/dns_naptr: includ...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Mar 19 17:24:33 CDT 2015


Author: mmichelson
Date: Thu Mar 19 17:24:19 2015
New Revision: 433196

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=433196
Log:
Add basic DNS NAPTR record handling.

In order to be able to allocate NAPTR records correctly, I had
to make an additional change to the ast_dns_result structure to
include the size of the DNS answer.

There is an incomplete test in res_resolver_unbound.c that was
being used simply to ensure that NAPTR records were being returned
and parsed as expected. The test will be expanded to actually
check values in the near future.

Also, it's probably best for your sanity if you don't look too
deeply at the NAPTR record allocation function.


Modified:
    team/group/dns_naptr/include/asterisk/dns_internal.h
    team/group/dns_naptr/main/dns_core.c
    team/group/dns_naptr/main/dns_naptr.c
    team/group/dns_naptr/res/res_resolver_unbound.c

Modified: team/group/dns_naptr/include/asterisk/dns_internal.h
URL: http://svnview.digium.com/svn/asterisk/team/group/dns_naptr/include/asterisk/dns_internal.h?view=diff&rev=433196&r1=433195&r2=433196
==============================================================================
--- team/group/dns_naptr/include/asterisk/dns_internal.h (original)
+++ team/group/dns_naptr/include/asterisk/dns_internal.h Thu Mar 19 17:24:19 2015
@@ -35,6 +35,7 @@
 	size_t data_len;
 	/*! \brief Linked list information */
 	AST_LIST_ENTRY(ast_dns_record) list;
+	char *data_ptr;
 	/*! \brief The raw DNS record */
 	char data[0];
 };
@@ -69,6 +70,7 @@
 	unsigned short order;
 	/*! \brief The preference of the NAPTR record */
 	unsigned short preference;
+	char data[0];
 };
 
 /*! \brief The result of a DNS query */
@@ -85,6 +87,8 @@
 	const char *canonical;
 	/*! \brief The raw DNS answer */
 	const char *answer;
+	/*! \brief The size of the raw DNS answer */
+	size_t answer_size;
 	/*! \brief Buffer for dynamic data */
 	char buf[0];
 };

Modified: team/group/dns_naptr/main/dns_core.c
URL: http://svnview.digium.com/svn/asterisk/team/group/dns_naptr/main/dns_core.c?view=diff&rev=433196&r1=433195&r2=433196
==============================================================================
--- team/group/dns_naptr/main/dns_core.c (original)
+++ team/group/dns_naptr/main/dns_core.c Thu Mar 19 17:24:19 2015
@@ -43,7 +43,9 @@
 #include "asterisk/dns_resolver.h"
 #include "asterisk/dns_internal.h"
 
+#include <netinet/in.h>
 #include <arpa/nameser.h>
+#include <resolv.h>
 
 AST_RWLIST_HEAD_STATIC(resolvers, ast_dns_resolver);
 
@@ -159,7 +161,7 @@
 
 const char *ast_dns_record_get_data(const struct ast_dns_record *record)
 {
-	return record->data;
+	return record->data_ptr;
 }
 
 const struct ast_dns_record *ast_dns_record_get_next(const struct ast_dns_record *record)
@@ -406,8 +408,150 @@
 	buf_ptr += strlen(canonical) + 1;
 	memcpy(buf_ptr, answer, answer_size); /* SAFE */
 	query->result->answer = buf_ptr;
+	query->result->answer_size = answer_size;
 
 	return 0;
+}
+
+static struct ast_dns_record *generic_record_alloc(struct ast_dns_query *query, const char *data, const size_t size)
+{
+	struct ast_dns_record *record;
+
+	record = ast_calloc(1, sizeof(*record) + size);
+	if (!record) {
+		return NULL;
+	}
+
+	record->data_ptr = record->data;
+
+	return record;
+}
+
+static struct ast_dns_record *naptr_record_alloc(struct ast_dns_query *query, const char *data, const size_t size)
+{
+	struct ast_dns_naptr_record *naptr;
+	char *ptr = NULL;
+	uint16_t order;
+	uint16_t preference;
+	uint8_t flags_size;
+	char *flags;
+	uint8_t services_size;
+	char *services;
+	uint8_t regexp_size;
+	char *regexp;
+	char replacement[256] = "";
+	int replacement_size;
+	char *naptr_offset;
+	char *naptr_search_base = (char *)query->result->answer;
+	size_t remaining_size = query->result->answer_size;
+
+	/* 
+	 * This is bordering on the hackiest thing I've ever written.
+	 * Part of parsing a NAPTR record is to parse a potential replacement
+	 * domain name. Decoding this domain name requires the use of the
+	 * dn_expand() function. This function requires that the domain you
+	 * pass in be a pointer to within the full DNS answer. Unfortunately,
+	 * libunbound gives its RRs back as copies of data from the DNS answer
+	 * instead of pointers to within the DNS answer. This means that in order
+	 * to be able to parse the domain name correctly, I need to find the
+	 * current NAPTR record inside the DNS answer and operate on it. This
+	 * loop is designed to find the current NAPTR record within the full
+	 * DNS answer and set the "ptr" variable to the beginning of the
+	 * NAPTR RDATA
+	 */
+	while (1) {
+		naptr_offset = memchr(naptr_search_base, data[0], remaining_size);
+		/* Couldn't find first byte of NAPTR record */
+		if (!naptr_offset) {
+			ast_log(LOG_NOTICE, "Failed to find NAPTR record within answer\n");
+			return NULL;
+		}
+		/* Found first byte of NAPTR record, but not enough space left in
+		 * the answer for this to be us
+		 */
+		if ((naptr_search_base + remaining_size) - naptr_offset < size) {
+			/* This really shouldn't happen */
+			ast_log(LOG_ERROR, "Ran out of room searching for NAPTR record in answer\n");
+			return NULL;
+		}
+		if (!memcmp(naptr_offset, data, size)) {
+			/* BAM! FOUND IT! */
+			ptr = naptr_offset;
+			break;
+		}
+		/* Data didn't match us, so keep looking */
+		remaining_size -= naptr_offset - naptr_search_base;
+		naptr_search_base = naptr_offset + 1;
+	}
+
+	if (!ptr) {
+		/* WHAT? */
+		return NULL;
+	}
+
+	/* ORDER */
+	order = (ptr[1] << 0) | (ptr[0] << 8);
+	ptr += 2;
+
+	/* PREFERENCE */
+	preference = (ptr[1] << 0) | (ptr[0] << 8);
+	ptr += 2;
+
+	/* FLAGS */
+	flags_size = *ptr;
+	++ptr;
+	flags = ptr;
+	ptr += flags_size;
+
+	/* SERVICES */
+	services_size = *ptr;
+	++ptr;
+	services = ptr;
+	ptr += services_size;
+
+	/* REGEXP */
+	regexp_size = *ptr;
+	++ptr;
+	regexp = ptr;
+	ptr += regexp_size;
+
+	replacement_size = dn_expand((unsigned char *)query->result->answer, (unsigned char *) (naptr_offset + size), (unsigned char *) ptr, replacement, sizeof(replacement) - 1);
+	if (replacement_size < 0) {
+		ast_log(LOG_ERROR, "Failed to expand domain name: %s\n", strerror(errno));
+		return NULL;
+	}
+
+	naptr = ast_calloc(1, sizeof(*naptr) + size + flags_size + 1 + services_size + 1 + regexp_size + 1 + replacement_size + 1);
+	if (!naptr) {
+		return NULL;
+	}
+
+	naptr->generic.data_ptr = naptr->data;
+	naptr->order = order;
+	naptr->preference = preference;
+
+	ptr = naptr->data;
+	ptr += size;
+
+	strncpy(ptr, flags, flags_size);
+	ptr[flags_size] = '\0';
+	naptr->flags = ptr;
+	ptr += flags_size + 1;
+
+	strncpy(ptr, services, services_size);
+	ptr[services_size] = '\0';
+	naptr->service = ptr;
+	ptr += services_size + 1;
+
+	strncpy(ptr, regexp, regexp_size);
+	ptr[regexp_size] = '\0';
+	naptr->regexp = ptr;
+	ptr += regexp_size + 1;
+
+	strcpy(ptr, replacement);
+	naptr->replacement = ptr;
+
+	return (struct ast_dns_record *)naptr;
 }
 
 int ast_dns_resolver_add_record(struct ast_dns_query *query, int rr_type, int rr_class, int ttl, const char *data, const size_t size)
@@ -444,7 +588,12 @@
 		return -1;
 	}
 
-	record = ast_calloc(1, sizeof(*record) + size);
+	if (rr_type == ns_t_naptr) {
+		record = naptr_record_alloc(query, data, size);
+	} else {
+		record = generic_record_alloc(query, data, size);
+	}
+
 	if (!record) {
 		return -1;
 	}
@@ -452,8 +601,8 @@
 	record->rr_type = rr_type;
 	record->rr_class = rr_class;
 	record->ttl = ttl;
-	memcpy(record->data, data, size);
 	record->data_len = size;
+	memcpy(record->data_ptr, data, size);
 
 	AST_LIST_INSERT_TAIL(&query->result->records, record, list);
 

Modified: team/group/dns_naptr/main/dns_naptr.c
URL: http://svnview.digium.com/svn/asterisk/team/group/dns_naptr/main/dns_naptr.c?view=diff&rev=433196&r1=433195&r2=433196
==============================================================================
--- team/group/dns_naptr/main/dns_naptr.c (original)
+++ team/group/dns_naptr/main/dns_naptr.c Thu Mar 19 17:24:19 2015
@@ -31,35 +31,58 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include <arpa/nameser.h>
+
 #include "asterisk/dns_core.h"
 #include "asterisk/dns_naptr.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/dns_internal.h"
+#include "asterisk/utils.h"
 
 const char *ast_dns_naptr_get_flags(const struct ast_dns_record *record)
 {
-	return NULL;
+	struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record;
+
+	ast_assert(ast_dns_record_get_rr_type(record) == ns_t_naptr);
+	return naptr->flags;
 }
 
 const char *ast_dns_naptr_get_service(const struct ast_dns_record *record)
 {
-	return NULL;
+	struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record;
+
+	ast_assert(ast_dns_record_get_rr_type(record) == ns_t_naptr);
+	return naptr->service;
 }
 
 const char *ast_dns_naptr_get_regexp(const struct ast_dns_record *record)
 {
-	return NULL;
+	struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record;
+
+	ast_assert(ast_dns_record_get_rr_type(record) == ns_t_naptr);
+	return naptr->regexp;
 }
 
 const char *ast_dns_naptr_get_replacement(const struct ast_dns_record *record)
 {
-	return NULL;
+	struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record;
+
+	ast_assert(ast_dns_record_get_rr_type(record) == ns_t_naptr);
+	return naptr->replacement;
 }
 
 unsigned short ast_dns_naptr_get_order(const struct ast_dns_record *record)
 {
-	return 0;
+	struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record;
+
+	ast_assert(ast_dns_record_get_rr_type(record) == ns_t_naptr);
+	return naptr->order;
 }
 
 unsigned short ast_dns_naptr_get_preference(const struct ast_dns_record *record)
 {
-	return 0;
-}
+	struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record;
+
+	ast_assert(ast_dns_record_get_rr_type(record) == ns_t_naptr);
+	return naptr->preference;
+}

Modified: team/group/dns_naptr/res/res_resolver_unbound.c
URL: http://svnview.digium.com/svn/asterisk/team/group/dns_naptr/res/res_resolver_unbound.c?view=diff&rev=433196&r1=433195&r2=433196
==============================================================================
--- team/group/dns_naptr/res/res_resolver_unbound.c (original)
+++ team/group/dns_naptr/res/res_resolver_unbound.c Thu Mar 19 17:24:19 2015
@@ -299,7 +299,6 @@
 
 	ao2_ref(data, -1);
 	ao2_ref(cfg, -1);
-
 	return res;
 }
 
@@ -488,6 +487,8 @@
 }
 
 #ifdef TEST_FRAMEWORK
+
+#include "asterisk/dns_naptr.h"
 
 /*!
  * \brief A DNS record to be used during a test
@@ -1181,6 +1182,66 @@
 
 	return AST_TEST_PASS;
 }
+
+AST_TEST_DEFINE(resolve_naptr)
+{
+	RAII_VAR(struct unbound_resolver *, resolver, NULL, ao2_cleanup);
+	RAII_VAR(struct unbound_config *, cfg, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free);
+
+	const struct ast_dns_record *record;
+
+	static const char * DOMAIN1 = "goose.feathers";
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "resolve_naptr";
+		info->category = "/res/res_resolver_unbound/";
+		info->summary = "Attempt resolution of NAPTR record\n";
+		info->description = "This test performs a NAPTR lookup and ensures that\n"
+			"the returned record has the appropriate values set\n";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	cfg = ao2_global_obj_ref(globals);
+	resolver = ao2_bump(cfg->global->state->resolver);
+
+	ub_ctx_zone_add(resolver->context, DOMAIN1, "static");
+
+	ub_ctx_data_add(resolver->context, "goose.feathers 12345 IN NAPTR 100 100 A \"Fake service\" \"\" goose.down");
+
+	if (ast_dns_resolve(DOMAIN1, ns_t_naptr, ns_c_in, &result)) {
+		ast_test_status_update(test, "Failed to resolve domain\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (!result) {
+		ast_test_status_update(test, "Successful resolution set a NULL result\n");
+		return AST_TEST_FAIL;
+	}
+
+	record = ast_dns_result_get_records(result);
+	if (!record) {
+		ast_test_status_update(test, "Failed to get any DNS records from the result\n");
+		return AST_TEST_FAIL;
+	}
+
+	/* XXX This just prints data for my own inspection right now. It will need to actually
+	 * perform a check in order to really pass. This will be done once more NAPTR records
+	 * are added so I can check ordering as well as individual data
+	 */
+	ast_log(LOG_NOTICE, "order is %hu\n", ast_dns_naptr_get_order(record));
+	ast_log(LOG_NOTICE, "preference is %hu\n", ast_dns_naptr_get_preference(record));
+	ast_log(LOG_NOTICE, "flags is %s\n", ast_dns_naptr_get_flags(record));
+	ast_log(LOG_NOTICE, "service is %s\n", ast_dns_naptr_get_service(record));
+	ast_log(LOG_NOTICE, "regexp is %s\n", ast_dns_naptr_get_regexp(record));
+	ast_log(LOG_NOTICE, "replacement is %s\n", ast_dns_naptr_get_replacement(record));
+
+	return AST_TEST_PASS;
+
+}
 #endif
 
 static int reload_module(void)
@@ -1202,6 +1263,7 @@
 	AST_TEST_UNREGISTER(resolve_sync_off_nominal);
 	AST_TEST_UNREGISTER(resolve_sync_off_nominal);
 	AST_TEST_UNREGISTER(resolve_cancel_off_nominal);
+	AST_TEST_UNREGISTER(resolve_naptr);
 	return 0;
 }
 
@@ -1258,6 +1320,7 @@
 	AST_TEST_REGISTER(resolve_sync_off_nominal);
 	AST_TEST_REGISTER(resolve_async_off_nominal);
 	AST_TEST_REGISTER(resolve_cancel_off_nominal);
+	AST_TEST_REGISTER(resolve_naptr);
 
 	return AST_MODULE_LOAD_SUCCESS;
 }




More information about the svn-commits mailing list