Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Macros | Functions | Variables
res_pjsip_nat.c File Reference
#include "asterisk.h"
#include <pjsip.h>
#include <pjsip_ua.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_session.h"
#include "asterisk/module.h"
#include "asterisk/acl.h"
Include dependency graph for res_pjsip_nat.c:

Go to the source code of this file.

Data Structures

struct  nat_hook_details
 Structure which contains hook details. More...
 
struct  request_transport_details
 Structure which contains information about a transport. More...
 

Macros

#define AST_SIP_X_AST_ORIG_HOST   "x-ast-orig-host"
 
#define AST_SIP_X_AST_ORIG_HOST_LEN   15
 
#define COLON_LEN   1
 
#define is_sip_uri(uri)   (PJSIP_URI_SCHEME_IS_SIP(uri) || PJSIP_URI_SCHEME_IS_SIPS(uri))
 
#define MAX_PORT_LEN   5
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int find_transport_state_in_use (void *obj, void *arg, int flags)
 Callback function for finding the transport the request is going out on. More...
 
static pj_bool_t handle_rx_message (struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
 
static int load_module (void)
 
static pjsip_sip_uri * nat_get_contact_sip_uri (pjsip_tx_data *tdata)
 Helper function which returns the SIP URI of a Contact header. More...
 
static int nat_incoming_invite_request (struct ast_sip_session *session, struct pjsip_rx_data *rdata)
 Function called when an INVITE goes out. More...
 
static void nat_incoming_invite_response (struct ast_sip_session *session, struct pjsip_rx_data *rdata)
 Function called when an INVITE response comes in. More...
 
static int nat_invoke_hook (void *obj, void *arg, int flags)
 Callback function for invoking hooks. More...
 
static pj_bool_t nat_on_rx_message (pjsip_rx_data *rdata)
 
static pj_status_t nat_on_tx_message (pjsip_tx_data *tdata)
 
static void nat_outgoing_invite_request (struct ast_sip_session *session, struct pjsip_tx_data *tdata)
 Function called when an INVITE comes in. More...
 
static pj_status_t process_nat (pjsip_tx_data *tdata)
 
static void restore_orig_contact_host (pjsip_tx_data *tdata)
 
static int rewrite_contact (pjsip_rx_data *rdata, pjsip_dialog *dlg)
 
static int rewrite_route_set (pjsip_rx_data *rdata, pjsip_dialog *dlg)
 
static void rewrite_uri (pjsip_rx_data *rdata, pjsip_sip_uri *uri, pj_pool_t *pool)
 
static void save_orig_contact_host (pjsip_rx_data *rdata, pjsip_sip_uri *uri)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP NAT Support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip,res_pjsip_session", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static pjsip_module nat_module
 
static struct ast_sip_session_supplement nat_supplement
 Supplement for adding NAT functionality to dialog. More...
 

Macro Definition Documentation

◆ AST_SIP_X_AST_ORIG_HOST

#define AST_SIP_X_AST_ORIG_HOST   "x-ast-orig-host"

URI parameter for original host/port

Definition at line 37 of file res_pjsip_nat.c.

Referenced by restore_orig_contact_host(), and save_orig_contact_host().

◆ AST_SIP_X_AST_ORIG_HOST_LEN

#define AST_SIP_X_AST_ORIG_HOST_LEN   15

Definition at line 38 of file res_pjsip_nat.c.

Referenced by restore_orig_contact_host().

◆ COLON_LEN

#define COLON_LEN   1

Referenced by save_orig_contact_host().

◆ is_sip_uri

#define is_sip_uri (   uri)    (PJSIP_URI_SCHEME_IS_SIP(uri) || PJSIP_URI_SCHEME_IS_SIPS(uri))

Definition at line 40 of file res_pjsip_nat.c.

Referenced by restore_orig_contact_host().

◆ MAX_PORT_LEN

#define MAX_PORT_LEN   5

Referenced by save_orig_contact_host().

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 556 of file res_pjsip_nat.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 556 of file res_pjsip_nat.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 556 of file res_pjsip_nat.c.

◆ find_transport_state_in_use()

static int find_transport_state_in_use ( void *  obj,
void *  arg,
int  flags 
)
static

Callback function for finding the transport the request is going out on.

Definition at line 254 of file res_pjsip_nat.c.

References CMP_MATCH, ast_sip_transport_state::factory, request_transport_details::factory, request_transport_details::local_address, request_transport_details::local_port, ast_sip_transport_state::transport, request_transport_details::transport, ast_sip_transport_state::type, and request_transport_details::type.

Referenced by process_nat().

255 {
256  struct ast_sip_transport_state *transport_state = obj;
257  struct request_transport_details *details = arg;
258 
259  /* If an explicit transport or factory matches then this is what is in use, if we are unavailable
260  * to compare based on that we make sure that the type is the same and the source IP address/port are the same
261  */
262  if (transport_state && ((details->transport && details->transport == transport_state->transport) ||
263  (details->factory && details->factory == transport_state->factory) ||
264  ((details->type == transport_state->type) && (transport_state->factory) &&
265  !pj_strcmp(&transport_state->factory->addr_name.host, &details->local_address) &&
266  transport_state->factory->addr_name.port == details->local_port))) {
267  return CMP_MATCH;
268  }
269 
270  return 0;
271 }
enum ast_transport type
Definition: res_pjsip.h:101
pjsip_tpfactory * factory
Potential pointer to the transport factory itself, if TCP/TLS.
enum ast_transport type
Type of transport.
pj_str_t local_address
Local address for transport.
pjsip_transport * transport
Potential pointer to the transport itself, if UDP.
Structure which contains information about a transport.
Structure for SIP transport information.
Definition: res_pjsip.h:87
int local_port
Local port for transport.
struct pjsip_transport * transport
Transport itself.
Definition: res_pjsip.h:89
struct pjsip_tpfactory * factory
Transport factory.
Definition: res_pjsip.h:91

◆ handle_rx_message()

static pj_bool_t handle_rx_message ( struct ast_sip_endpoint endpoint,
pjsip_rx_data *  rdata 
)
static

Definition at line 200 of file res_pjsip_nat.c.

References ast_sip_endpoint_nat_configuration::force_rport, ast_sip_endpoint::nat, rewrite_contact(), ast_sip_endpoint_nat_configuration::rewrite_contact, and rewrite_route_set().

Referenced by nat_incoming_invite_response(), and nat_on_rx_message().

201 {
202  pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
203 
204  if (!endpoint) {
205  return PJ_FALSE;
206  }
207 
208  if (endpoint->nat.rewrite_contact) {
209  /* rewrite_contact is intended to ensure we send requests/responses to
210  * a routeable address when NAT is involved. The URI that dictates where
211  * we send requests/responses can be determined either by Record-Route
212  * headers or by the Contact header if no Record-Route headers are present.
213  * We therefore will attempt to rewrite a Record-Route header first, and if
214  * none are present, we fall back to rewriting the Contact header instead.
215  */
216  if (rewrite_route_set(rdata, dlg)) {
217  rewrite_contact(rdata, dlg);
218  }
219  }
220 
221  if (endpoint->nat.force_rport) {
222  rdata->msg_info.via->rport_param = rdata->pkt_info.src_port;
223  }
224 
225  return PJ_FALSE;
226 }
struct ast_sip_endpoint_nat_configuration nat
Definition: res_pjsip.h:845
static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg)
static int rewrite_contact(pjsip_rx_data *rdata, pjsip_dialog *dlg)

