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