Merge "DNS: Create a system-level DNS resolver"
This commit is contained in:
commit
af3f4b342b
5 changed files with 628 additions and 23 deletions
|
@ -29,6 +29,7 @@ int ast_cli_perms_init(int reload); /*!< Provided by cli.c */
|
|||
int dnsmgr_init(void); /*!< Provided by dnsmgr.c */
|
||||
void dnsmgr_start_refresh(void); /*!< Provided by dnsmgr.c */
|
||||
int dnsmgr_reload(void); /*!< Provided by dnsmgr.c */
|
||||
int ast_dns_system_resolver_init(void); /*!< Provided by dns_system_resolver.c */
|
||||
void threadstorage_init(void); /*!< Provided by threadstorage.c */
|
||||
int ast_device_state_engine_init(void); /*!< Provided by devicestate.c */
|
||||
int astobj2_init(void); /*!< Provided by astobj2.c */
|
||||
|
|
|
@ -24,17 +24,63 @@
|
|||
#ifndef _ASTERISK_DNS_H
|
||||
#define _ASTERISK_DNS_H
|
||||
|
||||
/*! \brief Perform DNS lookup (used by DNS, enum and SRV lookups)
|
||||
\param context
|
||||
\param dname Domain name to lookup (host, SRV domain, TXT record name)
|
||||
\param class Record Class (see "man res_search")
|
||||
\param type Record type (see "man res_search")
|
||||
\param callback Callback function for handling DNS result
|
||||
\note Asterisk DNS is synchronus at this time. This means that if your DNS
|
||||
services does not work, Asterisk may lock while waiting for response.
|
||||
*/
|
||||
/*! \brief DNS search return values */
|
||||
enum ast_dns_search_result {
|
||||
AST_DNS_SEARCH_FAILURE = -1, /*!< DNS search resulted in failure */
|
||||
AST_DNS_SEARCH_NO_RECORDS = 0, /*!< DNS search yielded no results */
|
||||
AST_DNS_SEARCH_SUCCESS = 1 /*!< DNS search yielded at least one discovered record */
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Perform DNS lookup (used by DNS, enum and SRV lookups)
|
||||
*
|
||||
* \param context Void pointer containing data to use in the callback function.
|
||||
* \param dname Domain name to lookup (host, SRV domain, TXT record name).
|
||||
* \param class Record Class (see "man res_search").
|
||||
* \param type Record type (see "man res_search").
|
||||
* \param answer The full DNS response.
|
||||
* \param len The length of the full DNS response.
|
||||
* \param callback Callback function for handling the discovered resource records from
|
||||
* the DNS search.
|
||||
*
|
||||
* \retval -1 on search failure
|
||||
* \retval 0 on no records found
|
||||
* \retval 1 on success
|
||||
*
|
||||
* \note Asterisk DNS is synchronus at this time. This means that if your DNS
|
||||
* service does not work, Asterisk may lock while waiting for a response.
|
||||
*/
|
||||
int ast_search_dns(void *context, const char *dname, int class, int type,
|
||||
int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer));
|
||||
int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer));
|
||||
|
||||
/*!
|
||||
* \brief Extended version of the DNS search function.
|
||||
*
|
||||
* \details Performs a DNS lookup, (used by DNS, enum and SRV lookups), parses the
|
||||
* results and notifies the observer with the response and discovered records
|
||||
* via invoking the provided callbacks (used by ast_dns_system_resolver).
|
||||
*
|
||||
* \param context Void pointer containing data to use in the handler functions.
|
||||
* \param dname Domain name to lookup (host, SRV domain, TXT record name).
|
||||
* \param rr_class Record Class (see "man res_search").
|
||||
* \param rr_type Record type (see "man res_search").
|
||||
* \param response_handler Callback function for handling the DNS response. Invoked upon
|
||||
* completion of the DNS search.
|
||||
* \param record_handler Callback function for handling the discovered resource
|
||||
* records from the DNS search. Invoked n times, where n is the
|
||||
* number of records discovered while parsing the DNS
|
||||
* response.
|
||||
*
|
||||
* \retval AST_DNS_SEARCH_FAILURE on search failure
|
||||
* \retval AST_DNS_SEARCH_NO_RECORDS on no records found
|
||||
* \retval AST_DNS_SEARCH_SUCCESS on success
|
||||
*
|
||||
* \note Asterisk DNS is synchronus at this time. This means that if your DNS
|
||||
* service does not work, Asterisk may lock while waiting for a response.
|
||||
*/
|
||||
enum ast_dns_search_result ast_search_dns_ex(void *context, const char *dname, int rr_class, int rr_type,
|
||||
int (*response_handler)(void *context, unsigned char *dns_response, int dns_response_len, int rcode),
|
||||
int (*record_handler)(void *context, unsigned char *record, int record_len, int ttl));
|
||||
|
||||
/*! \brief Retrieve the configured nameservers of the system */
|
||||
struct ao2_container *ast_dns_get_nameservers(void);
|
||||
|
|
|
@ -4511,6 +4511,11 @@ int main(int argc, char *argv[])
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if (ast_dns_system_resolver_init()) { /* Initialize the default DNS resolver */
|
||||
printf("Failed: ast_dns_system_resolver_init\n%s", term_quit());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((moduleresult = load_modules(1))) { /* Load modules, pre-load only */
|
||||
printf("Failed: load_modules\n%s", term_quit());
|
||||
exit(moduleresult == -2 ? 2 : 1);
|
||||
|
|
312
main/dns.c
312
main/dns.c
|
@ -45,6 +45,7 @@ ASTERISK_REGISTER_FILE()
|
|||
#include "asterisk/dns.h"
|
||||
#include "asterisk/endian.h"
|
||||
|
||||
/*! \brief The maximum size permitted for the answer from the DNS server */
|
||||
#define MAX_SIZE 4096
|
||||
|
||||
#ifdef __PDP_ENDIAN
|
||||
|
@ -59,6 +60,10 @@ ASTERISK_REGISTER_FILE()
|
|||
#define DETERMINED_BYTE_ORDER __LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_RES_NINIT
|
||||
AST_MUTEX_DEFINE_STATIC(res_lock);
|
||||
#endif
|
||||
|
||||
/* The dns_HEADER structure definition below originated
|
||||
in the arpa/nameser.h header file distributed with ISC
|
||||
BIND, which contains the following copyright and license
|
||||
|
@ -156,12 +161,23 @@ typedef struct {
|
|||
} dns_HEADER;
|
||||
|
||||
struct dn_answer {
|
||||
unsigned short rtype;
|
||||
unsigned short class;
|
||||
unsigned int ttl;
|
||||
unsigned short size;
|
||||
unsigned short rtype; /*!< The resource record type. */
|
||||
unsigned short class; /*!< The resource record class. */
|
||||
unsigned int ttl; /*!< The resource record time to live. */
|
||||
unsigned short size; /*!< The resource record size. */
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/*!
|
||||
* \brief Tries to find the position of the next field in the DNS response.
|
||||
*
|
||||
* \internal
|
||||
*
|
||||
* \param s A char pointer to the current frame in the DNS response.
|
||||
* \param len The remaining available length of the DNS response.
|
||||
*
|
||||
* \retval The position of the next field
|
||||
* \retval -1 if there are no remaining fields
|
||||
*/
|
||||
static int skip_name(unsigned char *s, int len)
|
||||
{
|
||||
int x = 0;
|
||||
|
@ -172,20 +188,149 @@ static int skip_name(unsigned char *s, int len)
|
|||
x++;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((*s & 0xc0) == 0xc0) {
|
||||
s += 2;
|
||||
x += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
x += *s + 1;
|
||||
s += *s + 1;
|
||||
}
|
||||
if (x >= len)
|
||||
return -1;
|
||||
|
||||
/* If we are out of room to search, return failure. */
|
||||
if (x >= len) {
|
||||
return AST_DNS_SEARCH_FAILURE;
|
||||
}
|
||||
|
||||
/* Return the value for the current position in the DNS response. This is the start
|
||||
position of the next field. */
|
||||
return x;
|
||||
}
|
||||
|
||||
/*! \brief Parse DNS lookup result, call callback */
|
||||
/*!
|
||||
* \brief Advances the position of the DNS response pointer by the size of the current field.
|
||||
*
|
||||
* \internal
|
||||
*
|
||||
* \param dns_response A pointer to a char pointer to the current field in the DNS response.
|
||||
* \param remaining_len The remaining available length in the DNS response to search.
|
||||
* \param field_size A positive value representing the size of the current field
|
||||
pointed to by the dns_response parameter.
|
||||
*
|
||||
* \retval The remaining length in the DNS response
|
||||
* \retval -1 there are no frames remaining in the DNS response
|
||||
*/
|
||||
static int dns_advance_field(unsigned char **dns_response, int remaining_len, int field_size)
|
||||
{
|
||||
if (dns_response == NULL || field_size < 0 || remaining_len < field_size) {
|
||||
return AST_DNS_SEARCH_FAILURE;
|
||||
}
|
||||
|
||||
*dns_response += field_size;
|
||||
remaining_len -= field_size;
|
||||
|
||||
return remaining_len;
|
||||
}
|
||||
|
||||
#ifndef HAVE_RES_NINIT
|
||||
/*!
|
||||
* \brief Handles the DNS search if the system has RES_INIT.
|
||||
*
|
||||
* \internal
|
||||
*
|
||||
* \param dname Domain name to lookup (host, SRV domain, TXT record name).
|
||||
* \param rr_class Record Class (see "man res_search").
|
||||
* \param rr_type Record type (see "man res_search").
|
||||
* \param dns_response The full DNS response.
|
||||
* \param dns_response_len The length of the full DNS response.
|
||||
*
|
||||
* \retval The length of the DNS response
|
||||
* \retval -1 on search failure
|
||||
*/
|
||||
static int dns_search_res(const char *dname, int rr_class, int rr_type,
|
||||
unsigned char *dns_response, int dns_response_len)
|
||||
{
|
||||
|
||||
int ret = AST_DNS_SEARCH_FAILURE;
|
||||
struct __res_state dns_state;
|
||||
|
||||
ast_mutex_lock(&res_lock);
|
||||
res_init();
|
||||
ret = res_search(&dns_state,
|
||||
dname,
|
||||
rr_class,
|
||||
rr_type,
|
||||
dns_response,
|
||||
dns_response_len);
|
||||
|
||||
#ifdef HAVE_RES_CLOSE
|
||||
res_close();
|
||||
#endif
|
||||
|
||||
ast_mutex_unlock(&res_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
/*!
|
||||
* \brief Handles the DNS search if the system has RES_NINIT.
|
||||
*
|
||||
* \internal
|
||||
*
|
||||
* \param dname Domain name to lookup (host, SRV domain, TXT record name).
|
||||
* \param rr_class Record Class (see "man res_search").
|
||||
* \param rr_type Record type (see "man res_search").
|
||||
* \param dns_response The full DNS response.
|
||||
* \param dns_response_len The length of the full DNS response.
|
||||
*
|
||||
* \retval The length of the DNS response
|
||||
* \retval -1 on search failure
|
||||
*/
|
||||
static int dns_search_res(const char *dname, int rr_class, int rr_type,
|
||||
unsigned char *dns_response, int dns_response_len)
|
||||
{
|
||||
|
||||
int ret = AST_DNS_SEARCH_FAILURE;
|
||||
struct __res_state dns_state;
|
||||
|
||||
memset(&dns_state, 0, sizeof(dns_state));
|
||||
res_ninit(&dns_state);
|
||||
ret = res_nsearch(&dns_state,
|
||||
dname,
|
||||
rr_class,
|
||||
rr_type,
|
||||
dns_response,
|
||||
dns_response_len);
|
||||
|
||||
#ifdef HAVE_RES_NDESTROY
|
||||
res_ndestroy(&dns_state);
|
||||
#else
|
||||
res_nclose(&dns_state);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief Parse DNS lookup result, call callback
|
||||
*
|
||||
* \internal
|
||||
*
|
||||
* \param context Void pointer containing data to use in the callback functions.
|
||||
* \param dname Domain name to lookup (host, SRV domain, TXT record name).
|
||||
* \param class Record Class (see "man res_search").
|
||||
* \param type Record type (see "man res_search").
|
||||
* \param answer The full DNS response.
|
||||
* \param len The length of the full DNS response.
|
||||
* \param callback Callback function for handling the discovered resource records from the DNS search.
|
||||
*
|
||||
* \retval -1 on search failure
|
||||
* \retval 0 on no records found
|
||||
* \retval 1 on success
|
||||
*/
|
||||
static int dns_parse_answer(void *context,
|
||||
int class, int type, unsigned char *answer, int len,
|
||||
int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
|
||||
|
@ -244,13 +389,110 @@ static int dns_parse_answer(void *context,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifndef HAVE_RES_NINIT
|
||||
AST_MUTEX_DEFINE_STATIC(res_lock);
|
||||
#endif
|
||||
/*!
|
||||
* \brief Extended version of the DNS Parsing function.
|
||||
*
|
||||
* \details Parses the DNS lookup result and notifies the observer of each discovered
|
||||
* resource record with the provided callback.
|
||||
*
|
||||
* \internal
|
||||
*
|
||||
* \param context Void pointer containing data to use in the callback functions.
|
||||
* \param dname Domain name to lookup (host, SRV domain, TXT record name).
|
||||
* \param rr_class Record Class (see "man res_search").
|
||||
* \param rr_type Record type (see "man res_search").
|
||||
* \param answer The full DNS response.
|
||||
* \param answer_len The length of the full DNS response.
|
||||
* \param response_handler Callback function for handling the DNS response.
|
||||
* \param record_handler Callback function for handling the discovered resource records from the DNS search.
|
||||
*
|
||||
* \retval -1 on search failure
|
||||
* \retval 0 on no records found
|
||||
* \retval 1 on success
|
||||
*/
|
||||
static int dns_parse_answer_ex(void *context, int rr_class, int rr_type, unsigned char *answer, int answer_len,
|
||||
int (*response_handler)(void *context, unsigned char *dns_response, int dns_response_len, int rcode),
|
||||
int (*record_handler)(void *context, unsigned char *record, int record_len, int ttl))
|
||||
{
|
||||
unsigned char *dns_response = answer;
|
||||
dns_HEADER *dns_header = (dns_HEADER *)answer;
|
||||
|
||||
/*! \brief Lookup record in DNS
|
||||
\note Asterisk DNS is synchronus at this time. This means that if your DNS does
|
||||
not work properly, Asterisk might not start properly or a channel may lock.
|
||||
struct dn_answer *ans;
|
||||
int res, x, pos, dns_response_len, ret;
|
||||
|
||||
dns_response_len = answer_len;
|
||||
ret = AST_DNS_SEARCH_NO_RECORDS;
|
||||
|
||||
/* Invoke the response_handler callback to notify the observer of the raw DNS response */
|
||||
response_handler(context, dns_response, dns_response_len, ntohs(dns_header->rcode));
|
||||
|
||||
/* Verify there is something to parse */
|
||||
if (answer_len == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Try advancing the cursor for the dns header */
|
||||
if ((pos = dns_advance_field(&answer, answer_len, sizeof(dns_HEADER))) < 0) {
|
||||
ast_log(LOG_WARNING, "Length of DNS answer exceeds available search frames\n");
|
||||
return AST_DNS_SEARCH_FAILURE;
|
||||
}
|
||||
|
||||
/* Skip domain name and QCODE / QCLASS */
|
||||
for (x = 0; x < ntohs(dns_header->qdcount); x++) {
|
||||
if ((res = skip_name(answer, pos)) < 0) {
|
||||
ast_log(LOG_WARNING, "Failed skipping name\n");
|
||||
return AST_DNS_SEARCH_FAILURE;
|
||||
}
|
||||
|
||||
/* Try advancing the cursor for the name and QCODE / QCLASS fields */
|
||||
if ((pos = dns_advance_field(&answer, pos, res + 4)) < 0) {
|
||||
return AST_DNS_SEARCH_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract the individual records */
|
||||
for (x = 0; x < ntohs(dns_header->ancount); x++) {
|
||||
if ((res = skip_name(answer, pos)) < 0) {
|
||||
ast_log(LOG_WARNING, "Failed skipping name\n");
|
||||
return AST_DNS_SEARCH_FAILURE;
|
||||
}
|
||||
|
||||
/* Try advancing the cursor to the current record */
|
||||
if ((pos = dns_advance_field(&answer, pos, res)) < 0) {
|
||||
ast_log(LOG_WARNING, "Length of DNS answer exceeds available search frames\n");
|
||||
return AST_DNS_SEARCH_FAILURE;
|
||||
}
|
||||
|
||||
/* Cast the current value for the answer pointer as a dn_answer struct */
|
||||
ans = (struct dn_answer *) answer;
|
||||
|
||||
/* Try advancing the cursor to the end of the current record */
|
||||
if ((pos = dns_advance_field(&answer, pos, sizeof(struct dn_answer))) < 0) {
|
||||
ast_log(LOG_WARNING, "Length of DNS answer exceeds available search frames\n");
|
||||
return AST_DNS_SEARCH_FAILURE;
|
||||
}
|
||||
|
||||
/* Skip over the records that do not have the same resource record class and type we care about */
|
||||
if (ntohs(ans->class) == rr_class && ntohs(ans->rtype) == rr_type) {
|
||||
/* Invoke the record handler callback to deliver the discovered record */
|
||||
record_handler(context, answer, ntohs(ans->size), ans->ttl);
|
||||
/*At least one record was found */
|
||||
ret = AST_DNS_SEARCH_SUCCESS;
|
||||
}
|
||||
|
||||
/* Try and update the field to the next record, but ignore any errors that come
|
||||
* back because this may be the end of the line. */
|
||||
pos = dns_advance_field(&answer, pos, res + ntohs(ans->size));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Lookup record in DNS
|
||||
*
|
||||
* \note Asterisk DNS is synchronus at this time. This means that if your DNS does not
|
||||
* work properly, Asterisk might not start properly or a channel may lock.
|
||||
*/
|
||||
int ast_search_dns(void *context,
|
||||
const char *dname, int class, int type,
|
||||
|
@ -297,6 +539,50 @@ int ast_search_dns(void *context,
|
|||
return ret;
|
||||
}
|
||||
|
||||
enum ast_dns_search_result ast_search_dns_ex(void *context, const char *dname, int rr_class, int rr_type,
|
||||
int (*response_handler)(void *context, unsigned char *dns_response, int dns_response_len, int rcode),
|
||||
int (*record_handler)(void *context, unsigned char *record, int record_len, int ttl))
|
||||
{
|
||||
int ret, dns_response_len;
|
||||
unsigned char dns_response[MAX_SIZE];
|
||||
|
||||
/* Assert that the callbacks are not NULL */
|
||||
ast_assert(response_handler != NULL);
|
||||
ast_assert(record_handler != NULL);
|
||||
|
||||
/* Try the DNS search. */
|
||||
dns_response_len = dns_search_res(dname,
|
||||
rr_class,
|
||||
rr_type,
|
||||
dns_response,
|
||||
sizeof(dns_response));
|
||||
|
||||
if (dns_response_len < 0) {
|
||||
ast_log(LOG_ERROR, "DNS search failed for %s\n", dname);
|
||||
return AST_DNS_SEARCH_FAILURE;
|
||||
}
|
||||
|
||||
/* Parse records from DNS response */
|
||||
ret = dns_parse_answer_ex(context,
|
||||
rr_class,
|
||||
rr_type,
|
||||
dns_response,
|
||||
dns_response_len,
|
||||
response_handler,
|
||||
record_handler);
|
||||
|
||||
/* Handle the return code from parsing the DNS response */
|
||||
if (ret == AST_DNS_SEARCH_FAILURE) {
|
||||
/* Parsing Error */
|
||||
ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
|
||||
} else if (ret == AST_DNS_SEARCH_NO_RECORDS) {
|
||||
/* No results found */
|
||||
ast_debug(1, "DNS search yielded no results for %s\n", dname);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct ao2_container *ast_dns_get_nameservers(void)
|
||||
{
|
||||
#ifdef HAVE_RES_NINIT
|
||||
|
|
267
main/dns_system_resolver.c
Executable file
267
main/dns_system_resolver.c
Executable file
|
@ -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;
|
||||
}
|
Loading…
Reference in a new issue