◆ load_module()

static int load_module ( void  )
static

Definition at line 538 of file res_pjsip_nat.c.

References ast_log, AST_MODFLAG_LOAD_ORDER, AST_MODPRI_APP_DEPEND, AST_MODULE_INFO(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, AST_MODULE_SUPPORT_CORE, ast_sip_register_service(), ast_sip_session_register_supplement, ASTERISK_GPL_KEY, LOG_ERROR, nat_module, and unload_module().

539 {
541  ast_log(LOG_ERROR, "Could not register NAT module for incoming and outgoing requests\n");
543  }
544 
546 
548 }
#define ast_log
Definition: astobj2.c:42
static pjsip_module nat_module
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:3315
#define LOG_ERROR
Definition: logger.h:285
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static struct ast_sip_session_supplement nat_supplement
Supplement for adding NAT functionality to dialog.
#define ast_sip_session_register_supplement(supplement)

◆ nat_get_contact_sip_uri()

static pjsip_sip_uri* nat_get_contact_sip_uri ( pjsip_tx_data *  tdata)
static

Helper function which returns the SIP URI of a Contact header.

Definition at line 274 of file res_pjsip_nat.c.

References NULL.

Referenced by process_nat().

275 {
276  pjsip_contact_hdr *contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
277 
278  if (!contact || (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
279  return NULL;
280  }
281 
282  return pjsip_uri_get_uri(contact->uri);
283 }
#define NULL
Definition: resample.c:96

◆ nat_incoming_invite_request()

static int nat_incoming_invite_request ( struct ast_sip_session session,
struct pjsip_rx_data *  rdata 
)
static

Function called when an INVITE goes out.

Definition at line 498 of file res_pjsip_nat.c.

References ast_sip_session::inv_session, nat_module, and NULL.

499 {
500  if (session->inv_session->state == PJSIP_INV_STATE_INCOMING) {
501  pjsip_dlg_add_usage(session->inv_session->dlg, &nat_module, NULL);
502  }
503 
504  return 0;
505 }
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
static pjsip_module nat_module

◆ nat_incoming_invite_response()

static void nat_incoming_invite_response ( struct ast_sip_session session,
struct pjsip_rx_data *  rdata 
)
static

Function called when an INVITE response comes in.

Definition at line 508 of file res_pjsip_nat.c.

References ast_sip_session::endpoint, and handle_rx_message().

509 {
510  handle_rx_message(session->endpoint, rdata);
511 }
struct ast_sip_endpoint * endpoint
static pj_bool_t handle_rx_message(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)

◆ nat_invoke_hook()

static int nat_invoke_hook ( void *  obj,
void *  arg,
int  flags 
)
static

Callback function for invoking hooks.

Definition at line 294 of file res_pjsip_nat.c.

References ast_sip_nat_hook::outgoing_external_message, nat_hook_details::tdata, and nat_hook_details::transport.

Referenced by process_nat().

295 {
296  struct ast_sip_nat_hook *hook = obj;
297  struct nat_hook_details *details = arg;
298 
299  if (hook->outgoing_external_message) {
300  hook->outgoing_external_message(details->tdata, details->transport);
301  }
302 
303  return 0;
304 }
Structure which contains hook details.
struct ast_sip_transport * transport
Chosen transport.
Structure for SIP nat hook information.
Definition: res_pjsip.h:271
void(* outgoing_external_message)(struct pjsip_tx_data *tdata, struct ast_sip_transport *transport)
Definition: res_pjsip.h:275
pjsip_tx_data * tdata
Outgoing message itself.

◆ nat_on_rx_message()

static pj_bool_t nat_on_rx_message ( pjsip_rx_data *  rdata)
static

Definition at line 228 of file res_pjsip_nat.c.

References ao2_cleanup, ast_pjsip_rdata_get_endpoint(), and handle_rx_message().

229 {
230  pj_bool_t res;
231  struct ast_sip_endpoint *endpoint;
232 
233  endpoint = ast_pjsip_rdata_get_endpoint(rdata);
234  res = handle_rx_message(endpoint, rdata);
235  ao2_cleanup(endpoint);
236  return res;
237 }
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.
static pj_bool_t handle_rx_message(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ nat_on_tx_message()

static pj_status_t nat_on_tx_message ( pjsip_tx_data *  tdata)
static

Definition at line 477 of file res_pjsip_nat.c.

References process_nat(), and restore_orig_contact_host().

477  {
478  pj_status_t rc;
479 
480  rc = process_nat(tdata);
482 
483  return rc;
484 }
static pj_status_t process_nat(pjsip_tx_data *tdata)
static void restore_orig_contact_host(pjsip_tx_data *tdata)

◆ nat_outgoing_invite_request()

static void nat_outgoing_invite_request ( struct ast_sip_session session,
struct pjsip_tx_data *  tdata 
)
static

Function called when an INVITE comes in.

Definition at line 514 of file res_pjsip_nat.c.

References ast_sip_session::inv_session, nat_module, and NULL.

515 {
516  if (session->inv_session->state == PJSIP_INV_STATE_NULL) {
517  pjsip_dlg_add_usage(session->inv_session->dlg, &nat_module, NULL);
518  }
519 }
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
static pjsip_module nat_module

◆ process_nat()

static pj_status_t process_nat ( pjsip_tx_data *  tdata)
static

Definition at line 365 of file res_pjsip_nat.c.

References ao2_callback, ao2_cleanup, ast_debug, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sip_get_sorcery(), ast_sip_get_transport_states(), ast_sip_transport_is_local, ast_sockaddr_isnull(), ast_sockaddr_parse(), ast_sockaddr_set_port, ast_sockaddr_stringify_host(), ast_sorcery_retrieve_by_fields(), ast_sorcery_retrieve_by_id(), AST_TRANSPORT_TCP, AST_TRANSPORT_TLS, AST_TRANSPORT_UDP, request_transport_details::factory, find_transport_state_in_use(), request_transport_details::local_address, request_transport_details::local_port, nat_get_contact_sip_uri(), nat_invoke_hook(), NULL, PARSE_PORT_FORBID, RAII_VAR, nat_hook_details::tdata, request_transport_details::transport, transport_states, and request_transport_details::type.

Referenced by nat_on_tx_message().

366 {
369  RAII_VAR(struct ast_sip_transport_state *, transport_state, NULL, ao2_cleanup);
370  struct request_transport_details details = { 0, };
371  pjsip_via_hdr *via = NULL;
372  struct ast_sockaddr addr = { { 0, } };
373  pjsip_sip_uri *uri = NULL;
374  RAII_VAR(struct ao2_container *, hooks, NULL, ao2_cleanup);
375 
376  /* If a transport selector is in use we know the transport or factory, so explicitly find it */
377  if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT) {
378  details.transport = tdata->tp_sel.u.transport;
379  } else if (tdata->tp_sel.type == PJSIP_TPSELECTOR_LISTENER) {
380  details.factory = tdata->tp_sel.u.listener;
381  } else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP || tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
382  /* Connectionless uses the same transport for all requests */
383  details.type = AST_TRANSPORT_UDP;
384  details.transport = tdata->tp_info.transport;
385  } else {
386  if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TCP) {
387  details.type = AST_TRANSPORT_TCP;
388  } else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TLS) {
389  details.type = AST_TRANSPORT_TLS;
390  } else {
391  /* Unknown transport type, we can't map and thus can't apply NAT changes */
392  return PJ_SUCCESS;
393  }
394 
395  if ((uri = nat_get_contact_sip_uri(tdata))) {
396  details.local_address = uri->host;
397  details.local_port = uri->port;
398  } else if ((tdata->msg->type == PJSIP_REQUEST_MSG) &&
399  (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL))) {
400  details.local_address = via->sent_by.host;
401  details.local_port = via->sent_by.port;
402  } else {
403  return PJ_SUCCESS;
404  }
405 
406  if (!details.local_port) {
407  details.local_port = (details.type == AST_TRANSPORT_TLS) ? 5061 : 5060;
408  }
409  }
410 
412  return PJ_SUCCESS;
413  }
414 
415  if (!(transport_state = ao2_callback(transport_states, 0, find_transport_state_in_use, &details))) {
416  return PJ_SUCCESS;
417  }
418 
419  if (!(transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id))) {
420  return PJ_SUCCESS;
421  }
422 
423  if (transport_state->localnet) {
424  ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID);
425  ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port);
426 
427  /* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */
428  if (ast_sip_transport_is_local(transport_state, &addr)) {
429  ast_debug(5, "Request is being sent to local address, skipping NAT manipulation\n");
430  return PJ_SUCCESS;
431  }
432  }
433 
434  if (!ast_sockaddr_isnull(&transport_state->external_signaling_address)) {
435  pjsip_cseq_hdr *cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg);
436 
437  /* Update the Contact header with the external address. We only do this if
438  * a CSeq is not present (which should not happen - but we are extra safe),
439  * if a request is being sent, or if a response is sent that is not a response
440  * to a REGISTER. We specifically don't do this for a response to a REGISTER
441  * as the Contact headers would contain the registered Contacts, and not our
442  * own Contact.
443  */
444  if (!cseq || tdata->msg->type == PJSIP_REQUEST_MSG ||
445  pjsip_method_cmp(&cseq->method, &pjsip_register_method)) {
446  /* We can only rewrite the URI when one is present */
447  if (uri || (uri = nat_get_contact_sip_uri(tdata))) {
448  pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport_state->external_signaling_address));
449  if (transport->external_signaling_port) {
450  uri->port = transport->external_signaling_port;
451  ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port);
452  }
453  }
454  }
455 
456  /* Update the via header if relevant */
457  if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) {
458  pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport_state->external_signaling_address));
459  if (transport->external_signaling_port) {
460  via->sent_by.port = transport->external_signaling_port;
461  }
462  }
463  }
464 
465  /* Invoke any additional hooks that may be registered */
467  struct nat_hook_details hook_details = {
468  .tdata = tdata,
469  .transport = transport,
470  };
471  ao2_callback(hooks, 0, nat_invoke_hook, &hook_details);
472  }
473 
474  return PJ_SUCCESS;
475 }
static int find_transport_state_in_use(void *obj, void *arg, int flags)
Callback function for finding the transport the request is going out on.
pjsip_tpfactory * factory
Potential pointer to the transport factory itself, if TCP/TLS.
Structure which contains hook details.
enum ast_transport type
Type of transport.
struct ast_sip_transport * transport
Chosen transport.
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
const ast_string_field transport
Definition: res_pjsip.h:817
pj_str_t local_address
Local address for transport.
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
pjsip_transport * transport
Potential pointer to the transport itself, if UDP.
static struct ao2_container * transport_states
Perform no matching, return all objects.
Definition: sorcery.h:123
Structure which contains information about a transport.
Return all matching objects.
Definition: sorcery.h:120
#define NULL
Definition: resample.c:96
Socket address structure.
Definition: netsock2.h:97
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. "null" in this sense essentially means uninitialized, or having a 0 length.
Definition: netsock2.h:127
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
Structure for SIP transport information.
Definition: res_pjsip.h:87
int local_port
Local port for transport.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
static int nat_invoke_hook(void *obj, void *arg, int flags)
Callback function for invoking hooks.
struct ao2_container * ast_sip_get_transport_states(void)
Retrieves all transport states.
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:537
Transport to bind to.
Definition: res_pjsip.h:171
#define ast_sip_transport_is_local(transport_state, addr)
Definition: res_pjsip.h:165
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition: sorcery.c:1897
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static pjsip_sip_uri * nat_get_contact_sip_uri(pjsip_tx_data *tdata)
Helper function which returns the SIP URI of a Contact header.
Generic container type.
static char * ast_sockaddr_stringify_host(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only, suitable for a URL (with brack...
Definition: netsock2.h:331
pjsip_tx_data * tdata
Outgoing message itself.

◆ restore_orig_contact_host()

static void restore_orig_contact_host ( pjsip_tx_data *  tdata)
static

Definition at line 306 of file res_pjsip_nat.c.

References ast_debug, AST_SIP_X_AST_ORIG_HOST, AST_SIP_X_AST_ORIG_HOST_LEN, is_sip_uri, and NULL.

Referenced by nat_on_tx_message().

307 {
308  pjsip_contact_hdr *contact;
310  pjsip_param *x_orig_host;
311  pjsip_sip_uri *uri;
312  pjsip_hdr *hdr;
313 
314  if (tdata->msg->type == PJSIP_REQUEST_MSG) {
315  if (is_sip_uri(tdata->msg->line.req.uri)) {
316  uri = pjsip_uri_get_uri(tdata->msg->line.req.uri);
317  while ((x_orig_host = pjsip_param_find(&uri->other_param, &x_name))) {
318  pj_list_erase(x_orig_host);
319  }
320  }
321  for (hdr = tdata->msg->hdr.next; hdr != &tdata->msg->hdr; hdr = hdr->next) {
322  if (hdr->type == PJSIP_H_TO) {
323  if (is_sip_uri(((pjsip_fromto_hdr *) hdr)->uri)) {
324  uri = pjsip_uri_get_uri(((pjsip_fromto_hdr *) hdr)->uri);
325  while ((x_orig_host = pjsip_param_find(&uri->other_param, &x_name))) {
326  pj_list_erase(x_orig_host);
327  }
328  }
329  }
330  }
331  }
332 
333  if (tdata->msg->type != PJSIP_RESPONSE_MSG) {
334  return;
335  }
336 
337  contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
338  while (contact) {
339  pjsip_sip_uri *contact_uri = pjsip_uri_get_uri(contact->uri);
340  x_orig_host = pjsip_param_find(&contact_uri->other_param, &x_name);
341 
342  if (x_orig_host) {
343  char host_port[x_orig_host->value.slen + 1];
344  char *sep;
345 
346  ast_debug(1, "Restoring contact %.*s:%d to %.*s\n", (int)contact_uri->host.slen,
347  contact_uri->host.ptr, contact_uri->port,
348  (int)x_orig_host->value.slen, x_orig_host->value.ptr);
349 
350  strncpy(host_port, x_orig_host->value.ptr, x_orig_host->value.slen);
351  host_port[x_orig_host->value.slen] = '\0';
352  sep = strchr(host_port, ':');
353  if (sep) {
354  *sep = '\0';
355  sep++;
356  pj_strdup2(tdata->pool, &contact_uri->host, host_port);
357  contact_uri->port = strtol(sep, NULL, 10);
358  }
359  pj_list_erase(x_orig_host);
360  }
361  contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, contact->next);
362  }
363 }
#define is_sip_uri(uri)
Definition: res_pjsip_nat.c:40
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define AST_SIP_X_AST_ORIG_HOST_LEN
Definition: res_pjsip_nat.c:38
#define AST_SIP_X_AST_ORIG_HOST
Definition: res_pjsip_nat.c:37
pjsip_tx_data * tdata
Outgoing message itself.

◆ rewrite_contact()

static int rewrite_contact ( pjsip_rx_data *  rdata,
pjsip_dialog *  dlg 
)
static

Definition at line 179 of file res_pjsip_nat.c.

References NULL, and rewrite_uri().

Referenced by handle_rx_message().

180 {
181  pjsip_contact_hdr *contact;
182 
183  contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
184  if (contact && !contact->star && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
185  pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);
186 
187  rewrite_uri(rdata, uri, rdata->tp_info.pool);
188 
189  if (dlg && pj_list_empty(&dlg->route_set) && (!dlg->remote.contact
190  || pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, dlg->remote.contact->uri, contact->uri))) {
191  dlg->remote.contact = (pjsip_contact_hdr*)pjsip_hdr_clone(dlg->pool, contact);
192  dlg->target = dlg->remote.contact->uri;
193  }
194  return 0;
195  }
196 
197  return -1;
198 }
#define NULL
Definition: resample.c:96
static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri, pj_pool_t *pool)
Definition: res_pjsip_nat.c:69

