res_stun_monitor.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2010, Digium, Inc.
  5. *
  6. * David Vossel <dvossel@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. * \file
  20. * \brief STUN Network Monitor
  21. *
  22. * \author David Vossel <dvossel@digium.com>
  23. */
  24. /*** MODULEINFO
  25. <support_level>core</support_level>
  26. ***/
  27. #include "asterisk.h"
  28. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  29. #include "asterisk/module.h"
  30. #include "asterisk/event.h"
  31. #include "asterisk/sched.h"
  32. #include "asterisk/config.h"
  33. #include "asterisk/stun.h"
  34. #include "asterisk/netsock2.h"
  35. #include "asterisk/lock.h"
  36. #include "asterisk/acl.h"
  37. #include <fcntl.h>
  38. #define DEFAULT_MONITOR_REFRESH 30 /*!< Default refresh period in seconds */
  39. static const char stun_conf_file[] = "res_stun_monitor.conf";
  40. static struct ast_sched_context *sched;
  41. static struct {
  42. /*! STUN monitor protection lock. */
  43. ast_mutex_t lock;
  44. /*! Current perceived external address. */
  45. struct sockaddr_in external_addr;
  46. /*! STUN server host name. */
  47. const char *server_hostname;
  48. /*! Port of STUN server to use */
  49. unsigned int stun_port;
  50. /*! Number of seconds between polls to the STUN server for the external address. */
  51. unsigned int refresh;
  52. /*! Monitoring STUN socket. */
  53. int stun_sock;
  54. /*! TRUE if the STUN monitor is enabled. */
  55. unsigned int monitor_enabled:1;
  56. /*! TRUE if the perceived external address is valid/known. */
  57. unsigned int external_addr_known:1;
  58. /*! TRUE if we have already griped about a STUN poll failing. */
  59. unsigned int stun_poll_failed_gripe:1;
  60. } args;
  61. static void stun_close_sock(void)
  62. {
  63. if (0 <= args.stun_sock) {
  64. close(args.stun_sock);
  65. args.stun_sock = -1;
  66. }
  67. }
  68. /* \brief called by scheduler to send STUN request */
  69. static int stun_monitor_request(const void *blarg)
  70. {
  71. int res;
  72. struct sockaddr_in answer;
  73. static const struct sockaddr_in no_addr = { 0, };
  74. ast_mutex_lock(&args.lock);
  75. if (!args.monitor_enabled) {
  76. goto monitor_request_cleanup;
  77. }
  78. if (args.stun_sock < 0) {
  79. struct ast_sockaddr stun_addr;
  80. /* STUN socket not open. Refresh the server DNS address resolution. */
  81. if (!args.server_hostname) {
  82. /* No STUN hostname? */
  83. goto monitor_request_cleanup;
  84. }
  85. /* Lookup STUN address. */
  86. memset(&stun_addr, 0, sizeof(stun_addr));
  87. stun_addr.ss.ss_family = AF_INET;
  88. if (ast_get_ip(&stun_addr, args.server_hostname)) {
  89. /* Lookup failed. */
  90. ast_log(LOG_WARNING, "Unable to lookup STUN server '%s'\n",
  91. args.server_hostname);
  92. goto monitor_request_cleanup;
  93. }
  94. ast_sockaddr_set_port(&stun_addr, args.stun_port);
  95. /* open socket binding */
  96. args.stun_sock = socket(AF_INET, SOCK_DGRAM, 0);
  97. if (args.stun_sock < 0) {
  98. ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
  99. goto monitor_request_cleanup;
  100. }
  101. if (ast_connect(args.stun_sock, &stun_addr)) {
  102. ast_log(LOG_WARNING, "STUN Failed to connect to %s: %s\n",
  103. ast_sockaddr_stringify(&stun_addr), strerror(errno));
  104. stun_close_sock();
  105. goto monitor_request_cleanup;
  106. }
  107. }
  108. res = ast_stun_request(args.stun_sock, NULL, NULL, &answer);
  109. if (res) {
  110. /*
  111. * STUN request timed out or errored.
  112. *
  113. * Refresh the server DNS address resolution next time around.
  114. */
  115. if (!args.stun_poll_failed_gripe) {
  116. args.stun_poll_failed_gripe = 1;
  117. ast_log(LOG_WARNING, "STUN poll %s. Re-evaluating STUN server address.\n",
  118. res < 0 ? "failed" : "got no response");
  119. }
  120. stun_close_sock();
  121. } else {
  122. args.stun_poll_failed_gripe = 0;
  123. if (memcmp(&no_addr, &answer, sizeof(no_addr))
  124. && memcmp(&args.external_addr, &answer, sizeof(args.external_addr))) {
  125. const char *newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
  126. int newport = ntohs(answer.sin_port);
  127. ast_log(LOG_NOTICE, "Old external address/port %s:%d now seen as %s:%d.\n",
  128. ast_inet_ntoa(args.external_addr.sin_addr),
  129. ntohs(args.external_addr.sin_port), newaddr, newport);
  130. args.external_addr = answer;
  131. if (args.external_addr_known) {
  132. struct ast_event *event;
  133. /*
  134. * The external address was already known, and has changed...
  135. * generate event.
  136. */
  137. event = ast_event_new(AST_EVENT_NETWORK_CHANGE, AST_EVENT_IE_END);
  138. if (!event) {
  139. ast_log(LOG_ERROR, "Could not create AST_EVENT_NETWORK_CHANGE event.\n");
  140. } else if (ast_event_queue(event)) {
  141. ast_event_destroy(event);
  142. ast_log(LOG_ERROR, "Could not queue AST_EVENT_NETWORK_CHANGE event.\n");
  143. }
  144. } else {
  145. /* this was the first external address we found, do not alert listeners
  146. * until this address changes to something else. */
  147. args.external_addr_known = 1;
  148. }
  149. }
  150. }
  151. monitor_request_cleanup:
  152. /* always refresh this scheduler item. It will be removed elsewhere when
  153. * it is supposed to go away */
  154. res = args.refresh * 1000;
  155. ast_mutex_unlock(&args.lock);
  156. return res;
  157. }
  158. /*!
  159. * \internal
  160. * \brief Stops the STUN monitor thread.
  161. *
  162. * \note do not hold the args->lock while calling this
  163. *
  164. * \return Nothing
  165. */
  166. static void stun_stop_monitor(void)
  167. {
  168. ast_mutex_lock(&args.lock);
  169. args.monitor_enabled = 0;
  170. ast_free((char *) args.server_hostname);
  171. args.server_hostname = NULL;
  172. stun_close_sock();
  173. ast_mutex_unlock(&args.lock);
  174. if (sched) {
  175. ast_sched_context_destroy(sched);
  176. sched = NULL;
  177. ast_log(LOG_NOTICE, "STUN monitor stopped\n");
  178. }
  179. }
  180. /*!
  181. * \internal
  182. * \brief Starts the STUN monitor thread.
  183. *
  184. * \note The args->lock MUST be held when calling this function
  185. *
  186. * \return Nothing
  187. */
  188. static int stun_start_monitor(void)
  189. {
  190. /* if scheduler thread is not started, make sure to start it now */
  191. if (sched) {
  192. return 0; /* already started */
  193. }
  194. if (!(sched = ast_sched_context_create())) {
  195. ast_log(LOG_ERROR, "Failed to create stun monitor scheduler context\n");
  196. return -1;
  197. }
  198. if (ast_sched_start_thread(sched)) {
  199. ast_sched_context_destroy(sched);
  200. sched = NULL;
  201. stun_close_sock();
  202. return -1;
  203. }
  204. if (ast_sched_add_variable(sched, (args.refresh * 1000), stun_monitor_request, NULL, 1) < 0) {
  205. ast_log(LOG_ERROR, "Unable to schedule STUN network monitor \n");
  206. ast_sched_context_destroy(sched);
  207. sched = NULL;
  208. return -1;
  209. }
  210. ast_log(LOG_NOTICE, "STUN monitor started\n");
  211. return 0;
  212. }
  213. /*!
  214. * \internal
  215. * \brief Parse and setup the stunaddr parameter.
  216. *
  217. * \param value Configuration parameter variable value.
  218. *
  219. * \retval 0 on success.
  220. * \retval -1 on error.
  221. */
  222. static int setup_stunaddr(const char *value)
  223. {
  224. char *val;
  225. char *host_str;
  226. char *port_str;
  227. unsigned int port;
  228. struct ast_sockaddr stun_addr;
  229. if (ast_strlen_zero(value)) {
  230. /* Setting to an empty value disables STUN monitoring. */
  231. args.monitor_enabled = 0;
  232. return 0;
  233. }
  234. val = ast_strdupa(value);
  235. if (!ast_sockaddr_split_hostport(val, &host_str, &port_str, 0)
  236. || ast_strlen_zero(host_str)) {
  237. return -1;
  238. }
  239. /* Determine STUN port */
  240. if (ast_strlen_zero(port_str)
  241. || 1 != sscanf(port_str, "%30u", &port)) {
  242. port = STANDARD_STUN_PORT;
  243. }
  244. host_str = ast_strdup(host_str);
  245. if (!host_str) {
  246. return -1;
  247. }
  248. /* Lookup STUN address. */
  249. memset(&stun_addr, 0, sizeof(stun_addr));
  250. stun_addr.ss.ss_family = AF_INET;
  251. if (ast_get_ip(&stun_addr, host_str)) {
  252. ast_log(LOG_WARNING, "Unable to lookup STUN server '%s'\n", host_str);
  253. ast_free(host_str);
  254. return -1;
  255. }
  256. /* Save STUN server information. */
  257. ast_free((char *) args.server_hostname);
  258. args.server_hostname = host_str;
  259. args.stun_port = port;
  260. /* Enable STUN monitor */
  261. args.monitor_enabled = 1;
  262. return 0;
  263. }
  264. static int load_config(int startup)
  265. {
  266. struct ast_flags config_flags = { 0, };
  267. struct ast_config *cfg;
  268. struct ast_variable *v;
  269. if (!startup) {
  270. ast_set_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
  271. }
  272. cfg = ast_config_load2(stun_conf_file, "res_stun_monitor", config_flags);
  273. if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
  274. ast_log(LOG_WARNING, "Unable to load config %s\n", stun_conf_file);
  275. return -1;
  276. }
  277. if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
  278. return 0;
  279. }
  280. /* clean up any previous open socket */
  281. stun_close_sock();
  282. args.stun_poll_failed_gripe = 0;
  283. /* set defaults */
  284. args.monitor_enabled = 0;
  285. args.refresh = DEFAULT_MONITOR_REFRESH;
  286. for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
  287. if (!strcasecmp(v->name, "stunaddr")) {
  288. if (setup_stunaddr(v->value)) {
  289. ast_log(LOG_WARNING, "Invalid STUN server address: %s at line %d\n",
  290. v->value, v->lineno);
  291. }
  292. } else if (!strcasecmp(v->name, "stunrefresh")) {
  293. if ((sscanf(v->value, "%30u", &args.refresh) != 1) || !args.refresh) {
  294. ast_log(LOG_WARNING, "Invalid stunrefresh value '%s', must be an integer > 0 at line %d\n", v->value, v->lineno);
  295. args.refresh = DEFAULT_MONITOR_REFRESH;
  296. }
  297. } else {
  298. ast_log(LOG_WARNING, "Invalid config option %s at line %d\n",
  299. v->value, v->lineno);
  300. }
  301. }
  302. ast_config_destroy(cfg);
  303. return 0;
  304. }
  305. static int __reload(int startup)
  306. {
  307. int res;
  308. ast_mutex_lock(&args.lock);
  309. if (!(res = load_config(startup)) && args.monitor_enabled) {
  310. res = stun_start_monitor();
  311. }
  312. ast_mutex_unlock(&args.lock);
  313. if (res < 0 || !args.monitor_enabled) {
  314. stun_stop_monitor();
  315. }
  316. return res;
  317. }
  318. static int reload(void)
  319. {
  320. return __reload(0);
  321. }
  322. static int unload_module(void)
  323. {
  324. stun_stop_monitor();
  325. ast_mutex_destroy(&args.lock);
  326. return 0;
  327. }
  328. static int load_module(void)
  329. {
  330. ast_mutex_init(&args.lock);
  331. args.stun_sock = -1;
  332. if (__reload(1)) {
  333. ast_mutex_destroy(&args.lock);
  334. return AST_MODULE_LOAD_DECLINE;
  335. }
  336. return AST_MODULE_LOAD_SUCCESS;
  337. }
  338. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "STUN Network Monitor",
  339. .load = load_module,
  340. .unload = unload_module,
  341. .reload = reload,
  342. .load_pri = AST_MODPRI_CHANNEL_DEPEND
  343. );