Asterisk - The Open Source Telephony Project GIT-master-6144b6b
Loading...
Searching...
No Matches
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 "asterisk/strings.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...
 

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 pj_bool_t handle_rx_message (struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
 
static int load_module (void)
 
static int nat_incoming_invite_request (struct ast_sip_session *session, struct pjsip_rx_data *rdata)
 Function called when an INVITE goes out.
 
static void nat_incoming_invite_response (struct ast_sip_session *session, struct pjsip_rx_data *rdata)
 Function called when an INVITE response comes in.
 
static int nat_invoke_hook (void *obj, void *arg, int flags)
 Callback function for invoking hooks.
 
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.
 
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 = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .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.
 

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 38 of file res_pjsip_nat.c.

◆ AST_SIP_X_AST_ORIG_HOST_LEN

#define AST_SIP_X_AST_ORIG_HOST_LEN   15

Definition at line 39 of file res_pjsip_nat.c.

◆ COLON_LEN

#define COLON_LEN   1

◆ is_sip_uri

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

Definition at line 41 of file res_pjsip_nat.c.

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
69static 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 */
115static 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
178static 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
199static 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
227static 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 */
239struct nat_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 */
247static 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
259static void restore_orig_contact_host(pjsip_tx_data *tdata)
260{
261 pjsip_contact_hdr *contact;
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
318static pj_status_t process_nat(pjsip_tx_data *tdata)
319{
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 const char *transport_type_name = "unknown";
328
329 if (ast_sip_set_request_transport_details(&details, tdata, 0)) {
330 ast_debug(4, "Unable to process message for transport type '%s'\n", transport_type_name);
331 return PJ_SUCCESS;
332 }
333
334 if (details.transport) {
335 transport_type_name = details.transport->type_name;
336 } else if (details.factory) {
337 transport_type_name = details.factory->type_name;
338 }
339
340 ast_debug(4, "Processing outgoing message for transport type '%s'\n", transport_type_name);
341
342 uri = ast_sip_get_contact_sip_uri(tdata);
343 via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
344
345 if (!(transport_state = ast_sip_find_transport_state_in_use(&details))) {
346 return PJ_SUCCESS;
347 }
348
349 ast_debug(4, "Found transport state '%s' for type '%s'\n", transport_state->id,
350 transport_type_name);
351
352 if (!(transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id))) {
353 ast_debug(4, "Unable to find transport for transport state '%s' type '%s'\n", transport_state->id,
354 transport_type_name);
355 return PJ_SUCCESS;
356 }
357
358 ast_debug(4, "Found transport '%s' for transport state '%s' type '%s'\n",
359 ast_sorcery_object_get_id(transport),
360 transport_state->id, transport_type_name);
361
362 if (transport_state->localnet) {
363 ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID);
364 ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port);
365
366 /* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */
367 if (ast_sip_transport_is_local(transport_state, &addr)) {
368 ast_debug(4, "Request is being sent to local address, skipping NAT manipulation\n");
369 return PJ_SUCCESS;
370 }
371 }
372
373 if (!ast_sockaddr_isnull(&transport_state->external_signaling_address) ||
374 !ast_strlen_zero(transport->external_signaling_hostname)) {
375 pjsip_cseq_hdr *cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg);
376 const char *signaling_host = !ast_strlen_zero(transport->external_signaling_hostname) ?
377 transport->external_signaling_hostname :
378 ast_sockaddr_stringify_host(&transport_state->external_signaling_address);
379
380 /* Update the Contact header with the external address. We only do this if
381 * a CSeq is not present (which should not happen - but we are extra safe),
382 * if a request is being sent, or if a response is sent that is not a response
383 * to a REGISTER. We specifically don't do this for a response to a REGISTER
384 * as the Contact headers would contain the registered Contacts, and not our
385 * own Contact. Nor do we do it for a 302 response to an INVITE request.
386 */
387 if ((!cseq || tdata->msg->type == PJSIP_REQUEST_MSG ||
388 pjsip_method_cmp(&cseq->method, &pjsip_register_method)) &&
389 (tdata->msg->type != PJSIP_RESPONSE_MSG ||
390 pjsip_method_cmp(&cseq->method, &pjsip_invite_method) ||
391 tdata->msg->line.status.code != PJSIP_SC_MOVED_TEMPORARILY )) {
392 /* We can only rewrite the URI when one is present */
393 if (uri || (uri = ast_sip_get_contact_sip_uri(tdata))) {
394 pj_strdup2(tdata->pool, &uri->host, signaling_host);
395 if (transport->external_signaling_port) {
396 uri->port = transport->external_signaling_port;
397 ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port);
398 }
399 }
400 }
401
402 /* Update the via header if relevant */
403 if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) {
404 pj_strdup2(tdata->pool, &via->sent_by.host, signaling_host);
405 if (transport->external_signaling_port) {
406 via->sent_by.port = transport->external_signaling_port;
407 }
408 }
409 }
410
411 /* Invoke any additional hooks that may be registered */
413 struct nat_hook_details hook_details = {
414 .tdata = tdata,
415 .transport = transport,
416 };
417 ao2_callback(hooks, 0, nat_invoke_hook, &hook_details);
418 }
419
420 return PJ_SUCCESS;
421}
422
423static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata) {
424 pj_status_t rc;
425
426 rc = process_nat(tdata);
428
429 return rc;
430}
431
432
433static pjsip_module nat_module = {
434 .name = { "NAT", 3 },
435 .id = -1,
436 .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 2,
437 .on_rx_request = nat_on_rx_message,
438 .on_rx_response = nat_on_rx_message,
439 .on_tx_request = nat_on_tx_message,
440 .on_tx_response = nat_on_tx_message,
441};
442
443/*! \brief Function called when an INVITE goes out */
444static int nat_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
445{
446 if (session->inv_session->state == PJSIP_INV_STATE_INCOMING) {
447 pjsip_dlg_add_usage(session->inv_session->dlg, &nat_module, NULL);
448 }
449
450 return 0;
451}
452
453/*! \brief Function called when an INVITE response comes in */
454static void nat_incoming_invite_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
455{
456 handle_rx_message(session->endpoint, rdata);
457}
458
459/*! \brief Function called when an INVITE comes in */
460static void nat_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
461{
462 if (session->inv_session->state == PJSIP_INV_STATE_NULL) {
463 pjsip_dlg_add_usage(session->inv_session->dlg, &nat_module, NULL);
464 }
465}
466
467/*! \brief Supplement for adding NAT functionality to dialog */
469 .method = "INVITE",
470 .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST + 1,
471 .incoming_request = nat_incoming_invite_request,
472 .outgoing_request = nat_outgoing_invite_request,
473 .incoming_response = nat_incoming_invite_response,
474};
475
476
477static int unload_module(void)
478{
481 return 0;
482}
483
484static int load_module(void)
485{
487 ast_log(LOG_ERROR, "Could not register NAT module for incoming and outgoing requests\n");
489 }
490
492
494}
495
497 .support_level = AST_MODULE_SUPPORT_CORE,
498 .load = load_module,
499 .unload = unload_module,
500 .load_pri = AST_MODPRI_APP_DEPEND,
501 .requires = "res_pjsip,res_pjsip_session",
502);
static struct ast_mansession session
#define ast_log
Definition astobj2.c:42
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
@ AST_MODFLAG_LOAD_ORDER
Definition module.h:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition module.h:557
@ AST_MODPRI_APP_DEPEND
Definition module.h:342
@ AST_MODULE_SUPPORT_CORE
Definition module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
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
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition netsock2.c:230
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. "null" in this sense essentially means uninitialized,...
Definition netsock2.h:127
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition netsock2.h:532
void ast_sip_unregister_service(pjsip_module *module)
Definition res_pjsip.c:127
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition res_pjsip.c:111
@ AST_SIP_SUPPLEMENT_PRIORITY_FIRST
Definition res_pjsip.h:3365
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.
struct ast_sip_transport_state * ast_sip_find_transport_state_in_use(struct ast_sip_request_transport_details *details)
Returns the transport state currently in use based on request transport details.
Definition res_pjsip.c:589
int ast_sip_set_request_transport_details(struct ast_sip_request_transport_details *details, pjsip_tx_data *tdata, int use_ipv6)
Sets request transport details based on tdata.
Definition res_pjsip.c:642
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define ast_sip_transport_is_local(transport_state, addr)
Definition res_pjsip.h:213
pjsip_sip_uri * ast_sip_get_contact_sip_uri(pjsip_tx_data *tdata)
Return the SIP URI of the Contact header.
Definition res_pjsip.c:558
static void nat_incoming_invite_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
Function called when an INVITE response comes in.
static int nat_invoke_hook(void *obj, void *arg, int flags)
Callback function for invoking hooks.
static void save_orig_contact_host(pjsip_rx_data *rdata, pjsip_sip_uri *uri)
static int nat_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
Function called when an INVITE goes out.
#define MAX_PORT_LEN
static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg)
static pjsip_module nat_module
#define COLON_LEN
static int rewrite_contact(pjsip_rx_data *rdata, pjsip_dialog *dlg)
#define is_sip_uri(uri)
#define AST_SIP_X_AST_ORIG_HOST_LEN
static void nat_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
Function called when an INVITE comes in.
static pj_bool_t handle_rx_message(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
static void restore_orig_contact_host(pjsip_tx_data *tdata)
static int load_module(void)
#define AST_SIP_X_AST_ORIG_HOST
static int unload_module(void)
static struct ast_sip_session_supplement nat_supplement
Supplement for adding NAT functionality to dialog.
static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata)
static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri, pj_pool_t *pool)
static pj_bool_t nat_on_rx_message(pjsip_rx_data *rdata)
static pj_status_t process_nat(pjsip_tx_data *tdata)
#define ast_sip_session_register_supplement(supplement)
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.
#define NULL
Definition resample.c:96
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition sorcery.c:2381
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition sorcery.h:123
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:1917
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:1961
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
Generic container type.
An entity with which Asterisk communicates.
Definition res_pjsip.h:1067
struct ast_sip_endpoint_nat_configuration nat
Definition res_pjsip.h:1104
Structure for SIP nat hook information.
Definition res_pjsip.h:329
void(* outgoing_external_message)(struct pjsip_tx_data *tdata, struct ast_sip_transport *transport)
Definition res_pjsip.h:333
Structure which contains information about a transport.
Definition res_pjsip.h:337
pjsip_transport * transport
Potential pointer to the transport itself, if UDP.
Definition res_pjsip.h:341
pjsip_tpfactory * factory
Potential pointer to the transport factory itself, if TCP/TLS.
Definition res_pjsip.h:343
A supplement to SIP message processing.
struct ast_module *const char * method
A structure describing a SIP session.
Structure for SIP transport information.
Definition res_pjsip.h:117
Transport to bind to.
Definition res_pjsip.h:219
Socket address structure.
Definition netsock2.h:97
Structure which contains hook details.
pjsip_tx_data * tdata
Outgoing message itself.
struct ast_sip_transport * transport
Chosen 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:981

