summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
authorTerry Wilson <twilson@digium.com>2010-09-01 18:52:27 +0000
committerTerry Wilson <twilson@digium.com>2010-09-01 18:52:27 +0000
commit920f5ea8b7ba39394b23037da82c92529b6b61a7 (patch)
treed44985b2775c7b67a6c6b95e497c7f9941721451 /res
parentaf67f7621a3dc3f1b5634459abf81f810e1713e8 (diff)
Merged revisions 284477 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r284477 | twilson | 2010-09-01 13:44:36 -0500 (Wed, 01 Sep 2010) | 17 lines Fix SRTP for changing SSRC and multiple a=crypto SDP lines Adding code to Asterisk that changed the SSRC during bridges and masquerades broke SRTP functionality. Also broken was handling the situation where an incoming INVITE had more than one crypto offer. This patch caches the SRTP policies the we use so that we can change the ssrc and inform libsrtp of the new streams. It also uses the first acceptable a=crypto line from the incoming INVITE. (closes issue #17563) Reported by: Alexcr Patches: srtp.diff uploaded by twilson (license 396) Tested by: twilson Review: https://reviewboard.asterisk.org/r/878/ ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@284479 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res')
-rw-r--r--res/res_rtp_asterisk.c12
-rw-r--r--res/res_srtp.c96
2 files changed, 99 insertions, 9 deletions
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index df7cf27b5..6ddd33902 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -717,12 +717,24 @@ static void ast_rtp_update_source(struct ast_rtp_instance *instance)
static void ast_rtp_change_source(struct ast_rtp_instance *instance)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+ struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance);
unsigned int ssrc = ast_random();
+ if (!rtp->lastts) {
+ ast_debug(3, "Not changing SSRC since we haven't sent any RTP yet\n");
+ return;
+ }
+
/* We simply set this bit so that the next packet sent will have the marker bit turned on */
ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
ast_debug(3, "Changing ssrc from %u to %u due to a source change\n", rtp->ssrc, ssrc);
+
+ if (srtp) {
+ ast_debug(3, "Changing ssrc for SRTP from %u to %u\n", rtp->ssrc, ssrc);
+ res_srtp->change_source(srtp, rtp->ssrc, ssrc);
+ }
+
rtp->ssrc = ssrc;
return;
diff --git a/res/res_srtp.c b/res/res_srtp.c
index 546f0733d..f92154f90 100644
--- a/res/res_srtp.c
+++ b/res/res_srtp.c
@@ -53,14 +53,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/options.h"
#include "asterisk/rtp_engine.h"
+#include "asterisk/astobj2.h"
struct ast_srtp {
struct ast_rtp_instance *rtp;
+ struct ao2_container *policies;
srtp_t session;
const struct ast_srtp_cb *cb;
void *data;
unsigned char buf[8192 + AST_FRIENDLY_OFFSET];
- unsigned int has_stream:1;
};
struct ast_srtp_policy {
@@ -73,6 +74,7 @@ static int g_initialized = 0;
static int ast_srtp_create(struct ast_srtp **srtp, struct ast_rtp_instance *rtp, struct ast_srtp_policy *policy);
static void ast_srtp_destroy(struct ast_srtp *srtp);
static int ast_srtp_add_stream(struct ast_srtp *srtp, struct ast_srtp_policy *policy);
+static int ast_srtp_change_source(struct ast_srtp *srtp, unsigned int from_ssrc, unsigned int to_ssrc);
static int ast_srtp_unprotect(struct ast_srtp *srtp, void *buf, int *len, int rtcp);
static int ast_srtp_protect(struct ast_srtp *srtp, void **buf, int *len, int rtcp);
@@ -90,6 +92,7 @@ static struct ast_srtp_res srtp_res = {
.create = ast_srtp_create,
.destroy = ast_srtp_destroy,
.add_stream = ast_srtp_add_stream,
+ .change_source = ast_srtp_change_source,
.set_cb = ast_srtp_set_cb,
.unprotect = ast_srtp_unprotect,
.protect = ast_srtp_protect,
@@ -144,6 +147,32 @@ static const char *srtp_errstr(int err)
}
}
+static int policy_hash_fn(const void *obj, const int flags)
+{
+ const struct ast_srtp_policy *policy = obj;
+
+ return policy->sp.ssrc.type == ssrc_specific ? policy->sp.ssrc.value : policy->sp.ssrc.type;
+}
+
+static int policy_cmp_fn(void *obj, void *arg, int flags)
+{
+ const struct ast_srtp_policy *one = obj, *two = arg;
+
+ return one->sp.ssrc.type == two->sp.ssrc.type && one->sp.ssrc.value == two->sp.ssrc.value;
+}
+
+static struct ast_srtp_policy *find_policy(struct ast_srtp *srtp, const srtp_policy_t *policy, int flags)
+{
+ struct ast_srtp_policy tmp = {
+ .sp = {
+ .ssrc.type = policy->ssrc.type,
+ .ssrc.value = policy->ssrc.value,
+ },
+ };
+
+ return ao2_t_find(srtp->policies, &tmp, flags, "Looking for policy");
+}
+
static struct ast_srtp *res_srtp_new(void)
{
struct ast_srtp *srtp;
@@ -153,6 +182,11 @@ static struct ast_srtp *res_srtp_new(void)
return NULL;
}
+ if (!(srtp->policies = ao2_t_container_alloc(5, policy_hash_fn, policy_cmp_fn, "SRTP policy container"))) {
+ ast_free(srtp);
+ return NULL;
+ }
+
return srtp;
}
@@ -188,11 +222,21 @@ static void ast_srtp_policy_set_ssrc(struct ast_srtp_policy *policy,
}
}
+static void policy_destructor(void *obj)
+{
+ struct ast_srtp_policy *policy = obj;
+
+ if (policy->sp.key) {
+ ast_free(policy->sp.key);
+ policy->sp.key = NULL;
+ }
+}
+
static struct ast_srtp_policy *ast_srtp_policy_alloc()
{
struct ast_srtp_policy *tmp;
- if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
+ if (!(tmp = ao2_t_alloc(sizeof(*tmp), policy_destructor, "Allocating policy"))) {
ast_log(LOG_ERROR, "Unable to allocate memory for srtp_policy\n");
}
@@ -201,11 +245,7 @@ static struct ast_srtp_policy *ast_srtp_policy_alloc()
static void ast_srtp_policy_destroy(struct ast_srtp_policy *policy)
{
- if (policy->sp.key) {
- ast_free(policy->sp.key);
- policy->sp.key = NULL;
- }
- ast_free(policy);
+ ao2_t_ref(policy, -1, "Destroying policy");
}
static int policy_set_suite(crypto_policy_t *p, enum ast_srtp_suite suite)
@@ -344,6 +384,8 @@ static int ast_srtp_create(struct ast_srtp **srtp, struct ast_rtp_instance *rtp,
temp->rtp = rtp;
*srtp = temp;
+ ao2_t_link((*srtp)->policies, policy, "Created initial policy");
+
return 0;
}
@@ -353,16 +395,52 @@ static void ast_srtp_destroy(struct ast_srtp *srtp)
srtp_dealloc(srtp->session);
}
+ ao2_t_callback(srtp->policies, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Unallocate policy");
+ ao2_t_ref(srtp->policies, -1, "Destroying container");
+
ast_free(srtp);
}
static int ast_srtp_add_stream(struct ast_srtp *srtp, struct ast_srtp_policy *policy)
{
- if (!srtp->has_stream && srtp_add_stream(srtp->session, &policy->sp) != err_status_ok) {
+ struct ast_srtp_policy *match;
+
+ if ((match = find_policy(srtp, &policy->sp, OBJ_POINTER))) {
+ ast_debug(3, "Policy already exists, not re-adding\n");
+ ao2_t_ref(match, -1, "Unreffing already existing policy");
return -1;
}
- srtp->has_stream = 1;
+ if (srtp_add_stream(srtp->session, &policy->sp) != err_status_ok) {
+ return -1;
+ }
+
+ ao2_t_link(srtp->policies, policy, "Added additional stream");
+
+ return 0;
+}
+
+static int ast_srtp_change_source(struct ast_srtp *srtp, unsigned int from_ssrc, unsigned int to_ssrc)
+{
+ struct ast_srtp_policy *match;
+ struct srtp_policy_t sp = {
+ .ssrc.type = ssrc_specific,
+ .ssrc.value = from_ssrc,
+ };
+ err_status_t status;
+
+ /* If we find a mach, return and unlink it from the container so we
+ * can change the SSRC (which is part of the hash) and then have
+ * ast_srtp_add_stream link it back in if all is well */
+ if ((match = find_policy(srtp, &sp, OBJ_POINTER | OBJ_UNLINK))) {
+ match->sp.ssrc.value = to_ssrc;
+ if (ast_srtp_add_stream(srtp, match)) {
+ ast_log(LOG_WARNING, "Couldn't add stream\n");
+ } else if ((status = srtp_remove_stream(srtp->session, from_ssrc))) {
+ ast_debug(3, "Couldn't remove stream (%d)\n", status);
+ }
+ ao2_t_ref(match, -1, "Unreffing found policy in change_source");
+ }
return 0;
}