<p>Joshua Colp has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/7223">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">pjsip / hep: Provide correct local address for Websockets.<br><br>Previously for PJSIP the local address of WebSocket connections<br>was set to the remote address. For logging purposes this is<br>not particularly useful.<br><br>The WebSocket API has been extended to allow the local<br>address to be queried and this is used in PJSIP to set the<br>local address to the correct value.<br><br>The PJSIP HEP support has also been tweaked so that reliable<br>transports always use the local address on the transport<br>and do not try to (wrongly) guess. As they are connection<br>based it is impossible for the source to be anything else.<br><br>ASTERISK-26758<br>ASTERISK-27363<br><br>Change-Id: Icd305fd038ad755e2682ab2786e381f6bf29e8ca<br>---<br>M include/asterisk/http_websocket.h<br>M res/res_hep_pjsip.c<br>M res/res_http_websocket.c<br>M res/res_pjsip_transport_websocket.c<br>4 files changed, 98 insertions(+), 63 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/23/7223/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/include/asterisk/http_websocket.h b/include/asterisk/http_websocket.h<br>index d8e7d06..83d5d4f 100644<br>--- a/include/asterisk/http_websocket.h<br>+++ b/include/asterisk/http_websocket.h<br>@@ -344,6 +344,15 @@<br> AST_OPTIONAL_API(struct ast_sockaddr *, ast_websocket_remote_address, (struct ast_websocket *session), {return NULL;});<br> <br> /*!<br>+ * \brief Get the local address for a WebSocket connection session.<br>+ *<br>+ * \retval ast_sockaddr Local address<br>+ *<br>+ * \since 13.19.0<br>+ */<br>+AST_OPTIONAL_API(struct ast_sockaddr *, ast_websocket_local_address, (struct ast_websocket *session), {return NULL;});<br>+<br>+/*!<br>  * \brief Get whether the WebSocket session is using a secure transport or not.<br>  *<br>  * \retval 0 if unsecure<br>diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c<br>index 1614b43..1d99fcc 100644<br>--- a/res/res_hep_pjsip.c<br>+++ b/res/res_hep_pjsip.c<br>@@ -91,35 +91,44 @@<br>       pjsip_cid_hdr *cid_hdr;<br>       pjsip_from_hdr *from_hdr;<br>     pjsip_to_hdr *to_hdr;<br>-        pjsip_tpmgr_fla2_param prm;<br> <br>        capture_info = hepv3_create_capture_info(tdata->buf.start, (size_t)(tdata->buf.cur - tdata->buf.start));<br>     if (!capture_info) {<br>          return PJ_SUCCESS;<br>    }<br> <br>- /* Attempt to determine what IP address will we send this packet out of */<br>-   pjsip_tpmgr_fla2_param_default(&prm);<br>-    prm.tp_type = tdata->tp_info.transport->key.type;<br>-      pj_strset2(&prm.dst_host, tdata->tp_info.dst_name);<br>-   prm.local_if = PJ_TRUE;<br>+      if (!(tdata->tp_info.transport->flag & PJSIP_TRANSPORT_RELIABLE)) {<br>+                pjsip_tpmgr_fla2_param prm;<br> <br>-       /* If we can't get the local address use what we have already */<br>- if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) {<br>-             pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);<br>- } else {<br>-             if (prm.tp_type & PJSIP_TRANSPORT_IPV6) {<br>-                        snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu",<br>-                               (int)pj_strlen(&prm.ret_addr),<br>-                           pj_strbuf(&prm.ret_addr),<br>-                                prm.ret_port);<br>+               /* Attempt to determine what IP address will we send this packet out of */<br>+           pjsip_tpmgr_fla2_param_default(&prm);<br>+            prm.tp_type = tdata->tp_info.transport->key.type;<br>+              pj_strset2(&prm.dst_host, tdata->tp_info.dst_name);<br>+           prm.local_if = PJ_TRUE;<br>+<br>+           /* If we can't get the local address use what we have already */<br>+         if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) {<br>+                     pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);<br>          } else {<br>-                     snprintf(local_buf, sizeof(local_buf), "%.*s:%hu",<br>-                         (int)pj_strlen(&prm.ret_addr),<br>-                           pj_strbuf(&prm.ret_addr),<br>-                                prm.ret_port);<br>+                       if (prm.tp_type & PJSIP_TRANSPORT_IPV6) {<br>+                                snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu",<br>+                                       (int)pj_strlen(&prm.ret_addr),<br>+                                   pj_strbuf(&prm.ret_addr),<br>+                                        prm.ret_port);<br>+                       } else {<br>+                             snprintf(local_buf, sizeof(local_buf), "%.*s:%hu",<br>+                                 (int)pj_strlen(&prm.ret_addr),<br>+                                   pj_strbuf(&prm.ret_addr),<br>+                                        prm.ret_port);<br>+                       }<br>             }<br>+    } else {<br>+             /* For reliable transports they can only ever come from the transport<br>+                 * local address.<br>+             */<br>+          pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);<br>  }<br>+<br>  pj_sockaddr_print(&tdata->tp_info.dst_addr, remote_buf, sizeof(remote_buf), 3);<br> <br>     cid_hdr = PJSIP_MSG_CID_HDR(tdata->msg);<br>@@ -152,7 +161,6 @@<br>      char remote_buf[256];<br>         char *uuid;<br>   struct hepv3_capture_info *capture_info;<br>-     pjsip_tpmgr_fla2_param prm;<br> <br>        capture_info = hepv3_create_capture_info(&rdata->pkt_info.packet, rdata->pkt_info.len);<br>     if (!capture_info) {<br>@@ -164,27 +172,33 @@<br>   }<br>     pj_sockaddr_print(&rdata->pkt_info.src_addr, remote_buf, sizeof(remote_buf), 3);<br> <br>-   /* Attempt to determine what IP address we probably received this packet on */<br>-       pjsip_tpmgr_fla2_param_default(&prm);<br>-    prm.tp_type = rdata->tp_info.transport->key.type;<br>-      pj_strset2(&prm.dst_host, rdata->pkt_info.src_name);<br>-  prm.local_if = PJ_TRUE;<br>+      if (!(rdata->tp_info.transport->flag & PJSIP_TRANSPORT_RELIABLE)) {<br>+                pjsip_tpmgr_fla2_param prm;<br> <br>-       /* If we can't get the local address use what we have already */<br>- if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), rdata->tp_info.pool, &prm) != PJ_SUCCESS) {<br>-             pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);<br>- } else {<br>-             if (prm.tp_type & PJSIP_TRANSPORT_IPV6) {<br>-                        snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu",<br>-                               (int)pj_strlen(&prm.ret_addr),<br>-                           pj_strbuf(&prm.ret_addr),<br>-                                prm.ret_port);<br>+               /* Attempt to determine what IP address we probably received this packet on */<br>+               pjsip_tpmgr_fla2_param_default(&prm);<br>+            prm.tp_type = rdata->tp_info.transport->key.type;<br>+              pj_strset2(&prm.dst_host, rdata->pkt_info.src_name);<br>+          prm.local_if = PJ_TRUE;<br>+<br>+           /* If we can't get the local address use what we have already */<br>+         if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), rdata->tp_info.pool, &prm) != PJ_SUCCESS) {<br>+                     pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);<br>          } else {<br>-                     snprintf(local_buf, sizeof(local_buf), "%.*s:%hu",<br>-                         (int)pj_strlen(&prm.ret_addr),<br>-                           pj_strbuf(&prm.ret_addr),<br>-                                prm.ret_port);<br>+                       if (prm.tp_type & PJSIP_TRANSPORT_IPV6) {<br>+                                snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu",<br>+                                       (int)pj_strlen(&prm.ret_addr),<br>+                                   pj_strbuf(&prm.ret_addr),<br>+                                        prm.ret_port);<br>+                       } else {<br>+                             snprintf(local_buf, sizeof(local_buf), "%.*s:%hu",<br>+                                 (int)pj_strlen(&prm.ret_addr),<br>+                                   pj_strbuf(&prm.ret_addr),<br>+                                        prm.ret_port);<br>+                       }<br>             }<br>+    } else {<br>+             pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);<br>  }<br> <br>  uuid = assign_uuid(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag);<br>diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c<br>index 2baccc0..75a6eba 100644<br>--- a/res/res_http_websocket.c<br>+++ b/res/res_http_websocket.c<br>@@ -87,18 +87,19 @@<br> <br> /*! \brief Structure definition for session */<br> struct ast_websocket {<br>- FILE *f;                          /*!< Pointer to the file instance used for writing and reading */<br>-       int fd;                           /*!< File descriptor for the session, only used for polling */<br>-  struct ast_sockaddr address;      /*!< Address of the remote client */<br>-    enum ast_websocket_opcode opcode; /*!< Cached opcode for multi-frame messages */<br>-  size_t payload_len;               /*!< Length of the payload */<br>-   char *payload;                    /*!< Pointer to the payload */<br>-  size_t reconstruct;               /*!< Number of bytes before a reconstructed payload will be returned and a new one started */<br>-   int timeout;                      /*!< The timeout for operations on the socket */<br>-        unsigned int secure:1;            /*!< Bit to indicate that the transport is secure */<br>-    unsigned int closing:1;           /*!< Bit to indicate that the session is in the process of being closed */<br>-      unsigned int close_sent:1;        /*!< Bit to indicate that the session close opcode has been sent and no further data will be sent */<br>-    struct websocket_client *client;  /*!< Client object when connected as a client websocket */<br>+      FILE *f;                            /*!< Pointer to the file instance used for writing and reading */<br>+     int fd;                             /*!< File descriptor for the session, only used for polling */<br>+        struct ast_sockaddr remote_address; /*!< Address of the remote client */<br>+  struct ast_sockaddr local_address;  /*!< Our local address */<br>+     enum ast_websocket_opcode opcode;   /*!< Cached opcode for multi-frame messages */<br>+        size_t payload_len;                 /*!< Length of the payload */<br>+ char *payload;                      /*!< Pointer to the payload */<br>+        size_t reconstruct;                 /*!< Number of bytes before a reconstructed payload will be returned and a new one started */<br>+ int timeout;                        /*!< The timeout for operations on the socket */<br>+      unsigned int secure:1;              /*!< Bit to indicate that the transport is secure */<br>+  unsigned int closing:1;             /*!< Bit to indicate that the session is in the process of being closed */<br>+    unsigned int close_sent:1;          /*!< Bit to indicate that the session close opcode has been sent and no further data will be sent */<br>+  struct websocket_client *client;    /*!< Client object when connected as a client websocket */<br> };<br> <br> /*! \brief Hashing function for protocols */<br>@@ -183,7 +184,7 @@<br>                 if (session->f) {<br>                  fclose(session->f);<br>                        ast_verb(2, "WebSocket connection %s '%s' closed\n", session->client ? "to" : "from",<br>-                               ast_sockaddr_stringify(&session->address));<br>+                           ast_sockaddr_stringify(&session->remote_address));<br>             }<br>     }<br> <br>@@ -316,7 +317,7 @@<br>             fclose(session->f);<br>                session->f = NULL;<br>                 ast_verb(2, "WebSocket connection %s '%s' forcefully closed due to fatal write error\n",<br>-                   session->client ? "to" : "from", ast_sockaddr_stringify(&session->address));<br>+                   session->client ? "to" : "from", ast_sockaddr_stringify(&session->remote_address));<br>     }<br> <br>  ao2_unlock(session);<br>@@ -429,7 +430,12 @@<br> <br> struct ast_sockaddr * AST_OPTIONAL_API_NAME(ast_websocket_remote_address)(struct ast_websocket *session)<br> {<br>- return &session->address;<br>+     return &session->remote_address;<br>+}<br>+<br>+struct ast_sockaddr * AST_OPTIONAL_API_NAME(ast_websocket_local_address)(struct ast_websocket *session)<br>+{<br>+ return &session->local_address;<br> }<br> <br> int AST_OPTIONAL_API_NAME(ast_websocket_is_secure)(struct ast_websocket *session)<br>@@ -890,12 +896,22 @@<br>              return 0;<br>     }<br> <br>+ /* Get our local address for the connected socket */<br>+ if (ast_getsockname(ser->fd, &session->local_address)) {<br>+           ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - failed to get local address\n",<br>+                       ast_sockaddr_stringify(&ser->remote_address));<br>+                websocket_bad_request(ser);<br>+          ao2_ref(session, -1);<br>+                ao2_ref(protocol_handler, -1);<br>+               return 0;<br>+    }<br>+<br>  ast_verb(2, "WebSocket connection from '%s' for protocol '%s' accepted using version '%d'\n", ast_sockaddr_stringify(&ser->remote_address), protocol ? : "", version);<br> <br>  /* Populate the session with all the needed details */<br>        session->f = ser->f;<br>    session->fd = ser->fd;<br>- ast_sockaddr_copy(&session->address, &ser->remote_address);<br>+    ast_sockaddr_copy(&session->remote_address, &ser->remote_address);<br>      session->opcode = -1;<br>      session->reconstruct = DEFAULT_RECONSTRUCTION_CEILING;<br>     session->secure = ser->ssl ? 1 : 0;<br>@@ -1350,7 +1366,7 @@<br>      ws->f = ws->client->ser->f;<br>       ws->fd = ws->client->ser->fd;<br>     ws->secure = ws->client->ser->ssl ? 1 : 0;<br>-       ast_sockaddr_copy(&ws->address, &ws->client->ser->remote_address);<br>+       ast_sockaddr_copy(&ws->remote_address, &ws->client->ser->remote_address);<br>         return WS_OK;<br> }<br> <br>diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c<br>index c04594f..b1f560c 100644<br>--- a/res/res_pjsip_transport_websocket.c<br>+++ b/res/res_pjsip_transport_websocket.c<br>@@ -206,20 +206,16 @@<br>      pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ws_addr_str), &newtransport->transport.key.rem_addr);<br>   if (newtransport->transport.key.rem_addr.addr.sa_family == pj_AF_INET6()) {<br>                newtransport->transport.key.type = transport_type_wss_ipv6;<br>-               newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN);<br>-           pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, PJ_INET6_ADDRSTRLEN, 0);<br>      } else {<br>              newtransport->transport.key.type = transport_type_wss;<br>-            newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, PJ_INET_ADDRSTRLEN);<br>-            pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, PJ_INET_ADDRSTRLEN, 0);<br>       }<br> <br>  newtransport->transport.addr_len = pj_sockaddr_get_len(&newtransport->transport.key.rem_addr);<br> <br>-  pj_sockaddr_cp(&newtransport->transport.local_addr, &newtransport->transport.key.rem_addr);<br>-<br>- newtransport->transport.local_name.host.slen = pj_ansi_strlen(newtransport->transport.local_name.host.ptr);<br>-    newtransport->transport.local_name.port = pj_sockaddr_get_port(&newtransport->transport.key.rem_addr);<br>+     ws_addr_str = ast_sockaddr_stringify(ast_websocket_local_address(newtransport->ws_session));<br>+      pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ws_addr_str), &newtransport->transport.local_addr);<br>+    pj_strdup2(pool, &newtransport->transport.local_name.host, ast_sockaddr_stringify_host(ast_websocket_local_address(newtransport->ws_session)));<br>+    newtransport->transport.local_name.port = ast_sockaddr_port(ast_websocket_local_address(newtransport->ws_session));<br> <br>  newtransport->transport.flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)newtransport->transport.key.type);<br>    newtransport->transport.info = (char *)pj_pool_alloc(newtransport->transport.pool, 64);<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/7223">change 7223</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/7223"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 13 </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Icd305fd038ad755e2682ab2786e381f6bf29e8ca </div>
<div style="display:none"> Gerrit-Change-Number: 7223 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@digium.com> </div>