diff options
Diffstat (limited to 'contrib/bind/bin/named/ns_config.c')
-rw-r--r-- | contrib/bind/bin/named/ns_config.c | 3194 |
1 files changed, 0 insertions, 3194 deletions
diff --git a/contrib/bind/bin/named/ns_config.c b/contrib/bind/bin/named/ns_config.c deleted file mode 100644 index 84973ce..0000000 --- a/contrib/bind/bin/named/ns_config.c +++ /dev/null @@ -1,3194 +0,0 @@ -#if !defined(lint) && !defined(SABER) -static const char rcsid[] = "$Id: ns_config.c,v 8.136.8.1 2003/06/02 09:56:34 marka Exp $"; -#endif /* not lint */ - -/* - * Copyright (c) 1996-2000 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -/* - * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, and that - * the name of Check Point Software Technologies Incorporated not be used - * in advertising or publicity pertaining to distribution of the document - * or software without specific, written prior permission. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND CHECK POINT SOFTWARE TECHNOLOGIES - * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. - * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED - * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR - * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "port_before.h" - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/un.h> - -#include <netinet/in.h> -#include <arpa/nameser.h> -#include <arpa/inet.h> - -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <resolv.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <time.h> -#include <unistd.h> -#include <fcntl.h> - -#include <isc/eventlib.h> -#include <isc/logging.h> -#include <isc/memcluster.h> - -#include <isc/dst.h> - -#include "port_after.h" - -#ifdef HAVE_GETRUSAGE /* XXX */ -#include <sys/resource.h> -#endif - -#include "named.h" -#include "ns_parseutil.h" - -/* Private. */ - -static int tmpnum = 0; -static int config_initialized = 0; - -static int need_logging_free = 0; -static int default_logging_installed; - -static int options_installed = 0; -static int logging_installed = 0; -static int default_options_installed; - -static char **logging_categories; -static char *current_pid_filename = NULL; - -#define ZONE_SYM_TABLE_SIZE 4973 -static symbol_table zone_symbol_table; - -/* Zones */ - -void -free_zone_timerinfo(struct zoneinfo *zp) { - if (zp->z_timerinfo != NULL) { - zp->z_timerinfo->name = freestr(zp->z_timerinfo->name); - memput(zp->z_timerinfo, sizeof *zp->z_timerinfo); - zp->z_timerinfo = NULL; - } else - ns_error(ns_log_config, "timer for zone '%s' had no timerinfo", - zp->z_origin); -} - -void -free_zone_contents(struct zoneinfo *zp, int undefine_sym) { - INSIST(zp != NULL); - - if (undefine_sym) - undefine_symbol(zone_symbol_table, zp->z_origin, zp->z_class); - if (zp->z_flags & Z_TIMER_SET) { - free_zone_timerinfo(zp); - if (evClearTimer(ev, zp->z_timer) < 0) - ns_error(ns_log_config, - "evClearTimer for zone '%s' failed in ns_init: %s", - zp->z_origin, - strerror(errno)); - } - if (zp->z_origin != NULL) - zp->z_origin = freestr(zp->z_origin); - if (zp->z_source != NULL) - zp->z_source = freestr(zp->z_source); - if (zp->z_ixfr_base != NULL) - zp->z_ixfr_base = freestr(zp->z_ixfr_base); - if (zp->z_ixfr_tmp != NULL) - zp->z_ixfr_tmp = freestr(zp->z_ixfr_tmp); - if (zp->z_update_acl != NULL) - free_ip_match_list(zp->z_update_acl); - zp->z_update_acl = NULL; - if (zp->z_query_acl != NULL) - free_ip_match_list(zp->z_query_acl); - zp->z_query_acl = NULL; - if (zp->z_transfer_acl != NULL) - free_ip_match_list(zp->z_transfer_acl); - zp->z_transfer_acl = NULL; -#ifdef BIND_UPDATE - if (zp->z_updatelog != NULL) - zp->z_updatelog = freestr(zp->z_updatelog); -#endif /* BIND_UPDATE */ -#ifdef BIND_NOTIFY - if (zp->z_also_notify != NULL) - memput(zp->z_also_notify, - zp->z_notify_count * sizeof *zp->z_also_notify); - zp->z_also_notify = NULL; -#endif - if (zp->z_fwdtab != NULL) - free_forwarders(zp->z_fwdtab); - zp->z_fwdtab = NULL; - block_signals(); - if (LINKED(zp, z_reloadlink)) - UNLINK(reloadingzones, zp, z_reloadlink); - unblock_signals(); -} - -static void -release_zone(struct zoneinfo *zp) { - INSIST(zp != NULL); - - free_zone_contents(zp, 0); - memput(zp, sizeof *zp); -} - -struct zoneinfo * -find_zone(const char *name, int class) { - struct zoneinfo *zp; - symbol_value value; - - ns_debug(ns_log_config, 3, "find_zone(%s, %d)", - *name ? name : ".", class); - if (lookup_symbol(zone_symbol_table, name, class, &value)) { - INSIST(value.integer >= 0 && value.integer < nzones); - ns_debug(ns_log_config, 3, "find_zone: existing zone %d", - value.integer); - zp = &zones[value.integer]; - return (zp); - } - ns_debug(ns_log_config, 3, "find_zone: unknown zone"); - return (NULL); -} - -static struct zoneinfo * -new_zone(void) { - struct zoneinfo *zp; - - if (EMPTY(freezones)) - make_new_zones(); - - zp = HEAD(freezones); - UNLINK(freezones, zp, z_freelink); - return (zp); -} - -/* - * Check out a zoneinfo structure and return non-zero if it's OK. - */ -static int -validate_zone(struct zoneinfo *zp) { - char filename[MAXPATHLEN+1]; - - /* Check name */ - if (!res_dnok(zp->z_origin)) { - ns_error(ns_log_config, "invalid zone name '%s'", - zp->z_origin); - return (0); - } - - /* Check class */ - if (zp->z_class == C_ANY || zp->z_class == C_NONE) { - ns_error(ns_log_config, "invalid class %d for zone '%s'", - zp->z_class, zp->z_origin); - return (0); - } - - /* Check type. */ - if (zp->z_type == 0) { - ns_error(ns_log_config, "no type specified for zone '%s'", - zp->z_origin); - return (0); - } - if (zp->z_type == z_cache && ns_samename(zp->z_origin, "") != 1) { - ns_error(ns_log_config, - "only the root zone may be a cache zone (zone '%s')", - zp->z_origin); - return (0); - } - if (zp->z_type == z_hint && ns_samename(zp->z_origin, "") != 1) { - ns_error(ns_log_config, - "only the root zone may be a hint zone (zone '%s')", - zp->z_origin); - return (0); - } - - /* Check filename. */ - if (zp->z_type == z_master && zp->z_source == NULL) { - ns_error(ns_log_config, - "'file' statement missing for master zone %s", - zp->z_origin); - return (0); - } - /* - * XXX We should run filename through an OS-specific - * validator here. - */ - if (zp->z_source != NULL && - strlen(zp->z_source) > MAXPATHLEN) { - ns_error(ns_log_config, "filename too long for zone '%s'", - zp->z_origin); - return (0); - } - - if (zp->z_ixfr_base != NULL && strlen(zp->z_ixfr_base) > MAXPATHLEN) { - ns_error(ns_log_config, "ixfr filename too long for zone '%s'", - zp->z_origin); - return (0); - } - if (zp->z_ixfr_tmp != NULL && strlen(zp->z_ixfr_tmp) > MAXPATHLEN) { - ns_error(ns_log_config, "tmp ixfr filename too long for zone '%s'", - zp->z_origin); - return (0); - } - - /* Check masters */ - if (zp->z_addrcnt != 0) { - if (zp->z_type == z_master || zp->z_type == z_hint || - zp->z_type == z_cache) { - ns_error(ns_log_config, - "'masters' statement present for %s zone '%s'", - (zp->z_type == z_master) ? "master" : - (zp->z_type == z_hint) ? "hint" : "cache", - zp->z_origin); - return (0); - } - } else { - if (zp->z_type == z_slave || zp->z_type == z_stub) { - ns_error(ns_log_config, - "no 'masters' statement for non-master zone '%s'", - zp->z_origin); - return (0); - } - } - - /* Check allow-update and allow-transfer. */ - if (zp->z_update_acl || zp->z_transfer_acl) { - if (zp->z_type != z_master && zp->z_type != z_slave) { - ns_error(ns_log_config, - "'allow-{update,transfer}' option for non-{master,slave} zone '%s'", - zp->z_origin); - return (0); - } - } - - /* Check allow-query. */ - if (zp->z_query_acl) { - if (zp->z_type != z_master && - zp->z_type != z_slave && -#ifdef FORWARD_ALLOWS - zp->z_type != z_forward && -#endif - zp->z_type != z_stub) { - ns_error(ns_log_config, -#ifdef FORWARD_ALLOWS - "'allow-query' option for hint zone '%s'", -#else - "'allow-query' option for non-{master,slave,stub} zone '%s'", -#endif - zp->z_origin); - return (0); - } - } - -#ifdef BIND_NOTIFY - /* Check notify */ - if (zp->z_notify != notify_use_default) { - if (zp->z_type != z_master && zp->z_type != z_slave) { - ns_error(ns_log_config, - "'notify' given for non-master, non-slave zone '%s'", - zp->z_origin); - return (0); - } - } - - /* Check also-notify */ - if (zp->z_notify_count != 0) { - if (zp->z_type != z_master && zp->z_type != z_slave) { - ns_error(ns_log_config, - "'also-notify' given for non-master, non-slave zone '%s'", - zp->z_origin); - return (0); - } - } -#endif - -#ifdef BIND_UPDATE - /* XXX need more checking here */ - if (!zp->z_updatelog && zp->z_source) { - /* XXX OS-specific filename validation here */ - if ((strlen(zp->z_source) + (sizeof ".log" - 1)) > - MAXPATHLEN) { - ns_error(ns_log_config, - "filename too long for dynamic zone '%s'", - zp->z_origin); - return (0); - } - /* this sprintf() is now safe */ - sprintf(filename, "%s.log", zp->z_source); - zp->z_updatelog = savestr(filename, 1); - } - - /* Check forward */ - if (zp->z_optset & OPTION_FORWARD_ONLY) { - if (zp->z_type == z_hint) { - ns_error(ns_log_config, - "'forward' given for hint zone '%s'", - zp->z_origin); - return (0); - } - } - /* Check forwarders */ - if (zp->z_fwdtab) { - if (zp->z_type == z_hint) { - ns_error(ns_log_config, - "'forwarders' given for hint zone '%s'", - zp->z_origin); - return (0); - } - } - - if (zp->z_type == z_master) { - if (!zp->z_soaincrintvl) - zp->z_soaincrintvl = SOAINCRINTVL; - if (!zp->z_dumpintvl) - zp->z_dumpintvl = DUMPINTVL; - if (!zp->z_deferupdcnt) - zp->z_deferupdcnt = DEFERUPDCNT; - } -#endif /* BIND_UPDATE */ - - if (!zp->z_ixfr_base && zp->z_source) { - /* XXX OS-specific filename validation here */ - if ((strlen(zp->z_source) + (sizeof ".ixfr" - 1)) > - MAXPATHLEN) { - ns_error(ns_log_config, - "filename too long for dynamic zone '%s'", - zp->z_origin); - return (0); - } - /* this sprintf() is now safe */ - sprintf(filename, "%s.ixfr", zp->z_source); - zp->z_ixfr_base = savestr(filename, 1); - } - if (!zp->z_ixfr_tmp && zp->z_source) { - /* XXX OS-specific filename validation here */ - if ((strlen(zp->z_source) + (sizeof ".ixfr.tmp" - 1)) > - MAXPATHLEN) { - ns_error(ns_log_config, - "filename too long for dynamic zone '%s'", - zp->z_origin); - return (0); - } - /* this sprintf() is now safe */ - sprintf(filename, "%s.ixfr.tmp", zp->z_source); - zp->z_ixfr_tmp = savestr(filename, 1); - } - - return (1); -} - -/* - * Start building a new zoneinfo structure. Returns an opaque - * zone_config suitable for use by the parser. - */ -zone_config -begin_zone(char *name, int class) { - zone_config zh; - struct zoneinfo *zp; - - /* - * require: name is canonical, class is a valid class - */ - - ns_debug(ns_log_config, 3, "begin_zone('%s', %d)", - (*name == '\0') ? "." : name, class); - - zp = (struct zoneinfo *)memget(sizeof (struct zoneinfo)); - if (zp == NULL) - panic("memget failed in begin_zone", NULL); - memset(zp, 0, sizeof (struct zoneinfo)); - zp->z_origin = name; - zp->z_class = class; - zp->z_checknames = not_set; - if (server_options->flags & OPTION_MAINTAIN_IXFR_BASE) - zp->z_maintain_ixfr_base = 1; - else - zp->z_maintain_ixfr_base = 0; - zp->z_max_log_size_ixfr = server_options->max_log_size_ixfr; - zh.opaque = zp; - return (zh); -} - -/* - * Merge new configuration information into an existing zone. The - * new zoneinfo must be valid. - */ -static void -update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { - char buf[MAXPATHLEN+1]; - int i; - - INSIST(zp != NULL); - INSIST(new_zp != NULL); - - ns_debug(ns_log_config, 1, "update_zone_info('%s', %d)", - (*new_zp->z_origin == '\0') ? "." : new_zp->z_origin, - new_zp->z_type); - -#ifdef BIND_UPDATE - /* - * A dynamic master zone that's becoming non-dynamic may need to be - * dumped before we start the update. - */ - if ((zp->z_flags & Z_DYNAMIC) && !(new_zp->z_flags & Z_DYNAMIC) && - ((zp->z_flags & Z_NEED_SOAUPDATE) || - (zp->z_flags & Z_NEED_DUMP))) - (void) zonedump(zp, ISNOTIXFR); -#endif - - /* - * First do the simple stuff, making sure to free - * any data that was dynamically allocated. - */ - if (zp->z_origin != NULL) - (void)freestr(zp->z_origin); - zp->z_origin = new_zp->z_origin; - new_zp->z_origin = NULL; - zp->z_maintain_ixfr_base = new_zp->z_maintain_ixfr_base; - zp->z_max_log_size_ixfr = new_zp->z_max_log_size_ixfr; - zp->z_class = new_zp->z_class; - zp->z_type = new_zp->z_type; - zp->z_checknames = new_zp->z_checknames; - for (i = 0; i < new_zp->z_addrcnt; i++) { - zp->z_addr[i] = new_zp->z_addr[i]; - zp->z_keys[i] = new_zp->z_keys[i]; - } - zp->z_addrcnt = new_zp->z_addrcnt; - if (zp->z_update_acl) - free_ip_match_list(zp->z_update_acl); - zp->z_update_acl = new_zp->z_update_acl; - new_zp->z_update_acl = NULL; - if (zp->z_query_acl) - free_ip_match_list(zp->z_query_acl); - zp->z_query_acl = new_zp->z_query_acl; - new_zp->z_query_acl = NULL; - zp->z_axfr_src = new_zp->z_axfr_src; - if (zp->z_transfer_acl) - free_ip_match_list(zp->z_transfer_acl); - zp->z_transfer_acl = new_zp->z_transfer_acl; - new_zp->z_transfer_acl = NULL; - zp->z_max_transfer_time_in = new_zp->z_max_transfer_time_in; -#ifdef BIND_NOTIFY - zp->z_notify = new_zp->z_notify; - if (zp->z_also_notify) - memput(zp->z_also_notify, - zp->z_notify_count * sizeof *zp->z_also_notify); - zp->z_also_notify = new_zp->z_also_notify; - zp->z_notify_count = new_zp->z_notify_count; - new_zp->z_also_notify = NULL; - new_zp->z_notify_count = 0; -#endif - if ((new_zp->z_flags & Z_FORWARD_SET) != 0) - zp->z_flags |= Z_FORWARD_SET; - else - zp->z_flags &= ~Z_FORWARD_SET; - if (zp->z_fwdtab != NULL) - free_forwarders(zp->z_fwdtab); - zp->z_fwdtab = new_zp->z_fwdtab; - new_zp->z_fwdtab = NULL; - - zp->z_dialup = new_zp->z_dialup; - zp->z_options = new_zp->z_options; - zp->z_optset = new_zp->z_optset; - -#ifdef BIND_UPDATE - if (new_zp->z_flags & Z_DYNAMIC) - zp->z_flags |= Z_DYNAMIC; - else - zp->z_flags &= ~Z_DYNAMIC; - zp->z_soaincrintvl = new_zp->z_soaincrintvl; - zp->z_dumpintvl = new_zp->z_dumpintvl; - zp->z_deferupdcnt = new_zp->z_deferupdcnt; - if (zp->z_updatelog) - (void)freestr(zp->z_updatelog); - zp->z_updatelog = new_zp->z_updatelog; - new_zp->z_updatelog = NULL; -#endif /* BIND_UPDATE */ - zp->z_port = new_zp->z_port; - - /* - * Now deal with files. - */ - switch (zp->z_type) { - case z_cache: - ns_panic(ns_log_config, 1, "impossible condition"); - break; - case z_hint: - ns_debug(ns_log_config, 1, "source = %s", new_zp->z_source); - zp->z_refresh = 0; /* No dumping. */ - if (zp->z_source != NULL && - strcmp(new_zp->z_source, zp->z_source) == 0 && - (reconfiging || !zonefile_changed_p(zp))) { - ns_debug(ns_log_config, 1, "cache is up to date"); - break; - } - - /* File has changed, or hasn't been loaded yet. */ - if (zp->z_source) { - zp->z_source = freestr(zp->z_source); - ns_stopxfrs(zp); - purge_zone(zp, fcachetab); - } - zp->z_source = new_zp->z_source; - new_zp->z_source = NULL; - - if (zp->z_ixfr_base) - (void)freestr(zp->z_ixfr_base); - zp->z_ixfr_base = new_zp->z_ixfr_base; - new_zp->z_ixfr_base = NULL; - - if (zp->z_ixfr_tmp) - (void)freestr(zp->z_ixfr_tmp); - zp->z_ixfr_tmp = new_zp->z_ixfr_tmp; - new_zp->z_ixfr_tmp = NULL; - - ns_debug(ns_log_config, 1, "reloading hint zone"); - (void) db_load(zp->z_source, zp->z_origin, zp, NULL, - ISNOTIXFR); - break; - - case z_master: - ns_debug(ns_log_config, 1, "source = %s", new_zp->z_source); - /* - * If we've loaded this file, and the file hasn't changed - * then there's no need to reload. - */ - if (zp->z_source != NULL && - strcmp(new_zp->z_source, zp->z_source) == 0 && - (reconfiging || !zonefile_changed_p(zp))) { - ns_debug(ns_log_config, 1, "zone is up to date"); - break; - } -#ifdef BIND_UPDATE - if (zp->z_source && (zp->z_flags & Z_DYNAMIC)) - ns_warning(ns_log_config, - "source file of dynamic zone '%s' has changed", - zp->z_origin); - - primary_reload: -#endif /* BIND_UPDATE */ - if (zp->z_source != NULL) - (void)freestr(zp->z_source); - zp->z_source = new_zp->z_source; - new_zp->z_source = NULL; - - if (zp->z_ixfr_base != NULL) - (void)freestr(zp->z_ixfr_base); - zp->z_ixfr_base = new_zp->z_ixfr_base; - new_zp->z_ixfr_base = NULL; - - if (zp->z_ixfr_tmp != NULL) - (void)freestr(zp->z_ixfr_tmp); - zp->z_ixfr_tmp = new_zp->z_ixfr_tmp; - new_zp->z_ixfr_tmp = NULL; - - if (reload_master(zp) == 1) { - /* - * Note that going to primary_reload - * unconditionally reloads the zone. - */ - new_zp->z_source = savestr(zp->z_source, 1); - new_zp->z_ixfr_base = savestr(zp->z_ixfr_base, 1); - new_zp->z_ixfr_tmp = savestr(zp->z_ixfr_tmp, 1); - goto primary_reload; - } - break; - - case z_slave: -#ifdef STUBS - case z_stub: -#endif - ns_debug(ns_log_config, 1, "addrcnt = %d", zp->z_addrcnt); - if (!new_zp->z_source) { - /* - * We will always transfer this zone again - * after a reload. - */ - sprintf(buf, "NsTmp%ld.%d", (long)getpid(), tmpnum++); - new_zp->z_source = savestr(buf, 1); - zp->z_flags |= Z_TMP_FILE; - } else - zp->z_flags &= ~Z_TMP_FILE; - /* - * If we had a backup file name, and it was changed, - * free old zone and start over. If we don't have - * current zone contents, try again now in case - * we have a new server on the list. - */ - if (zp->z_source != NULL && - (strcmp(new_zp->z_source, zp->z_source) != 0 || - ((!reconfiging) && zonefile_changed_p(zp)))) { - ns_debug(ns_log_config, 1, - "backup file changed or missing"); - zp->z_source = freestr(zp->z_source); - zp->z_serial = 0; /* force xfer */ - ns_stopxfrs(zp); - /* - * We only need to reload if we have ever - * successfully transferred the zone. - */ - if ((zp->z_flags & Z_AUTH) != 0) { - zp->z_flags &= ~Z_AUTH; - /* - * Purge old data and mark the parent for - * reloading so that NS records are present - * during the zone transfer. - */ - do_reload(zp, 1); - } - } - if (zp->z_source == NULL) { - zp->z_source = new_zp->z_source; - new_zp->z_source = NULL; - } - - if (zp->z_ixfr_base != NULL) - (void)freestr(zp->z_ixfr_base); - zp->z_ixfr_base = new_zp->z_ixfr_base; - new_zp->z_ixfr_base = NULL; - - if (zp->z_ixfr_tmp != NULL) - freestr(zp->z_ixfr_tmp); - zp->z_ixfr_tmp = new_zp->z_ixfr_tmp; - new_zp->z_ixfr_tmp = NULL; - - if ((!noexpired || ((zp->z_flags & Z_EXPIRED) == 0)) && - ((zp->z_flags & Z_AUTH) == 0)) - zoneinit(zp); - else { - /* - ** Force slave to try transfer soon after SIGHUP. - */ - if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0 && - reloading && !reconfiging) { - qserial_retrytime(zp, tt.tv_sec); - sched_zone_maint(zp); - } - } - break; - case z_forward: - /* - * We don't know if the forwarder's list has changed - * so just purge the cache. In the future we may want - * see if the forwarders list has changed and only - * do this then. - */ - clean_cache_from(zp->z_origin, hashtab); - break; - } - if ((zp->z_flags & Z_FOUND) != 0 && /* already found? */ - (zp - zones) != DB_Z_CACHE) /* cache never sets Z_FOUND */ - ns_error(ns_log_config, "Zone \"%s\" declared more than once", - zp->z_origin); - zp->z_flags |= Z_FOUND; - ns_debug(ns_log_config, 1, - "zone[%d] type %d: '%s' z_time %lu, z_refresh %u", - zp-zones, zp->z_type, - *(zp->z_origin) == '\0' ? "." : zp->z_origin, - (u_long)zp->z_time, zp->z_refresh); -} - -/* - * Finish constructing a new zone. If valid, the constructed zone is - * merged into the zone database. The zone_config used is invalid after - * end_zone() completes. - */ -void -end_zone(zone_config zh, int should_install) { - struct zoneinfo *zp, *new_zp; - const char *zname; - symbol_value value; - - new_zp = zh.opaque; - INSIST(new_zp != NULL); - - zname = (new_zp->z_origin[0] == '\0') ? "." : new_zp->z_origin; - ns_debug(ns_log_config, 3, "end_zone('%s', %d)", zname, - should_install); - - if (!should_install) { - release_zone(new_zp); - return; - } - if (!validate_zone(new_zp)) { - ns_error(ns_log_config, - "zone '%s' did not validate, skipping", zname); - release_zone(new_zp); - return; - } - zp = find_zone(new_zp->z_origin, new_zp->z_class); - if (zp != NULL && zp->z_type != new_zp->z_type) { - remove_zone(zp, "redefined"); - zp = NULL; - } - if (zp == NULL) { - zp = new_zone(); - INSIST(zp != NULL); - value.integer = (zp - zones); - define_symbol(zone_symbol_table, new_zp->z_origin, - new_zp->z_class, value, 0); - } - ns_debug(ns_log_config, 5, "zone '%s', type = %d, class = %d", zname, - new_zp->z_type, new_zp->z_class); - if (new_zp->z_source != NULL) - ns_debug(ns_log_config, 5, " file = %s", new_zp->z_source); - ns_debug(ns_log_config, 5, " checknames = %d", new_zp->z_checknames); - if (new_zp->z_addrcnt != 0) { - int i; - - ns_debug(ns_log_config, 5, " masters:"); - for (i = 0; i < new_zp->z_addrcnt; i++) - ns_debug(ns_log_config, 5, " %s", - inet_ntoa(new_zp->z_addr[i])); - } - - update_zone_info(zp, new_zp); - release_zone(new_zp); - zh.opaque = NULL; -} - -int -set_zone_type(zone_config zh, int type) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - /* Fail if type already set for this zone */ - if (zp->z_type != 0) - return (0); - zp->z_type = type; - return (1); -} - -int -set_zone_filename(zone_config zh, char *filename) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - /* Fail if filename already set for this zone */ - if (zp->z_source != NULL) - return (0); - zp->z_source = filename; - return (1); -} - -int -set_zone_checknames(zone_config zh, enum severity s) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - /* Fail if checknames already set for this zone */ - if (zp->z_checknames != not_set) - return (0); - zp->z_checknames = s; - return (1); -} - -int -set_zone_ixfr_file(zone_config zh, char *filename) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - /* Fail if filename already set for this zone */ - if (zp->z_ixfr_base != NULL) - return (0); - zp->z_ixfr_base = filename; - if (zp->z_ixfr_tmp == NULL) { - int len = strlen(zp->z_ixfr_base) + (sizeof ".tmp"); - char *str = (char *) memget(len); - - sprintf(str, "%s.tmp", zp->z_ixfr_base); - zp->z_ixfr_tmp = savestr(str, 1); - memput(str, len); - } - - return (1); -} - -int -set_zone_ixfr_tmp(zone_config zh, char *filename) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - /* Fail if filename already set for this zone */ - if (zp->z_ixfr_tmp != NULL) - return (0); - zp->z_ixfr_tmp = filename; - return (1); -} - -int -set_zone_dialup(zone_config zh, int value) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - if (value) { - zp->z_dialup = zdialup_yes; -#ifdef BIND_NOTIFY - zp->z_notify = notify_yes; -#endif - } else - zp->z_dialup = zdialup_no; - - return (1); -} - -int -set_zone_notify(zone_config zh, enum notify value) { -#ifdef BIND_NOTIFY - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - zp->z_notify = value; -#endif - return (1); -} - -int -set_zone_maintain_ixfr_base(zone_config zh, int value) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - zp->z_maintain_ixfr_base = value; - - return (1); -} - -int -set_zone_update_acl(zone_config zh, ip_match_list iml) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - /* Fail if update_acl already set for this zone */ - if (zp->z_update_acl != NULL) - return (0); - zp->z_update_acl = iml; -#ifdef BIND_UPDATE - if (!ip_match_is_none(iml)) - zp->z_flags |= Z_DYNAMIC; - else - ns_debug(ns_log_config, 3, "update acl is none for '%s'", - zp->z_origin); -#endif - return (1); -} - -int -set_zone_query_acl(zone_config zh, ip_match_list iml) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - /* Fail if allow-query acl already set for this zone */ - if (zp->z_query_acl != NULL) - return (0); - zp->z_query_acl = iml; - return (1); -} - -int -set_zone_master_port(zone_config zh, u_short port) { - struct zoneinfo *zp = zh.opaque; - - zp->z_port = port; - return (1); -} - -int -set_zone_transfer_source(zone_config zh, struct in_addr ina) { - struct zoneinfo *zp = zh.opaque; - - zp->z_axfr_src = ina; - return (1); -} - -int -set_zone_transfer_acl(zone_config zh, ip_match_list iml) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - /* Fail if allow-transfer acl already set for this zone */ - if (zp->z_transfer_acl != NULL) - return (0); - zp->z_transfer_acl = iml; - return (1); -} - -int -set_zone_transfer_time_in(zone_config zh, long max_time) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - /* Fail if max-transfer-time-in already set for this zone */ - if (zp->z_max_transfer_time_in) - return (0); - zp->z_max_transfer_time_in = max_time; - return (1); -} - -int -set_zone_max_log_size_ixfr(zone_config zh, int size) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - zp->z_max_log_size_ixfr = size; - return (0); -} - -int -set_zone_pubkey(zone_config zh, const int flags, const int proto, - const int alg, const char *str) -{ - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - INSIST(zp != NULL && zp->z_origin != NULL); - return (add_trusted_key(zp->z_origin, flags, proto, alg, str)); -} - -int -set_trusted_key(const char *name, const int flags, const int proto, - const int alg, const char *str) { - INSIST(name != NULL); - return (add_trusted_key(name, flags, proto, alg, str)); -} - -int -add_zone_master(zone_config zh, struct in_addr address, struct dst_key * key) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - zp->z_addr[zp->z_addrcnt] = address; - zp->z_keys[zp->z_addrcnt] = key; - zp->z_addrcnt++; - if (zp->z_addrcnt >= NSMAX) { - ns_warning(ns_log_config, "NSMAX reached for zone '%s'", - zp->z_origin); - zp->z_addrcnt = NSMAX - 1; - } - return (1); -} - -int -add_zone_notify(zone_config zh, struct in_addr address) { -#ifdef BIND_NOTIFY - struct zoneinfo *zp; - int i; - - zp = zh.opaque; - INSIST(zp != NULL); - - /* Check for duplicates. */ - - for (i = 0; i < zp->z_notify_count; i++) { - if (memcmp(zp->z_also_notify + i, - &address, sizeof address) == 0) { - ns_warning(ns_log_config, - "duplicate also-notify address ignored [%s] for zone '%s'", - inet_ntoa(address), zp->z_origin); - return (1); - } - } - i = 0; - - if (zp->z_also_notify == NULL) { - zp->z_also_notify = memget(sizeof *zp->z_also_notify); - if (zp->z_also_notify == NULL) - i = 1; - } else { - register size_t size; - register struct in_addr *an_tmp; - size = zp->z_notify_count * sizeof *zp->z_also_notify; - an_tmp = memget(size + sizeof *zp->z_also_notify); - if (an_tmp == NULL) { - i = 1; - } else { - memcpy(an_tmp, zp->z_also_notify, size); - memput(zp->z_also_notify, size); - zp->z_also_notify = an_tmp; - } - } - if (i == 0) { - zp->z_also_notify[zp->z_notify_count] = address; - zp->z_notify_count++; - } else { - ns_warning(ns_log_config, "also-notify add failed (memget) [%s] for zone '%s'", - inet_ntoa(address), zp->z_origin); - } -#endif - return (1); -} - -/* Options */ - -options -new_options() { - options op; - char hostname[256]; - - op = (options)memget(sizeof (struct options)); - if (op == NULL) - panic("memget failed in new_options()", NULL); - - op->version = savestr(ShortVersion, 1); - if (gethostname(hostname, sizeof(hostname)) == 0) - op->hostname = savestr(hostname, 1); - else - op->hostname = NULL; - op->directory = savestr(".", 1); - op->pid_filename = savestr(_PATH_PIDFILE, 1); - op->named_xfer = savestr(_PATH_XFER, 1); - op->dump_filename = savestr(_PATH_DUMPFILE, 1); - op->stats_filename = savestr(_PATH_STATS, 1); - op->memstats_filename = savestr(_PATH_MEMSTATS, 1); - op->flags = DEFAULT_OPTION_FLAGS; - op->transfers_in = DEFAULT_XFERS_RUNNING; - op->transfers_per_ns = DEFAULT_XFERS_PER_NS; - op->transfers_out = 0; - op->serial_queries = MAXQSERIAL; - op->transfer_format = axfr_one_answer; - op->max_transfer_time_in = MAX_XFER_TIME; - memset(&op->query_source, 0, sizeof op->query_source); - op->query_source.sin_family = AF_INET; - op->query_source.sin_addr.s_addr = htonl(INADDR_ANY); - op->query_source.sin_port = htons(0); /* INPORT_ANY */ - op->axfr_src.s_addr = 0; -#ifdef BIND_NOTIFY - op->notify_count = 0; - op->also_notify = NULL; -#endif - op->blackhole_acl = NULL; - op->query_acl = NULL; - op->transfer_acl = NULL; - op->recursion_acl = NULL; - op->sortlist = NULL; - op->topology = NULL; - op->data_size = 0UL; /* use system default */ - op->stack_size = 0UL; /* use system default */ - op->core_size = 0UL; /* use system default */ - op->files = ULONG_MAX; /* unlimited */ - op->check_names[primary_trans] = fail; - op->check_names[secondary_trans] = warn; - op->check_names[response_trans] = ignore; - op->listen_list = NULL; - op->fwdtab = NULL; - /* XXX init forwarding */ - op->clean_interval = 3600; - op->interface_interval = 3600; - op->stats_interval = 3600; - op->ordering = NULL; - op->max_ncache_ttl = DEFAULT_MAX_NCACHE_TTL; - op->max_host_stats = 0; - op->lame_ttl = NTTL; - op->heartbeat_interval = 3600; - op->max_log_size_ixfr = 0; - op->minroots = MINROOTS; - op->preferred_glue = 0; -#ifdef BIND_NOTIFY - op->notify = notify_yes; -#endif - op->edns_udp_size = EDNS_MESSAGE_SZ; - return (op); -} - -void -free_options(options op) { - INSIST(op != NULL); - - if (op->hostname) - op->hostname = freestr(op->hostname); - if (op->version) - op->version = freestr(op->version); - if (op->directory) - op->directory = freestr(op->directory); - if (op->pid_filename) - op->pid_filename = freestr(op->pid_filename); - if (op->named_xfer) - op->named_xfer = freestr(op->named_xfer); - if (op->dump_filename) - op->dump_filename = freestr(op->dump_filename); - if (op->stats_filename) - op->stats_filename = freestr(op->stats_filename); - if (op->memstats_filename) - op->memstats_filename = freestr(op->memstats_filename); -#ifdef BIND_NOTIFY - if (op->also_notify) - free_also_notify(op); -#endif - if (op->blackhole_acl) - free_ip_match_list(op->blackhole_acl); - if (op->query_acl) - free_ip_match_list(op->query_acl); - if (op->recursion_acl) - free_ip_match_list(op->recursion_acl); - if (op->transfer_acl) - free_ip_match_list(op->transfer_acl); - if (op->sortlist) - free_ip_match_list(op->sortlist); - if (op->ordering) - free_rrset_order_list(op->ordering); - if (op->topology) - free_ip_match_list(op->topology); - if (op->listen_list) - free_listen_info_list(op->listen_list); - if (op->fwdtab) - free_forwarders(op->fwdtab); - memput(op, sizeof *op); -} - -static void -set_boolean_option(u_int *op_flags, int bool_opt, int value) { - INSIST(op_flags != NULL); - - switch (bool_opt) { -#ifdef HITCOUNTS - case OPTION_HITCOUNT: -#endif /* HITCOUNTS */ - case OPTION_NORECURSE: - case OPTION_NOFETCHGLUE: - case OPTION_FORWARD_ONLY: - case OPTION_FAKE_IQUERY: - case OPTION_SUPNOTIFY_INITIAL: - case OPTION_NONAUTH_NXDOMAIN: - case OPTION_MULTIPLE_CNAMES: - case OPTION_USE_IXFR: - case OPTION_MAINTAIN_IXFR_BASE: - case OPTION_HOSTSTATS: - case OPTION_DEALLOC_ON_EXIT: - case OPTION_USE_ID_POOL: - case OPTION_NORFC2308_TYPE1: - case OPTION_NODIALUP: - case OPTION_TREAT_CR_AS_SPACE: - if (value) - *op_flags |= bool_opt; - else - *op_flags &= ~bool_opt; - break; - default: - panic("unexpected option in set_boolean_option", NULL); - } -} - -void -set_global_boolean_option(options op, int bool_opt, int value) { - - INSIST(op != NULL); - - set_boolean_option(&op->flags, bool_opt, value); -} - -void -set_zone_boolean_option(zone_config zh, int bool_opt, int value) { - struct zoneinfo *zp; - - zp = zh.opaque; - INSIST(zp != NULL); - - set_boolean_option(&zp->z_options, bool_opt, value); - - /* Flag that zone option overrides corresponding global option */ - zp->z_optset |= bool_opt; -} - -#ifdef HAVE_GETRUSAGE -enum limit { Datasize, Stacksize, Coresize, Files }; - -static struct rlimit initial_data_size; -static struct rlimit initial_stack_size; -static struct rlimit initial_core_size; -static struct rlimit initial_num_files; - -static void -get_initial_limits() { - int fdlimit = evHighestFD(ev) + 1; - -# ifdef RLIMIT_DATA - if (getrlimit(RLIMIT_DATA, &initial_data_size) < 0) - ns_warning(ns_log_config, "getrlimit(DATA): %s", - strerror(errno)); -# endif -# ifdef RLIMIT_STACK - if (getrlimit(RLIMIT_STACK, &initial_stack_size) < 0) - ns_warning(ns_log_config, "getrlimit(STACK): %s", - strerror(errno)); -# endif -# ifdef RLIMIT_CORE - if (getrlimit(RLIMIT_CORE, &initial_core_size) < 0) - ns_warning(ns_log_config, "getrlimit(CORE): %s", - strerror(errno)); -# endif -# ifdef RLIMIT_NOFILE - if (getrlimit(RLIMIT_NOFILE, &initial_num_files) < 0) - ns_warning(ns_log_config, "getrlimit(NOFILE): %s", - strerror(errno)); - else if (initial_num_files.rlim_cur > fdlimit) { - initial_num_files.rlim_cur = fdlimit; - if (initial_num_files.rlim_cur > initial_num_files.rlim_max) - initial_num_files.rlim_max = fdlimit; - if (setrlimit(RLIMIT_NOFILE, &initial_num_files) < 0) { - ns_warning(ns_log_config, "setrlimit(files): %s", - strerror(errno)); - } else { - ns_warning(ns_log_config, - "limit files set to fdlimit (%d)", - fdlimit); - } - } -# endif -} - -static void -ns_rlimit(enum limit limit, u_long limit_value) { - struct rlimit limits, old_limits; - int rlimit = -1; - int fdlimit = evHighestFD(ev) + 1; - const char *name; - rlimit_type value; - - if (limit_value == ULONG_MAX) { -#ifndef RLIMIT_FILE_INFINITY - if (limit == Files) - value = MIN((rlimit_type)evHighestFD(ev) + 1, - initial_num_files.rlim_max); - else -#endif - value = (rlimit_type)RLIM_INFINITY; - } else - value = (rlimit_type)limit_value; - - limits.rlim_cur = limits.rlim_max = value; - switch (limit) { - case Datasize: -#ifdef RLIMIT_DATA - rlimit = RLIMIT_DATA; -#endif - name = "max data size"; - if (value == 0) - limits = initial_data_size; - break; - case Stacksize: -#ifdef RLIMIT_STACK - rlimit = RLIMIT_STACK; -#endif - name = "max stack size"; - if (value == 0) - limits = initial_stack_size; - break; - case Coresize: -#ifdef RLIMIT_CORE - rlimit = RLIMIT_CORE; -#endif - name = "max core size"; - if (value == 0) - limits = initial_core_size; - break; - case Files: -#ifdef RLIMIT_NOFILE - rlimit = RLIMIT_NOFILE; -#endif - name = "max number of open files"; - if (value == 0) - limits = initial_num_files; - if ((int)value > fdlimit) - limits.rlim_cur = limits.rlim_max = value = fdlimit; - break; - default: - name = NULL; /* Make gcc happy. */ - panic("impossible condition in ns_rlimit()", NULL); - } - if (rlimit == -1) { - ns_warning(ns_log_config, - "limit \"%s\" not supported on this system - ignored", - name); - return; - } - if (getrlimit(rlimit, &old_limits) < 0) { - ns_warning(ns_log_config, "getrlimit(%s): %s", name, - strerror(errno)); - } - if (user_id != 0 && limits.rlim_max == RLIM_INFINITY) - limits.rlim_cur = limits.rlim_max = old_limits.rlim_max; - if (setrlimit(rlimit, &limits) < 0) { - ns_warning(ns_log_config, "setrlimit(%s): %s", name, - strerror(errno)); - return; - } else { - if (value == 0) - ns_debug(ns_log_config, 3, "%s is default", name); - else if (value == RLIM_INFINITY) - ns_debug(ns_log_config, 3, "%s is unlimited", name); - else -#ifdef RLIMIT_LONGLONG - ns_debug(ns_log_config, 3, "%s is %llu", name, - (unsigned long long)value); -#else - ns_debug(ns_log_config, 3, "%s is %lu", name, value); -#endif - } -} -#endif /* HAVE_GETRUSAGE */ - -listen_info_list -new_listen_info_list() { - listen_info_list ll; - - ll = (listen_info_list)memget(sizeof (struct listen_info_list)); - if (ll == NULL) - panic("memget failed in new_listen_info_list()", NULL); - ll->first = NULL; - ll->last = NULL; - return (ll); -} - -void -free_listen_info_list(listen_info_list ll) { - listen_info li, next_li; - - INSIST(ll != NULL); - for (li = ll->first; li != NULL; li = next_li) { - next_li = li->next; - free_ip_match_list(li->list); - memput(li, sizeof *li); - } - memput(ll, sizeof *ll); -} - -void -add_listen_on(options op, u_short port, ip_match_list iml) { - listen_info_list ll; - listen_info ni; - - INSIST(op != NULL); - - if (op->listen_list == NULL) - op->listen_list = new_listen_info_list(); - ll = op->listen_list; - ni = (listen_info)memget(sizeof (struct listen_info)); - if (ni == NULL) - panic("memget failed in add_listen_on", NULL); - ni->port = port; - ni->list = iml; - ni->next = NULL; - if (ll->last != NULL) - ll->last->next = ni; - ll->last = ni; - if (ll->first == NULL) - ll->first = ni; -} - -FILE * -write_open(char *filename) { - FILE *stream; - int fd; - struct stat sb; - int regular; - - if (stat(filename, &sb) < 0) { - if (errno != ENOENT) { - ns_error(ns_log_os, - "write_open: stat of %s failed: %s", - filename, strerror(errno)); - return (NULL); - } - regular = 1; - } else - regular = (sb.st_mode & S_IFREG); - - if (!regular) { - ns_error(ns_log_os, "write_open: %s isn't a regular file", - filename); - return (NULL); - } - - (void)unlink(filename); - fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, - S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); - if (fd < 0) - return (NULL); - (void) fchown(fd, user_id, group_id); - stream = fdopen(fd, "w"); - if (stream == NULL) { - (void)unlink(filename); - (void)close(fd); - } - return (stream); -} - -void -update_pid_file() { - FILE *fp; - - REQUIRE(server_options != NULL); - REQUIRE(server_options->pid_filename != NULL); - - /* XXX */ ns_debug(ns_log_default, 1, "update_pid_file()"); - if (current_pid_filename != NULL) { - (void)unlink(current_pid_filename); - current_pid_filename = freestr(current_pid_filename); - } - current_pid_filename = savestr(server_options->pid_filename, 0); - if (current_pid_filename == NULL) { - ns_error(ns_log_config, - "savestr() failed in update_pid_file()"); - return; - } - fp = write_open(current_pid_filename); - if (fp != NULL) { - (void) fprintf(fp, "%ld\n", (long)getpid()); - (void) fclose(fp); - } else - ns_error(ns_log_config, "couldn't create pid file '%s'", - server_options->pid_filename); -} - -/* - * XXX This function will eventually be public and will be relocated to - * the UNIX OS support library. - */ - -static int -os_change_directory(const char *name) { - struct stat sb; - - if (name == NULL || - *name == '\0') { - errno = EINVAL; - return (0); - } - - if (chdir(name) < 0) - return (0); - - if (stat(name, &sb) < 0) { - ns_error(ns_log_os, "stat(%s) failed: %s", name, - strerror(errno)); - return (1); - } - if (sb.st_mode & S_IWOTH) - ns_warning(ns_log_os, "directory %s is world-writable", name); - - return (1); -} - -static void -periodic_getnetconf(evContext ctx, void *uap, struct timespec due, - struct timespec inter) -{ - UNUSED(ctx); - UNUSED(uap); - UNUSED(due); - UNUSED(inter); - - getnetconf(1); -} - -static int clean_interval = 0; -static int interface_interval = 0; -static int stats_interval = 0; -static int heartbeat_interval = 0; - -static void -set_interval_timer(int which_timer, int interval) { - evTimerID *tid = NULL; - evTimerFunc func = NULL; - int changed = 0; - - switch (which_timer) { - case CLEAN_TIMER: - if (clean_interval != interval) - changed = 1; - clean_interval = interval; - tid = &clean_timer; - func = ns_cleancache; - break; - case INTERFACE_TIMER: - if (interface_interval != interval) - changed = 1; - interface_interval = interval; - tid = &interface_timer; - func = periodic_getnetconf; - break; - case STATS_TIMER: - if (stats_interval != interval) - changed = 1; - stats_interval = interval; - tid = &stats_timer; - func = ns_logstats; - break; - case HEARTBEAT_TIMER: - if (heartbeat_interval != interval) - changed = 1; - heartbeat_interval = interval; - tid = &heartbeat_timer; - func = ns_heartbeat; - break; - default: - ns_panic(ns_log_config, 1, - "set_interval_timer: unknown timer %d", which_timer); - } - if ((active_timers & which_timer) != 0) { - if (interval > 0) { - if (changed && - evResetTimer(ev, *tid, func, NULL, - evAddTime(evNowTime(), - evConsTime(interval, 0)), - evConsTime(interval, 0)) < 0) - ns_error(ns_log_config, - "evResetTimer %d interval %d failed: %s", - which_timer, interval, - strerror(errno)); - } else { - if (evClearTimer(ev, *tid) < 0) - ns_error(ns_log_config, - "evClearTimer %d failed: %s", - which_timer, strerror(errno)); - else - active_timers &= ~which_timer; - } - } else if (interval > 0) { - if (evSetTimer(ev, func, NULL, - evAddTime(evNowTime(), - evConsTime(interval, 0)), - evConsTime(interval, 0), tid) < 0) - ns_error(ns_log_config, - "evSetTimer %d interval %d failed: %s", - which_timer, interval, strerror(errno)); - else - active_timers |= which_timer; - } -} - -/* - * Set all named global options based on the global options structure - * generated by the parser. - */ -void -set_options(options op, int is_default) { - INSIST(op != NULL); - - if (op->listen_list == NULL) { - ip_match_list iml; - ip_match_element ime; - struct in_addr address; - - op->listen_list = new_listen_info_list(); - - address.s_addr = htonl(INADDR_ANY); - iml = new_ip_match_list(); - ime = new_ip_match_pattern(address, 0); - add_to_ip_match_list(iml, ime); - add_listen_on(op, htons(NS_DEFAULTPORT), iml); - } - if (op->topology == NULL) { - ip_match_list iml; - ip_match_element ime; - - /* default topology is { localhost; localnets; } */ - iml = new_ip_match_list(); - ime = new_ip_match_localhost(); - add_to_ip_match_list(iml, ime); - ime = new_ip_match_localnets(); - add_to_ip_match_list(iml, ime); - op->topology = iml; - } - if (server_options != NULL) - free_options(server_options); - server_options = op; - - /* XXX should validate pid filename */ - INSIST(op->pid_filename != NULL); - - if (op->directory && !os_change_directory(op->directory)) - ns_panic(ns_log_config, 0, "can't change directory to %s: %s", - op->directory, strerror(errno)); - - /* XXX currently a value of 0 means "use default"; it would be - better if the options block had a "attributes updated" vector - (like the way X deals with GC updates) */ - - if (!op->transfers_in) - op->transfers_in = DEFAULT_XFERS_RUNNING; - else if (op->transfers_in > MAX_XFERS_RUNNING) { - ns_warning(ns_log_config, - "the maximum number of concurrent inbound transfers is %d", - MAX_XFERS_RUNNING); - op->transfers_in = MAX_XFERS_RUNNING; - } - - if (!op->transfers_per_ns) - op->transfers_per_ns = DEFAULT_XFERS_PER_NS; - - if (!op->max_transfer_time_in) - op->max_transfer_time_in = MAX_XFER_TIME; - - /* XXX currently transfers_out is not used */ - - if (!op->max_ncache_ttl) - op->max_ncache_ttl = DEFAULT_MAX_NCACHE_TTL; - else if (op->max_ncache_ttl > max_cache_ttl) - op->max_ncache_ttl = max_cache_ttl; - - if (op->lame_ttl > (3 * NTTL)) - op->lame_ttl = 3 * NTTL; - - /* - * Limits - */ - -#ifdef HAVE_GETRUSAGE - ns_rlimit(Datasize, op->data_size); - ns_rlimit(Stacksize, op->stack_size); - ns_rlimit(Coresize, op->core_size); - ns_rlimit(Files, op->files); -#else - ns_info(ns_log_config, "cannot set resource limits on this system"); -#endif - - /* - * Timers - */ - set_interval_timer(CLEAN_TIMER, server_options->clean_interval); - set_interval_timer(INTERFACE_TIMER, - server_options->interface_interval); - set_interval_timer(STATS_TIMER, server_options->stats_interval); - set_interval_timer(HEARTBEAT_TIMER, - server_options->heartbeat_interval); - - options_installed = 1; - default_options_installed = is_default; -} - -void -use_default_options() { - set_options(new_options(), 1); -} - -/* - * rrset order types - */ -static struct res_sym order_table [] = { - { unknown_order, " unknown ", NULL }, /* can't match */ - { fixed_order, "fixed", NULL }, - { cyclic_order, "cyclic", NULL }, - { random_order, "random", NULL }, - { unknown_order, NULL, NULL } -}; - -/* - * Return the print name of the ordering value. - */ -const char * -p_order(int order) { - return (__sym_ntos(order_table, order, (int *)0)); -} - -/* - * Lookup the ordering by name and return the matching enum value. - */ -enum ordering -lookup_ordering(const char *name) { - int i; - - for (i = 0; order_table[i].name != NULL; i++) - if (strcasecmp(name,order_table[i].name) == 0) - return ((enum ordering)order_table[i].number); - return (unknown_order); -} - -/* - * rrset-order Lists - */ -rrset_order_list -new_rrset_order_list() { - rrset_order_list rol ; - - rol = (rrset_order_list)memget(sizeof (struct rrset_order_list)); - if (rol == NULL) - panic("memget failed in new_rrset_order_list", NULL); - rol->first = NULL; - rol->last = NULL; - - return (rol); -} - -void -free_rrset_order_list(rrset_order_list rol) { - rrset_order_element roe, next_element; - - for (roe = rol->first; roe != NULL; roe = next_element) { - next_element = roe->next; - roe->name = freestr(roe->name); - memput(roe, sizeof (*roe)); - } - memput(rol, sizeof (*rol)); -} - -void -add_to_rrset_order_list(rrset_order_list rol, rrset_order_element roe) { - INSIST(rol != NULL); - INSIST(roe != NULL); - - if (rol->last != NULL) - rol->last->next = roe; - roe->next = NULL; - rol->last = roe; - if (rol->first == NULL) - rol->first = roe; -} - -#ifdef notyet -/* XXX this isn't being used yet, but it probably should be. Where? */ -void -dprint_rrset_order_list(int category, rrset_order_list rol, int indent, - char *allow, char *deny) { - rrset_order_element roe ; - char spaces[40+1]; - - INSIST(rol != NULL); - - if (indent > 40) - indent = 40; - if (indent) - memset(spaces, ' ', indent); - spaces[indent] = '\0'; - - for (roe = rol->first; roe != NULL; roe = roe->next) { - ns_debug(category, 7, "%sclass %s type %s name %s order %s", - spaces, p_class(roe->class), p_type(roe->type), - roe->name, p_order(roe->order)); - } -} -#endif - -rrset_order_element -new_rrset_order_element(int class, int type, char *name, enum ordering order) -{ - rrset_order_element roe; - int i ; - - roe = (rrset_order_element)memget(sizeof (struct rrset_order_element)); - if (roe == NULL) - panic("memget failed in new_rrset_order_element", NULL); - roe->class = class ; - roe->type = type ; - roe->name = name; - roe->order = order; - - i = strlen(roe->name) - 1; - INSIST (i >= 0); - if (roe->name[i - 1] == '.') { - /* We compare from right to left so we don't need a dot on - the end. */ - roe->name[i - 1] = '\0' ; - } - - return roe ; -} - - -/* - * IP Matching Lists - */ - -ip_match_list -new_ip_match_list() { - ip_match_list iml; - - iml = (ip_match_list)memget(sizeof (struct ip_match_list)); - if (iml == NULL) - panic("memget failed in new_ip_match_list", NULL); - iml->first = NULL; - iml->last = NULL; - return (iml); -} - -void -free_ip_match_list(ip_match_list iml) { - ip_match_element ime, next_element; - - for (ime = iml->first; ime != NULL; ime = next_element) { - next_element = ime->next; - memput(ime, sizeof *ime); - } - memput(iml, sizeof *iml); -} - -ip_match_element -new_ip_match_pattern(struct in_addr address, u_int mask_bits) { - ip_match_element ime; - u_int32_t mask; - - ime = (ip_match_element)memget(sizeof (struct ip_match_element)); - if (ime == NULL) - panic("memget failed in new_ip_match_pattern", NULL); - ime->type = ip_match_pattern; - ime->flags = 0; - ime->u.direct.address = address; - if (mask_bits == 0) - /* can't shift >= the size of a type in bits, so - we deal with an empty mask here */ - mask = 0; - else { - /* set the 'mask_bits' most significant bits */ - mask = 0xffffffffU; - mask >>= (32 - mask_bits); - mask <<= (32 - mask_bits); - } - mask = ntohl(mask); - ime->u.direct.mask.s_addr = mask; - ime->next = NULL; - if (!ina_onnet(ime->u.direct.address, ime->u.direct.address, - ime->u.direct.mask)) { - memput(ime, sizeof *ime); - ime = NULL; - } - return (ime); -} - -ip_match_element -new_ip_match_mask(struct in_addr address, struct in_addr mask) { - ip_match_element ime; - - ime = (ip_match_element)memget(sizeof (struct ip_match_element)); - if (ime == NULL) - panic("memget failed in new_ip_match_pattern", NULL); - ime->type = ip_match_pattern; - ime->flags = 0; - ime->u.direct.address = address; - ime->u.direct.mask = mask; - ime->next = NULL; - if (!ina_onnet(ime->u.direct.address, ime->u.direct.address, - ime->u.direct.mask)) { - memput(ime, sizeof *ime); - ime = NULL; - } - return (ime); -} - -ip_match_element -new_ip_match_indirect(ip_match_list iml) { - ip_match_element ime; - - INSIST(iml != NULL); - - ime = (ip_match_element)memget(sizeof (struct ip_match_element)); - if (ime == NULL) - panic("memget failed in new_ip_match_indirect", NULL); - ime->type = ip_match_indirect; - ime->flags = 0; - ime->u.indirect.list = iml; - ime->next = NULL; - return (ime); -} - -ip_match_element -new_ip_match_key(DST_KEY *dst_key) { - ip_match_element ime; - - ime = (ip_match_element)memget(sizeof (struct ip_match_element)); - if (ime == NULL) - panic("memget failed in new_ip_match_key", NULL); - ime->type = ip_match_key; - ime->flags = 0; - ime->u.key.key = dst_key; - return (ime); -} - -ip_match_element -new_ip_match_localhost() { - ip_match_element ime; - - ime = (ip_match_element)memget(sizeof (struct ip_match_element)); - if (ime == NULL) - panic("memget failed in new_ip_match_localhost", NULL); - ime->type = ip_match_localhost; - ime->flags = 0; - ime->u.indirect.list = NULL; - ime->next = NULL; - return (ime); -} - -ip_match_element -new_ip_match_localnets() { - ip_match_element ime; - - ime = (ip_match_element)memget(sizeof (struct ip_match_element)); - if (ime == NULL) - panic("memget failed in new_ip_match_localnets", NULL); - ime->type = ip_match_localnets; - ime->flags = 0; - ime->u.indirect.list = NULL; - ime->next = NULL; - return (ime); -} - -void -ip_match_negate(ip_match_element ime) { - if (ime->flags & IP_MATCH_NEGATE) - ime->flags &= ~IP_MATCH_NEGATE; - else - ime->flags |= IP_MATCH_NEGATE; -} - -void -add_to_ip_match_list(ip_match_list iml, ip_match_element ime) { - INSIST(iml != NULL); - INSIST(ime != NULL); - - if (iml->last != NULL) - iml->last->next = ime; - ime->next = NULL; - iml->last = ime; - if (iml->first == NULL) - iml->first = ime; -} - -void -dprint_ip_match_list(int category, ip_match_list iml, int indent, - const char *allow, const char *deny) { - ip_match_element ime; - char spaces[40+1]; - char addr_text[sizeof "255.255.255.255"]; - char mask_text[sizeof "255.255.255.255"]; - - INSIST(iml != NULL); - - if (indent > 40) - indent = 40; - if (indent) - memset(spaces, ' ', indent); - spaces[indent] = '\0'; - - for (ime = iml->first; ime != NULL; ime = ime->next) { - switch (ime->type) { - case ip_match_pattern: - memset(addr_text, 0, sizeof addr_text); - strncpy(addr_text, inet_ntoa(ime->u.direct.address), - ((sizeof addr_text) - 1)); - memset(mask_text, 0, sizeof mask_text); - strncpy(mask_text, inet_ntoa(ime->u.direct.mask), - ((sizeof mask_text) - 1)); - ns_debug(category, 7, "%s%saddr: %s, mask: %s", - spaces, - (ime->flags & IP_MATCH_NEGATE) ? deny : allow, - addr_text, mask_text); - break; - case ip_match_localhost: - ns_debug(category, 7, "%s%slocalhost", spaces, - (ime->flags & IP_MATCH_NEGATE) ? - deny : allow); - break; - case ip_match_localnets: - ns_debug(category, 7, "%s%slocalnets", spaces, - (ime->flags & IP_MATCH_NEGATE) ? - deny : allow); - break; - case ip_match_indirect: - ns_debug(category, 7, "%s%sindirect list %p", spaces, - (ime->flags & IP_MATCH_NEGATE) ? deny : allow, - ime->u.indirect.list); - if (ime->u.indirect.list != NULL) - dprint_ip_match_list(category, - ime->u.indirect.list, - indent+2, allow, deny); - break; - case ip_match_key: - ns_debug(category, 7, "%s%skey %s", spaces, - (ime->flags & IP_MATCH_NEGATE) ? deny : allow, - ime->u.key.key->dk_key_name); - break; - default: - panic("unexpected ime type in dprint_ip_match_list()", - NULL); - } - } -} - -int -ip_match_addr_or_key(ip_match_list iml, struct in_addr address, - DST_KEY *key) -{ - ip_match_element ime; - int ret; - int indirect; - - INSIST(iml != NULL); - for (ime = iml->first; ime != NULL; ime = ime->next) { - switch (ime->type) { - case ip_match_pattern: - indirect = 0; - break; - case ip_match_indirect: - indirect = 1; - break; - case ip_match_localhost: - ime->u.indirect.list = local_addresses; - indirect = 1; - break; - case ip_match_localnets: - ime->u.indirect.list = local_networks; - indirect = 1; - break; - case ip_match_key: - if (key == NULL) { - indirect = 0; - break; - } - else { - if (ns_samename(ime->u.key.key->dk_key_name, - key->dk_key_name) == 1) - return (1); - else - continue; - } - default: - indirect = 0; - panic("unexpected ime type in ip_match_addr_or_key()", - NULL); - } - if (indirect) { - ret = ip_match_addr_or_key(ime->u.indirect.list, - address, key); - if (ret > 0) { - if (ime->flags & IP_MATCH_NEGATE) - ret = (ret) ? 0 : 1; - return (ret); - } - } else { - if (ina_onnet(address, ime->u.direct.address, - ime->u.direct.mask)) { - if (ime->flags & IP_MATCH_NEGATE) - return (0); - else - return (1); - } - } - } - return (-1); -} - -int -ip_match_address(ip_match_list iml, struct in_addr address) { - return ip_match_addr_or_key(iml, address, NULL); -} - -int -ip_addr_or_key_allowed(ip_match_list iml, struct in_addr address, - DST_KEY *key) -{ - int ret; - - if (iml == NULL) - return (0); - ret = ip_match_addr_or_key(iml, address, key); - if (ret < 0) - ret = 0; - return (ret); -} - -int -ip_address_allowed(ip_match_list iml, struct in_addr address) { - return(ip_addr_or_key_allowed(iml, address, NULL)); -} - -int -ip_match_network(ip_match_list iml, struct in_addr address, - struct in_addr mask) { - ip_match_element ime; - int ret; - int indirect; - - INSIST(iml != NULL); - for (ime = iml->first; ime != NULL; ime = ime->next) { - switch (ime->type) { - case ip_match_pattern: - indirect = 0; - break; - case ip_match_indirect: - indirect = 1; - break; - case ip_match_localhost: - ime->u.indirect.list = local_addresses; - indirect = 1; - break; - case ip_match_localnets: - ime->u.indirect.list = local_networks; - indirect = 1; - break; - case ip_match_key: - indirect = 0; - break; - default: - indirect = 0; /* Make gcc happy. */ - panic("unexpected ime type in ip_match_network()", - NULL); - } - if (indirect) { - ret = ip_match_network(ime->u.indirect.list, - address, mask); - if (ret >= 0) { - if (ime->flags & IP_MATCH_NEGATE) - ret = (ret) ? 0 : 1; - return (ret); - } - } else { - if (address.s_addr == ime->u.direct.address.s_addr && - mask.s_addr == ime->u.direct.mask.s_addr) { - if (ime->flags & IP_MATCH_NEGATE) - return (0); - else - return (1); - } - } - } - return (-1); -} - -int -distance_of_address(ip_match_list iml, struct in_addr address) { - ip_match_element ime; - int ret; - int indirect; - int distance; - - INSIST(iml != NULL); - for (distance = 1, ime = iml->first; - ime != NULL; ime = ime->next, distance++) { - switch (ime->type) { - case ip_match_pattern: - indirect = 0; - break; - case ip_match_indirect: - indirect = 1; - break; - case ip_match_localhost: - ime->u.indirect.list = local_addresses; - indirect = 1; - break; - case ip_match_localnets: - ime->u.indirect.list = local_networks; - indirect = 1; - break; - case ip_match_key: - indirect = 0; - return (-1); - default: - indirect = 0; /* Make gcc happy. */ - panic("unexpected ime type in distance_of_address()", - NULL); - } - if (indirect) { - ret = ip_match_address(ime->u.indirect.list, address); - if (ret >= 0) { - if (ime->flags & IP_MATCH_NEGATE) - ret = (ret) ? 0 : 1; - if (distance > MAX_TOPOLOGY_DISTANCE) - distance = MAX_TOPOLOGY_DISTANCE; - if (ret) - return (distance); - else - return (MAX_TOPOLOGY_DISTANCE); - } - } else { - if (ina_onnet(address, ime->u.direct.address, - ime->u.direct.mask)) { - if (distance > MAX_TOPOLOGY_DISTANCE) - distance = MAX_TOPOLOGY_DISTANCE; - if (ime->flags & IP_MATCH_NEGATE) - return (MAX_TOPOLOGY_DISTANCE); - else - return (distance); - } - } - } - return (UNKNOWN_TOPOLOGY_DISTANCE); -} - -int -ip_match_is_none(ip_match_list iml) { - ip_match_element ime; - - if ((iml == NULL) || (iml->first == NULL)) - return (1); - ime = iml->first; - if (ime->type == ip_match_indirect) { - if (ime->flags & IP_MATCH_NEGATE) - return (0); - iml = ime->u.indirect.list; - if ((iml == NULL) || (iml->first == NULL)) - return (0); - ime = iml->first; - } - if (ime->type == ip_match_pattern) { - if ((ime->flags & IP_MATCH_NEGATE) && - ime->u.direct.address.s_addr == 0 && - ime->u.direct.mask.s_addr == 0) - return (1); - } - return (0); -} - -/* - * find_forwarder finds the fwddata structure for an address, - * allocating one if we can't find one already existing. - */ - -static struct fwddata * -find_forwarder(struct in_addr address) -{ - struct fwddata *fdp; - struct fwddata **fdpp = NULL; - register int i; - - for (i = 0; i < fwddata_count; i++) { - fdp = fwddata[i]; - if (fdp == NULL) { - if (fdpp == NULL) - fdpp = &fwddata[i]; - continue; - } - if (memcmp(&fdp->fwdaddr.sin_addr, &address, - sizeof(address)) == 0) { - fdp->ref_count++; - return (fdp); - } - } - - fdp = (struct fwddata *)memget(sizeof(struct fwddata)); - if (!fdp) - panic("memget failed in find_forwarder", NULL); - - memset(&fdp->fwdaddr, 0, sizeof(fdp->fwdaddr)); - fdp->fwdaddr.sin_family = AF_INET; - fdp->fwdaddr.sin_addr = address; - fdp->fwdaddr.sin_port = ns_port; - - fdp->ns = savedata(C_IN, T_NS, 0, NULL, 0); - if (!fdp->ns) - panic("memget failed in find_forwarder", NULL); - - fdp->nsdata = savedata(C_IN, T_A, 0, NULL, 0); - if (!fdp->nsdata) - panic("memget failed in find_forwarder", NULL); - fdp->nsdata->d_nstime = 1 + (int)(25.0*rand()/(RAND_MAX + 1.0)); - - fdp->ref_count = 1; - - if (fdpp != NULL) { - *fdpp = fdp; - return (fdp); - } - - i = 0; - if (fwddata == NULL) { - fwddata = memget(sizeof *fwddata); - if (fwddata == NULL) - i = 1; - } else { - register size_t size; - register struct fwddata **an_tmp; - - size = fwddata_count * sizeof *fwddata; - an_tmp = memget(size + sizeof *fwddata); - if (an_tmp == NULL) { - i = 1; - } else { - memcpy(an_tmp, fwddata, size); - memput(fwddata, size); - fwddata = an_tmp; - } - } - - if (i == 0) { - fwddata[fwddata_count] = fdp; - fwddata_count++; - } else { - ns_warning(ns_log_config, "forwarder add failed (memget) [%s]", - inet_ntoa(address)); - } - - return (fdp); -} - -/* - * Forwarder glue - * - * XXX This will go away when the rest of bind understands - * forward zones. - */ - -static void -add_forwarder(struct fwdinfo **fipp, struct in_addr address) { - struct fwdinfo *fip = *fipp, *ftp = NULL; - struct fwddata *fdp; - -#ifdef FWD_LOOP - if (aIsUs(address)) { - ns_error(ns_log_config, "forwarder '%s' ignored, my address", - inet_ntoa(address)); - return; - } -#endif /* FWD_LOOP */ - - /* On multiple forwarder lines, move to end of the list. */ - while (fip != NULL && fip->next != NULL) - fip = fip->next; - - fdp = find_forwarder(address); - ftp = (struct fwdinfo *)memget(sizeof(struct fwdinfo)); - if (!ftp) - panic("memget failed in add_forwarder", NULL); - ftp->fwddata = fdp; - ftp->next = NULL; - if (fip == NULL) - *fipp = ftp; /* First time only */ - else - fip->next = ftp; -} - -void -free_also_notify(options op) { -#ifdef BIND_NOTIFY - memput(op->also_notify, op->notify_count * sizeof *op->also_notify); - op->also_notify = NULL; - op->notify_count = 0; -#endif -} - -int -add_global_also_notify(options op, struct in_addr address) { -#ifdef BIND_NOTIFY - int i; - - INSIST(op != NULL); - - ns_debug(ns_log_config, 2, "adding global notify %s", - inet_ntoa(address)); - - /* Check for duplicates. */ - - for (i = 0; i < op->notify_count; i++) { - if (memcmp(op->also_notify + i, - &address, sizeof address) == 0) { - ns_warning(ns_log_config, - "duplicate global also-notify address ignored [%s]", - inet_ntoa(address)); - return (1); - } - } - i = 0; - - if (op->also_notify == NULL) { - op->also_notify = memget(sizeof *op->also_notify); - if (op->also_notify == NULL) - i = 1; - } else { - register size_t size; - register struct in_addr *an_tmp; - size = op->notify_count * sizeof *op->also_notify; - an_tmp = memget(size + sizeof *op->also_notify); - if (an_tmp == NULL) { - i = 1; - } else { - memcpy(an_tmp, op->also_notify, size); - memput(op->also_notify, size); - op->also_notify = an_tmp; - } - } - if (i == 0) { - op->also_notify[op->notify_count] = address; - op->notify_count++; - } else { - ns_warning(ns_log_config, - "global also-notify add failed (memget) [%s]", - inet_ntoa(address)); - } -#endif - return (1); -} - -void -add_global_forwarder(options op, struct in_addr address) { - - INSIST(op != NULL); - - ns_debug(ns_log_config, 2, "adding default forwarder %s", - inet_ntoa(address)); - - add_forwarder(&op->fwdtab, address); -} - -void -set_zone_forward(zone_config zh) { - struct zoneinfo *zp; - zp = zh.opaque; - - zp->z_flags |= Z_FORWARD_SET; - set_zone_boolean_option(zh, OPTION_FORWARD_ONLY, 0); -} - -void -add_zone_forwarder(zone_config zh, struct in_addr address) { - struct zoneinfo *zp; - const char *zname; - - zp = zh.opaque; - INSIST(zp != NULL); - - zname = (zp->z_origin[0] == '\0') ? "." : zp->z_origin; - ns_debug(ns_log_config, 2, "adding forwarder %s for zone zone '%s'", - inet_ntoa(address), zname); - - zp->z_flags |= Z_FORWARD_SET; - - add_forwarder(&zp->z_fwdtab, address); -} - -void -free_forwarders(struct fwdinfo *fwdtab) { - struct fwdinfo *ftp, *fnext; - int i; - - for (ftp = fwdtab; ftp != NULL; ftp = fnext) { - fnext = ftp->next; - if (--ftp->fwddata->ref_count == 0) { - for (i = 0 ; i < fwddata_count; i++) - if (fwddata[i] == ftp->fwddata) { - fwddata[i] = NULL; - break; - } - db_detach(&ftp->fwddata->ns); - db_detach(&ftp->fwddata->nsdata); - memput(ftp->fwddata, sizeof *ftp->fwddata); - } - memput(ftp, sizeof *ftp); - } - fwdtab = NULL; -} - -/* - * Servers - */ - -static server_info -new_server(struct in_addr address) { - server_info si; - - si = (server_info)memget(sizeof (struct server_info)); - if (si == NULL) - panic("memget failed in new_server()", NULL); - si->address = address; - si->flags = 0U; - si->transfers = 0; - si->transfer_format = axfr_use_default; - si->key_list = NULL; - si->next = NULL; - if (server_options->flags & OPTION_MAINTAIN_IXFR_BASE) - si->flags |= SERVER_INFO_SUPPORT_IXFR; - else - si->flags &= ~SERVER_INFO_SUPPORT_IXFR; - si->flags |= SERVER_INFO_EDNS; - return (si); -} - -static void -free_server(server_info si) { - if (si->key_list) - free_key_info_list(si->key_list); - memput(si, sizeof *si); -} - -server_info -find_server(struct in_addr address) { - server_info si; - - for (si = nameserver_info; si != NULL; si = si->next) - if (si->address.s_addr == address.s_addr) - break; - return (si); -} - -static void -add_server(server_info si) { - ip_match_element ime; - - si->next = nameserver_info; - nameserver_info = si; - - /* - * To ease transition, we'll add bogus nameservers to an - * ip matching list. This will probably be redone when the - * merging of nameserver data structures occurs. - */ - if (si->flags & SERVER_INFO_BOGUS) { - ime = new_ip_match_pattern(si->address, 32); - INSIST(ime != NULL); - add_to_ip_match_list(bogus_nameservers, ime); - } - ns_debug(ns_log_config, 3, "server %s: flags %08x transfers %d", - inet_ntoa(si->address), si->flags, si->transfers); - if (si->key_list != NULL) - dprint_key_info_list(si->key_list); -} - -static void -free_nameserver_info() { - server_info si_next, si; - - for (si = nameserver_info; si != NULL; si = si_next) { - si_next = si->next; - free_server(si); - } - nameserver_info = NULL; - if (bogus_nameservers != NULL) { - free_ip_match_list(bogus_nameservers); - bogus_nameservers = NULL; - } -} - -static void -free_secretkey_info() { - if (secretkey_info != NULL) { - free_key_info_list(secretkey_info); - secretkey_info = NULL; - } -} - -server_config -begin_server(struct in_addr address) { - server_config sc; - - sc.opaque = new_server(address); - return (sc); -} - -void -end_server(server_config sc, int should_install) { - server_info si; - - si = sc.opaque; - - INSIST(si != NULL); - - if (should_install) - add_server(si); - else - free_server(si); - sc.opaque = NULL; -} - -void -set_server_option(server_config sc, int bool_opt, int value) { - server_info si; - - si = sc.opaque; - - INSIST(si != NULL); - - switch (bool_opt) { - case SERVER_INFO_BOGUS: - case SERVER_INFO_SUPPORT_IXFR: - case SERVER_INFO_EDNS: - if (value) - si->flags |= bool_opt; - else - si->flags &= ~bool_opt; - break; - default: - panic("unexpected option in set_server_option", NULL); - } -} - -void -set_server_transfers(server_config sc, int transfers) { - server_info si; - - si = sc.opaque; - - INSIST(si != NULL); - - if (transfers < 0) - transfers = 0; - si->transfers = transfers; -} - -void -set_server_transfer_format(server_config sc, - enum axfr_format transfer_format) { - server_info si; - - si = sc.opaque; - - INSIST(si != NULL); - - si->transfer_format = transfer_format; -} - -void -add_server_key_info(server_config sc, DST_KEY *dst_key) { - server_info si; - - si = sc.opaque; - - INSIST(si != NULL); - - if (si->key_list == NULL) - si->key_list = new_key_info_list(); - add_to_key_info_list(si->key_list, dst_key); -} - -/* - * Keys - */ - -DST_KEY * -new_key_info(char *name, char *algorithm, char *secret) { - DST_KEY *dst_key; - int alg, blen; - u_char buffer[1024]; - - INSIST(name != NULL); - INSIST(algorithm != NULL); - INSIST(secret != NULL); - alg = tsig_alg_value(algorithm); - if (alg == -1) { - ns_warning(ns_log_config, "Unsupported TSIG algorithm %s", - algorithm); - return (NULL); - } - - blen = b64_pton(secret, buffer, sizeof(buffer)); - if (blen < 0) { - ns_warning(ns_log_config, "Invalid TSIG secret \"%s\"", secret); - return (NULL); - } - dst_key = dst_buffer_to_key(name, alg, - NS_KEY_TYPE_AUTH_ONLY|NS_KEY_NAME_ENTITY, - NS_KEY_PROT_ANY, buffer, blen); - if (dst_key == NULL) - ns_warning(ns_log_config, - "dst_buffer_to_key failed in new_key_info"); - return (dst_key); -} - -void -free_key_info(DST_KEY *dst_key) { - INSIST(dst_key != NULL); - dst_free_key(dst_key); -} - -DST_KEY * -find_key(char *name, char *algorithm) { - key_list_element ke; - - if (secretkey_info == NULL) - return (NULL); - - for (ke = secretkey_info->first; ke != NULL; ke = ke->next) { - DST_KEY *dst_key = ke->key; - - if (ns_samename(name, dst_key->dk_key_name) != 1) - continue; - if (algorithm == NULL || - dst_key->dk_alg == tsig_alg_value(algorithm)) - break; - } - if (ke == NULL) - return (NULL); - return (ke->key); -} - -void -dprint_key_info(DST_KEY *dst_key) { - INSIST(dst_key != NULL); - ns_debug(ns_log_config, 7, "key %s", dst_key->dk_key_name); - ns_debug(ns_log_config, 7, " algorithm %d", dst_key->dk_alg); -} - -key_info_list -new_key_info_list() { - key_info_list kil; - - kil = (key_info_list)memget(sizeof (struct key_info_list)); - if (kil == NULL) - panic("memget failed in new_key_info_list()", NULL); - kil->first = NULL; - kil->last = NULL; - return (kil); -} - -void -free_key_info_list(key_info_list kil) { - key_list_element kle, kle_next; - - INSIST(kil != NULL); - for (kle = kil->first; kle != NULL; kle = kle_next) { - kle_next = kle->next; - /* note we do NOT free kle->info */ - memput(kle, sizeof *kle); - } - memput(kil, sizeof *kil); -} - -void -add_to_key_info_list(key_info_list kil, DST_KEY *dst_key) { - key_list_element kle; - - INSIST(kil != NULL); - INSIST(dst_key != NULL); - - kle = (key_list_element)memget(sizeof (struct key_list_element)); - if (kle == NULL) - panic("memget failed in add_to_key_info_list()", NULL); - kle->key = dst_key; - if (kil->last != NULL) - kil->last->next = kle; - kle->next = NULL; - kil->last = kle; - if (kil->first == NULL) - kil->first = kle; -} - -void -dprint_key_info_list(key_info_list kil) { - key_list_element kle; - - INSIST(kil != NULL); - - for (kle = kil->first; kle != NULL; kle = kle->next) - dprint_key_info(kle->key); -} - -/* - * Logging. - */ - -log_config -begin_logging() { - log_config log_cfg; - log_context lc; - - log_cfg = (log_config)memget(sizeof (struct log_config)); - if (log_cfg == NULL) - ns_panic(ns_log_config, 0, - "memget failed creating log_config"); - if (log_new_context(ns_log_max_category, logging_categories, &lc) < 0) - ns_panic(ns_log_config, 0, - "log_new_context() failed: %s", strerror(errno)); - log_cfg->log_ctx = lc; - log_cfg->eventlib_channel = NULL; - log_cfg->packet_channel = NULL; - log_cfg->default_debug_active = 0; - return (log_cfg); -} - -void -add_log_channel(log_config log_cfg, int category, log_channel chan) { - log_channel_type type; - - INSIST(log_cfg != NULL); - - type = log_get_channel_type(chan); - if (category == ns_log_eventlib) { - if (type != log_file && type != log_null) { - ns_error(ns_log_config, - "must specify a file or null channel for the eventlib category"); - return; - } - if (log_cfg->eventlib_channel != NULL) { - ns_error(ns_log_config, - "only one channel allowed for the eventlib category"); - return; - } - log_cfg->eventlib_channel = chan; - } - if (category == ns_log_packet) { - if (type != log_file && type != log_null) { - ns_error(ns_log_config, - "must specify a file or null channel for the packet category"); - return; - } - if (log_cfg->packet_channel != NULL) { - ns_error(ns_log_config, - "only one channel allowed for the packet category"); - return; - } - log_cfg->packet_channel = chan; - } - - if (log_add_channel(log_cfg->log_ctx, category, chan) < 0) { - ns_error(ns_log_config, "log_add_channel() failed"); - return; - } - - if (chan == debug_channel) - log_cfg->default_debug_active = 1; -} - -void -open_special_channels() { - int using_null = 0; - - if (log_open_stream(eventlib_channel) == NULL) { - eventlib_channel = null_channel; - using_null = 1; - } - if (log_open_stream(packet_channel) == NULL) { - packet_channel = null_channel; - using_null = 1; - } - - if (using_null && - log_open_stream(null_channel) == NULL) - ns_panic(ns_log_config, 1, "couldn't open null channel"); -} - -void -set_logging(log_config log_cfg, int is_default) { - log_context lc; - - INSIST(log_cfg != NULL); - lc = log_cfg->log_ctx; - - /* - * Add the default category if it's not in the context already. - */ - if (!log_category_is_active(lc, ns_log_default)) { - add_log_channel(log_cfg, ns_log_default, debug_channel); - add_log_channel(log_cfg, ns_log_default, syslog_channel); - } - - /* - * Add the panic category if it's not in the context already. - */ - if (!log_category_is_active(lc, ns_log_panic)) { - add_log_channel(log_cfg, ns_log_panic, stderr_channel); - add_log_channel(log_cfg, ns_log_panic, syslog_channel); - } - - /* - * Add the eventlib category if it's not in the context already. - */ - if (!log_category_is_active(lc, ns_log_eventlib)) - add_log_channel(log_cfg, ns_log_eventlib, debug_channel); - - /* - * Add the packet category if it's not in the context already. - */ - if (!log_category_is_active(lc, ns_log_packet)) - add_log_channel(log_cfg, ns_log_packet, debug_channel); - -#ifdef DEBUG - /* - * Preserve debugging state. - */ - log_option(lc, LOG_OPTION_DEBUG, debug); - log_option(lc, LOG_OPTION_LEVEL, debug); -#endif - - /* - * Special case for query-log, so we can co-exist with the command - * line option and SIGWINCH. - */ - if (log_category_is_active(lc, ns_log_queries)) - qrylog = 1; - - /* - * Cleanup the old context. - */ - if (need_logging_free) - log_free_context(log_ctx); - - /* - * The default file channels will never have their reference counts - * drop to zero, and so they will not be closed by the logging system - * when log_free_context() is called. We don't want to keep files - * open unnecessarily, and we want them to behave like user-created - * channels, so we close them here. - */ - if (log_get_stream(debug_channel) != stderr) - (void)log_close_stream(debug_channel); - (void)log_close_stream(null_channel); - - /* - * Install the new context. - */ - log_ctx = lc; - eventlib_channel = log_cfg->eventlib_channel; - packet_channel = log_cfg->packet_channel; - -#ifdef DEBUG - if (debug) { - open_special_channels(); - evSetDebug(ev, debug, log_get_stream(eventlib_channel)); - } -#endif - - log_ctx_valid = 1; - need_logging_free = 1; - logging_installed = 1; - default_logging_installed = is_default; -} - -void -end_logging(log_config log_cfg, int should_install) { - if (should_install) - set_logging(log_cfg, 0); - else - log_free_context(log_cfg->log_ctx); - memput(log_cfg, sizeof (struct log_config)); -} - -void -use_default_logging() { - log_config log_cfg; - - log_cfg = begin_logging(); - set_logging(log_cfg, 1); - memput(log_cfg, sizeof (struct log_config)); -} - -static void -init_default_log_channels() { - u_int flags; - const char *name; - FILE *stream; - - syslog_channel = log_new_syslog_channel(0, log_info, ISC_FACILITY); - if (syslog_channel == NULL || log_inc_references(syslog_channel) < 0) - ns_panic(ns_log_config, 0, "couldn't create syslog_channel"); - - flags = LOG_USE_CONTEXT_LEVEL|LOG_REQUIRE_DEBUG; - if (foreground) { - name = NULL; - stream = stderr; - } else { - name = _PATH_DEBUG; - stream = NULL; - } - debug_channel = log_new_file_channel(flags, log_info, name, stream, - 0, ULONG_MAX); - if (debug_channel == NULL || log_inc_references(debug_channel) < 0) - ns_panic(ns_log_config, 0, "couldn't create debug_channel"); - log_set_file_owner(debug_channel, user_id, group_id); - - stderr_channel = log_new_file_channel(0, log_info, NULL, stderr, - 0, ULONG_MAX); - if (stderr_channel == NULL || log_inc_references(stderr_channel) < 0) - ns_panic(ns_log_config, 0, "couldn't create stderr_channel"); - log_set_file_owner(stderr_channel, user_id, group_id); - - null_channel = log_new_file_channel(LOG_CHANNEL_OFF, log_info, - _PATH_DEVNULL, NULL, 0, ULONG_MAX); - if (null_channel == NULL || log_inc_references(null_channel) < 0) - ns_panic(ns_log_config, 0, "couldn't create null_channel"); - log_set_file_owner(null_channel, user_id, group_id); -} - -static void -shutdown_default_log_channels() { - log_free_channel(syslog_channel); - log_free_channel(debug_channel); - log_free_channel(stderr_channel); - log_free_channel(null_channel); -} - -void -init_logging() { - int size; - const struct ns_sym *s; - char category_name[256]; - - size = ns_log_max_category * (sizeof (char *)); - - logging_categories = (char **)memget(size); - if (logging_categories == NULL) - ns_panic(ns_log_config, 0, "memget failed in init_logging"); - memset(logging_categories, 0, size); - for (s = category_constants; s != NULL && s->name != NULL; s++) { - sprintf(category_name, "%s: ", s->name); - logging_categories[s->number] = savestr(category_name, 1); - } - - init_default_log_channels(); - use_default_logging(); -} - -void -shutdown_logging() { - int size; - const struct ns_sym *s; - - evSetDebug(ev, 0, NULL); - shutdown_default_log_channels(); - log_free_context(log_ctx); - - for (s = category_constants; s != NULL && s->name != NULL; s++) - logging_categories[s->number] = - freestr(logging_categories[s->number]); - size = ns_log_max_category * (sizeof (char *)); - memput(logging_categories, size); - logging_categories = NULL; -} - -/* - * Main Loader - */ - -void -init_configuration() { - /* - * Remember initial limits for use if "default" is specified in - * a config file. - */ -#ifdef HAVE_GETRUSAGE - get_initial_limits(); -#endif - zone_symbol_table = new_symbol_table(ZONE_SYM_TABLE_SIZE, NULL); - use_default_options(); - parser_initialize(); - ns_ctl_initialize(); - config_initialized = 1; -} - -void -shutdown_configuration() { - REQUIRE(config_initialized); - - ns_ctl_shutdown(); - if (server_options != NULL) { - free_options(server_options); - server_options = NULL; - } - if (current_pid_filename != NULL) - current_pid_filename = freestr(current_pid_filename); - free_nameserver_info(); - free_secretkey_info(); - free_symbol_table(zone_symbol_table); - parser_shutdown(); - if (fwddata != NULL) - memput(fwddata, fwddata_count * sizeof *fwddata); - fwddata = NULL; - fwddata_count = 0; - config_initialized = 0; -} - -time_t -load_configuration(const char *filename) { - time_t mtime; - - REQUIRE(config_initialized); - - ns_debug(ns_log_config, 3, "load configuration %s", filename); - - loading = 1; - - /* - * Clean up any previous configuration and initialize - * global data structures we'll be updating. - */ - free_nameserver_info(); - free_secretkey_info(); - bogus_nameservers = new_ip_match_list(); - - options_installed = 0; - logging_installed = 0; - - mtime = parse_configuration(filename); - - /* - * If the user didn't specify logging or options, but they previously - * had specified one or both of them, then we need to - * re-establish the default environment. We have to be careful - * about when we install default options because the parser - * must respect limits (e.g. data-size, number of open files) - * specified in the options file. In the ordinary case where the - * options section isn't changing on a zone reload, it would be bad - * to lower these limits temporarily, because we might not survive - * to the point where they get raised back again. The logging case - * has similar motivation -- we don't want to override the existing - * logging scheme (perhaps causing log messages to go somewhere - * unexpected) when the user hasn't expressed a desire for a new - * scheme. - */ - if (!logging_installed) - use_default_logging(); - if (!options_installed && !default_options_installed) { - use_default_options(); - ns_warning(ns_log_config, "re-establishing default options"); - } - - update_pid_file(); - - /* Init or reinit the interface/port list and associated sockets. */ - getnetconf(0); - opensocket_f(); - - initial_configuration = 0; - loading = 0; - /* release queued notifies */ - notify_afterload(); - return (mtime); -} |