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