res_pjsip_nat.c 10 KB

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