◆ rewrite_route_set()

static int rewrite_route_set ( pjsip_rx_data *  rdata,
pjsip_dialog *  dlg 
)
static

Record-Route header has no meaning in REGISTER requests and should be ignored

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

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

Definition at line 116 of file res_pjsip_nat.c.

References NULL, and rewrite_uri().

Referenced by handle_rx_message().

117 {
118  pjsip_rr_hdr *rr = NULL;
119  pjsip_sip_uri *uri;
120  int res = -1;
121  int ignore_rr = 0;
122  int pubsub = 0;
123 
124  if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG) {
125  pjsip_hdr *iter;
126  for (iter = rdata->msg_info.msg->hdr.prev; iter != &rdata->msg_info.msg->hdr; iter = iter->prev) {
127  if (iter->type == PJSIP_H_RECORD_ROUTE) {
128  rr = (pjsip_rr_hdr *)iter;
129  break;
130  }
131  }
132  } else if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method)) {
133  rr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_RECORD_ROUTE, NULL);
134  } else {
135  /**
136  * Record-Route header has no meaning in REGISTER requests
137  * and should be ignored
138  */
139  ignore_rr = 1;
140  }
141 
142  if (!pjsip_method_cmp(&rdata->msg_info.cseq->method, &pjsip_subscribe_method) ||
143  !pjsip_method_cmp(&rdata->msg_info.cseq->method, &pjsip_notify_method)) {
144  /**
145  * There is currently no good way to get the dlg object for a pubsub dialog
146  * so we will just look at the rr & contact of the current message and
147  * hope for the best
148  */
149  pubsub = 1;
150  }
151 
152  if (rr) {
153  uri = pjsip_uri_get_uri(&rr->name_addr);
154  rewrite_uri(rdata, uri, rdata->tp_info.pool);
155  res = 0;
156  }
157 
158  if (dlg && !pj_list_empty(&dlg->route_set) && !dlg->route_set_frozen) {
159  pjsip_routing_hdr *route = dlg->route_set.next;
160  uri = pjsip_uri_get_uri(&route->name_addr);
161  rewrite_uri(rdata, uri, dlg->pool);
162  res = 0;
163  }
164 
165  if (!dlg && !rr && !ignore_rr && !pubsub && rdata->msg_info.to->tag.slen){
166  /**
167  * Even if this message doesn't have any route headers
168  * the dialog may, so wait until a later invocation that
169  * has a dialog reference to make sure there isn't a
170  * previously saved routset in the dialog before deciding
171  * the contact needs to be modified
172  */
173  res = 0;
174  }
175 
176  return res;
177 }
#define NULL
Definition: resample.c:96
static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri, pj_pool_t *pool)
Definition: res_pjsip_nat.c:69

