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