@@ 0,0 1,315 @@
+From: Stephen Paul Weber <singpolyma@singpolyma.net>
+Date: Wed, 22 Jul 2020 14:34:00 -0500
+X-Dgit-Generated: 1:16.2.1~dfsg-1+deb10u1 585dac068290d9281c0a49f324c566a22323adea
+Subject: Apply patch from eta
+
+https://theta.eu.org/lx/asterisk.patch
+
+---
+
+--- asterisk-16.2.1~dfsg.orig/channels/chan_motif.c
++++ asterisk-16.2.1~dfsg/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 j
+ 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 j
+ }
+ }
+
++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_all
+ 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
+ }
+
+ 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
+ }
+
+ 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_cau
+ }
+
+ /*! \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(s
+ 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_descri
+ 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 jin
+ 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 *da
+ }
+ 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(
+ 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_tran
+ 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_tran
+ 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_initia
+
+ /* 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;
+ }
+--- asterisk-16.2.1~dfsg.orig/res/res_xmpp.c
++++ asterisk-16.2.1~dfsg/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
+ 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
+ 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);