mirror of
https://github.com/asterisk/asterisk.git
synced 2026-06-04 10:22:01 +00:00
If a hostname is specified for stunaddr in rtp.conf, periodic DNS resolution is enabled based on the TTL returned in the DNS results. If the TTL returned is 0, it means that the next time the IP address is needed, it must be looked up again. I.E. Don't cache. Historically (and incorrectly) however, res_rtp_asterisk stopped the periodic resolution and never re-resolved the hostname again. Besides what's mentioned in the user notes... * Additional debugging was added in various STUN/DNS functions. * The `rtp show settings` CLI command shows more detailed STUN info. * Some debugging was added to dns_core.c and dns_recurring.c. UserNote: A new `stunaddr_reresolve_ttl_0` parameter has been added to rtp.conf that allows control over what happens when a STUN server hostname lookup returns a TTL of 0. The values can be set as follows: - 'no': This is the historical (and current default) behavior of not doing any further lookups and continuing to use the last successful result until Asterisk is restarted or rtp.conf is reloaded. - 'yes': Use the last cached result for the current call but trigger re-resolution in the background for the benefit of future calls. If the result of the background lookup is a ttl > 0, periodic resolution will be restarted otherwise the next call will use the new cached value and will trigger a background lookup again. UserNote: A new CLI command `rtp resolve stun hostname` has been added that will force a resolution of the STUN hostname and (re)start periodic resolution if the result has a TTL > 0. Resolves: #1858
173 lines
5.3 KiB
C
173 lines
5.3 KiB
C
/*
|
|
* Asterisk -- An open source telephony toolkit.
|
|
*
|
|
* Copyright (C) 2015, Digium, Inc.
|
|
*
|
|
* Joshua Colp <jcolp@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 DNS Recurring Query Support
|
|
*
|
|
* \author Joshua Colp <jcolp@digium.com>
|
|
*/
|
|
|
|
/*** MODULEINFO
|
|
<support_level>core</support_level>
|
|
***/
|
|
|
|
#include "asterisk.h"
|
|
|
|
#include "asterisk/astobj2.h"
|
|
#include "asterisk/linkedlists.h"
|
|
#include "asterisk/sched.h"
|
|
#include "asterisk/strings.h"
|
|
#include "asterisk/dns_core.h"
|
|
#include "asterisk/dns_recurring.h"
|
|
#include "asterisk/dns_internal.h"
|
|
|
|
#include <arpa/nameser.h>
|
|
|
|
/*! \brief Delay between TTL expiration and the next DNS query, to make sure the
|
|
resolver cache really expired. */
|
|
#define EXTRA_TTL 2
|
|
#define MAX_TTL ((INT_MAX - EXTRA_TTL) / 1000)
|
|
|
|
/*! \brief Destructor for a DNS query */
|
|
static void dns_query_recurring_destroy(void *data)
|
|
{
|
|
struct ast_dns_query_recurring *recurring = data;
|
|
|
|
ao2_cleanup(recurring->user_data);
|
|
}
|
|
|
|
static void dns_query_recurring_resolution_callback(const struct ast_dns_query *query);
|
|
|
|
/*! \brief Scheduled recurring query callback */
|
|
static int dns_query_recurring_scheduled_callback(const void *data)
|
|
{
|
|
struct ast_dns_query_recurring *recurring = (struct ast_dns_query_recurring *)data;
|
|
|
|
ao2_lock(recurring);
|
|
recurring->timer = -1;
|
|
if (!recurring->cancelled) {
|
|
recurring->active = ast_dns_resolve_async(recurring->name, recurring->rr_type, recurring->rr_class, dns_query_recurring_resolution_callback,
|
|
recurring);
|
|
}
|
|
ao2_unlock(recurring);
|
|
|
|
ao2_ref(recurring, -1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*! \brief Query resolution callback */
|
|
static void dns_query_recurring_resolution_callback(const struct ast_dns_query *query)
|
|
{
|
|
struct ast_dns_query_recurring *recurring = ast_dns_query_get_data(query);
|
|
struct ast_dns_query *callback_query;
|
|
|
|
/* Create a separate query to invoke the user specific callback on as the
|
|
* recurring query user data may get used externally (by the unit test)
|
|
* and thus changing it is problematic
|
|
*/
|
|
callback_query = dns_query_alloc(query->name, query->rr_type, query->rr_class,
|
|
recurring->callback, recurring->user_data);
|
|
if (callback_query) {
|
|
/* The result is immutable at this point and can be safely provided */
|
|
callback_query->result = query->result;
|
|
callback_query->callback(callback_query);
|
|
callback_query->result = NULL;
|
|
ao2_ref(callback_query, -1);
|
|
}
|
|
|
|
ao2_lock(recurring);
|
|
/* So.. if something has not externally cancelled this we can reschedule based on the TTL */
|
|
if (!recurring->cancelled) {
|
|
const struct ast_dns_result *result = ast_dns_query_get_result(query);
|
|
int ttl = MIN(ast_dns_result_get_lowest_ttl(result), MAX_TTL);
|
|
|
|
if (ttl) {
|
|
recurring->timer = ast_sched_add(ast_dns_get_sched(), (ttl + EXTRA_TTL) * 1000, dns_query_recurring_scheduled_callback, ao2_bump(recurring));
|
|
if (recurring->timer < 0) {
|
|
/* It is impossible for this to be the last reference as the query has a reference to it */
|
|
ao2_ref(recurring, -1);
|
|
}
|
|
ast_debug(2, "Rescheduled resolution for name: %s class: %d type: %d in %d seconds",
|
|
ast_dns_query_get_name(query), ast_dns_query_get_rr_class(query),
|
|
ast_dns_query_get_rr_type(query), ttl + EXTRA_TTL);
|
|
} else {
|
|
ast_debug(2, "TTL = 0 so not rescheduling resolution for name: %s class: %d type: %d",
|
|
ast_dns_query_get_name(query), ast_dns_query_get_rr_class(query), ast_dns_query_get_rr_type(query));
|
|
}
|
|
} else {
|
|
ast_debug(2, "Recurring resolution cancelled for name: %s class: %d type: %d",
|
|
ast_dns_query_get_name(query), ast_dns_query_get_rr_class(query), ast_dns_query_get_rr_type(query));
|
|
}
|
|
|
|
ao2_replace(recurring->active, NULL);
|
|
ao2_unlock(recurring);
|
|
}
|
|
|
|
struct ast_dns_query_recurring *ast_dns_resolve_recurring(const char *name, int rr_type, int rr_class, ast_dns_resolve_callback callback, void *data)
|
|
{
|
|
struct ast_dns_query_recurring *recurring;
|
|
|
|
if (ast_strlen_zero(name) || !callback || !ast_dns_get_sched()) {
|
|
return NULL;
|
|
}
|
|
|
|
recurring = ao2_alloc(sizeof(*recurring) + strlen(name) + 1, dns_query_recurring_destroy);
|
|
if (!recurring) {
|
|
return NULL;
|
|
}
|
|
|
|
recurring->callback = callback;
|
|
recurring->user_data = ao2_bump(data);
|
|
recurring->timer = -1;
|
|
recurring->rr_type = rr_type;
|
|
recurring->rr_class = rr_class;
|
|
strcpy(recurring->name, name); /* SAFE */
|
|
|
|
recurring->active = ast_dns_resolve_async(name, rr_type, rr_class, dns_query_recurring_resolution_callback, recurring);
|
|
if (!recurring->active) {
|
|
ao2_ref(recurring, -1);
|
|
return NULL;
|
|
}
|
|
|
|
return recurring;
|
|
}
|
|
|
|
int ast_dns_resolve_recurring_cancel(struct ast_dns_query_recurring *recurring)
|
|
{
|
|
int res = 0;
|
|
|
|
ao2_lock(recurring);
|
|
|
|
ast_debug(2, "Cancelling recurring resolution for name: %s class: %d type: %d",
|
|
recurring->name, recurring->rr_class, recurring->rr_type);
|
|
|
|
recurring->cancelled = 1;
|
|
AST_SCHED_DEL_UNREF(ast_dns_get_sched(), recurring->timer, ao2_ref(recurring, -1));
|
|
|
|
if (recurring->active) {
|
|
res = ast_dns_resolve_cancel(recurring->active);
|
|
ao2_replace(recurring->active, NULL);
|
|
}
|
|
|
|
ao2_unlock(recurring);
|
|
|
|
return res;
|
|
}
|