BSD 4_3_Tahoe release
[unix-history] / usr / src / etc / named / ns_init.c
CommitLineData
95f51977 1/*
ca67e7b4
C
2 * Copyright (c) 1986 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
95f51977
C
16 */
17
ca67e7b4
C
18#ifndef lint
19static char sccsid[] = "@(#)ns_init.c 4.24 (Berkeley) 6/18/88";
20#endif /* not lint */
21
95f51977
C
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <sys/time.h>
25#include <netinet/in.h>
26#include <stdio.h>
27#include <errno.h>
28#include <signal.h>
29#include <syslog.h>
30#include <ctype.h>
31#include <arpa/nameser.h>
32#include "ns.h"
33#include "db.h"
34
35struct zoneinfo zones[MAXZONES]; /* zone information */
36int nzones; /* number of zones in use */
ca67e7b4
C
37int forward_only = 0; /* run only as a slave */
38char *cache_file;
39char *localdomain; /* "default" for non-dotted names */
40int maint_interval = 300; /* minimum ns_maint() interval */
41
42extern int lineno;
95f51977
C
43
44/*
45 * Read boot file for configuration info.
46 */
ca67e7b4 47
95f51977
C
48ns_init(bootfile)
49 char *bootfile;
50{
51 register struct zoneinfo *zp;
52 char buf[BUFSIZ];
95f51977 53 FILE *fp;
ca67e7b4
C
54 int type;
55 time_t next_refresh = 0;
95f51977 56 struct itimerval ival;
ca67e7b4 57 extern int needmaint;
95f51977
C
58
59#ifdef DEBUG
60 if (debug >= 3)
61 fprintf(ddt,"ns_init(%s)\n", bootfile);
62#endif
ca67e7b4 63 gettime(&tt);
95f51977
C
64
65 if ((fp = fopen(bootfile, "r")) == NULL) {
66 syslog(LOG_ERR, "%s: %m", bootfile);
67 exit(1);
68 }
ca67e7b4 69 lineno = 0;
95f51977 70
ca67e7b4 71 /* allocate cache hash table, formerly the root hash table. */
95f51977
C
72 hashtab = savehash((struct hashbuf *)NULL);
73
ca67e7b4
C
74 /* allocate root-hints/file-cache hash table */
75 fcachetab = savehash((struct hashbuf *)NULL);
76
77 if (localdomain)
78 free(localdomain);
79 localdomain = NULL;
80
95f51977 81 /* init zone data */
ca67e7b4 82 cache_file = NULL;
95f51977 83 nzones = 1; /* zone zero is cache data */
ca67e7b4
C
84 zones[0].z_type = Z_CACHE;
85 while (!feof(fp) && !ferror(fp)) {
86 if (!getword(buf, sizeof(buf), fp))
87 continue;
88 /* read named.boot keyword and process args */
89 if (strcasecmp(buf, "cache") == 0) {
95f51977
C
90 type = Z_CACHE;
91 zp = zones;
ca67e7b4
C
92 }
93 else if (strcasecmp(buf, "primary") == 0)
94 type = Z_PRIMARY;
95 else if (strcasecmp(buf, "secondary") == 0)
96 type = Z_SECONDARY;
97 else if (strcasecmp(buf, "directory") == 0) {
98 (void) getword(buf, sizeof(buf), fp);
99 if (chdir(buf) < 0) {
100 syslog(LOG_CRIT, "directory %s: %m\n",
101 buf);
95f51977
C
102 exit(1);
103 }
ca67e7b4
C
104 continue;
105 }
106 else if (strcasecmp(buf, "sortlist") == 0) {
107 get_sort_list(fp);
108 continue;
109 }
110 else if (strcasecmp(buf, "forwarders") == 0) {
111 get_forwarders(fp);
112 continue;
113 }
114 else if (strcasecmp(buf, "slave") == 0) {
115 forward_only++;
116 endline(fp);
117 continue;
118 }
119 else if (strcasecmp(buf, "domain") == 0) {
120 if (getword(buf, sizeof(buf), fp))
121 localdomain = savestr(buf);
122 endline(fp);
123 continue;
124 } else {
125 syslog(LOG_ERR, "%s: line %d: unknown field '%s'\n",
126 bootfile, lineno, buf);
127 endline(fp);
128 continue;
129 }
130 if (nzones >= MAXZONES) {
131 syslog(LOG_ERR, "too many zones (MAXZONES=%d)\n",
132 MAXZONES);
133 endline(fp);
134 continue;
135 }
136 if (type != Z_CACHE)
95f51977 137 zp = &zones[nzones++];
ca67e7b4
C
138 if (zp->z_origin) {
139 free(zp->z_origin);
140 zp->z_origin = 0;
141 }
142 if (zp->z_source) {
143 free(zp->z_source);
144 zp->z_source = 0;
95f51977
C
145 }
146 zp->z_type = type;
147 zp->z_addrcnt = 0;
ca67e7b4 148 zp->z_auth = 0;
95f51977
C
149 /*
150 * read zone origin
151 */
ca67e7b4
C
152 if (!getword(buf, sizeof(buf), fp)) {
153 syslog(LOG_ERR, "%s: line %d: missing origin\n",
154 bootfile, lineno);
155 continue;
156 }
95f51977
C
157 if (buf[0] == '.')
158 buf[0] = '\0';
159 zp->z_origin = savestr(buf);
160 /*
161 * read source file or host address
162 */
ca67e7b4
C
163 if (!getword(buf, sizeof(buf), fp)) {
164 syslog(LOG_ERR, "%s: line %d: missing origin\n",
165 bootfile, lineno);
166 continue;
167 }
95f51977 168#ifdef DEBUG
ca67e7b4
C
169 if (debug)
170 fprintf(ddt,"zone[%d] type %d: '%s'",
171 zp-zones, zp->z_type,
172 *(zp->z_origin) == '\0' ? "." : zp->z_origin);
95f51977 173#endif
ca67e7b4
C
174 zp->z_time = 0;
175 zp->z_refresh = 0; /* by default, no dumping */
176 switch (type) {
177 case Z_CACHE:
178 zp->z_source = savestr(buf);
95f51977 179#ifdef DEBUG
ca67e7b4
C
180 if (debug)
181 fprintf(ddt,", source = %s\n", zp->z_source);
95f51977 182#endif
ca67e7b4
C
183 if (getword(buf, sizeof(buf), fp)) {
184#ifdef notyet
185 zp->z_refresh = atoi(buf);
186 if (zp->z_refresh <= 0) {
187 syslog(LOG_ERR,
188 "%s: line %d: bad refresh '%s', ignored\n",
189 bootfile, lineno, buf);
190 zp->z_refresh = 0;
191 } else if (cache_file == NULL)
192 cache_file = zp->z_source;
193#else
194 syslog(LOG_WARNING,
195 "%s: line %d: cache refresh ignored\n",
196 bootfile, lineno);
197#endif
198 endline(fp);
199 }
200 (void) db_load(zp->z_source, zp->z_origin, zp);
201 break;
202
95f51977 203 case Z_PRIMARY:
ca67e7b4 204 zp->z_source = savestr(buf);
95f51977
C
205#ifdef DEBUG
206 if (debug)
ca67e7b4 207 fprintf(ddt,", source = %s\n", zp->z_source);
95f51977 208#endif
ca67e7b4
C
209 if (db_load(zp->z_source, zp->z_origin, zp) == 0)
210 zp->z_auth = 1;
211#ifdef ALLOW_UPDATES
212 /* Guarantee calls to ns_maint() */
213 zp->z_refresh = maint_interval;
214#else
215 zp->z_refresh = 0;
216 zp->z_time = 0;
217#endif ALLOW_UPDATES
95f51977
C
218 break;
219
220 case Z_SECONDARY:
ca67e7b4
C
221#ifdef DEBUG
222 if (debug)
223 fprintf(ddt,"\n\taddrs: %s, ", buf);
224#endif
95f51977 225 zp->z_addr[zp->z_addrcnt].s_addr =
ca67e7b4
C
226 inet_addr(buf);
227 /* Indicate no cache for this zone yet */
228 zp->z_source = (char *) NULL;
95f51977 229 if (zp->z_addr[zp->z_addrcnt].s_addr != (unsigned)-1)
ca67e7b4 230 zp->z_addrcnt++;
95f51977 231 while (getword(buf, sizeof(buf), fp)) {
95f51977 232 zp->z_addr[zp->z_addrcnt].s_addr =
ca67e7b4 233 inet_addr(buf);
95f51977
C
234 if (zp->z_addr[zp->z_addrcnt].s_addr ==
235 (unsigned)-1) {
ca67e7b4
C
236 zp->z_source = savestr(buf);
237 break;
95f51977
C
238 }
239#ifdef DEBUG
240 if (debug)
ca67e7b4 241 fprintf(ddt,"%s, ",buf);
95f51977 242#endif
ca67e7b4
C
243 if (++zp->z_addrcnt >= NSMAX) {
244 zp->z_addrcnt = NSMAX;
95f51977
C
245#ifdef DEBUG
246 if (debug)
247 fprintf(ddt,
ca67e7b4 248 "\nns.h NSMAX reached\n");
95f51977
C
249#endif
250 break;
251 }
252 }
253#ifdef DEBUG
254 if (debug)
ca67e7b4 255 fprintf(ddt,"addrcnt = %d\n", zp->z_addrcnt);
95f51977
C
256#endif
257 zoneinit(zp);
95f51977
C
258 break;
259
ca67e7b4
C
260 }
261 if (zp->z_refresh && zp->z_time == 0)
262 zp->z_time = zp->z_refresh + tt.tv_sec;
95f51977 263#ifdef DEBUG
ca67e7b4
C
264 if (debug)
265 fprintf(ddt, "z_time %d, z_refresh %d\n",
266 zp->z_time, zp->z_refresh);
95f51977 267#endif
ca67e7b4
C
268 if (zp->z_time != 0 &&
269 (next_refresh == 0 || next_refresh > zp->z_time))
270 next_refresh = zp->z_time;
95f51977
C
271 }
272 (void) fclose(fp);
ca67e7b4
C
273
274 /*
275 * Schedule calls to ns_maint().
276 */
277 bzero((char *)&ival, sizeof(ival));
278 if (next_refresh) {
279 gettime(&tt);
280 if (next_refresh <= tt.tv_sec)
281 needmaint = 1;
282 else {
95f51977 283 ival.it_value.tv_sec = next_refresh - tt.tv_sec;
ca67e7b4
C
284 if (ival.it_value.tv_sec < maint_interval)
285 ival.it_value.tv_sec = maint_interval;
95f51977 286 }
ca67e7b4 287 }
95f51977 288 (void) setitimer(ITIMER_REAL, &ival, (struct itimerval *)NULL);
ca67e7b4
C
289#ifdef DEBUG
290 if (debug) {
291 fprintf(ddt,"exit ns_init() ");
292 if (needmaint || ival.it_value.tv_sec)
293 fprintf(ddt,"Next interrupt in %d sec\n",
294 ival.it_value.tv_sec);
295 else
296 fprintf(ddt,"No maintenance scheduled\n");
297 }
95f51977
C
298#endif
299}
300
301zoneinit(zp)
ca67e7b4 302 register struct zoneinfo *zp;
95f51977 303{
95f51977
C
304
305#ifdef DEBUG
306 if (debug)
307 fprintf(ddt,"zoneinit()\n");
308#endif
309
ca67e7b4
C
310 /*
311 * Try to load zone from backup file,
312 * if one was specified and it exists.
313 * If not, or if the data are out of date,
314 * we will refresh the zone from a primary
315 * immediately.
316 */
317 if (zp->z_source == NULL ||
318 db_load(zp->z_source, zp->z_origin, zp) != 0) {
319 /*
320 * Set zone to be refreshed immediately.
321 */
322 zp->z_refresh = INIT_REFRESH;
323 zp->z_retry = INIT_REFRESH;
324 zp->z_time = tt.tv_sec;
325 } else
326 zp->z_auth = 1;
327}
328
329#ifdef ALLOW_UPDATES
330/*
331 * Look for the authoritative zone with the longest matching RHS of dname
332 * and return its zone # or zero if not found.
333 */
334findzone(dname, class)
335 char *dname;
336 int class;
337{
338 char *dZoneName, *zoneName, *index(), *dotPos;
339 int dZoneNameLen, zoneNameLen;
340 int maxMatchLen = 0;
341 int maxMatchZoneNum = 0;
342 int zoneNum;
95f51977 343
95f51977 344#ifdef DEBUG
ca67e7b4
C
345 if (debug >= 4)
346 fprintf(ddt, "findzone(dname=%s, class=%d)\n", dname, class);
347 if (debug >= 5) {
348 fprintf(ddt, "zone dump:\n");
349 for (zoneNum = 1; zoneNum < nzones; zoneNum++)
350 printzoneinfo(zoneNum);
351 }
352#endif DEBUG
353
354 dZoneName = index(dname, '.');
355 if (dZoneName == NULL)
356 dZoneName = ""; /* root */
357 else
358 dZoneName++; /* There is a '.' in dname, so use remainder of
359 string as the zone name */
360 dZoneNameLen = strlen(dZoneName);
361 for (zoneNum = 1; zoneNum < nzones; zoneNum++) {
362 zoneName = (zones[zoneNum]).z_origin;
363 zoneNameLen = strlen(zoneName);
364 /* The zone name may or may not end with a '.' */
365 dotPos = index(zoneName, '.');
366 if (dotPos)
367 zoneNameLen--;
368 if (dZoneNameLen != zoneNameLen)
369 continue;
95f51977 370#ifdef DEBUG
ca67e7b4
C
371 if (debug >= 5)
372 fprintf(ddt, "about to strncasecmp('%s', '%s', %d)\n",
373 dZoneName, zoneName, dZoneNameLen);
95f51977 374#endif
ca67e7b4 375 if (strncasecmp(dZoneName, zoneName, dZoneNameLen) == 0) {
95f51977 376#ifdef DEBUG
ca67e7b4
C
377 if (debug >= 5)
378 fprintf(ddt, "match\n");
95f51977 379#endif
95f51977 380 /*
ca67e7b4
C
381 * See if this is as long a match as any so far.
382 * Check if "<=" instead of just "<" so that if
383 * root domain (whose name length is 0) matches,
384 * we use it's zone number instead of just 0
95f51977 385 */
ca67e7b4
C
386 if (maxMatchLen <= zoneNameLen) {
387 maxMatchZoneNum = zoneNum;
388 maxMatchLen = zoneNameLen;
95f51977
C
389 }
390 }
95f51977 391#ifdef DEBUG
ca67e7b4
C
392 else
393 if (debug >= 5)
394 fprintf(ddt, "no match\n");
95f51977
C
395#endif
396 }
ca67e7b4
C
397#ifdef DEBUG
398 if (debug >= 4)
399 fprintf(ddt, "findzone: returning %d\n", maxMatchZoneNum);
400#endif DEBUG
401 return (maxMatchZoneNum);
95f51977 402}
ca67e7b4 403#endif ALLOW_UPDATES
95f51977 404
ca67e7b4
C
405soa_zinfo(zp, cp, eom)
406 register struct zoneinfo *zp;
407 register u_char *cp;
408 u_char *eom;
95f51977
C
409{
410 cp += 3 * sizeof(u_short);
411 cp += sizeof(u_long);
ca67e7b4
C
412 cp += dn_skipname(cp, eom);
413 cp += dn_skipname(cp, eom);
414 GETLONG(zp->z_serial, cp);
415 GETLONG(zp->z_refresh, cp);
416 gettime(&tt);
95f51977 417 zp->z_time = tt.tv_sec + zp->z_refresh;
ca67e7b4
C
418 GETLONG(zp->z_retry, cp);
419 GETLONG(zp->z_expire, cp);
420 GETLONG(zp->z_minimum, cp);
421}
422
423get_forwarders(fp)
424 FILE *fp;
425{
426 char buf[BUFSIZ];
427 struct fwdinfo *fip = NULL, *ftp = NULL;
428
429 extern struct sockaddr_in nsaddr;
430 extern struct fwdinfo *fwdtab;
431
432#ifdef DEBUG
433 if (debug)
434 fprintf(ddt,"forwarders ");
435#endif
436 while (getword(buf, sizeof(buf), fp)) {
437 if (strlen(buf) == 0)
438 break;
439#ifdef DEBUG
440 if (debug)
441 fprintf(ddt," %s",buf);
442#endif
443 if (ftp == NULL)
444 ftp = (struct fwdinfo *)malloc(sizeof(struct fwdinfo));
445 if ( isdigit(buf[0]) &&
446 (ftp->fwdaddr.sin_addr.s_addr = inet_addr(buf))
447 != (unsigned)-1) {
448 ftp->fwdaddr.sin_port = nsaddr.sin_port;
449 ftp->fwdaddr.sin_family = AF_INET;
450 } else {
451 syslog(LOG_ERR, "'%s' (ignored, NOT dotted quad)", buf);
452#ifdef DEBUG
453 if (debug)
454 fprintf(ddt," (ignored, NOT dotted quad)");
455#endif
456 continue;
457 }
458 ftp->next = NULL;
459 if (fwdtab == NULL)
460 fwdtab = ftp; /* First time only */
461 else
462 fip->next = ftp;
463 fip = ftp;
464 ftp = NULL;
465 }
466 if (ftp)
467 free((char *)ftp);
468
469#ifdef DEBUG
470 if (debug)
471 fprintf(ddt,"\n");
472 if (debug > 2)
473 for (ftp = fwdtab; ftp != NULL; ftp = ftp->next)
474 fprintf(ddt,"ftp x%x %s next x%x\n", ftp,
475 inet_ntoa(ftp->fwdaddr.sin_addr), ftp->next);
476#endif
95f51977 477}