<p>George Joseph <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/13907">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved; Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">dns_txt: Add TXT record parsing support<br><br>Change-Id: Ie0eca23b8e6f4c7d9846b6013d79099314d90ef5<br>---<br>M include/asterisk/dns_internal.h<br>A include/asterisk/dns_txt.h<br>M main/dns_core.c<br>A main/dns_txt.c<br>4 files changed, 218 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/dns_internal.h b/include/asterisk/dns_internal.h</span><br><span>index 7ce0c28..3d2d0df 100644</span><br><span>--- a/include/asterisk/dns_internal.h</span><br><span>+++ b/include/asterisk/dns_internal.h</span><br><span>@@ -26,6 +26,9 @@</span><br><span> #ifndef _ASTERISK_DNS_INTERNAL_H</span><br><span> #define _ASTERISK_DNS_INTERNAL_H</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief For AST_LIST */</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/linkedlists.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief For AST_VECTOR */</span><br><span> #include "asterisk/vector.h"</span><br><span> </span><br><span>@@ -57,6 +60,16 @@</span><br><span>        char data[0];</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief A TXT record */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_dns_txt_record {</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! \brief Generic DNS record information */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_dns_record generic;</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! \brief The number of character strings in the TXT record */</span><br><span style="color: hsl(120, 100%, 40%);">+       size_t count;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief The raw DNS record */</span><br><span style="color: hsl(120, 100%, 40%);">+      char data[0];</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief An SRV record */</span><br><span> struct ast_dns_srv_record {</span><br><span>    /*! \brief Generic DNS record information */</span><br><span>@@ -200,6 +213,19 @@</span><br><span> struct ast_sched_context *ast_dns_get_sched(void);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Allocate and parse a DNS TXT record</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.10.0, 17.4.0</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param query The DNS query</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param data This specific TXT record</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param size The size of the TXT record</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-NULL success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL failure</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_dns_record *dns_txt_alloc(struct ast_dns_query *query, const char *data, const size_t size);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Allocate and parse a DNS NAPTR record</span><br><span>  *</span><br><span>  * \param query The DNS query</span><br><span>diff --git a/include/asterisk/dns_txt.h b/include/asterisk/dns_txt.h</span><br><span>new file mode 100644</span><br><span>index 0000000..368a861</span><br><span>--- /dev/null</span><br><span>+++ b/include/asterisk/dns_txt.h</span><br><span>@@ -0,0 +1,64 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2020, Sean Bright</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Sean Bright <sean.bright@gmail.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief DNS TXT Record Parsing API</span><br><span style="color: hsl(120, 100%, 40%);">+ * \author Sean Bright <sean.bright@gmail.com></span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef ASTERISK_DNS_TXT_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define ASTERISK_DNS_TXT_H</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(__cplusplus) || defined(c_plusplus)</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Get the number of character strings in a TXT record</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.10.0, 17.4.0</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param record The DNS record</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return the number of character strings in this TXT record</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+size_t ast_dns_txt_get_count(const struct ast_dns_record *record);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Get the character strings from this TXT record</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.10.0, 17.4.0</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param record The DNS record</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL Unable to allocate memory</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return Vector of strings. Free with ast_dns_txt_free_strings</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_vector_string *ast_dns_txt_get_strings(const struct ast_dns_record *record);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Free strings returned by ast_dns_txt_get_strings</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.10.0, 17.4.0</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param strings The vector to free</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_dns_txt_free_strings(struct ast_vector_string *strings);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(__cplusplus) || defined(c_plusplus)</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* ASTERISK_DNS_TXT_H */</span><br><span>diff --git a/main/dns_core.c b/main/dns_core.c</span><br><span>index f262d7d..0fb0731 100644</span><br><span>--- a/main/dns_core.c</span><br><span>+++ b/main/dns_core.c</span><br><span>@@ -516,8 +516,9 @@</span><br><span> typedef struct ast_dns_record *(*dns_alloc_fn)(struct ast_dns_query *query, const char *data, const size_t size);</span><br><span> </span><br><span> static dns_alloc_fn dns_alloc_table [] = {</span><br><span style="color: hsl(120, 100%, 40%);">+     [T_TXT]   = dns_txt_alloc,</span><br><span>   [T_NAPTR] = dns_naptr_alloc,</span><br><span style="color: hsl(0, 100%, 40%);">-    [T_SRV] = dns_srv_alloc,</span><br><span style="color: hsl(120, 100%, 40%);">+      [T_SRV]   = dns_srv_alloc,</span><br><span> };</span><br><span> </span><br><span> static struct ast_dns_record *allocate_dns_record(unsigned int rr_type, struct ast_dns_query *query, const char *data, const size_t size)</span><br><span>diff --git a/main/dns_txt.c b/main/dns_txt.c</span><br><span>new file mode 100644</span><br><span>index 0000000..5c1c581</span><br><span>--- /dev/null</span><br><span>+++ b/main/dns_txt.c</span><br><span>@@ -0,0 +1,126 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2020, Sean Bright</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Sean Bright <sean.bright@gmail.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief DNS TXT Record Parsing API</span><br><span style="color: hsl(120, 100%, 40%);">+ * \author Sean Bright <sean.bright@gmail.com></span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*** MODULEINFO</span><br><span style="color: hsl(120, 100%, 40%);">+        <support_level>core</support_level></span><br><span style="color: hsl(120, 100%, 40%);">+ ***/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <resolv.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/dns_core.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/dns_txt.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/dns_internal.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/utils.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_dns_record *dns_txt_alloc(struct ast_dns_query *query, const char *data, const size_t size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_dns_txt_record *txt;</span><br><span style="color: hsl(120, 100%, 40%);">+       const char *end_of_record = data + size;</span><br><span style="color: hsl(120, 100%, 40%);">+      size_t count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Because we can't allocate additional memory, the best we can do here is just</span><br><span style="color: hsl(120, 100%, 40%);">+    * validate that this conforms to a TXT record. */</span><br><span style="color: hsl(120, 100%, 40%);">+    while (data < end_of_record) {</span><br><span style="color: hsl(120, 100%, 40%);">+             uint8_t byte_count = (uint8_t) *data;</span><br><span style="color: hsl(120, 100%, 40%);">+         count++;</span><br><span style="color: hsl(120, 100%, 40%);">+              data += byte_count + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (data != end_of_record) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* This is not a valid TXT record, so we can bail out */</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   txt = ast_calloc(1, sizeof(*txt) + size);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!txt) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   txt->count = count;</span><br><span style="color: hsl(120, 100%, 40%);">+        txt->generic.data_ptr = txt->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return (struct ast_dns_record *) txt;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+size_t ast_dns_txt_get_count(const struct ast_dns_record *record)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_dns_txt_record *txt = (struct ast_dns_txt_record *) record;</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_assert(ast_dns_record_get_rr_type(record) == T_TXT);</span><br><span style="color: hsl(120, 100%, 40%);">+      return txt->count;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_vector_string *ast_dns_txt_get_strings(const struct ast_dns_record *record)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_vector_string *strings;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  const size_t size = ast_dns_record_get_data_size(record);</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *data = ast_dns_record_get_data(record);</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *end_of_record = data + size;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_assert(ast_dns_record_get_rr_type(record) == T_TXT);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    strings = ast_malloc(sizeof(struct ast_vector_const_string));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!strings) {</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (AST_VECTOR_INIT(strings, ast_dns_txt_get_count(record))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_free(strings);</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   while (data < end_of_record) {</span><br><span style="color: hsl(120, 100%, 40%);">+             char *s;</span><br><span style="color: hsl(120, 100%, 40%);">+              uint8_t bytes = (uint8_t) *data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            s = ast_malloc(bytes + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!s) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_dns_txt_free_strings(strings);</span><br><span style="color: hsl(120, 100%, 40%);">+                    return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           memcpy(s, &data[1], bytes);</span><br><span style="color: hsl(120, 100%, 40%);">+               s[bytes] = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* We know the size in advance so this can't fail */</span><br><span style="color: hsl(120, 100%, 40%);">+              AST_VECTOR_APPEND(strings, s);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              data += bytes + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Sanity check */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (data != end_of_record) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_dns_txt_free_strings(strings);</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return strings;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_dns_txt_free_strings(struct ast_vector_string *strings)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_VECTOR_CALLBACK_VOID(strings, ast_free);</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_VECTOR_PTR_FREE(strings);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/13907">change 13907</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/13907"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: Ie0eca23b8e6f4c7d9846b6013d79099314d90ef5 </div>
<div style="display:none"> Gerrit-Change-Number: 13907 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: Sean Bright <sean.bright@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>