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