STUN Network Monitor. More...
#include "asterisk.h"
#include "asterisk/module.h"
#include "asterisk/event.h"
#include "asterisk/sched.h"
#include "asterisk/config.h"
#include "asterisk/stun.h"
#include "asterisk/netsock2.h"
#include "asterisk/lock.h"
#include "asterisk/acl.h"
#include <fcntl.h>
Go to the source code of this file.
Defines | |
#define | DEFAULT_MONITOR_REFRESH 30 |
Functions | |
static void | __reg_module (void) |
static int | __reload (int startup) |
static void | __unreg_module (void) |
static int | load_config (int startup) |
static int | load_module (void) |
static int | reload (void) |
static int | setup_stunaddr (const char *value) |
static void | stun_close_sock (void) |
static int | stun_monitor_request (const void *blarg) |
static int | stun_start_monitor (void) |
static void | stun_stop_monitor (void) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "STUN Network Monitor" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND } |
struct { | |
struct sockaddr_in external_addr | |
unsigned int external_addr_known:1 | |
ast_mutex_t lock | |
unsigned int monitor_enabled:1 | |
unsigned int refresh | |
const char * server_hostname | |
unsigned int stun_poll_failed_gripe:1 | |
unsigned int stun_port | |
int stun_sock | |
} | args |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_sched_thread * | sched |
static const char | stun_conf_file [] = "res_stun_monitor.conf" |
STUN Network Monitor.
Definition in file res_stun_monitor.c.
#define DEFAULT_MONITOR_REFRESH 30 |
Default refresh period in seconds
Definition at line 44 of file res_stun_monitor.c.
Referenced by load_config().
static void __reg_module | ( | void | ) | [static] |
Definition at line 388 of file res_stun_monitor.c.
static int __reload | ( | int | startup | ) | [static] |
Definition at line 342 of file res_stun_monitor.c.
References args, ast_mutex_lock, ast_mutex_unlock, load_config(), stun_start_monitor(), and stun_stop_monitor().
Referenced by load_module(), and reload().
00343 { 00344 int res; 00345 00346 ast_mutex_lock(&args.lock); 00347 if (!(res = load_config(startup)) && args.monitor_enabled) { 00348 res = stun_start_monitor(); 00349 } 00350 ast_mutex_unlock(&args.lock); 00351 00352 if (res < 0 || !args.monitor_enabled) { 00353 stun_stop_monitor(); 00354 } 00355 00356 return res; 00357 }
static void __unreg_module | ( | void | ) | [static] |
Definition at line 388 of file res_stun_monitor.c.
static int load_config | ( | int | startup | ) | [static] |
Definition at line 293 of file res_stun_monitor.c.
References args, ast_config_destroy(), ast_config_load2(), ast_log(), ast_set_flag, ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_MONITOR_REFRESH, ast_variable::lineno, LOG_WARNING, ast_variable::name, ast_variable::next, setup_stunaddr(), stun_close_sock(), and ast_variable::value.
Referenced by __reload().
00294 { 00295 struct ast_flags config_flags = { 0, }; 00296 struct ast_config *cfg; 00297 struct ast_variable *v; 00298 00299 if (!startup) { 00300 ast_set_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); 00301 } 00302 00303 cfg = ast_config_load2(stun_conf_file, "res_stun_monitor", config_flags); 00304 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { 00305 ast_log(LOG_WARNING, "Unable to load config %s\n", stun_conf_file); 00306 return -1; 00307 } 00308 if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 00309 return 0; 00310 } 00311 00312 /* clean up any previous open socket */ 00313 stun_close_sock(); 00314 args.stun_poll_failed_gripe = 0; 00315 00316 /* set defaults */ 00317 args.monitor_enabled = 0; 00318 args.refresh = DEFAULT_MONITOR_REFRESH; 00319 00320 for (v = ast_variable_browse(cfg, "general"); v; v = v->next) { 00321 if (!strcasecmp(v->name, "stunaddr")) { 00322 if (setup_stunaddr(v->value)) { 00323 ast_log(LOG_WARNING, "Invalid STUN server address: %s at line %d\n", 00324 v->value, v->lineno); 00325 } 00326 } else if (!strcasecmp(v->name, "stunrefresh")) { 00327 if ((sscanf(v->value, "%30u", &args.refresh) != 1) || !args.refresh) { 00328 ast_log(LOG_WARNING, "Invalid stunrefresh value '%s', must be an integer > 0 at line %d\n", v->value, v->lineno); 00329 args.refresh = DEFAULT_MONITOR_REFRESH; 00330 } 00331 } else { 00332 ast_log(LOG_WARNING, "Invalid config option %s at line %d\n", 00333 v->value, v->lineno); 00334 } 00335 } 00336 00337 ast_config_destroy(cfg); 00338 00339 return 0; 00340 }
static int load_module | ( | void | ) | [static] |
Definition at line 371 of file res_stun_monitor.c.
References __reload(), args, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_mutex_destroy, and ast_mutex_init.
00372 { 00373 ast_mutex_init(&args.lock); 00374 args.stun_sock = -1; 00375 if (__reload(1)) { 00376 ast_mutex_destroy(&args.lock); 00377 return AST_MODULE_LOAD_DECLINE; 00378 } 00379 00380 return AST_MODULE_LOAD_SUCCESS; 00381 }
static int reload | ( | void | ) | [static] |
Definition at line 359 of file res_stun_monitor.c.
References __reload().
00360 { 00361 return __reload(0); 00362 }
static int setup_stunaddr | ( | const char * | value | ) | [static] |
Definition at line 243 of file res_stun_monitor.c.
References args, ast_free, ast_get_ip(), ast_log(), ast_sockaddr_split_hostport(), ast_strdup, ast_strdupa, ast_strlen_zero(), LOG_WARNING, ast_sockaddr::ss, and STANDARD_STUN_PORT.
Referenced by load_config().
00244 { 00245 char *val; 00246 char *host_str; 00247 char *port_str; 00248 unsigned int port; 00249 struct ast_sockaddr stun_addr; 00250 00251 if (ast_strlen_zero(value)) { 00252 /* Setting to an empty value disables STUN monitoring. */ 00253 args.monitor_enabled = 0; 00254 return 0; 00255 } 00256 00257 val = ast_strdupa(value); 00258 if (!ast_sockaddr_split_hostport(val, &host_str, &port_str, 0) 00259 || ast_strlen_zero(host_str)) { 00260 return -1; 00261 } 00262 00263 /* Determine STUN port */ 00264 if (ast_strlen_zero(port_str) 00265 || 1 != sscanf(port_str, "%30u", &port)) { 00266 port = STANDARD_STUN_PORT; 00267 } 00268 00269 host_str = ast_strdup(host_str); 00270 if (!host_str) { 00271 return -1; 00272 } 00273 00274 /* Lookup STUN address. */ 00275 memset(&stun_addr, 0, sizeof(stun_addr)); 00276 stun_addr.ss.ss_family = AF_INET; 00277 if (ast_get_ip(&stun_addr, host_str)) { 00278 ast_log(LOG_WARNING, "Unable to lookup STUN server '%s'\n", host_str); 00279 ast_free(host_str); 00280 return -1; 00281 } 00282 00283 /* Save STUN server information. */ 00284 ast_free((char *) args.server_hostname); 00285 args.server_hostname = host_str; 00286 args.stun_port = port; 00287 00288 /* Enable STUN monitor */ 00289 args.monitor_enabled = 1; 00290 return 0; 00291 }
static void stun_close_sock | ( | void | ) | [static] |
Definition at line 70 of file res_stun_monitor.c.
References args.
Referenced by load_config(), stun_monitor_request(), and stun_stop_monitor().
static int stun_monitor_request | ( | const void * | blarg | ) | [static] |
Definition at line 79 of file res_stun_monitor.c.
References args, ast_connect(), ast_event_destroy(), AST_EVENT_IE_END, AST_EVENT_NETWORK_CHANGE, ast_event_new(), ast_event_queue(), ast_get_ip(), ast_inet_ntoa(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_sockaddr_set_port, ast_sockaddr_stringify(), ast_strdupa, ast_stun_request(), errno, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_sockaddr::ss, and stun_close_sock().
Referenced by stun_start_monitor().
00080 { 00081 int res; 00082 struct sockaddr_in answer; 00083 static const struct sockaddr_in no_addr = { 0, }; 00084 00085 ast_mutex_lock(&args.lock); 00086 if (!args.monitor_enabled) { 00087 goto monitor_request_cleanup; 00088 } 00089 00090 if (args.stun_sock < 0) { 00091 struct ast_sockaddr stun_addr; 00092 00093 /* STUN socket not open. Refresh the server DNS address resolution. */ 00094 if (!args.server_hostname) { 00095 /* No STUN hostname? */ 00096 goto monitor_request_cleanup; 00097 } 00098 00099 /* Lookup STUN address. */ 00100 memset(&stun_addr, 0, sizeof(stun_addr)); 00101 stun_addr.ss.ss_family = AF_INET; 00102 if (ast_get_ip(&stun_addr, args.server_hostname)) { 00103 /* Lookup failed. */ 00104 ast_log(LOG_WARNING, "Unable to lookup STUN server '%s'\n", 00105 args.server_hostname); 00106 goto monitor_request_cleanup; 00107 } 00108 ast_sockaddr_set_port(&stun_addr, args.stun_port); 00109 00110 /* open socket binding */ 00111 args.stun_sock = socket(AF_INET, SOCK_DGRAM, 0); 00112 if (args.stun_sock < 0) { 00113 ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno)); 00114 goto monitor_request_cleanup; 00115 } 00116 if (ast_connect(args.stun_sock, &stun_addr)) { 00117 ast_log(LOG_WARNING, "STUN Failed to connect to %s: %s\n", 00118 ast_sockaddr_stringify(&stun_addr), strerror(errno)); 00119 stun_close_sock(); 00120 goto monitor_request_cleanup; 00121 } 00122 } 00123 00124 res = ast_stun_request(args.stun_sock, NULL, NULL, &answer); 00125 if (res) { 00126 /* 00127 * STUN request timed out or errored. 00128 * 00129 * Refresh the server DNS address resolution next time around. 00130 */ 00131 if (!args.stun_poll_failed_gripe) { 00132 args.stun_poll_failed_gripe = 1; 00133 ast_log(LOG_WARNING, "STUN poll %s. Re-evaluating STUN server address.\n", 00134 res < 0 ? "failed" : "got no response"); 00135 } 00136 stun_close_sock(); 00137 } else { 00138 args.stun_poll_failed_gripe = 0; 00139 if (memcmp(&no_addr, &answer, sizeof(no_addr)) 00140 && memcmp(&args.external_addr, &answer, sizeof(args.external_addr))) { 00141 const char *newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr)); 00142 int newport = ntohs(answer.sin_port); 00143 00144 ast_log(LOG_NOTICE, "Old external address/port %s:%d now seen as %s:%d.\n", 00145 ast_inet_ntoa(args.external_addr.sin_addr), 00146 ntohs(args.external_addr.sin_port), newaddr, newport); 00147 00148 args.external_addr = answer; 00149 00150 if (args.external_addr_known) { 00151 struct ast_event *event; 00152 00153 /* 00154 * The external address was already known, and has changed... 00155 * generate event. 00156 */ 00157 event = ast_event_new(AST_EVENT_NETWORK_CHANGE, AST_EVENT_IE_END); 00158 if (!event) { 00159 ast_log(LOG_ERROR, "Could not create AST_EVENT_NETWORK_CHANGE event.\n"); 00160 } else if (ast_event_queue(event)) { 00161 ast_event_destroy(event); 00162 ast_log(LOG_ERROR, "Could not queue AST_EVENT_NETWORK_CHANGE event.\n"); 00163 } 00164 } else { 00165 /* this was the first external address we found, do not alert listeners 00166 * until this address changes to something else. */ 00167 args.external_addr_known = 1; 00168 } 00169 } 00170 } 00171 00172 monitor_request_cleanup: 00173 /* always refresh this scheduler item. It will be removed elsewhere when 00174 * it is supposed to go away */ 00175 res = args.refresh * 1000; 00176 ast_mutex_unlock(&args.lock); 00177 00178 return res; 00179 }
static int stun_start_monitor | ( | void | ) | [static] |
Definition at line 212 of file res_stun_monitor.c.
References args, ast_log(), ast_sched_thread_add_variable(), ast_sched_thread_create(), ast_sched_thread_destroy(), LOG_ERROR, LOG_NOTICE, and stun_monitor_request().
Referenced by __reload().
00213 { 00214 /* if scheduler thread is not started, make sure to start it now */ 00215 if (sched) { 00216 return 0; /* already started */ 00217 } 00218 00219 if (!(sched = ast_sched_thread_create())) { 00220 ast_log(LOG_ERROR, "Failed to create stun monitor scheduler thread\n"); 00221 return -1; 00222 } 00223 00224 if (ast_sched_thread_add_variable(sched, (args.refresh * 1000), stun_monitor_request, NULL, 1) < 0) { 00225 ast_log(LOG_ERROR, "Unable to schedule STUN network monitor \n"); 00226 sched = ast_sched_thread_destroy(sched); 00227 return -1; 00228 } 00229 00230 ast_log(LOG_NOTICE, "STUN monitor started\n"); 00231 return 0; 00232 }
static void stun_stop_monitor | ( | void | ) | [static] |
Definition at line 189 of file res_stun_monitor.c.
References args, ast_free, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_sched_thread_destroy(), LOG_NOTICE, and stun_close_sock().
Referenced by __reload(), and unload_module().
00190 { 00191 ast_mutex_lock(&args.lock); 00192 args.monitor_enabled = 0; 00193 ast_free((char *) args.server_hostname); 00194 args.server_hostname = NULL; 00195 stun_close_sock(); 00196 ast_mutex_unlock(&args.lock); 00197 00198 if (sched) { 00199 sched = ast_sched_thread_destroy(sched); 00200 ast_log(LOG_NOTICE, "STUN monitor stopped\n"); 00201 } 00202 }
static int unload_module | ( | void | ) | [static] |
Definition at line 364 of file res_stun_monitor.c.
References args, ast_mutex_destroy, and stun_stop_monitor().
00365 { 00366 stun_stop_monitor(); 00367 ast_mutex_destroy(&args.lock); 00368 return 0; 00369 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "STUN Network Monitor" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND } [static] |
Definition at line 388 of file res_stun_monitor.c.
struct { ... } args [static] |
Referenced by __reload(), acf_curl_helper(), acf_isexten_exec(), acf_jabberreceive_read(), acf_jabberstatus_read(), acf_meetme_info(), acf_odbc_read(), acf_odbc_write(), acf_rand_exec(), acf_strftime(), acf_strptime(), acf_transaction_read(), acf_transaction_write(), acf_version_exec(), acf_vmcount_exec(), add_agent(), add_cfg_entry(), add_rt_cfg_entry(), add_rt_multi_cfg_entry(), admin_exec(), adsi_process(), aelsub_exec(), aes_helper(), agi_exec_full(), aji_join_exec(), aji_leave_exec(), aji_send_exec(), aji_sendgroup_exec(), aji_status_exec(), answer_exec_enable(), app_exec(), aqm_exec(), ast_cc_agent_status_response(), ast_cli_command_full(), ast_eivr_senddtmf(), ast_func_read(), ast_func_read2(), ast_func_write(), ast_queue_log(), asyncgoto_exec(), background_detect_exec(), bridge_exec(), build_profile(), builtin_automixmonitor(), builtin_automonitor(), calendar_query_exec(), calendar_query_result_exec(), callerid_read(), cc_do_state_change(), cc_request_state_change(), cc_status_response(), cdr_read(), cdr_write(), celgenuserevent_exec(), chanavail_exec(), channel_admin_exec(), channel_set_debug(), chanspy_exec(), cli_odbc_read(), cli_odbc_write(), conf_exec(), confbridge_exec(), config_function_read(), controlplayback_exec(), count_exec(), cut_internal(), dahdiras_exec(), determine_starting_point(), dial_exec_full(), dial_trunk(), dialgroup_write(), dictate_exec(), directory_exec(), disa_exec(), dundi_query_read(), dundi_result_read(), dundifunc_read(), enable_jack_hook(), enum_query_read(), enum_result_read(), exec_exec(), extenspy_exec(), festival_exec(), file_count_line(), file_read(), file_write(), filter(), find_call(), find_conf(), find_realtime_gw(), func_args(), func_header_read(), function_agent(), function_db_delete(), function_db_exists(), function_db_read(), function_db_write(), function_enum(), function_fieldnum_helper(), function_fieldqty_helper(), function_realtime_read(), function_realtime_readdestroy(), function_realtime_write(), function_txtcidname(), gosubif_exec(), handle_verbose(), hint_read(), iconv_read(), import_helper(), isAnsweringMachine(), isexten_function_read(), jb_debug_output(), jb_error_output(), jb_warning_output(), listfilter(), load_config(), load_module(), log_exec(), login_exec(), man_do_variable_value(), math(), misdn_call(), misdn_check_l2l1(), misdn_facility_exec(), misdn_request(), mixmonitor_exec(), originate_exec(), ospauth_exec(), ospfinished_exec(), osplookup_exec(), ospnext_exec(), oss_call(), oss_request(), page_exec(), parkandannounce_exec(), pbx_builtin_answer(), pbx_builtin_background(), pbx_builtin_resetcdr(), pbx_builtin_saydate(), pbx_builtin_saytime(), pbx_builtin_setvar_multiple(), pbx_builtin_waitexten(), peek_read(), pickup_by_name_cb(), pickupchan_exec(), playback_exec(), pp_each_extension_helper(), pp_each_user_helper(), pqm_exec(), privacy_exec(), process_applicationmap_line(), ql_exec(), queue_exec(), queue_function_memberpenalty_read(), queue_function_memberpenalty_write(), queue_function_queuememberpaused(), queue_function_queuememberstatus(), rcvfax_exec(), realtimefield_read(), receivefax_exec(), record_exec(), reg_source_db(), regex(), reload_single_member(), replace(), retrydial_exec(), rqm_exec(), run_station(), saycountedadj_exec(), saycountednoun_exec(), sayunixtime_exec(), senddtmf_exec(), sendfax_exec(), sendurl_exec(), setup_stunaddr(), shared_read(), shared_write(), shift_pop(), sip_acf_channel_read(), sip_request_call(), sip_tcptls_client_args_destructor(), sla_trunk_exec(), smdi_msg_read(), smdi_msg_retrieve_read(), sndfax_exec(), softhangup_exec(), speech_background(), speech_load(), srv_result_read(), stackpeek_read(), start_monitor_exec(), stun_close_sock(), stun_monitor_request(), stun_start_monitor(), stun_stop_monitor(), transfer_exec(), tryexec_exec(), unload_module(), unshift_push(), upqm_exec(), userevent_exec(), verbose_exec(), vm_box_exists(), vm_exec(), vm_execmain(), volume_write(), and zapateller_exec().
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 388 of file res_stun_monitor.c.
struct sockaddr_in external_addr |
Current perceived external address.
Definition at line 53 of file res_stun_monitor.c.
unsigned int external_addr_known |
TRUE if the perceived external address is valid/known.
Definition at line 65 of file res_stun_monitor.c.
STUN monitor protection lock.
Definition at line 51 of file res_stun_monitor.c.
unsigned int monitor_enabled |
TRUE if the STUN monitor is enabled.
Definition at line 63 of file res_stun_monitor.c.
unsigned int refresh |
Number of seconds between polls to the STUN server for the external address.
Definition at line 59 of file res_stun_monitor.c.
Referenced by iax2_ack_registry().
struct ast_sched_thread* sched [static] |
Definition at line 47 of file res_stun_monitor.c.
const char* server_hostname |
STUN server host name.
Definition at line 55 of file res_stun_monitor.c.
const char stun_conf_file[] = "res_stun_monitor.conf" [static] |
Definition at line 46 of file res_stun_monitor.c.
unsigned int stun_poll_failed_gripe |
TRUE if we have already griped about a STUN poll failing.
Definition at line 67 of file res_stun_monitor.c.
unsigned int stun_port |
Port of STUN server to use
Definition at line 57 of file res_stun_monitor.c.
int stun_sock |
Monitoring STUN socket.
Definition at line 61 of file res_stun_monitor.c.