◆ MAX_PORT_LEN

#define MAX_PORT_LEN   5

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 503 of file res_pjsip_nat.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 503 of file res_pjsip_nat.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 503 of file res_pjsip_nat.c.

◆ 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.

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 routable 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}

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

Referenced by nat_incoming_invite_response(), and nat_on_rx_message().

◆ load_module()

static int load_module ( void  )
static

Definition at line 485 of file res_pjsip_nat.c.

486{
488 ast_log(LOG_ERROR, "Could not register NAT module for incoming and outgoing requests\n");
490 }
491
493
495}

References ast_log, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_sip_register_service(), ast_sip_session_register_supplement, LOG_ERROR, nat_module, and nat_supplement.

◆ 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 445 of file res_pjsip_nat.c.

446{
447 if (session->inv_session->state == PJSIP_INV_STATE_INCOMING) {
448 pjsip_dlg_add_usage(session->inv_session->dlg, &nat_module, NULL);
449 }
450
451 return 0;
452}

References nat_module, NULL, and session.

◆ 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 455 of file res_pjsip_nat.c.

456{
457 handle_rx_message(session->endpoint, rdata);
458}

References handle_rx_message(), and session.

◆ nat_invoke_hook()

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

Callback function for invoking hooks.

Definition at line 248 of file res_pjsip_nat.c.

