mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-14 00:24:05 +00:00
Merge "Detect potential forwarding loops based on count."
This commit is contained in:
@@ -2237,9 +2237,7 @@ static void call_destructor_with_no_monitor(const char * const monitor_type, voi
|
||||
* Note that it is not necessarily erroneous to add the same
|
||||
* device to the tree twice. If the same device is called by
|
||||
* two different extension during the same call, then
|
||||
* that is a legitimate situation. Of course, I'm pretty sure
|
||||
* the dialed_interfaces global datastore will not allow that
|
||||
* to happen anyway.
|
||||
* that is a legitimate situation.
|
||||
*
|
||||
* \param device_name The name of the device being added to the tree
|
||||
* \param dialstring The dialstring used to dial the device being added
|
||||
|
@@ -75,6 +75,7 @@ ASTERISK_REGISTER_FILE()
|
||||
#include "asterisk/bridge.h"
|
||||
#include "asterisk/test.h"
|
||||
#include "asterisk/stasis_channels.h"
|
||||
#include "asterisk/max_forwards.h"
|
||||
|
||||
/*** DOCUMENTATION
|
||||
***/
|
||||
@@ -5621,6 +5622,7 @@ static void call_forward_inherit(struct ast_channel *new_chan, struct ast_channe
|
||||
ast_channel_lock_both(parent, new_chan);
|
||||
ast_channel_inherit_variables(parent, new_chan);
|
||||
ast_channel_datastore_inherit(parent, new_chan);
|
||||
ast_max_forwards_decrement(new_chan);
|
||||
ast_channel_unlock(new_chan);
|
||||
ast_channel_unlock(parent);
|
||||
}
|
||||
@@ -5740,6 +5742,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
|
||||
ast_channel_lock_both(oh->parent_channel, chan);
|
||||
ast_channel_inherit_variables(oh->parent_channel, chan);
|
||||
ast_channel_datastore_inherit(oh->parent_channel, chan);
|
||||
ast_max_forwards_decrement(chan);
|
||||
ast_channel_unlock(oh->parent_channel);
|
||||
ast_channel_unlock(chan);
|
||||
}
|
||||
|
15
main/dial.c
15
main/dial.c
@@ -44,6 +44,7 @@ ASTERISK_REGISTER_FILE()
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/causes.h"
|
||||
#include "asterisk/stasis_channels.h"
|
||||
#include "asterisk/max_forwards.h"
|
||||
|
||||
/*! \brief Main dialing structure. Contains global options, channels being dialed, and more! */
|
||||
struct ast_dial {
|
||||
@@ -299,6 +300,19 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
|
||||
.uniqueid2 = channel->assignedid2,
|
||||
};
|
||||
|
||||
if (chan) {
|
||||
int max_forwards;
|
||||
|
||||
ast_channel_lock(chan);
|
||||
max_forwards = ast_max_forwards_get(chan);
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
if (max_forwards <= 0) {
|
||||
ast_log(LOG_WARNING, "Cannot dial from channel '%s'. Max forwards exceeded\n",
|
||||
ast_channel_name(chan));
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy device string over */
|
||||
ast_copy_string(numsubst, channel->device, sizeof(numsubst));
|
||||
|
||||
@@ -337,6 +351,7 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
|
||||
if (chan) {
|
||||
ast_channel_inherit_variables(chan, channel->owner);
|
||||
ast_channel_datastore_inherit(chan, channel->owner);
|
||||
ast_max_forwards_decrement(channel->owner);
|
||||
|
||||
/* Copy over callerid information */
|
||||
ast_party_redirecting_copy(ast_channel_redirecting(channel->owner), ast_channel_redirecting(chan));
|
||||
|
@@ -78,6 +78,7 @@ ASTERISK_REGISTER_FILE()
|
||||
#include "asterisk/stasis.h"
|
||||
#include "asterisk/stasis_channels.h"
|
||||
#include "asterisk/features_config.h"
|
||||
#include "asterisk/max_forwards.h"
|
||||
|
||||
/*** DOCUMENTATION
|
||||
<application name="Bridge" language="en_US">
|
||||
@@ -420,22 +421,6 @@ static void add_features_datastores(struct ast_channel *caller, struct ast_chann
|
||||
add_features_datastore(callee, &config->features_callee, &config->features_caller);
|
||||
}
|
||||
|
||||
static void clear_dialed_interfaces(struct ast_channel *chan)
|
||||
{
|
||||
struct ast_datastore *di_datastore;
|
||||
|
||||
ast_channel_lock(chan);
|
||||
if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
|
||||
if (option_debug) {
|
||||
ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", ast_channel_name(chan));
|
||||
}
|
||||
if (!ast_channel_datastore_remove(chan, di_datastore)) {
|
||||
ast_datastore_free(di_datastore);
|
||||
}
|
||||
}
|
||||
ast_channel_unlock(chan);
|
||||
}
|
||||
|
||||
static void bridge_config_set_limits_warning_values(struct ast_bridge_config *config, struct ast_bridge_features_limits *limits)
|
||||
{
|
||||
if (config->end_sound) {
|
||||
@@ -572,20 +557,13 @@ static int pre_bridge_setup(struct ast_channel *chan, struct ast_channel *peer,
|
||||
ast_channel_log("Pre-bridge PEER Channel info", peer);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If we are bridging a call, stop worrying about forwarding
|
||||
* loops. We presume that if a call is being bridged, that the
|
||||
* humans in charge know what they're doing. If they don't,
|
||||
* well, what can we do about that?
|
||||
*/
|
||||
clear_dialed_interfaces(chan);
|
||||
clear_dialed_interfaces(peer);
|
||||
|
||||
res = 0;
|
||||
ast_channel_lock(chan);
|
||||
ast_max_forwards_reset(chan);
|
||||
res |= ast_bridge_features_ds_append(chan, &config->features_caller);
|
||||
ast_channel_unlock(chan);
|
||||
ast_channel_lock(peer);
|
||||
ast_max_forwards_reset(peer);
|
||||
res |= ast_bridge_features_ds_append(peer, &config->features_callee);
|
||||
ast_channel_unlock(peer);
|
||||
|
||||
|
@@ -32,62 +32,6 @@
|
||||
ASTERISK_REGISTER_FILE()
|
||||
|
||||
#include "asterisk/global_datastores.h"
|
||||
#include "asterisk/linkedlists.h"
|
||||
|
||||
static void dialed_interface_destroy(void *data)
|
||||
{
|
||||
struct ast_dialed_interface *di = NULL;
|
||||
AST_LIST_HEAD(, ast_dialed_interface) *dialed_interface_list = data;
|
||||
|
||||
if (!dialed_interface_list) {
|
||||
return;
|
||||
}
|
||||
|
||||
AST_LIST_LOCK(dialed_interface_list);
|
||||
while ((di = AST_LIST_REMOVE_HEAD(dialed_interface_list, list)))
|
||||
ast_free(di);
|
||||
AST_LIST_UNLOCK(dialed_interface_list);
|
||||
|
||||
AST_LIST_HEAD_DESTROY(dialed_interface_list);
|
||||
ast_free(dialed_interface_list);
|
||||
}
|
||||
|
||||
static void *dialed_interface_duplicate(void *data)
|
||||
{
|
||||
struct ast_dialed_interface *di = NULL;
|
||||
AST_LIST_HEAD(, ast_dialed_interface) *old_list;
|
||||
AST_LIST_HEAD(, ast_dialed_interface) *new_list = NULL;
|
||||
|
||||
if(!(old_list = data)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!(new_list = ast_calloc(1, sizeof(*new_list)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AST_LIST_HEAD_INIT(new_list);
|
||||
AST_LIST_LOCK(old_list);
|
||||
AST_LIST_TRAVERSE(old_list, di, list) {
|
||||
struct ast_dialed_interface *di2 = ast_calloc(1, sizeof(*di2) + strlen(di->interface));
|
||||
if(!di2) {
|
||||
AST_LIST_UNLOCK(old_list);
|
||||
dialed_interface_destroy(new_list);
|
||||
return NULL;
|
||||
}
|
||||
strcpy(di2->interface, di->interface);
|
||||
AST_LIST_INSERT_TAIL(new_list, di2, list);
|
||||
}
|
||||
AST_LIST_UNLOCK(old_list);
|
||||
|
||||
return new_list;
|
||||
}
|
||||
|
||||
const struct ast_datastore_info dialed_interface_info = {
|
||||
.type = "dialed-interface",
|
||||
.destroy = dialed_interface_destroy,
|
||||
.duplicate = dialed_interface_duplicate,
|
||||
};
|
||||
|
||||
static void secure_call_store_destroy(void *data)
|
||||
{
|
||||
|
165
main/max_forwards.c
Normal file
165
main/max_forwards.c
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2015, Digium, Inc.
|
||||
*
|
||||
* Mark Michelson <mmichelson@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not mfrectly 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, mfstributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/max_forwards.h"
|
||||
#include "asterisk/channel.h"
|
||||
|
||||
#define DEFAULT_MAX_FORWARDS 20
|
||||
|
||||
/*!
|
||||
* \brief Channel datastore data for max forwards
|
||||
*/
|
||||
struct max_forwards {
|
||||
/*! The starting count. Used to allow resetting to the original value */
|
||||
int starting_count;
|
||||
/*! The current count. When this reaches 0, you're outta luck */
|
||||
int current_count;
|
||||
};
|
||||
|
||||
static struct max_forwards *max_forwards_alloc(int starting_count, int current_count)
|
||||
{
|
||||
struct max_forwards *mf;
|
||||
|
||||
mf = ast_malloc(sizeof(*mf));
|
||||
if (!mf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mf->starting_count = starting_count;
|
||||
mf->current_count = current_count;
|
||||
|
||||
return mf;
|
||||
}
|
||||
|
||||
static void *max_forwards_duplicate(void *data)
|
||||
{
|
||||
struct max_forwards *mf = data;
|
||||
|
||||
return max_forwards_alloc(mf->starting_count, mf->current_count);
|
||||
}
|
||||
|
||||
static void max_forwards_destroy(void *data)
|
||||
{
|
||||
ast_free(data);
|
||||
}
|
||||
|
||||
const struct ast_datastore_info max_forwards_info = {
|
||||
.type = "mfaled-interface",
|
||||
.duplicate = max_forwards_duplicate,
|
||||
.destroy = max_forwards_destroy,
|
||||
};
|
||||
|
||||
static struct ast_datastore *max_forwards_datastore_alloc(struct ast_channel *chan,
|
||||
int starting_count)
|
||||
{
|
||||
struct ast_datastore *mf_datastore;
|
||||
struct max_forwards *mf;
|
||||
|
||||
mf_datastore = ast_datastore_alloc(&max_forwards_info, NULL);
|
||||
if (!mf_datastore) {
|
||||
return NULL;
|
||||
}
|
||||
mf_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
|
||||
|
||||
mf = max_forwards_alloc(starting_count, starting_count);
|
||||
if (!mf) {
|
||||
ast_datastore_free(mf_datastore);
|
||||
return NULL;
|
||||
}
|
||||
mf_datastore->data = mf;
|
||||
|
||||
ast_channel_datastore_add(chan, mf_datastore);
|
||||
|
||||
return mf_datastore;
|
||||
}
|
||||
|
||||
static struct ast_datastore *max_forwards_datastore_find_or_alloc(struct ast_channel *chan)
|
||||
{
|
||||
struct ast_datastore *mf_datastore;
|
||||
|
||||
mf_datastore = ast_channel_datastore_find(chan, &max_forwards_info, NULL);
|
||||
if (!mf_datastore) {
|
||||
mf_datastore = max_forwards_datastore_alloc(chan, DEFAULT_MAX_FORWARDS);
|
||||
}
|
||||
|
||||
return mf_datastore;
|
||||
}
|
||||
|
||||
int ast_max_forwards_set(struct ast_channel *chan, int starting_count)
|
||||
{
|
||||
struct ast_datastore *mf_datastore;
|
||||
struct max_forwards *mf;
|
||||
|
||||
mf_datastore = max_forwards_datastore_find_or_alloc(chan);
|
||||
if (!mf_datastore) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mf = mf_datastore->data;
|
||||
mf->starting_count = mf->current_count = starting_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_max_forwards_get(struct ast_channel *chan)
|
||||
{
|
||||
struct ast_datastore *mf_datastore;
|
||||
struct max_forwards *mf;
|
||||
|
||||
mf_datastore = max_forwards_datastore_find_or_alloc(chan);
|
||||
if (!mf_datastore) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mf = mf_datastore->data;
|
||||
return mf->current_count;
|
||||
}
|
||||
|
||||
int ast_max_forwards_decrement(struct ast_channel *chan)
|
||||
{
|
||||
struct ast_datastore *mf_datastore;
|
||||
struct max_forwards *mf;
|
||||
|
||||
mf_datastore = max_forwards_datastore_find_or_alloc(chan);
|
||||
if (!mf_datastore) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mf = mf_datastore->data;
|
||||
--mf->current_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_max_forwards_reset(struct ast_channel *chan)
|
||||
{
|
||||
struct ast_datastore *mf_datastore;
|
||||
struct max_forwards *mf;
|
||||
|
||||
mf_datastore = max_forwards_datastore_find_or_alloc(chan);
|
||||
if (!mf_datastore) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mf = mf_datastore->data;
|
||||
mf->current_count = mf->starting_count;
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user