Asterisk - The Open Source Telephony Project  18.5.0
res_pjsip_nat.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Joshua Colp <[email protected]>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*** MODULEINFO
20  <depend>pjproject</depend>
21  <depend>res_pjsip</depend>
22  <depend>res_pjsip_session</depend>
23  <support_level>core</support_level>
24  ***/
25 
26 #include "asterisk.h"
27 
28 #include <pjsip.h>
29 #include <pjsip_ua.h>
30 
31 #include "asterisk/res_pjsip.h"
33 #include "asterisk/module.h"
34 #include "asterisk/acl.h"
35 
36 /*! URI parameter for original host/port */
37 #define AST_SIP_X_AST_ORIG_HOST "x-ast-orig-host"
38 #define AST_SIP_X_AST_ORIG_HOST_LEN 15
39 
40 #define is_sip_uri(uri) \
41  (PJSIP_URI_SCHEME_IS_SIP(uri) || PJSIP_URI_SCHEME_IS_SIPS(uri))
42 
43 static void save_orig_contact_host(pjsip_rx_data *rdata, pjsip_sip_uri *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 }
68 
69 static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri, pj_pool_t *pool)
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 }
86 
87 /*
88  * Update the Record-Route headers in the request or response and in the dialog
89  * object if exists.
90  *
91  * When NAT is in use, the address of the next hop in the SIP may be incorrect.
92  * To address this asterisk uses two strategies in parallel:
93  * 1. intercept the messages at the transaction level and rewrite the
94  * messages before arriving at the dialog layer
95  * 2. after the application processing, update the dialog object with the
96  * correct information
97  *
98  * The first strategy has a limitation that the SIP message may not have all
99  * the information required to determine if the next hop is in the route set
100  * or in the contact. Causing risk that asterisk will update the Contact on
101  * receipt of an in-dialog message despite there being a route set saved in
102  * the dialog.
103  *
104  * The second strategy has a limitation that not all UAC layers have interfaces
105  * available to invoke this module after dialog creation. (pjsip_sesion does
106  * but pjsip_pubsub does not), thus this strategy can't update the dialog in
107  * all cases needed.
108  *
109  * The ideal solution would be to implement an "incomming_request" event
110  * in pubsub module that can then pass the dialog object to this module
111  * on SUBSCRIBE, this module then should add itself as a listener to the dialog
112  * for the subsequent requests and responses & then be able to properly update
113  * the dialog object for all required events.
114  */
115 
116 static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg)
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 }
178 
179 static int rewrite_contact(pjsip_rx_data *rdata, pjsip_dialog *dlg)
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 }
199 
200 static pj_bool_t handle_rx_message(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
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 }
227 
228 static pj_bool_t nat_on_rx_message(pjsip_rx_data *rdata)
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 }
238 
239 /*! \brief Structure which contains information about a transport */
241  /*! \brief Type of transport */
243  /*! \brief Potential pointer to the transport itself, if UDP */
244  pjsip_transport *transport;
245  /*! \brief Potential pointer to the transport factory itself, if TCP/TLS */
246  pjsip_tpfactory *factory;
247  /*! \brief Local address for transport */
248  pj_str_t local_address;
249  /*! \brief Local port for transport */
251 };
252 
253 /*! \brief Callback function for finding the transport the request is going out on */
254 static int find_transport_state_in_use(void *obj, void *arg, int flags)
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 }
272 
273 /*! \brief Helper function which returns the SIP URI of a Contact header */
274 static pjsip_sip_uri *nat_get_contact_sip_uri(pjsip_tx_data *tdata)
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 }
284 
285 /*! \brief Structure which contains hook details */
287  /*! \brief Outgoing message itself */
288  pjsip_tx_data *tdata;
289  /*! \brief Chosen transport */
291 };
292 
293 /*! \brief Callback function for invoking hooks */
294 static int nat_invoke_hook(void *obj, void *arg, int flags)
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 }
305 
306 static void restore_orig_contact_host(pjsip_tx_data *tdata)
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 }
364 
365 static pj_status_t process_nat(pjsip_tx_data *tdata)
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 }
476 
477 static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata) {
478  pj_status_t rc;
479 
480  rc = process_nat(tdata);
482 
483  return rc;
484 }
485 
486 
487 static pjsip_module nat_module = {
488  .name = { "NAT", 3 },
489  .id = -1,
490  .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 2,
491  .on_rx_request = nat_on_rx_message,
492  .on_rx_response = nat_on_rx_message,
493  .on_tx_request = nat_on_tx_message,
494  .on_tx_response = nat_on_tx_message,
495 };
496 
497 /*! \brief Function called when an INVITE goes out */
498 static int nat_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
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 }
506 
507 /*! \brief Function called when an INVITE response comes in */
508 static void nat_incoming_invite_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
509 {
510  handle_rx_message(session->endpoint, rdata);
511 }
512 
513 /*! \brief Function called when an INVITE comes in */
514 static void nat_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
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 }
520 
521 /*! \brief Supplement for adding NAT functionality to dialog */
523  .method = "INVITE",
524  .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST + 1,
525  .incoming_request = nat_incoming_invite_request,
526  .outgoing_request = nat_outgoing_invite_request,
527  .incoming_response = nat_incoming_invite_response,
528 };
529 
530 
531 static int unload_module(void)
532 {
533  ast_sip_session_unregister_supplement(&nat_supplement);
535  return 0;
536 }
537 
538 static int load_module(void)
539 {
541  ast_log(LOG_ERROR, "Could not register NAT module for incoming and outgoing requests\n");
543  }
544 
545  ast_sip_session_register_supplement(&nat_supplement);
546 
548 }
549 
551  .support_level = AST_MODULE_SUPPORT_CORE,
552  .load = load_module,
553  .unload = unload_module,
554  .load_pri = AST_MODPRI_APP_DEPEND,
555  .requires = "res_pjsip,res_pjsip_session",
556 );
enum ast_transport type
Definition: res_pjsip.h:101
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.
struct ast_sip_endpoint * endpoint
enum ast_transport type
Type of transport.
Asterisk main include file. File version handling, generic pbx functions.
struct ast_sip_transport * transport
Chosen transport.
static int unload_module(void)
static void nat_incoming_invite_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
Function called when an INVITE response comes in.
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
struct ast_sip_endpoint_nat_configuration nat
Definition: res_pjsip.h:845
ast_transport
Definition: netsock2.h:59
pj_str_t local_address
Local address for transport.
#define is_sip_uri(uri)
Definition: res_pjsip_nat.c:40
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
pjsip_transport * transport
Potential pointer to the transport itself, if UDP.
static pj_bool_t nat_on_rx_message(pjsip_rx_data *rdata)
static pj_pool_t * pool
Global memory pool for configuration and timers.
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
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
#define NULL
Definition: resample.c:96
static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg)
struct pjsip_inv_session * inv_session
Socket address structure.
Definition: netsock2.h:97
A structure describing a SIP session.
#define COLON_LEN
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 void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri, pj_pool_t *pool)
Definition: res_pjsip_nat.c:69
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 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
static pj_bool_t handle_rx_message(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
Structure for SIP nat hook information.
Definition: res_pjsip.h:271
#define AST_SIP_X_AST_ORIG_HOST_LEN
Definition: res_pjsip_nat.c:38
static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata)
Structure for SIP transport information.
Definition: res_pjsip.h:87
void(* outgoing_external_message)(struct pjsip_tx_data *tdata, struct ast_sip_transport *transport)
Definition: res_pjsip.h:275
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
struct pjsip_transport * transport
Transport itself.
Definition: res_pjsip.h:89
static pjsip_module nat_module
static struct ast_mansession session
Access Control of various sorts.
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
static int nat_invoke_hook(void *obj, void *arg, int flags)
Callback function for invoking hooks.
#define MAX_PORT_LEN
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:3315
static void save_orig_contact_host(pjsip_rx_data *rdata, pjsip_sip_uri *uri)
Definition: res_pjsip_nat.c:43
struct ao2_container * ast_sip_get_transport_states(void)
Retrieves all transport states.
#define LOG_ERROR
Definition: logger.h:285
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:537
static int nat_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
Function called when an INVITE goes out.
Transport to bind to.
Definition: res_pjsip.h:171
static pj_status_t process_nat(pjsip_tx_data *tdata)
#define ast_sip_transport_is_local(transport_state, addr)
Definition: res_pjsip.h:165
struct pjsip_tpfactory * factory
Transport factory.
Definition: res_pjsip.h:91
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
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
A supplement to SIP message processing.
static int load_module(void)
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 void restore_orig_contact_host(pjsip_tx_data *tdata)
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.
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 int rewrite_contact(pjsip_rx_data *rdata, pjsip_dialog *dlg)
#define AST_SIP_X_AST_ORIG_HOST
Definition: res_pjsip_nat.c:37
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
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.
static void nat_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
Function called when an INVITE comes in.
#define ast_sip_session_register_supplement(supplement)