PJSIP: Fix address for ACK in NAT situations
authorKinsey Moore <kmoore@digium.com>
Fri, 31 Jan 2014 15:08:49 +0000 (15:08 +0000)
committerKinsey Moore <kmoore@digium.com>
Fri, 31 Jan 2014 15:08:49 +0000 (15:08 +0000)
In NAT scenarios where a call is placed to a Grandstream phone,
res_pjsip will sometimes send the ACK to a 200 OK to the private
address of the device behind the NAT instead of the address of the NAT
device. This corrects that behavior by rewriting the address in the
Contact header in the incoming 200 OK and the dialog's target address
if necessary (since it has already been rewritten to the incorrect
private address).

(closes issue ASTERISK-23106)
Review: https://reviewboard.asterisk.org/r/3168/
Reported by: Matt Jordan
........

Merged revisions 407000 from http://svn.asterisk.org/svn/asterisk/branches/12

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@407001 65c4cc65-6c06-0410-ace0-fbb531ad65f3

res/res_pjsip_nat.c

index 092ff00..30dae2b 100644 (file)
@@ -32,9 +32,8 @@
 #include "asterisk/module.h"
 #include "asterisk/acl.h"
 
-static pj_bool_t nat_on_rx_message(pjsip_rx_data *rdata)
+static pj_bool_t handle_rx_message(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
 {
-       RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
        pjsip_contact_hdr *contact;
 
        if (!endpoint) {
@@ -44,9 +43,17 @@ static pj_bool_t nat_on_rx_message(pjsip_rx_data *rdata)
        if (endpoint->nat.rewrite_contact && (contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL)) &&
                !contact->star && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
                pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);
+               pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
 
                pj_cstr(&uri->host, rdata->pkt_info.src_name);
                uri->port = rdata->pkt_info.src_port;
+
+               /* rewrite the session target since it may have already been pulled from the contact header */
+               if (dlg && (!dlg->remote.contact
+                       || pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, dlg->remote.contact->uri, contact->uri))) {
+                       dlg->remote.contact = (pjsip_contact_hdr*)pjsip_hdr_clone(dlg->pool, contact);
+                       dlg->target = dlg->remote.contact->uri;
+               }
        }
 
        if (endpoint->nat.force_rport) {
@@ -56,6 +63,12 @@ static pj_bool_t nat_on_rx_message(pjsip_rx_data *rdata)
        return PJ_FALSE;
 }
 
+static pj_bool_t nat_on_rx_message(pjsip_rx_data *rdata)
+{
+       RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
+       return handle_rx_message(endpoint, rdata);
+}
+
 /*! \brief Structure which contains information about a transport */
 struct request_transport_details {
        /*! \brief Type of transport */
@@ -230,6 +243,12 @@ static int nat_incoming_invite_request(struct ast_sip_session *session, struct p
        return 0;
 }
 
+/*! \brief Function called when an INVITE response comes in */
+static void nat_incoming_invite_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
+{
+       handle_rx_message(session->endpoint, rdata);
+}
+
 /*! \brief Function called when an INVITE comes in */
 static void nat_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
 {
@@ -244,6 +263,7 @@ static struct ast_sip_session_supplement nat_supplement = {
        .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST + 1,
        .incoming_request = nat_incoming_invite_request,
        .outgoing_request = nat_outgoing_invite_request,
+       .incoming_response = nat_incoming_invite_response,
 };