d6da9453b6
This has most of the non-essential stuff removed (ie: what is not built) bmake glue to follow.
1111 lines
27 KiB
C
1111 lines
27 KiB
C
#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);
|
|
}
|
|
}
|