diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 844013361e..d566434457 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -403,6 +403,7 @@ SWITCH_DECLARE(void) switch_channel_clear_flag_recursive(switch_channel_t *chann SWITCH_DECLARE(switch_status_t) switch_channel_perform_answer(switch_channel_t *channel, const char *file, const char *func, int line); SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_answered(switch_channel_t *channel, const char *file, const char *func, int line); +SWITCH_DECLARE(void) switch_channel_check_zrtp(switch_channel_t *channel); /*! \brief Answer a channel (initiate/acknowledge a successful connection) diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 004b67c727..87577caae1 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1208,6 +1208,8 @@ typedef enum { CF_VIDEO_REFRESH_REQ, CF_SERVICE_AUDIO, CF_SERVICE_VIDEO, + CF_ZRTP_HASH, + CF_ZRTP_PASS, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ /* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */ CF_FLAG_MAX diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 21172b5f90..cfcebdab01 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -2568,6 +2568,8 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } } + switch_channel_check_zrtp(tech_pvt->channel); + if ((status = sofia_glue_tech_choose_port(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); goto end_lock; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 789bad0da8..bedafc2e5e 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -6270,6 +6270,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, sofia_set_flag_locked(tech_pvt, TFLAG_ANS); if (match) { + switch_channel_check_zrtp(channel); + if (sofia_glue_tech_choose_port(tech_pvt, 0) == SWITCH_STATUS_SUCCESS) { if (sofia_glue_activate_rtp(tech_pvt, 0) == SWITCH_STATUS_SUCCESS) { switch_channel_mark_answered(channel); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index b66288ecfb..72267d7ea4 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -184,7 +184,8 @@ static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen, int rate; int already_did[128] = { 0 }; int ptime = 0, noptime = 0; - + const char *zrtp; + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "m=audio %d RTP/%sAVP", port, secure ? "S" : ""); @@ -343,6 +344,10 @@ static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen, switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=ptime:%d\n", cur_ptime); } + if ((zrtp = switch_channel_get_variable(tech_pvt->channel, "sdp_zrtp_hash_string"))) { + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=zrtp-hash:%s\n", zrtp); + } + if (sr) { switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=%s\n", sr); } @@ -386,6 +391,7 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch switch_event_t *map = NULL, *ptmap = NULL; const char *b_sdp = NULL; int verbose_sdp = 0; + const char *zrtp; sofia_glue_check_dtmf_type(tech_pvt); @@ -539,6 +545,10 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=ptime:%d\n", ptime); } + if ((zrtp = switch_channel_get_variable(tech_pvt->channel, "sdp_zrtp_hash_string"))) { + switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=zrtp-hash:%s\n", zrtp); + } + if (sr) { switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=%s\n", sr); } @@ -3552,6 +3562,14 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip); switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp); + + if (switch_channel_test_flag(tech_pvt->channel, CF_ZRTP_PASS)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_INFO, "Activating ZRTP PROXY MODE\n"); + sofia_clear_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE); + switch_rtp_udptl_mode(tech_pvt->rtp_session); + } + + video: sofia_glue_check_video_codecs(tech_pvt); @@ -4657,12 +4675,13 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) { switch_channel_set_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port", attr->a_value); - } - - if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) { + } else if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) { ptime = atoi(attr->a_value); } else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) { maxptime = atoi(attr->a_value); + } else if (!strcasecmp(attr->a_name, "zrtp-hash") && attr->a_value) { + switch_channel_set_variable(tech_pvt->channel, "sdp_zrtp_hash_string", attr->a_value); + switch_channel_set_flag(tech_pvt->channel, CF_ZRTP_HASH); } else if (!got_crypto && !strcasecmp(attr->a_name, "crypto") && !zstr(attr->a_value)) { int crypto_tag; diff --git a/src/switch_channel.c b/src/switch_channel.c index 2e6ccf7ffd..58f72e504d 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -2918,6 +2918,58 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_ring_ready_value(swi return SWITCH_STATUS_FALSE; } +SWITCH_DECLARE(void) switch_channel_check_zrtp(switch_channel_t *channel) +{ + + if (switch_channel_test_flag(channel, CF_ZRTP_HASH) && !switch_channel_test_flag(channel, CF_ZRTP_PASS)) { + switch_core_session_t *other_session; + switch_channel_t *other_channel; + int doit = 1; + + if (switch_core_session_get_partner(channel->session, &other_session) == SWITCH_STATUS_SUCCESS) { + other_channel = switch_core_session_get_channel(other_session); + + if (switch_channel_test_flag(other_channel, CF_ZRTP_HASH) && !switch_channel_test_flag(other_channel, CF_ZRTP_PASS)) { + + switch_channel_set_flag(channel, CF_ZRTP_PASS); + switch_channel_set_flag(other_channel, CF_ZRTP_PASS); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(channel->session), SWITCH_LOG_INFO, + "%s Activating ZRTP passthru mode.\n", switch_channel_get_name(channel)); + + switch_channel_set_variable(channel, "zrtp_secure_media", "false"); + switch_channel_set_variable(other_channel, "zrtp_secure_media", "false"); + doit = 0; + } + + switch_core_session_rwunlock(other_session); + } + + if (doit) { + switch_channel_set_variable(channel, "zrtp_secure_media", "true"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(channel->session), SWITCH_LOG_INFO, + "%s ZRTP not negotiated on both sides, Activating ZRTP man-in-the-middle mode.\n", switch_channel_get_name(channel)); + + switch_channel_clear_flag(channel, CF_ZRTP_PASS); + switch_channel_clear_flag(channel, CF_ZRTP_HASH); + + if (switch_core_session_get_partner(channel->session, &other_session) == SWITCH_STATUS_SUCCESS) { + other_channel = switch_core_session_get_channel(other_session); + + switch_channel_set_variable(other_channel, "zrtp_secure_media", "true"); + switch_channel_clear_flag(other_channel, CF_ZRTP_PASS); + switch_channel_clear_flag(other_channel, CF_ZRTP_HASH); + + switch_core_session_rwunlock(other_session); + } + + } + } +} + + + + SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_pre_answered(switch_channel_t *channel, const char *file, const char *func, int line) { switch_event_t *event; @@ -2927,6 +2979,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_pre_answered(switch_ const char *uuid; switch_core_session_t *other_session; + switch_channel_check_zrtp(channel); switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_channel_get_uuid(channel), SWITCH_LOG_NOTICE, "Pre-Answer %s!\n", channel->name); switch_channel_set_flag(channel, CF_EARLY_MEDIA); switch_channel_set_callstate(channel, CCS_EARLY); @@ -3186,6 +3239,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_answered(switch_chan switch_mutex_unlock(channel->profile_mutex); } + switch_channel_check_zrtp(channel); switch_channel_set_flag(channel, CF_ANSWERED); switch_channel_set_callstate(channel, CCS_ACTIVE); @@ -3265,6 +3319,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_answer(switch_channel_t * return SWITCH_STATUS_SUCCESS; } + msg.message_id = SWITCH_MESSAGE_INDICATE_ANSWER; msg.from = channel->name; status = switch_core_session_perform_receive_message(channel->session, &msg, file, func, line);