summaryrefslogtreecommitdiffstats
path: root/contrib/bind/named/ns_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind/named/ns_init.c')
-rw-r--r--contrib/bind/named/ns_init.c1110
1 files changed, 1110 insertions, 0 deletions
diff --git a/contrib/bind/named/ns_init.c b/contrib/bind/named/ns_init.c
new file mode 100644
index 0000000..3ca8180
--- /dev/null
+++ b/contrib/bind/named/ns_init.c
@@ -0,0 +1,1110 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_init.c 4.38 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: ns_init.c,v 8.17 1996/08/05 08:31:30 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1990
+ * -
+ * Copyright (c) 1986, 1990
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * 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 Digital Equipment Corporation 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 DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION 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.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <syslog.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "named.h"
+
+#undef nsaddr
+
+enum limit { Datasize };
+
+static void zoneinit __P((struct zoneinfo *)),
+ get_forwarders __P((FILE *)),
+ boot_read __P((const char *filename, int includefile)),
+#ifdef DEBUG
+ content_zone __P((int)),
+#endif
+ free_forwarders __P((void)),
+ ns_limit __P((const char *name, int value)),
+ ns_checknames __P((const char *names,
+ const char *severity)),
+ ns_rlimit __P((const char *name, enum limit limit,
+ long value)),
+ ns_option __P((const char *name));
+
+static struct zoneinfo *find_zone __P((char *, int, int));
+
+static enum severity checkname_severity[num_trans];
+
+/*
+ * Set new refresh time for zone. Use a random number in the last half of
+ * the refresh limit; we want it to be substantially correct while still
+ * preventing slave synchronization.
+ */
+void
+ns_refreshtime(zp, timebase)
+ struct zoneinfo *zp;
+ time_t timebase;
+{
+ u_long refresh = (zp->z_refresh > 0) ? zp->z_refresh : INIT_REFRESH;
+ time_t half = (refresh + 1) / 2;
+
+ zp->z_time = timebase + half + (rand() % half);
+}
+
+/*
+ * Set new retry time for zone.
+ */
+void
+ns_retrytime(zp, timebase)
+ struct zoneinfo *zp;
+ time_t timebase;
+{
+ zp->z_time = timebase + zp->z_retry;
+}
+
+/*
+ * Read boot file for configuration info.
+ */
+void
+ns_init(bootfile)
+ char *bootfile;
+{
+ register struct zoneinfo *zp;
+ static int loads = 0; /* number of times loaded */
+
+ dprintf(1, (ddt, "\nns_init(%s)\n", bootfile));
+ gettime(&tt);
+
+ memset(checkname_severity, '\0', sizeof checkname_severity);
+ checkname_severity[primary_trans] = fail;
+ checkname_severity[secondary_trans] = warn;
+ checkname_severity[response_trans] = ignore;
+
+ if (loads == 0) {
+ if ((zones =
+ (struct zoneinfo *)calloc(64, sizeof(struct zoneinfo)))
+ == NULL) {
+ syslog(LOG_ERR,
+ "Not enough memory to allocate initial zones array");
+ exit(1);
+ }
+ nzones = 1; /* zone zero is cache data */
+ /* allocate cache hash table, formerly the root hash table. */
+ hashtab = savehash((struct hashbuf *)NULL);
+
+ /* allocate root-hints/file-cache hash table */
+ fcachetab = savehash((struct hashbuf *)NULL);
+ /* init zone data */
+ zones[0].z_type = Z_CACHE;
+ zones[0].z_origin = "";
+ } else {
+ /* Mark previous zones as not yet found in boot file. */
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++)
+ zp->z_flags &= ~Z_FOUND;
+#ifdef LOCALDOM
+ if (localdomain) {
+ free(localdomain);
+ localdomain = NULL;
+ }
+#endif
+ free_forwarders();
+ free_netlist(enettab);
+#ifdef XFRNETS
+ free_netlist(&xfrnets);
+#endif
+#ifdef BOGUSNS
+ free_netlist(&boglist);
+#endif
+ forward_only = 0;
+ }
+
+ dprintf(3, (ddt, "\n content of zones before loading \n"));
+#ifdef DEBUG
+ if (debug >= 3) {
+ content_zone(nzones - 1);
+ }
+#endif
+ boot_read(bootfile, 0);
+
+ /* erase all old zones that were not found */
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++) {
+ if (zp->z_type && (zp->z_flags & Z_FOUND) == 0) {
+#ifdef CLEANCACHE
+ remove_zone(hashtab, zp - zones, 1);
+#else
+ remove_zone(hashtab, zp - zones);
+#endif
+#ifdef SECURE_ZONES
+ free_netlist(&zp->secure_nets);
+#endif
+ syslog(LOG_NOTICE, "Zone \"%s\" was removed", zp->z_origin);
+ free(zp->z_origin);
+ free(zp->z_source);
+ bzero((char *) zp, sizeof(*zp));
+ }
+ }
+ dprintf(2, (ddt,"\n content of zones after loading\n"));
+
+#ifdef DEBUG
+ if (debug >= 2) {
+ content_zone(nzones-1);
+ }
+#endif
+
+ /*
+ * Schedule calls to ns_maint().
+ */
+ if (!needmaint)
+ sched_maint();
+ dprintf(1, (ddt, "exit ns_init()%s\n",
+ needmaint ? ", need maintenance immediately" : ""));
+ loads++;
+}
+
+/*
+ * Read the actual boot file.
+ * Set up to recurse.
+ */
+static void
+boot_read(filename, includefile)
+ const char *filename;
+ int includefile;
+{
+ register struct zoneinfo *zp;
+ char buf[BUFSIZ], obuf[BUFSIZ], *source;
+ FILE *fp;
+ int type;
+ int class;
+#ifdef GEN_AXFR
+ char *class_p;
+#endif
+ struct stat f_time;
+ static int tmpnum = 0; /* unique number for tmp zone files */
+#ifdef ALLOW_UPDATES
+ char *flag;
+#endif
+ int slineno; /* Saved global line number. */
+ int i;
+
+ if ((fp = fopen(filename, "r")) == NULL) {
+ syslog(LOG_ERR, "%s: %m", filename);
+ if (includefile)
+ return;
+ exit(1);
+ }
+
+ slineno = lineno;
+ lineno = 1;
+
+ while (!feof(fp) && !ferror(fp)) {
+ /* read named.boot keyword and process args */
+ if (!getword(buf, sizeof(buf), fp, 0)) {
+ /*
+ * This is a blank line, a commented line, or the
+ * '\n' of the previous line.
+ */
+ continue;
+ }
+ if (strcasecmp(buf, "directory") == 0) {
+ (void) getword(buf, sizeof(buf), fp, 0);
+ if (chdir(buf) < 0) {
+ syslog(LOG_CRIT, "directory %s: %m\n",
+ buf);
+ exit(1);
+ }
+ continue;
+ } else if (strcasecmp(buf, "sortlist") == 0) {
+ get_netlist(fp, enettab, ALLOW_NETS, buf);
+ continue;
+ } else if (strcasecmp(buf, "max-fetch") == 0) {
+ max_xfers_running = getnum(fp, filename, GETNUM_NONE);
+ continue;
+ } else if (strcasecmp(buf, "limit") == 0) {
+ (void) getword(buf, sizeof(buf), fp, 0);
+ ns_limit(buf, getnum(fp, filename, GETNUM_SCALED));
+ continue;
+ } else if (strcasecmp(buf, "options") == 0) {
+ while (getword(buf, sizeof(buf), fp, 0))
+ ns_option(buf);
+ continue;
+ } else if (strcasecmp(buf, "check-names") == 0) {
+ (void) getword(buf, sizeof(buf), fp, 0);
+ (void) getword(obuf, sizeof(obuf), fp, 0);
+ ns_checknames(buf, obuf);
+ continue;
+ } else if (strcasecmp(buf, "forwarders") == 0) {
+ get_forwarders(fp);
+ continue;
+ } else if (strcasecmp(buf, "slave") == 0) {
+ forward_only++;
+ continue;
+#ifdef BOGUSNS
+ } else if (strcasecmp(buf, "bogusns") == 0) {
+ get_netlist(fp, &boglist, ALLOW_HOSTS, buf);
+ continue;
+#endif
+#ifdef XFRNETS
+ } else if ((strcasecmp(buf, "tcplist") == 0) ||
+ (strcasecmp(buf, "xfrnets") == 0)) {
+ get_netlist(fp, &xfrnets, ALLOW_NETS, buf);
+ continue;
+#endif
+#ifdef LOCALDOM
+ } else if (strcasecmp(buf, "domain") == 0) {
+ if (getword(buf, sizeof(buf), fp, 1))
+ localdomain = savestr(buf);
+ continue;
+#endif
+ } else if (strcasecmp(buf, "include") == 0) {
+ if (getword(buf, sizeof(buf), fp, 0))
+ boot_read(buf, 1);
+ continue;
+ } else if (strncasecmp(buf, "cache", 5) == 0) {
+ type = Z_CACHE;
+ class = C_IN;
+#ifdef GEN_AXFR
+ if (class_p = strchr(buf, '/')) {
+ class = get_class(class_p+1);
+
+ if (class != C_IN) {
+ syslog(LOG_NOTICE,
+ "cache directive with non-IN class is not supported (yet)");
+ endline(fp);
+ continue;
+ }
+ }
+#endif
+ } else if (strncasecmp(buf, "primary", 7) == 0) {
+ type = Z_PRIMARY;
+ class = C_IN;
+#ifdef GEN_AXFR
+ if (class_p = strchr(buf, '/'))
+ class = get_class(class_p+1);
+#endif
+ } else if (strncasecmp(buf, "secondary", 9) == 0) {
+ type = Z_SECONDARY;
+ class = C_IN;
+#ifdef GEN_AXFR
+ if (class_p = strchr(buf, '/'))
+ class = get_class(class_p+1);
+#endif
+#ifdef STUBS
+ } else if (strncasecmp(buf, "stub", 4) == 0) {
+ type = Z_STUB;
+ class = C_IN;
+#ifdef GEN_AXFR
+ if (class_p = strchr(buf, '/'))
+ class = get_class(class_p+1);
+#endif
+#endif
+ } else {
+ syslog(LOG_NOTICE,
+ "%s: line %d: unknown directive '%s'\n",
+ filename, lineno, buf);
+ endline(fp);
+ continue;
+ }
+
+ /*
+ * read zone origin
+ */
+ if (!getword(obuf, sizeof(obuf), fp, 1)) {
+ syslog(LOG_NOTICE, "%s: line %d: missing origin\n",
+ filename, lineno);
+ continue;
+ }
+ i = strlen(obuf);
+ if ((obuf[i-1] == '.') && (i != 1))
+ syslog(LOG_INFO,
+ "%s: line %d: zone \"%s\" has trailing dot\n",
+ filename, lineno, obuf);
+ while ((--i >= 0) && (obuf[i] == '.'))
+ obuf[i] = '\0';
+ dprintf(1, (ddt, "zone origin %s", obuf[0]?obuf:"."));
+ /*
+ * Read source file or host address.
+ */
+ if (!getword(buf, sizeof(buf), fp, 0)) {
+ syslog(LOG_NOTICE, "%s: line %d: missing %s\n",
+ filename, lineno,
+#ifdef STUBS
+ (type == Z_SECONDARY || type == Z_STUB)
+#else
+ (type == Z_SECONDARY)
+#endif
+ ?"host address"
+ :"source file");
+ continue;
+ }
+
+ /*
+ * Check for previous instance of this zone (reload).
+ */
+ if (!(zp = find_zone(obuf, type, class))) {
+ if (type == Z_CACHE) {
+ zp = &zones[0];
+ goto gotcache;
+ }
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++)
+ if (zp->z_type == Z_NIL)
+ goto gotzone;
+ /*
+ * This code assumes that nzones never decreases.
+ */
+ if (nzones % 64 == 0) {
+ dprintf(1, (ddt,
+ "Reallocating zones structure\n"));
+ /*
+ * Realloc() not used since it might damage zones
+ * if an error occurs.
+ */
+ zp = (struct zoneinfo *)
+ malloc((64 + nzones)
+ * sizeof(struct zoneinfo));
+ if (!zp) {
+ syslog(LOG_NOTICE,
+ "no memory for more zones");
+ endline(fp);
+ continue;
+ }
+ bcopy((char *)zones, (char *)zp,
+ nzones * sizeof(struct zoneinfo));
+ bzero((char *)&zp[nzones],
+ 64 * sizeof(struct zoneinfo));
+ free(zones);
+ zones = zp;
+ }
+ zp = &zones[nzones++];
+ gotzone:
+ zp->z_origin = savestr(obuf);
+ gotcache:
+ zp->z_type = type;
+ zp->z_class = class;
+ }
+ zp->z_addrcnt = 0;
+
+ switch (type) {
+ case Z_CACHE:
+ source = savestr(buf);
+ dprintf(1, (ddt, ", source = %s\n", source));
+ zp->z_refresh = 0; /* by default, no dumping */
+ if (getword(buf, sizeof(buf), fp, 0)) {
+#ifdef notyet
+ zp->z_refresh = atoi(buf);
+ if (zp->z_refresh <= 0) {
+ syslog(LOG_NOTICE,
+ "%s: line %d: bad refresh time '%s', ignored\n",
+ filename, lineno, buf);
+ zp->z_refresh = 0;
+ } else if (cache_file == NULL)
+ cache_file = source;
+#else
+ syslog(LOG_NOTICE,
+ "%s: line %d: cache refresh ignored\n",
+ filename, lineno);
+#endif
+ endline(fp);
+ }
+ /*
+ * If we've loaded this file, and the file has
+ * not been modified and contains no $include,
+ * then there's no need to reload.
+ */
+ if (zp->z_source &&
+ !strcmp(source, zp->z_source) &&
+ !(zp->z_flags & Z_INCLUDE) &&
+ stat(zp->z_source, &f_time) != -1 &&
+ zp->z_ftime == f_time.st_mtime) {
+ dprintf(1, (ddt, "cache is up to date\n"));
+ if (source != cache_file)
+ free(source);
+ break; /* zone is already up to date */
+ }
+
+ /* file has changed, or hasn't been loaded yet */
+ if (zp->z_source) {
+ free(zp->z_source);
+#ifdef CLEANCACHE
+ remove_zone(fcachetab, 0, 1);
+#else
+ remove_zone(fcachetab, 0);
+#endif
+ }
+ zp->z_source = source;
+ dprintf(1, (ddt, "reloading zone\n"));
+ (void) db_load(zp->z_source, zp->z_origin, zp, NULL);
+ break;
+
+ case Z_PRIMARY:
+ source = savestr(buf);
+#ifdef ALLOW_UPDATES
+ if (getword(buf, sizeof(buf), fp, 0)) {
+ endline(fp);
+ flag = buf;
+ while (flag) {
+ char *cp = strchr(flag, ',');
+ if (cp)
+ *cp++ = 0;
+ if (strcasecmp(flag, "dynamic") == 0)
+ zp->z_flags |= Z_DYNAMIC;
+ else if (strcasecmp(flag, "addonly") == 0)
+ zp->z_flags |= Z_DYNADDONLY;
+ else {
+ syslog(LOG_NOTICE,
+ "%s: line %d: bad flag '%s'\n",
+ filename, lineno, flag);
+ }
+ flag = cp;
+ }
+ }
+#else /*ALLOW_UPDATES*/
+ endline(fp);
+#endif
+
+ dprintf(1, (ddt, ", source = %s\n", source));
+ /*
+ * If we've loaded this file, and the file has
+ * not been modified and contains no $include,
+ * then there's no need to reload.
+ */
+ if (zp->z_source &&
+ !strcmp(source, zp->z_source) &&
+ !(zp->z_flags & Z_INCLUDE) &&
+ stat(zp->z_source, &f_time) != -1 &&
+ zp->z_ftime == f_time.st_mtime) {
+ dprintf(1, (ddt, "zone is up to date\n"));
+ free(source);
+ break; /* zone is already up to date */
+ }
+ if (zp->z_source) {
+ free(zp->z_source);
+#ifdef CLEANCACHE
+ remove_zone(hashtab, zp - zones, 1);
+#else
+ remove_zone(hashtab, zp - zones);
+#endif
+ }
+ zp->z_source = source;
+ zp->z_flags &= ~Z_AUTH;
+#ifdef PURGE_ZONE
+ purge_zone(zp->z_origin, hashtab, zp->z_class);
+#endif
+ dprintf(1, (ddt, "reloading zone\n"));
+ if (!db_load(zp->z_source, zp->z_origin, zp, NULL))
+ zp->z_flags |= Z_AUTH;
+#ifdef ALLOW_UPDATES
+ /* Guarantee calls to ns_maint() */
+ zp->z_refresh = maint_interval;
+#else
+ zp->z_refresh = 0; /* no maintenance needed */
+ zp->z_time = 0;
+#endif
+ break;
+
+ case Z_SECONDARY:
+#ifdef STUBS
+ case Z_STUB:
+#endif
+ source = NULL;
+ dprintf(1, (ddt, "\n\taddrs: "));
+ do {
+ if (!inet_aton(buf,
+ &zp->z_addr[zp->z_addrcnt])
+ ) {
+ source = savestr(buf);
+ endline(fp);
+ break;
+ }
+ dprintf(1, (ddt, "%s, ", buf));
+ if ((int)++zp->z_addrcnt > NSMAX - 1) {
+ zp->z_addrcnt = NSMAX - 1;
+ dprintf(1, (ddt,
+ "\nns.h NSMAX reached\n"));
+ }
+ } while (getword(buf, sizeof(buf), fp, 0));
+ dprintf(1, (ddt, "addrcnt = %d\n", zp->z_addrcnt));
+ if (!source) {
+ /*
+ * We will always transfer this zone again
+ * after a reload.
+ */
+ sprintf(buf, "%s/NsTmp%ld.%d", _PATH_TMPDIR,
+ (long)getpid(), tmpnum++);
+ source = savestr(buf);
+ 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 &&
+ (strcmp(source, zp->z_source) ||
+ (stat(zp->z_source, &f_time) == -1 ||
+ (zp->z_ftime != f_time.st_mtime)))) {
+ dprintf(1, (ddt, "backup file changed\n"));
+ free(zp->z_source);
+ zp->z_source = NULL;
+ zp->z_flags &= ~Z_AUTH;
+ zp->z_serial = 0; /* force xfer */
+#ifdef CLEANCACHE
+ remove_zone(hashtab, zp - zones, 1);
+#else
+ remove_zone(hashtab, zp - zones);
+#endif
+ }
+ if (zp->z_source)
+ free(source);
+ else
+ zp->z_source = source;
+ if (!(zp->z_flags & Z_AUTH))
+ zoneinit(zp);
+#ifdef FORCED_RELOAD
+ else {
+ /*
+ ** Force secondary to try transfer right away
+ ** after SIGHUP.
+ */
+ if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))
+ && reloading) {
+ zp->z_time = tt.tv_sec;
+ needmaint = 1;
+ }
+ }
+#endif /* FORCED_RELOAD */
+ break;
+
+ }
+ if ((zp->z_flags & Z_FOUND) && /* already found? */
+ (zp - zones) != DB_Z_CACHE) /* cache never sets Z_FOUND */
+ syslog(LOG_NOTICE,
+ "Zone \"%s\" declared more than once",
+ zp->z_origin);
+ zp->z_flags |= Z_FOUND;
+ dprintf(1, (ddt, "zone[%d] type %d: '%s'",
+ zp-zones, type,
+ *(zp->z_origin) == '\0' ? "." : zp->z_origin));
+ if (zp->z_refresh && zp->z_time == 0)
+ ns_refreshtime(zp, tt.tv_sec);
+ if (zp->z_time <= tt.tv_sec)
+ needmaint = 1;
+ dprintf(1, (ddt, " z_time %lu, z_refresh %lu\n",
+ (u_long)zp->z_time, (u_long)zp->z_refresh));
+ }
+ (void) my_fclose(fp);
+ lineno = slineno;
+}
+
+static void
+zoneinit(zp)
+ register struct zoneinfo *zp;
+{
+ struct stat sb;
+ int result;
+
+ /*
+ * Try to load zone from backup file,
+ * if one was specified and it exists.
+ * If not, or if the data are out of date,
+ * we will refresh the zone from a primary
+ * immediately.
+ */
+ if (!zp->z_source)
+ return;
+ result = stat(zp->z_source, &sb);
+#ifdef PURGE_ZONE
+ if (result != -1)
+ purge_zone(zp->z_origin, hashtab, zp->z_class);
+#endif
+ if (result == -1 || db_load(zp->z_source, zp->z_origin, zp, NULL)) {
+ /*
+ * Set zone to be refreshed immediately.
+ */
+ zp->z_refresh = INIT_REFRESH;
+ zp->z_retry = INIT_REFRESH;
+ if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))) {
+ zp->z_time = tt.tv_sec;
+ needmaint = 1;
+ }
+ } else {
+ zp->z_flags |= Z_AUTH;
+ }
+}
+
+#ifdef ALLOW_UPDATES
+/*
+ * Look for the authoritative zone with the longest matching RHS of dname
+ * and return its zone # or zero if not found.
+ */
+int
+findzone(dname, class)
+ char *dname;
+ int class;
+{
+ char *dZoneName, *zoneName;
+ int dZoneNameLen, zoneNameLen;
+ int maxMatchLen = 0;
+ int maxMatchZoneNum = 0;
+ int zoneNum;
+
+ dprintf(4, (ddt, "findzone(dname=%s, class=%d)\n", dname, class));
+#ifdef DEBUG
+ if (debug >= 5) {
+ fprintf(ddt, "zone dump:\n");
+ for (zoneNum = 1; zoneNum < nzones; zoneNum++)
+ printzoneinfo(zoneNum);
+ }
+#endif
+
+ dZoneName = strchr(dname, '.');
+ if (dZoneName == NULL)
+ dZoneName = ""; /* root */
+ else
+ dZoneName++; /* There is a '.' in dname, so use remainder of
+ string as the zone name */
+ dZoneNameLen = strlen(dZoneName);
+ for (zoneNum = 1; zoneNum < nzones; zoneNum++) {
+ if (zones[zoneNum].z_type == Z_NIL)
+ continue;
+ zoneName = (zones[zoneNum]).z_origin;
+ zoneNameLen = strlen(zoneName);
+ /* The zone name may or may not end with a '.' */
+ if (zoneName[zoneNameLen - 1] == '.')
+ zoneNameLen--;
+ if (dZoneNameLen != zoneNameLen)
+ continue;
+ dprintf(5, (ddt, "about to strncasecmp('%s', '%s', %d)\n",
+ dZoneName, zoneName, dZoneNameLen));
+ if (strncasecmp(dZoneName, zoneName, dZoneNameLen) == 0) {
+ dprintf(5, (ddt, "match\n"));
+ /*
+ * See if this is as long a match as any so far.
+ * Check if "<=" instead of just "<" so that if
+ * root domain (whose name length is 0) matches,
+ * we use it's zone number instead of just 0
+ */
+ if (maxMatchLen <= zoneNameLen) {
+ maxMatchZoneNum = zoneNum;
+ maxMatchLen = zoneNameLen;
+ }
+ } else {
+ dprintf(5, (ddt, "no match\n"));
+ }
+ }
+ dprintf(4, (ddt, "findzone: returning %d\n", maxMatchZoneNum));
+ return (maxMatchZoneNum);
+}
+#endif /* ALLOW_UPDATES */
+
+static void
+get_forwarders(fp)
+ FILE *fp;
+{
+ char buf[BUFSIZ];
+ register struct fwdinfo *fip = NULL, *ftp = NULL;
+
+#ifdef SLAVE_FORWARD
+ int forward_count = 0;
+#endif
+
+ dprintf(1, (ddt, "forwarders "));
+
+ /* On multiple forwarder lines, move to end of the list. */
+#ifdef SLAVE_FORWARD
+ if (fwdtab != NULL){
+ forward_count++;
+ for (fip = fwdtab; fip->next != NULL; fip = fip->next)
+ forward_count++;
+ }
+#else
+ if (fwdtab != NULL) {
+ for (fip = fwdtab; fip->next != NULL; fip = fip->next) {
+ ;
+ }
+ }
+#endif /* SLAVE_FORWARD */
+
+ while (getword(buf, sizeof(buf), fp, 0)) {
+ if (strlen(buf) == 0)
+ break;
+ dprintf(1, (ddt," %s",buf));
+ if (!ftp) {
+ ftp = (struct fwdinfo *)malloc(sizeof(struct fwdinfo));
+ if (!ftp)
+ panic(errno, "malloc(fwdinfo)");
+ }
+ if (inet_aton(buf, &ftp->fwdaddr.sin_addr)) {
+ ftp->fwdaddr.sin_port = ns_port;
+ ftp->fwdaddr.sin_family = AF_INET;
+ } else {
+ syslog(LOG_NOTICE, "'%s' (ignored, NOT dotted quad)",
+ buf);
+ continue;
+ }
+#ifdef FWD_LOOP
+ if (aIsUs(ftp->fwdaddr.sin_addr)) {
+ syslog(LOG_NOTICE,
+ "Forwarder '%s' ignored, my address",
+ buf);
+ dprintf(1, (ddt, " (ignored, my address)"));
+ continue;
+ }
+#endif /* FWD_LOOP */
+ ftp->next = NULL;
+ if (fwdtab == NULL)
+ fwdtab = ftp; /* First time only */
+ else
+ fip->next = ftp;
+ fip = ftp;
+ ftp = NULL;
+#ifdef SLAVE_FORWARD
+ forward_count++;
+#endif /* SLAVE_FORWARD */
+ }
+ if (ftp)
+ free((char *)ftp);
+
+#ifdef SLAVE_FORWARD
+ /*
+ ** Set the slave retry time to 60 seconds total divided
+ ** between each forwarder
+ */
+ if (forward_count != 0) {
+ slave_retry = (int) (60 / forward_count);
+ if(slave_retry <= 0)
+ slave_retry = 1;
+ }
+#endif
+
+ dprintf(1, (ddt, "\n"));
+#ifdef DEBUG
+ if (debug > 2) {
+ for (ftp = fwdtab; ftp != NULL; ftp = ftp->next) {
+ fprintf(ddt, "ftp x%lx [%s] next x%lx\n",
+ (u_long)ftp,
+ inet_ntoa(ftp->fwdaddr.sin_addr),
+ (u_long)ftp->next);
+ }
+ }
+#endif
+}
+
+static void
+free_forwarders()
+{
+ register struct fwdinfo *ftp, *fnext;
+
+ for (ftp = fwdtab; ftp != NULL; ftp = fnext) {
+ fnext = ftp->next;
+ free((char *)ftp);
+ }
+ fwdtab = NULL;
+}
+
+static struct zoneinfo *
+find_zone(name, type, class)
+ char *name;
+ int type, class;
+{
+ register struct zoneinfo *zp;
+
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++) {
+ if (zp->z_type == type && zp->z_class == class &&
+ strcasecmp(name, zp->z_origin) == 0) {
+ dprintf(2, (ddt, ", old zone (%d)", zp - zones));
+ return (zp);
+ }
+ }
+ dprintf(2, (ddt, ", new zone"));
+ return NULL;
+}
+
+#ifdef DEBUG
+/* prints out the content of zones */
+static void
+content_zone(end)
+ int end;
+{
+ int i;
+
+ for (i = 1; i <= end; i++) {
+ printzoneinfo(i);
+ }
+}
+#endif
+
+static void
+ns_limit(name, value)
+ const char *name;
+ int value;
+{
+ if (!strcasecmp(name, "transfers-in")) {
+ max_xfers_running = value;
+ } else if (!strcasecmp(name, "transfers-per-ns")) {
+ max_xfers_per_ns = value;
+ } else if (!strcasecmp(name, "datasize")) {
+ ns_rlimit("datasize", Datasize, value);
+ } else {
+ syslog(LOG_ERR,
+ "error: unrecognized limit in bootfile: \"%s\"",
+ name);
+ exit(1);
+ }
+}
+
+static int
+select_string(strings, string)
+ const char *strings[];
+ const char *string;
+{
+ int i;
+
+ for (i = 0; strings[i] != NULL; i++)
+ if (!strcasecmp(strings[i], string))
+ return (i);
+ return (-1);
+}
+
+static void
+ns_checknames(transport_str, severity_str)
+ const char *transport_str;
+ const char *severity_str;
+{
+ enum transport transport;
+ enum severity severity;
+ int i;
+
+ if ((i = select_string(transport_strings, transport_str)) == -1) {
+ syslog(LOG_ERR,
+ "error: unrecognized transport type in bootfile: \"%s\"",
+ transport_str);
+ exit(1);
+ }
+ transport = (enum transport) i;
+
+ if ((i = select_string(severity_strings, severity_str)) == -1) {
+ syslog(LOG_ERR,
+ "error: unrecognized severity type in bootfile: \"%s\"",
+ severity_str);
+ exit(1);
+ }
+ severity = (enum severity) i;
+
+ checkname_severity[transport] = severity;
+ syslog(LOG_INFO, "check-names %s %s", transport_str, severity_str);
+}
+
+enum context
+ns_ptrcontext(owner)
+ const char *owner;
+{
+ if (samedomain(owner, "in-addr.arpa") || samedomain(owner, "ip6.int"))
+ return (hostname_ctx);
+ return (domain_ctx);
+}
+
+enum context
+ns_ownercontext(type, transport)
+ int type;
+ enum transport transport;
+{
+ enum context context;
+
+ switch (type) {
+ case T_A:
+ case T_WKS:
+ case T_MX:
+ switch (transport) {
+ case primary_trans:
+ case secondary_trans:
+ context = owner_ctx;
+ break;
+ case response_trans:
+ context = hostname_ctx;
+ break;
+ default:
+ abort();
+ }
+ break;
+ case T_MB:
+ case T_MG:
+ context = mailname_ctx;
+ default:
+ context = domain_ctx;
+ break;
+ }
+ return (context);
+}
+
+int
+ns_nameok(name, class, transport, context)
+ const char *name;
+ int class;
+ enum transport transport;
+ enum context context;
+{
+ int ok = 1;
+ enum severity severity = checkname_severity[transport];
+
+ if (severity == ignore)
+ return (1);
+ switch (context) {
+ case domain_ctx:
+ ok = (class != C_IN) || res_dnok(name);
+ break;
+ case owner_ctx:
+ ok = (class != C_IN) || res_ownok(name);
+ break;
+ case mailname_ctx:
+ ok = res_mailok(name);
+ break;
+ case hostname_ctx:
+ ok = res_hnok(name);
+ break;
+ default:
+ abort();
+ }
+ if (!ok) {
+ syslog((transport == response_trans) ? LOG_INFO : LOG_NOTICE,
+ "%s name \"%s %s\" (%s) is invalid - %s",
+ context_strings[context],
+ name, p_class(class),
+ transport_strings[transport],
+ (severity == fail) ? "rejecting" : "proceeding anyway");
+ if (severity == warn)
+ ok = 1;
+ }
+ return (ok);
+}
+
+int
+ns_wildcard(name)
+ const char *name;
+{
+ if (*name != '*')
+ return (0);
+ return (*++name == '\0');
+}
+
+static void
+ns_rlimit(name, limit, value)
+ const char *name;
+ enum limit limit;
+ long value;
+{
+#ifndef HAVE_GETRUSAGE
+# ifdef LINT
+ name; limit; value;
+# endif
+ syslog(LOG_WARNING, "warning: unimplemented limit in bootfile: \"%s\"",
+ name);
+#else
+ struct rlimit limits;
+ int rlimit;
+
+ switch (limit) {
+ case Datasize:
+ rlimit = RLIMIT_DATA;
+ break;
+ default:
+ abort();
+ }
+ if (getrlimit(rlimit, &limits) < 0) {
+ syslog(LOG_WARNING, "getrlimit(%s): %m", name);
+ return;
+ }
+ limits.rlim_cur = limits.rlim_max = value;
+ if (setrlimit(rlimit, &limits) < 0) {
+ syslog(LOG_WARNING, "setrlimit(%s, %ld): %m", name, value);
+ return;
+ }
+#endif
+}
+
+static void
+ns_option(name)
+ const char *name;
+{
+ if (!strcasecmp(name, "no-recursion")) {
+ NoRecurse = 1;
+ } else if (!strcasecmp(name, "no-fetch-glue")) {
+ NoFetchGlue = 1;
+#ifdef QRYLOG
+ } else if (!strcasecmp(name, "query-log")) {
+ qrylog = 1;
+#endif
+ } else if (!strcasecmp(name, "forward-only")) {
+ forward_only = 1;
+#ifndef INVQ
+ } else if (!strcasecmp(name, "fake-iquery")) {
+ fake_iquery = 1;
+#endif
+ } else {
+ syslog(LOG_ERR,
+ "error: unrecognized option in bootfile: \"%s\"",
+ name);
+ exit(1);
+ }
+}
OpenPOWER on IntegriCloud