[Freeswitch-dev] Freeswitch support for generating an SRTP offer from an incoming 3PCC INVITE?

Guy Mesika guy032 at gmail.com
Thu Apr 30 12:37:10 UTC 2020


I'm using Freeswitch ESL (Event Socket Library) in Node.js When I receive
an invite to SIP.js from a classic sip endpoint the SDP content is regular
RTP. I need to be able to connect RTP endpoint to SRTP endpoint using
Freeswitch in the middle. In order to do so we need to be able create an
endpoint on Freeswitch without SDP (3PCC INVITE) but we want this endpoint
to return SRTP SDP and not RTP SDP.

*Main question: Does Freeswitch supports generating SRTP offer from an
incoming 3PCC INVITE?*

I believe this is the part to handle 3PCC INVITE in Freeswitch 1.8.5:
https://github.com/signalwire/freeswitch/blob/v1.8.5/src/mod/endpoints/mod_sofia/sofia.c

if (sofia_test_pflag(profile, PFLAG_3PCC)) {
    if (switch_channel_test_flag(channel, CF_PROXY_MODE) ||
switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
SWITCH_LOG_INFO, "No SDP in INVITE and 3pcc=yes cannot work with
bypass or proxy media, hanging up.\n");
        switch_channel_set_variable(channel,
SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "3PCC DISABLED");
        switch_channel_hangup(channel, SWITCH_CAUSE_MANDATORY_IE_MISSING);
    } else {
        switch_channel_set_variable(channel,
SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP");
        switch_core_media_choose_port(tech_pvt->session,
SWITCH_MEDIA_TYPE_AUDIO, 0);
        switch_core_media_prepare_codecs(session, 1);
        switch_channel_set_state(channel, CS_HIBERNATE);
        switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST,
NULL, 0, NULL, 0);
        sofia_set_flag_locked(tech_pvt, TFLAG_3PCC);

        if (sofia_use_soa(tech_pvt)) {
            nua_respond(tech_pvt->nh, SIP_200_OK,
                        SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
                        SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
                        SOATAG_REUSE_REJECTED(1),
                        SOATAG_AUDIO_AUX("cn telephone-event"),
                        TAG_IF(sofia_test_pflag(profile,
PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END());
        } else {
            nua_respond(tech_pvt->nh, SIP_200_OK,
                        NUTAG_MEDIA_ENABLE(0),
                        SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
                        SIPTAG_CONTENT_TYPE_STR("application/sdp"),
SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END());
        }
    }}

Maybe the same pattern they used for mod_verto can be used:
https://github.com/signalwire/freeswitch/blob/v1.8.5/src/mod/endpoints/mod_verto/mod_verto.c

This function *switch_core_media_gen_local_sdp* seems to be the one to
create the RTP SDP:
https://github.com/signalwire/freeswitch/blob/v1.8.5/src/switch_core_media.c
How
can we change this to SRTP SDP instead?

static const char *get_media_profile_name(switch_core_session_t
*session, int secure){
    switch_assert(session);

    if (switch_channel_test_flag(session->channel, CF_AVPF)) {
        if (switch_channel_test_flag(session->channel, CF_DTLS) || secure) {
            if (switch_channel_test_flag(session->channel, CF_AVPF_MOZ)) {
                return "UDP/TLS/RTP/SAVPF";
            } else {
                return "RTP/SAVPF";
            }
        } else {
            if (switch_channel_test_flag(session->channel, CF_AVPF_MOZ)) {
                return "UDP/AVPF";
            } else {
                return "RTP/AVPF";
            }
        }
    }

    if (secure) {
        return "RTP/SAVP";
    }

    return "RTP/AVP";
}

There are 3 conditions to enable SRTP:

session->channel->flags['CF_AVPF'](session->channel->flags['CF_DTLS'] || secure)
session->channel->flags['CF_AVPF_MOZ']

The conditions to put *CF_AVPF* flag are calling
*switch_core_session_set_ice* or:

if (is_outbound || switch_channel_test_flag(session->channel, CF_RECOVERING) ||
    switch_channel_test_flag(session->channel, CF_3PCC)) {
    if (!switch_channel_test_flag(session->channel, CF_AVPF) &&
        switch_true(switch_channel_get_variable(session->channel,
"media_webrtc"))) {
        switch_channel_set_flag(session->channel, CF_AVPF);
        switch_channel_set_flag(session->channel, CF_ICE);
        smh->mparams->rtcp_audio_interval_msec =
SWITCH_RTCP_AUDIO_INTERVAL_MSEC;
        smh->mparams->rtcp_video_interval_msec =
SWITCH_RTCP_VIDEO_INTERVAL_MSEC;
    }

    if (switch_true(switch_channel_get_variable(session->channel,
"add_ice_candidates"))) {
        switch_channel_set_flag(session->channel, CF_ICE);
    }

    if ( switch_rtp_has_dtls() && dtls_ok(session)) {
        if (switch_channel_test_flag(session->channel, CF_AVPF) ||
            switch_true(switch_channel_get_variable(smh->session->channel,
"rtp_use_dtls"))) {
            switch_channel_set_flag(smh->session->channel, CF_DTLS);
            switch_channel_set_flag(smh->session->channel, CF_SECURE);
            generate_local_fingerprint(smh, SWITCH_MEDIA_TYPE_AUDIO);
        }
    }
    switch_core_session_parse_crypto_prefs(session);
    switch_core_session_check_outgoing_crypto(session);}

The conditions to put *CF_DTLS* flag are the same as above (*CF_AVPF*) or
calling *check_ice*:

if (switch_rtp_has_dtls() && dtls_ok(smh->session) &&
!strcasecmp(attr->a_name, "fingerprint") && !zstr(attr->a_value)) {
    char *p;

    engine->remote_dtls_fingerprint.type =
switch_core_session_strdup(smh->session, attr->a_value);

    if ((p = strchr(engine->remote_dtls_fingerprint.type, ' '))) {
        *p++ = '\0';

        if (switch_channel_test_flag(smh->session->channel,
CF_REINVITE) && !switch_channel_test_flag(smh->session->channel,
CF_RECOVERING) &&
            !zstr(engine->remote_dtls_fingerprint.str) &&
!strcmp(engine->remote_dtls_fingerprint.str, p)) {
            engine->new_dtls = 0;
        } else {
            switch_set_string(engine->remote_dtls_fingerprint.str, p);
            engine->new_dtls = 1;
            engine->new_ice = 1;
        }
    }

    generate_local_fingerprint(smh, type);
    switch_channel_set_flag(smh->session->channel, CF_DTLS);
}

There is also the possibility to send true for the *secure* parameter but
the conditions are many.

The conditions to put *CF_AVPF_MOZ* flag:

if (m->m_proto_name && !strcasecmp(m->m_proto_name, "UDP/TLS/RTP/SAVPF")) {
    switch_channel_set_flag(session->channel, CF_AVPF_MOZ);}
if (m->m_proto_name && !strcasecmp(m->m_proto_name, "UDP/RTP/AVPF")) {
    switch_channel_set_flag(session->channel, CF_AVPF_MOZ);}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freeswitch.org/pipermail/freeswitch-dev/attachments/20200430/d6841fe7/attachment-0001.html>


More information about the FreeSWITCH-dev mailing list