summaryrefslogtreecommitdiff
path: root/funcs
diff options
context:
space:
mode:
authorMark Michelson <mmichelson@digium.com>2015-04-15 10:38:02 -0500
committerMatt Jordan <mjordan@digium.com>2015-04-17 15:57:10 -0500
commit4f1a8dbe9241cf967000d9f5f359830948da3c9a (patch)
treea2056f9e99a4bc0272ec4137ea26a1efdc0726b1 /funcs
parentb56c1914fa54817e88be92ed8394aa6f64aa26ad (diff)
Detect potential forwarding loops based on count.
A potential problem that can arise is the following: * Bob's phone is programmed to automatically forward to Carol. * Carol's phone is programmed to automatically forward to Bob. * Alice calls Bob. If left unchecked, this results in an endless loops of call forwards that would eventually result in some sort of fiery crash. Asterisk's method of solving this issue was to track which interfaces had been dialed. If a destination were dialed a second time, then the attempt to call that destination would fail since a loop was detected. The problem with this method is that call forwarding has evolved. Some SIP phones allow for a user to manually forward an incoming call to an ad-hoc destination. This can mean that: * There are legitimate use cases where a device may be dialed multiple times, or * There can be human error when forwarding calls. This change removes the old method of detecting forwarding loops in favor of keeping a count of the number of destinations a channel has dialed on a particular branch of a call. If the number exceeds the set number of max forwards, then the call fails. This approach has the following advantages over the old: * It is much simpler. * It can detect loops involving local channels. * It is user configurable. The only disadvantage it has is that in the case where there is a legitimate forwarding loop present, it takes longer to detect it. However, the forwarding loop is still properly detected and the call is cleaned up as it should be. Address review feedback on gerrit. * Correct "mfgium" to "Digium" * Decrement max forwards by one in the case where allocation of the max forwards datastore is required. * Remove irrelevant code change from pjsip_global_headers.c ASTERISK-24958 #close Change-Id: Ia7e4b7cd3bccfbd34d9a859838356931bba56c23
Diffstat (limited to 'funcs')
-rw-r--r--funcs/func_channel.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/funcs/func_channel.c b/funcs/func_channel.c
index 4024cdf8b..7f87f450e 100644
--- a/funcs/func_channel.c
+++ b/funcs/func_channel.c
@@ -46,6 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/global_datastores.h"
#include "asterisk/bridge_basic.h"
#include "asterisk/bridge_after.h"
+#include "asterisk/max_forwards.h"
/*** DOCUMENTATION
<function name="CHANNELS" language="en_US">
@@ -388,6 +389,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<enum name="caller_url">
<para>R/0 Returns caller URL</para>
</enum>
+ <enum name="max_forwards">
+ <para>R/W Get or set the maximum number of call forwards for this channel.
+
+ This number describes the number of times a call may be forwarded by this channel
+ before the call fails. "Forwards" in this case refers to redirects by phones as well
+ as calls to local channels.
+
+ Note that this has no relation to the SIP Max-Forwards header.
+ </para>
+ </enum>
</enumlist>
</parameter>
</syntax>
@@ -577,6 +588,10 @@ static int func_channel_read(struct ast_channel *chan, const char *function,
}
}
ast_channel_unlock(chan);
+ } else if (!strcasecmp(data, "max_forwards")) {
+ ast_channel_lock(chan);
+ snprintf(buf, len, "%d", ast_max_forwards_get(chan));
+ ast_channel_unlock(chan);
} else if (!ast_channel_tech(chan) || !ast_channel_tech(chan)->func_channel_read || ast_channel_tech(chan)->func_channel_read(chan, function, data, buf, len)) {
ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
ret = -1;
@@ -737,6 +752,16 @@ static int func_channel_write_real(struct ast_channel *chan, const char *functio
store->media = ast_true(value) ? 1 : 0;
}
ast_channel_unlock(chan);
+ } else if (!strcasecmp(data, "max_forwards")) {
+ int max_forwards;
+ if (sscanf(value, "%d", &max_forwards) != 1) {
+ ast_log(LOG_WARNING, "Unable to set max forwards to '%s'\n", value);
+ ret = -1;
+ } else {
+ ast_channel_lock(chan);
+ ret = ast_max_forwards_set(chan, max_forwards);
+ ast_channel_unlock(chan);
+ }
} else if (!ast_channel_tech(chan)->func_channel_write
|| ast_channel_tech(chan)->func_channel_write(chan, function, data, value)) {
ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n",