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_maint.c 4.23 (Berkeley) 2/28/88"; 15: #endif /* not lint */ 16: 17: #include <sys/param.h> 18: #include <sys/socket.h> 19: #include <sys/time.h> 20: #if defined(SYSV) 21: #include <unistd.h> 22: #endif SYSV 23: #include <netinet/in.h> 24: #include <stdio.h> 25: #include <syslog.h> 26: #include <signal.h> 27: #include <errno.h> 28: #include <arpa/nameser.h> 29: #include "ns.h" 30: #include "db.h" 31: 32: extern int errno; 33: extern u_long maint_interval; 34: 35: 36: /* 37: * Invoked at regular intervals by signal interrupt; refresh all secondary 38: * zones from primary name server and remove old cache entries. Also, 39: * ifdef'd ALLOW_UPDATES, dump database if it has changed since last 40: * dump/bootup. 41: */ 42: ns_maint() 43: { 44: register struct zoneinfo *zp; 45: struct itimerval ival; 46: time_t next_refresh = 0; 47: int zonenum; 48: 49: #ifdef DEBUG 50: if (debug) 51: fprintf(ddt,"ns_maint()\n"); 52: #endif 53: 54: for (zp = zones, zonenum = 0; zp < &zones[nzones]; zp++, zonenum++) { 55: switch(zp->z_type) { 56: #ifdef ALLOW_UPDATES 57: case Z_PRIMARY: 58: #endif ALLOW_UPDATES 59: case Z_SECONDARY: 60: case Z_CACHE: 61: break; 62: 63: default: 64: continue; 65: } 66: gettime(&tt); 67: #ifdef DEBUG 68: if (debug >= 2) 69: printzoneinfo(zonenum); 70: #endif 71: if (tt.tv_sec >= zp->z_time && zp->z_refresh > 0) { 72: if (zp->z_type == Z_CACHE) 73: doachkpt(); 74: if (zp->z_type == Z_SECONDARY) 75: zoneref(zp); 76: #ifdef ALLOW_UPDATES 77: /* 78: * Checkpoint the zone if it has changed 79: * since we last checkpointed 80: */ 81: if (zp->z_type == Z_PRIMARY && zp->hasChanged) 82: zonedump(zp); 83: #endif ALLOW_UPDATES 84: zp->z_time = tt.tv_sec + zp->z_refresh; 85: } 86: 87: /* 88: * Find when the next refresh needs to be and set 89: * interrupt time accordingly. 90: */ 91: if (next_refresh == 0 || 92: (zp->z_time != 0 && next_refresh > zp->z_time)) 93: next_refresh = zp->z_time; 94: } 95: 96: /* 97: * Schedule the next call to this function. 98: * Don't visit any sooner than maint_interval. 99: */ 100: bzero((char *)&ival, sizeof (ival)); 101: ival.it_value.tv_sec = next_refresh - tt.tv_sec; 102: if (ival.it_value.tv_sec < maint_interval) 103: ival.it_value.tv_sec = maint_interval; 104: (void) setitimer(ITIMER_REAL, &ival, (struct itimerval *)NULL); 105: #ifdef DEBUG 106: if (debug) 107: fprintf(ddt,"exit ns_maint() Next interrupt in %ld sec\n", 108: ival.it_value.tv_sec); 109: #endif 110: } 111: 112: zoneref(zp) 113: struct zoneinfo *zp; 114: { 115: HEADER *hp; 116: u_short len; 117: u_long serial; 118: int s, n, l, tries; 119: int cnt, soacnt, error = 0; 120: int zone = zp - zones; 121: u_char *cp, *nmp, *eom; 122: u_char *tmp; 123: u_char buf[PACKETSZ]; 124: char name[MAXDNAME], name2[MAXDNAME]; 125: struct sockaddr_in sin; 126: struct zoneinfo zp_start, zp_finish; 127: struct itimerval ival; 128: struct itimerval zeroival; 129: extern struct sockaddr_in nsaddr; 130: extern int errno; 131: extern int read_interrupted; 132: extern int read_alarm(); 133: struct sigvec sv, osv; 134: 135: #ifdef DEBUG 136: if (debug) 137: fprintf(ddt,"zoneref() %s\n", zp->z_origin); 138: #endif 139: bzero((char *)&zeroival, sizeof(zeroival)); 140: ival = zeroival; 141: ival.it_value.tv_sec = 30; 142: sv.sv_handler = read_alarm; 143: sv.sv_onstack = 0; 144: sv.sv_mask = ~0; 145: (void) sigvec(SIGALRM, &sv, &osv); 146: 147: for( cnt = 0; cnt < zp->z_addrcnt; cnt++) { 148: error = 0; 149: bzero((char *)&sin, sizeof(sin)); 150: sin.sin_family = AF_INET; 151: sin.sin_port = nsaddr.sin_port; 152: sin.sin_addr = zp->z_addr[cnt]; 153: if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 154: syslog(LOG_ERR, "zoneref: socket: %m"); 155: error++; 156: break; 157: } 158: #ifdef DEBUG 159: if (debug >= 2) { 160: fprintf(ddt,"connecting to server #%d %s, %d\n", 161: cnt+1, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); 162: } 163: #endif 164: if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 165: (void) close(s); 166: error++; 167: #ifdef DEBUG 168: if (debug >= 2) 169: fprintf(ddt,"connect failed, errno %d\n", errno); 170: #endif 171: continue; 172: } 173: if ((n = res_mkquery(QUERY, zp->z_origin, C_IN, 174: T_SOA, (char *)NULL, 0, NULL, buf, sizeof(buf))) < 0) { 175: syslog(LOG_ERR, "zoneref: res_mkquery failed"); 176: (void) close(s); 177: (void) sigvec(SIGALRM, &osv, (struct sigvec *)0); 178: return; 179: } 180: /* 181: * Send length & message for zone transfer 182: */ 183: if (writemsg(s, buf, n) < 0) { 184: (void) close(s); 185: error++; 186: #ifdef DEBUG 187: if (debug >= 2) 188: fprintf(ddt,"writemsg failed\n"); 189: #endif 190: continue; 191: } 192: /* 193: * Get out your butterfly net and catch the SOA 194: */ 195: cp = buf; 196: l = sizeof(u_short); 197: read_interrupted = 0; 198: while (l > 0) { 199: (void) setitimer(ITIMER_REAL, &ival, 200: (struct itimerval *)NULL); 201: if ((n = recv(s, cp, l, 0)) > 0) { 202: cp += n; 203: l -= n; 204: } else { 205: if (errno == EINTR && !read_interrupted) 206: continue; 207: error++; 208: break; 209: } 210: } 211: (void) setitimer(ITIMER_REAL, &zeroival, 212: (struct itimerval *)NULL); 213: if (error) { 214: (void) close(s); 215: continue; 216: } 217: if ((len = htons(*(u_short *)buf)) == 0) { 218: (void) close(s); 219: if (zp->z_sysloged == 0) 220: syslog(LOG_ERR, 221: "no SOA from server %s, zone %s (len 0)\n", 222: inet_ntoa(sin.sin_addr), zp->z_origin); 223: continue; 224: } 225: l = len; 226: cp = buf; 227: while (l > 0) { 228: (void) setitimer(ITIMER_REAL, &ival, 229: (struct itimerval *)NULL); 230: if ((n = recv(s, cp, l, 0)) > 0) { 231: cp += n; 232: l -= n; 233: } else { 234: if (errno == EINTR && !read_interrupted) 235: continue; 236: error++; 237: break; 238: } 239: } 240: (void) setitimer(ITIMER_REAL, &zeroival, 241: (struct itimerval *)NULL); 242: if (error) { 243: (void) close(s); 244: continue; 245: } 246: #ifdef DEBUG 247: if (debug >= 3) { 248: fprintf(ddt,"len = %d\n", len); 249: fp_query(buf, ddt); 250: } 251: #endif DEBUG 252: zp_start = *zp; 253: tmp = buf + sizeof(HEADER); 254: eom = buf + len; 255: /* NEED TO CHECK MESSAGE LENGTH, ANCOUNT, AA */ 256: tmp += dn_skipname(tmp, eom) + QFIXEDSZ; 257: tmp += dn_skipname(tmp, eom); 258: soa_zinfo(&zp_start, tmp, eom); 259: if (zp->z_serial >= zp_start.z_serial && zp->z_auth) { 260: #ifdef DEBUG 261: if (debug) 262: fprintf(ddt,"zoneref: up to date (%ld >= %ld)\n", 263: zp->z_serial, zp_start.z_serial); 264: #endif DEBUG 265: zp->z_lastupdate = tt.tv_sec; 266: zp->z_refresh = zp_start.z_refresh; 267: (void) close(s); 268: (void) sigvec(SIGALRM, &osv, (struct sigvec *)0); 269: if (zp->z_source) { 270: #if defined(SYSV) 271: struct utimbuf t; 272: 273: t.actime = t.modtime = tt.tv_sec; 274: (void) utime(zp->z_source, &t); 275: #else 276: struct timeval t[2]; 277: 278: t[0] = tt; 279: t[1] = tt; 280: (void) utimes(zp->z_source, t); 281: #endif /* SYSV */ 282: } 283: return; 284: } 285: #ifdef DEBUG 286: if (debug) 287: fprintf(ddt,"zoneref: need xfer (%ld < %ld)\n", 288: zp->z_serial, zp_start.z_serial); 289: #endif DEBUG 290: hp = (HEADER *) buf; 291: soacnt = 0; 292: /* mark all existing RR's for zone as "old" */ 293: mark_zone (hashtab, zone, 1); 294: for (tries = 0; ; tries++) { 295: if (soacnt == 0) { 296: /* delete unmarked (new) RR's for zone */ 297: if (tries) 298: clean_zone (hashtab, zone, 0); 299: if ((n = res_mkquery(QUERY, zp->z_origin, C_IN, 300: T_AXFR, (char *)NULL, 0, NULL, 301: buf, sizeof(buf))) < 0) { 302: syslog(LOG_ERR, "zoneref: res_mkquery failed"); 303: (void) close(s); 304: (void) sigvec(SIGALRM, &osv, 305: (struct sigvec *)0); 306: return; 307: } 308: /* 309: * Send length & message for zone transfer 310: */ 311: if (writemsg(s, buf, n) < 0) { 312: (void) close(s); 313: error++; 314: #ifdef DEBUG 315: if (debug >= 2) 316: fprintf(ddt,"writemsg failed\n"); 317: #endif 318: break; 319: } 320: } 321: /* 322: * Receive length & response 323: */ 324: cp = buf; 325: l = sizeof(u_short); 326: while (l > 0) { 327: (void) setitimer(ITIMER_REAL, &ival, 328: (struct itimerval *)NULL); 329: if ((n = recv(s, cp, l, 0)) > 0) { 330: cp += n; 331: l -= n; 332: } else { 333: if (errno == EINTR && !read_interrupted) 334: continue; 335: error++; 336: break; 337: } 338: } 339: (void) setitimer(ITIMER_REAL, &zeroival, 340: (struct itimerval *)NULL); 341: if (error) 342: break; 343: if ((len = htons(*(u_short *)buf)) == 0) 344: break; 345: l = len; 346: cp = buf; 347: eom = buf + len; 348: while (l > 0) { 349: (void) setitimer(ITIMER_REAL, &ival, 350: (struct itimerval *)NULL); 351: if ((n = recv(s, cp, l, 0)) > 0) { 352: cp += n; 353: l -= n; 354: } else { 355: if (errno == EINTR && !read_interrupted) 356: continue; 357: error++; 358: break; 359: } 360: } 361: (void) setitimer(ITIMER_REAL, &zeroival, 362: (struct itimerval *)NULL); 363: if (error) 364: break; 365: #ifdef DEBUG 366: if (debug >= 3) { 367: fprintf(ddt,"len = %d\n", len); 368: fp_query(buf, ddt); 369: } 370: #endif 371: cp = buf + sizeof(HEADER); 372: if (hp->qdcount) 373: cp += dn_skipname(cp, eom) + QFIXEDSZ; 374: nmp = cp; 375: tmp = cp + dn_skipname(cp, eom); 376: n = doupdate(buf, sizeof(buf), cp, zone, 377: (struct databuf **)0, DB_NODATA); 378: if (cp + n != eom) { 379: #ifdef DEBUG 380: if (debug) 381: fprintf(ddt,"zoneref: doupdate failed (%d, %d)\n", 382: cp - buf, n); 383: #endif 384: error++; 385: break; 386: } 387: GETSHORT(n, tmp); 388: if (n == T_SOA) { 389: if (soacnt == 0) { 390: soacnt++; 391: dn_expand(buf, buf + 512, nmp, name, 392: sizeof(name)); 393: tmp += 2 * sizeof(u_short) 394: + sizeof(u_long); 395: tmp += dn_skipname(tmp, eom); 396: tmp += dn_skipname(tmp, eom); 397: GETLONG(serial, tmp); 398: #ifdef DEBUG 399: if (debug) 400: fprintf(ddt, 401: "first SOA for %s, serial %ld\n", 402: name, serial); 403: #endif DEBUG 404: continue; 405: } 406: dn_expand(buf, buf + 512, nmp, name2, 407: sizeof(name2)); 408: if (strcasecmp(name, name2) !=0) { 409: #ifdef DEBUG 410: if (debug) 411: fprintf(ddt, 412: "extraneous SOA for %s\n", 413: name2); 414: #endif DEBUG 415: continue; 416: } 417: tmp -= sizeof(u_short); 418: soa_zinfo(&zp_finish, tmp, eom); 419: #ifdef DEBUG 420: if (debug) 421: fprintf(ddt, 422: "SOA, serial %ld\n", zp_finish.z_serial); 423: #endif DEBUG 424: if (serial != zp_finish.z_serial) { 425: soacnt = 0; 426: #ifdef DEBUG 427: if (debug) 428: fprintf(ddt, 429: "serial changed, restart\n"); 430: #endif DEBUG 431: } else 432: break; 433: } 434: } 435: (void) close(s); 436: if ( error == 0) { 437: zp->z_refresh = zp_finish.z_refresh; 438: zp->z_retry = zp_finish.z_retry; 439: zp->z_expire = zp_finish.z_expire; 440: zp->z_minimum = zp_finish.z_minimum; 441: zp->z_serial = zp_finish.z_serial; 442: zp->z_lastupdate = tt.tv_sec; 443: zp->z_sysloged = 0; 444: zp->z_auth = 1; 445: /* delete previously marked RR's here, then dump */ 446: clean_zone (hashtab, zone, 1); 447: zonedump(zp); 448: (void) sigvec(SIGALRM, &osv, (struct sigvec *)0); 449: return; 450: } 451: /* error: delete unmarked RR's here; remove old marks */ 452: clean_zone (hashtab, zone, 0); 453: mark_zone (hashtab, zone, 0); 454: #ifdef DEBUG 455: if (debug >= 2) 456: fprintf(ddt,"error receiving zone transfer\n"); 457: #endif 458: } 459: (void) sigvec(SIGALRM, &osv, (struct sigvec *)0); 460: /* 461: * Freedom at last!! 462: * 463: * The land where all repressed slaves dream of. 464: * 465: * Can't find a master to talk to. 466: * syslog it and hope we can find a master during next maintenance. 467: */ 468: if (error && (!zp->z_sysloged)) { 469: syslog(LOG_WARNING, 470: "zoneref: Masters for secondary zone %s unreachable", 471: zp->z_origin); 472: zp->z_sysloged++; 473: } 474: zp->z_refresh = zp->z_retry; 475: if (tt.tv_sec - zp->z_lastupdate > zp->z_expire) 476: zp->z_auth = 0; 477: } 478: 479: #ifdef unused 480: /* 481: * Recursively delete all domains (except for root SOA records), 482: * starting from head of list pointed to by np. 483: */ 484: static DelDom(fnp, isroot) 485: struct namebuf *fnp; 486: int isroot; 487: { 488: register struct databuf *dp, *pdp = NULL; 489: register struct namebuf *np = fnp; 490: struct namebuf **npp, **nppend; 491: 492: #ifdef DEBUG 493: if (debug >= 3) 494: fprintf(ddt, "DelDom('%s', %d)\n", fnp->n_dname, isroot); 495: #endif DEBUG 496: 497: /* first do data records */ 498: for (dp = np->n_data; dp != NULL; ) { 499: /* skip the root SOA record (marks end of data) */ 500: if (isroot && dp->d_type == T_SOA) { 501: pdp = dp; 502: dp = dp->d_next; 503: continue; 504: } 505: dp = rm_datum(dp, np, pdp); 506: } 507: 508: /* next do subdomains */ 509: if (np->n_hash == NULL) 510: return; 511: npp = np->n_hash->h_tab; 512: nppend = npp + np->n_hash->h_size; 513: while (npp < nppend) { 514: for (np = *npp++; np != NULL; np = np->n_next) { 515: DelDom(np, 0); 516: } 517: } 518: } 519: #endif unused 520: 521: #ifdef DEBUG 522: printzoneinfo(zonenum) 523: int zonenum; 524: { 525: struct timeval tt; 526: struct zoneinfo *zp = &zones[zonenum]; 527: char *ZoneType; 528: 529: if (!debug) 530: return; /* Else fprintf to ddt will bomb */ 531: fprintf(ddt, "printzoneinfo(%d):\n", zonenum); 532: 533: gettime(&tt); 534: switch (zp->z_type) { 535: case Z_PRIMARY: ZoneType = "Primary"; break; 536: case Z_SECONDARY: ZoneType = "Secondary"; break; 537: case Z_CACHE: ZoneType = "Cache"; break; 538: default: ZoneType = "Unknown"; 539: } 540: if (zp->z_origin[0] == '\0') 541: fprintf(ddt,"origin ='.'"); 542: else 543: fprintf(ddt,"origin ='%s'", zp->z_origin); 544: fprintf(ddt,", type = %s", ZoneType); 545: fprintf(ddt,", source = %s\n", zp->z_source); 546: fprintf(ddt,"z_refresh = %ld", zp->z_refresh); 547: fprintf(ddt,", retry = %ld", zp->z_retry); 548: fprintf(ddt,", expire = %ld", zp->z_expire); 549: fprintf(ddt,", minimum = %ld", zp->z_minimum); 550: fprintf(ddt,", serial = %ld\n", zp->z_serial); 551: fprintf(ddt,"z_time = %ld", zp->z_time); 552: fprintf(ddt,", now time : %ld sec", tt.tv_sec); 553: fprintf(ddt,", time left: %ld sec\n", zp->z_time - tt.tv_sec); 554: } 555: #endif DEBUG 556: 557: /* 558: * New code added by Rich Wales (UCLA), October 1986: 559: * 560: * The following routines manipulate the d_mark field. When a zone 561: * is being refreshed, the old RR's are marked. This allows old RR's to 562: * be cleaned up after the new copy of the zone has been completely read 563: * -- or new RR's to be cleaned up if an error prevents transfer of a 564: * new zone copy. 565: * 566: */ 567: 568: /* 569: * Set the "d_mark" field to on each RR in the zone "zone". 570: * Initially called with "htp" equal to "hashtab", this routine 571: * calls itself recursively in order to traverse all subdomains. 572: */ 573: mark_zone (htp, zone, flag) 574: struct hashbuf *htp; 575: register int zone; 576: register int flag; 577: { 578: register struct databuf *dp; 579: register struct namebuf *np; 580: register struct namebuf **npp, **nppend; 581: 582: nppend = htp->h_tab + htp->h_size; 583: for (npp = htp->h_tab; npp < nppend; npp++) { 584: for (np = *npp; np != NULL; np = np->n_next) { 585: for (dp = np->n_data; dp != NULL; dp = dp->d_next) 586: if (dp->d_zone == zone) 587: dp->d_mark = flag; 588: if (np->n_hash != NULL) /* mark subdomains */ 589: mark_zone (np->n_hash, zone, flag); 590: } 591: } 592: } 593: 594: /* 595: * clean_zone (htp, zone, flag) -- 596: * Delete all RR's in the zone "zone" whose "d_mark" values are 597: * equal to "flag". Originally called with "htp" equal to 598: * "hashtab", this routine calls itself recursively in order to 599: * traverse all subdomains. 600: */ 601: clean_zone (htp, zone, flag) 602: register struct hashbuf *htp; 603: register int zone; 604: register int flag; 605: { 606: register struct databuf *dp, *pdp; 607: register struct namebuf *np; 608: struct namebuf **npp, **nppend; 609: 610: nppend = htp->h_tab + htp->h_size; 611: for (npp = htp->h_tab; npp < nppend; npp++) { 612: for (np = *npp; np != NULL; np = np->n_next) { 613: for (pdp = NULL, dp = np->n_data; dp != NULL; ) { 614: if (dp->d_zone == zone && dp->d_mark == flag) 615: dp = rm_datum(dp, np, pdp); 616: else { 617: pdp = dp; 618: dp = dp->d_next; 619: } 620: } 621: /* Call recursively to clean up subdomains. */ 622: if (np->n_hash != NULL) 623: clean_zone (np->n_hash, zone, flag); 624: } 625: } 626: }