249{
250 struct ast_sip_nat_hook *hook = obj;
251 struct nat_hook_details *details = arg;
252
253 if (hook->outgoing_external_message) {
254 hook->outgoing_external_message(details->tdata, details->transport);
255 }
256
257 return 0;
258}

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

Referenced by process_nat().

◆ 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.

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}

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

◆ nat_on_tx_message()

static pj_status_t nat_on_tx_message ( pjsip_tx_data *  tdata)
static

Definition at line 424 of file res_pjsip_nat.c.

424 {
425 pj_status_t rc;
426
427 rc = process_nat(tdata);
429
430 return rc;
431}

References process_nat(), restore_orig_contact_host(), and nat_hook_details::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 461 of file res_pjsip_nat.c.

462{
463 if (session->inv_session->state == PJSIP_INV_STATE_NULL) {
464 pjsip_dlg_add_usage(session->inv_session->dlg, &nat_module, NULL);
465 }
466}

References nat_module, NULL, and session.

◆ process_nat()

static pj_status_t process_nat ( pjsip_tx_data *  tdata)
static

Definition at line 319 of file res_pjsip_nat.c.

320{
321 RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
322 RAII_VAR(struct ast_sip_transport_state *, transport_state, NULL, ao2_cleanup);
323 struct ast_sip_request_transport_details details = { 0, };
324 pjsip_via_hdr *via = NULL;
325 struct ast_sockaddr addr = { { 0, } };
326 pjsip_sip_uri *uri = NULL;
327 RAII_VAR(struct ao2_container *, hooks, NULL, ao2_cleanup);
328 const char *transport_type_name = "unknown";
329
330 if (ast_sip_set_request_transport_details(&details, tdata, 0)) {
331 ast_debug(4, "Unable to process message for transport type '%s'\n", transport_type_name);
332 return PJ_SUCCESS;
333 }
334
335 if (details.transport) {
336 transport_type_name = details.transport->type_name;
337 } else if (details.factory) {
338 transport_type_name = details.factory->type_name;
339 }
340
341 ast_debug(4, "Processing outgoing message for transport type '%s'\n", transport_type_name);
342
343 uri = ast_sip_get_contact_sip_uri(tdata);
344 via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
345
346 if (!(transport_state = ast_sip_find_transport_state_in_use(&details))) {
347 return PJ_SUCCESS;
348 }
349
350 ast_debug(4, "Found transport state '%s' for type '%s'\n", transport_state->id,
351 transport_type_name);
352
353 if (!(transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id))) {
354 ast_debug(4, "Unable to find transport for transport state '%s' type '%s'\n", transport_state->id,
355 transport_type_name);
356 return PJ_SUCCESS;
357 }
358
359 ast_debug(4, "Found transport '%s' for transport state '%s' type '%s'\n",
360 ast_sorcery_object_get_id(transport),
361 transport_state->id, transport_type_name);
362
363 if (transport_state->localnet) {
364 ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID);
365 ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port);
366
367 /* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */
368 if (ast_sip_transport_is_local(transport_state, &addr)) {
369 ast_debug(4, "Request is being sent to local address, skipping NAT manipulation\n");
370 return PJ_SUCCESS;
371 }
372 }
373
374 if (!ast_sockaddr_isnull(&transport_state->external_signaling_address) ||
375 !ast_strlen_zero(transport->external_signaling_hostname)) {
376 pjsip_cseq_hdr *cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg);
377 const char *signaling_host = !ast_strlen_zero(transport->external_signaling_hostname) ?
378 transport->external_signaling_hostname :
379 ast_sockaddr_stringify_host(&transport_state->external_signaling_address);
380
381 /* Update the Contact header with the external address. We only do this if
382 * a CSeq is not present (which should not happen - but we are extra safe),
383 * if a request is being sent, or if a response is sent that is not a response
384 * to a REGISTER. We specifically don't do this for a response to a REGISTER
385 * as the Contact headers would contain the registered Contacts, and not our
386 * own Contact. Nor do we do it for a 302 response to an INVITE request.
387 */
388 if ((!cseq || tdata->msg->type == PJSIP_REQUEST_MSG ||
389 pjsip_method_cmp(&cseq->method, &pjsip_register_method)) &&
390 (tdata->msg->type != PJSIP_RESPONSE_MSG ||
391 pjsip_method_cmp(&cseq->method, &pjsip_invite_method) ||
392 tdata->msg->line.status.code != PJSIP_SC_MOVED_TEMPORARILY )) {
393 /* We can only rewrite the URI when one is present */
394 if (uri || (uri = ast_sip_get_contact_sip_uri(tdata))) {
395 pj_strdup2(tdata->pool, &uri->host, signaling_host);
396 if (transport->external_signaling_port) {
397 uri->port = transport->external_signaling_port;
398 ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port);
399 }
400 }
401 }
402
403 /* Update the via header if relevant */
404 if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) {
405 pj_strdup2(tdata->pool, &via->sent_by.host, signaling_host);
406 if (transport->external_signaling_port) {
407 via->sent_by.port = transport->external_signaling_port;
408 }
409 }
410 }
411
412 /* Invoke any additional hooks that may be registered */
414 struct nat_hook_details hook_details = {
415 .tdata = tdata,
416 .transport = transport,
417 };
418 ao2_callback(hooks, 0, nat_invoke_hook, &hook_details);
419 }
420
421 return PJ_SUCCESS;
422}

