31 #include "asterisk/res_pjsip.h"
32 #include "asterisk/res_pjsip_session.h"
37 #define AST_SIP_X_AST_ORIG_HOST "x-ast-orig-host"
38 #define AST_SIP_X_AST_ORIG_HOST_LEN 15
40 #define is_sip_uri(uri) \
41 (PJSIP_URI_SCHEME_IS_SIP(uri) || PJSIP_URI_SCHEME_IS_SIPS(uri))
43 static void save_orig_contact_host(pjsip_rx_data *rdata, pjsip_sip_uri *uri)
45 pjsip_param *x_orig_host;
48 #define MAX_PORT_LEN 5
50 if (rdata->msg_info.msg->type != PJSIP_REQUEST_MSG ||
51 rdata->msg_info.msg->line.req.method.id != PJSIP_REGISTER_METHOD) {
55 ast_debug(1,
"Saving contact '%.*s:%d'\n",
56 (
int)uri->host.slen, uri->host.ptr, uri->port);
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);
69 static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri, pj_pool_t *
pool)
72 if (pj_strcmp2(&uri->host, rdata->pkt_info.src_name) != 0) {
73 save_orig_contact_host(rdata, uri);
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)) {
80 }
else if (strcasecmp(
"udp", rdata->tp_info.transport->type_name)) {
81 uri->transport_param = pj_str(rdata->tp_info.transport->type_name);
83 uri->transport_param.slen = 0;
115 static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg)
117 pjsip_rr_hdr *rr = NULL;
123 if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG) {
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;
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);
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)) {
152 uri = pjsip_uri_get_uri(&rr->name_addr);
153 rewrite_uri(rdata, uri, rdata->tp_info.pool);
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);
164 if (!dlg && !rr && !ignore_rr && !pubsub && rdata->msg_info.to->tag.slen){
178 static int rewrite_contact(pjsip_rx_data *rdata, pjsip_dialog *dlg)
180 pjsip_contact_hdr *contact;
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);
186 rewrite_uri(rdata, uri, rdata->tp_info.pool);
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;
199 static pj_bool_t handle_rx_message(
struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
201 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
215 if (rewrite_route_set(rdata, dlg)) {
216 rewrite_contact(rdata, dlg);
221 rdata->msg_info.via->rport_param = rdata->pkt_info.src_port;
227 static pj_bool_t nat_on_rx_message(pjsip_rx_data *rdata)
232 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
233 res = handle_rx_message(endpoint, rdata);
234 ao2_cleanup(endpoint);
247 static int nat_invoke_hook(
void *obj,
void *arg,
int flags)
259 static void restore_orig_contact_host(pjsip_tx_data *
tdata)
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;
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);
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);
286 if (tdata->msg->type != PJSIP_RESPONSE_MSG) {
290 contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
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);
296 char host_port[x_orig_host->value.slen + 1];
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);
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,
':');
309 pj_strdup2(tdata->pool, &contact_uri->host, host_port);
310 contact_uri->port = strtol(sep, NULL, 10);
312 pj_list_erase(x_orig_host);
314 contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, contact->next);
318 static pj_status_t process_nat(pjsip_tx_data *tdata)
323 pjsip_via_hdr *via = NULL;
325 pjsip_sip_uri *uri = NULL;
328 if (ast_sip_set_request_transport_details(&details, tdata, 0)) {
332 uri = ast_sip_get_contact_sip_uri(tdata);
333 via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
335 if (!(transport_state = ast_sip_find_transport_state_in_use(&details))) {
343 if (transport_state->localnet) {
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");
355 pjsip_cseq_hdr *cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg);
364 if (!cseq || tdata->msg->type == PJSIP_REQUEST_MSG ||
365 pjsip_method_cmp(&cseq->method, &pjsip_register_method)) {
367 if (uri || (uri = ast_sip_get_contact_sip_uri(tdata))) {
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);
377 if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) {
379 if (transport->external_signaling_port) {
380 via->sent_by.port = transport->external_signaling_port;
397 static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata) {
400 rc = process_nat(tdata);
401 restore_orig_contact_host(tdata);
407 static pjsip_module nat_module = {
408 .name = {
"NAT", 3 },
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,
418 static int nat_incoming_invite_request(
struct ast_sip_session *session,
struct pjsip_rx_data *rdata)
420 if (session->
inv_session->state == PJSIP_INV_STATE_INCOMING) {
421 pjsip_dlg_add_usage(session->
inv_session->dlg, &nat_module, NULL);
428 static void nat_incoming_invite_response(
struct ast_sip_session *session,
struct pjsip_rx_data *rdata)
430 handle_rx_message(session->
endpoint, rdata);
434 static void nat_outgoing_invite_request(
struct ast_sip_session *session,
struct pjsip_tx_data *tdata)
436 if (session->
inv_session->state == PJSIP_INV_STATE_NULL) {
437 pjsip_dlg_add_usage(session->
inv_session->dlg, &nat_module, NULL);
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,
451 static int unload_module(
void)
453 ast_sip_session_unregister_supplement(&nat_supplement);
454 ast_sip_unregister_service(&nat_module);
458 static int load_module(
void)
460 if (ast_sip_register_service(&nat_module)) {
461 ast_log(LOG_ERROR,
"Could not register NAT module for incoming and outgoing requests\n");
465 ast_sip_session_register_supplement(&nat_supplement);
470 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"PJSIP NAT Support",
471 .support_level = AST_MODULE_SUPPORT_CORE,
473 .unload = unload_module,
475 .requires =
"res_pjsip,res_pjsip_session",
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.
struct ast_sip_endpoint_nat_configuration nat
#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.
static pj_pool_t * pool
Global memory pool for configuration and timers.
Perform no matching, return all objects.
Return all matching objects.
struct pjsip_inv_session * inv_session
Socket address structure.
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.
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.
Structure for SIP nat hook information.
Structure for SIP transport information.
void(* outgoing_external_message)(struct pjsip_tx_data *tdata, struct ast_sip_transport *transport)
Access Control of various sorts.
#define ast_debug(level,...)
Log a DEBUG message.
An entity with which Asterisk communicates.
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
unsigned int rewrite_contact
Module has failed to load, may be in an inconsistent state.
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.
A supplement to SIP message processing.
Structure which contains information about a transport.
#define ASTERISK_GPL_KEY
The text the key() function should return.
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.
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...
pjsip_tx_data * tdata
Outgoing message itself.