Asterisk - The Open Source Telephony Project GIT-master-6144b6b
Loading...
Searching...
No Matches
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 <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"
33#include "asterisk/module.h"
34#include "asterisk/acl.h"
35#include "asterisk/strings.h"
36
37/*! URI parameter for original host/port */
38#define AST_SIP_X_AST_ORIG_HOST "x-ast-orig-host"
39#define AST_SIP_X_AST_ORIG_HOST_LEN 15
40
41#define is_sip_uri(uri) \
42 (PJSIP_URI_SCHEME_IS_SIP(uri) || PJSIP_URI_SCHEME_IS_SIPS(uri))
43
44static void save_orig_contact_host(pjsip_rx_data *rdata, pjsip_sip_uri *uri)
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}
69
70static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri, pj_pool_t *pool)
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}
87
88/*
89 * Update the Record-Route headers in the request or response and in the dialog
90 * object if exists.
91 *
92 * When NAT is in use, the address of the next hop in the SIP may be incorrect.
93 * To address this asterisk uses two strategies in parallel:
94 * 1. intercept the messages at the transaction level and rewrite the
95 * messages before arriving at the dialog layer
96 * 2. after the application processing, update the dialog object with the
97 * correct information
98 *
99 * The first strategy has a limitation that the SIP message may not have all
100 * the information required to determine if the next hop is in the route set
101 * or in the contact. Causing risk that asterisk will update the Contact on
102 * receipt of an in-dialog message despite there being a route set saved in
103 * the dialog.
104 *
105 * The second strategy has a limitation that not all UAC layers have interfaces
106 * available to invoke this module after dialog creation. (pjsip_sesion does
107 * but pjsip_pubsub does not), thus this strategy can't update the dialog in
108 * all cases needed.
109 *
110 * The ideal solution would be to implement an "incomming_request" event
111 * in pubsub module that can then pass the dialog object to this module
112 * on SUBSCRIBE, this module then should add itself as a listener to the dialog
113 * for the subsequent requests and responses & then be able to properly update
114 * the dialog object for all required events.
115 */
116static 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
179static 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
200static 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 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}
227
228static 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 hook details */
241 /*! \brief Outgoing message itself */
242 pjsip_tx_data *tdata;
243 /*! \brief Chosen transport */
245};
246
247/*! \brief Callback function for invoking hooks */
248static int nat_invoke_hook(void *obj, void *arg, int flags)
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}
259
260static void restore_orig_contact_host(pjsip_tx_data *tdata)
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}
318
319static pj_status_t process_nat(pjsip_tx_data *tdata)
320{
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}
423
424static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata) {
425 pj_status_t rc;
426
427 rc = process_nat(tdata);
429
430 return rc;
431}
432
433
434static pjsip_module nat_module = {
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};
443
444/*! \brief Function called when an INVITE goes out */
445static int nat_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
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}
453
454/*! \brief Function called when an INVITE response comes in */
455static void nat_incoming_invite_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
456{
457 handle_rx_message(session->endpoint, rdata);
458}
459
460/*! \brief Function called when an INVITE comes in */
461static void nat_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
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}
467
468/*! \brief Supplement for adding NAT functionality to dialog */
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};
476
477
484
485static int load_module(void)
486{
488 ast_log(LOG_ERROR, "Could not register NAT module for incoming and outgoing requests\n");
490 }
491
493
495}
496
498 .support_level = AST_MODULE_SUPPORT_CORE,
499 .load = load_module,
500 .unload = unload_module,
501 .load_pri = AST_MODPRI_APP_DEPEND,
502 .requires = "res_pjsip,res_pjsip_session",
Access Control of various sorts.
Asterisk main include file. File version handling, generic pbx functions.
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
Asterisk module definitions.
@ 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
String manipulation functions.
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