ARI/PJSIP: Add the ability to redirect (transfer) a channel in a Stasis app
[asterisk/asterisk.git] / res / 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         <support_level>core</support_level>
23  ***/
24
25 #include "asterisk.h"
26
27 #include <pjsip.h>
28 #include <pjsip_ua.h>
29
30 #include "asterisk/res_pjsip.h"
31 #include "asterisk/res_pjsip_session.h"
32 #include "asterisk/module.h"
33 #include "asterisk/acl.h"
34
35 static pj_bool_t handle_rx_message(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
36 {
37         pjsip_contact_hdr *contact;
38
39         if (!endpoint) {
40                 return PJ_FALSE;
41         }
42
43         if (endpoint->nat.rewrite_contact && (contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL)) &&
44                 !contact->star && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
45                 pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);
46                 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
47
48                 pj_cstr(&uri->host, rdata->pkt_info.src_name);
49                 if (strcasecmp("udp", rdata->tp_info.transport->type_name)) {
50                         uri->transport_param = pj_str(rdata->tp_info.transport->type_name);
51                 } else {
52                         uri->transport_param.slen = 0;
53                 }
54                 uri->port = rdata->pkt_info.src_port;
55                 ast_debug(4, "Re-wrote Contact URI host/port to %.*s:%d\n",
56                         (int)pj_strlen(&uri->host), pj_strbuf(&uri->host), uri->port);
57
58                 /* rewrite the session target since it may have already been pulled from the contact header */
59                 if (dlg && (!dlg->remote.contact
60                         || pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, dlg->remote.contact->uri, contact->uri))) {
61                         dlg->remote.contact = (pjsip_contact_hdr*)pjsip_hdr_clone(dlg->pool, contact);
62                         dlg->target = dlg->remote.contact->uri;
63                 }
64         }
65
66         if (endpoint->nat.force_rport) {
67                 rdata->msg_info.via->rport_param = rdata->pkt_info.src_port;
68         }
69
70         return PJ_FALSE;
71 }
72
73 static pj_bool_t nat_on_rx_message(pjsip_rx_data *rdata)
74 {
75         RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
76         return handle_rx_message(endpoint, rdata);
77 }
78
79 /*! \brief Structure which contains information about a transport */
80 struct request_transport_details {
81         /*! \brief Type of transport */
82         enum ast_transport type;
83         /*! \brief Potential pointer to the transport itself, if UDP */
84         pjsip_transport *transport;
85         /*! \brief Potential pointer to the transport factory itself, if TCP/TLS */
86         pjsip_tpfactory *factory;
87         /*! \brief Local address for transport */
88         pj_str_t local_address;
89         /*! \brief Local port for transport */
90         int local_port;
91 };
92
93 /*! \brief Callback function for finding the transport the request is going out on */
94 static int find_transport_in_use(void *obj, void *arg, int flags)
95 {
96         struct ast_sip_transport *transport = obj;
97         struct request_transport_details *details = arg;
98
99         /* If an explicit transport or factory matches then this is what is in use, if we are unavailable
100          * to compare based on that we make sure that the type is the same and the source IP address/port are the same
101          */
102         if ((details->transport && details->transport == transport->state->transport) ||
103                 (details->factory && details->factory == transport->state->factory) ||
104                 ((details->type == transport->type) && (transport->state->factory) &&
105                         !pj_strcmp(&transport->state->factory->addr_name.host, &details->local_address) &&
106                         transport->state->factory->addr_name.port == details->local_port)) {
107                 return CMP_MATCH | CMP_STOP;
108         }
109
110         return 0;
111 }
112
113 /*! \brief Helper function which returns the SIP URI of a Contact header */
114 static pjsip_sip_uri *nat_get_contact_sip_uri(pjsip_tx_data *tdata)
115 {
116         pjsip_contact_hdr *contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
117
118         if (!contact || (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
119                 return NULL;
120         }
121
122         return pjsip_uri_get_uri(contact->uri);
123 }
124
125 /*! \brief Structure which contains hook details */
126 struct nat_hook_details {
127         /*! \brief Outgoing message itself */
128         pjsip_tx_data *tdata;
129         /*! \brief Chosen transport */
130         struct ast_sip_transport *transport;
131 };
132
133 /*! \brief Callback function for invoking hooks */
134 static int nat_invoke_hook(void *obj, void *arg, int flags)
135 {
136         struct ast_sip_nat_hook *hook = obj;
137         struct nat_hook_details *details = arg;
138
139         if (hook->outgoing_external_message) {
140                 hook->outgoing_external_message(details->tdata, details->transport);
141         }
142
143         return 0;
144 }
145
146 static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata)
147 {
148         RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup);
149         RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
150         struct request_transport_details details = { 0, };
151         pjsip_via_hdr *via = NULL;
152         struct ast_sockaddr addr = { { 0, } };
153         pjsip_sip_uri *uri = NULL;
154         RAII_VAR(struct ao2_container *, hooks, NULL, ao2_cleanup);
155
156         /* If a transport selector is in use we know the transport or factory, so explicitly find it */
157         if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT) {
158                 details.transport = tdata->tp_sel.u.transport;
159         } else if (tdata->tp_sel.type == PJSIP_TPSELECTOR_LISTENER) {
160                 details.factory = tdata->tp_sel.u.listener;
161         } else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP || tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
162                 /* Connectionless uses the same transport for all requests */
163                 details.type = AST_TRANSPORT_UDP;
164                 details.transport = tdata->tp_info.transport;
165         } else {
166                 if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TCP) {
167                         details.type = AST_TRANSPORT_TCP;
168                 } else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TLS) {
169                         details.type = AST_TRANSPORT_TLS;
170                 } else {
171                         /* Unknown transport type, we can't map and thus can't apply NAT changes */
172                         return PJ_SUCCESS;
173                 }
174
175                 if ((uri = nat_get_contact_sip_uri(tdata))) {
176                         details.local_address = uri->host;
177                         details.local_port = uri->port;
178                 } else if ((tdata->msg->type == PJSIP_REQUEST_MSG) &&
179                         (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL))) {
180                         details.local_address = via->sent_by.host;
181                         details.local_port = via->sent_by.port;
182                 } else {
183                         return PJ_SUCCESS;
184                 }
185
186                 if (!details.local_port) {
187                         details.local_port = (details.type == AST_TRANSPORT_TLS) ? 5061 : 5060;
188                 }
189         }
190
191         if (!(transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) ||
192                 !(transport = ao2_callback(transports, 0, find_transport_in_use, &details)) || !transport->localnet ||
193                 ast_sockaddr_isnull(&transport->external_address)) {
194                 return PJ_SUCCESS;
195         }
196
197         ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID);
198         ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port);
199
200         /* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */
201         if (ast_apply_ha(transport->localnet, &addr) != AST_SENSE_ALLOW) {
202                 return PJ_SUCCESS;
203         }
204
205         /* Update the contact header with the external address */
206         if (uri || (uri = nat_get_contact_sip_uri(tdata))) {
207                 pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport->external_address));
208                 if (transport->external_signaling_port) {
209                         uri->port = transport->external_signaling_port;
210                         ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port);
211                 }
212         }
213
214         /* Update the via header if relevant */
215         if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) {
216                 pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport->external_address));
217                 if (transport->external_signaling_port) {
218                         via->sent_by.port = transport->external_signaling_port;
219                 }
220         }
221
222         /* Invoke any additional hooks that may be registered */
223         if ((hooks = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "nat_hook", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
224                 struct nat_hook_details hook_details = {
225                         .tdata = tdata,
226                         .transport = transport,
227                 };
228                 ao2_callback(hooks, 0, nat_invoke_hook, &hook_details);
229         }
230
231         return PJ_SUCCESS;
232 }
233
234 static pjsip_module nat_module = {
235         .name = { "NAT", 3 },
236         .id = -1,
237         .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 2,
238         .on_rx_request = nat_on_rx_message,
239         .on_rx_response = nat_on_rx_message,
240         .on_tx_request = nat_on_tx_message,
241         .on_tx_response = nat_on_tx_message,
242 };
243
244 /*! \brief Function called when an INVITE goes out */
245 static int nat_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
246 {
247         if (session->inv_session->state == PJSIP_INV_STATE_INCOMING) {
248                 pjsip_dlg_add_usage(session->inv_session->dlg, &nat_module, NULL);
249         }
250
251         return 0;
252 }
253
254 /*! \brief Function called when an INVITE response comes in */
255 static void nat_incoming_invite_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
256 {
257         handle_rx_message(session->endpoint, rdata);
258 }
259
260 /*! \brief Function called when an INVITE comes in */
261 static void nat_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
262 {
263         if (session->inv_session->state == PJSIP_INV_STATE_NULL) {
264                 pjsip_dlg_add_usage(session->inv_session->dlg, &nat_module, NULL);
265         }
266 }
267
268 /*! \brief Supplement for adding NAT functionality to dialog */
269 static struct ast_sip_session_supplement nat_supplement = {
270         .method = "INVITE",
271         .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST + 1,
272         .incoming_request = nat_incoming_invite_request,
273         .outgoing_request = nat_outgoing_invite_request,
274         .incoming_response = nat_incoming_invite_response,
275 };
276
277
278 static int unload_module(void)
279 {
280         ast_sip_session_unregister_supplement(&nat_supplement);
281         ast_sip_unregister_service(&nat_module);
282         return 0;
283 }
284
285 static int load_module(void)
286 {
287         CHECK_PJSIP_SESSION_MODULE_LOADED();
288
289         if (ast_sip_register_service(&nat_module)) {
290                 ast_log(LOG_ERROR, "Could not register NAT module for incoming and outgoing requests\n");
291                 return AST_MODULE_LOAD_FAILURE;
292         }
293
294         if (ast_sip_session_register_supplement(&nat_supplement)) {
295                 ast_log(LOG_ERROR, "Could not register NAT session supplement for incoming and outgoing INVITE requests\n");
296                 unload_module();
297                 return AST_MODULE_LOAD_FAILURE;
298         }
299
300         return AST_MODULE_LOAD_SUCCESS;
301 }
302
303 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP NAT Support",
304                 .support_level = AST_MODULE_SUPPORT_CORE,
305                 .load = load_module,
306                 .unload = unload_module,
307                 .load_pri = AST_MODPRI_APP_DEPEND,
308                );