summaryrefslogtreecommitdiff
path: root/main/dns_system_resolver.c
diff options
context:
space:
mode:
authorAshley Sanders <asanders@digium.com>2015-07-07 15:03:34 -0500
committerAshley Sanders <asanders@digium.com>2015-07-07 21:31:49 -0500
commit3cdfd39af7c632403bff34fdbf2c4945cd02bb79 (patch)
tree524730d0dcaf6057306c4b8c1976f020cecacce1 /main/dns_system_resolver.c
parentc12ace3ab31bd61606252f5a3721ce720d2ad209 (diff)
DNS: Create a system-level DNS resolver
Prior to this patch, the DNS core present in master had no default system-level resolver implementation. Therefore, it was not possible for the DNS core to perform resolutions unless the libunbound library was installed and the res_resolver_unbound module was loaded. This patch introduces a system-level DNS resolver implementation that will register itself with the lowest consideration priority available (to ensure that it is to be used only as a last resort). The resolver relies on low-level DNS search functions to perform a rudimentary DNS search based on a provided query and then supplies the search results to the DNS core. ASTERISK-25146 #close Reported By: Joshua Colp Change-Id: I3b36ea17b889a98df4f8d80d50bb7ee175afa077
Diffstat (limited to 'main/dns_system_resolver.c')
-rwxr-xr-xmain/dns_system_resolver.c267
1 files changed, 267 insertions, 0 deletions
diff --git a/main/dns_system_resolver.c b/main/dns_system_resolver.c
new file mode 100755
index 000000000..a5ac77127
--- /dev/null
+++ b/main/dns_system_resolver.c
@@ -0,0 +1,267 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2015, Digium, Inc.
+ *
+ * Ashley Sanders <asanders@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief The default DNS resolver for Asterisk.
+ *
+ * \arg See also \ref res_resolver_unbound
+ *
+ * \author Ashley Sanders <asanders@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_REGISTER_FILE()
+
+#include "asterisk/_private.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/dns.h"
+#include "asterisk/dns_core.h"
+#include "asterisk/dns_resolver.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/taskprocessor.h"
+
+/*! \brief The consideration priority for this resolver implementation. */
+#define DNS_SYSTEM_RESOLVER_PRIORITY INT_MAX
+
+/*! \brief Resolver return code upon success. */
+#define DNS_SYSTEM_RESOLVER_SUCCESS 0
+
+/*! \brief Resolver return code upon failure. */
+#define DNS_SYSTEM_RESOLVER_FAILURE -1
+
+
+static int dns_system_resolver_add_record(void *context, unsigned char *record, int record_len, int ttl);
+static int dns_system_resolver_cancel(struct ast_dns_query *query);
+static void dns_system_resolver_destroy(void);
+static int dns_system_resolver_process_query(void *data);
+static int dns_system_resolver_resolve(struct ast_dns_query *query);
+static int dns_system_resolver_set_response(void *context, unsigned char *dns_response, int dns_response_len, int rcode);
+
+
+/*! \brief The task processor to use for making DNS searches asynchronous. */
+static struct ast_taskprocessor *dns_system_resolver_tp;
+
+/*! \brief The base definition for the dns_system_resolver */
+struct ast_dns_resolver dns_system_resolver_base = {
+ .name = "system",
+ .priority = DNS_SYSTEM_RESOLVER_PRIORITY,
+ .resolve = dns_system_resolver_resolve,
+ .cancel = dns_system_resolver_cancel,
+};
+
+/*!
+ * \brief Callback to handle processing resource records.
+ *
+ * \details Adds an individual resource record discovered with ast_search_dns_ex to the
+ * ast_dns_query currently being resolved.
+ *
+ * \internal
+ *
+ * \param context A void pointer to the ast_dns_query being processed.
+ * \param record An individual resource record discovered during the DNS search.
+ * \param record_len The length of the resource record.
+ * \param ttl The resource record's expiration time limit (time to live).
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+static int dns_system_resolver_add_record(void *context, unsigned char *record, int record_len, int ttl)
+{
+ struct ast_dns_query *query = context;
+
+ /* Add the record to the query.*/
+ return ast_dns_resolver_add_record(query,
+ ast_dns_query_get_rr_type(query),
+ ast_dns_query_get_rr_class(query),
+ ttl,
+ (const char*) record,
+ record_len);
+}
+
+/*!
+ * \brief Cancels processing resolution for a given query.
+ *
+ * \note The system API calls block so there is no way to cancel them. Therefore, this function always
+ * returns failure when invoked.
+ *
+ * \internal
+ *
+ * \param query The ast_dns_query to cancel.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+static int dns_system_resolver_cancel(struct ast_dns_query *query)
+{
+ return DNS_SYSTEM_RESOLVER_FAILURE;
+}
+
+/*!
+ * \brief Destructor.
+ *
+ * \internal
+ */
+static void dns_system_resolver_destroy(void)
+{
+ /* Unreference the task processor */
+ dns_system_resolver_tp = ast_taskprocessor_unreference(dns_system_resolver_tp);
+
+ /* Unregister the base resolver */
+ ast_dns_resolver_unregister(&dns_system_resolver_base);
+}
+
+/*!
+ * \brief Callback to handle processing the query from the ast_taskprocessor instance.
+ *
+ * \internal
+ *
+ * \param data A void pointer to the ast_dns_query being processed.
+ *
+ * \retval -1 on search failure
+ * \retval 0 on no records found
+ * \retval 1 on success
+ */
+static int dns_system_resolver_process_query(void *data)
+{
+ struct ast_dns_query *query = data;
+
+ /* Perform the DNS search */
+ enum ast_dns_search_result res = ast_search_dns_ex(query,
+ ast_dns_query_get_name(query),
+ ast_dns_query_get_rr_class(query),
+ ast_dns_query_get_rr_type(query),
+ dns_system_resolver_set_response,
+ dns_system_resolver_add_record);
+
+ /* Handle the possible return values from the DNS search */
+ if (res == AST_DNS_SEARCH_FAILURE) {
+ ast_log(LOG_ERROR, "DNS search failed for query: '%s'\n",
+ ast_dns_query_get_name(query));
+ } else if (res == AST_DNS_SEARCH_NO_RECORDS) {
+ ast_log(LOG_WARNING, "DNS search failed to yield any results for query: '%s'\n",
+ ast_dns_query_get_name(query));
+ }
+
+ /* Mark the query as complete */
+ ast_dns_resolver_completed(query);
+
+ /* Reduce the reference count on the query object */
+ ao2_ref(query, -1);
+
+ return res;
+}
+
+/*!
+ * \brief Resolves a DNS query.
+ *
+ * \internal
+ *
+ * \param query The ast_dns_query to resolve.
+ *
+ * \retval 0 on successful load of query handler to the ast_taskprocessor instance
+ * \retval -1 on failure to load the query handler to the ast_taskprocessor instance
+ */
+static int dns_system_resolver_resolve(struct ast_dns_query *query)
+{
+ /* Add query processing handler to the task processor */
+ int res = ast_taskprocessor_push(dns_system_resolver_tp,
+ dns_system_resolver_process_query,
+ ao2_bump(query));
+
+ /* The query processing handler was not added to the task processor */
+ if (res < 0) {
+ ast_log(LOG_ERROR, "Failed to perform async DNS resolution of '%s'\n",
+ ast_dns_query_get_name(query));
+ ao2_ref(query, -1);
+ }
+
+ /* Return the result of adding the query processing handler to the task processor */
+ return res;
+}
+
+/*!
+ * \brief Callback to handle initializing the results field.
+ *
+ * \internal
+ *
+ * \param dns_response The full DNS response.
+ * \param dns_response The length of the full DNS response.
+ * \param rcode The DNS response code.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+static int dns_system_resolver_set_response(void *context, unsigned char *dns_response, int dns_response_len, int rcode)
+{
+ struct ast_dns_query *query = context;
+ int res;
+
+ /* Instantiate the query's result field (if necessary). */
+ if (!ast_dns_query_get_result(query)) {
+ res = ast_dns_resolver_set_result(query,
+ 0,
+ 0,
+ rcode,
+ ast_dns_query_get_name(query),
+ (const char*) dns_response,
+ dns_response_len);
+
+ if (res) {
+ /* There was a problem instantiating the results field. */
+ ast_log(LOG_ERROR, "Could not instantiate the results field for query: '%s'\n",
+ ast_dns_query_get_name(query));
+ }
+ } else {
+ res = DNS_SYSTEM_RESOLVER_SUCCESS;
+ }
+
+ return res;
+}
+
+/*!
+ * \brief Initializes the resolver.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int ast_dns_system_resolver_init(void)
+{
+ /* Register the base resolver */
+ int res = ast_dns_resolver_register(&dns_system_resolver_base);
+
+ if (res) {
+ return DNS_SYSTEM_RESOLVER_FAILURE;
+ }
+
+ /* Instantiate the task processor */
+ dns_system_resolver_tp = ast_taskprocessor_get("dns_system_resolver_tp",
+ TPS_REF_DEFAULT);
+
+ /* Return error if the task processor failed to instantiate */
+ if (!dns_system_resolver_tp) {
+ dns_system_resolver_destroy();
+ return DNS_SYSTEM_RESOLVER_FAILURE;
+ }
+
+ /* Register the cleanup function */
+ ast_register_cleanup(dns_system_resolver_destroy);
+
+ return DNS_SYSTEM_RESOLVER_SUCCESS;
+}