References ao2_callback, ao2_cleanup, ast_debug, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sip_find_transport_state_in_use(), ast_sip_get_contact_sip_uri(), ast_sip_get_sorcery(), ast_sip_set_request_transport_details(), ast_sip_transport_is_local, ast_sockaddr_isnull(), ast_sockaddr_parse(), ast_sockaddr_set_port, ast_sockaddr_stringify_host(), ast_sorcery_object_get_id(), ast_sorcery_retrieve_by_fields(), ast_sorcery_retrieve_by_id(), ast_strlen_zero(), ast_sip_request_transport_details::factory, nat_invoke_hook(), NULL, PARSE_PORT_FORBID, RAII_VAR, nat_hook_details::tdata, ast_sip_request_transport_details::transport, and nat_hook_details::transport.

Referenced by nat_on_tx_message().

◆ restore_orig_contact_host()

static void restore_orig_contact_host ( pjsip_tx_data *  tdata)
static

Definition at line 260 of file res_pjsip_nat.c.

261{
262 pjsip_contact_hdr *contact;
264 pjsip_param *x_orig_host;
265 pjsip_sip_uri *uri;
266 pjsip_hdr *hdr;
267
268 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
269 if (is_sip_uri(tdata->msg->line.req.uri)) {
270 uri = pjsip_uri_get_uri(tdata->msg->line.req.uri);
271 while ((x_orig_host = pjsip_param_find(&uri->other_param, &x_name))) {
272 pj_list_erase(x_orig_host);
273 }
274 }
275 for (hdr = tdata->msg->hdr.next; hdr != &tdata->msg->hdr; hdr = hdr->next) {
276 if (hdr->type == PJSIP_H_TO) {
277 if (is_sip_uri(((pjsip_fromto_hdr *) hdr)->uri)) {
278 uri = pjsip_uri_get_uri(((pjsip_fromto_hdr *) hdr)->uri);
279 while ((x_orig_host = pjsip_param_find(&uri->other_param, &x_name))) {
280 pj_list_erase(x_orig_host);
281 }
282 }
283 }
284 }
285 }
286
287 if (tdata->msg->type != PJSIP_RESPONSE_MSG) {
288 return;
289 }
290
291 contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
292 while (contact) {
293 pjsip_sip_uri *contact_uri = pjsip_uri_get_uri(contact->uri);
294 x_orig_host = pjsip_param_find(&contact_uri->other_param, &x_name);
295
296 if (x_orig_host) {
297 char host_port[x_orig_host->value.slen + 1];
298 char *sep;
299
300 ast_debug(1, "Restoring contact %.*s:%d to %.*s\n", (int)contact_uri->host.slen,
301 contact_uri->host.ptr, contact_uri->port,
302 (int)x_orig_host->value.slen, x_orig_host->value.ptr);
303
304 strncpy(host_port, x_orig_host->value.ptr, x_orig_host->value.slen);
305 host_port[x_orig_host->value.slen] = '\0';
306 sep = strchr(host_port, ':');
307 if (sep) {
308 *sep = '\0';
309 sep++;
310 pj_strdup2(tdata->pool, &contact_uri->host, host_port);
311 contact_uri->port = strtol(sep, NULL, 10);
312 }
313 pj_list_erase(x_orig_host);
314 }
315 contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, contact->next);
316 }
317}

