Asterisk - The Open Source Telephony Project  21.4.1
res_pjsip_nat.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
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"
32 #include "asterisk/res_pjsip_session.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 static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg)
116 {
117  pjsip_rr_hdr *rr = NULL;
118  pjsip_sip_uri *uri;
119  int res = -1;
120  int ignore_rr = 0;
121  int pubsub = 0;
122 
123  if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG) {
124  pjsip_hdr *iter;
125  for (iter = rdata->msg_info.msg->hdr.prev; iter != &rdata->msg_info.msg->hdr; iter = iter->prev) {
126  if (iter->type == PJSIP_H_RECORD_ROUTE) {
127  rr = (pjsip_rr_hdr *)iter;
128  break;
129  }
130  }
131  } else if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method)) {
132  rr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_RECORD_ROUTE, NULL);
133  } else {
134  /**
135  * Record-Route header has no meaning in REGISTER requests
136  * and should be ignored
137  */
138  ignore_rr = 1;
139  }
140 
141  if (!pjsip_method_cmp(&rdata->msg_info.cseq->method, &pjsip_subscribe_method) ||
142  !pjsip_method_cmp(&rdata->msg_info.cseq->method, &pjsip_notify_method)) {
143  /**
144  * There is currently no good way to get the dlg object for a pubsub dialog
145  * so we will just look at the rr & contact of the current message and
146  * hope for the best
147  */
148  pubsub = 1;
149  }
150 
151  if (rr) {
152  uri = pjsip_uri_get_uri(&rr->name_addr);
153  rewrite_uri(rdata, uri, rdata->tp_info.pool);
154  res = 0;
155  }
156 
157  if (dlg && !pj_list_empty(&dlg->route_set) && !dlg->route_set_frozen) {
158  pjsip_routing_hdr *route = dlg->route_set.next;
159  uri = pjsip_uri_get_uri(&route->name_addr);
160  rewrite_uri(rdata, uri, dlg->pool);
161  res = 0;
162  }
163 
164  if (!dlg && !rr && !ignore_rr && !pubsub && rdata->msg_info.to->tag.slen){
165  /**
166  * Even if this message doesn't have any route headers
167  * the dialog may, so wait until a later invocation that
168  * has a dialog reference to make sure there isn't a
169  * previously saved routset in the dialog before deciding
170  * the contact needs to be modified
171  */
172  res = 0;
173  }
174 
175  return res;
176 }
177 
178 static int rewrite_contact(pjsip_rx_data *rdata, pjsip_dialog *dlg)
179 {
180  pjsip_contact_hdr *contact;
181 
182  contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
183  if (contact && !contact->star && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
184  pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);
185 
186  rewrite_uri(rdata, uri, rdata->tp_info.pool);
187 
188  if (dlg && pj_list_empty(&dlg->route_set) && (!dlg->remote.contact
189  || pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, dlg->remote.contact->uri, contact->uri))) {
190  dlg->remote.contact = (pjsip_contact_hdr*)pjsip_hdr_clone(dlg->pool, contact);
191  dlg->target = dlg->remote.contact->uri;
192  }
193  return 0;
194  }
195 
196  return -1;
197 }
198 
199 static pj_bool_t handle_rx_message(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
200 {
201  pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
202 
203  if (!endpoint) {
204  return PJ_FALSE;
205  }
206 
207  if (endpoint->nat.rewrite_contact) {
208  /* rewrite_contact is intended to ensure we send requests/responses to
209  * a routable address when NAT is involved. The URI that dictates where
210  * we send requests/responses can be determined either by Record-Route
211  * headers or by the Contact header if no Record-Route headers are present.
212  * We therefore will attempt to rewrite a Record-Route header first, and if
213  * none are present, we fall back to rewriting the Contact header instead.
214  */
215  if (rewrite_route_set(rdata, dlg)) {
216  rewrite_contact(rdata, dlg);
217  }
218  }
219 
220  if (endpoint->nat.force_rport) {
221  rdata->msg_info.via->rport_param = rdata->pkt_info.src_port;
222  }
223 
224  return PJ_FALSE;
225 }
226 
227 static pj_bool_t nat_on_rx_message(pjsip_rx_data *rdata)
228 {
229  pj_bool_t res;
230  struct ast_sip_endpoint *endpoint;
231 
232  endpoint = ast_pjsip_rdata_get_endpoint(rdata);
233  res = handle_rx_message(endpoint, rdata);
234  ao2_cleanup(endpoint);
235  return res;
236 }
237 
238 /*! \brief Structure which contains hook details */
240  /*! \brief Outgoing message itself */
241  pjsip_tx_data *tdata;
242  /*! \brief Chosen transport */
244 };
245 
246 /*! \brief Callback function for invoking hooks */
247 static int nat_invoke_hook(void *obj, void *arg, int flags)
248 {
249  struct ast_sip_nat_hook *hook = obj;
250  struct nat_hook_details *details = arg;
251 
252  if (hook->outgoing_external_message) {
253  hook->outgoing_external_message(details->tdata, details->transport);
254  }
255 
256  return 0;
257 }
258 
259 static void restore_orig_contact_host(pjsip_tx_data *tdata)
260 {
261  pjsip_contact_hdr *contact;
262  pj_str_t x_name = { AST_SIP_X_AST_ORIG_HOST, AST_SIP_X_AST_ORIG_HOST_LEN };
263  pjsip_param *x_orig_host;
264  pjsip_sip_uri *uri;
265  pjsip_hdr *hdr;
266 
267  if (tdata->msg->type == PJSIP_REQUEST_MSG) {
268  if (is_sip_uri(tdata->msg->line.req.uri)) {
269  uri = pjsip_uri_get_uri(tdata->msg->line.req.uri);
270  while ((x_orig_host = pjsip_param_find(&uri->other_param, &x_name))) {
271  pj_list_erase(x_orig_host);
272  }
273  }
274  for (hdr = tdata->msg->hdr.next; hdr != &tdata->msg->hdr; hdr = hdr->next) {
275  if (hdr->type == PJSIP_H_TO) {
276  if (is_sip_uri(((pjsip_fromto_hdr *) hdr)->uri)) {
277  uri = pjsip_uri_get_uri(((pjsip_fromto_hdr *) hdr)->uri);
278  while ((x_orig_host = pjsip_param_find(&uri->other_param, &x_name))) {
279  pj_list_erase(x_orig_host);
280  }
281  }
282  }
283  }
284  }
285 
286  if (tdata->msg->type != PJSIP_RESPONSE_MSG) {
287  return;
288  }
289 
290  contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
291  while (contact) {
292  pjsip_sip_uri *contact_uri = pjsip_uri_get_uri(contact->uri);
293  x_orig_host = pjsip_param_find(&contact_uri->other_param, &x_name);
294 
295  if (x_orig_host) {
296  char host_port[x_orig_host->value.slen + 1];
297  char *sep;
298 
299  ast_debug(1, "Restoring contact %.*s:%d to %.*s\n", (int)contact_uri->host.slen,
300  contact_uri->host.ptr, contact_uri->port,
301  (int)x_orig_host->value.slen, x_orig_host->value.ptr);
302 
303  strncpy(host_port, x_orig_host->value.ptr, x_orig_host->value.slen);
304  host_port[x_orig_host->value.slen] = '\0';
305  sep = strchr(host_port, ':');
306  if (sep) {
307  *sep = '\0';
308  sep++;
309  pj_strdup2(tdata->pool, &contact_uri->host, host_port);
310  contact_uri->port = strtol(sep, NULL, 10);
311  }
312  pj_list_erase(x_orig_host);
313  }
314  contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, contact->next);
315  }
316 }
317 
318 static pj_status_t process_nat(pjsip_tx_data *tdata)
319 {
320  RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
321  RAII_VAR(struct ast_sip_transport_state *, transport_state, NULL, ao2_cleanup);
322  struct ast_sip_request_transport_details details = { 0, };
323  pjsip_via_hdr *via = NULL;
324  struct ast_sockaddr addr = { { 0, } };
325  pjsip_sip_uri *uri = NULL;
326  RAII_VAR(struct ao2_container *, hooks, NULL, ao2_cleanup);
327 
328  if (ast_sip_set_request_transport_details(&details, tdata, 0)) {
329  return PJ_SUCCESS;
330  }
331 
332  uri = ast_sip_get_contact_sip_uri(tdata);
333  via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
334 
335  if (!(transport_state = ast_sip_find_transport_state_in_use(&details))) {
336  return PJ_SUCCESS;
337  }
338 
339  if (!(transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id))) {
340  return PJ_SUCCESS;
341  }
342 
343  if (transport_state->localnet) {
344  ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID);
345  ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port);
346 
347  /* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */
348  if (ast_sip_transport_is_local(transport_state, &addr)) {
349  ast_debug(5, "Request is being sent to local address, skipping NAT manipulation\n");
350  return PJ_SUCCESS;
351  }
352  }
353 
354  if (!ast_sockaddr_isnull(&transport_state->external_signaling_address)) {
355  pjsip_cseq_hdr *cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg);
356 
357  /* Update the Contact header with the external address. We only do this if
358  * a CSeq is not present (which should not happen - but we are extra safe),
359  * if a request is being sent, or if a response is sent that is not a response
360  * to a REGISTER. We specifically don't do this for a response to a REGISTER
361  * as the Contact headers would contain the registered Contacts, and not our
362  * own Contact.
363  */
364  if (!cseq || tdata->msg->type == PJSIP_REQUEST_MSG ||
365  pjsip_method_cmp(&cseq->method, &pjsip_register_method)) {
366  /* We can only rewrite the URI when one is present */
367  if (uri || (uri = ast_sip_get_contact_sip_uri(tdata))) {
368  pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport_state->external_signaling_address));
369  if (transport->external_signaling_port) {
370  uri->port = transport->external_signaling_port;
371  ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port);
372  }
373  }
374  }
375 
376  /* Update the via header if relevant */
377  if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) {
378  pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport_state->external_signaling_address));
379  if (transport->external_signaling_port) {
380  via->sent_by.port = transport->external_signaling_port;
381  }
382  }
383  }
384 
385  /* Invoke any additional hooks that may be registered */
386  if ((hooks = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "nat_hook", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
387  struct nat_hook_details hook_details = {
388  .tdata = tdata,
389  .transport = transport,
390  };
391  ao2_callback(hooks, 0, nat_invoke_hook, &hook_details);
392  }
393 
394  return PJ_SUCCESS;
395 }
396 
397 static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata) {
398  pj_status_t rc;
399 
400  rc = process_nat(tdata);
401  restore_orig_contact_host(tdata);
402 
403  return rc;
404 }
405 
406 
407 static pjsip_module nat_module = {
408  .name = { "NAT", 3 },
409  .id = -1,
410  .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 2,
411  .on_rx_request = nat_on_rx_message,
412  .on_rx_response = nat_on_rx_message,
413  .on_tx_request = nat_on_tx_message,
414  .on_tx_response = nat_on_tx_message,
415 };
416 
417 /*! \brief Function called when an INVITE goes out */
418 static int nat_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
419 {
420  if (session->inv_session->state == PJSIP_INV_STATE_INCOMING) {
421  pjsip_dlg_add_usage(session->inv_session->dlg, &nat_module, NULL);
422  }
423 
424  return 0;
425 }
426 
427 /*! \brief Function called when an INVITE response comes in */
428 static void nat_incoming_invite_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
429 {
430  handle_rx_message(session->endpoint, rdata);
431 }
432 
433 /*! \brief Function called when an INVITE comes in */
434 static void nat_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
435 {
436  if (session->inv_session->state == PJSIP_INV_STATE_NULL) {
437  pjsip_dlg_add_usage(session->inv_session->dlg, &nat_module, NULL);
438  }
439 }
440 
441 /*! \brief Supplement for adding NAT functionality to dialog */
442 static struct ast_sip_session_supplement nat_supplement = {
443  .method = "INVITE",
444  .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST + 1,
445  .incoming_request = nat_incoming_invite_request,
446  .outgoing_request = nat_outgoing_invite_request,
447  .incoming_response = nat_incoming_invite_response,
448 };
449 
450 
451 static int unload_module(void)
452 {
453  ast_sip_session_unregister_supplement(&nat_supplement);
454  ast_sip_unregister_service(&nat_module);
455  return 0;
456 }
457 
458 static int load_module(void)
459 {
460  if (ast_sip_register_service(&nat_module)) {
461  ast_log(LOG_ERROR, "Could not register NAT module for incoming and outgoing requests\n");
463  }
464 
465  ast_sip_session_register_supplement(&nat_supplement);
466 
468 }
469 
470 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP NAT Support",
471  .support_level = AST_MODULE_SUPPORT_CORE,
472  .load = load_module,
473  .unload = unload_module,
474  .load_pri = AST_MODPRI_APP_DEPEND,
475  .requires = "res_pjsip,res_pjsip_session",
476 );
Structure which contains hook details.
struct ast_sip_endpoint * endpoint
Asterisk main include file. File version handling, generic pbx functions.
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
struct ast_sip_endpoint_nat_configuration nat
Definition: res_pjsip.h:984
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:1693
static pj_pool_t * pool
Global memory pool for configuration and timers.
Perform no matching, return all objects.
Definition: sorcery.h:123
Return all matching objects.
Definition: sorcery.h:120
struct pjsip_inv_session * inv_session
Socket address structure.
Definition: netsock2.h:97
A structure describing a SIP session.
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
Structure for SIP nat hook information.
Definition: res_pjsip.h:329
Structure for SIP transport information.
Definition: res_pjsip.h:119
void(* outgoing_external_message)(struct pjsip_tx_data *tdata, struct ast_sip_transport *transport)
Definition: res_pjsip.h:333
Access Control of various sorts.
#define ast_debug(level,...)
Log a DEBUG message.
An entity with which Asterisk communicates.
Definition: res_pjsip.h:949
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:532
Transport to bind to.
Definition: res_pjsip.h:221
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
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.
Generic container type.
Structure which contains information about a transport.
Definition: res_pjsip.h:337
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
#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:941
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:327
pjsip_tx_data * tdata
Outgoing message itself.