[asterisk-commits] mmichelson: trunk r434068 - in /trunk: include/asterisk/ main/ res/ tests/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Apr 6 12:05:51 CDT 2015
Author: mmichelson
Date: Mon Apr 6 12:05:47 2015
New Revision: 434068
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=434068
Log:
Merge NAPTR support into trunk.
This adds NAPTR record allocation and sorting, as well as
unit tests that verify that NAPTR records are parsed and
sorted correctly.
Review: https://reviewboard.asterisk.org/r/4542
Modified:
trunk/include/asterisk/dns_internal.h (contents, props changed)
trunk/main/dns_core.c
trunk/main/dns_naptr.c
trunk/res/res_resolver_unbound.c
trunk/tests/test_dns.c (props changed)
trunk/tests/test_dns_recurring.c (props changed)
Modified: trunk/include/asterisk/dns_internal.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/dns_internal.h?view=diff&rev=434068&r1=434067&r2=434068
==============================================================================
--- trunk/include/asterisk/dns_internal.h (original)
+++ trunk/include/asterisk/dns_internal.h Mon Apr 6 12:05:47 2015
@@ -35,6 +35,14 @@
size_t data_len;
/*! \brief Linked list information */
AST_LIST_ENTRY(ast_dns_record) list;
+ /*! \brief pointer to record-specific data.
+ *
+ * For certain "subclasses" of DNS records, the
+ * location of the raw DNS data will differ from
+ * the generic case. This pointer will reliably
+ * be set to point to the raw DNS data, no matter
+ * where in the structure it may lie.
+ */
char *data_ptr;
/*! \brief The raw DNS record */
char data[0];
@@ -74,6 +82,13 @@
unsigned short order;
/*! \brief The preference of the NAPTR record */
unsigned short preference;
+ /*! \brief Buffer for NAPTR-specific data
+ *
+ * This includes the raw NAPTR record, as well as
+ * the area where the flags, service, regexp, and
+ * replacement strings are stored.
+ */
+ char data[0];
};
/*! \brief The result of a DNS query */
@@ -152,6 +167,25 @@
struct ast_sched_context *ast_dns_get_sched(void);
/*!
+ * \brief Allocate and parse a DNS NAPTR record
+ *
+ * \param query The DNS query
+ * \param data This specific NAPTR record
+ * \param size The size of the NAPTR record
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ */
+struct ast_dns_record *dns_naptr_alloc(struct ast_dns_query *query, const char *data, const size_t size);
+
+/*!
+ * \brief Sort the NAPTR records on a result
+ *
+ * \param result The DNS result
+ */
+void dns_naptr_sort(struct ast_dns_result *result);
+
+/*!
* \brief Allocate and parse a DNS SRV record
*
* \param query The DNS query
@@ -170,4 +204,3 @@
*/
void ast_dns_srv_sort(struct ast_dns_result *result);
-
Propchange: trunk/include/asterisk/dns_internal.h
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Mon Apr 6 12:05:47 2015
@@ -1,1 +1,1 @@
-Author Date Id Revision
+'Author Date Id Revision'
Modified: trunk/main/dns_core.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/dns_core.c?view=diff&rev=434068&r1=434067&r2=434068
==============================================================================
--- trunk/main/dns_core.c (original)
+++ trunk/main/dns_core.c Mon Apr 6 12:05:47 2015
@@ -460,7 +460,9 @@
return -1;
}
- if (rr_type == ns_t_srv) {
+ if (rr_type == ns_t_naptr) {
+ record = dns_naptr_alloc(query, data, size);
+ } else if (rr_type == ns_t_srv) {
record = ast_dns_srv_alloc(query, data, size);
} else {
record = generic_record_alloc(query, data, size);
@@ -483,7 +485,9 @@
void ast_dns_resolver_completed(struct ast_dns_query *query)
{
- if (ast_dns_query_get_rr_type(query) == ns_t_srv) {
+ if (ast_dns_query_get_rr_type(query) == ns_t_naptr) {
+ dns_naptr_sort(query->result);
+ } else if (ast_dns_query_get_rr_type(query) == ns_t_srv) {
ast_dns_srv_sort(query->result);
}
Modified: trunk/main/dns_naptr.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/dns_naptr.c?view=diff&rev=434068&r1=434067&r2=434068
==============================================================================
--- trunk/main/dns_naptr.c (original)
+++ trunk/main/dns_naptr.c Mon Apr 6 12:05:47 2015
@@ -31,35 +31,673 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <regex.h>
+
#include "asterisk/dns_core.h"
#include "asterisk/dns_naptr.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/dns_internal.h"
+#include "asterisk/utils.h"
+
+/*!
+ * \brief Result of analyzing NAPTR flags on a record
+ */
+enum flags_result {
+ /*! Terminal record, meaning the DDDS algorithm can be stopped */
+ FLAGS_TERMINAL,
+ /*! No flags provided, likely meaning another NAPTR lookup */
+ FLAGS_EMPTY,
+ /*! Unrecognized but valid flags. We cannot conclude what they mean */
+ FLAGS_UNKNOWN,
+ /*! Non-alphanumeric or invalid combination of flags */
+ FLAGS_INVALID,
+};
+
+/*!
+ * \brief Analyze and interpret NAPTR flags as per RFC 3404
+ *
+ * \note The flags string passed into this function is NOT NULL-terminated
+ *
+ * \param flags The flags string from a NAPTR record
+ * \flags_size The size of the flags string in bytes
+ * \return flag result
+ */
+static enum flags_result interpret_flags(const char *flags, uint8_t flags_size)
+{
+ int i;
+ char known_flag_found = 0;
+
+ if (flags_size == 0) {
+ return FLAGS_EMPTY;
+ }
+
+ /* Take care of the most common (and easy) case, one character */
+ if (flags_size == 1) {
+ if (*flags == 's' || *flags == 'S' ||
+ *flags == 'a' || *flags == 'A' ||
+ *flags == 'u' || *flags == 'U') {
+ return FLAGS_TERMINAL;
+ } else if (!isalnum(*flags)) {
+ return FLAGS_INVALID;
+ } else {
+ return FLAGS_UNKNOWN;
+ }
+ }
+
+ /*
+ * Multiple flags are allowed, but you cannot mix the
+ * S, A, U, and P flags together.
+ */
+ for (i = 0; i < flags_size; ++i) {
+ if (!isalnum(flags[i])) {
+ return FLAGS_INVALID;
+ } else if (flags[i] == 's' || flags[i] == 'S') {
+ if (known_flag_found && known_flag_found != 's') {
+ return FLAGS_INVALID;
+ }
+ known_flag_found = 's';
+ } else if (flags[i] == 'u' || flags[i] == 'U') {
+ if (known_flag_found && known_flag_found != 'u') {
+ return FLAGS_INVALID;
+ }
+ known_flag_found = 'u';
+ } else if (flags[i] == 'a' || flags[i] == 'A') {
+ if (known_flag_found && known_flag_found != 'a') {
+ return FLAGS_INVALID;
+ }
+ known_flag_found = 'a';
+ } else if (flags[i] == 'p' || flags[i] == 'P') {
+ if (known_flag_found && known_flag_found != 'p') {
+ return FLAGS_INVALID;
+ }
+ known_flag_found = 'p';
+ }
+ }
+
+ return (!known_flag_found || known_flag_found == 'p') ? FLAGS_UNKNOWN : FLAGS_TERMINAL;
+}
+
+/*!
+ * \brief Analyze NAPTR services for validity as defined by RFC 3404
+ *
+ * \note The services string passed to this function is NOT NULL-terminated
+ * \param services The services string parsed from a NAPTR record
+ * \param services_size The size of the services string
+ * \retval 0 Services are valid
+ * \retval -1 Services are invalid
+ */
+static int services_invalid(const char *services, uint8_t services_size)
+{
+ const char *current_pos = services;
+ const char *end_of_services = services + services_size;
+
+ if (services_size == 0) {
+ return 0;
+ }
+
+ /* Services are broken into sections divided by a + sign. Each section
+ * must start with an alphabetic character, and then can only contain
+ * alphanumeric characters. The size of any section is limited to
+ * 32 characters
+ */
+ while (1) {
+ char *plus_pos = memchr(current_pos, '+', end_of_services - current_pos);
+ uint8_t current_size = plus_pos ? plus_pos - current_pos : end_of_services - current_pos;
+ int i;
+
+ if (!isalpha(current_pos[0])) {
+ return -1;
+ }
+
+ if (current_size > 32) {
+ return -1;
+ }
+
+ for (i = 1; i < current_size; ++i) {
+ if (!isalnum(current_pos[i])) {
+ return -1;
+ }
+ }
+
+ if (!plus_pos) {
+ break;
+ }
+ current_pos = plus_pos + 1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \brief Determine if flags in the regexp are invalid
+ *
+ * A NAPTR regexp is structured like so
+ * /pattern/repl/FLAGS
+ *
+ * This ensures that the flags on the regexp are valid. Regexp
+ * flags can either be zero or one character long. If the flags
+ * are one character long, that character must be "i" to indicate
+ * the regex evaluation is case-insensitive.
+ *
+ * \note The flags string passed to this function is not NULL-terminated
+ * \param flags The regexp flags from the NAPTR record
+ * \param end A pointer to the end of the flags string
+ * \retval 0 Flags are valid
+ * \retval -1 Flags are invalid
+ */
+static int regexp_flags_invalid(const char *flags, const char *end)
+{
+ if (flags >= end) {
+ return 0;
+ }
+
+ if (end - flags > 1) {
+ return -1;
+ }
+
+ if (*flags != 'i') {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \brief Determine if the replacement in the regexp is invalid
+ *
+ * A NAPTR regexp is structured like so
+ * /pattern/REPL/flags
+ *
+ * This ensures that the replacement on the regexp is valid. The regexp
+ * replacement is free to use any character it wants, plus backreferences
+ * and an escaped regexp delimiter.
+ *
+ * This function does not attempt to ensure that the backreferences refer
+ * to valid portions of the regexp's regex pattern.
+ *
+ * \note The repl string passed to this function is NOT NULL-terminated
+ *
+ * \param repl The regexp replacement string
+ * \param end Pointer to the end of the replacement string
+ * \param delim The delimiter character for the regexp
+ *
+ * \retval 0 Replacement is valid
+ * \retval -1 Replacement is invalid
+ */
+static int regexp_repl_invalid(const char *repl, const char *end, char delim)
+{
+ const char *ptr = repl;
+
+ if (repl == end) {
+ /* Kind of weird, but this is fine */
+ return 0;
+ }
+
+ while (1) {
+ char *backslash_pos = memchr(ptr, '\\', end - ptr);
+ if (!backslash_pos) {
+ break;
+ }
+
+ ast_assert(backslash_pos < end - 1);
+
+ /* XXX RFC 3402 is unclear about whether other backslash-escaped characters
+ * (such as a backslash-escaped backslash) are legal
+ */
+ if (!strchr("12345689", backslash_pos[1]) && backslash_pos[1] != delim) {
+ return -1;
+ }
+
+ ptr = backslash_pos + 1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \brief Determine if the pattern in a regexp is invalid
+ *
+ * A NAPTR regexp is structured like so
+ * /PATTERN/repl/flags
+ *
+ * This ensures that the pattern on the regexp is valid. The pattern is
+ * passed to a regex compiler to determine its validity.
+ *
+ * \note The pattern string passed to this function is NOT NULL-terminated
+ *
+ * \param pattern The pattern from the NAPTR record
+ * \param end A pointer to the end of the pattern
+ *
+ * \retval 0 Pattern is valid
+ * \retval non-zero Pattern is invalid
+ */
+static int regexp_pattern_invalid(const char *pattern, const char *end)
+{
+ int pattern_size = end - pattern;
+ char pattern_str[pattern_size + 1];
+ regex_t reg;
+ int res;
+
+ /* regcomp requires a NULL-terminated string */
+ memcpy(pattern_str, pattern, pattern_size);
+ pattern_str[pattern_size] = '\0';
+
+ res = regcomp(®, pattern_str, REG_EXTENDED);
+
+ regfree(®);
+
+ return res;
+}
+
+/*!
+ * \brief Determine if the regexp in a NAPTR record is invalid
+ *
+ * The goal of this function is to divide the regexp into its
+ * constituent parts and then let validation subroutines determine
+ * if each part is valid. If all parts are valid, then the entire
+ * regexp is valid.
+ *
+ * \note The regexp string passed to this function is NOT NULL-terminated
+ *
+ * \param regexp The regexp from the NAPTR record
+ * \param regexp_size The size of the regexp string
+ *
+ * \retval 0 regexp is valid
+ * \retval non-zero regexp is invalid
+ */
+static int regexp_invalid(const char *regexp, uint8_t regexp_size)
+{
+ char delim;
+ const char *delim2_pos;
+ const char *delim3_pos;
+ const char *ptr = regexp;
+ const char *end_of_regexp = regexp + regexp_size;
+ const char *regex_pos;
+ const char *repl_pos;
+ const char *flags_pos;
+
+ if (regexp_size == 0) {
+ return 0;
+ }
+
+ /* The delimiter will be a ! or / in most cases, but the rules allow
+ * for the delimiter to be nearly any character. It cannot be 'i' because
+ * the delimiter cannot be the same as regexp flags. The delimiter cannot
+ * be 1-9 because the delimiter cannot be a backreference number. RFC
+ * 2915 specified that backslash was also not allowed as a delimiter, but
+ * RFC 3402 does not say this. We've gone ahead and made the character
+ * illegal for our purposes.
+ */
+ delim = *ptr;
+ if (strchr("123456789\\i", delim)) {
+ return -1;
+ }
+ ++ptr;
+ regex_pos = ptr;
+
+ /* Find the other two delimiters. If the delim is escaped with a backslash, it doesn't count */
+ while (1) {
+ delim2_pos = memchr(ptr, delim, end_of_regexp - ptr);
+ if (!delim2_pos) {
+ return -1;
+ }
+ ptr = delim2_pos + 1;
+ if (delim2_pos[-1] != '\\') {
+ break;
+ }
+ }
+
+ if (ptr >= end_of_regexp) {
+ return -1;
+ }
+
+ repl_pos = ptr;
+
+ while (1) {
+ delim3_pos = memchr(ptr, delim, end_of_regexp - ptr);
+ if (!delim3_pos) {
+ return -1;
+ }
+ ptr = delim3_pos + 1;
+ if (delim3_pos[-1] != '\\') {
+ break;
+ }
+ }
+ flags_pos = ptr;
+
+ if (regexp_flags_invalid(flags_pos, end_of_regexp) ||
+ regexp_repl_invalid(repl_pos, delim3_pos, delim) ||
+ regexp_pattern_invalid(regex_pos, delim2_pos)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+#define PAST_END_OF_RECORD ptr >= end_of_record
+
+struct ast_dns_record *dns_naptr_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;
+ char *end_of_record;
+ enum flags_result flags_res;
+
+ /*
+ * 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);
+
+ /* Since the NAPTR record we have been given came from the DNS answer,
+ * we should never run into a situation where we can't find ourself
+ * in the answer
+ */
+ ast_assert(naptr_offset != NULL);
+ ast_assert(naptr_search_base + remaining_size - naptr_offset >= size);
+
+ /* ... but just to be on the safe side, let's be sure we can break
+ * out if the assertion doesn't hold
+ */
+ if (!naptr_offset || naptr_search_base + remaining_size - naptr_offset < size) {
+ ast_log(LOG_ERROR, "Failed to locate NAPTR record within DNS result\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;
+ }
+
+ ast_assert(ptr != NULL);
+
+ end_of_record = ptr + size;
+
+ /* ORDER */
+ /* This assignment takes a big-endian 16-bit value and stores it in the
+ * machine's native byte order. Using this method allows us to avoid potential
+ * alignment issues in case the order is not on a short-addressable boundary.
+ * See http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html for
+ * more information
+ */
+ order = ((unsigned char)(ptr[1]) << 0) | ((unsigned char)(ptr[0]) << 8);
+ ptr += 2;
+
+ if (PAST_END_OF_RECORD) {
+ return NULL;
+ }
+
+ /* PREFERENCE */
+ preference = ((unsigned char) (ptr[1]) << 0) | ((unsigned char)(ptr[0]) << 8);
+ ptr += 2;
+
+ if (PAST_END_OF_RECORD) {
+ return NULL;
+ }
+
+ /* FLAGS */
+ flags_size = *ptr;
+ ++ptr;
+ if (PAST_END_OF_RECORD) {
+ return NULL;
+ }
+ flags = ptr;
+ ptr += flags_size;
+ if (PAST_END_OF_RECORD) {
+ return NULL;
+ }
+
+ /* SERVICES */
+ services_size = *ptr;
+ ++ptr;
+ if (PAST_END_OF_RECORD) {
+ return NULL;
+ }
+ services = ptr;
+ ptr += services_size;
+ if (PAST_END_OF_RECORD) {
+ return NULL;
+ }
+
+ /* REGEXP */
+ regexp_size = *ptr;
+ ++ptr;
+ if (PAST_END_OF_RECORD) {
+ return NULL;
+ }
+ regexp = ptr;
+ ptr += regexp_size;
+ if (PAST_END_OF_RECORD) {
+ return NULL;
+ }
+
+ replacement_size = dn_expand((unsigned char *)query->result->answer, (unsigned char *) end_of_record, (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;
+ }
+
+ ptr += replacement_size;
+
+ if (ptr != end_of_record) {
+ ast_log(LOG_ERROR, "NAPTR record gave undersized string indications.\n");
+ return NULL;
+ }
+
+ /* We've validated the size of the NAPTR record. Now we can validate
+ * the individual parts
+ */
+ flags_res = interpret_flags(flags, flags_size);
+ if (flags_res == FLAGS_INVALID) {
+ ast_log(LOG_ERROR, "NAPTR Record contained invalid flags %.*s\n", flags_size, flags);
+ return NULL;
+ }
+
+ if (services_invalid(services, services_size)) {
+ ast_log(LOG_ERROR, "NAPTR record contained invalid services %.*s\n", services_size, services);
+ return NULL;
+ }
+
+ if (regexp_invalid(regexp, regexp_size)) {
+ ast_log(LOG_ERROR, "NAPTR record contained invalid regexp %.*s\n", regexp_size, regexp);
+ return NULL;
+ }
+
+ /* replacement_size takes into account the NULL label, so a NAPTR record with no replacement
+ * will have a replacement_size of 1.
+ */
+ if (regexp_size && replacement_size > 1) {
+ ast_log(LOG_ERROR, "NAPTR record contained both a regexp and replacement\n");
+ 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->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;
+
+ naptr->generic.data_ptr = naptr->data;
+
+ return (struct ast_dns_record *)naptr;
+}
+
+
+static int compare_order(const void *record1, const void *record2)
+{
+ const struct ast_dns_naptr_record **left = (const struct ast_dns_naptr_record **)record1;
+ const struct ast_dns_naptr_record **right = (const struct ast_dns_naptr_record **)record2;
+
+ if ((*left)->order < (*right)->order) {
+ return -1;
+ } else if ((*left)->order > (*right)->order) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int compare_preference(const void *record1, const void *record2)
+{
+ const struct ast_dns_naptr_record **left = (const struct ast_dns_naptr_record **)record1;
+ const struct ast_dns_naptr_record **right = (const struct ast_dns_naptr_record **)record2;
+
+ if ((*left)->preference < (*right)->preference) {
+ return -1;
+ } else if ((*left)->preference > (*right)->preference) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void dns_naptr_sort(struct ast_dns_result *result)
+{
+ struct ast_dns_record *current;
+ size_t num_records = 0;
+ struct ast_dns_naptr_record **records;
+ int i = 0;
+ int j = 0;
+ int cur_order;
+
+ /* Determine the number of records */
+ AST_LIST_TRAVERSE(&result->records, current, list) {
+ ++num_records;
+ }
+
+ /* No point in continuing if there are no records */
+ if (num_records == 0) {
+ return;
+ }
+
+ /* Allocate an array with that number of records */
+ records = ast_alloca(num_records * sizeof(*records));
+
+ /* Move records from the list to the array */
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&result->records, current, list) {
+ records[i++] = (struct ast_dns_naptr_record *) current;
+ AST_LIST_REMOVE_CURRENT(list);
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+
+ /* Sort the array by order */
+ qsort(records, num_records, sizeof(*records), compare_order);
+
+ /* Sort subarrays by preference */
+ for (i = 0; i < num_records; i = j) {
+ cur_order = records[i]->order;
+ for (j = i + 1; j < num_records; ++j) {
+ if (records[j]->order != cur_order) {
+ break;
+ }
+ }
+ qsort(&records[i], j - i, sizeof(*records), compare_preference);
+ }
+
+ /* Place sorted records back into the original list */
+ for (i = 0; i < num_records; ++i) {
+ AST_LIST_INSERT_TAIL(&result->records, (struct ast_dns_record *)(records[i]), list);
+ }
+}
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: trunk/res/res_resolver_unbound.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_resolver_unbound.c?view=diff&rev=434068&r1=434067&r2=434068
==============================================================================
--- trunk/res/res_resolver_unbound.c (original)
+++ trunk/res/res_resolver_unbound.c Mon Apr 6 12:05:47 2015
@@ -303,7 +303,6 @@
ao2_ref(data, -1);
ao2_ref(cfg, -1);
-
return res;
}
@@ -492,6 +491,8 @@
}
#ifdef TEST_FRAMEWORK
+
+#include "asterisk/dns_naptr.h"
/*!
* \brief A DNS record to be used during a test
@@ -1186,6 +1187,123 @@
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";
+ int i;
+ enum ast_test_result_state res = AST_TEST_PASS;
+
+ struct naptr_record {
+ const char *zone_entry;
+ uint16_t order;
+ uint16_t preference;
+ const char *flags;
+ const char *services;
+ const char *regexp;
+ const char *replacement;
+ int visited;
+ } records [] = {
+ { "goose.feathers 12345 IN NAPTR 100 100 A SIP+D2U \"\" goose.down", 100, 100, "A", "SIP+D2U", "", "goose.down", 0},
+ { "goose.feathers 12345 IN NAPTR 100 200 A SIP+D2T \"\" duck.down", 100, 200, "A", "SIP+D2T", "", "duck.down", 0},
+ { "goose.feathers 12345 IN NAPTR 200 100 A SIPS+D2U \"\" pheasant.down", 200, 100, "A", "SIPS+D2U", "", "pheasant.down", 0},
+ { "goose.feathers 12345 IN NAPTR 200 200 A SIPS+D2T \"\" platypus.fur", 200, 200, "A", "SIPS+D2T", "", "platypus.fur", 0},
+ };
+
+ 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");
+
+ for (i = 0; i < ARRAY_LEN(records); ++i) {
+ ub_ctx_data_add(resolver->context, records[i].zone_entry);
+ }
+
+ 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;
+ }
+
+ i = 0;
+ for (record = ast_dns_result_get_records(result); record; record = ast_dns_record_get_next(record)) {
+ if (ast_dns_naptr_get_order(record) != records[i].order) {
+ ast_test_status_update(test, "Expected order %hu, got order %hu from NAPTR record\n",
+ records[i].order, ast_dns_naptr_get_order(record));
+ res = AST_TEST_FAIL;
+ }
+ if (ast_dns_naptr_get_preference(record) != records[i].preference) {
+ ast_test_status_update(test, "Expected preference %hu, got preference %hu from NAPTR record\n",
+ records[i].preference, ast_dns_naptr_get_preference(record));
+ res = AST_TEST_FAIL;
+ }
+ if (strcmp(ast_dns_naptr_get_flags(record), records[i].flags)) {
+ ast_test_status_update(test, "Expected flags %s, got flags %s from NAPTR record\n",
+ records[i].flags, ast_dns_naptr_get_flags(record));
+ res = AST_TEST_FAIL;
+ }
+ if (strcmp(ast_dns_naptr_get_service(record), records[i].services)) {
+ ast_test_status_update(test, "Expected services %s, got services %s from NAPTR record\n",
+ records[i].services, ast_dns_naptr_get_service(record));
+ res = AST_TEST_FAIL;
+ }
+ if (strcmp(ast_dns_naptr_get_regexp(record), records[i].regexp)) {
+ ast_test_status_update(test, "Expected regexp %s, got regexp %s from NAPTR record\n",
+ records[i].regexp, ast_dns_naptr_get_regexp(record));
+ res = AST_TEST_FAIL;
+ }
+ if (strcmp(ast_dns_naptr_get_replacement(record), records[i].replacement)) {
+ ast_test_status_update(test, "Expected replacement %s, got replacement %s from NAPTR record\n",
+ records[i].replacement, ast_dns_naptr_get_replacement(record));
+ res = AST_TEST_FAIL;
+ }
+ records[i].visited = 1;
+ ++i;
+ }
+
+ if (i != ARRAY_LEN(records)) {
+ ast_test_status_update(test, "Unexpected number of records visited\n");
+ res = AST_TEST_FAIL;
+ }
+
+ for (i = 0; i < ARRAY_LEN(records); ++i) {
+ if (!records[i].visited) {
+ ast_test_status_update(test, "Did not visit all expected NAPTR records\n");
+ res = AST_TEST_FAIL;
+ }
+ }
+
+ return res;
+
+}
+
AST_TEST_DEFINE(resolve_srv)
{
RAII_VAR(struct unbound_resolver *, resolver, NULL, ao2_cleanup);
@@ -1274,6 +1392,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);
AST_TEST_UNREGISTER(resolve_srv);
return 0;
}
@@ -1331,6 +1450,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);
AST_TEST_REGISTER(resolve_srv);
return AST_MODULE_LOAD_SUCCESS;
Propchange: trunk/tests/test_dns.c
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Mon Apr 6 12:05:47 2015
@@ -1,1 +1,1 @@
-Author Date Id Revision
+'Author Date Id Revision'
Propchange: trunk/tests/test_dns_recurring.c
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Mon Apr 6 12:05:47 2015
@@ -1,1 +1,1 @@
-Author Date Id Revision
+'Author Date Id Revision'
More information about the asterisk-commits
mailing list