References ast_debug, AST_SIP_X_AST_ORIG_HOST, AST_SIP_X_AST_ORIG_HOST_LEN, is_sip_uri, NULL, and nat_hook_details::tdata.

Referenced by nat_on_tx_message().

◆ rewrite_contact()

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

Definition at line 179 of file res_pjsip_nat.c.

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}

References NULL, and rewrite_uri().

Referenced by handle_rx_message().

◆ 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.

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}

References NULL, and rewrite_uri().

Referenced by handle_rx_message().

◆ rewrite_uri()

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

Definition at line 70 of file res_pjsip_nat.c.

71{
72
73 if (pj_strcmp2(&uri->host, rdata->pkt_info.src_name) != 0) {
74 save_orig_contact_host(rdata, uri);
75 }
76
77 pj_strdup2(pool, &uri->host, rdata->pkt_info.src_name);
78 uri->port = rdata->pkt_info.src_port;
79 if (!strcasecmp("WSS", rdata->tp_info.transport->type_name)) {
80 /* WSS is special, we don't want to overwrite the URI at all as it needs to be ws */
81 } else if (strcasecmp("udp", rdata->tp_info.transport->type_name)) {
82 uri->transport_param = pj_str(rdata->tp_info.transport->type_name);
83 } else {
84 uri->transport_param.slen = 0;
85 }
86}

