From 585dac068290d9281c0a49f324c566a22323adea Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 22 Jul 2020 14:34:00 -0500 Subject: [PATCH] Apply patch from eta https://theta.eu.org/lx/asterisk.patch --- channels/chan_motif.c | 152 +++++++++++++++++++++++++++++++++++++++--- res/res_xmpp.c | 6 +- 2 files changed, 148 insertions(+), 10 deletions(-) diff --git a/channels/chan_motif.c b/channels/chan_motif.c index a9dd2af..2691d61 100644 --- a/channels/chan_motif.c +++ b/channels/chan_motif.c @@ -258,6 +258,8 @@ /*! \brief Namespace for XMPP stanzas */ #define XMPP_STANZAS_NS "urn:ietf:params:xml:ns:xmpp-stanzas" +#define DTLS_NS "urn:xmpp:jingle:apps:dtls:0" + /*! \brief The various transport methods supported, from highest priority to lowest priority when doing fallback */ enum jingle_transport { JINGLE_TRANSPORT_ICE_UDP = 3, /*!< XEP-0176 */ @@ -686,7 +688,7 @@ static void jingle_enable_video(struct jingle_session *session) return; } - ast_rtp_instance_set_prop(session->vrtp, AST_RTP_PROPERTY_RTCP, 1); + ast_rtp_instance_set_prop(session->vrtp, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_MUX); ast_rtp_instance_set_channel_id(session->vrtp, ast_channel_uniqueid(session->owner)); ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0)); ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1)); @@ -697,6 +699,8 @@ static void jingle_enable_video(struct jingle_session *session) } } +static struct ast_rtp_dtls_cfg dtls_cfg; + /*! \brief Internal helper function used to allocate Jingle session on an endpoint */ static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid) { @@ -755,9 +759,35 @@ static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, con ao2_ref(session, -1); return NULL; } + ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_RTCP, 1); ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_DTMF, 1); + struct ast_rtp_engine_dtls *dtls; + + if ((dtls = ast_rtp_instance_get_dtls(session->rtp))) { + dtls_cfg.enabled = 1; + dtls_cfg.default_setup = AST_RTP_DTLS_SETUP_ACTPASS; + dtls_cfg.hash = AST_RTP_DTLS_HASH_SHA256; + dtls_cfg.verify = AST_RTP_DTLS_VERIFY_FINGERPRINT; + dtls_cfg.suite = AST_AES_CM_128_HMAC_SHA1_80; + dtls_cfg.ephemeral_cert = 1; + dtls_cfg.certfile = ast_strdup(""); + dtls_cfg.pvtfile = ast_strdup(""); + dtls_cfg.cipher = ast_strdup(""); + dtls_cfg.cafile = ast_strdup(""); + dtls_cfg.capath = ast_strdup(""); + + if (dtls->set_configuration(session->rtp, &dtls_cfg)) { + ast_log(LOG_ERROR, "Attempted to set an invalid DTLS-SRTP configuration on RTP instance '%p'\n", + session->rtp); + } + } + else { + ast_log(LOG_ERROR, "No DTLS-SRTP support present on engine for RTP instance '%p', was it compiled with support for it?\n", + session->rtp); + } + session->maxicecandidates = endpoint->maxicecandidates; session->maxpayloads = endpoint->maxpayloads; @@ -914,6 +944,49 @@ end: iks_delete(response); } +static void jingle_add_fingerprint(struct ast_rtp_instance *rtp, iks *transport) { + struct ast_rtp_engine_dtls *dtls; + if ((dtls = ast_rtp_instance_get_dtls(rtp)) || dtls->active(rtp)) { + // Add the DTLS fingerprint in there as well + iks *fingerprint_node = NULL; + const char *fingerprint; + if (!(fingerprint_node = iks_new("fingerprint"))) { + ast_log(LOG_ERROR, "Failed to allocate stanzas for DTLS"); + return; + } + iks_insert_attrib(fingerprint_node, "xmlns", DTLS_NS); + switch (dtls->get_setup(rtp)) { + case AST_RTP_DTLS_SETUP_ACTIVE: + iks_insert_attrib(fingerprint_node, "setup", "active"); + break; + case AST_RTP_DTLS_SETUP_PASSIVE: + iks_insert_attrib(fingerprint_node, "setup", "passive"); + break; + case AST_RTP_DTLS_SETUP_ACTPASS: + iks_insert_attrib(fingerprint_node, "setup", "actpass"); + break; + case AST_RTP_DTLS_SETUP_HOLDCONN: + iks_insert_attrib(fingerprint_node, "setup", "holdconn"); + break; + default: + break; + } + switch (dtls->get_fingerprint_hash(rtp)) { + case AST_RTP_DTLS_HASH_SHA1: + iks_insert_attrib(fingerprint_node, "hash", "sha-1"); + break; + case AST_RTP_DTLS_HASH_SHA256: + iks_insert_attrib(fingerprint_node, "hash", "sha-256"); + break; + default: + break; + } + fingerprint = dtls->get_fingerprint(rtp); + iks_insert_cdata(fingerprint_node, fingerprint, strlen(fingerprint)); + iks_insert_node(transport, fingerprint_node); + } +} + /*! \brief Internal helper function which adds ICE-UDP candidates to a transport node */ static int jingle_add_ice_udp_candidates_to_transport(struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int maximum) { @@ -929,6 +1002,7 @@ static int jingle_add_ice_udp_candidates_to_transport(struct ast_rtp_instance *r } iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS); + jingle_add_fingerprint(rtp, transport); iks_insert_attrib(transport, "pwd", ice->get_password(rtp)); iks_insert_attrib(transport, "ufrag", ice->get_ufrag(rtp)); @@ -967,7 +1041,9 @@ static int jingle_add_ice_udp_candidates_to_transport(struct ast_rtp_instance *r } iks_insert_node(transport, local_candidate); - candidates[i++] = local_candidate; + if (candidates != NULL) { + candidates[i++] = local_candidate; + } } ao2_iterator_destroy(&it); @@ -1208,7 +1284,7 @@ static void jingle_queue_hangup_with_cause(struct jingle_session *session, int c } /*! \brief Internal function which sends a transport-info message */ -static void jingle_send_transport_info(struct jingle_session *session, const char *from) +static void jingle_send_transport_info(struct jingle_session *session, const char *from, int actually_initiate) { iks *iq, *jingle = NULL, *audio = NULL, *audio_transport = NULL, *video = NULL, *video_transport = NULL; iks *audio_candidates[session->maxicecandidates], *video_candidates[session->maxicecandidates]; @@ -1237,7 +1313,7 @@ static void jingle_send_transport_info(struct jingle_session *session, const cha iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS); iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : from); } else { - iks_insert_attrib(jingle, "action", "transport-info"); + iks_insert_attrib(jingle, "action", actually_initiate == 1 ? "session-initiate" : "transport-info"); iks_insert_attrib(jingle, "sid", session->sid); iks_insert_attrib(jingle, "xmlns", JINGLE_NS); } @@ -1384,6 +1460,10 @@ static int jingle_add_payloads_to_description(struct jingle_session *session, st payloads[i++] = payload; } } + iks *rtcp_mux = iks_new("rtcp-mux"); + if (rtcp_mux) { + iks_insert_node(description, rtcp_mux); + } return res; } @@ -1416,6 +1496,8 @@ static int jingle_add_content(struct jingle_session *session, iks *jingle, iks * if (!(res = jingle_add_payloads_to_description(session, rtp, description, payloads, type))) { if (session->transport == JINGLE_TRANSPORT_ICE_UDP) { iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS); + jingle_add_ice_udp_candidates_to_transport(rtp, transport, NULL, session->maxicecandidates); + jingle_add_fingerprint(rtp, transport); iks_insert_node(content, transport); } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) { iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS); @@ -1543,7 +1625,7 @@ static int jingle_outgoing_hook(void *data, ikspak *pak) } ao2_unlock(session); - jingle_send_transport_info(session, iks_find_attrib(pak->x, "from")); + jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"), 0); goto end; } @@ -2084,8 +2166,19 @@ static int jingle_interpret_description(struct jingle_session *session, iks *des return -1; } + struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(session->rtp); /* Iterate the codecs updating the relevant RTP instance as we go */ for (codec = iks_child(description); codec; codec = iks_next(codec)) { + if (strcasecmp(iks_name(codec), "rtcp-mux") == 0) { + if (ice) { + ast_log(LOG_NOTICE, "Enabling RTCP MUX for session '%s'\n", session->sid); + ice->change_components(session->rtp, 1); + } + else { + ast_log(LOG_ERROR, "Could not enable RTCP MUX for session '%s' as ICE not available\n", session->sid); + } + continue; + } char *id = iks_find_attrib(codec, "id"), *name = iks_find_attrib(codec, "name"); char *clockrate = iks_find_attrib(codec, "clockrate"); int rtp_id, rtp_clockrate; @@ -2131,10 +2224,53 @@ static int jingle_interpret_ice_udp_transport(struct jingle_session *session, ik if (!ast_strlen_zero(ufrag) && !ast_strlen_zero(pwd)) { ice->set_authentication(rtp, ufrag, pwd); } + iks *fingerprint_node; + if ((fingerprint_node = iks_find_with_attrib(transport, "transport", "xmlns", DTLS_NS))) { + char *dtls_hash, *dtls_fingerprint, *dtls_setup; + dtls_hash = iks_find_attrib(fingerprint_node, "hash"); + dtls_fingerprint = iks_cdata(fingerprint_node); + dtls_setup = iks_find_attrib(fingerprint_node, "setup"); + if (!ast_strlen_zero(dtls_hash) && !ast_strlen_zero(dtls_fingerprint) && !ast_strlen_zero(dtls_setup)) { + struct ast_rtp_engine_dtls *dtls; + if ((dtls = ast_rtp_instance_get_dtls(rtp))) { + ast_log(LOG_NOTICE, "Received DTLS information on session '%s' (hash %s): %s\n", session->sid, dtls_hash, dtls_fingerprint); + if (!strcasecmp(dtls_hash, "sha-1")) { + dtls->set_fingerprint(rtp, AST_RTP_DTLS_HASH_SHA1, dtls_fingerprint); + } else if (!strcasecmp(dtls_hash, "sha-256")) { + dtls->set_fingerprint(rtp, AST_RTP_DTLS_HASH_SHA256, dtls_fingerprint); + } else { + ast_log(LOG_WARNING, "Unsupported fingerprint hash type '%s' received for session '%s'\n", + dtls_hash, session->sid); + } + if (!strcasecmp(dtls_setup, "active")) { + dtls->set_setup(rtp, AST_RTP_DTLS_SETUP_ACTIVE); + } else if (!strcasecmp(dtls_setup, "passive")) { + dtls->set_setup(rtp, AST_RTP_DTLS_SETUP_PASSIVE); + } else if (!strcasecmp(dtls_setup, "actpass")) { + dtls->set_setup(rtp, AST_RTP_DTLS_SETUP_ACTPASS); + } else if (!strcasecmp(dtls_setup, "holdconn")) { + dtls->set_setup(rtp, AST_RTP_DTLS_SETUP_HOLDCONN); + } else { + ast_log(LOG_WARNING, "Unsupported setup attribute dtls_setup '%s' received for session '%s'\n", + dtls_setup, session->sid); + } + } + else { + ast_log(LOG_WARNING, "Received DTLS information on session '%s', but it wasn't enabled\n", session->sid); + } + } + else { + ast_log(LOG_WARNING, "Invalid DTLS information on session '%s'\n", session->sid); + } + } for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) { + char *name = iks_name(candidate); + if (strcasecmp(name, "candidate") != 0) { + continue; + } char *component = iks_find_attrib(candidate, "component"), *foundation = iks_find_attrib(candidate, "foundation"); - char *generation = iks_find_attrib(candidate, "generation"), *id = iks_find_attrib(candidate, "id"); + char *generation = iks_find_attrib(candidate, "generation"); char *ip = iks_find_attrib(candidate, "ip"), *port = iks_find_attrib(candidate, "port"); char *priority = iks_find_attrib(candidate, "priority"), *protocol = iks_find_attrib(candidate, "protocol"); char *type = iks_find_attrib(candidate, "type"); @@ -2143,7 +2279,7 @@ static int jingle_interpret_ice_udp_transport(struct jingle_session *session, ik struct ast_sockaddr remote_address = { { 0, } }; /* If this candidate is incomplete skip it */ - if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) || + if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(ip) || ast_strlen_zero(port) || ast_strlen_zero(priority) || ast_strlen_zero(protocol) || ast_strlen_zero(type)) { jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR); @@ -2450,7 +2586,7 @@ static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, str /* Only send a transport-info message if we successfully interpreted the available content */ if (!jingle_interpret_content(session, pak)) { - jingle_send_transport_info(session, iks_find_attrib(pak->x, "from")); + jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"), 0); } break; } diff --git a/res/res_xmpp.c b/res/res_xmpp.c index 3a2d749..e7da3b2 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -2427,11 +2427,11 @@ done: static int xmpp_client_service_discovery_get_hook(void *data, ikspak *pak) { struct ast_xmpp_client *client = data; - iks *iq, *disco = NULL, *ident = NULL, *google = NULL, *jingle = NULL, *ice = NULL, *rtp = NULL, *audio = NULL, *video = NULL, *query = NULL; + iks *iq, *disco = NULL, *ident = NULL, *google = NULL, *jingle = NULL, *ice = NULL, *rtp = NULL, *audio = NULL, *video = NULL, *query = NULL, *dtls = NULL; if (!(iq = iks_new("iq")) || !(query = iks_new("query")) || !(ident = iks_new("identity")) || !(disco = iks_new("feature")) || !(google = iks_new("feature")) || !(jingle = iks_new("feature")) || !(ice = iks_new("feature")) || !(rtp = iks_new("feature")) || - !(audio = iks_new("feature")) || !(video = iks_new("feature"))) { + !(audio = iks_new("feature")) || !(video = iks_new("feature")) || !(dtls = iks_new("feature"))) { ast_log(LOG_ERROR, "Could not allocate memory for responding to service discovery request from '%s' on client '%s'\n", pak->from->full, client->name); goto end; @@ -2455,6 +2455,7 @@ static int xmpp_client_service_discovery_get_hook(void *data, ikspak *pak) iks_insert_attrib(jingle, "var", "urn:xmpp:jingle:1"); iks_insert_attrib(ice, "var", "urn:xmpp:jingle:transports:ice-udp:1"); iks_insert_attrib(rtp, "var", "urn:xmpp:jingle:apps:rtp:1"); + iks_insert_attrib(dtls, "var", "urn:xmpp:jingle:apps:dtls:0"); iks_insert_attrib(audio, "var", "urn:xmpp:jingle:apps:rtp:audio"); iks_insert_attrib(video, "var", "urn:xmpp:jingle:apps:rtp:video"); iks_insert_node(iq, query); @@ -2464,6 +2465,7 @@ static int xmpp_client_service_discovery_get_hook(void *data, ikspak *pak) iks_insert_node(query, jingle); iks_insert_node(query, ice); iks_insert_node(query, rtp); + iks_insert_node(query, dtls); iks_insert_node(query, audio); iks_insert_node(query, video); ast_xmpp_client_send(client, iq); -- 2.45.2