00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369681 $")
00033
00034 #include "asterisk/module.h"
00035 #include "asterisk/event.h"
00036 #include "asterisk/sched.h"
00037 #include "asterisk/config.h"
00038 #include "asterisk/stun.h"
00039 #include "asterisk/netsock2.h"
00040 #include "asterisk/lock.h"
00041 #include "asterisk/acl.h"
00042 #include "asterisk/cli.h"
00043
00044 #include <fcntl.h>
00045
00046 #define DEFAULT_MONITOR_REFRESH 30
00047 #define DEFAULT_RETRIES 3
00048
00049
00050 static const char stun_conf_file[] = "res_stun_monitor.conf";
00051 static struct ast_sched_context *sched;
00052
00053 static struct {
00054
00055 ast_mutex_t lock;
00056
00057 struct sockaddr_in external_addr;
00058
00059 const char *server_hostname;
00060
00061 unsigned int stun_port;
00062
00063 unsigned int refresh;
00064
00065 int stun_sock;
00066
00067 unsigned int monitor_enabled:1;
00068
00069 unsigned int external_addr_known:1;
00070
00071 unsigned int stun_poll_failed_gripe:1;
00072 } args;
00073
00074 static void stun_close_sock(void)
00075 {
00076 if (0 <= args.stun_sock) {
00077 close(args.stun_sock);
00078 args.stun_sock = -1;
00079 }
00080 }
00081
00082
00083 static int stun_monitor_request(const void *blarg)
00084 {
00085 int res;
00086 struct sockaddr_in answer;
00087 static const struct sockaddr_in no_addr = { 0, };
00088
00089 ast_mutex_lock(&args.lock);
00090 if (!args.monitor_enabled) {
00091 goto monitor_request_cleanup;
00092 }
00093
00094 if (args.stun_sock < 0) {
00095 struct ast_sockaddr stun_addr;
00096
00097
00098 if (!args.server_hostname) {
00099
00100 goto monitor_request_cleanup;
00101 }
00102
00103
00104 memset(&stun_addr, 0, sizeof(stun_addr));
00105 stun_addr.ss.ss_family = AF_INET;
00106 if (ast_get_ip(&stun_addr, args.server_hostname)) {
00107
00108 ast_log(LOG_WARNING, "Unable to lookup STUN server '%s'\n",
00109 args.server_hostname);
00110 goto monitor_request_cleanup;
00111 }
00112 ast_sockaddr_set_port(&stun_addr, args.stun_port);
00113
00114
00115 args.stun_sock = socket(AF_INET, SOCK_DGRAM, 0);
00116 if (args.stun_sock < 0) {
00117 ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
00118 goto monitor_request_cleanup;
00119 }
00120 if (ast_connect(args.stun_sock, &stun_addr)) {
00121 ast_log(LOG_WARNING, "STUN Failed to connect to %s: %s\n",
00122 ast_sockaddr_stringify(&stun_addr), strerror(errno));
00123 stun_close_sock();
00124 goto monitor_request_cleanup;
00125 }
00126 }
00127
00128 res = ast_stun_request(args.stun_sock, NULL, NULL, &answer);
00129 if (res) {
00130
00131
00132
00133
00134
00135 if (!args.stun_poll_failed_gripe) {
00136 args.stun_poll_failed_gripe = 1;
00137 ast_log(LOG_WARNING, "STUN poll %s. Re-evaluating STUN server address.\n",
00138 res < 0 ? "failed" : "got no response");
00139 }
00140 stun_close_sock();
00141 } else {
00142 args.stun_poll_failed_gripe = 0;
00143 if (memcmp(&no_addr, &answer, sizeof(no_addr))
00144 && memcmp(&args.external_addr, &answer, sizeof(args.external_addr))) {
00145 const char *newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
00146 int newport = ntohs(answer.sin_port);
00147
00148 ast_log(LOG_NOTICE, "Old external address/port %s:%d now seen as %s:%d.\n",
00149 ast_inet_ntoa(args.external_addr.sin_addr),
00150 ntohs(args.external_addr.sin_port), newaddr, newport);
00151
00152 args.external_addr = answer;
00153
00154 if (args.external_addr_known) {
00155 struct ast_event *event;
00156
00157
00158
00159
00160
00161 event = ast_event_new(AST_EVENT_NETWORK_CHANGE, AST_EVENT_IE_END);
00162 if (!event) {
00163 ast_log(LOG_ERROR, "Could not create AST_EVENT_NETWORK_CHANGE event.\n");
00164 } else if (ast_event_queue(event)) {
00165 ast_event_destroy(event);
00166 ast_log(LOG_ERROR, "Could not queue AST_EVENT_NETWORK_CHANGE event.\n");
00167 }
00168 } else {
00169
00170
00171 args.external_addr_known = 1;
00172 }
00173 }
00174 }
00175
00176 monitor_request_cleanup:
00177
00178
00179 res = args.refresh * 1000;
00180 ast_mutex_unlock(&args.lock);
00181
00182 return res;
00183 }
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193 static void stun_stop_monitor(void)
00194 {
00195 ast_mutex_lock(&args.lock);
00196 args.monitor_enabled = 0;
00197 ast_free((char *) args.server_hostname);
00198 args.server_hostname = NULL;
00199 stun_close_sock();
00200 ast_mutex_unlock(&args.lock);
00201
00202 if (sched) {
00203 ast_sched_context_destroy(sched);
00204 sched = NULL;
00205 ast_log(LOG_NOTICE, "STUN monitor stopped\n");
00206 }
00207 }
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 static int stun_start_monitor(void)
00218 {
00219
00220 if (sched) {
00221 return 0;
00222 }
00223
00224 if (!(sched = ast_sched_context_create())) {
00225 ast_log(LOG_ERROR, "Failed to create stun monitor scheduler context\n");
00226 return -1;
00227 }
00228
00229 if (ast_sched_start_thread(sched)) {
00230 ast_sched_context_destroy(sched);
00231 sched = NULL;
00232 stun_close_sock();
00233 return -1;
00234 }
00235
00236 if (ast_sched_add_variable(sched, (args.refresh * 1000), stun_monitor_request, NULL, 1) < 0) {
00237 ast_log(LOG_ERROR, "Unable to schedule STUN network monitor \n");
00238 ast_sched_context_destroy(sched);
00239 sched = NULL;
00240 return -1;
00241 }
00242
00243 ast_log(LOG_NOTICE, "STUN monitor started\n");
00244
00245 return 0;
00246 }
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 static int setup_stunaddr(const char *value)
00258 {
00259 char *val;
00260 char *host_str;
00261 char *port_str;
00262 unsigned int port;
00263 struct ast_sockaddr stun_addr;
00264
00265 if (ast_strlen_zero(value)) {
00266
00267 args.monitor_enabled = 0;
00268 return 0;
00269 }
00270
00271 val = ast_strdupa(value);
00272 if (!ast_sockaddr_split_hostport(val, &host_str, &port_str, 0)
00273 || ast_strlen_zero(host_str)) {
00274 return -1;
00275 }
00276
00277
00278 if (ast_strlen_zero(port_str)
00279 || 1 != sscanf(port_str, "%30u", &port)) {
00280 port = STANDARD_STUN_PORT;
00281 }
00282
00283 host_str = ast_strdup(host_str);
00284 if (!host_str) {
00285 return -1;
00286 }
00287
00288
00289 memset(&stun_addr, 0, sizeof(stun_addr));
00290 stun_addr.ss.ss_family = AF_INET;
00291 if (ast_get_ip(&stun_addr, host_str)) {
00292 ast_log(LOG_WARNING, "Unable to lookup STUN server '%s'\n", host_str);
00293 ast_free(host_str);
00294 return -1;
00295 }
00296
00297
00298 ast_free((char *) args.server_hostname);
00299 args.server_hostname = host_str;
00300 args.stun_port = port;
00301
00302
00303 args.monitor_enabled = 1;
00304 return 0;
00305 }
00306
00307 static int load_config(int startup)
00308 {
00309 struct ast_flags config_flags = { 0, };
00310 struct ast_config *cfg;
00311 struct ast_variable *v;
00312
00313 if (!startup) {
00314 ast_set_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
00315 }
00316
00317 cfg = ast_config_load2(stun_conf_file, "res_stun_monitor", config_flags);
00318 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
00319 ast_log(LOG_WARNING, "Unable to load config %s\n", stun_conf_file);
00320 return -1;
00321 }
00322 if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00323 return 0;
00324 }
00325
00326
00327 stun_close_sock();
00328 args.stun_poll_failed_gripe = 0;
00329
00330
00331 args.monitor_enabled = 0;
00332 args.refresh = DEFAULT_MONITOR_REFRESH;
00333
00334 for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
00335 if (!strcasecmp(v->name, "stunaddr")) {
00336 if (setup_stunaddr(v->value)) {
00337 ast_log(LOG_WARNING, "Invalid STUN server address: %s at line %d\n",
00338 v->value, v->lineno);
00339 }
00340 } else if (!strcasecmp(v->name, "stunrefresh")) {
00341 if ((sscanf(v->value, "%30u", &args.refresh) != 1) || !args.refresh) {
00342 ast_log(LOG_WARNING, "Invalid stunrefresh value '%s', must be an integer > 0 at line %d\n", v->value, v->lineno);
00343 args.refresh = DEFAULT_MONITOR_REFRESH;
00344 }
00345 } else {
00346 ast_log(LOG_WARNING, "Invalid config option %s at line %d\n",
00347 v->value, v->lineno);
00348 }
00349 }
00350
00351 ast_config_destroy(cfg);
00352
00353 return 0;
00354 }
00355
00356
00357 static void _stun_show_status(int fd)
00358 {
00359 const char *status;
00360
00361 #define DATALN "%-25s %-5d %-7d %-8d %-7s %-16s %-d\n"
00362 #define HEADER "%-25s %-5s %-7s %-8s %-7s %-16s %-s\n"
00363
00364
00365 ast_cli(fd, HEADER, "Hostname", "Port", "Period", "Retries", "Status", "ExternAddr", "ExternPort");
00366
00367 if (args.stun_poll_failed_gripe) {
00368 status = "FAIL";
00369 } else if (args.external_addr_known) {
00370 status = "OK";
00371 } else {
00372 status = "INIT";
00373 }
00374 ast_cli( fd, DATALN,
00375 args.server_hostname,
00376 args.stun_port,
00377 args.refresh,
00378 DEFAULT_RETRIES,
00379 status,
00380 ast_inet_ntoa(args.external_addr.sin_addr),
00381 ntohs(args.external_addr.sin_port)
00382 );
00383
00384 #undef HEADER
00385 #undef DATALN
00386 }
00387
00388 static char *handle_cli_stun_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00389 {
00390 switch (cmd) {
00391 case CLI_INIT:
00392 e->command = "stun show status";
00393 e->usage =
00394 "Usage: stun show status\n"
00395 " List all known STUN servers and statuses.\n";
00396 return NULL;
00397 case CLI_GENERATE:
00398 return NULL;
00399 }
00400
00401 if (a->argc != 3) {
00402 return CLI_SHOWUSAGE;
00403 }
00404
00405 _stun_show_status(a->fd);
00406 return CLI_SUCCESS;
00407 }
00408
00409 static struct ast_cli_entry cli_stun[] = {
00410 AST_CLI_DEFINE(handle_cli_stun_show_status, "Show STUN servers and statuses"),
00411 };
00412
00413 static int __reload(int startup)
00414 {
00415 int res;
00416
00417 ast_mutex_lock(&args.lock);
00418 if (!(res = load_config(startup)) && args.monitor_enabled) {
00419 res = stun_start_monitor();
00420 }
00421 ast_mutex_unlock(&args.lock);
00422
00423 if (res < 0 || !args.monitor_enabled) {
00424 stun_stop_monitor();
00425 }
00426
00427 return res;
00428 }
00429
00430 static int reload(void)
00431 {
00432 return __reload(0);
00433 }
00434
00435 static int unload_module(void)
00436 {
00437 stun_stop_monitor();
00438 ast_mutex_destroy(&args.lock);
00439
00440
00441 ast_cli_unregister_multiple(cli_stun, ARRAY_LEN(cli_stun));
00442
00443 return 0;
00444 }
00445
00446 static int load_module(void)
00447 {
00448 ast_mutex_init(&args.lock);
00449 args.stun_sock = -1;
00450 if (__reload(1)) {
00451 ast_mutex_destroy(&args.lock);
00452 return AST_MODULE_LOAD_DECLINE;
00453 }
00454
00455
00456 ast_cli_register_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
00457
00458 return AST_MODULE_LOAD_SUCCESS;
00459 }
00460
00461 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "STUN Network Monitor",
00462 .load = load_module,
00463 .unload = unload_module,
00464 .reload = reload,
00465 .load_pri = AST_MODPRI_CHANNEL_DEPEND
00466 );