| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2010, Digium, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * David Vossel <dvossel@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \file | 
					
						
							|  |  |  |  * \brief STUN Network Monitor | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \author David Vossel <dvossel@digium.com> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-14 20:28:54 +00:00
										 |  |  | /*** MODULEINFO
 | 
					
						
							|  |  |  | 	<support_level>core</support_level> | 
					
						
							|  |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/sched.h"
 | 
					
						
							|  |  |  | #include "asterisk/config.h"
 | 
					
						
							|  |  |  | #include "asterisk/stun.h"
 | 
					
						
							|  |  |  | #include "asterisk/netsock2.h"
 | 
					
						
							|  |  |  | #include "asterisk/lock.h"
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | #include "asterisk/acl.h"
 | 
					
						
							| 
									
										
										
										
											2012-07-05 21:36:41 +00:00
										 |  |  | #include "asterisk/cli.h"
 | 
					
						
							| 
									
										
										
										
											2013-05-03 18:03:26 +00:00
										 |  |  | #include "asterisk/json.h"
 | 
					
						
							| 
									
										
										
										
											2013-07-08 14:42:57 +00:00
										 |  |  | #include "asterisk/stasis.h"
 | 
					
						
							|  |  |  | #include "asterisk/stasis_system.h"
 | 
					
						
							| 
									
										
										
										
											2013-05-03 18:03:26 +00:00
										 |  |  | #include "asterisk/astobj2.h"
 | 
					
						
							| 
									
										
										
										
											2012-07-05 21:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | #define DEFAULT_MONITOR_REFRESH 30	/*!< Default refresh period in seconds */
 | 
					
						
							| 
									
										
										
										
											2012-07-05 21:36:41 +00:00
										 |  |  | #define DEFAULT_RETRIES 3		/*!< retries shown in stun show status
 | 
					
						
							|  |  |  | 					     matching static retries in stun.c */ | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static const char stun_conf_file[] = "res_stun_monitor.conf"; | 
					
						
							| 
									
										
										
										
											2010-12-20 17:15:54 +00:00
										 |  |  | static struct ast_sched_context *sched; | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static struct { | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	/*! STUN monitor protection lock. */ | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 	ast_mutex_t lock; | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	/*! Current perceived external address. */ | 
					
						
							|  |  |  | 	struct sockaddr_in external_addr; | 
					
						
							|  |  |  | 	/*! STUN server host name. */ | 
					
						
							|  |  |  | 	const char *server_hostname; | 
					
						
							|  |  |  | 	/*! Port of STUN server to use */ | 
					
						
							|  |  |  | 	unsigned int stun_port; | 
					
						
							|  |  |  | 	/*! Number of seconds between polls to the STUN server for the external address. */ | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 	unsigned int refresh; | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	/*! Monitoring STUN socket. */ | 
					
						
							|  |  |  | 	int stun_sock; | 
					
						
							|  |  |  | 	/*! TRUE if the STUN monitor is enabled. */ | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 	unsigned int monitor_enabled:1; | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	/*! TRUE if the perceived external address is valid/known. */ | 
					
						
							|  |  |  | 	unsigned int external_addr_known:1; | 
					
						
							|  |  |  | 	/*! TRUE if we have already griped about a STUN poll failing. */ | 
					
						
							|  |  |  | 	unsigned int stun_poll_failed_gripe:1; | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | } args; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | static void stun_close_sock(void) | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	if (0 <= args.stun_sock) { | 
					
						
							|  |  |  | 		close(args.stun_sock); | 
					
						
							|  |  |  | 		args.stun_sock = -1; | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* \brief called by scheduler to send STUN request */ | 
					
						
							|  |  |  | static int stun_monitor_request(const void *blarg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int res; | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	struct sockaddr_in answer; | 
					
						
							|  |  |  | 	static const struct sockaddr_in no_addr = { 0, }; | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_lock(&args.lock); | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	if (!args.monitor_enabled) { | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 		goto monitor_request_cleanup; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	if (args.stun_sock < 0) { | 
					
						
							|  |  |  | 		struct ast_sockaddr stun_addr; | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 		/* STUN socket not open.  Refresh the server DNS address resolution. */ | 
					
						
							|  |  |  | 		if (!args.server_hostname) { | 
					
						
							|  |  |  | 			/* No STUN hostname? */ | 
					
						
							|  |  |  | 			goto monitor_request_cleanup; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 		/* Lookup STUN address. */ | 
					
						
							|  |  |  | 		memset(&stun_addr, 0, sizeof(stun_addr)); | 
					
						
							|  |  |  | 		stun_addr.ss.ss_family = AF_INET; | 
					
						
							|  |  |  | 		if (ast_get_ip(&stun_addr, args.server_hostname)) { | 
					
						
							|  |  |  | 			/* Lookup failed. */ | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "Unable to lookup STUN server '%s'\n", | 
					
						
							|  |  |  | 				args.server_hostname); | 
					
						
							|  |  |  | 			goto monitor_request_cleanup; | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 		ast_sockaddr_set_port(&stun_addr, args.stun_port); | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 		/* open socket binding */ | 
					
						
							|  |  |  | 		args.stun_sock = socket(AF_INET, SOCK_DGRAM, 0); | 
					
						
							|  |  |  | 		if (args.stun_sock < 0) { | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 			goto monitor_request_cleanup; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 		if (ast_connect(args.stun_sock, &stun_addr)) { | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "STUN Failed to connect to %s: %s\n", | 
					
						
							|  |  |  | 				ast_sockaddr_stringify(&stun_addr), strerror(errno)); | 
					
						
							|  |  |  | 			stun_close_sock(); | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 			goto monitor_request_cleanup; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	res = ast_stun_request(args.stun_sock, NULL, NULL, &answer); | 
					
						
							|  |  |  | 	if (res) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * STUN request timed out or errored. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * Refresh the server DNS address resolution next time around. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if (!args.stun_poll_failed_gripe) { | 
					
						
							|  |  |  | 			args.stun_poll_failed_gripe = 1; | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "STUN poll %s. Re-evaluating STUN server address.\n", | 
					
						
							|  |  |  | 				res < 0 ? "failed" : "got no response"); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		stun_close_sock(); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		args.stun_poll_failed_gripe = 0; | 
					
						
							|  |  |  | 		if (memcmp(&no_addr, &answer, sizeof(no_addr)) | 
					
						
							|  |  |  | 			&& memcmp(&args.external_addr, &answer, sizeof(args.external_addr))) { | 
					
						
							|  |  |  | 			const char *newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr)); | 
					
						
							|  |  |  | 			int newport = ntohs(answer.sin_port); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ast_log(LOG_NOTICE, "Old external address/port %s:%d now seen as %s:%d.\n", | 
					
						
							|  |  |  | 				ast_inet_ntoa(args.external_addr.sin_addr), | 
					
						
							|  |  |  | 				ntohs(args.external_addr.sin_port), newaddr, newport); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			args.external_addr = answer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (args.external_addr_known) { | 
					
						
							| 
									
										
										
										
											2013-05-03 18:03:26 +00:00
										 |  |  | 				RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); | 
					
						
							|  |  |  | 				RAII_VAR(struct ast_json_payload *, json_payload, NULL, ao2_cleanup); | 
					
						
							| 
									
										
										
										
											2014-08-06 12:55:28 +00:00
										 |  |  | 				RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (!ast_network_change_type()) { | 
					
						
							|  |  |  | 					goto publish_failure; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2013-05-03 18:03:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				/* This json_object doesn't actually contain anything yet. We have to reference something
 | 
					
						
							|  |  |  | 				 * for stasis, and this is useful for if we want to ever add data for any reason. */ | 
					
						
							| 
									
										
										
										
											2014-08-06 12:55:28 +00:00
										 |  |  | 				json_object = ast_json_object_create(); | 
					
						
							| 
									
										
										
										
											2013-05-03 18:03:26 +00:00
										 |  |  | 				if (!json_object) { | 
					
						
							|  |  |  | 					goto publish_failure; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (!(json_payload = ast_json_payload_create(json_object))) { | 
					
						
							|  |  |  | 					goto publish_failure; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				msg = stasis_message_create(ast_network_change_type(), json_payload); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | publish_failure: | 
					
						
							|  |  |  | 				if (msg) { | 
					
						
							|  |  |  | 					stasis_publish(ast_system_topic(), msg); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					ast_log(LOG_ERROR, "Failed to issue network change message.\n"); | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				/* this was the first external address we found, do not alert listeners
 | 
					
						
							|  |  |  | 				 * until this address changes to something else. */ | 
					
						
							|  |  |  | 				args.external_addr_known = 1; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | monitor_request_cleanup: | 
					
						
							|  |  |  | 	/* always refresh this scheduler item.  It will be removed elsewhere when
 | 
					
						
							|  |  |  | 	 * it is supposed to go away */ | 
					
						
							|  |  |  | 	res = args.refresh * 1000; | 
					
						
							|  |  |  | 	ast_mutex_unlock(&args.lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Stops the STUN monitor thread. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  |  * \note do not hold the args->lock while calling this | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | static void stun_stop_monitor(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	ast_mutex_lock(&args.lock); | 
					
						
							|  |  |  | 	args.monitor_enabled = 0; | 
					
						
							|  |  |  | 	ast_free((char *) args.server_hostname); | 
					
						
							|  |  |  | 	args.server_hostname = NULL; | 
					
						
							|  |  |  | 	stun_close_sock(); | 
					
						
							|  |  |  | 	ast_mutex_unlock(&args.lock); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 	if (sched) { | 
					
						
							| 
									
										
										
										
											2010-12-20 17:15:54 +00:00
										 |  |  | 		ast_sched_context_destroy(sched); | 
					
						
							|  |  |  | 		sched = NULL; | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 		ast_log(LOG_NOTICE, "STUN monitor stopped\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Starts the STUN monitor thread. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  |  * \note The args->lock MUST be held when calling this function | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | static int stun_start_monitor(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* if scheduler thread is not started, make sure to start it now */ | 
					
						
							|  |  |  | 	if (sched) { | 
					
						
							|  |  |  | 		return 0; /* already started */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-20 17:15:54 +00:00
										 |  |  | 	if (!(sched = ast_sched_context_create())) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Failed to create stun monitor scheduler context\n"); | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-20 17:15:54 +00:00
										 |  |  | 	if (ast_sched_start_thread(sched)) { | 
					
						
							|  |  |  | 		ast_sched_context_destroy(sched); | 
					
						
							|  |  |  | 		sched = NULL; | 
					
						
							|  |  |  | 		stun_close_sock(); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_sched_add_variable(sched, (args.refresh * 1000), stun_monitor_request, NULL, 1) < 0) { | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 		ast_log(LOG_ERROR, "Unable to schedule STUN network monitor \n"); | 
					
						
							| 
									
										
										
										
											2010-12-20 17:15:54 +00:00
										 |  |  | 		ast_sched_context_destroy(sched); | 
					
						
							|  |  |  | 		sched = NULL; | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_log(LOG_NOTICE, "STUN monitor started\n"); | 
					
						
							| 
									
										
										
										
											2010-12-20 17:15:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Parse and setup the stunaddr parameter. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param value Configuration parameter variable value. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \retval 0 on success. | 
					
						
							|  |  |  |  * \retval -1 on error. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-04-14 17:50:56 -04:00
										 |  |  | static int setup_stunaddr(const char *value, int reload) | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	char *val; | 
					
						
							|  |  |  | 	char *host_str; | 
					
						
							|  |  |  | 	char *port_str; | 
					
						
							|  |  |  | 	unsigned int port; | 
					
						
							|  |  |  | 	struct ast_sockaddr stun_addr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_strlen_zero(value)) { | 
					
						
							|  |  |  | 		/* Setting to an empty value disables STUN monitoring. */ | 
					
						
							|  |  |  | 		args.monitor_enabled = 0; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = ast_strdupa(value); | 
					
						
							|  |  |  | 	if (!ast_sockaddr_split_hostport(val, &host_str, &port_str, 0) | 
					
						
							|  |  |  | 		|| ast_strlen_zero(host_str)) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Determine STUN port */ | 
					
						
							|  |  |  | 	if (ast_strlen_zero(port_str) | 
					
						
							|  |  |  | 		|| 1 != sscanf(port_str, "%30u", &port)) { | 
					
						
							|  |  |  | 		port = STANDARD_STUN_PORT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	host_str = ast_strdup(host_str); | 
					
						
							|  |  |  | 	if (!host_str) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Lookup STUN address. */ | 
					
						
							|  |  |  | 	memset(&stun_addr, 0, sizeof(stun_addr)); | 
					
						
							|  |  |  | 	stun_addr.ss.ss_family = AF_INET; | 
					
						
							|  |  |  | 	if (ast_get_ip(&stun_addr, host_str)) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Unable to lookup STUN server '%s'\n", host_str); | 
					
						
							| 
									
										
										
										
											2017-04-14 17:50:56 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* Only treat this as fatal if we are reloading */ | 
					
						
							|  |  |  | 		if (reload) { | 
					
						
							|  |  |  | 			ast_free(host_str); | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Save STUN server information. */ | 
					
						
							|  |  |  | 	ast_free((char *) args.server_hostname); | 
					
						
							|  |  |  | 	args.server_hostname = host_str; | 
					
						
							|  |  |  | 	args.stun_port = port; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Enable STUN monitor */ | 
					
						
							|  |  |  | 	args.monitor_enabled = 1; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | static int load_config(int startup) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_flags config_flags = { 0, }; | 
					
						
							|  |  |  | 	struct ast_config *cfg; | 
					
						
							|  |  |  | 	struct ast_variable *v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!startup) { | 
					
						
							|  |  |  | 		ast_set_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	cfg = ast_config_load2(stun_conf_file, "res_stun_monitor", config_flags); | 
					
						
							|  |  |  | 	if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { | 
					
						
							| 
									
										
										
										
											2010-08-24 18:45:57 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Unable to load config %s\n", stun_conf_file); | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	if (cfg == CONFIG_STATUS_FILEUNCHANGED) { | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	/* clean up any previous open socket */ | 
					
						
							|  |  |  | 	stun_close_sock(); | 
					
						
							|  |  |  | 	args.stun_poll_failed_gripe = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 	/* set defaults */ | 
					
						
							|  |  |  | 	args.monitor_enabled = 0; | 
					
						
							|  |  |  | 	args.refresh = DEFAULT_MONITOR_REFRESH; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (v = ast_variable_browse(cfg, "general"); v; v = v->next) { | 
					
						
							|  |  |  | 		if (!strcasecmp(v->name, "stunaddr")) { | 
					
						
							| 
									
										
										
										
											2017-04-14 17:50:56 -04:00
										 |  |  | 			if (setup_stunaddr(v->value, !startup)) { | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 				ast_log(LOG_WARNING, "Invalid STUN server address: %s at line %d\n", | 
					
						
							|  |  |  | 					v->value, v->lineno); | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} else if (!strcasecmp(v->name, "stunrefresh")) { | 
					
						
							|  |  |  | 			if ((sscanf(v->value, "%30u", &args.refresh) != 1) || !args.refresh) { | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "Invalid stunrefresh value '%s', must be an integer > 0 at line %d\n", v->value, v->lineno); | 
					
						
							|  |  |  | 				args.refresh = DEFAULT_MONITOR_REFRESH; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 			ast_log(LOG_WARNING, "Invalid config option %s at line %d\n", | 
					
						
							|  |  |  | 				v->value, v->lineno); | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_config_destroy(cfg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-05 21:36:41 +00:00
										 |  |  | /*! \brief Execute stun show status command */ | 
					
						
							|  |  |  | static void _stun_show_status(int fd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const char *status; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-09 22:49:26 +00:00
										 |  |  | #define DATALN "%-25s %-5u %-7u %-8d %-7s %-16s %-d\n"
 | 
					
						
							| 
									
										
										
										
											2012-07-05 21:36:41 +00:00
										 |  |  | #define HEADER "%-25s %-5s %-7s %-8s %-7s %-16s %-s\n"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*! we only have one stun server, but start to play well with more */ | 
					
						
							|  |  |  | 	ast_cli(fd, HEADER, "Hostname", "Port", "Period", "Retries", "Status", "ExternAddr", "ExternPort"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (args.stun_poll_failed_gripe) { | 
					
						
							|  |  |  | 		status = "FAIL"; | 
					
						
							|  |  |  | 	} else if (args.external_addr_known) { | 
					
						
							|  |  |  | 		status = "OK"; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		status = "INIT"; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ast_cli( fd, DATALN, | 
					
						
							|  |  |  | 		     args.server_hostname, | 
					
						
							|  |  |  | 		     args.stun_port, | 
					
						
							|  |  |  | 		     args.refresh, | 
					
						
							|  |  |  | 		     DEFAULT_RETRIES, | 
					
						
							|  |  |  | 		     status, | 
					
						
							|  |  |  | 		     ast_inet_ntoa(args.external_addr.sin_addr), | 
					
						
							|  |  |  | 		     ntohs(args.external_addr.sin_port) | 
					
						
							|  |  |  | 		   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #undef HEADER
 | 
					
						
							|  |  |  | #undef DATALN
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static char *handle_cli_stun_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case CLI_INIT: | 
					
						
							|  |  |  | 		e->command = "stun show status"; | 
					
						
							|  |  |  | 		e->usage = | 
					
						
							|  |  |  | 		    "Usage: stun show status\n" | 
					
						
							|  |  |  | 		    "       List all known STUN servers and statuses.\n"; | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	case CLI_GENERATE: | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (a->argc != 3) { | 
					
						
							|  |  |  | 		return CLI_SHOWUSAGE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_stun_show_status(a->fd); | 
					
						
							|  |  |  | 	return CLI_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_cli_entry cli_stun[] = { | 
					
						
							|  |  |  | 	AST_CLI_DEFINE(handle_cli_stun_show_status, "Show STUN servers and statuses"), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | static int __reload(int startup) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int res; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_lock(&args.lock); | 
					
						
							|  |  |  | 	if (!(res = load_config(startup)) && args.monitor_enabled) { | 
					
						
							|  |  |  | 		res = stun_start_monitor(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ast_mutex_unlock(&args.lock); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	if (res < 0 || !args.monitor_enabled) { | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 		stun_stop_monitor(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int reload(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return __reload(0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int unload_module(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	stun_stop_monitor(); | 
					
						
							|  |  |  | 	ast_mutex_destroy(&args.lock); | 
					
						
							| 
									
										
										
										
											2012-07-05 21:36:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*! Unregister CLI commands */ | 
					
						
							|  |  |  | 	ast_cli_unregister_multiple(cli_stun, ARRAY_LEN(cli_stun)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int load_module(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ast_mutex_init(&args.lock); | 
					
						
							| 
									
										
										
										
											2011-12-01 21:19:41 +00:00
										 |  |  | 	args.stun_sock = -1; | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 	if (__reload(1)) { | 
					
						
							|  |  |  | 		ast_mutex_destroy(&args.lock); | 
					
						
							| 
									
										
										
										
											2010-08-23 12:09:17 +00:00
										 |  |  | 		return AST_MODULE_LOAD_DECLINE; | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-05 21:36:41 +00:00
										 |  |  | 	/*! Register CLI commands */ | 
					
						
							|  |  |  | 	ast_cli_register_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-13 20:05:44 +00:00
										 |  |  | 	return AST_MODULE_LOAD_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "STUN Network Monitor", | 
					
						
							| 
									
										
										
										
											2015-05-05 20:49:04 -04:00
										 |  |  | 	.support_level = AST_MODULE_SUPPORT_CORE, | 
					
						
							|  |  |  | 	.load = load_module, | 
					
						
							|  |  |  | 	.unload = unload_module, | 
					
						
							|  |  |  | 	.reload = reload, | 
					
						
							|  |  |  | 	.load_pri = AST_MODPRI_CHANNEL_DEPEND | 
					
						
							|  |  |  | ); |