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: 166272 $")
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 sockaddr_in *result;
00055
00056 struct sockaddr_in last;
00057
00058 char *service;
00059
00060 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(const char *name, struct sockaddr_in *result, const char *service)
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 entry->result = result;
00097 ast_mutex_init(&entry->lock);
00098 strcpy(entry->name, name);
00099 memcpy(&entry->last, result, sizeof(entry->last));
00100 if (service) {
00101 entry->service = ((char *) entry) + sizeof(*entry) + strlen(name);
00102 strcpy(entry->service, service);
00103 }
00104
00105 AST_RWLIST_WRLOCK(&entry_list);
00106 AST_RWLIST_INSERT_HEAD(&entry_list, entry, list);
00107 AST_RWLIST_UNLOCK(&entry_list);
00108
00109 return entry;
00110 }
00111
00112 void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry)
00113 {
00114 if (!entry)
00115 return;
00116
00117 AST_RWLIST_WRLOCK(&entry_list);
00118 AST_RWLIST_REMOVE(&entry_list, entry, list);
00119 AST_RWLIST_UNLOCK(&entry_list);
00120 ast_verb(4, "removing dns manager for '%s'\n", entry->name);
00121
00122 ast_mutex_destroy(&entry->lock);
00123 ast_free(entry);
00124 }
00125
00126 int ast_dnsmgr_lookup(const char *name, struct sockaddr_in *result, struct ast_dnsmgr_entry **dnsmgr, const char *service)
00127 {
00128 if (ast_strlen_zero(name) || !result || !dnsmgr)
00129 return -1;
00130
00131 if (*dnsmgr && !strcasecmp((*dnsmgr)->name, name))
00132 return 0;
00133
00134
00135
00136 if (inet_aton(name, &result->sin_addr))
00137 return 0;
00138
00139 ast_verb(4, "doing dnsmgr_lookup for '%s'\n", name);
00140
00141
00142 ast_get_ip_or_srv(result, name, service);
00143
00144
00145 if (!enabled)
00146 return 0;
00147
00148 ast_verb(3, "adding dns manager for '%s'\n", name);
00149 *dnsmgr = ast_dnsmgr_get(name, result, service);
00150 return !*dnsmgr;
00151 }
00152
00153
00154
00155
00156 static int dnsmgr_refresh(struct ast_dnsmgr_entry *entry, int verbose)
00157 {
00158 char iabuf[INET_ADDRSTRLEN];
00159 char iabuf2[INET_ADDRSTRLEN];
00160 struct sockaddr_in tmp;
00161 int changed = 0;
00162
00163 ast_mutex_lock(&entry->lock);
00164 if (verbose)
00165 ast_verb(3, "refreshing '%s'\n", entry->name);
00166
00167 tmp.sin_port = entry->last.sin_port;
00168
00169 if (!ast_get_ip_or_srv(&tmp, entry->name, entry->service) && inaddrcmp(&tmp, &entry->last)) {
00170 ast_copy_string(iabuf, ast_inet_ntoa(entry->last.sin_addr), sizeof(iabuf));
00171 ast_copy_string(iabuf2, ast_inet_ntoa(tmp.sin_addr), sizeof(iabuf2));
00172 ast_log(LOG_NOTICE, "dnssrv: host '%s' changed from %s:%d to %s:%d\n",
00173 entry->name, iabuf, ntohs(entry->last.sin_port), iabuf2, ntohs(tmp.sin_port));
00174 *entry->result = tmp;
00175 entry->last = tmp;
00176 changed = entry->changed = 1;
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_load2("dnsmgr.conf", "dnsmgr", 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 }