◆ rewrite_uri()

static void rewrite_uri ( pjsip_rx_data *  rdata,
pjsip_sip_uri *  uri,
pj_pool_t *  pool 
)
static

Definition at line 69 of file res_pjsip_nat.c.

References save_orig_contact_host().

Referenced by rewrite_contact(), and rewrite_route_set().

70 {
71 
72  if (pj_strcmp2(&uri->host, rdata->pkt_info.src_name) != 0) {
73  save_orig_contact_host(rdata, uri);
74  }
75 
76  pj_strdup2(pool, &uri->host, rdata->pkt_info.src_name);
77  uri->port = rdata->pkt_info.src_port;
78  if (!strcasecmp("WSS", rdata->tp_info.transport->type_name)) {
79  /* WSS is special, we don't want to overwrite the URI at all as it needs to be ws */
80  } else if (strcasecmp("udp", rdata->tp_info.transport->type_name)) {
81  uri->transport_param = pj_str(rdata->tp_info.transport->type_name);
82  } else {
83  uri->transport_param.slen = 0;
84  }
85 }
static pj_pool_t * pool
Global memory pool for configuration and timers.
static void save_orig_contact_host(pjsip_rx_data *rdata, pjsip_sip_uri *uri)
Definition: res_pjsip_nat.c:43

