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: 369001 $")
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 int dnsmgr_init(void)
00398 {
00399 if (!(sched = sched_context_create())) {
00400 ast_log(LOG_ERROR, "Unable to create schedule context.\n");
00401 return -1;
00402 }
00403 ast_cli_register(&cli_reload);
00404 ast_cli_register(&cli_status);
00405 ast_cli_register(&cli_refresh);
00406 return do_reload(1);
00407 }
00408
00409 int dnsmgr_reload(void)
00410 {
00411 return do_reload(0);
00412 }
00413
00414 static int do_reload(int loading)
00415 {
00416 struct ast_config *config;
00417 struct ast_flags config_flags = { loading ? 0 : CONFIG_FLAG_FILEUNCHANGED };
00418 const char *interval_value;
00419 const char *enabled_value;
00420 int interval;
00421 int was_enabled;
00422 int res = -1;
00423
00424 config = ast_config_load2("dnsmgr.conf", "dnsmgr", config_flags);
00425 if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEUNCHANGED || config == CONFIG_STATUS_FILEINVALID) {
00426 return 0;
00427 }
00428
00429
00430 ast_mutex_lock(&refresh_lock);
00431
00432
00433 refresh_interval = REFRESH_DEFAULT;
00434 was_enabled = enabled;
00435 enabled = 0;
00436
00437 AST_SCHED_DEL(sched, refresh_sched);
00438
00439 if (config) {
00440 if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
00441 enabled = ast_true(enabled_value);
00442 }
00443 if ((interval_value = ast_variable_retrieve(config, "general", "refreshinterval"))) {
00444 if (sscanf(interval_value, "%30d", &interval) < 1)
00445 ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", interval_value);
00446 else if (interval < 0)
00447 ast_log(LOG_WARNING, "Invalid refresh interval '%d' specified, using default\n", interval);
00448 else
00449 refresh_interval = interval;
00450 }
00451 ast_config_destroy(config);
00452 }
00453
00454 if (enabled && refresh_interval)
00455 ast_log(LOG_NOTICE, "Managed DNS entries will be refreshed every %d seconds.\n", refresh_interval);
00456
00457
00458
00459 if (enabled) {
00460 if (!was_enabled && (refresh_thread == AST_PTHREADT_NULL)) {
00461 if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) {
00462 ast_log(LOG_ERROR, "Unable to start refresh thread.\n");
00463 }
00464 }
00465
00466 refresh_sched = ast_sched_add_variable(sched, 100, refresh_list, &master_refresh_info, 1);
00467 res = 0;
00468 }
00469
00470
00471 else if (!enabled && was_enabled && (refresh_thread != AST_PTHREADT_NULL)) {
00472
00473 pthread_cancel(refresh_thread);
00474 pthread_kill(refresh_thread, SIGURG);
00475 pthread_join(refresh_thread, NULL);
00476 refresh_thread = AST_PTHREADT_NULL;
00477 res = 0;
00478 }
00479 else
00480 res = 0;
00481
00482 ast_mutex_unlock(&refresh_lock);
00483 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: DNSmgr\r\nStatus: %s\r/nMessage: DNSmgr reload Requested\r\n", enabled ? "Enabled" : "Disabled");
00484
00485 return res;
00486 }