Author: mmichelson
Date: Mon Apr  6 11:59:22 2015
New Revision: 434067

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=434067
Log:
Merge NAPTR changes into the main DNS branch.

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

Modified: team/group/dns/include/asterisk/dns_internal.h
URL: 
http://svnview.digium.com/svn/asterisk/team/group/dns/include/asterisk/dns_internal.h?view=diff&rev=434067&r1=434066&r2=434067
==============================================================================
--- team/group/dns/include/asterisk/dns_internal.h (original)
+++ team/group/dns/include/asterisk/dns_internal.h Mon Apr  6 11:59:22 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);
 
-

Modified: team/group/dns/main/dns_core.c
URL: 
http://svnview.digium.com/svn/asterisk/team/group/dns/main/dns_core.c?view=diff&rev=434067&r1=434066&r2=434067
==============================================================================
--- team/group/dns/main/dns_core.c (original)
+++ team/group/dns/main/dns_core.c Mon Apr  6 11:59:22 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: team/group/dns/main/dns_naptr.c
URL: 
http://svnview.digium.com/svn/asterisk/team/group/dns/main/dns_naptr.c?view=diff&rev=434067&r1=434066&r2=434067
==============================================================================
--- team/group/dns/main/dns_naptr.c (original)
+++ team/group/dns/main/dns_naptr.c Mon Apr  6 11:59:22 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(&reg, pattern_str, REG_EXTENDED);
+
+       regfree(&reg);
+
+       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: team/group/dns/res/res_resolver_unbound.c
URL: 
http://svnview.digium.com/svn/asterisk/team/group/dns/res/res_resolver_unbound.c?view=diff&rev=434067&r1=434066&r2=434067
==============================================================================
--- team/group/dns/res/res_resolver_unbound.c (original)
+++ team/group/dns/res/res_resolver_unbound.c Mon Apr  6 11:59:22 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;


-- 
_____________________________________________________________________
-- Bandwidth and Colocation Provided by http://www.api-digital.com --

svn-commits mailing list
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/svn-commits

Reply via email to