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