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
00031
00032
00033
00034
00035 #include "asterisk.h"
00036
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 377704 $")
00038
00039 #include "asterisk/_private.h"
00040 #include <regex.h>
00041 #include <signal.h>
00042
00043 #include "asterisk/dnsmgr.h"
00044 #include "asterisk/linkedlists.h"
00045 #include "asterisk/utils.h"
00046 #include "asterisk/config.h"
00047 #include "asterisk/sched.h"
00048 #include "asterisk/cli.h"
00049 #include "asterisk/manager.h"
00050 #include "asterisk/acl.h"
00051
00052 static struct sched_context *sched;
00053 static int refresh_sched = -1;
00054 static pthread_t refresh_thread = AST_PTHREADT_NULL;
00055
00056 struct ast_dnsmgr_entry {
00057
00058 struct ast_sockaddr *result;
00059
00060 char *service;
00061
00062 unsigned int family;
00063
00064 unsigned int changed:1;
00065
00066 void *data;
00067
00068 dns_update_func update_func;
00069 ast_mutex_t lock;
00070 AST_RWLIST_ENTRY(ast_dnsmgr_entry) list;
00071
00072 char name[1];
00073 };
00074
00075 static AST_RWLIST_HEAD_STATIC(entry_list, ast_dnsmgr_entry);
00076
00077 AST_MUTEX_DEFINE_STATIC(refresh_lock);
00078
00079 #define REFRESH_DEFAULT 300
00080
00081 static int enabled;
00082 static int refresh_interval;
00083
00084 struct refresh_info {
00085 struct entry_list *entries;
00086 int verbose;
00087 unsigned int regex_present:1;
00088 regex_t filter;
00089 };
00090
00091 static struct refresh_info master_refresh_info = {
00092 .entries = &entry_list,
00093 .verbose = 0,
00094 };
00095
00096 struct ast_dnsmgr_entry *ast_dnsmgr_get_family(const char *name, struct ast_sockaddr *result, const char *service, unsigned int family)
00097 {
00098 struct ast_dnsmgr_entry *entry;
00099 int total_size = sizeof(*entry) + strlen(name) + (service ? strlen(service) + 1 : 0);
00100
00101 if (!result || ast_strlen_zero(name) || !(entry = ast_calloc(1, total_size))) {
00102 return NULL;
00103 }
00104
00105 entry->result = result;
00106 ast_mutex_init(&entry->lock);
00107 strcpy(entry->name, name);
00108 if (service) {
00109 entry->service = ((char *) entry) + sizeof(*entry) + strlen(name);
00110 strcpy(entry->service, service);
00111 }
00112 entry->family = family;
00113
00114 AST_RWLIST_WRLOCK(&entry_list);
00115 AST_RWLIST_INSERT_HEAD(&entry_list, entry, list);
00116 AST_RWLIST_UNLOCK(&entry_list);
00117
00118 return entry;
00119 }
00120
00121 struct ast_dnsmgr_entry *ast_dnsmgr_get(const char *name, struct ast_sockaddr *result, const char *service)
00122 {
00123 return ast_dnsmgr_get_family(name, result, service, 0);
00124 }
00125
00126 void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry)
00127 {
00128 if (!entry)
00129 return;
00130
00131 AST_RWLIST_WRLOCK(&entry_list);
00132 AST_RWLIST_REMOVE(&entry_list, entry, list);
00133 AST_RWLIST_UNLOCK(&entry_list);
00134 ast_verb(6, "removing dns manager for '%s'\n", entry->name);
00135
00136 ast_mutex_destroy(&entry->lock);
00137 ast_free(entry);
00138 }
00139
00140 static int internal_dnsmgr_lookup(const char *name, struct ast_sockaddr *result, struct ast_dnsmgr_entry **dnsmgr, const char *service, dns_update_func func, void *data)
00141 {
00142 unsigned int family;
00143
00144 if (ast_strlen_zero(name) || !result || !dnsmgr) {
00145 return -1;
00146 }
00147
00148 if (*dnsmgr && !strcasecmp((*dnsmgr)->name, name)) {
00149 return 0;
00150 }
00151
00152
00153 family = result->ss.ss_family;
00154
00155
00156
00157
00158
00159 if (ast_sockaddr_parse(result, name, PARSE_PORT_FORBID)) {
00160 return 0;
00161 }
00162
00163 ast_verb(6, "doing dnsmgr_lookup for '%s'\n", name);
00164
00165
00166 ast_get_ip_or_srv(result, name, service);
00167
00168
00169 if (!enabled) {
00170 return 0;
00171 }
00172
00173 ast_verb(6, "adding dns manager for '%s'\n", name);
00174 *dnsmgr = ast_dnsmgr_get_family(name, result, service, family);
00175 (*dnsmgr)->update_func = func;
00176 (*dnsmgr)->data = data;
00177 return !*dnsmgr;
00178 }
00179
00180 int ast_dnsmgr_lookup(const char *name, struct ast_sockaddr *result, struct ast_dnsmgr_entry **dnsmgr, const char *service)
00181 {
00182 return internal_dnsmgr_lookup(name, result, dnsmgr, service, NULL, NULL);
00183 }
00184
00185 int ast_dnsmgr_lookup_cb(const char *name, struct ast_sockaddr *result, struct ast_dnsmgr_entry **dnsmgr, const char *service, dns_update_func func, void *data)
00186 {
00187 return internal_dnsmgr_lookup(name, result, dnsmgr, service, func, data);
00188 }
00189
00190
00191
00192
00193 static int dnsmgr_refresh(struct ast_dnsmgr_entry *entry, int verbose)
00194 {
00195 struct ast_sockaddr tmp = { .len = 0, };
00196 int changed = 0;
00197
00198 ast_mutex_lock(&entry->lock);
00199
00200 if (verbose) {
00201 ast_verb(6, "refreshing '%s'\n", entry->name);
00202 }
00203
00204 tmp.ss.ss_family = entry->family;
00205 if (!ast_get_ip_or_srv(&tmp, entry->name, entry->service)) {
00206 if (!ast_sockaddr_port(&tmp)) {
00207 ast_sockaddr_set_port(&tmp, ast_sockaddr_port(entry->result));
00208 }
00209 if (ast_sockaddr_cmp(&tmp, entry->result)) {
00210 const char *old_addr = ast_strdupa(ast_sockaddr_stringify(entry->result));
00211 const char *new_addr = ast_strdupa(ast_sockaddr_stringify(&tmp));
00212
00213 if (entry->update_func) {
00214 entry->update_func(entry->result, &tmp, entry->data);
00215 } else {
00216 ast_log(LOG_NOTICE, "dnssrv: host '%s' changed from %s to %s\n",
00217 entry->name, old_addr, new_addr);
00218
00219 ast_sockaddr_copy(entry->result, &tmp);
00220 changed = entry->changed = 1;
00221 }
00222 }
00223 }
00224
00225 ast_mutex_unlock(&entry->lock);
00226
00227 return changed;
00228 }
00229
00230 int ast_dnsmgr_refresh(struct ast_dnsmgr_entry *entry)
00231 {
00232 return dnsmgr_refresh(entry, 0);
00233 }
00234
00235
00236
00237
00238 int ast_dnsmgr_changed(struct ast_dnsmgr_entry *entry)
00239 {
00240 int changed;
00241
00242 ast_mutex_lock(&entry->lock);
00243
00244 changed = entry->changed;
00245 entry->changed = 0;
00246
00247 ast_mutex_unlock(&entry->lock);
00248
00249 return changed;
00250 }
00251
00252 static void *do_refresh(void *data)
00253 {
00254 for (;;) {
00255 pthread_testcancel();
00256 usleep((ast_sched_wait(sched)*1000));
00257 pthread_testcancel();
00258 ast_sched_runq(sched);
00259 }
00260 return NULL;
00261 }
00262
00263 static int refresh_list(const void *data)
00264 {
00265 struct refresh_info *info = (struct refresh_info *)data;
00266 struct ast_dnsmgr_entry *entry;
00267
00268
00269 if (ast_mutex_trylock(&refresh_lock)) {
00270 if (info->verbose)
00271 ast_log(LOG_WARNING, "DNS Manager refresh already in progress.\n");
00272 return -1;
00273 }
00274
00275 ast_verb(6, "Refreshing DNS lookups.\n");
00276 AST_RWLIST_RDLOCK(info->entries);
00277 AST_RWLIST_TRAVERSE(info->entries, entry, list) {
00278 if (info->regex_present && regexec(&info->filter, entry->name, 0, NULL, 0))
00279 continue;
00280
00281 dnsmgr_refresh(entry, info->verbose);
00282 }
00283 AST_RWLIST_UNLOCK(info->entries);
00284
00285 ast_mutex_unlock(&refresh_lock);
00286
00287
00288 return refresh_interval * 1000;
00289 }
00290
00291 void dnsmgr_start_refresh(void)
00292 {
00293 if (refresh_sched > -1) {
00294 AST_SCHED_DEL(sched, refresh_sched);
00295 refresh_sched = ast_sched_add_variable(sched, 100, refresh_list, &master_refresh_info, 1);
00296 }
00297 }
00298
00299 static int do_reload(int loading);
00300
00301 static char *handle_cli_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00302 {
00303 switch (cmd) {
00304 case CLI_INIT:
00305 e->command = "dnsmgr reload";
00306 e->usage =
00307 "Usage: dnsmgr reload\n"
00308 " Reloads the DNS manager configuration.\n";
00309 return NULL;
00310 case CLI_GENERATE:
00311 return NULL;
00312 }
00313 if (a->argc > 2)
00314 return CLI_SHOWUSAGE;
00315
00316 do_reload(0);
00317 return CLI_SUCCESS;
00318 }
00319
00320 static char *handle_cli_refresh(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00321 {
00322 struct refresh_info info = {
00323 .entries = &entry_list,
00324 .verbose = 1,
00325 };
00326 switch (cmd) {
00327 case CLI_INIT:
00328 e->command = "dnsmgr refresh";
00329 e->usage =
00330 "Usage: dnsmgr refresh [pattern]\n"
00331 " Peforms an immediate refresh of the managed DNS entries.\n"
00332 " Optional regular expression pattern is used to filter the entries to refresh.\n";
00333 return NULL;
00334 case CLI_GENERATE:
00335 return NULL;
00336 }
00337
00338 if (!enabled) {
00339 ast_cli(a->fd, "DNS Manager is disabled.\n");
00340 return 0;
00341 }
00342
00343 if (a->argc > 3) {
00344 return CLI_SHOWUSAGE;
00345 }
00346
00347 if (a->argc == 3) {
00348 if (regcomp(&info.filter, a->argv[2], REG_EXTENDED | REG_NOSUB)) {
00349 return CLI_SHOWUSAGE;
00350 } else {
00351 info.regex_present = 1;
00352 }
00353 }
00354
00355 refresh_list(&info);
00356
00357 if (info.regex_present) {
00358 regfree(&info.filter);
00359 }
00360
00361 return CLI_SUCCESS;
00362 }
00363
00364 static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00365 {
00366 int count = 0;
00367 struct ast_dnsmgr_entry *entry;
00368 switch (cmd) {
00369 case CLI_INIT:
00370 e->command = "dnsmgr status";
00371 e->usage =
00372 "Usage: dnsmgr status\n"
00373 " Displays the DNS manager status.\n";
00374 return NULL;
00375 case CLI_GENERATE:
00376 return NULL;
00377 }
00378
00379 if (a->argc > 2)
00380 return CLI_SHOWUSAGE;
00381
00382 ast_cli(a->fd, "DNS Manager: %s\n", enabled ? "enabled" : "disabled");
00383 ast_cli(a->fd, "Refresh Interval: %d seconds\n", refresh_interval);
00384 AST_RWLIST_RDLOCK(&entry_list);
00385 AST_RWLIST_TRAVERSE(&entry_list, entry, list)
00386 count++;
00387 AST_RWLIST_UNLOCK(&entry_list);
00388 ast_cli(a->fd, "Number of entries: %d\n", count);
00389
00390 return CLI_SUCCESS;
00391 }
00392
00393 static struct ast_cli_entry cli_reload = AST_CLI_DEFINE(handle_cli_reload, "Reloads the DNS manager configuration");
00394 static struct ast_cli_entry cli_refresh = AST_CLI_DEFINE(handle_cli_refresh, "Performs an immediate refresh");
00395 static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the DNS manager status");
00396
00397 static void dnsmgr_shutdown(void)
00398 {
00399 ast_cli_unregister(&cli_reload);
00400 ast_cli_unregister(&cli_status);
00401 ast_cli_unregister(&cli_refresh);
00402
00403
00404 ast_mutex_lock(&refresh_lock);
00405 if (refresh_thread != AST_PTHREADT_NULL) {
00406
00407 pthread_cancel(refresh_thread);
00408 pthread_kill(refresh_thread, SIGURG);
00409 pthread_join(refresh_thread, NULL);
00410 refresh_thread = AST_PTHREADT_NULL;
00411 }
00412 ast_mutex_unlock(&refresh_lock);
00413
00414 sched_context_destroy(sched);
00415 }
00416
00417 int dnsmgr_init(void)
00418 {
00419 if (!(sched = sched_context_create())) {
00420 ast_log(LOG_ERROR, "Unable to create schedule context.\n");
00421 return -1;
00422 }
00423 ast_cli_register(&cli_reload);
00424 ast_cli_register(&cli_status);
00425 ast_cli_register(&cli_refresh);
00426
00427 ast_register_atexit(dnsmgr_shutdown);
00428
00429 return do_reload(1);
00430 }
00431
00432 int dnsmgr_reload(void)
00433 {
00434 return do_reload(0);
00435 }
00436
00437 static int do_reload(int loading)
00438 {
00439 struct ast_config *config;
00440 struct ast_flags config_flags = { loading ? 0 : CONFIG_FLAG_FILEUNCHANGED };
00441 const char *interval_value;
00442 const char *enabled_value;
00443 int interval;
00444 int was_enabled;
00445 int res = -1;
00446
00447 config = ast_config_load2("dnsmgr.conf", "dnsmgr", config_flags);
00448 if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEUNCHANGED || config == CONFIG_STATUS_FILEINVALID) {
00449 return 0;
00450 }
00451
00452
00453 ast_mutex_lock(&refresh_lock);
00454
00455
00456 refresh_interval = REFRESH_DEFAULT;
00457 was_enabled = enabled;
00458 enabled = 0;
00459
00460 AST_SCHED_DEL(sched, refresh_sched);
00461
00462 if (config) {
00463 if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
00464 enabled = ast_true(enabled_value);
00465 }
00466 if ((interval_value = ast_variable_retrieve(config, "general", "refreshinterval"))) {
00467 if (sscanf(interval_value, "%30d", &interval) < 1)
00468 ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", interval_value);
00469 else if (interval < 0)
00470 ast_log(LOG_WARNING, "Invalid refresh interval '%d' specified, using default\n", interval);
00471 else
00472 refresh_interval = interval;
00473 }
00474 ast_config_destroy(config);
00475 }
00476
00477 if (enabled && refresh_interval)
00478 ast_log(LOG_NOTICE, "Managed DNS entries will be refreshed every %d seconds.\n", refresh_interval);
00479
00480
00481
00482 if (enabled) {
00483 if (!was_enabled && (refresh_thread == AST_PTHREADT_NULL)) {
00484 if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) {
00485 ast_log(LOG_ERROR, "Unable to start refresh thread.\n");
00486 }
00487 }
00488
00489 refresh_sched = ast_sched_add_variable(sched, 100, refresh_list, &master_refresh_info, 1);
00490 res = 0;
00491 }
00492
00493
00494 else if (!enabled && was_enabled && (refresh_thread != AST_PTHREADT_NULL)) {
00495
00496 pthread_cancel(refresh_thread);
00497 pthread_kill(refresh_thread, SIGURG);
00498 pthread_join(refresh_thread, NULL);
00499 refresh_thread = AST_PTHREADT_NULL;
00500 res = 0;
00501 }
00502 else
00503 res = 0;
00504
00505 ast_mutex_unlock(&refresh_lock);
00506 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: DNSmgr\r\nStatus: %s\r/nMessage: DNSmgr reload Requested\r\n", enabled ? "Enabled" : "Disabled");
00507
00508 return res;
00509 }