RFC4568 support, you don't need the cone of silence anymore...

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@7244 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2008-01-16 06:01:53 +00:00
parent ca55a0113e
commit 65668e7e6a
10 changed files with 371 additions and 121 deletions

View File

@ -41,12 +41,50 @@
SWITCH_BEGIN_EXTERN_C SWITCH_BEGIN_EXTERN_C
#define SWITCH_RTP_MAX_BUF_LEN 16384 #define SWITCH_RTP_MAX_BUF_LEN 16384
#define SWITCH_RTP_MAX_CRYPTO_LEN 64
#define SWITCH_RTP_KEY_LEN 30
#define SWITCH_RTP_CRYPTO_KEY_32 "AES_CM_128_HMAC_SHA1_32"
#define SWITCH_RTP_CRYPTO_KEY_80 "AES_CM_128_HMAC_SHA1_80"
typedef enum {
SWITCH_RTP_CRYPTO_SEND,
SWITCH_RTP_CRYPTO_RECV,
SWITCH_RTP_CRYPTO_MAX
} switch_rtp_crypto_direction_t;
typedef enum {
NO_CRYPTO,
AES_CM_128_HMAC_SHA1_80,
AES_CM_128_HMAC_SHA1_32
} switch_rtp_crypto_key_type_t;
struct switch_rtp_crypto_key {
uint32_t index;
switch_rtp_crypto_key_type_t type;
unsigned char key[SWITCH_RTP_MAX_CRYPTO_LEN];
switch_size_t keylen;
struct switch_rtp_crypto_key *next;
};
typedef struct switch_rtp_crypto_key switch_rtp_crypto_key_t;
SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_session,
switch_rtp_crypto_direction_t direction,
uint32_t index,
switch_rtp_crypto_key_type_t type,
unsigned char *key,
switch_size_t keylen);
///\defgroup rtp RTP (RealTime Transport Protocol) ///\defgroup rtp RTP (RealTime Transport Protocol)
///\ingroup core1 ///\ingroup core1
///\{ ///\{
typedef void (*switch_rtp_invalid_handler_t) (switch_rtp_t *rtp_session, typedef void (*switch_rtp_invalid_handler_t) (switch_rtp_t *rtp_session,
switch_socket_t * sock, void *data, switch_size_t datalen, switch_sockaddr_t * from_addr); switch_socket_t * sock, void *data, switch_size_t datalen, switch_sockaddr_t * from_addr);
SWITCH_DECLARE(void) switch_rtp_get_random(void *buf, uint32_t len);
/*! /*!
\brief Initilize the RTP System \brief Initilize the RTP System
\param pool the memory pool to use for long term allocations \param pool the memory pool to use for long term allocations
@ -83,7 +121,6 @@ SWITCH_DECLARE(void) switch_rtp_release_port(const char *ip, switch_port_t port)
\param samples_per_interval the default samples_per_interval \param samples_per_interval the default samples_per_interval
\param ms_per_packet time in microseconds per packet \param ms_per_packet time in microseconds per packet
\param flags flags to control behaviour \param flags flags to control behaviour
\param crypto_key optional crypto key
\param timer_name timer interface to use \param timer_name timer interface to use
\param err a pointer to resolve error messages \param err a pointer to resolve error messages
\param pool a memory pool to use for the session \param pool a memory pool to use for the session
@ -93,7 +130,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
switch_payload_t payload, switch_payload_t payload,
uint32_t samples_per_interval, uint32_t samples_per_interval,
uint32_t ms_per_packet, uint32_t ms_per_packet,
switch_rtp_flag_t flags, char *crypto_key, char *timer_name, const char **err, switch_rtp_flag_t flags,
char *timer_name,
const char **err,
switch_memory_pool_t *pool); switch_memory_pool_t *pool);
@ -107,7 +146,6 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
\param samples_per_interval the default samples_per_interval \param samples_per_interval the default samples_per_interval
\param ms_per_packet time in microseconds per packet \param ms_per_packet time in microseconds per packet
\param flags flags to control behaviour \param flags flags to control behaviour
\param crypto_key optional crypto key
\param timer_name timer interface to use \param timer_name timer interface to use
\param err a pointer to resolve error messages \param err a pointer to resolve error messages
\param pool a memory pool to use for the session \param pool a memory pool to use for the session
@ -120,7 +158,10 @@ SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host,
switch_payload_t payload, switch_payload_t payload,
uint32_t samples_per_interval, uint32_t samples_per_interval,
uint32_t ms_per_packet, uint32_t ms_per_packet,
switch_rtp_flag_t flags, char *crypto_key, char *timer_name, const char **err, switch_memory_pool_t *pool); switch_rtp_flag_t flags,
char *timer_name,
const char **err,
switch_memory_pool_t *pool);
/*! /*!

View File

@ -56,7 +56,7 @@ SWITCH_BEGIN_EXTERN_C
#endif #endif
SWITCH_DECLARE(switch_status_t) switch_b64_encode(unsigned char *in, switch_size_t ilen, unsigned char *out, switch_size_t olen); SWITCH_DECLARE(switch_status_t) switch_b64_encode(unsigned char *in, switch_size_t ilen, unsigned char *out, switch_size_t olen);
SWITCH_DECLARE(switch_status_t) switch_b64_decode(char *in, char *out, switch_size_t olen); SWITCH_DECLARE(switch_size_t) switch_b64_decode(char *in, char *out, switch_size_t olen);
SWITCH_DECLARE(char *) switch_amp_encode(char *s, char *buf, switch_size_t len); SWITCH_DECLARE(char *) switch_amp_encode(char *s, char *buf, switch_size_t len);
static inline switch_bool_t switch_is_digit_string(const char *s) { static inline switch_bool_t switch_is_digit_string(const char *s) {

View File

@ -167,7 +167,7 @@ SWITCH_STANDARD_APP(bcast_function)
read_codec->implementation->samples_per_frame, read_codec->implementation->samples_per_frame,
read_codec->implementation->microseconds_per_frame, read_codec->implementation->microseconds_per_frame,
(switch_rtp_flag_t) flags, (switch_rtp_flag_t) flags,
NULL, "soft", &err, switch_core_session_get_pool(session)); "soft", &err, switch_core_session_get_pool(session));
if (!switch_rtp_ready(rtp_session)) { if (!switch_rtp_ready(rtp_session)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP Error\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP Error\n");

View File

@ -877,7 +877,7 @@ static int activate_rtp(struct private_object *tech_pvt)
tech_pvt->codec_num, tech_pvt->codec_num,
tech_pvt->read_codec.implementation->samples_per_frame, tech_pvt->read_codec.implementation->samples_per_frame,
tech_pvt->read_codec.implementation->microseconds_per_frame, tech_pvt->read_codec.implementation->microseconds_per_frame,
flags, NULL, tech_pvt->profile->timer_name, &err, switch_core_session_get_pool(tech_pvt->session)))) { flags, tech_pvt->profile->timer_name, &err, switch_core_session_get_pool(tech_pvt->session)))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP ERROR %s\n", err); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP ERROR %s\n", err);
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return 0; return 0;

View File

@ -90,6 +90,19 @@ static switch_status_t sofia_on_init(switch_core_session_t *session)
} }
if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
const char *var;
if ((var = switch_channel_get_variable(channel, SOFIA_SECURE_MEDIA_VARIABLE)) && !switch_strlen_zero(var)) {
if (switch_true(var) || !strcasecmp(var, SWITCH_RTP_CRYPTO_KEY_32)) {
switch_set_flag_locked(tech_pvt, TFLAG_SECURE);
sofia_glue_build_crypto(tech_pvt, 1, AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND);
} else if (!strcasecmp(var, SWITCH_RTP_CRYPTO_KEY_80)) {
switch_set_flag_locked(tech_pvt, TFLAG_SECURE);
sofia_glue_build_crypto(tech_pvt, 1, AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND);
}
}
if (sofia_glue_do_invite(session) != SWITCH_STATUS_SUCCESS) { if (sofia_glue_do_invite(session) != SWITCH_STATUS_SUCCESS) {
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return SWITCH_STATUS_FALSE; return SWITCH_STATUS_FALSE;
@ -786,6 +799,13 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
tech_pvt = (private_object_t *) switch_core_session_get_private(session); tech_pvt = (private_object_t *) switch_core_session_get_private(session);
switch_assert(tech_pvt != NULL); switch_assert(tech_pvt != NULL);
if (msg->message_id == SWITCH_MESSAGE_INDICATE_ANSWER || msg->message_id == SWITCH_MESSAGE_INDICATE_PROGRESS) {
const char *var;
if ((var = switch_channel_get_variable(channel, SOFIA_SECURE_MEDIA_VARIABLE)) && switch_true(var)) {
switch_set_flag_locked(tech_pvt, TFLAG_SECURE);
}
}
switch (msg->message_id) { switch (msg->message_id) {
case SWITCH_MESSAGE_INDICATE_BROADCAST: { case SWITCH_MESSAGE_INDICATE_BROADCAST: {
const char *ip = NULL, *port = NULL; const char *ip = NULL, *port = NULL;
@ -1746,6 +1766,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session
*pool = NULL; *pool = NULL;
done: done:
if (profile) { if (profile) {
sofia_glue_release_profile(profile); sofia_glue_release_profile(profile);
} }

View File

@ -73,6 +73,9 @@ typedef struct private_object private_object_t;
#define SOFIA_DEFAULT_PORT "5060" #define SOFIA_DEFAULT_PORT "5060"
#define SOFIA_DEFAULT_TLS_PORT "5061" #define SOFIA_DEFAULT_TLS_PORT "5061"
#define SOFIA_REFER_TO_VARIABLE "sip_refer_to" #define SOFIA_REFER_TO_VARIABLE "sip_refer_to"
#define SOFIA_SECURE_MEDIA_VARIABLE "sip_secure_media"
#define SOFIA_SECURE_MEDIA_CONFIRMED_VARIABLE "sip_secure_media_confirmed"
#define SOFIA_HAS_CRYPTO_VARIABLE "sip_has_crypto"
#include <sofia-sip/nua.h> #include <sofia-sip/nua.h>
#include <sofia-sip/sip_status.h> #include <sofia-sip/sip_status.h>
@ -124,7 +127,8 @@ typedef enum {
PFLAG_MULTIREG = (1 << 11), PFLAG_MULTIREG = (1 << 11),
PFLAG_SUPRESS_CNG = (1 << 12), PFLAG_SUPRESS_CNG = (1 << 12),
PFLAG_TLS = (1 << 13), PFLAG_TLS = (1 << 13),
PFLAG_CHECKUSER = (1 << 14) PFLAG_CHECKUSER = (1 << 14),
PFLAG_SECURE = (1 << 15)
} PFLAGS; } PFLAGS;
typedef enum { typedef enum {
@ -339,6 +343,13 @@ struct private_object {
char *invite_contact; char *invite_contact;
char *local_url; char *local_url;
char *gateway_name; char *gateway_name;
char *local_crypto_key;
char *remote_crypto_key;
unsigned char local_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
unsigned char remote_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
switch_rtp_crypto_key_type_t crypto_send_type;
switch_rtp_crypto_key_type_t crypto_recv_type;
switch_rtp_crypto_key_type_t crypto_type;
unsigned long rm_rate; unsigned long rm_rate;
switch_payload_t pt; switch_payload_t pt;
switch_mutex_t *flag_mutex; switch_mutex_t *flag_mutex;
@ -561,3 +572,4 @@ const char *sofia_glue_transport2str(const sofia_transport_t tp);
int sofia_glue_transport_has_tls(const sofia_transport_t tp); int sofia_glue_transport_has_tls(const sofia_transport_t tp);
const char *sofia_glue_get_unknown_header(sip_t const *sip, const char *name); const char *sofia_glue_get_unknown_header(sip_t const *sip, const char *name);
switch_status_t sofia_glue_build_crypto(private_object_t *tech_pvt, int index, switch_rtp_crypto_key_type_t type, switch_rtp_crypto_direction_t direction);

View File

@ -1010,6 +1010,10 @@ switch_status_t config_sofia(int reload, char *profile_name)
if (switch_true(val)) { if (switch_true(val)) {
profile->pflags |= PFLAG_PRESENCE; profile->pflags |= PFLAG_PRESENCE;
} }
} else if (!strcasecmp(var, "require-secure-rtp")) {
if (switch_true(val)) {
profile->pflags |= PFLAG_SECURE;
}
} else if (!strcasecmp(var, "multiple-registrations")) { } else if (!strcasecmp(var, "multiple-registrations")) {
if (switch_true(val)) { if (switch_true(val)) {
profile->pflags |= PFLAG_MULTIREG; profile->pflags |= PFLAG_MULTIREG;

View File

@ -89,6 +89,8 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32
"a=%s\n" "a=%s\n"
"m=audio %d RTP/AVP", tech_pvt->owner_id, tech_pvt->session_id, ip, ip, sr, port); "m=audio %d RTP/AVP", tech_pvt->owner_id, tech_pvt->session_id, ip, ip, sr, port);
if (tech_pvt->rm_encoding) { if (tech_pvt->rm_encoding) {
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->pt); switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->pt);
} else if (tech_pvt->num_codecs) { } else if (tech_pvt->num_codecs) {
@ -126,6 +128,7 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\n"); switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\n");
if (tech_pvt->rm_encoding) { if (tech_pvt->rm_encoding) {
rate = tech_pvt->rm_rate; rate = tech_pvt->rm_rate;
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", tech_pvt->pt, tech_pvt->rm_encoding, rate); switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", tech_pvt->pt, tech_pvt->rm_encoding, rate);
@ -181,6 +184,11 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=ptime:%d\n", ptime); switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=ptime:%d\n", ptime);
} }
if (!switch_strlen_zero(tech_pvt->local_crypto_key) && switch_test_flag(tech_pvt, TFLAG_SECURE)) {
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=crypto:%s\n", tech_pvt->local_crypto_key);
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=encryption:optional\n");
}
if (switch_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding) { if (switch_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding) {
sofia_glue_tech_choose_video_port(tech_pvt); sofia_glue_tech_choose_video_port(tech_pvt);
if ((v_port = tech_pvt->adv_sdp_video_port)) { if ((v_port = tech_pvt->adv_sdp_video_port)) {
@ -928,7 +936,7 @@ void sofia_glue_tech_absorb_sdp(private_object_t *tech_pvt)
void sofia_glue_deactivate_rtp(private_object_t *tech_pvt) void sofia_glue_deactivate_rtp(private_object_t *tech_pvt)
{ {
int loops = 0; //, sock = -1; int loops = 0;
if (switch_rtp_ready(tech_pvt->rtp_session)) { if (switch_rtp_ready(tech_pvt->rtp_session)) {
while (loops < 10 && (switch_test_flag(tech_pvt, TFLAG_READING) || switch_test_flag(tech_pvt, TFLAG_WRITING))) { while (loops < 10 && (switch_test_flag(tech_pvt, TFLAG_READING) || switch_test_flag(tech_pvt, TFLAG_WRITING))) {
switch_yield(10000); switch_yield(10000);
@ -1077,6 +1085,102 @@ switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force)
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
switch_status_t sofia_glue_build_crypto(private_object_t *tech_pvt, int index, switch_rtp_crypto_key_type_t type, switch_rtp_crypto_direction_t direction)
{
unsigned char b64_key[512] = "";
const char *type_str;
unsigned char *key;
char *p;
if (type == AES_CM_128_HMAC_SHA1_80) {
type_str = SWITCH_RTP_CRYPTO_KEY_80;
} else {
type_str = SWITCH_RTP_CRYPTO_KEY_32;
}
if (direction == SWITCH_RTP_CRYPTO_SEND) {
key = tech_pvt->local_raw_key;
} else {
key = tech_pvt->remote_raw_key;
}
switch_rtp_get_random(key, SWITCH_RTP_KEY_LEN);
switch_b64_encode(key, SWITCH_RTP_KEY_LEN, b64_key, sizeof(b64_key));
p = strrchr((char *)b64_key, '=');
while(p && *p && *p == '=') {
*p-- = '\0';
}
tech_pvt->local_crypto_key = switch_core_session_sprintf(tech_pvt->session, "%d %s inline:%s", index, type_str, b64_key);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set Local Key [%s]\n", tech_pvt->local_crypto_key);
tech_pvt->crypto_type = type;
return SWITCH_STATUS_SUCCESS;
}
switch_status_t sofia_glue_add_crypto(private_object_t *tech_pvt, const char *key_str, switch_rtp_crypto_direction_t direction)
{
unsigned char key[SWITCH_RTP_MAX_CRYPTO_LEN];
int index;
switch_rtp_crypto_key_type_t type;
char *p;
if (!switch_rtp_ready(tech_pvt->rtp_session)) {
goto bad;
}
index = atoi(key_str);
p = strchr(key_str, ' ');
if (p && *p && *(p+1)) {
p++;
if (!strncasecmp(p, SWITCH_RTP_CRYPTO_KEY_32, strlen(SWITCH_RTP_CRYPTO_KEY_32))) {
type = AES_CM_128_HMAC_SHA1_32;
} else if (!strncasecmp(p, SWITCH_RTP_CRYPTO_KEY_80, strlen(SWITCH_RTP_CRYPTO_KEY_80))) {
type = AES_CM_128_HMAC_SHA1_80;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error near [%s]\n", p);
goto bad;
}
p = strchr(p, ' ');
if (p && *p && *(p+1)) {
p++;
if (strncasecmp(p, "inline:", 7)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error near [%s]\n", p);
goto bad;
}
p += 7;
switch_b64_decode(p, (char *)key, sizeof(key));
if (direction == SWITCH_RTP_CRYPTO_SEND) {
tech_pvt->crypto_send_type = type;
memcpy(tech_pvt->local_raw_key, key, SWITCH_RTP_KEY_LEN);
} else {
tech_pvt->crypto_recv_type = type;
memcpy(tech_pvt->remote_raw_key, key, SWITCH_RTP_KEY_LEN);
}
return SWITCH_STATUS_SUCCESS;
}
}
bad:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error!\n");
return SWITCH_STATUS_FALSE;
}
switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_flag_t myflags) switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_flag_t myflags)
{ {
int bw, ms; int bw, ms;
@ -1175,7 +1279,9 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
tech_pvt->read_codec.implementation->samples_per_frame, tech_pvt->read_codec.implementation->samples_per_frame,
tech_pvt->codec_ms * 1000, tech_pvt->codec_ms * 1000,
(switch_rtp_flag_t) flags, (switch_rtp_flag_t) flags,
NULL, tech_pvt->profile->timer_name, &err, switch_core_session_get_pool(tech_pvt->session)); tech_pvt->profile->timer_name,
&err,
switch_core_session_get_pool(tech_pvt->session));
if (switch_rtp_ready(tech_pvt->rtp_session)) { if (switch_rtp_ready(tech_pvt->rtp_session)) {
uint8_t vad_in = switch_test_flag(tech_pvt, TFLAG_VAD_IN) ? 1 : 0; uint8_t vad_in = switch_test_flag(tech_pvt, TFLAG_VAD_IN) ? 1 : 0;
@ -1243,6 +1349,14 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt); switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
} }
if (tech_pvt->remote_crypto_key && switch_test_flag(tech_pvt, TFLAG_SECURE)) {
sofia_glue_add_crypto(tech_pvt, tech_pvt->remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, 1, tech_pvt->crypto_type, tech_pvt->local_raw_key, SWITCH_RTP_KEY_LEN);
switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_RECV, 1, tech_pvt->crypto_type, tech_pvt->remote_raw_key, SWITCH_RTP_KEY_LEN);
switch_channel_set_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_CONFIRMED_VARIABLE, "true");
}
sofia_glue_check_video_codecs(tech_pvt); sofia_glue_check_video_codecs(tech_pvt);
if (switch_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding) { if (switch_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding) {
@ -1258,8 +1372,8 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
0, 0,
(switch_rtp_flag_t) flags, (switch_rtp_flag_t) flags,
NULL, NULL,
NULL, &err,
&err, switch_core_session_get_pool(tech_pvt->session)); switch_core_session_get_pool(tech_pvt->session));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n", switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n",
switch_channel_get_name(tech_pvt->channel), switch_channel_get_name(tech_pvt->channel),
@ -1396,7 +1510,6 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
} }
if (stream) { if (stream) {
//switch_ivr_displace_session(tech_pvt->session, stream, 0, "rl");
switch_ivr_broadcast(switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE), stream, SMF_ECHO_ALEG | SMF_LOOP); switch_ivr_broadcast(switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE), stream, SMF_ECHO_ALEG | SMF_LOOP);
} }
} }
@ -1405,8 +1518,6 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
const char *uuid; const char *uuid;
switch_core_session_t *b_session; switch_core_session_t *b_session;
//const char *stream;
if (tech_pvt->max_missed_packets) { if (tech_pvt->max_missed_packets) {
switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets); switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets);
} }
@ -1418,14 +1529,6 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
switch_core_session_rwunlock(b_session); switch_core_session_rwunlock(b_session);
} }
//if (!(stream = switch_channel_get_variable(tech_pvt->channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
//stream = tech_pvt->profile->hold_music;
//}
//if (stream) {
//switch_ivr_stop_displace_session(tech_pvt->session, stream);
//}
switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
switch_channel_presence(tech_pvt->channel, "unknown", "unhold"); switch_channel_presence(tech_pvt->channel, "unknown", "unhold");
} }
@ -1444,6 +1547,24 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
ptime = atoi(a->a_value); ptime = atoi(a->a_value);
} else if (!strcasecmp(a->a_name, "crypto") && a->a_value) { } else if (!strcasecmp(a->a_name, "crypto") && a->a_value) {
crypto = a->a_value; crypto = a->a_value;
if (tech_pvt->remote_crypto_key) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Already have a key\n");
} else {
tech_pvt->remote_crypto_key = switch_core_session_strdup(tech_pvt->session, crypto);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set Remote Key [%s]\n", tech_pvt->remote_crypto_key);
if (switch_strlen_zero(tech_pvt->local_crypto_key)) {
if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_32, crypto)) {
switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_32);
sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND);
} else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_80, crypto)) {
switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_80);
sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Crypto Setup Failed!.\n");
}
}
}
} }
} }
@ -1461,7 +1582,6 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
greed: greed:
x = 0; x = 0;
//xxxxxx
if (tech_pvt->rm_encoding) { if (tech_pvt->rm_encoding) {
for (map = m->m_rtpmaps; map; map = map->rm_next) { for (map = m->m_rtpmaps; map; map = map->rm_next) {
if (map->rm_pt < 96) { if (map->rm_pt < 96) {
@ -1486,7 +1606,6 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
const char *rm_encoding; const char *rm_encoding;
if (x++ < skip) { if (x++ < skip) {
//printf("skip %s\n", map->rm_encoding);
continue; continue;
} }

View File

@ -43,14 +43,16 @@
#undef inline #undef inline
#include <datatypes.h> #include <datatypes.h>
#include <srtp.h> #include <srtp.h>
#include "stfu.h" #include "stfu.h"
#define MAX_KEY_LEN 64
#define rtp_header_len 12 #define rtp_header_len 12
#define RTP_START_PORT 16384 #define RTP_START_PORT 16384
#define RTP_END_PORT 32768 #define RTP_END_PORT 32768
#define MAX_KEY_LEN 64
#define MASTER_KEY_LEN 30 #define MASTER_KEY_LEN 30
#define RTP_MAGIC_NUMBER 42 #define RTP_MAGIC_NUMBER 42
#define MAX_SRTP_ERRS 10
static switch_port_t START_PORT = RTP_START_PORT; static switch_port_t START_PORT = RTP_START_PORT;
static switch_port_t END_PORT = RTP_END_PORT; static switch_port_t END_PORT = RTP_END_PORT;
@ -121,14 +123,19 @@ struct switch_rtp {
switch_sockaddr_t *local_addr; switch_sockaddr_t *local_addr;
rtp_msg_t send_msg; rtp_msg_t send_msg;
srtp_ctx_t *send_ctx;
switch_sockaddr_t *remote_addr; switch_sockaddr_t *remote_addr;
rtp_msg_t recv_msg; rtp_msg_t recv_msg;
srtp_ctx_t *recv_ctx;
uint32_t autoadj_window; uint32_t autoadj_window;
uint32_t autoadj_tally; uint32_t autoadj_tally;
srtp_ctx_t *send_ctx;
srtp_ctx_t *recv_ctx;
srtp_policy_t send_policy;
srtp_policy_t recv_policy;
uint32_t srtp_errs;
uint16_t seq; uint16_t seq;
uint32_t ssrc; uint32_t ssrc;
uint8_t sending_dtmf; uint8_t sending_dtmf;
@ -168,6 +175,7 @@ struct switch_rtp {
uint32_t max_missed_packets; uint32_t max_missed_packets;
uint32_t missed_count; uint32_t missed_count;
rtp_msg_t write_msg; rtp_msg_t write_msg;
switch_rtp_crypto_key_t *crypto_keys[SWITCH_RTP_CRYPTO_MAX];
}; };
static int global_init = 0; static int global_init = 0;
@ -277,6 +285,12 @@ SWITCH_DECLARE(void) switch_rtp_init(switch_memory_pool_t *pool)
global_init = 1; global_init = 1;
} }
SWITCH_DECLARE(void) switch_rtp_get_random(void *buf, uint32_t len)
{
crypto_get_random(buf, len);
}
SWITCH_DECLARE(void) switch_rtp_shutdown(void) SWITCH_DECLARE(void) switch_rtp_shutdown(void)
{ {
switch_core_hash_destroy(&alloc_hash); switch_core_hash_destroy(&alloc_hash);
@ -470,16 +484,89 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_session,
switch_rtp_crypto_direction_t direction,
uint32_t index,
switch_rtp_crypto_key_type_t type,
unsigned char *key,
switch_size_t keylen)
{
switch_rtp_crypto_key_t *crypto_key;
srtp_policy_t *policy;
err_status_t stat;
crypto_key = switch_core_alloc(rtp_session->pool, sizeof(*crypto_key));
policy = direction == SWITCH_RTP_CRYPTO_RECV ? &rtp_session->recv_policy : &rtp_session->send_policy;
crypto_key->type = type;
crypto_key->index = index;
memcpy(crypto_key->key, key, keylen);
crypto_key->next = rtp_session->crypto_keys[direction];
rtp_session->crypto_keys[direction] = crypto_key;
memset(policy, 0, sizeof(*policy));
switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_SECURE);
switch(crypto_key->type) {
case AES_CM_128_HMAC_SHA1_80:
crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy->rtp);
break;
case AES_CM_128_HMAC_SHA1_32:
crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy->rtp);
break;
default:
break;
}
policy->next = NULL;
policy->key = (uint8_t *) crypto_key->key;
crypto_policy_set_rtcp_default(&policy->rtcp);
policy->rtcp.sec_serv = sec_serv_none;
policy->rtp.sec_serv = sec_serv_conf_and_auth;
switch(direction) {
case SWITCH_RTP_CRYPTO_RECV:
policy->ssrc.type = ssrc_any_inbound;
if ((stat = srtp_create(&rtp_session->recv_ctx, policy))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocating srtp [%d]\n", stat);
return SWITCH_STATUS_FALSE;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Activating Secure RTP RECV\n");
break;
case SWITCH_RTP_CRYPTO_SEND:
policy->ssrc.type = ssrc_specific;
policy->ssrc.value = rtp_session->ssrc;
if ((stat = srtp_create(&rtp_session->send_ctx, policy))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocating srtp [%d]\n", stat);
return SWITCH_STATUS_FALSE;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Activating Secure RTP SEND\n");
break;
default:
abort();
break;
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session, SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session,
switch_payload_t payload, switch_payload_t payload,
uint32_t samples_per_interval, uint32_t samples_per_interval,
uint32_t ms_per_packet, uint32_t ms_per_packet,
switch_rtp_flag_t flags, char *crypto_key, char *timer_name, const char **err, switch_rtp_flag_t flags,
char *timer_name,
const char **err,
switch_memory_pool_t *pool) switch_memory_pool_t *pool)
{ {
switch_rtp_t *rtp_session = NULL; switch_rtp_t *rtp_session = NULL;
srtp_policy_t policy;
char key[MAX_KEY_LEN];
uint32_t ssrc = rand() & 0xffff; uint32_t ssrc = rand() & 0xffff;
*new_rtp_session = NULL; *new_rtp_session = NULL;
@ -507,44 +594,10 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
/* for from address on recvfrom calls */ /* for from address on recvfrom calls */
switch_sockaddr_info_get(&rtp_session->from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool); switch_sockaddr_info_get(&rtp_session->from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool);
memset(&policy, 0, sizeof(policy));
if (crypto_key) {
int len;
switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_SECURE);
crypto_policy_set_rtp_default(&policy.rtp);
crypto_policy_set_rtcp_default(&policy.rtcp);
policy.ssrc.type = ssrc_any_inbound;
policy.ssrc.value = ssrc;
policy.key = (uint8_t *) key;
policy.next = NULL;
policy.rtp.sec_serv = sec_serv_conf_and_auth;
policy.rtcp.sec_serv = sec_serv_none;
/* read key from hexadecimal on command line into an octet string */
len = hex_string_to_octet_string(key, crypto_key, MASTER_KEY_LEN * 2);
/* check that hex string is the right length */
if (len < MASTER_KEY_LEN * 2) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"error: too few digits in key/salt " "(should be %d hexadecimal digits, found %d)\n", MASTER_KEY_LEN * 2, len);
*err = "Crypt Error";
return SWITCH_STATUS_FALSE;
}
if (strlen(crypto_key) > MASTER_KEY_LEN * 2) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"error: too many digits in key/salt "
"(should be %d hexadecimal digits, found %u)\n", MASTER_KEY_LEN * 2, (unsigned) strlen(crypto_key));
*err = "Crypt Error";
return SWITCH_STATUS_FALSE;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Activating Secure RTP!\n");
}
rtp_session->seq = (uint16_t) rand(); rtp_session->seq = (uint16_t) rand();
rtp_session->ssrc = ssrc; rtp_session->ssrc = ssrc;
rtp_session->send_msg.header.ssrc = htonl(ssrc); rtp_session->send_msg.header.ssrc = htonl(rtp_session->ssrc);
rtp_session->send_msg.header.ts = 0; rtp_session->send_msg.header.ts = 0;
rtp_session->send_msg.header.m = 0; rtp_session->send_msg.header.m = 0;
rtp_session->send_msg.header.pt = (switch_payload_t) htonl(payload); rtp_session->send_msg.header.pt = (switch_payload_t) htonl(payload);
@ -553,7 +606,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
rtp_session->send_msg.header.x = 0; rtp_session->send_msg.header.x = 0;
rtp_session->send_msg.header.cc = 0; rtp_session->send_msg.header.cc = 0;
rtp_session->recv_msg.header.ssrc = htonl(ssrc); rtp_session->recv_msg.header.ssrc = 0;
rtp_session->recv_msg.header.ts = 0; rtp_session->recv_msg.header.ts = 0;
rtp_session->recv_msg.header.seq = 0; rtp_session->recv_msg.header.seq = 0;
rtp_session->recv_msg.header.m = 0; rtp_session->recv_msg.header.m = 0;
@ -568,20 +621,6 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
rtp_session->samples_per_interval = rtp_session->conf_samples_per_interval = samples_per_interval; rtp_session->samples_per_interval = rtp_session->conf_samples_per_interval = samples_per_interval;
rtp_session->timer_name = switch_core_strdup(pool, timer_name); rtp_session->timer_name = switch_core_strdup(pool, timer_name);
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE)) {
err_status_t stat;
if ((stat = srtp_create(&rtp_session->recv_ctx, &policy))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocating srtp [%d]\n", stat);
*err = "Crypt Error";
return SWITCH_STATUS_FALSE;
}
if ((stat = srtp_create(&rtp_session->send_ctx, &policy))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocating srtp [%d]\n", stat);
*err = "Crypt Error";
return SWITCH_STATUS_FALSE;
}
}
if (!switch_strlen_zero(timer_name)) { if (!switch_strlen_zero(timer_name)) {
switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_USE_TIMER); switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
@ -615,11 +654,14 @@ SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host,
switch_payload_t payload, switch_payload_t payload,
uint32_t samples_per_interval, uint32_t samples_per_interval,
uint32_t ms_per_packet, uint32_t ms_per_packet,
switch_rtp_flag_t flags, char *crypto_key, char *timer_name, const char **err, switch_memory_pool_t *pool) switch_rtp_flag_t flags,
char *timer_name,
const char **err,
switch_memory_pool_t *pool)
{ {
switch_rtp_t *rtp_session = NULL; switch_rtp_t *rtp_session = NULL;
if (switch_rtp_create(&rtp_session, payload, samples_per_interval, ms_per_packet, flags, crypto_key, timer_name, err, pool) != SWITCH_STATUS_SUCCESS) { if (switch_rtp_create(&rtp_session, payload, samples_per_interval, ms_per_packet, flags, timer_name, err, pool) != SWITCH_STATUS_SUCCESS) {
goto end; goto end;
} }
@ -928,6 +970,29 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
return -1; return -1;
} }
if (bytes && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE)) {
int sbytes = (int) bytes;
err_status_t stat;
stat = srtp_unprotect(rtp_session->recv_ctx, &rtp_session->recv_msg.header, &sbytes);
if (stat && rtp_session->recv_msg.header.pt != rtp_session->te && rtp_session->recv_msg.header.pt != rtp_session->cng_pt) {
if (++rtp_session->srtp_errs >= MAX_SRTP_ERRS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"error: srtp unprotection failed with code %d%s\n", stat,
stat == err_status_replay_fail ? " (replay check failed)" : stat == err_status_auth_fail ? " (auth check failed)" : "");
return -1;
} else {
sbytes = 0;
}
} else {
rtp_session->srtp_errs = 0;
}
bytes = sbytes;
}
if (rtp_session->jb && bytes && rtp_session->recv_msg.header.pt == rtp_session->payload) { if (rtp_session->jb && bytes && rtp_session->recv_msg.header.pt == rtp_session->payload) {
if (rtp_session->recv_msg.header.m) { if (rtp_session->recv_msg.header.m) {
stfu_n_reset(rtp_session->jb); stfu_n_reset(rtp_session->jb);
@ -1028,20 +1093,6 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
return 2 + rtp_header_len; return 2 + rtp_header_len;
} }
if (bytes && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE)) {
int sbytes = (int) bytes;
err_status_t stat;
stat = srtp_unprotect(rtp_session->recv_ctx, &rtp_session->recv_msg.header, &sbytes);
if (stat) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"error: srtp unprotection failed with code %d%s\n", stat,
stat == err_status_replay_fail ? " (replay check failed)" : stat == err_status_auth_fail ? " (auth check failed)" : "");
return -1;
}
bytes = sbytes;
}
if (bytes > 0) { if (bytes > 0) {
rtp_session->missed_count = 0; rtp_session->missed_count = 0;
} }
@ -1356,7 +1407,6 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
if (flags && *flags & SFF_RFC2833) { if (flags && *flags & SFF_RFC2833) {
send_msg->header.pt = rtp_session->te; send_msg->header.pt = rtp_session->te;
} }
send_msg->header.ssrc = htonl(rtp_session->ssrc);
} else { } else {
uint8_t m = 0; uint8_t m = 0;
@ -1392,17 +1442,7 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
bytes = datalen + rtp_header_len; bytes = datalen + rtp_header_len;
} }
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE)) { send_msg->header.ssrc = htonl(rtp_session->ssrc);
int sbytes = (int) bytes;
err_status_t stat;
stat = srtp_protect(rtp_session->send_ctx, &send_msg->header, &sbytes);
if (stat) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error: srtp protection failed with code %d\n", stat);
}
bytes = sbytes;
}
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_GOOGLEHACK) && rtp_session->send_msg.header.pt == 97) { if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_GOOGLEHACK) && rtp_session->send_msg.header.pt == 97) {
rtp_session->recv_msg.header.pt = 102; rtp_session->recv_msg.header.pt = 102;
@ -1517,6 +1557,19 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
if (send) { if (send) {
send_msg->header.seq = htons(++rtp_session->seq); send_msg->header.seq = htons(++rtp_session->seq);
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE)) {
int sbytes = (int) bytes;
err_status_t stat;
stat = srtp_protect(rtp_session->send_ctx, &send_msg->header, &sbytes);
if (stat) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error: srtp protection failed with code %d\n", stat);
}
bytes = sbytes;
}
if (switch_socket_sendto(rtp_session->sock, rtp_session->remote_addr, 0, (void *) send_msg, &bytes) != SWITCH_STATUS_SUCCESS) { if (switch_socket_sendto(rtp_session->sock, rtp_session->remote_addr, 0, (void *) send_msg, &bytes) != SWITCH_STATUS_SUCCESS) {
rtp_session->seq--; rtp_session->seq--;
return -1; return -1;

View File

@ -166,7 +166,7 @@ SWITCH_DECLARE(switch_status_t) switch_b64_encode(unsigned char *in, switch_size
} }
SWITCH_DECLARE(switch_status_t) switch_b64_decode(char *in, char *out, switch_size_t olen) SWITCH_DECLARE(switch_size_t) switch_b64_decode(char *in, char *out, switch_size_t olen)
{ {
char l64[256]; char l64[256];
@ -203,7 +203,7 @@ SWITCH_DECLARE(switch_status_t) switch_b64_decode(char *in, char *out, switch_si
op[ol++] = '\0'; op[ol++] = '\0';
return SWITCH_STATUS_SUCCESS; return ol;
} }