From 8b60998d29641b21eb1e823d07b2b6b82d0323f1 Mon Sep 17 00:00:00 2001
From: Damian Ivereigh <damo@launtel.net.au>
Date: Thu, 11 Jun 2015 23:18:48 +1000
Subject: [PATCH] chan_sip.c: Update dialog fromtag after request with auth

If a client sends and INVITE which is 401 rejected, then subsequently
sends a new INVITE with the auth info and uses a different fromtag
from the first INVITE, Asterisk will accept the new INVITE as part of
the original dialog - match_req_to_dialog() specifically ignores the
fromtag. However it does not update the stored dialog with the new
fromtag.

This results in Asterisk being unable to match future packets that are
part of this dialog (such as the ACK to the OK or the OK to the BYE),
and the call is dropped.

This problem was originally found when using an NEC-i SV8100-GE (NEC SIP
Card).

* After a successful match of a packet to the dialog, if the packet is
  not a SIP_RESPONSE, authentication is present and the fromtags are
  different, the stored fromtag is updated with the one from the recent
  INVITE.

ASTERISK-25154 #close
Reported by: Damian Ivereigh
Tested by: Damian Ivereigh

Change-Id: I5c16cf3b409e5ef9f2b2fe974b6bd2a45a6aa17e
---
 channels/chan_sip.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 3637ad7468..a167f43470 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -9112,6 +9112,15 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
 
 			switch (found) {
 			case SIP_REQ_MATCH:
+				sip_pvt_lock(sip_pvt_ptr);
+				if (args.method != SIP_RESPONSE && args.authentication_present
+						&& strcmp(args.fromtag, sip_pvt_ptr->theirtag)) {
+					/* If we have a request that uses athentication and the fromtag is
+					 * different from that in the original call dialog, update the
+					 * fromtag in the saved call dialog */
+					ast_string_field_set(sip_pvt_ptr, theirtag, args.fromtag);
+				}
+				sip_pvt_unlock(sip_pvt_ptr);
 				ao2_iterator_destroy(iterator);
 				dialog_unref(fork_pvt, "unref fork_pvt");
 				free_via(via);
-- 
GitLab