|
|
1.1 root 1: /*-
2: * Copyright (c) 1986, 1990 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: static char sccsid[] = "@(#)ns_init.c 4.35 (Berkeley) 6/27/90";
22: #endif /* not lint */
23:
24: #include <sys/types.h>
25: #include <sys/socket.h>
26: #include <sys/time.h>
27: #include <sys/stat.h>
28: #include <netinet/in.h>
29: #include <stdio.h>
30: #include <errno.h>
31: #include <signal.h>
32: #include <syslog.h>
33: #include <ctype.h>
34: #include <string.h>
35: #include <arpa/nameser.h>
36: #include "pathnames.h"
37: #include "ns.h"
38: #include "db.h"
39:
40: struct zoneinfo *zones; /* zone information */
41: int nzones; /* number of zones in use */
42: int forward_only = 0; /* run only as a slave */
43: char *cache_file;
44: char *localdomain; /* "default" for non-dotted names */
45: int maint_interval = 15*60; /* minimum ns_maint() interval */
46:
47: extern int lineno;
48:
49:
50: /*
51: * Read boot file for configuration info.
52: */
53:
54: ns_init(bootfile)
55: char *bootfile;
56: {
57: register struct zoneinfo *zp;
58: struct zoneinfo *find_zone();
59: char buf[BUFSIZ], obuf[BUFSIZ], *source;
60: extern char *calloc();
61: FILE *fp;
62: int type;
63: extern int needmaint;
64: struct stat f_time;
65: static int loads = 0; /* number of times loaded */
66: static int tmpnum = 0; /* unique number for tmp zone files */
67: #ifdef ALLOW_UPDATES
68: char *cp, *flag;
69: #endif
70:
71: #ifdef DEBUG
72: if (debug)
73: fprintf(ddt,"\nns_init(%s)\n", bootfile);
74: #endif
75: gettime(&tt);
76:
77: if ((fp = fopen(bootfile, "r")) == NULL) {
78: syslog(LOG_ERR, "%s: %m", bootfile);
79: exit(1);
80: }
81: lineno = 0;
82: if (loads == 0) {
83: if ((zones =
84: (struct zoneinfo *)calloc(64, sizeof(struct zoneinfo)))
85: == NULL) {
86: syslog(LOG_ERR,
87: "Not enough memory to allocate initial zones array");
88: exit(1);
89: }
90: nzones = 1; /* zone zero is cache data */
91: /* allocate cache hash table, formerly the root hash table. */
92: hashtab = savehash((struct hashbuf *)NULL);
93:
94: /* allocate root-hints/file-cache hash table */
95: fcachetab = savehash((struct hashbuf *)NULL);
96: /* init zone data */
97: zones[0].z_type = Z_CACHE;
98: } else {
99: /* Mark previous zones as not yet found in boot file. */
100: for (zp = &zones[1]; zp < &zones[nzones]; zp++)
101: zp->z_state &= ~Z_FOUND;
102: if (localdomain)
103: free(localdomain);
104: localdomain = NULL;
105: free_forwarders();
106: forward_only = 0;
107: }
108:
109: #ifdef DEBUG
110: if (debug >= 3) {
111: fprintf(ddt,"\n content of zones before loading \n");
112: content_zone(nzones - 1);
113: }
114: #endif
115: while (!feof(fp) && !ferror(fp)) {
116: if (!getword(buf, sizeof(buf), fp))
117: continue;
118: /* read named.boot keyword and process args */
119: if (strcasecmp(buf, "directory") == 0) {
120: (void) getword(buf, sizeof(buf), fp);
121: if (chdir(buf) < 0) {
122: syslog(LOG_CRIT, "directory %s: %m\n",
123: buf);
124: exit(1);
125: }
126: continue;
127: } else if (strcasecmp(buf, "sortlist") == 0) {
128: get_sort_list(fp);
129: continue;
130: } else if (strcasecmp(buf, "forwarders") == 0) {
131: get_forwarders(fp);
132: continue;
133: } else if (strcasecmp(buf, "slave") == 0) {
134: forward_only++;
135: endline(fp);
136: continue;
137: } else if (strcasecmp(buf, "domain") == 0) {
138: if (getword(buf, sizeof(buf), fp))
139: localdomain = savestr(buf);
140: endline(fp);
141: continue;
142: } else if (strcasecmp(buf, "cache") == 0)
143: type = Z_CACHE;
144: else if (strcasecmp(buf, "primary") == 0)
145: type = Z_PRIMARY;
146: else if (strcasecmp(buf, "secondary") == 0)
147: type = Z_SECONDARY;
148: else {
149: syslog(LOG_ERR, "%s: line %d: unknown field '%s'\n",
150: bootfile, lineno, buf);
151: endline(fp);
152: continue;
153: }
154:
155: /*
156: * read zone origin
157: */
158: if (!getword(obuf, sizeof(obuf), fp)) {
159: syslog(LOG_ERR, "%s: line %d: missing origin\n",
160: bootfile, lineno);
161: continue;
162: }
163: #ifdef DEBUG
164: if (debug)
165: fprintf(ddt, "zone origin %s", obuf);
166: #endif
167: if (obuf[0] == '.' && obuf[1] == '\0')
168: obuf[0] = '\0';
169: /*
170: * read source file or host address
171: */
172: if (!getword(buf, sizeof(buf), fp)) {
173: syslog(LOG_ERR,
174: "%s: line %d: missing source or addr\n",
175: bootfile, lineno);
176: continue;
177: }
178:
179: /* check for previous instance of this zone (reload) */
180: if ((zp = find_zone(obuf, type)) == 0) {
181: if (type == Z_CACHE) {
182: zp = &zones[0];
183: zp->z_origin = "";
184: goto gotzone;
185: }
186: for (zp = &zones[1]; zp < &zones[nzones]; zp++)
187: if (zp->z_type == 0)
188: goto gotzone;
189: /*
190: * this code assume that nzones never decreases
191: */
192: if (nzones % 64 == 0) {
193: #ifdef DEBUG
194: if (debug > 1)
195: fprintf(ddt, "Reallocating zones structure\n");
196: #endif DEBUG
197: /*
198: * Realloc() not used since it might damage zones
199: * if an error occurs
200: */
201: if ((zp = (struct zoneinfo *)
202: malloc((64 + nzones) * sizeof(struct zoneinfo)))
203: == NULL) {
204: syslog(LOG_ERR, "no memory for more zones");
205: #ifdef DEBUG
206: if (debug)
207: fprintf(ddt,
208: "Out of memory for new zones\n");
209: #endif DEBUG
210: endline(fp);
211: continue;
212: }
213: bcopy((char *)zones, (char *)zp,
214: nzones * sizeof(struct zoneinfo));
215: bzero((char *)&zp[nzones],
216: 64 * sizeof(struct zoneinfo));
217: free(zones);
218: zones = zp;
219: }
220: zp = &zones[nzones++];
221: gotzone:
222: zp->z_origin = savestr(obuf);
223: zp->z_type = type;
224: }
225: zp->z_addrcnt = 0;
226:
227: switch (type) {
228: case Z_CACHE:
229: source = savestr(buf);
230: #ifdef DEBUG
231: if (debug)
232: fprintf(ddt,", source = %s\n", source);
233: #endif
234: zp->z_refresh = 0; /* by default, no dumping */
235: if (getword(buf, sizeof(buf), fp)) {
236: #ifdef notyet
237: zp->z_refresh = atoi(buf);
238: if (zp->z_refresh <= 0) {
239: syslog(LOG_ERR,
240: "%s: line %d: bad refresh time '%s', ignored\n",
241: bootfile, lineno, buf);
242: zp->z_refresh = 0;
243: } else if (cache_file == NULL)
244: cache_file = source;
245: #else
246: syslog(LOG_WARNING,
247: "%s: line %d: cache refresh ignored\n",
248: bootfile, lineno);
249: #endif
250: endline(fp);
251: }
252: /*
253: * If we've loaded this file, and the file has
254: * not been modified and contains no $include,
255: * then there's no need to reload.
256: */
257: if (zp->z_source && strcmp(source, zp->z_source) == 0 &&
258: (zp->z_state & Z_INCLUDE) == 0 &&
259: stat(zp->z_source, &f_time) == 0 &&
260: zp->z_ftime == f_time.st_mtime) {
261: #ifdef DEBUG
262: if (debug)
263: fprintf(ddt, "cache is up to date\n");
264: #endif
265: break; /* zone is already up to date */
266: }
267:
268: /* file has changed, or hasn't been loaded yet */
269: if (zp->z_source) {
270: free(zp->z_source);
271: remove_zone(fcachetab, 0);
272: }
273: zp->z_source = source;
274: #ifdef DEBUG
275: if (debug)
276: fprintf(ddt, "reloading zone\n");
277: #endif
278: (void) db_load(zp->z_source, zp->z_origin, zp, 0);
279: break;
280:
281: case Z_PRIMARY:
282: source = savestr(buf);
283: #ifdef ALLOW_UPDATES
284: if (getword(buf, sizeof(buf), fp)) {
285: endline(fp);
286: flag = buf;
287: while (flag) {
288: cp = index(flag, ',');
289: if (cp)
290: *cp++ = 0;
291: if (strcasecmp(flag, "dynamic") == 0)
292: zp->z_state |= Z_DYNAMIC;
293: else if (strcasecmp(flag, "addonly") == 0)
294: zp->z_state |= Z_DYNADDONLY;
295: else {
296: syslog(LOG_ERR,
297: "%s: line %d: bad flag '%s'\n",
298: bootfile, lineno, flag);
299: }
300: flag = cp;
301: }
302: }
303: #else ALLOW_UPDATES
304: endline(fp);
305: #endif
306:
307: #ifdef DEBUG
308: if (debug)
309: fprintf(ddt,", source = %s\n", source);
310: #endif
311: /*
312: * If we've loaded this file, and the file has
313: * not been modified and contains no $include,
314: * then there's no need to reload.
315: */
316: if (zp->z_source && strcmp(source, zp->z_source) == 0 &&
317: (zp->z_state & Z_INCLUDE) == 0 &&
318: stat(zp->z_source, &f_time) == 0 &&
319: zp->z_ftime == f_time.st_mtime) {
320: #ifdef DEBUG
321: if (debug)
322: fprintf(ddt, "zone is up to date\n");
323: #endif
324: break; /* zone is already up to date */
325: }
326: if (zp->z_source) {
327: free(zp->z_source);
328: remove_zone(hashtab, zp - zones);
329: }
330: zp->z_source = source;
331: zp->z_auth = 0;
332: #ifdef DEBUG
333: if (debug)
334: fprintf(ddt, "reloading zone\n");
335: #endif
336: if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0)
337: zp->z_auth = 1;
338: #ifdef ALLOW_UPDATES
339: /* Guarantee calls to ns_maint() */
340: zp->z_refresh = maint_interval;
341: #else ALLOW_UPDATES
342: zp->z_refresh = 0; /* no maintenance needed */
343: zp->z_time = 0;
344: #endif ALLOW_UPDATES
345: break;
346:
347: case Z_SECONDARY:
348: source = 0;
349: #ifdef DEBUG
350: if (debug)
351: fprintf(ddt,"\n\taddrs: ");
352: #endif
353: do {
354: zp->z_addr[zp->z_addrcnt].s_addr =
355: inet_addr(buf);
356: if (zp->z_addr[zp->z_addrcnt].s_addr ==
357: (u_long)-1) {
358: source = savestr(buf);
359: endline(fp);
360: break;
361: }
362: #ifdef DEBUG
363: if (debug)
364: fprintf(ddt,"%s, ",buf);
365: #endif
366: if (++zp->z_addrcnt > NSMAX - 1) {
367: zp->z_addrcnt = NSMAX - 1;
368: #ifdef DEBUG
369: if (debug)
370: fprintf(ddt,
371: "\nns.h NSMAX reached\n");
372: #endif
373: }
374: } while (getword(buf, sizeof(buf), fp));
375: #ifdef DEBUG
376: if (debug)
377: fprintf(ddt,"addrcnt = %d\n", zp->z_addrcnt);
378: #endif
379: if (source == 0) {
380: /*
381: * We will always transfer this zone again
382: * after a reload.
383: */
384: sprintf(buf, "/%s/NsTmp%d", _PATH_TMPDIR,
385: tmpnum++);
386: source = savestr(buf);
387: zp->z_state |= Z_TMP_FILE;
388: } else
389: zp->z_state &= ~Z_TMP_FILE;
390: /*
391: * If we had a backup file name, and it was changed,
392: * free old zone and start over. If we don't have
393: * current zone contents, try again now in case
394: * we have a new server on the list.
395: */
396: if (zp->z_source && strcmp(source, zp->z_source)) {
397: #ifdef DEBUG
398: if (debug)
399: fprintf(ddt,"backup file changed\n");
400: #endif
401: free(zp->z_source);
402: zp->z_source = 0;
403: zp->z_auth = 0;
404: zp->z_serial = 0; /* force xfer */
405: remove_zone(hashtab, zp - zones);
406: }
407: if (zp->z_source)
408: free(source);
409: else
410: zp->z_source = source;
411: if (zp->z_auth == 0)
412: zoneinit(zp);
413: break;
414:
415: }
416: zp->z_state |= Z_FOUND;
417: #ifdef DEBUG
418: if (debug)
419: fprintf(ddt,"zone[%d] type %d: '%s'",
420: zp-zones, type,
421: *(zp->z_origin) == '\0' ? "." : zp->z_origin);
422: #endif
423: if (zp->z_refresh && zp->z_time == 0)
424: zp->z_time = zp->z_refresh + tt.tv_sec;
425: if (zp->z_time <= tt.tv_sec)
426: needmaint = 1;
427: #ifdef DEBUG
428: if (debug)
429: fprintf(ddt, " z_time %d, z_refresh %d\n",
430: zp->z_time, zp->z_refresh);
431: #endif
432: }
433: (void) fclose(fp);
434: /* erase all old zones that were not found */
435: for (zp = &zones[1]; zp < &zones[nzones]; zp++)
436: if (zp->z_type && (zp->z_state & Z_FOUND) == 0) {
437: remove_zone(hashtab, zp - zones);
438: bzero((char *) zp, sizeof(*zp));
439: #ifdef DEBUG
440: if(debug >=2)
441: fprintf(ddt,"\n zone no %d was removed \n", zp - zones);
442: #endif
443: }
444: #ifdef DEBUG
445: if(debug >= 2) {
446: fprintf(ddt,"\n content of zones after loading \n");
447: content_zone(nzones-1);
448: }
449: #endif
450:
451: /*
452: * Schedule calls to ns_maint().
453: */
454: if (needmaint == 0)
455: sched_maint();
456: #ifdef DEBUG
457: if (debug)
458: fprintf(ddt,"exit ns_init()%s\n", needmaint ?
459: ", need maintenance immediately" : "");
460: #endif
461: loads++;
462: }
463:
464: zoneinit(zp)
465: register struct zoneinfo *zp;
466: {
467: extern int needmaint;
468: struct stat sb;
469:
470: /*
471: * Try to load zone from backup file,
472: * if one was specified and it exists.
473: * If not, or if the data are out of date,
474: * we will refresh the zone from a primary
475: * immediately.
476: */
477: if (zp->z_source == NULL)
478: return;
479: if (stat(zp->z_source, &sb) == -1 ||
480: db_load(zp->z_source, zp->z_origin, zp, 0) != 0) {
481: /*
482: * Set zone to be refreshed immediately.
483: */
484: zp->z_refresh = INIT_REFRESH;
485: zp->z_retry = INIT_REFRESH;
486: zp->z_time = tt.tv_sec;
487: needmaint = 1;
488: } else
489: zp->z_auth = 1;
490: }
491:
492: #ifdef ALLOW_UPDATES
493: /*
494: * Look for the authoritative zone with the longest matching RHS of dname
495: * and return its zone # or zero if not found.
496: */
497: findzone(dname, class)
498: char *dname;
499: int class;
500: {
501: char *dZoneName, *zoneName, *index();
502: int dZoneNameLen, zoneNameLen;
503: int maxMatchLen = 0;
504: int maxMatchZoneNum = 0;
505: int zoneNum;
506:
507: #ifdef DEBUG
508: if (debug >= 4)
509: fprintf(ddt, "findzone(dname=%s, class=%d)\n", dname, class);
510: if (debug >= 5) {
511: fprintf(ddt, "zone dump:\n");
512: for (zoneNum = 1; zoneNum < nzones; zoneNum++)
513: printzoneinfo(zoneNum);
514: }
515: #endif DEBUG
516:
517: dZoneName = index(dname, '.');
518: if (dZoneName == NULL)
519: dZoneName = ""; /* root */
520: else
521: dZoneName++; /* There is a '.' in dname, so use remainder of
522: string as the zone name */
523: dZoneNameLen = strlen(dZoneName);
524: for (zoneNum = 1; zoneNum < nzones; zoneNum++) {
525: zoneName = (zones[zoneNum]).z_origin;
526: zoneNameLen = strlen(zoneName);
527: /* The zone name may or may not end with a '.' */
528: if (zoneName[zoneNameLen - 1] == '.')
529: zoneNameLen--;
530: if (dZoneNameLen != zoneNameLen)
531: continue;
532: #ifdef DEBUG
533: if (debug >= 5)
534: fprintf(ddt, "about to strncasecmp('%s', '%s', %d)\n",
535: dZoneName, zoneName, dZoneNameLen);
536: #endif
537: if (strncasecmp(dZoneName, zoneName, dZoneNameLen) == 0) {
538: #ifdef DEBUG
539: if (debug >= 5)
540: fprintf(ddt, "match\n");
541: #endif
542: /*
543: * See if this is as long a match as any so far.
544: * Check if "<=" instead of just "<" so that if
545: * root domain (whose name length is 0) matches,
546: * we use it's zone number instead of just 0
547: */
548: if (maxMatchLen <= zoneNameLen) {
549: maxMatchZoneNum = zoneNum;
550: maxMatchLen = zoneNameLen;
551: }
552: }
553: #ifdef DEBUG
554: else
555: if (debug >= 5)
556: fprintf(ddt, "no match\n");
557: #endif
558: }
559: #ifdef DEBUG
560: if (debug >= 4)
561: fprintf(ddt, "findzone: returning %d\n", maxMatchZoneNum);
562: #endif DEBUG
563: return (maxMatchZoneNum);
564: }
565: #endif ALLOW_UPDATES
566:
567: soa_zinfo(zp, cp, eom)
568: register struct zoneinfo *zp;
569: register u_char *cp;
570: u_char *eom;
571: {
572: cp += 3 * sizeof(u_short);
573: cp += sizeof(u_long);
574: cp += dn_skipname(cp, eom);
575: cp += dn_skipname(cp, eom);
576: GETLONG(zp->z_serial, cp);
577: GETLONG(zp->z_refresh, cp);
578: gettime(&tt);
579: zp->z_time = tt.tv_sec + zp->z_refresh;
580: GETLONG(zp->z_retry, cp);
581: GETLONG(zp->z_expire, cp);
582: GETLONG(zp->z_minimum, cp);
583: }
584:
585: get_forwarders(fp)
586: FILE *fp;
587: {
588: char buf[BUFSIZ];
589: register struct fwdinfo *fip = NULL, *ftp = NULL;
590: extern struct sockaddr_in nsaddr;
591: extern struct fwdinfo *fwdtab;
592:
593: #ifdef DEBUG
594: if (debug)
595: fprintf(ddt,"forwarders ");
596: #endif
597:
598: /* on mulitple forwarder lines, move to end of the list */
599: if (fwdtab != NULL)
600: for (fip = fwdtab; fip->next != NULL; fip = fip->next)
601: ;
602:
603: while (getword(buf, sizeof(buf), fp)) {
604: if (strlen(buf) == 0)
605: break;
606: #ifdef DEBUG
607: if (debug)
608: fprintf(ddt," %s",buf);
609: #endif
610: if (ftp == NULL)
611: ftp = (struct fwdinfo *)malloc(sizeof(struct fwdinfo));
612: if (isdigit(buf[0]) &&
613: (ftp->fwdaddr.sin_addr.s_addr = inet_addr(buf)) !=
614: (u_long)-1) {
615: ftp->fwdaddr.sin_port = nsaddr.sin_port;
616: ftp->fwdaddr.sin_family = AF_INET;
617: } else {
618: syslog(LOG_ERR, "'%s' (ignored, NOT dotted quad)", buf);
619: #ifdef DEBUG
620: if (debug)
621: fprintf(ddt," (ignored, NOT dotted quad)");
622: #endif
623: continue;
624: }
625: ftp->next = NULL;
626: if (fwdtab == NULL)
627: fwdtab = ftp; /* First time only */
628: else
629: fip->next = ftp;
630: fip = ftp;
631: ftp = NULL;
632: }
633: if (ftp)
634: free((char *)ftp);
635:
636: #ifdef DEBUG
637: if (debug)
638: fprintf(ddt,"\n");
639: if (debug > 2)
640: for (ftp = fwdtab; ftp != NULL; ftp = ftp->next)
641: fprintf(ddt,"ftp x%x %s next x%x\n", ftp,
642: inet_ntoa(ftp->fwdaddr.sin_addr), ftp->next);
643: #endif
644: }
645:
646: free_forwarders()
647: {
648: extern struct fwdinfo *fwdtab;
649: register struct fwdinfo *ftp, *fnext;
650:
651: for (ftp = fwdtab; ftp != NULL; ftp = fnext) {
652: fnext = ftp->next;
653: free((char *)ftp);
654: }
655: fwdtab = NULL;
656: }
657:
658: struct zoneinfo *
659: find_zone(name, type)
660: char *name;
661: int type;
662: {
663: register struct zoneinfo *zp;
664:
665: for (zp = &zones[1]; zp < &zones[nzones]; zp++)
666: if (zp->z_type == type && strcasecmp(name, zp->z_origin) == 0) {
667: #ifdef DEBUG
668: if (debug > 1)
669: fprintf(ddt, ", old zone (%d)", zp - zones);
670: #endif
671: return (zp);
672: }
673: #ifdef DEBUG
674: if(debug > 1)
675: fprintf(ddt, ", new zone");
676: #endif
677: return ((struct zoneinfo *)NULL);
678: }
679:
680: /* prints out the content of zones */
681: content_zone(end)
682: int end;
683: {
684: int i;
685: for (i = 1; i <= end; i++)
686: printzoneinfo(i);
687: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.