References save_orig_contact_host().

Referenced by rewrite_contact(), and rewrite_route_set().

◆ save_orig_contact_host()

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

Definition at line 44 of file res_pjsip_nat.c.

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

References ast_debug, AST_SIP_X_AST_ORIG_HOST, COLON_LEN, and MAX_PORT_LEN.

Referenced by rewrite_uri().

◆ unload_module()

static int unload_module ( void  )
static

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP NAT Support" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .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 503 of file res_pjsip_nat.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 503 of file res_pjsip_nat.c.

◆ nat_module

pjsip_module nat_module
static

Definition at line 434 of file res_pjsip_nat.c.

434 {
435 .name = { "NAT", 3 },
436 .id = -1,
437 .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 2,
438 .on_rx_request = nat_on_rx_message,
439 .on_rx_response = nat_on_rx_message,
440 .on_tx_request = nat_on_tx_message,
441 .on_tx_response = nat_on_tx_message,
442};

Referenced by load_module(), nat_incoming_invite_request(), nat_outgoing_invite_request(), and unload_module().

◆ nat_supplement

struct ast_sip_session_supplement nat_supplement
static

Supplement for adding NAT functionality to dialog.

Definition at line 469 of file res_pjsip_nat.c.

469 {
470 .method = "INVITE",
471 .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST + 1,
472 .incoming_request = nat_incoming_invite_request,
473 .outgoing_request = nat_outgoing_invite_request,
474 .incoming_response = nat_incoming_invite_response,
475};

Referenced by load_module(), and unload_module().