From 692264c9ddaefee373901213794fd32b18ee2f0d Mon Sep 17 00:00:00 2001
From: Wenpeng Song <wenpeng.song@iopsys.eu>
Date: Fri, 10 Nov 2023 12:55:20 +0000
Subject: [PATCH] Fix a crash due to wrong handling of 200 OK to REGISTER

When SIP un-registration request got an 200 OK with expiration value which is not 0 (due to the
server setting and network), it is treated as registration success based on the non zero expiration value. This made the other procedures following and it went into an uncontrollable
stage, i.e. unstoppable loop of the un-registration requests until crash.

Solution
Retrieve the requested expiration if possible, and check it together with the received expiration
in response to identify if the 200 OK is to register or unregister.
---
 res/res_pjsip_outbound_registration.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c
index 7834367c9b..6c9aa59dc9 100644
--- a/res/res_pjsip_outbound_registration.c
+++ b/res/res_pjsip_outbound_registration.c
@@ -1533,8 +1533,16 @@ static int handle_registration_response(void *data)
 	response->client_state->auth_attempted = 0;
 
 	if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
-		/* Check if this is in regards to registering or unregistering */
-		if (response->expiration) {
+		/* Check if this is in regards to registering or unregistering
+		 * Retrieve the requested expiration if possible,
+		 * and check it combined with the received expiration to identify if it is reg or un-reg
+		 * Expiration was provided using the Expires header */
+		pjsip_expires_hdr *expires;
+		int exp_expiration = response->expiration;
+		if(response->old_request && (expires = pjsip_msg_find_hdr(response->old_request->msg, PJSIP_H_EXPIRES, NULL))){
+			exp_expiration = expires->ivalue;
+		}
+		if (exp_expiration && response->expiration) {
 			int next_registration_round;
 
 			response->client_state->is494=0;
@@ -1556,7 +1564,13 @@ static int handle_registration_response(void *data)
 					response->client_state->registration_name);
 			}
 		} else {
-			ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
+			if (!exp_expiration && !response->expiration) {
+				ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
+			} else {
+				// case1: unregistration request with expiration=0, but got response with non-zero expiration;
+				// case2: registration request with non-zero expiration but got expiration=0 in response
+				ast_debug(1, "Outbound registration/unregistration to '%s' with client '%s' failed, expiration not valid\n", server_uri, client_uri);
+			}
 			response->client_state->is494=0;
 			update_client_state_status(response->client_state, SIP_REGISTRATION_UNREGISTERED);
 			sip_outbound_registration_send_ubus_event("UNREGISTERED",response->expiration,client_uri);
-- 
GitLab