◆ save_orig_contact_host()

static void save_orig_contact_host ( pjsip_rx_data *  rdata,
pjsip_sip_uri *  uri 
)
static

Definition at line 43 of file res_pjsip_nat.c.

References ast_debug, AST_SIP_X_AST_ORIG_HOST, COLON_LEN, and MAX_PORT_LEN.

Referenced by rewrite_uri().

44 {
45  pjsip_param *x_orig_host;
46  pj_str_t p_value;
47 #define COLON_LEN 1
48 #define MAX_PORT_LEN 5
49 
50  if (rdata->msg_info.msg->type != PJSIP_REQUEST_MSG ||
51  rdata->msg_info.msg->line.req.method.id != PJSIP_REGISTER_METHOD) {
52  return;
53  }
54 
55  ast_debug(1, "Saving contact '%.*s:%d'\n",
56  (int)uri->host.slen, uri->host.ptr, uri->port);
57 
58  x_orig_host = PJ_POOL_ALLOC_T(rdata->tp_info.pool, pjsip_param);
59  x_orig_host->name = pj_strdup3(rdata->tp_info.pool, AST_SIP_X_AST_ORIG_HOST);
60  p_value.slen = pj_strlen(&uri->host) + COLON_LEN + MAX_PORT_LEN;
61  p_value.ptr = (char*)pj_pool_alloc(rdata->tp_info.pool, p_value.slen + 1);
62  p_value.slen = snprintf(p_value.ptr, p_value.slen + 1, "%.*s:%d", (int)uri->host.slen, uri->host.ptr, uri->port);
63  pj_strassign(&x_orig_host->value, &p_value);
64  pj_list_insert_before(&uri->other_param, x_orig_host);
65 
66  return;
67 }
#define COLON_LEN
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define MAX_PORT_LEN
#define AST_SIP_X_AST_ORIG_HOST
Definition: res_pjsip_nat.c:37

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 531 of file res_pjsip_nat.c.

References ast_sip_session_unregister_supplement(), ast_sip_unregister_service(), and nat_module.

Referenced by load_module().

532 {
535  return 0;
536 }
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.
Definition: pjsip_session.c:63
static pjsip_module nat_module
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:3331
static struct ast_sip_session_supplement nat_supplement
Supplement for adding NAT functionality to dialog.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP NAT Support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip,res_pjsip_session", }
static

Definition at line 556 of file res_pjsip_nat.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 556 of file res_pjsip_nat.c.

◆ nat_module

pjsip_module nat_module
static

◆ nat_supplement

struct ast_sip_session_supplement nat_supplement
static

Supplement for adding NAT functionality to dialog.

Definition at line 522 of file res_pjsip_nat.c.