[asterisk-commits] branch oej/securertp-trunk r32521 - in
/team/oej/securertp-trunk: ./ channels...
asterisk-commits at lists.digium.com
asterisk-commits at lists.digium.com
Tue Jun 6 02:03:52 MST 2006
Author: oej
Date: Tue Jun 6 04:03:51 2006
New Revision: 32521
URL: http://svn.digium.com/view/asterisk?rev=32521&view=rev
Log:
Update
Modified:
team/oej/securertp-trunk/channels/chan_sip.c
team/oej/securertp-trunk/include/asterisk/rtp.h
team/oej/securertp-trunk/rtp.c
Modified: team/oej/securertp-trunk/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/securertp-trunk/channels/chan_sip.c?rev=32521&r1=32520&r2=32521&view=diff
==============================================================================
--- team/oej/securertp-trunk/channels/chan_sip.c (original)
+++ team/oej/securertp-trunk/channels/chan_sip.c Tue Jun 6 04:03:51 2006
@@ -161,6 +161,19 @@
#define DEFAULT_MAX_EXPIRY 3600
#define DEFAULT_REGISTRATION_TIMEOUT 20
#define DEFAULT_MAX_FORWARDS "70"
+
+#define SRTP_MASTER_LEN 30
+#define SRTP_MASTERKEY_LEN 16
+#define SRTP_MASTERSALT_LEN (SRTP_MASTER_LEN - SRTP_MASTERKEY_LEN)
+#define SRTP_MASTER_LEN64 ((SRTP_MASTER_LEN * 8 + 5) / 6 + 1)
+
+/*! \brief structure for secure RTP audio */
+struct sip_srtp {
+ char *a_crypto;
+ unsigned char local_key[SRTP_MASTER_LEN];
+ char local_key64[SRTP_MASTER_LEN64];
+};
+
/* guard limit must be larger than guard secs */
/* guard min must be < 1000, and should be >= 250 */
@@ -857,6 +870,7 @@
struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */
struct sip_pvt *next; /*!< Next dialog in chain */
struct sip_invite_param *options; /*!< Options for INVITE */
+ struct sip_srtp *srtp; /*!< Structure for Secure RTP session data */
} *iflist = NULL;
#define FLAG_RESPONSE (1 << 0)
@@ -1260,6 +1274,19 @@
static int sip_get_codec(struct ast_channel *chan);
static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p);
+/*----- SRTP interface functions */
+static struct sip_srtp *sip_srtp_alloc(void);
+static void sip_srtp_destroy(struct sip_srtp *srtp);
+static int setup_crypto(struct sip_pvt *p);
+static int set_crypto_policy(struct ast_srtp_policy *policy,
+ int suite_val, const unsigned char *master_key,
+ unsigned long ssrc, int inbound);
+static int activate_crypto(struct sip_pvt *p, int suite_val, unsigned char *remote_key);
+static int process_crypto(struct sip_pvt *p, const char *attr);
+
+
+
+
/*! \brief Definition of this channel for PBX channel registration */
static const struct ast_channel_tech sip_tech = {
.type = "SIP",
@@ -2415,6 +2442,18 @@
} else if (!strcasecmp(ast_var_name(current),"SIPTRANSFER_REPLACES")) {
/* We're replacing a call. */
p->options->replaces = ast_var_value(current);
+ } else if (!strncasecmp(ast_var_name(current), "SIP_SRTP_SDES", strlen("SIP_SRTP_SDES"))) {
+ if (!ast_srtp_is_registered()) {
+ ast_log(LOG_WARNING, "SIP_SRTP_SDES set but SRTP is not available\n");
+ return -1;
+ }
+
+ if (!p->srtp) {
+ if (setup_crypto(p) < 0) {
+ ast_log(LOG_WARNING, "SIP SRTP sdes setup failed\n");
+ return -1;
+ }
+ }
}
}
@@ -2561,6 +2600,10 @@
if (p->chanvars) {
ast_variables_destroy(p->chanvars);
p->chanvars = NULL;
+ }
+ if (p->srtp) {
+ sip_srtp_destroy(p->srtp);
+ p->srtp = NULL;
}
ast_mutex_destroy(&p->lock);
@@ -2656,6 +2699,7 @@
ASTOBJ_UNREF(p, sip_destroy_peer);
return -1;
}
+
}
if (inringing && (event == INC_CALL_RINGING)) {
if (!ast_test_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING)) {
@@ -4065,6 +4109,7 @@
int x, y;
int debug = sip_debug_test_pvt(p);
struct ast_channel *bridgepeer = NULL;
+ int secure_audio = FALSE;
if (!p->rtp) {
ast_log(LOG_ERROR, "Got SDP but have no RTP session allocated.\n");
@@ -4095,8 +4140,20 @@
ast_set_flag(&p->flags[0], SIP_NOVIDEO);
while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
int found = 0;
- if ((sscanf(m, "audio %d/%d RTP/AVP %n", &x, &y, &len) == 2) ||
- (sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1)) {
+ char protocol[5] = "";
+ len = -1;
+ if ((sscanf(m, "audio %d/%d RTP/%4s %n", &x, &y, protocol, &len) == 3) ||
+ (sscanf(m, "audio %d RTP/%4s %n", &x, protocol, &len) == 2)) {
+ if (!strcmp(protocol, "SAVP"))
+ secure_audio = 1;
+ else if (strcmp(protocol, "AVP")) {
+ ast_log(LOG_WARNING, "Unknown SDP media protocol in offer: %s\n", protocol);
+ continue;
+ }
+ if (len < 0) {
+ ast_log(LOG_WARNING, "Unknown SDP media type in offer: %s\n", m);
+ continue;
+ }
found = 1;
portno = x;
/* Scan through the RTP payload types specified in a "m=" line: */
@@ -4196,10 +4253,13 @@
if (!strcasecmp(a, "sendonly")) {
sendonly=1;
continue;
- }
- if (!strcasecmp(a, "sendrecv")) {
+ } else if (!strcasecmp(a, "sendrecv")) {
sendonly=0;
- }
+ } else if (!strncasecmp(a, "crypto:", 7)) {
+ process_crypto(p, a);
+ continue;
+ }
+
if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) continue;
if (debug)
ast_verbose("Found description format %s\n", mimeSubtype);
@@ -4207,6 +4267,11 @@
ast_rtp_set_rtpmap_type(p->rtp, codec, "audio", mimeSubtype);
if (p->vrtp)
ast_rtp_set_rtpmap_type(p->vrtp, codec, "video", mimeSubtype);
+
+ if (secure_audio && !(p->srtp && p->srtp->a_crypto)) {
+ ast_log(LOG_WARNING, "Can't provide secure audio requested in SDP offer\n");
+ return -2;
+ }
}
/* Now gather all of the codecs that were asked for: */
@@ -4944,6 +5009,8 @@
char m_video[256];
char a_audio[1024];
char a_video[1024];
+ char crypto_buf[128];
+ const char *a_crypto = NULL;
char *m_audio_next = m_audio;
char *m_video_next = m_video;
size_t m_audio_left = sizeof(m_audio);
@@ -4958,6 +5025,8 @@
struct sockaddr_in dest;
struct sockaddr_in vdest = { 0, };
int debug;
+ const char *protocol = NULL;
+ struct sip_srtp *srtp = p->srtp;
debug = sip_debug_test_pvt(p);
@@ -5003,6 +5072,24 @@
ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ntohs(vsin.sin_port));
}
+ if (srtp) {
+ if (srtp->a_crypto) {
+ a_crypto = srtp->a_crypto;
+ } else {
+ const char *crypto_suite = "AES_CM_128_HMAC_SHA1_80";
+ snprintf(crypto_buf, sizeof(crypto_buf),
+ "a=crypto:1 %s inline:%s\r\n",
+ crypto_suite, srtp->local_key64);
+ a_crypto = crypto_buf;
+ }
+ }
+
+ if (a_crypto) {
+ protocol = "SAVP";
+ } else {
+ protocol = "AVP";
+ }
+
/* We break with the "recommendation" and send our IP, in order that our
peer doesn't have to ast_gethostbyname() us */
@@ -5016,8 +5103,8 @@
snprintf(b, sizeof(b), "b=CT:%d\r\n", p->maxcallbitrate);
snprintf(t, sizeof(t), "t=0 0\r\n");
- ast_build_string(&m_audio_next, &m_audio_left, "m=audio %d RTP/AVP", ntohs(dest.sin_port));
- ast_build_string(&m_video_next, &m_video_left, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
+ ast_build_string(&m_audio_next, &m_audio_left, "m=audio %d RTP/%s", ntohs(dest.sin_port), protocol);
+ ast_build_string(&m_video_next, &m_video_left, "m=video %d RTP/%s", ntohs(vdest.sin_port), protocol);
if (ast_test_flag(&p->flags[0], SIP_CALL_ONHOLD))
hold = "a=recvonly\r\n";
@@ -5110,6 +5197,9 @@
(capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
len += strlen(m_video) + strlen(a_video) + strlen(b) + strlen(hold);
+ if (a_crypto)
+ len += strlen(a_crypto);
+
add_header(resp, "Content-Type", "application/sdp");
add_header_contentLength(resp, len);
add_line(resp, v);
@@ -5123,6 +5213,8 @@
add_line(resp, t);
add_line(resp, m_audio);
add_line(resp, a_audio);
+ if (a_crypto)
+ len += strlen(a_crypto);
add_line(resp, hold);
if ((p->vrtp) &&
(!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
@@ -14964,6 +15056,239 @@
);
}
+
+/*
+ * SRTP sdescriptions
+ * Specified in: draft-ietf-mmusic-sdescriptions-12.txt
+ */
+
+static struct sip_srtp *sip_srtp_alloc(void)
+{
+ struct sip_srtp *srtp = malloc(sizeof(*srtp));
+
+ if (srtp)
+ memset(srtp, 0, sizeof(*srtp));
+ else
+ ast_log(LOG_ERROR, "Out of memory, can't allocate srtp structure\n");
+
+ return srtp;
+}
+
+static void sip_srtp_destroy(struct sip_srtp *srtp)
+{
+ free(srtp->a_crypto);
+ srtp->a_crypto = NULL;
+}
+
+
+static int setup_crypto(struct sip_pvt *p)
+{
+ if (!ast_srtp_is_registered()) {
+ ast_log(LOG_ERROR, "No SRTP module loaded, can't setup SRTP session.\n");
+ return -1;
+ }
+
+ p->srtp = sip_srtp_alloc(); /* Allocate SRTP data structure */
+ if (!p->srtp)
+ return -1;
+
+ if (ast_srtp_get_random(p->srtp->local_key, sizeof(p->srtp->local_key)) < 0) {
+ sip_srtp_destroy(p->srtp);
+ p->srtp = NULL;
+ return -1;
+ }
+
+ ast_base64encode(p->srtp->local_key64, p->srtp->local_key,
+ SRTP_MASTER_LEN, sizeof(p->srtp->local_key64));
+ return 0;
+}
+
+static int set_crypto_policy(struct ast_srtp_policy *policy,
+ int suite_val, const unsigned char *master_key,
+ unsigned long ssrc, int inbound)
+{
+ const unsigned char *master_salt = NULL;
+
+ master_salt = master_key + SRTP_MASTERKEY_LEN;
+ if (ast_srtp_policy_set_master_key(policy,
+ master_key, SRTP_MASTERKEY_LEN,
+ master_salt, SRTP_MASTERSALT_LEN) < 0)
+ return -1;
+
+
+ if (ast_srtp_policy_set_suite(policy, suite_val)) {
+ ast_log(LOG_WARNING, "Could not set remote SRTP suite\n");
+ return -1;
+ }
+
+ ast_srtp_policy_set_ssrc(policy, ssrc, inbound);
+
+ return 0;
+}
+
+static int activate_crypto(struct sip_pvt *p, int suite_val,
+ unsigned char *remote_key)
+{
+ struct ast_srtp_policy *local_policy = NULL;
+ struct ast_srtp_policy *remote_policy = NULL;
+ int res = -1;
+ struct sip_srtp *srtp = p->srtp;
+
+ if (!srtp)
+ return -1;
+
+ local_policy = ast_srtp_policy_alloc();
+ if (!local_policy)
+ goto err;
+
+ remote_policy = ast_srtp_policy_alloc();
+ if (!remote_policy) {
+ goto err;
+ }
+
+ if (set_crypto_policy(local_policy, suite_val, srtp->local_key,
+ ast_rtp_get_ssrc(p->rtp), 0) < 0)
+ goto err;
+
+ if (set_crypto_policy(remote_policy, suite_val, remote_key, 0, 1) < 0)
+ goto err;
+
+ if (ast_rtp_add_srtp_policy(p->rtp, local_policy)) {
+ ast_log(LOG_WARNING, "Could not set local SRTP policy\n");
+ goto err;
+ }
+
+ if (ast_rtp_add_srtp_policy(p->rtp, remote_policy)) {
+ ast_log(LOG_WARNING, "Could not set remote SRTP policy\n");
+ goto err;
+ }
+
+
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "SRTP policy activated\n");
+ res = 0;
+
+err:
+ if (local_policy)
+ ast_srtp_policy_destroy(local_policy);
+
+ if (remote_policy)
+ ast_srtp_policy_destroy(remote_policy);
+ return res;
+}
+
+static int process_crypto(struct sip_pvt *p, const char *attr)
+{
+ char *str = NULL;
+ char *name = NULL;
+ char *tag = NULL;
+ char *suite = NULL;
+ char *key_params = NULL;
+ char *key_param = NULL;
+ char *session_params = NULL;
+ char *key_salt = NULL;
+ char *lifetime = NULL;
+ int found = 0;
+ int attr_len = strlen(attr);
+ int key_len = 0;
+ unsigned char remote_key[SRTP_MASTER_LEN];
+ int suite_val = 0;
+ struct sip_srtp *srtp = p->srtp;
+
+ if (!ast_srtp_is_registered())
+ return -1;
+
+ /* Crypto already accepted */
+ if (srtp && srtp->a_crypto)
+ return -1;
+
+ str = ast_strdupa(attr);
+
+ name = strsep(&str, ":");
+ tag = strsep(&str, " ");
+ suite = strsep(&str, " ");
+ key_params = strsep(&str, " ");
+ session_params = strsep(&str, " ");
+
+ if (!tag || !suite) {
+ ast_log(LOG_WARNING, "Unrecognized a=%s", attr);
+ return -1;
+ }
+
+ if (session_params) {
+ ast_log(LOG_WARNING, "Unsupported crypto parameters: %s",
+ session_params);
+ return -1;
+ }
+
+ if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80")) {
+ suite_val = AST_AES_CM_128_HMAC_SHA1_80;
+ } else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) {
+ suite_val = AST_AES_CM_128_HMAC_SHA1_32;
+ } else {
+ ast_log(LOG_WARNING, "Unsupported crypto suite: %s",
+ suite);
+ return -1;
+ }
+
+ while ((key_param = strsep(&key_params, ";"))) {
+ char *method = NULL;
+ char *info = NULL;
+
+ method = strsep(&key_param, ":");
+ info = strsep(&key_param, ";");
+
+ if (!strcmp(method, "inline")) {
+ key_salt = strsep(&info, "|");
+ lifetime = strsep(&info, "|");
+
+ if (lifetime) {
+ ast_log(LOG_NOTICE, "Crypto life time unsupported: %s\n",
+ attr);
+ continue;
+ }
+
+/* if (info || strncmp(lifetime, "2^", 2)) { */
+/* ast_log(LOG_NOTICE, "MKI unsupported: %s\n", */
+/* attr); */
+/* continue; */
+/* } */
+
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ ast_log(LOG_NOTICE, "SRTP crypto offer not acceptable\n");
+ return -1;
+ }
+
+ if (!srtp) {
+ setup_crypto(p);
+ srtp = p->srtp;
+ }
+
+ key_len = ast_base64decode(remote_key, key_salt, sizeof(remote_key));
+ if (key_len != SRTP_MASTER_LEN) {
+ ast_log(LOG_WARNING, "SRTP sdescriptions key %d != %d\n",
+ key_len, SRTP_MASTER_LEN);
+ return -1;
+ }
+
+ if (activate_crypto(p, suite_val, remote_key) < 0)
+ return -1;
+
+ srtp->a_crypto = malloc(attr_len+11);
+ snprintf(srtp->a_crypto, attr_len+10,
+ "a=crypto:%s %s inline:%s\r\n",
+ tag, suite, srtp->local_key64);
+
+ return 0;
+}
+
+
+
/*! \brief Reload module */
static int sip_do_reload(enum channelreloadreason reason)
{
Modified: team/oej/securertp-trunk/include/asterisk/rtp.h
URL: http://svn.digium.com/view/asterisk/team/oej/securertp-trunk/include/asterisk/rtp.h?rev=32521&r1=32520&r2=32521&view=diff
==============================================================================
--- team/oej/securertp-trunk/include/asterisk/rtp.h (original)
+++ team/oej/securertp-trunk/include/asterisk/rtp.h Tue Jun 6 04:03:51 2006
@@ -71,6 +71,66 @@
* RTP session is defined on page 9 of RFC 3550: "An association among a set of participants communicating with RTP. A participant may be involved in multiple RTP sessions at the same time [...]"
*
*/
+struct ast_srtp;
+
+struct ast_srtp_policy;
+
+struct ast_srtp_cb {
+ int (*no_ctx)(struct ast_rtp *rtp, unsigned long ssrc, void *data);
+};
+
+struct ast_srtp_res {
+ int (*create)(struct ast_srtp **srtp, struct ast_rtp *rtp,
+ struct ast_srtp_policy *policy);
+ void (*destroy)(struct ast_srtp *srtp);
+ int (*add_stream)(struct ast_srtp *srtp, struct ast_srtp_policy *policy);
+ void (*set_cb)(struct ast_srtp *srtp,
+ const struct ast_srtp_cb *cb, void *data);
+ int (*unprotect)(struct ast_srtp *srtp, void *buf, int *size);
+ int (*protect)(struct ast_srtp *srtp, void **buf, int *size);
+ int (*get_random)(unsigned char *key, size_t len);
+};
+
+/* Crypto suites */
+enum ast_srtp_suite {
+ AST_AES_CM_128_HMAC_SHA1_80 = 1,
+ AST_AES_CM_128_HMAC_SHA1_32 = 2,
+ AST_F8_128_HMAC_SHA1_80 = 3
+};
+
+enum ast_srtp_ealg {
+ AST_MIKEY_SRTP_EALG_NULL = 0,
+ AST_MIKEY_SRTP_EALG_AESCM = 1
+};
+
+enum ast_srtp_aalg {
+ AST_MIKEY_SRTP_AALG_NULL = 0,
+ AST_MIKEY_SRTP_AALG_SHA1HMAC = 1
+};
+
+struct ast_srtp_policy_res {
+ struct ast_srtp_policy *(*alloc)(void);
+ void (*destroy)(struct ast_srtp_policy *policy);
+ int (*set_suite)(struct ast_srtp_policy *policy,
+ enum ast_srtp_suite suite);
+ int (*set_master_key)(struct ast_srtp_policy *policy,
+ const unsigned char *key, size_t key_len,
+ const unsigned char *salt, size_t salt_len);
+ int (*set_encr_alg)(struct ast_srtp_policy *policy,
+ enum ast_srtp_ealg ealg);
+ int (*set_auth_alg)(struct ast_srtp_policy *policy,
+ enum ast_srtp_aalg aalg);
+ void (*set_encr_keylen)(struct ast_srtp_policy *policy, int ekeyl);
+ void (*set_auth_keylen)(struct ast_srtp_policy *policy, int akeyl);
+ void (*set_srtp_auth_taglen)(struct ast_srtp_policy *policy, int autht);
+ void (*set_srtp_encr_enable)(struct ast_srtp_policy *policy, int enable);
+ void (*set_srtcp_encr_enable)(struct ast_srtp_policy *policy, int enable);
+ void (*set_srtp_auth_enable)(struct ast_srtp_policy *policy, int enable);
+ void (*set_ssrc)(struct ast_srtp_policy *policy, unsigned long ssrc,
+ int inbound);
+};
+
+typedef int (*ast_rtp_callback)(struct ast_rtp *rtp, struct ast_frame *f, void *data);
/*! \brief The value of each payload format mapping: */
struct rtpPayloadType {
@@ -130,6 +190,7 @@
int rtp_lookup_code_cache_code;
int rtp_lookup_code_cache_result;
struct ast_rtcp *rtcp;
+ struct ast_srtp *srtp; /*!< Secure RTP data */
};
/*!
@@ -238,6 +299,33 @@
int ast_rtp_reload(void);
+int ast_rtp_register_srtp(struct ast_srtp_res *srtp_res, struct ast_srtp_policy_res *policy_res);
+
+int ast_rtp_unregister_srtp(struct ast_srtp_res *srtp_res, struct ast_srtp_policy_res *policy_res);
+
+int ast_srtp_is_registered(void);
+
+unsigned int ast_rtp_get_ssrc(struct ast_rtp *rtp);
+void ast_rtp_set_srtp_cb(struct ast_rtp *rtp, const struct ast_srtp_cb *cb,
+ void *data);
+int ast_rtp_add_srtp_policy(struct ast_rtp *rtp, struct ast_srtp_policy *policy);
+struct ast_srtp_policy *ast_srtp_policy_alloc(void);
+int ast_srtp_policy_set_suite(struct ast_srtp_policy *policy, enum ast_srtp_suite suite);
+int ast_srtp_policy_set_master_key(struct ast_srtp_policy *policy, const unsigned char *key, size_t key_len, const unsigned char *salt, size_t salt_len);
+int ast_srtp_policy_set_encr_alg(struct ast_srtp_policy *policy, enum ast_srtp_ealg ealg);
+int ast_srtp_policy_set_auth_alg(struct ast_srtp_policy *policy, enum ast_srtp_aalg aalg);
+void ast_srtp_policy_set_encr_keylen(struct ast_srtp_policy *policy, int ekeyl);
+void ast_srtp_policy_set_auth_keylen(struct ast_srtp_policy *policy, int akeyl);
+void ast_srtp_policy_set_srtp_auth_taglen(struct ast_srtp_policy *policy, int autht);
+void ast_srtp_policy_set_srtp_encr_enable(struct ast_srtp_policy *policy, int enable);
+void ast_srtp_policy_set_srtcp_encr_enable(struct ast_srtp_policy *policy, int enable);
+void ast_srtp_policy_set_srtp_auth_enable(struct ast_srtp_policy *policy, int enable);
+void ast_srtp_policy_set_ssrc(struct ast_srtp_policy *policy, unsigned long ssrc, int inbound);
+
+void ast_srtp_policy_destroy(struct ast_srtp_policy *policy);
+int ast_srtp_get_random(unsigned char *key, size_t len);
+
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
Modified: team/oej/securertp-trunk/rtp.c
URL: http://svn.digium.com/view/asterisk/team/oej/securertp-trunk/rtp.c?rev=32521&r1=32520&r2=32521&view=diff
==============================================================================
--- team/oej/securertp-trunk/rtp.c (original)
+++ team/oej/securertp-trunk/rtp.c Tue Jun 6 04:03:51 2006
@@ -89,6 +89,9 @@
#ifdef SO_NO_CHECK
static int nochecksums = 0;
#endif
+
+struct ast_srtp_res *g_srtp_res;
+struct ast_srtp_policy_res *g_policy_res;
/* Forward declarations */
static int ast_rtcp_write(void *data);
@@ -643,6 +646,224 @@
rtp->f.delivery.tv_usec = rtp->f.delivery.tv_sec = 0;
f = &rtp->f;
return f;
+}
+
+/*! \brief Register SRTP module in res_srtp to rtp core */
+int ast_rtp_register_srtp(struct ast_srtp_res *srtp_res,
+ struct ast_srtp_policy_res *policy_res)
+{
+ if (g_srtp_res || g_policy_res)
+ return -1;
+
+ if (!srtp_res || !policy_res)
+ return -1;
+
+ g_srtp_res = srtp_res;
+ g_policy_res = policy_res;
+ return 0;
+}
+
+int ast_rtp_unregister_srtp(struct ast_srtp_res *srtp_res,
+ struct ast_srtp_policy_res *policy_res)
+{
+ g_srtp_res = NULL;
+ g_policy_res = NULL;
+ return 0;
+}
+
+/*! \brief Check if there's a SRTP module registred and available */
+int ast_srtp_is_registered(void)
+{
+ return g_srtp_res && g_policy_res;
+}
+
+unsigned int ast_rtp_get_ssrc(struct ast_rtp *rtp)
+{
+ return rtp->ssrc;
+}
+
+void ast_rtp_set_srtp_cb(struct ast_rtp *rtp, const struct ast_srtp_cb *cb,
+ void *data)
+{
+ if (!g_srtp_res || !rtp->srtp)
+ return;
+
+ g_srtp_res->set_cb(rtp->srtp, cb, data);
+}
+
+void ast_srtp_policy_set_ssrc(struct ast_srtp_policy *policy, unsigned long ssrc, int inbound)
+{
+ if (!g_policy_res)
+ return;
+
+ g_policy_res->set_ssrc(policy, ssrc, inbound);
+}
+
+int ast_rtp_add_srtp_policy(struct ast_rtp *rtp, struct ast_srtp_policy *policy)
+{
+ int res;
+
+ if (!g_srtp_res)
+ return -1;
+
+ if (!rtp->srtp) {
+ res = g_srtp_res->create(&rtp->srtp, rtp, policy);
+ } else {
+ res = g_srtp_res->add_stream(rtp->srtp, policy);
+ }
+
+ return res;
+}
+
+struct ast_srtp_policy *ast_srtp_policy_alloc()
+{
+ if (!g_policy_res)
+ return NULL;
+
+ return g_policy_res->alloc();
+}
+
+void ast_srtp_policy_destroy(struct ast_srtp_policy *policy)
+{
+ if (!g_policy_res)
+ return;
+
+ g_policy_res->destroy(policy);
+}
+
+int ast_srtp_policy_set_suite(struct ast_srtp_policy *policy,
+ enum ast_srtp_suite suite)
+{
+ if (!g_policy_res)
+ return -1;
+
+ return g_policy_res->set_suite(policy, suite);
+}
+
+int ast_srtp_policy_set_master_key(struct ast_srtp_policy *policy,
+ const unsigned char *key, size_t key_len,
+ const unsigned char *salt, size_t salt_len)
+{
+ if (!g_policy_res)
+ return -1;
+
+ return g_policy_res->set_master_key(policy, key, key_len, salt, salt_len);
+}
+
+int ast_srtp_policy_set_encr_alg(struct ast_srtp_policy *policy,
+ enum ast_srtp_ealg ealg)
+{
+ if (!g_policy_res)
+ return -1;
+
+ return g_policy_res->set_encr_alg(policy, ealg);
+}
+
+int ast_srtp_policy_set_auth_alg(struct ast_srtp_policy *policy,
+ enum ast_srtp_aalg aalg)
+{
+ if (!g_policy_res)
+ return -1;
+
+ return g_policy_res->set_auth_alg(policy, aalg);
+}
+
+void ast_srtp_policy_set_encr_keylen(struct ast_srtp_policy *policy, int ekeyl)
+{
+ if (!g_policy_res)
+ return;
+
+ return g_policy_res->set_encr_keylen(policy, ekeyl);
+}
+
+void ast_srtp_policy_set_auth_keylen(struct ast_srtp_policy *policy,
+ int akeyl)
+{
+ if (!g_policy_res)
+ return;
+
+ return g_policy_res->set_auth_keylen(policy, akeyl);
+}
+
+void ast_srtp_policy_set_srtp_auth_taglen(struct ast_srtp_policy *policy,
+ int autht)
+{
+ if (!g_policy_res)
+ return;
+
+ return g_policy_res->set_srtp_auth_taglen(policy, autht);
+}
+
+void ast_srtp_policy_set_srtp_encr_enable(struct ast_srtp_policy *policy,
+ int enable)
+{
+ if (!g_policy_res)
+ return;
+
+ return g_policy_res->set_srtp_encr_enable(policy, enable);
+}
+
+void ast_srtp_policy_set_srtcp_encr_enable(struct ast_srtp_policy *policy,
+ int enable)
+{
+ if (!g_policy_res)
+ return;
+
+ return g_policy_res->set_srtcp_encr_enable(policy, enable);
+}
+
+void ast_srtp_policy_set_srtp_auth_enable(struct ast_srtp_policy *policy,
+ int enable)
+{
+ if (!g_policy_res)
+ return;
+
+ return g_policy_res->set_srtp_auth_enable(policy, enable);
+}
+
+int ast_srtp_get_random(unsigned char *key, size_t len)
+{
+ if (!g_srtp_res)
+ return -1;
+
+ return g_srtp_res->get_random(key, len);
+}
+
+static int rtp_recvfrom(struct ast_rtp *rtp, void *buf, size_t size,
+ int flags, struct sockaddr *sa, socklen_t *salen)
+{
+ int len;
+
+ len = recvfrom(rtp->s, buf, size, flags, sa, salen);
+
+ if (len < 0)
+ return len;
+
+ if (g_srtp_res && rtp->srtp) {
+ int res;
+
+ res = g_srtp_res->unprotect(rtp->srtp, buf, &len);
+ if (res < 0)
+ return -1;
+ }
+
+ return len;
+}
+
+static int rtp_sendto(struct ast_rtp *rtp, void *buf, size_t size,
+ int flags, struct sockaddr *sa, socklen_t salen)
+{
+ int len = size;
+ void *temp = buf;
+
+ if (g_srtp_res && rtp->srtp) {
+ int res = g_srtp_res->protect(rtp->srtp, &temp, &len);
+
+ if (res < 0)
+ return -1;
+ }
+
+ return sendto(rtp->s, temp, len, flags, sa, salen);
}
static int rtpread(int *id, int fd, short events, void *cbdata)
@@ -1760,6 +1981,10 @@
free(rtp->rtcp);
rtp->rtcp=NULL;
}
+ if (g_srtp_res && rtp->srtp) {
+ g_srtp_res->destroy(rtp->srtp);
+ rtp->srtp = NULL;
+ }
free(rtp);
}
@@ -1822,7 +2047,7 @@
rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (0));
for (x = 0; x < 6; x++) {
if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
- res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
+ res = rtp_sendto(rtp, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
if (res < 0)
ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n",
ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr),
@@ -2126,7 +2351,7 @@
rtpheader[2] = htonl(rtp->ssrc);
data[12] = level;
if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
- res = sendto(rtp->s, (void *)rtpheader, hdrlen + 1, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
+ res = rtp_sendto(rtp, (void *)rtpheader, hdrlen + 1, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
if (res <0)
ast_log(LOG_ERROR, "RTP Comfort Noise Transmission error to %s:%d: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
if (rtp_debug_test_addr(&rtp->them))
@@ -2199,7 +2424,7 @@
put_unaligned_uint32(rtpheader + 8, htonl(rtp->ssrc));
if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
- res = sendto(rtp->s, (void *)rtpheader, f->datalen + hdrlen, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
+ res = rtp_sendto(rtp, (void *)rtpheader, f->datalen + hdrlen, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
if (res <0) {
if (!rtp->nat || (rtp->nat && (ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) {
ast_log(LOG_DEBUG, "RTP Transmission error of packet %d to %s:%d: %s\n", rtp->seqno, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
@@ -2454,17 +2679,31 @@
/* Get audio and video interface (if native bridge is possible) */
p0 = pr0->get_rtp_info(c0);
- vp0 = pr0->get_vrtp_info ? pr0->get_vrtp_info(c0) : NULL;
+ if (pr0->get_vrtp_info)
+ vp0 = pr0->get_vrtp_info(c0);
+ else
+ vp0 = NULL;
p1 = pr1->get_rtp_info(c1);
- vp1 = pr1->get_vrtp_info ? pr1->get_vrtp_info(c1) : NULL;
+ if (pr1->get_vrtp_info)
+ vp1 = pr1->get_vrtp_info(c1);
+ else
+ vp1 = NULL;
/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
if (!p0 || !p1) {
/* Somebody doesn't want to play... */
- ast_channel_unlock(c0);
- ast_channel_unlock(c1);
+ ast_mutex_unlock(&c0->lock);
+ ast_mutex_unlock(&c1->lock);
return AST_BRIDGE_FAILED_NOWARN;
}
+
+ if (p0->srtp || p1->srtp) {
+ ast_log(LOG_NOTICE, "Cannot native bridge in SRTP.\n");
+ ast_mutex_unlock(&c0->lock);
+ ast_mutex_unlock(&c1->lock);
+ return AST_BRIDGE_FAILED_NOWARN;
+ }
+
if (ast_test_flag(p0, FLAG_HAS_DTMF) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
/* can't bridge, we are carrying DTMF for this channel and the bridge
@@ -2485,21 +2724,24 @@
}
/* Get codecs from both sides */
- codec0 = pr0->get_codec ? pr0->get_codec(c0) : 0;
- codec1 = pr1->get_codec ? pr1->get_codec(c1) : 0;
+ if (pr0->get_codec)
+ codec0 = pr0->get_codec(c0);
+ else
+ codec0 = 0;
+ if (pr1->get_codec)
+ codec1 = pr1->get_codec(c1);
+ else
+ codec1 = 0;
if (pr0->get_codec && pr1->get_codec) {
/* Hey, we can't do reinvite if both parties speak different codecs */
if (!(codec0 & codec1)) {
if (option_debug)
ast_log(LOG_DEBUG, "Channel codec0 = %d is not codec1 = %d, cannot native bridge in RTP.\n", codec0, codec1);
- ast_channel_unlock(c0);
- ast_channel_unlock(c1);
+ ast_mutex_unlock(&c0->lock);
+ ast_mutex_unlock(&c1->lock);
return AST_BRIDGE_FAILED_NOWARN;
}
}
-
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Native bridging %s and %s\n", c0->name, c1->name);
/* Ok, we should be able to redirect the media. Start with one channel */
if (pr0->set_rtp_peer(c0, p1, vp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))
More information about the asterisk-commits
mailing list