From cd8f8b94f83208fa8c39e0f6afd6a3454be81950 Mon Sep 17 00:00:00 2001
From: Ben Ford <bford@digium.com>
Date: Tue, 3 Nov 2020 10:38:34 -0600
Subject: [PATCH] AST-2020-002 - res_pjsip: Stop sending INVITEs after
 challenge limit.

If Asterisk sends out and INVITE and receives a challenge with a
different nonce value each time, it will continually send out INVITEs,
even if the call is hung up. The endpoint must be configured for
outbound authentication in order 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
---
 include/asterisk/res_pjsip.h         | 3 +++
 include/asterisk/res_pjsip_session.h | 2 ++
 res/res_pjsip.c                      | 2 --
 res/res_pjsip_session.c              | 9 ++++++++-
 4 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index ddcf02fac2..2e1f7af312 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -76,6 +76,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
+
 AST_VECTOR(ast_sip_service_route_vector, char *);
 
 /*!
diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h
index 1e83696ffc..54c704fd11 100644
--- a/include/asterisk/res_pjsip_session.h
+++ b/include/asterisk/res_pjsip_session.h
@@ -235,6 +235,8 @@ struct ast_sip_session {
 	pjsip_uri *request_uri;
 	/*! Media statistics for negotiated RTP streams */
 	AST_VECTOR(, struct ast_rtp_instance_stats *) media_stats;
+	/*! Number of challenges received during outgoing requests to determine if we are in a loop */
+	unsigned int authentication_challenge_count:4;
 	/*! The direction of the call respective to Asterisk */
 	enum ast_sip_session_call_direction call_direction;
 };
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index cfc97b6477..73785604eb 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -4415,8 +4415,6 @@ static pj_bool_t does_method_match(const pj_str_t *message_method, const char *s
 	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
 
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index ec0114566d..e8319227db 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -2865,7 +2865,6 @@ static pjsip_module session_reinvite_module = {
 	.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)
 {
@@ -3120,6 +3119,8 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint,
 		return NULL;
 	}
 
+	session->authentication_challenge_count = 0;
+
 	/* Fire seesion begin handlers */
 	handle_session_begin(session);
 
@@ -3289,6 +3290,10 @@ static pj_bool_t outbound_invite_auth(pjsip_rx_data *rdata)
 	}
 	ast_debug(3, "%s: Initial INVITE is being challenged.\n", ast_sip_session_get_name(session));
 
+	if (++session->authentication_challenge_count > MAX_RX_CHALLENGES) {
+		ast_debug(3, "%s: Initial INVITE reached maximum number of auth attempts.\n", ast_sip_session_get_name(session));
+		return PJ_FALSE;
+	}
 
 	if (ast_sip_create_request_with_auth(&session->endpoint->outbound_auths, rdata,
 		tsx->last_tx, &tdata)) {
@@ -4696,6 +4701,7 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans
 							ast_sip_session_get_name(session),
 							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->last_tx, &tdata)) {
@@ -4789,6 +4795,7 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans
 						(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->last_tx, &tdata)) {
-- 
GitLab