]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res/res_pjsip_nat: Fix logic for REINVITES
authorTorrey Searle <torrey@voxbone.com>
Wed, 24 Oct 2018 12:38:37 +0000 (14:38 +0200)
committerJoshua Colp <jcolp@digium.com>
Thu, 15 Nov 2018 11:35:00 +0000 (07:35 -0400)
The presence of Record-Route in re-invites is optional, thus it is
important to make sure the dialog doesn't have a routset before
rewriting the contact header.

ASTERISK-28129 #close

Change-Id: Ic8ceb54ccfc93f7e315e476c514a2c777f2da7dc

res/res_pjsip_nat.c

index 370004a3aa062dc6c0c4a69499e441c3a58f1a07..a0161d7c0885fb546d12b8a5a5e5f02303f7fdd9 100644 (file)
@@ -45,10 +45,42 @@ static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri)
        }
 }
 
+/*
+ * Update the Record-Route headers in the request or response and in the dialog
+ * object if exists.
+ *
+ * When NAT is in use, the address of the next hop in the SIP may be incorrect.
+ * To address this  asterisk uses two strategies in parallel:
+ *  1. intercept the messages at the transaction level and rewrite the
+ *     messages before arriving at the dialog layer
+ *  2. after the application processing, update the dialog object with the
+ *     correct information
+ *
+ * The first strategy has a limitation that the SIP message may not have all
+ * the information required to determine if the next hop is in the route set
+ * or in the contact. Causing risk that asterisk will update the Contact on
+ * receipt of an in-dialog message despite there being a route set saved in
+ * the dialog.
+ *
+ * The second strategy has a limitation that not all UAC layers have interfaces
+ * available to invoke this module after dialog creation.  (pjsip_sesion does
+ * but pjsip_pubsub does not), thus this strategy can't update the dialog in
+ * all cases needed.
+ *
+ * The ideal solution would be to implement an "incomming_request" event
+ * in pubsub module that can then pass the dialog object to this module
+ * on SUBSCRIBE, this module then should add itself as a listener to the dialog
+ * for the subsequent requests and responses & then be able to properly update
+ * the dialog object for all required events.
+ */
+
 static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg)
 {
        pjsip_rr_hdr *rr = NULL;
        pjsip_sip_uri *uri;
+       int res = -1;
+       int ignore_rr = 0;
+       int pubsub = 0;
 
        if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG) {
                pjsip_hdr *iter;
@@ -60,21 +92,49 @@ static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg)
                }
        } else if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method)) {
                rr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_RECORD_ROUTE, NULL);
+       } else {
+               /**
+                * Record-Route header has no meaning in REGISTER requests
+                * and should be ignored
+                */
+               ignore_rr = 1;
+       }
+
+       if (!pjsip_method_cmp(&rdata->msg_info.cseq->method, &pjsip_subscribe_method) ||
+               !pjsip_method_cmp(&rdata->msg_info.cseq->method, &pjsip_notify_method)) {
+               /**
+                * There is currently no good way to get the dlg object for a pubsub dialog
+                * so we will just look at the rr & contact of the current message and
+                * hope for the best
+                */
+               pubsub = 1;
        }
 
        if (rr) {
                uri = pjsip_uri_get_uri(&rr->name_addr);
                rewrite_uri(rdata, uri);
-               if (dlg && !pj_list_empty(&dlg->route_set) && !dlg->route_set_frozen) {
-                       pjsip_routing_hdr *route = dlg->route_set.next;
-                       uri = pjsip_uri_get_uri(&route->name_addr);
-                       rewrite_uri(rdata, uri);
-               }
+               res = 0;
+       }
 
-               return 0;
+       if (dlg && !pj_list_empty(&dlg->route_set) && !dlg->route_set_frozen) {
+               pjsip_routing_hdr *route = dlg->route_set.next;
+               uri = pjsip_uri_get_uri(&route->name_addr);
+               rewrite_uri(rdata, uri);
+               res = 0;
        }
 
-       return -1;
+       if (!dlg && !rr && !ignore_rr  && !pubsub && rdata->msg_info.to->tag.slen){
+               /**
+                * Even if this message doesn't have any route headers
+                * the dialog may, so wait until a later invocation that
+                * has a dialog reference to make sure there isn't a
+                * previously saved routset in the dialog before deciding
+                * the contact needs to be modified
+                */
+               res = 0;
+       }
+
+       return res;
 }
 
 static int rewrite_contact(pjsip_rx_data *rdata, pjsip_dialog *dlg)