* Copyright (c) 1986 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
static char sccsid
[] = "@(#)ns_init.c 4.28 (Berkeley) 1/14/89";
#include <arpa/nameser.h>
struct zoneinfo zones
[MAXZONES
]; /* zone information */
int nzones
; /* number of zones in use */
int forward_only
= 0; /* run only as a slave */
char *localdomain
; /* "default" for non-dotted names */
int maint_interval
= 15*60; /* minimum ns_maint() interval */
* Read boot file for configuration info.
register struct zoneinfo
*zp
;
struct zoneinfo
*find_zone();
char buf
[BUFSIZ
], obuf
[BUFSIZ
], *origin
, *source
;
static int loads
= 0; /* number of times loaded */
fprintf(ddt
,"\nns_init(%s)\n", bootfile
);
if ((fp
= fopen(bootfile
, "r")) == NULL
) {
syslog(LOG_ERR
, "%s: %m", bootfile
);
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
);
zones
[0].z_type
= Z_CACHE
;
/* Mark previous zones as not yet found in boot file. */
for (zp
= &zones
[1]; zp
< &zones
[nzones
]; zp
++)
fprintf(ddt
,"\n content of zones before loading \n");
while (!feof(fp
) && !ferror(fp
)) {
if (!getword(buf
, sizeof(buf
), fp
))
/* read named.boot keyword and process args */
if (strcasecmp(buf
, "directory") == 0) {
(void) getword(buf
, sizeof(buf
), fp
);
syslog(LOG_CRIT
, "directory %s: %m\n",
} else if (strcasecmp(buf
, "sortlist") == 0) {
} else if (strcasecmp(buf
, "forwarders") == 0) {
} else if (strcasecmp(buf
, "slave") == 0) {
} else if (strcasecmp(buf
, "domain") == 0) {
if (getword(buf
, sizeof(buf
), fp
))
localdomain
= savestr(buf
);
} else if (strcasecmp(buf
, "cache") == 0)
else if (strcasecmp(buf
, "primary") == 0)
else if (strcasecmp(buf
, "secondary") == 0)
syslog(LOG_ERR
, "%s: line %d: unknown field '%s'\n",
if (!getword(obuf
, sizeof(obuf
), fp
)) {
syslog(LOG_ERR
, "%s: line %d: missing origin\n",
fprintf(ddt
, "zone origin %s", obuf
);
if (obuf
[0] == '.' && obuf
[1] == '\0')
* read source file or host address
if (!getword(buf
, sizeof(buf
), fp
)) {
"%s: line %d: missing source or addr\n",
/* check for previous instance of this zone (reload) */
if ((zp
= find_zone(obuf
, type
)) == 0) {
for (zp
= &zones
[1]; zp
< &zones
[nzones
]; zp
++)
if (nzones
>= MAXZONES
) {
"too many zones (MAXZONES=%d)\n",
zp
->z_origin
= savestr(obuf
);
zp
->z_refresh
= 0; /* by default, no dumping */
fprintf(ddt
,", source = %s\n", source
);
if (getword(buf
, sizeof(buf
), fp
)) {
zp
->z_refresh
= atoi(buf
);
if (zp
->z_refresh
<= 0) {
"%s: line %d: bad refresh time '%s', ignored\n",
} else if (cache_file
== NULL
)
"%s: line %d: cache refresh ignored\n",
* 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
) == 0 &&
(zp
->z_state
& Z_INCLUDE
) == 0 &&
stat(zp
->z_source
, &f_time
) == 0 &&
zp
->z_ftime
== f_time
.st_mtime
) {
fprintf(ddt
, "cache is up to date\n");
break; /* zone is already up to date */
/* file has changed, or hasn't been loaded yet */
remove_zone(fcachetab
, 0);
fprintf(ddt
, "reloading zone\n");
(void) db_load(zp
->z_source
, zp
->z_origin
, zp
);
fprintf(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
) == 0 &&
(zp
->z_state
& Z_INCLUDE
) == 0 &&
stat(zp
->z_source
, &f_time
) == 0 &&
zp
->z_ftime
== f_time
.st_mtime
) {
fprintf(ddt
, "zone is up to date\n");
break; /* zone is already up to date */
remove_zone(hashtab
, zp
- zones
);
fprintf(ddt
, "reloading zone\n");
if (db_load(zp
->z_source
, zp
->z_origin
, zp
) == 0)
/* Guarantee calls to ns_maint() */
zp
->z_refresh
= maint_interval
;
fprintf(ddt
,"\n\taddrs: ");
zp
->z_addr
[zp
->z_addrcnt
].s_addr
=
if (zp
->z_addr
[zp
->z_addrcnt
].s_addr
==
if (++zp
->z_addrcnt
> NSMAX
- 1) {
zp
->z_addrcnt
= NSMAX
- 1;
"\nns.h NSMAX reached\n");
} while (getword(buf
, sizeof(buf
), fp
));
fprintf(ddt
,"addrcnt = %d\n", zp
->z_addrcnt
);
* 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.
(source
== 0 || strcmp(source
, zp
->z_source
))) {
fprintf(ddt
,"backup file changed\n");
remove_zone(hashtab
, zp
- zones
);
fprintf(ddt
,"zone[%d] type %d: '%s'",
*(zp
->z_origin
) == '\0' ? "." : zp
->z_origin
);
if (zp
->z_refresh
&& zp
->z_time
== 0)
zp
->z_time
= zp
->z_refresh
+ tt
.tv_sec
;
fprintf(ddt
, " z_time %d, z_refresh %d\n",
zp
->z_time
, zp
->z_refresh
);
(next_refresh
== 0 || next_refresh
> zp
->z_time
))
next_refresh
= zp
->z_time
;
/* erase all old zones that were not found */
for (zp
= &zones
[1]; zp
< &zones
[nzones
]; zp
++)
if (zp
->z_type
&& (zp
->z_state
& Z_FOUND
) == 0) {
remove_zone(hashtab
, zp
- zones
);
bzero((char *) zp
, sizeof(*zp
));
fprintf(ddt
,"\n zone no %d was removed \n", zp
- zones
);
fprintf(ddt
,"\n content of zones after loading \n");
* Schedule calls to ns_maint().
bzero((char *)&ival
, sizeof(ival
));
if (next_refresh
<= tt
.tv_sec
)
ival
.it_value
.tv_sec
= next_refresh
- tt
.tv_sec
;
if (ival
.it_value
.tv_sec
< maint_interval
)
ival
.it_value
.tv_sec
= maint_interval
;
(void) setitimer(ITIMER_REAL
, &ival
, (struct itimerval
*)NULL
);
fprintf(ddt
,"exit ns_init() ");
if (needmaint
|| ival
.it_value
.tv_sec
)
fprintf(ddt
,"Next interrupt in %d sec\n",
fprintf(ddt
,"No maintenance scheduled\n");
register struct zoneinfo
*zp
;
* 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
if (zp
->z_source
== NULL
||
db_load(zp
->z_source
, zp
->z_origin
, zp
) != 0) {
* Set zone to be refreshed immediately.
zp
->z_refresh
= INIT_REFRESH
;
zp
->z_retry
= INIT_REFRESH
;
* Look for the authoritative zone with the longest matching RHS of dname
* and return its zone # or zero if not found.
char *dZoneName
, *zoneName
, *index(), *dotPos
;
int dZoneNameLen
, zoneNameLen
;
fprintf(ddt
, "findzone(dname=%s, class=%d)\n", dname
, class);
fprintf(ddt
, "zone dump:\n");
for (zoneNum
= 1; zoneNum
< nzones
; zoneNum
++)
dZoneName
= index(dname
, '.');
dZoneName
= ""; /* root */
dZoneName
++; /* There is a '.' in dname, so use remainder of
string as the zone name */
dZoneNameLen
= strlen(dZoneName
);
for (zoneNum
= 1; zoneNum
< nzones
; zoneNum
++) {
zoneName
= (zones
[zoneNum
]).z_origin
;
zoneNameLen
= strlen(zoneName
);
/* The zone name may or may not end with a '.' */
dotPos
= index(zoneName
, '.');
if (dZoneNameLen
!= zoneNameLen
)
fprintf(ddt
, "about to strncasecmp('%s', '%s', %d)\n",
dZoneName
, zoneName
, dZoneNameLen
);
if (strncasecmp(dZoneName
, zoneName
, dZoneNameLen
) == 0) {
* 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
;
fprintf(ddt
, "no match\n");
fprintf(ddt
, "findzone: returning %d\n", maxMatchZoneNum
);
return (maxMatchZoneNum
);
register struct zoneinfo
*zp
;
cp
+= 3 * sizeof(u_short
);
cp
+= dn_skipname(cp
, eom
);
cp
+= dn_skipname(cp
, eom
);
GETLONG(zp
->z_serial
, cp
);
GETLONG(zp
->z_refresh
, cp
);
zp
->z_time
= tt
.tv_sec
+ zp
->z_refresh
;
GETLONG(zp
->z_retry
, cp
);
GETLONG(zp
->z_expire
, cp
);
GETLONG(zp
->z_minimum
, cp
);
register struct fwdinfo
*fip
= NULL
, *ftp
= NULL
;
extern struct sockaddr_in nsaddr
;
extern struct fwdinfo
*fwdtab
;
fprintf(ddt
,"forwarders ");
while (getword(buf
, sizeof(buf
), fp
)) {
ftp
= (struct fwdinfo
*)malloc(sizeof(struct fwdinfo
));
(ftp
->fwdaddr
.sin_addr
.s_addr
= inet_addr(buf
)) !=
ftp
->fwdaddr
.sin_port
= nsaddr
.sin_port
;
ftp
->fwdaddr
.sin_family
= AF_INET
;
syslog(LOG_ERR
, "'%s' (ignored, NOT dotted quad)", buf
);
fprintf(ddt
," (ignored, NOT dotted quad)");
fwdtab
= ftp
; /* First time only */
for (ftp
= fwdtab
; ftp
!= NULL
; ftp
= ftp
->next
)
fprintf(ddt
,"ftp x%x %s next x%x\n", ftp
,
inet_ntoa(ftp
->fwdaddr
.sin_addr
), ftp
->next
);
register struct fwdinfo
*ftp
, *fnext
;
for (ftp
= fwdtab
; ftp
!= NULL
; ftp
= fnext
) {
register struct zoneinfo
*zp
;
for (zp
= &zones
[1]; zp
< &zones
[nzones
]; zp
++)
if (zp
->z_type
== type
&& strcasecmp(name
, zp
->z_origin
) == 0) {
fprintf(ddt
, ", old zone %d",
fprintf(ddt
, ", new zone", name
, type
);
return ((struct zoneinfo
*)NULL
);
/* prints out the content of zones */