mirror of
https://git.openwrt.org/feed/telephony.git
synced 2025-01-08 11:47:32 +08:00
Merge pull request #588 from micmac1/18.06AST
[18.06] asterisk-13.x: fix AST-2020-001 and 002
This commit is contained in:
commit
e6a20f46da
@ -11,7 +11,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=asterisk13
|
||||
PKG_VERSION:=13.20.0
|
||||
PKG_RELEASE:=5
|
||||
PKG_RELEASE:=6
|
||||
|
||||
PKG_SOURCE:=asterisk-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://downloads.asterisk.org/pub/telephony/asterisk/releases
|
||||
|
401
net/asterisk-13.x/patches/170-AST-2020-001-13.diff
Normal file
401
net/asterisk-13.x/patches/170-AST-2020-001-13.diff
Normal file
@ -0,0 +1,401 @@
|
||||
From b4c49adbb9ed22f3ccc4fc45f98421012d6b62a5 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Harwell <kharwell@digium.com>
|
||||
Date: Mon, 19 Oct 2020 17:21:57 -0500
|
||||
Subject: [PATCH] AST-2020-001 - res_pjsip: Return dialog locked and referenced
|
||||
|
||||
pjproject returns the dialog locked and with a reference. However,
|
||||
in Asterisk the method that handles this decrements the reference
|
||||
and removes the lock prior to returning. This makes it possible,
|
||||
under some circumstances, for another thread to free said dialog
|
||||
before the thread that created it attempts to use it again. Of
|
||||
course when the thread that created it tries to use a freed dialog
|
||||
a crash can occur.
|
||||
|
||||
This patch makes it so Asterisk now returns the newly created
|
||||
dialog both locked, and with an added reference. This allows the
|
||||
caller to de-reference, and unlock the dialog when it is safe to
|
||||
do so.
|
||||
|
||||
In the case of a new SIP Invite the lock, and reference are now
|
||||
held for the entirety of the new invite handling process.
|
||||
Otherwise it's possible for the dialog, or its dependent objects,
|
||||
like the transaction, to disappear. For example if there is a TCP
|
||||
transport error.
|
||||
|
||||
Change-Id: I5ef645a47829596f402cf383dc02c629c618969e
|
||||
---
|
||||
|
||||
--- a/include/asterisk/res_pjsip.h
|
||||
+++ b/include/asterisk/res_pjsip.h
|
||||
@@ -1840,6 +1840,11 @@ pjsip_dialog *ast_sip_create_dialog_uac(
|
||||
/*!
|
||||
* \brief General purpose method for creating a UAS dialog with an endpoint
|
||||
*
|
||||
+ * \deprecated This function is unsafe (due to the returned object not being locked nor
|
||||
+ * having its reference incremented) and should no longer be used. Instead
|
||||
+ * use ast_sip_create_dialog_uas_locked so a properly locked and referenced
|
||||
+ * object is returned.
|
||||
+ *
|
||||
* \param endpoint A pointer to the endpoint
|
||||
* \param rdata The request that is starting the dialog
|
||||
* \param[out] status On failure, the reason for failure in creating the dialog
|
||||
@@ -1847,6 +1852,44 @@ pjsip_dialog *ast_sip_create_dialog_uac(
|
||||
pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status);
|
||||
|
||||
/*!
|
||||
+ * \brief General purpose method for creating a UAS dialog with an endpoint
|
||||
+ *
|
||||
+ * This function creates and returns a locked, and referenced counted pjsip
|
||||
+ * dialog object. The caller is thus responsible for freeing the allocated
|
||||
+ * memory, decrementing the reference, and releasing the lock when done with
|
||||
+ * the returned object.
|
||||
+ *
|
||||
+ * \note The safest way to unlock the object, and decrement its reference is by
|
||||
+ * calling pjsip_dlg_dec_lock. Alternatively, pjsip_dlg_dec_session can be
|
||||
+ * used to decrement the reference only.
|
||||
+ *
|
||||
+ * The dialog is returned locked and with a reference in order to ensure that the
|
||||
+ * dialog object, and any of its associated objects (e.g. transaction) are not
|
||||
+ * untimely destroyed. For instance, that could happen when a transport error
|
||||
+ * occurs.
|
||||
+ *
|
||||
+ * As long as the caller maintains a reference to the dialog there should be no
|
||||
+ * worry that it might unknowningly be destroyed. However, once the caller unlocks
|
||||
+ * the dialog there is a danger that some of the dialog's internal objects could
|
||||
+ * be lost and/or compromised. For example, when the aforementioned transport error
|
||||
+ * occurs the dialog's associated transaction gets destroyed (see pjsip_dlg_on_tsx_state
|
||||
+ * in sip_dialog.c, and mod_inv_on_tsx_state in sip_inv.c).
|
||||
+ *
|
||||
+ * In this case and before using the dialog again the caller should re-lock the
|
||||
+ * dialog, check to make sure the dialog is still established, and the transaction
|
||||
+ * still exists and has not been destroyed.
|
||||
+ *
|
||||
+ * \param endpoint A pointer to the endpoint
|
||||
+ * \param rdata The request that is starting the dialog
|
||||
+ * \param[out] status On failure, the reason for failure in creating the dialog
|
||||
+ *
|
||||
+ * \retval A locked, and reference counted pjsip_dialog object.
|
||||
+ * \retval NULL on failure
|
||||
+ */
|
||||
+pjsip_dialog *ast_sip_create_dialog_uas_locked(const struct ast_sip_endpoint *endpoint,
|
||||
+ pjsip_rx_data *rdata, pj_status_t *status);
|
||||
+
|
||||
+/*!
|
||||
* \brief General purpose method for creating an rdata structure using specific information
|
||||
* \since 13.15.0
|
||||
*
|
||||
--- a/res/res_pjsip.c
|
||||
+++ b/res/res_pjsip.c
|
||||
@@ -3293,7 +3293,11 @@ static int uas_use_sips_contact(pjsip_rx
|
||||
return 0;
|
||||
}
|
||||
|
||||
-pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status)
|
||||
+typedef pj_status_t (*create_dlg_uac)(pjsip_user_agent *ua, pjsip_rx_data *rdata,
|
||||
+ const pj_str_t *contact, pjsip_dialog **p_dlg);
|
||||
+
|
||||
+static pjsip_dialog *create_dialog_uas(const struct ast_sip_endpoint *endpoint,
|
||||
+ pjsip_rx_data *rdata, pj_status_t *status, create_dlg_uac create_fun)
|
||||
{
|
||||
pjsip_dialog *dlg;
|
||||
pj_str_t contact;
|
||||
@@ -3328,11 +3332,7 @@ pjsip_dialog *ast_sip_create_dialog_uas(
|
||||
(type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
|
||||
(type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "");
|
||||
|
||||
-#ifdef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK
|
||||
- *status = pjsip_dlg_create_uas_and_inc_lock(pjsip_ua_instance(), rdata, &contact, &dlg);
|
||||
-#else
|
||||
- *status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg);
|
||||
-#endif
|
||||
+ *status = create_fun(pjsip_ua_instance(), rdata, &contact, &dlg);
|
||||
if (*status != PJ_SUCCESS) {
|
||||
char err[PJ_ERR_MSG_SIZE];
|
||||
|
||||
@@ -3345,11 +3345,46 @@ pjsip_dialog *ast_sip_create_dialog_uas(
|
||||
dlg->sess_count++;
|
||||
pjsip_dlg_set_transport(dlg, &selector);
|
||||
dlg->sess_count--;
|
||||
+
|
||||
+ return dlg;
|
||||
+}
|
||||
+
|
||||
+pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status)
|
||||
+{
|
||||
#ifdef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK
|
||||
- pjsip_dlg_dec_lock(dlg);
|
||||
+ pjsip_dialog *dlg;
|
||||
+
|
||||
+ dlg = create_dialog_uas(endpoint, rdata, status, pjsip_dlg_create_uas_and_inc_lock);
|
||||
+ if (dlg) {
|
||||
+ pjsip_dlg_dec_lock(dlg);
|
||||
+ }
|
||||
+
|
||||
+ return dlg;
|
||||
+#else
|
||||
+ return create_dialog_uas(endpoint, rdata, status, pjsip_dlg_create_uas);
|
||||
#endif
|
||||
+}
|
||||
+
|
||||
+pjsip_dialog *ast_sip_create_dialog_uas_locked(const struct ast_sip_endpoint *endpoint,
|
||||
+ pjsip_rx_data *rdata, pj_status_t *status)
|
||||
+{
|
||||
+#ifdef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK
|
||||
+ return create_dialog_uas(endpoint, rdata, status, pjsip_dlg_create_uas_and_inc_lock);
|
||||
+#else
|
||||
+ /*
|
||||
+ * This is put here in order to be compatible with older versions of pjproject.
|
||||
+ * Best we can do in this case is immediately lock after getting the dialog.
|
||||
+ * However, that does leave a "gap" between creating and locking.
|
||||
+ */
|
||||
+ pjsip_dialog *dlg;
|
||||
+
|
||||
+ dlg = create_dialog_uas(endpoint, rdata, status, pjsip_dlg_create_uas);
|
||||
+ if (dlg) {
|
||||
+ pjsip_dlg_inc_lock(dlg);
|
||||
+ }
|
||||
|
||||
return dlg;
|
||||
+#endif
|
||||
}
|
||||
|
||||
int ast_sip_create_rdata_with_contact(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port,
|
||||
--- a/res/res_pjsip_pubsub.c
|
||||
+++ b/res/res_pjsip_pubsub.c
|
||||
@@ -1441,7 +1441,7 @@ static struct sip_subscription_tree *cre
|
||||
}
|
||||
sub_tree->role = AST_SIP_NOTIFIER;
|
||||
|
||||
- dlg = ast_sip_create_dialog_uas(endpoint, rdata, dlg_status);
|
||||
+ dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, dlg_status);
|
||||
if (!dlg) {
|
||||
if (*dlg_status != PJ_EEXISTS) {
|
||||
ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
|
||||
@@ -1462,8 +1462,16 @@ static struct sip_subscription_tree *cre
|
||||
}
|
||||
|
||||
pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub_tree->evsub);
|
||||
+
|
||||
subscription_setup_dialog(sub_tree, dlg);
|
||||
|
||||
+ /*
|
||||
+ * The evsub and subscription setup both add dialog refs, so the dialog ref that
|
||||
+ * was added when the dialog was created (see ast_sip_create_dialog_uas_lock) can
|
||||
+ * now be removed. The lock should no longer be needed so can be removed too.
|
||||
+ */
|
||||
+ pjsip_dlg_dec_lock(dlg);
|
||||
+
|
||||
#ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
|
||||
pjsip_evsub_add_ref(sub_tree->evsub);
|
||||
#endif
|
||||
--- a/res/res_pjsip_session.c
|
||||
+++ b/res/res_pjsip_session.c
|
||||
@@ -2050,6 +2050,75 @@ static enum sip_get_destination_result g
|
||||
return SIP_GET_DEST_EXTEN_NOT_FOUND;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * /internal
|
||||
+ * /brief Process initial answer for an incoming invite
|
||||
+ *
|
||||
+ * This function should only be called during the setup, and handling of a
|
||||
+ * new incoming invite. Most, if not all of the time, this will be called
|
||||
+ * when an error occurs and we need to respond as such.
|
||||
+ *
|
||||
+ * When a SIP session termination code is given for the answer it's assumed
|
||||
+ * this call then will be the final bit of processing before ending session
|
||||
+ * setup. As such, we've been holding a lock, and a reference on the invite
|
||||
+ * session's dialog. So before returning this function removes that reference,
|
||||
+ * and unlocks the dialog.
|
||||
+ *
|
||||
+ * \param inv_session The session on which to answer
|
||||
+ * \param rdata The original request
|
||||
+ * \param answer_code The answer's numeric code
|
||||
+ * \param terminate_code The termination code if the answer fails
|
||||
+ * \param notify Whether or not to call on_state_changed
|
||||
+ *
|
||||
+ * \retval 0 if invite successfully answered, -1 if an error occurred
|
||||
+ */
|
||||
+static int new_invite_initial_answer(pjsip_inv_session *inv_session, pjsip_rx_data *rdata,
|
||||
+ int answer_code, int terminate_code, pj_bool_t notify)
|
||||
+{
|
||||
+ pjsip_tx_data *tdata = NULL;
|
||||
+ int res = 0;
|
||||
+
|
||||
+ if (inv_session->state != PJSIP_INV_STATE_DISCONNECTED) {
|
||||
+ if (pjsip_inv_initial_answer(
|
||||
+ inv_session, rdata, answer_code, NULL, NULL, &tdata) != PJ_SUCCESS) {
|
||||
+
|
||||
+ pjsip_inv_terminate(inv_session, terminate_code ? terminate_code : answer_code, notify);
|
||||
+ res = -1;
|
||||
+ } else {
|
||||
+ pjsip_inv_send_msg(inv_session, tdata);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (answer_code >= 300) {
|
||||
+ /*
|
||||
+ * A session is ending. The dialog has a reference that needs to be
|
||||
+ * removed and holds a lock that needs to be unlocked before returning.
|
||||
+ */
|
||||
+ pjsip_dlg_dec_lock(inv_session->dlg);
|
||||
+ }
|
||||
+
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * /internal
|
||||
+ * /brief Create and initialize a pjsip invite session
|
||||
+
|
||||
+ * pjsip_inv_session adds, and maintains a reference to the dialog upon a successful
|
||||
+ * invite session creation until the session is destroyed. However, we'll wait to
|
||||
+ * remove the reference that was added for the dialog when it gets created since we're
|
||||
+ * not ready to unlock the dialog in this function.
|
||||
+ *
|
||||
+ * So, if this function successfully returns that means it returns with its newly
|
||||
+ * created, and associated dialog locked and with two references (i.e. dialog's
|
||||
+ * reference count should be 2).
|
||||
+ *
|
||||
+ * \param endpoint A pointer to the endpoint
|
||||
+ * \param rdata The request that is starting the dialog
|
||||
+ *
|
||||
+ * \retval A pjsip invite session object
|
||||
+ * \retval NULL on error
|
||||
+ */
|
||||
static pjsip_inv_session *pre_session_setup(pjsip_rx_data *rdata, const struct ast_sip_endpoint *endpoint)
|
||||
{
|
||||
pjsip_tx_data *tdata;
|
||||
@@ -2068,15 +2137,28 @@ static pjsip_inv_session *pre_session_se
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
- dlg = ast_sip_create_dialog_uas(endpoint, rdata, &dlg_status);
|
||||
+
|
||||
+ dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, &dlg_status);
|
||||
if (!dlg) {
|
||||
if (dlg_status != PJ_EEXISTS) {
|
||||
pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
+
|
||||
+ /*
|
||||
+ * The returned dialog holds a lock and has a reference added. Any paths where the
|
||||
+ * dialog invite session is not returned must unlock the dialog and remove its reference.
|
||||
+ */
|
||||
+
|
||||
if (pjsip_inv_create_uas(dlg, rdata, NULL, options, &inv_session) != PJ_SUCCESS) {
|
||||
pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
|
||||
+ /*
|
||||
+ * The acquired dialog holds a lock, and a reference. Since the dialog is not
|
||||
+ * going to be returned here it must first be unlocked and de-referenced. This
|
||||
+ * must be done prior to calling dialog termination.
|
||||
+ */
|
||||
+ pjsip_dlg_dec_lock(dlg);
|
||||
pjsip_dlg_terminate(dlg);
|
||||
return NULL;
|
||||
}
|
||||
@@ -2085,12 +2167,13 @@ static pjsip_inv_session *pre_session_se
|
||||
inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
|
||||
#endif
|
||||
if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
|
||||
- if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) != PJ_SUCCESS) {
|
||||
- pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
|
||||
- }
|
||||
- pjsip_inv_send_msg(inv_session, tdata);
|
||||
+ /* Dialog's lock and a reference are removed in new_invite_initial_answer */
|
||||
+ new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE);
|
||||
+ /* Remove 2nd reference added at inv_session creation */
|
||||
+ pjsip_dlg_dec_session(inv_session->dlg, &session_module);
|
||||
return NULL;
|
||||
}
|
||||
+
|
||||
return inv_session;
|
||||
}
|
||||
|
||||
@@ -2220,7 +2303,6 @@ static void handle_new_invite_request(pj
|
||||
{
|
||||
RAII_VAR(struct ast_sip_endpoint *, endpoint,
|
||||
ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
|
||||
- pjsip_tx_data *tdata = NULL;
|
||||
pjsip_inv_session *inv_session = NULL;
|
||||
struct ast_sip_session *session;
|
||||
struct new_invite invite;
|
||||
@@ -2233,27 +2315,48 @@ static void handle_new_invite_request(pj
|
||||
return;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * Upon a successful pre_session_setup the associated dialog is returned locked
|
||||
+ * and with an added reference. Well actually two references. One added when the
|
||||
+ * dialog itself was created, and another added when the pjsip invite session was
|
||||
+ * created and the dialog was added to it.
|
||||
+ *
|
||||
+ * In order to ensure the dialog's, and any of its internal attributes, lifetimes
|
||||
+ * we'll hold the lock and maintain the reference throughout the entire new invite
|
||||
+ * handling process. See ast_sip_create_dialog_uas_locked for more details but,
|
||||
+ * basically we do this to make sure a transport failure does not destroy the dialog
|
||||
+ * and/or transaction out from underneath us between pjsip calls. Alternatively, we
|
||||
+ * could probably release the lock if we needed to, but then we'd have to re-lock and
|
||||
+ * check the dialog and transaction prior to every pjsip call.
|
||||
+ *
|
||||
+ * That means any off nominal/failure paths in this function must remove the associated
|
||||
+ * dialog reference added at dialog creation, and remove the lock. As well the
|
||||
+ * referenced pjsip invite session must be "cleaned up", which should also then
|
||||
+ * remove its reference to the dialog at that time.
|
||||
+ *
|
||||
+ * Nominally we'll unlock the dialog, and release the reference when all new invite
|
||||
+ * process handling has successfully completed.
|
||||
+ */
|
||||
+
|
||||
#ifdef HAVE_PJSIP_INV_SESSION_REF
|
||||
if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) {
|
||||
ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
|
||||
- if (inv_session->state != PJSIP_INV_STATE_DISCONNECTED) {
|
||||
- if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
|
||||
- pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
|
||||
- } else {
|
||||
- pjsip_inv_send_msg(inv_session, tdata);
|
||||
- }
|
||||
+ /* Dialog's lock and a reference are removed in new_invite_initial_answer */
|
||||
+ if (!new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE)) {
|
||||
+ /* Terminate the session if it wasn't done in the answer */
|
||||
+ pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
-
|
||||
session = ast_sip_session_alloc(endpoint, NULL, inv_session, rdata);
|
||||
if (!session) {
|
||||
- if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
|
||||
+ /* Dialog's lock and reference are removed in new_invite_initial_answer */
|
||||
+ if (!new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE)) {
|
||||
+ /* Terminate the session if it wasn't done in the answer */
|
||||
pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
|
||||
- } else {
|
||||
- pjsip_inv_send_msg(inv_session, tdata);
|
||||
}
|
||||
+
|
||||
#ifdef HAVE_PJSIP_INV_SESSION_REF
|
||||
pjsip_inv_dec_ref(inv_session);
|
||||
#endif
|
||||
@@ -2271,6 +2374,17 @@ static void handle_new_invite_request(pj
|
||||
invite.rdata = rdata;
|
||||
new_invite(&invite);
|
||||
|
||||
+ /*
|
||||
+ * The dialog lock and reference added at dialog creation time must be
|
||||
+ * maintained throughout the new invite process. Since we're pretty much
|
||||
+ * done at this point with things it's safe to go ahead and remove the lock
|
||||
+ * and the reference here. See ast_sip_create_dialog_uas_locked for more info.
|
||||
+ *
|
||||
+ * Note, any future functionality added that does work using the dialog must
|
||||
+ * be done before this.
|
||||
+ */
|
||||
+ pjsip_dlg_dec_lock(inv_session->dlg);
|
||||
+
|
||||
ao2_ref(session, -1);
|
||||
}
|
||||
|
107
net/asterisk-13.x/patches/180-AST-2020-002-13.diff
Normal file
107
net/asterisk-13.x/patches/180-AST-2020-002-13.diff
Normal file
@ -0,0 +1,107 @@
|
||||
From 01b7ac0d590b0ad2e3e856d1a81fc87154ae68a0 Mon Sep 17 00:00:00 2001
|
||||
From: Ben Ford <bford@digium.com>
|
||||
Date: Mon, 02 Nov 2020 10:29:31 -0600
|
||||
Subject: [PATCH] AST-2020-002 - res_pjsip: Stop sending INVITEs after challenge limit.
|
||||
|
||||
If Asterisk sends out an INVITE and receives a challenge with a
|
||||
different nonce value each time, it will continuously send out INVITEs,
|
||||
even if the call is hung up. The endpoint must be configured for
|
||||
outbound authentication for this to occur. A limit has been set on
|
||||
outbound INVITEs so that, once reached, Asterisk will stop sending
|
||||
INVITEs and the transaction will terminate.
|
||||
|
||||
ASTERISK-29013
|
||||
|
||||
Change-Id: I2d001ca745b00ca8aa12030f2240cd72363b46f7
|
||||
---
|
||||
|
||||
--- a/include/asterisk/res_pjsip.h
|
||||
+++ b/include/asterisk/res_pjsip.h
|
||||
@@ -64,6 +64,9 @@ struct pjsip_tpselector;
|
||||
/*! \brief Maximum number of ciphers supported for a TLS transport */
|
||||
#define SIP_TLS_MAX_CIPHERS 64
|
||||
|
||||
+/*! Maximum number of challenges before assuming that we are in a loop */
|
||||
+#define MAX_RX_CHALLENGES 10
|
||||
+
|
||||
/*!
|
||||
* \brief Structure for SIP transport information
|
||||
*/
|
||||
--- a/include/asterisk/res_pjsip_session.h
|
||||
+++ b/include/asterisk/res_pjsip_session.h
|
||||
@@ -161,6 +161,8 @@ struct ast_sip_session {
|
||||
enum ast_sip_dtmf_mode dtmf;
|
||||
/*! Initial incoming INVITE Request-URI. NULL otherwise. */
|
||||
pjsip_uri *request_uri;
|
||||
+ /*! Number of challenges received during outgoing requests to determine if we are in a loop */
|
||||
+ unsigned int authentication_challenge_count:4;
|
||||
};
|
||||
|
||||
typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata);
|
||||
--- a/res/res_pjsip.c
|
||||
+++ b/res/res_pjsip.c
|
||||
@@ -3693,8 +3693,6 @@ static pj_bool_t does_method_match(const
|
||||
return pj_stristr(&method, message_method) ? PJ_TRUE : PJ_FALSE;
|
||||
}
|
||||
|
||||
-/*! Maximum number of challenges before assuming that we are in a loop */
|
||||
-#define MAX_RX_CHALLENGES 10
|
||||
#define TIMER_INACTIVE 0
|
||||
#define TIMEOUT_TIMER2 5
|
||||
|
||||
--- a/res/res_pjsip_session.c
|
||||
+++ b/res/res_pjsip_session.c
|
||||
@@ -1184,7 +1184,6 @@ static pjsip_module session_reinvite_mod
|
||||
.on_rx_request = session_reinvite_on_rx_request,
|
||||
};
|
||||
|
||||
-
|
||||
void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata,
|
||||
ast_sip_session_response_cb on_response)
|
||||
{
|
||||
@@ -1470,12 +1469,17 @@ struct ast_sip_session *ast_sip_session_
|
||||
ao2_ref(session, -1);
|
||||
return NULL;
|
||||
}
|
||||
+
|
||||
+ /* Track the number of challenges received on outbound requests */
|
||||
+ session->authentication_challenge_count = 0;
|
||||
+
|
||||
AST_LIST_TRAVERSE(&session->supplements, iter, next) {
|
||||
if (iter->session_begin) {
|
||||
iter->session_begin(session);
|
||||
}
|
||||
}
|
||||
|
||||
+
|
||||
/* Avoid unnecessary ref manipulation to return a session */
|
||||
ret_session = session;
|
||||
session = NULL;
|
||||
@@ -1642,6 +1646,11 @@ static pj_bool_t outbound_invite_auth(pj
|
||||
|
||||
session = inv->mod_data[session_module.id];
|
||||
|
||||
+ if (++session->authentication_challenge_count > MAX_RX_CHALLENGES) {
|
||||
+ ast_debug(3, "Initial INVITE reached maximum number of auth attempts.\n");
|
||||
+ return PJ_FALSE;
|
||||
+ }
|
||||
+
|
||||
if (ast_sip_create_request_with_auth(&session->endpoint->outbound_auths, rdata, tsx,
|
||||
&tdata)) {
|
||||
return PJ_FALSE;
|
||||
@@ -2888,6 +2897,7 @@ static void session_inv_on_tsx_state_cha
|
||||
ast_debug(1, "reINVITE received final response code %d\n",
|
||||
tsx->status_code);
|
||||
if ((tsx->status_code == 401 || tsx->status_code == 407)
|
||||
+ && ++session->authentication_challenge_count < MAX_RX_CHALLENGES
|
||||
&& !ast_sip_create_request_with_auth(
|
||||
&session->endpoint->outbound_auths,
|
||||
e->body.tsx_state.src.rdata, tsx, &tdata)) {
|
||||
@@ -2962,6 +2972,7 @@ static void session_inv_on_tsx_state_cha
|
||||
(int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),
|
||||
tsx->status_code);
|
||||
if ((tsx->status_code == 401 || tsx->status_code == 407)
|
||||
+ && ++session->authentication_challenge_count < MAX_RX_CHALLENGES
|
||||
&& !ast_sip_create_request_with_auth(
|
||||
&session->endpoint->outbound_auths,
|
||||
e->body.tsx_state.src.rdata, tsx, &tdata)) {
|
Loading…
Reference in New Issue
Block a user