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