|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1986, 1988, 1990 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_req.c 4.44 (Berkeley) 6/27/90"; ! 22: #endif /* not lint */ ! 23: ! 24: #include <stdio.h> ! 25: #include <sys/param.h> ! 26: #include <sys/uio.h> ! 27: #include <sys/time.h> ! 28: #include <sys/socket.h> ! 29: #include <netinet/in.h> ! 30: #include <syslog.h> ! 31: #include <sys/file.h> ! 32: #include <arpa/nameser.h> ! 33: #include "ns.h" ! 34: #include "db.h" ! 35: ! 36: #define NADDRECS 20 ! 37: ! 38: extern int debug; ! 39: extern FILE *ddt; ! 40: ! 41: struct addinfo { ! 42: char *a_dname; /* domain name */ ! 43: u_short a_class; /* class for address */ ! 44: }; ! 45: ! 46: struct addinfo addinfo[NADDRECS]; /* additional info records */ ! 47: int addcount; /* number of names in addinfo */ ! 48: int xfr_disabled = 0; /* set to disable zone xfrs */ ! 49: int needs_prime_cache = 0; /* set if we need a priming */ ! 50: ! 51: u_char *dnptrs[20]; /* ptrs to dnames in message for dn_comp */ ! 52: ! 53: extern time_t retrytime(); ! 54: extern struct qinfo *sysquery(); ! 55: extern char *localdomain; /* XXX */ ! 56: extern int errno; ! 57: /* ! 58: * Process request using database; assemble and send response. ! 59: */ ! 60: ns_req(msg, msglen, buflen, qsp, from, dfd) ! 61: u_char *msg; ! 62: int msglen, buflen; ! 63: struct qstream *qsp; ! 64: struct sockaddr_in *from; ! 65: int dfd; ! 66: { ! 67: register HEADER *hp; ! 68: register u_char *cp; ! 69: struct namebuf *np; ! 70: register struct databuf *dp; ! 71: struct hashbuf *htp; ! 72: struct netinfo *lp; ! 73: char *fname, *answers; ! 74: u_char *eom, *omsg; ! 75: char dnbuf[MAXDNAME], *dname; ! 76: u_char **dpp; ! 77: int n, class, type, count, foundname, founddata, omsglen, cname = 0; ! 78: u_short id; ! 79: struct databuf *nsp[NSMAX]; ! 80: struct qinfo *qp; ! 81: extern struct qinfo *qhead; ! 82: extern struct netinfo *local(); ! 83: extern int nsid; ! 84: ! 85: #ifdef DEBUG ! 86: if (debug > 3) { ! 87: fprintf(ddt,"ns_req()\n"); ! 88: fp_query(msg, ddt); ! 89: } ! 90: #endif ! 91: ! 92: hp = (HEADER *) msg; ! 93: if (hp->qr) { ! 94: ns_resp(msg, msglen); ! 95: ! 96: /* Now is a safe time for housekeeping */ ! 97: if (needs_prime_cache) ! 98: prime_cache(); ! 99: return; ! 100: } ! 101: ! 102: hp->rcode = NOERROR; ! 103: cp = msg + sizeof(HEADER); ! 104: eom = msg + msglen; ! 105: dpp = dnptrs; ! 106: *dpp++ = msg; ! 107: addcount = 0; ! 108: ! 109: switch (hp->opcode) { ! 110: case QUERY: ! 111: #ifdef STATS ! 112: stats[S_QUERIES].cnt++; ! 113: #endif ! 114: if (ntohs(hp->qdcount) != 1 || ! 115: hp->ancount || hp->nscount || hp->arcount) { ! 116: #ifdef DEBUG ! 117: if (debug) ! 118: fprintf(ddt,"FORMERR Query header counts wrong\n"); ! 119: #endif ! 120: hp->qdcount = 0; ! 121: hp->ancount = 0; ! 122: hp->nscount = 0; ! 123: hp->arcount = 0; ! 124: hp->rcode = FORMERR; ! 125: goto finish; ! 126: } ! 127: /* ! 128: * Get domain name, class, and type. ! 129: */ ! 130: if ((*cp & INDIR_MASK) == 0) ! 131: *dpp++ = cp; /* remember name for compression */ ! 132: *dpp = NULL; ! 133: if ((n = dn_expand(msg, eom, cp, dnbuf, ! 134: sizeof(dnbuf))) < 0) { ! 135: #ifdef DEBUG ! 136: if (debug) ! 137: fprintf(ddt,"FORMERR Query expand name failed\n"); ! 138: #endif ! 139: hp->rcode = FORMERR; ! 140: goto finish; ! 141: } ! 142: cp += n; ! 143: GETSHORT(type, cp); ! 144: GETSHORT(class, cp); ! 145: if (cp > eom) { ! 146: #ifdef DEBUG ! 147: if (debug) ! 148: fprintf(ddt,"FORMERR Query message length short\n"); ! 149: #endif ! 150: hp->rcode = FORMERR; ! 151: goto finish; ! 152: } ! 153: #ifdef DEBUG ! 154: if (cp < eom) ! 155: if (debug > 5) ! 156: fprintf(ddt,"message length > received message\n"); ! 157: #endif ! 158: ! 159: #ifdef STATS ! 160: if ((type > T_ANY) || (type < 0)) ! 161: typestats[0]++; /* Bad type */ ! 162: else ! 163: typestats[type]++; ! 164: #endif ! 165: /* ! 166: * Process query. ! 167: */ ! 168: if (type == T_AXFR) { ! 169: /* refuse request if not a TCP connection */ ! 170: if (qsp == QSTREAM_NULL || xfr_disabled) { ! 171: #ifdef DEBUG ! 172: if (debug) ! 173: fprintf(ddt,"T_AXFR via UDP refused\n"); ! 174: #endif ! 175: hp->rcode = REFUSED; ! 176: goto finish; ! 177: } ! 178: dnptrs[0] = NULL; /* don't compress names */ ! 179: hp->rd = 0; /* recursion not possible */ ! 180: } ! 181: buflen -= msglen; ! 182: count = 0; ! 183: foundname = 0; ! 184: founddata = 0; ! 185: dname = dnbuf; ! 186: try_again: ! 187: #ifdef DEBUG ! 188: if (debug) ! 189: fprintf(ddt,"req: nlookup(%s) id %d type=%d\n", ! 190: dname, hp->id, type); ! 191: #endif ! 192: htp = hashtab; /* lookup relative to root */ ! 193: if ((np = nlookup(dname, &htp, &fname, 0)) == NULL) ! 194: fname = ""; ! 195: #ifdef DEBUG ! 196: if (debug) ! 197: fprintf(ddt,"req: %s '%s' as '%s' (cname=%d)\n", ! 198: np == NULL ? "missed" : "found", ! 199: dname, fname, cname); ! 200: #endif ! 201: /* START XXX */ ! 202: /* ! 203: * if nlookup failed to find address then ! 204: * see if there are any '.''s in the name ! 205: * if not then add local domain name to the ! 206: * name and try again. ! 207: */ ! 208: if (np == NULL && localdomain && index(dname, '.') == NULL) { ! 209: (void) strcat(dname,"."); ! 210: (void) strcat(dname, localdomain); ! 211: #ifdef DEBUG ! 212: if (debug) ! 213: fprintf(ddt,"req: nlookup(%s) type=%d\n", ! 214: dname, type); ! 215: #endif ! 216: htp = hashtab; ! 217: np = nlookup(dname, &htp, &fname, 0); ! 218: } ! 219: /* END XXX */ ! 220: if (np == NULL || fname != dname) ! 221: goto fetchns; ! 222: ! 223: foundname++; ! 224: answers = (char *)cp; ! 225: count = cp - msg; ! 226: n = finddata(np, class, type, hp, &dname, &buflen, &count); ! 227: if (n == 0) ! 228: goto fetchns; /* NO data available */ ! 229: cp += n; ! 230: buflen -= n; ! 231: msglen += n; ! 232: hp->ancount += count; ! 233: if (fname != dname && type != T_CNAME && type != T_ANY) { ! 234: if (cname++ >= MAXCNAMES) { ! 235: #ifdef DEBUG ! 236: if (debug >= 3) ! 237: fprintf(ddt, ! 238: "resp: leaving, MAXCNAMES exceeded\n"); ! 239: #endif ! 240: hp->rcode = SERVFAIL; ! 241: goto finish; ! 242: } ! 243: goto try_again; ! 244: } ! 245: founddata = 1; ! 246: #ifdef DEBUG ! 247: if (debug >= 3) { ! 248: fprintf(ddt,"req: foundname = %d count = %d ", foundname, count); ! 249: fprintf(ddt,"founddata = %d cname = %d\n",founddata, cname); ! 250: } ! 251: #endif ! 252: if ((lp = local(from)) != NULL) ! 253: sort_response(answers, count, lp, cp); ! 254: if (type == T_AXFR) { ! 255: if (founddata) { ! 256: hp->ancount = htons(hp->ancount); ! 257: startxfr(qsp, np, msg, cp - msg); ! 258: return; ! 259: } ! 260: hp->rcode = REFUSED; /* No go if unauthoritative */ ! 261: goto finish; ! 262: } ! 263: #ifdef notdef ! 264: /* ! 265: * If we found an authoritative answer, ! 266: * we're done. ! 267: */ ! 268: if (hp->aa) ! 269: goto finish; ! 270: #endif ! 271: ! 272: fetchns: ! 273: /* ! 274: * Look for name servers to refer to and fill in the authority ! 275: * section or record the address for forwarding the query ! 276: * (recursion desired). ! 277: */ ! 278: nsp[0] = NULL; ! 279: switch (findns(&np, class, nsp, &count)) { ! 280: case NXDOMAIN: ! 281: if (!foundname) ! 282: hp->rcode = NXDOMAIN; ! 283: #ifdef DEBUG ! 284: if (debug >= 3) ! 285: fprintf(ddt,"req: leaving (%s, rcode %d)\n", ! 286: dname, hp->rcode); ! 287: #endif ! 288: if (class != C_ANY) { ! 289: hp->aa = 1; ! 290: /* XXX ! 291: * should return SOA if founddata == 0, ! 292: * but old named's are confused by an SOA ! 293: * in the auth. section if there's no error. ! 294: */ ! 295: if (foundname == 0 && np) { ! 296: n = doaddauth(hp, cp, buflen, np, nsp[0]); ! 297: cp += n; ! 298: buflen -= n; ! 299: } ! 300: } ! 301: goto finish; ! 302: ! 303: case SERVFAIL: ! 304: if (!founddata) { ! 305: hp->rcode = SERVFAIL; ! 306: goto finish; ! 307: } ! 308: } ! 309: ! 310: /* ! 311: * If we successfully found the answer in the cache ! 312: * or this is not a recursive query, then add the ! 313: * nameserver references here and return. ! 314: */ ! 315: if (founddata || (!hp->rd)) { ! 316: n = add_data(np, nsp, cp, buflen); ! 317: if (n < 0) { ! 318: hp->tc = 1; ! 319: n = (-n); ! 320: } ! 321: cp += n; ! 322: buflen -= n; ! 323: hp->nscount = htons((u_short)count); ! 324: goto finish; ! 325: } ! 326: ! 327: /* ! 328: * At this point, we don't have the answer, but we do ! 329: * have some NS's to try. If the user would like us ! 330: * to recurse, create the initial query. If a cname ! 331: * is involved, we need to build a new query and save ! 332: * the old one in cmsg/cmsglen. ! 333: */ ! 334: if (cname) { ! 335: omsg = (u_char *)malloc((unsigned)msglen); ! 336: if (omsg == (u_char *)NULL) { ! 337: #ifdef DEBUG ! 338: if (debug) ! 339: fprintf(ddt,"ns_req: malloc fail\n"); ! 340: #endif ! 341: syslog(LOG_ERR, "ns_req: Out Of Memory"); ! 342: hp->rcode = SERVFAIL; ! 343: break; ! 344: } ! 345: id = hp->id; ! 346: hp->ancount = htons(hp->ancount); ! 347: bcopy(msg, omsg, omsglen = msglen); ! 348: msglen = res_mkquery(QUERY, dname, class, type, ! 349: (char *)NULL, 0, NULL, msg, msglen+buflen); ! 350: } ! 351: n = ns_forw(nsp, msg, msglen, from, qsp, dfd, &qp); ! 352: if (n != FW_OK && cname) ! 353: free(omsg); ! 354: switch (n) { ! 355: case FW_OK: ! 356: if (cname) { ! 357: qp->q_cname = cname; ! 358: qp->q_cmsg = (char *)omsg; ! 359: qp->q_cmsglen = omsglen; ! 360: qp->q_id = id; ! 361: } ! 362: break; ! 363: case FW_DUP: ! 364: break; /* Duplicate request dropped */ ! 365: case FW_NOSERVER: ! 366: if(np) ! 367: np = np->n_parent; ! 368: goto fetchns; /* Try again. */ ! 369: case FW_SERVFAIL: ! 370: hp->rcode = SERVFAIL; ! 371: goto finish; ! 372: } ! 373: /* Now is a safe time for housekeeping */ ! 374: if (needs_prime_cache) ! 375: prime_cache(); ! 376: return; ! 377: ! 378: case IQUERY: { ! 379: register struct invbuf *ip; ! 380: register int i; ! 381: int dlen, alen; ! 382: char anbuf[PACKETSZ], *data; ! 383: ! 384: #ifdef STATS ! 385: stats[S_IQUERIES].cnt++; ! 386: #endif ! 387: hp->ancount = htons(hp->ancount); ! 388: if (hp->ancount != 1 || ! 389: hp->qdcount || hp->nscount || hp->arcount) { ! 390: #ifdef DEBUG ! 391: if (debug) ! 392: fprintf(ddt,"FORMERR IQuery header counts wrong\n"); ! 393: #endif ! 394: hp->qdcount = 0; ! 395: hp->ancount = 0; ! 396: hp->nscount = 0; ! 397: hp->arcount = 0; ! 398: hp->rcode = FORMERR; ! 399: goto finish; ! 400: } ! 401: /* ! 402: * Skip domain name, get class, and type. ! 403: */ ! 404: if ((n = dn_skipname(cp, eom)) < 0) { ! 405: #ifdef DEBUG ! 406: if (debug) ! 407: fprintf(ddt,"FORMERR IQuery packet name problem\n"); ! 408: #endif ! 409: hp->rcode = FORMERR; ! 410: goto finish; ! 411: } ! 412: cp += n; ! 413: GETSHORT(type, cp); ! 414: GETSHORT(class, cp); ! 415: cp += sizeof(u_long); ! 416: GETSHORT(dlen, cp); ! 417: cp += dlen; ! 418: if (cp != eom) { ! 419: #ifdef DEBUG ! 420: if (debug) ! 421: fprintf(ddt,"FORMERR IQuery message length off\n"); ! 422: #endif ! 423: hp->rcode = FORMERR; ! 424: goto finish; ! 425: } ! 426: /* not all inverse queries are handled. */ ! 427: switch (type) { ! 428: case T_A: ! 429: case T_UID: ! 430: case T_GID: ! 431: break; ! 432: ! 433: default: ! 434: hp->rcode = REFUSED; ! 435: goto finish; ! 436: } ! 437: #ifdef DEBUG ! 438: if (debug) ! 439: fprintf(ddt,"req: IQuery class %d type %d\n", ! 440: class, type); ! 441: #endif ! 442: fname = (char *)msg + sizeof(HEADER); ! 443: bcopy(fname, anbuf, alen = (char *)cp - fname); ! 444: data = anbuf + alen - dlen; ! 445: cp = (u_char *)fname; ! 446: buflen -= sizeof(HEADER); ! 447: count = 0; ! 448: for (ip = invtab[dhash(data, dlen)]; ip != NULL; ! 449: ip = ip->i_next) { ! 450: for (i = 0; i < INVBLKSZ; i++) { ! 451: if ((np = ip->i_dname[i]) == NULL) ! 452: break; ! 453: #ifdef DEBUG ! 454: if (debug >= 5) ! 455: fprintf(ddt,"dname = %d\n", np->n_dname); ! 456: #endif ! 457: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { ! 458: if (!match(dp, class, type)) ! 459: continue; ! 460: if (dp->d_size != dlen || ! 461: bcmp(dp->d_data, data, dlen)) ! 462: continue; ! 463: getname(np, dnbuf, sizeof(dnbuf)); ! 464: #ifdef DEBUG ! 465: if (debug > 2) ! 466: fprintf(ddt,"req: IQuery found %s\n", ! 467: dnbuf); ! 468: #endif ! 469: buflen -= QFIXEDSZ; ! 470: if ((n = ! 471: dn_comp(dnbuf, cp, buflen, (char **)NULL, ! 472: (char **)NULL)) < 0) ! 473: { ! 474: hp->tc = 1; ! 475: goto finish; ! 476: } ! 477: cp += n; ! 478: PUTSHORT((u_short)dp->d_type, cp); ! 479: PUTSHORT((u_short)dp->d_class, cp); ! 480: buflen -= n; ! 481: count++; ! 482: } ! 483: } ! 484: } ! 485: #ifdef DEBUG ! 486: if (debug) ! 487: fprintf(ddt,"req: IQuery %d records\n", count); ! 488: #endif ! 489: hp->qdcount = htons((u_short)count); ! 490: if (alen > buflen) { ! 491: hp->tc = 1; ! 492: break; ! 493: } ! 494: bcopy(anbuf, cp, alen); ! 495: cp += alen; ! 496: break; ! 497: } ! 498: ! 499: #ifdef ALLOW_UPDATES ! 500: /* ! 501: * In a sense the following constant should be defined in <arpa/nameser.h>, ! 502: * since it is returned here in place of a response code if the update was ! 503: * forwarded, and the response codes are defined in nameser.h. On the other ! 504: * hand, though, this constant is only seen in this file. The assumption ! 505: * here is that none of the other return codes equals this one (a good ! 506: * assumption, since they only occupy 4 bits over-the-wire) ! 507: */ ! 508: #define FORWARDED 1000 ! 509: /* Call InitDynUpdate for all dynamic update requests */ ! 510: case UPDATEM: ! 511: case UPDATEMA: ! 512: case UPDATED: ! 513: case UPDATEDA: ! 514: case UPDATEA: ! 515: n = InitDynUpdate(hp, nsp, msg, msglen, cp, from, qsp, dfd); ! 516: if (n == FORWARDED) ! 517: return; /* Return directly because InitDynUpdate ! 518: * forwarded the query to the primary, so we ! 519: * will send response later ! 520: */ ! 521: else ! 522: break; /* Either sucessful primary update or failure; ! 523: * return response code to client ! 524: */ ! 525: #endif ALLOW_UPDATES ! 526: ! 527: case ZONEREF: ! 528: #ifdef DEBUG ! 529: if (debug) ! 530: fprintf(ddt,"Refresh Zone\n"); ! 531: #endif ! 532: ! 533: default: ! 534: #ifdef DEBUG ! 535: if (debug >= 2) ! 536: fprintf(ddt,"Opcode %d not implemented\n", hp->opcode); ! 537: #endif ! 538: hp->qdcount = 0; ! 539: hp->ancount = 0; ! 540: hp->nscount = 0; ! 541: hp->arcount = 0; ! 542: hp->rcode = NOTIMP; ! 543: } ! 544: finish: ! 545: #ifdef STATS ! 546: switch(hp->rcode) { ! 547: case NOERROR: ! 548: stats[S_RESPOK].cnt++; ! 549: break; ! 550: case FORMERR: ! 551: stats[S_RESPFORMERR].cnt++; ! 552: break; ! 553: default: ! 554: stats[S_RESPFAIL].cnt++; ! 555: break; ! 556: } ! 557: #endif ! 558: hp->qr = 1; /* set Response flag */ ! 559: hp->ra = 1; /* Recursion is Available */ ! 560: hp->ancount = htons(hp->ancount); ! 561: if (addcount) { ! 562: n = doaddinfo(hp, cp, buflen); ! 563: cp += n; ! 564: buflen -= n; ! 565: } ! 566: ! 567: #ifdef DEBUG ! 568: if (debug) { ! 569: fprintf(ddt,"req: answer -> %s %d (%d) id=%d %s\n", ! 570: inet_ntoa(from->sin_addr), ! 571: qsp == QSTREAM_NULL ? dfd : qsp->s_rfd, ! 572: ntohs(from->sin_port), ! 573: ntohs(hp->id), local(from) == NULL ? "Remote" : "Local"); ! 574: } ! 575: if (debug >= 10) ! 576: fp_query(msg, ddt); ! 577: #endif DEBUG ! 578: if (qsp == QSTREAM_NULL) { ! 579: if (sendto(dfd, msg, cp-msg, 0, (struct sockaddr *)from, ! 580: sizeof(*from))< 0){ ! 581: #ifdef DEBUG ! 582: if (debug) ! 583: fprintf(ddt,"error returning msg errno=%d\n",errno); ! 584: #endif DEBUG ! 585: } ! 586: #ifdef STATS ! 587: stats[S_OUTPKTS].cnt++; ! 588: #endif ! 589: } else { ! 590: (void) writemsg(qsp->s_rfd, msg, cp - msg); ! 591: sq_done(qsp); ! 592: } ! 593: if (needs_prime_cache) ! 594: prime_cache(); /* Now is a safe time */ ! 595: } ! 596: ! 597: fwritemsg(rfp, msg, msglen) ! 598: FILE *rfp; ! 599: char *msg; ! 600: int msglen; ! 601: { ! 602: u_short len = htons((u_short)msglen); ! 603: ! 604: if (fwrite((char *)&len, sizeof(len), 1, rfp) != 1 || ! 605: fwrite(msg, msglen, 1, rfp) != 1) { ! 606: #ifdef DEBUG ! 607: if (debug) ! 608: fprintf(ddt,"fwrite failed %d\n", errno); ! 609: #endif ! 610: } ! 611: return; ! 612: } ! 613: ! 614: writemsg(rfd, msg, msglen) ! 615: int rfd; ! 616: char *msg; ! 617: int msglen; ! 618: { ! 619: struct iovec iov[2]; ! 620: u_short len = htons((u_short)msglen); ! 621: ! 622: iov[0].iov_base = (caddr_t)&len; ! 623: iov[0].iov_len = sizeof(len); ! 624: iov[1].iov_base = msg; ! 625: iov[1].iov_len = msglen; ! 626: if (writev(rfd, iov, 2) != sizeof(len) + msglen) { ! 627: #ifdef DEBUG ! 628: if (debug) ! 629: fprintf(ddt,"write failed %d\n", errno); ! 630: #endif ! 631: return (-1); ! 632: } ! 633: return (0); ! 634: } ! 635: ! 636: /* ! 637: * Test a datum for validity and return non-zero if it is out of date. ! 638: */ ! 639: stale(dp) ! 640: register struct databuf *dp; ! 641: { ! 642: register struct zoneinfo *zp = &zones[dp->d_zone]; ! 643: ! 644: switch (zp->z_type) { ! 645: ! 646: case Z_PRIMARY: ! 647: return (0); ! 648: ! 649: case Z_SECONDARY: ! 650: /* ! 651: * Check to see whether a secondary zone ! 652: * has expired; if so clear authority flag ! 653: * for zone and return true. If lastupdate ! 654: * is in the future, assume zone is up-to-date. ! 655: */ ! 656: if ((long)(tt.tv_sec - zp->z_lastupdate) > (long)zp->z_expire) { ! 657: #ifdef DEBUG ! 658: if (debug) ! 659: fprintf(ddt, ! 660: "stale: secondary zone %s expired\n", ! 661: zp->z_origin); ! 662: #endif ! 663: syslog(LOG_ERR, "secondary zone \"%s\" expired\n", ! 664: zp->z_origin); ! 665: zp->z_auth = 0; ! 666: return (1); ! 667: } ! 668: return (0); ! 669: ! 670: case Z_CACHE: ! 671: #ifdef DEBUG ! 672: if (debug >= 3) ! 673: fprintf(ddt,"stale: ttl %d %d (x%x)\n", ! 674: dp->d_ttl, dp->d_ttl - tt.tv_sec, dp->d_flags); ! 675: #endif ! 676: if (dp->d_flags & DB_F_HINT) ! 677: return(0); ! 678: return(dp->d_ttl < tt.tv_sec); ! 679: ! 680: } ! 681: /* NOTREACHED */ ! 682: } ! 683: ! 684: /* ! 685: * Copy databuf into a resource record for replies. ! 686: * Return size of RR if OK, -1 if buffer is full. ! 687: */ ! 688: make_rr(name, dp, buf, buflen, doadd) ! 689: char *name; ! 690: register struct databuf *dp; ! 691: char *buf; ! 692: int buflen, doadd; ! 693: { ! 694: register char *cp; ! 695: char *cp1, *sp; ! 696: struct zoneinfo *zp; ! 697: register long n; ! 698: register long ttl; ! 699: u_char **edp = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]); ! 700: ! 701: #ifdef DEBUG ! 702: if (debug >= 5) ! 703: fprintf(ddt,"make_rr(%s, %x, %x, %d, %d) %d zone %d ttl %d\n", ! 704: name, dp, buf, ! 705: buflen, doadd, dp->d_size, dp->d_zone, dp->d_ttl); ! 706: #endif ! 707: ! 708: zp = &zones[dp->d_zone]; ! 709: /* check for outdated RR before updating dnptrs by dn_comp() (???) */ ! 710: if (zp->z_type == Z_CACHE) { ! 711: ttl = dp->d_ttl - (u_long) tt.tv_sec; ! 712: if ((dp->d_flags & DB_F_HINT) || (ttl < 0)) { ! 713: #ifdef DEBUG ! 714: /*XXX*/if (debug >= 3) fprintf(ddt,"make_rr: %d=>0, x%x\n", ttl, dp->d_flags); ! 715: #endif ! 716: ttl = 0; ! 717: } ! 718: } else { ! 719: if (dp->d_ttl) ! 720: ttl = dp->d_ttl; ! 721: else ! 722: ttl = zp->z_minimum; /* really default */ ! 723: #ifdef notdef /* don't decrease ttl based on time since verification */ ! 724: if (zp->z_type == Z_SECONDARY) { ! 725: /* ! 726: * Set ttl to value received from primary, ! 727: * less time since we verified it (but never ! 728: * less than a small positive value). ! 729: */ ! 730: ttl -= tt.tv_sec - zp->z_lastupdate; ! 731: if (ttl <= 0) ! 732: ttl = 120; ! 733: } ! 734: #endif ! 735: } ! 736: ! 737: buflen -= RRFIXEDSZ; ! 738: if ((n = dn_comp(name, buf, buflen, (char **)dnptrs, (char **)edp)) < 0) ! 739: return (-1); ! 740: cp = buf + n; ! 741: buflen -= n; ! 742: PUTSHORT((u_short)dp->d_type, cp); ! 743: PUTSHORT((u_short)dp->d_class, cp); ! 744: PUTLONG(ttl, cp); ! 745: sp = cp; ! 746: cp += sizeof(u_short); ! 747: switch (dp->d_type) { ! 748: case T_CNAME: ! 749: case T_MG: ! 750: case T_MR: ! 751: case T_PTR: ! 752: if ((n = dn_comp(dp->d_data, cp, buflen, (char **)dnptrs, ! 753: (char **)edp)) < 0) ! 754: return (-1); ! 755: PUTSHORT((u_short)n, sp); ! 756: cp += n; ! 757: break; ! 758: ! 759: case T_MB: ! 760: case T_NS: ! 761: /* Store domain name in answer */ ! 762: if ((n = dn_comp(dp->d_data, cp, buflen, (char **)dnptrs, ! 763: (char **)edp)) < 0) ! 764: return (-1); ! 765: PUTSHORT((u_short)n, sp); ! 766: cp += n; ! 767: if (doadd) ! 768: addname(dp->d_data, dp->d_class); ! 769: break; ! 770: ! 771: case T_SOA: ! 772: case T_MINFO: ! 773: cp1 = dp->d_data; ! 774: if ((n = dn_comp(cp1, cp, buflen, (char **)dnptrs, ! 775: (char **)edp)) < 0) ! 776: return (-1); ! 777: cp += n; ! 778: buflen -= dp->d_type == T_MINFO ? n : n + 5 * sizeof(u_long); ! 779: cp1 += strlen(cp1) + 1; ! 780: if ((n = dn_comp(cp1, cp, buflen, (char **)dnptrs, ! 781: (char **)edp)) < 0) ! 782: return (-1); ! 783: cp += n; ! 784: if (dp->d_type == T_SOA) { ! 785: cp1 += strlen(cp1) + 1; ! 786: bcopy(cp1, cp, ! 787: (int)(n = dp->d_size - (cp1 - dp->d_data))); ! 788: cp += n; ! 789: } ! 790: n = (u_short)(cp - sp) - sizeof(u_short); ! 791: PUTSHORT((u_short)n, sp); ! 792: break; ! 793: ! 794: case T_MX: ! 795: /* cp1 == our data/ cp == data of RR */ ! 796: cp1 = dp->d_data; ! 797: ! 798: /* copy preference */ ! 799: bcopy(cp1,cp,sizeof(u_short)); ! 800: cp += sizeof(u_short); ! 801: cp1 += sizeof(u_short); ! 802: buflen -= sizeof(u_short); ! 803: ! 804: if ((n = dn_comp(cp1, cp, buflen, (char **)dnptrs, ! 805: (char **)edp)) < 0) ! 806: return(-1); ! 807: cp += n; ! 808: ! 809: /* save data length */ ! 810: n = (u_short)(cp - sp) - sizeof(u_short); ! 811: PUTSHORT((u_short)n, sp); ! 812: if (doadd) ! 813: addname(cp1, dp->d_class); ! 814: break; ! 815: ! 816: default: ! 817: if (dp->d_size > buflen) ! 818: return (-1); ! 819: bcopy(dp->d_data, cp, dp->d_size); ! 820: PUTSHORT((u_short)dp->d_size, sp); ! 821: cp += dp->d_size; ! 822: } ! 823: return (cp - buf); ! 824: } ! 825: ! 826: addname(name, class) ! 827: register char *name; ! 828: short class; ! 829: { ! 830: register struct addinfo *ap; ! 831: register int n; ! 832: ! 833: for (ap = addinfo, n = addcount; --n >= 0; ap++) ! 834: if (strcasecmp(ap->a_dname, name) == 0) ! 835: return; ! 836: /* add domain name to additional section */ ! 837: if (addcount < NADDRECS) { ! 838: addcount++; ! 839: ap->a_dname = name; ! 840: ap->a_class = class; ! 841: } ! 842: } ! 843: ! 844: /* ! 845: * Lookup addresses for names in addinfo and put into the message's ! 846: * additional section. ! 847: */ ! 848: doaddinfo(hp, msg, msglen) ! 849: HEADER *hp; ! 850: char *msg; ! 851: int msglen; ! 852: { ! 853: register struct namebuf *np; ! 854: register struct databuf *dp; ! 855: register struct addinfo *ap; ! 856: register char *cp; ! 857: struct hashbuf *htp; ! 858: char *fname; ! 859: int n, count, foundstale; ! 860: ! 861: #ifdef DEBUG ! 862: if (debug >= 3) ! 863: fprintf(ddt,"doaddinfo() addcount = %d\n", addcount); ! 864: #endif ! 865: ! 866: count = 0; ! 867: cp = msg; ! 868: for (ap = addinfo; --addcount >= 0; ap++) { ! 869: #ifdef DEBUG ! 870: if (debug >= 3) ! 871: fprintf(ddt,"do additional '%s'\n", ap->a_dname); ! 872: #endif ! 873: htp = hashtab; /* because "nlookup" stomps on arg. */ ! 874: np = nlookup(ap->a_dname, &htp, &fname, 0); ! 875: if (np == NULL || fname != ap->a_dname) ! 876: continue; ! 877: #ifdef DEBUG ! 878: if (debug >= 3) ! 879: fprintf(ddt,"found it\n"); ! 880: #endif ! 881: foundstale = 0; ! 882: /* look for the data */ ! 883: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { ! 884: if (!match(dp, (int)ap->a_class, T_A)) ! 885: continue; ! 886: if (stale(dp)) { ! 887: foundstale++; ! 888: #ifdef DEBUG ! 889: if (debug) ! 890: fprintf(ddt,"doaddinfo: stale entry '%s'%s\n", ! 891: np->n_dname, ! 892: (dp->d_flags&DB_F_HINT) ? " hint":"" ); ! 893: #endif ! 894: continue; ! 895: } ! 896: /* ! 897: * Should be smart and eliminate duplicate ! 898: * data here. XXX ! 899: */ ! 900: if ((n = make_rr(ap->a_dname, dp, cp, msglen, 0)) < 0) ! 901: break; ! 902: #ifdef DEBUG ! 903: if (debug >= 5) ! 904: fprintf(ddt,"addinfo: adding address data n = %d\n", ! 905: n); ! 906: #endif ! 907: cp += n; ! 908: msglen -= n; ! 909: count++; ! 910: } ! 911: if (foundstale) { ! 912: /* Cache invalidate the address RR's */ ! 913: delete_all(np, (int)ap->a_class, T_A); ! 914: (void) sysquery(ap->a_dname, (int)ap->a_class, T_A); ! 915: } ! 916: } ! 917: hp->arcount = htons((u_short)count); ! 918: return (cp - msg); ! 919: } ! 920: ! 921: doaddauth(hp, cp, buflen, np, dp) ! 922: register HEADER *hp; ! 923: char *cp; ! 924: int buflen; ! 925: struct namebuf *np; ! 926: struct databuf *dp; ! 927: { ! 928: char dnbuf[MAXDNAME]; ! 929: int n; ! 930: ! 931: getname(np, dnbuf, sizeof(dnbuf)); ! 932: if (stale(dp) || (n = make_rr(dnbuf, dp, cp, buflen, 1)) <= 0) { ! 933: #ifdef DEBUG ! 934: if (debug) ! 935: fprintf(ddt,"doaddauth: can't add '%s' (%d)\n", ! 936: dnbuf, buflen); ! 937: #endif ! 938: return(0); ! 939: } else { ! 940: hp->nscount = htons(1); ! 941: return(n); ! 942: } ! 943: } ! 944: ! 945: ! 946: /* ! 947: * Get the domain name of 'np' and put in 'buf'. Bounds checking is done. ! 948: */ ! 949: getname(np, buf, buflen) ! 950: struct namebuf *np; ! 951: char *buf; ! 952: int buflen; ! 953: { ! 954: register char *cp; ! 955: register int i; ! 956: ! 957: cp = buf; ! 958: while (np != NULL) { ! 959: if ((i = strlen(np->n_dname))+1 >= buflen) { ! 960: *cp = '\0'; ! 961: syslog(LOG_ERR, "domain name too long: %s...\n", buf); ! 962: strcpy(buf, "Name_Too_Long"); ! 963: return; ! 964: } ! 965: if (cp != buf) ! 966: *cp++ = '.'; ! 967: (void) strcpy(cp, np->n_dname); ! 968: cp += i; ! 969: buflen -= (i+1); ! 970: np = np->n_parent; ! 971: } ! 972: *cp = '\0'; ! 973: } ! 974: ! 975: /* ! 976: * Do a zone transfer. SOA record already sent. ! 977: */ ! 978: doaxfr(np, rfp, isroot) ! 979: register struct namebuf *np; ! 980: FILE *rfp; ! 981: int isroot; ! 982: { ! 983: register struct databuf *dp; ! 984: register int n; ! 985: struct hashbuf *htp; ! 986: struct databuf *gdp; /* glue databuf */ ! 987: struct namebuf *gnp; /* glue namebuf */ ! 988: struct namebuf **npp, **nppend; ! 989: char msg[PACKETSZ]; ! 990: char *cp; ! 991: char *fname; ! 992: char dname[MAXDNAME]; ! 993: HEADER *hp = (HEADER *) msg; ! 994: int fndns; ! 995: ! 996: #ifdef DEBUG ! 997: if (debug && isroot) ! 998: fprintf(ddt,"doaxfr()\n"); ! 999: #endif ! 1000: fndns = 0; ! 1001: hp->id = 0; ! 1002: hp->opcode = QUERY; ! 1003: hp->aa = hp->tc = hp->ra = hp->pr = hp->rd = 0; ! 1004: hp->qr = 1; ! 1005: hp->rcode = NOERROR; ! 1006: hp->qdcount = 0; ! 1007: hp->ancount = htons(1); ! 1008: hp->nscount = 0; ! 1009: hp->arcount = 0; ! 1010: cp = msg + sizeof(HEADER); ! 1011: getname(np, dname, sizeof(dname)); ! 1012: ! 1013: /* first do data records */ ! 1014: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { ! 1015: /* ! 1016: * Skip the root SOA record (marks end of data); ! 1017: * don't send SOA for subdomains, as we're not sending them. ! 1018: */ ! 1019: if (dp->d_type == T_SOA) ! 1020: continue; ! 1021: if (dp->d_type == T_NS) ! 1022: fndns = 1; ! 1023: if (dp->d_zone == 0 || stale(dp)) ! 1024: continue; ! 1025: if ((n = make_rr(dname, dp, cp, sizeof(msg)-sizeof(HEADER), 0)) < 0) ! 1026: continue; ! 1027: fwritemsg(rfp, msg, n + sizeof(HEADER)); ! 1028: ! 1029: if (dp->d_type == T_NS) { ! 1030: /* Glue the sub domains together by sending ! 1031: * the address records for the sub domain ! 1032: * name servers along. ! 1033: */ ! 1034: htp = hashtab; ! 1035: cp = msg + sizeof(HEADER); ! 1036: gnp = nlookup(dp->d_data, &htp, &fname, 0); ! 1037: if (gnp == NULL || fname != dp->d_data) ! 1038: continue; ! 1039: for(gdp=gnp->n_data; gdp != NULL; gdp=gdp->d_next) { ! 1040: if (gdp->d_type != T_A || stale(gdp)) ! 1041: continue; ! 1042: if ((n = make_rr(fname, gdp, cp, ! 1043: sizeof(msg)-sizeof(HEADER), 0)) < 0) ! 1044: continue; ! 1045: fwritemsg(rfp, msg, n + sizeof(HEADER)); ! 1046: } ! 1047: } ! 1048: } ! 1049: ! 1050: /* next do subdomains, unless delegated */ ! 1051: if ((isroot == 0 && fndns) || np->n_hash == NULL) ! 1052: return; ! 1053: npp = np->n_hash->h_tab; ! 1054: nppend = npp + np->n_hash->h_size; ! 1055: while (npp < nppend) { ! 1056: for (np = *npp++; np != NULL; np = np->n_next) { ! 1057: doaxfr(np, rfp, 0); ! 1058: } ! 1059: } ! 1060: #ifdef DEBUG ! 1061: if (debug && isroot) ! 1062: fprintf(ddt,"exit doaxfr()\n"); ! 1063: #endif ! 1064: } ! 1065: ! 1066: #ifdef ALLOW_UPDATES ! 1067: /* ! 1068: * Called by UPDATE{A,D,DA,M,MA} to initiate a dynamic update. If this is the ! 1069: * primary server for the zone being updated, we update the zone's serial ! 1070: * number and then call doupdate directly. If this is a secondary, we just ! 1071: * forward the update; this way, if the primary update fails (e.g., if the ! 1072: * primary is unavailable), we don't update the secondary; if the primary ! 1073: * update suceeds, ns_resp will get called with the response (when it comes ! 1074: * in), and then update the secondary's copy. ! 1075: */ ! 1076: InitDynUpdate(hp, nsp, msg, msglen, startcp, from, qsp, dfd) ! 1077: register HEADER *hp; ! 1078: struct databuf *nsp[]; ! 1079: char *msg; ! 1080: int msglen; ! 1081: u_char *startcp; ! 1082: struct sockaddr_in *from; ! 1083: struct qstream *qsp; ! 1084: int dfd; ! 1085: { ! 1086: struct zoneinfo *zp; ! 1087: char dnbuf[MAXDNAME]; ! 1088: struct hashbuf *htp = hashtab; /* lookup relative to root */ ! 1089: struct namebuf *np; ! 1090: struct databuf *olddp, *newdp, *dp; ! 1091: struct databuf **nspp; ! 1092: char *fname; ! 1093: register u_char *cp = startcp; ! 1094: short class, type; ! 1095: int n, size, zonenum; ! 1096: char ZoneName[MAXDNAME], *znp; ! 1097: ! 1098: if ((n = dn_expand(msg, msg + msglen, cp, dnbuf, sizeof(dnbuf))) < 0) { ! 1099: #ifdef DEBUG ! 1100: if (debug) ! 1101: fprintf(ddt,"FORMERR InitDynUpdate expand name failed\n"); ! 1102: #endif ! 1103: hp->rcode = FORMERR; ! 1104: return(FORMERR); ! 1105: } ! 1106: cp += n; ! 1107: GETSHORT(type, cp); ! 1108: if (type == T_SOA) { /* T_SOA updates not allowed */ ! 1109: hp->rcode = REFUSED; ! 1110: #ifdef DEBUG ! 1111: if (debug) ! 1112: fprintf(ddt, "InitDynUpdate: REFUSED - SOA update\n"); ! 1113: #endif ! 1114: return(REFUSED); ! 1115: } ! 1116: GETSHORT(class, cp); ! 1117: cp += sizeof(u_long); ! 1118: GETSHORT(size, cp); ! 1119: /****XXX - need bounds checking here ****/ ! 1120: cp += size; ! 1121: ! 1122: if ((zonenum = findzone(dnbuf, class)) == 0) { /* zone not found */ ! 1123: hp->rcode = NXDOMAIN; ! 1124: return(NXDOMAIN); ! 1125: } ! 1126: zp = &zones[zonenum]; ! 1127: ! 1128: /* Disallow updates for which we aren't authoratative. Note: the ! 1129: following test doesn't work right: If it's for a non-local zone, ! 1130: we will think it's a primary but be unable to lookup the namebuf, ! 1131: thus returning 'NXDOMAIN' */ ! 1132: if (zp->z_type != Z_PRIMARY && zp->z_type != Z_SECONDARY) { ! 1133: hp->rcode = REFUSED; ! 1134: #ifdef DEBUG ! 1135: if (debug) ! 1136: fprintf(ddt, "InitDynUpdate: REFUSED - non-primary, non-sedondary update\n"); ! 1137: #endif ! 1138: return(REFUSED); ! 1139: } ! 1140: if (!(zp->z_state & Z_DYNAMIC)) { ! 1141: hp->rcode = REFUSED; ! 1142: #ifdef DEBUG ! 1143: if (debug) ! 1144: fprintf(ddt, "InitDynUpdate: REFUSED - dynamic flag not set for zone\n"); ! 1145: #endif ! 1146: return(REFUSED); ! 1147: } ! 1148: ! 1149: /* ! 1150: * Lookup the zone namebuf. Lookup "xyz" not "xyz.", since ! 1151: * otherwise the lookup fails, because '.' may have a nil n_hash ! 1152: * associated with it. ! 1153: */ ! 1154: strcpy(ZoneName, zp->z_origin); ! 1155: znp = &ZoneName[strlen(ZoneName) - 1]; ! 1156: if (*znp == '.') ! 1157: *znp = NULL; ! 1158: np = nlookup(ZoneName, &htp, &fname, 0); ! 1159: if ((np == NULL) || (fname != ZoneName)) { ! 1160: #ifdef DEBUG ! 1161: if (debug) ! 1162: fprintf(ddt, "InitDynUpdate: lookup failed on zone (%s)\n", ! 1163: ZoneName); ! 1164: #endif DEBUG ! 1165: syslog(LOG_ERR, "InitDynUpdate: lookup failed on zone (%s)\n", ! 1166: ZoneName); ! 1167: hp->rcode = NXDOMAIN; ! 1168: return(NXDOMAIN); ! 1169: } ! 1170: ! 1171: /* ! 1172: * If this is the primary copy increment the serial number. Don't ! 1173: * increment the serial number if this is a secondary; this way, if 2 ! 1174: * different secondaries both update the primary, they will both have ! 1175: * lower serial numbers than the primary has, and hence eventually ! 1176: * refresh and get all updates and become consistent. ! 1177: * ! 1178: * Note that the serial number must be incremented in both the zone ! 1179: * data structure and the zone's namebuf. ! 1180: */ ! 1181: switch (zp->z_type) { ! 1182: case Z_SECONDARY: /* forward update to primary */ ! 1183: nspp = nsp; ! 1184: dp = np->n_data; ! 1185: while (dp != NULL) { ! 1186: if (match(dp, class, T_NS)) { ! 1187: if (nspp < &nsp[NSMAX-1]) ! 1188: *nspp++ = dp; ! 1189: else ! 1190: break; ! 1191: } ! 1192: dp = dp->d_next; ! 1193: } ! 1194: *nspp = NULL; /* Delimiter */ ! 1195: if (ns_forw(nsp, msg, msglen, from, qsp, dfd, NULL) < 0) { ! 1196: hp->rcode = SERVFAIL; ! 1197: return(SERVFAIL); ! 1198: } ! 1199: return(FORWARDED); ! 1200: ! 1201: case Z_PRIMARY: ! 1202: zp->z_serial++; ! 1203: olddp = np->n_data; /* old databuf */ ! 1204: /* Find the SOA record */ ! 1205: for (olddp = np->n_data; olddp != NULL; olddp = olddp->d_next) ! 1206: if (match(olddp, class, T_SOA)) ! 1207: break; ! 1208: if (olddp == NULL) { ! 1209: #ifdef DEBUG ! 1210: if (debug) ! 1211: fprintf(ddt,"InitDynUpdate: Couldn't find SOA record for '%s'\n", ! 1212: ZoneName); ! 1213: #endif DEBUG ! 1214: syslog(LOG_ERR, ! 1215: "InitDynUpdate: Couldn't find SOA record for '%s'\n" ! 1216: , ! 1217: ZoneName); ! 1218: hp->rcode = NXDOMAIN; ! 1219: return(NXDOMAIN); ! 1220: } ! 1221: newdp = savedata(olddp->d_class, olddp->d_type, olddp->d_ttl, ! 1222: olddp->d_data, olddp->d_size); ! 1223: newdp->d_zone = olddp->d_zone; ! 1224: cp = (u_char *)newdp->d_data; ! 1225: cp += strlen(cp) + 1; /* skip origin string */ ! 1226: cp += strlen(cp) + 1; /* skip in-charge string */ ! 1227: putlong((u_long)(zp->z_serial), cp); ! 1228: #ifdef DEBUG ! 1229: if (debug >= 4) { ! 1230: fprintf(ddt, "after stuffing data into newdp:\n"); ! 1231: printSOAdata(newdp); ! 1232: } ! 1233: #endif DEBUG ! 1234: ! 1235: if ((n = db_update(ZoneName, olddp, newdp, DB_DELETE, ! 1236: hashtab)) != NOERROR) { ! 1237: #ifdef DEBUG ! 1238: if (debug) ! 1239: fprintf(ddt,"InitDynUpdate: SOA update failed\n"); ! 1240: #endif DEBUG ! 1241: hp->rcode = NOCHANGE; ! 1242: return(NOCHANGE); ! 1243: } ! 1244: ! 1245: /* Now update the RR itself */ ! 1246: if (doupdate(msg, msglen, msg + sizeof(HEADER), ! 1247: zonenum, (struct databuf *)0, DB_NODATA) < 0) { ! 1248: #ifdef DEBUG ! 1249: if (debug) ! 1250: fprintf(ddt,"InitDynUpdate: doupdate failed\n"); ! 1251: #endif DEBUG ! 1252: /* doupdate fills in rcode */ ! 1253: return(hp->rcode); ! 1254: } ! 1255: zp->hasChanged++; ! 1256: return(NOERROR); ! 1257: } ! 1258: } ! 1259: ! 1260: #ifdef DEBUG ! 1261: /* ! 1262: * Print the contents of the data in databuf pointed to by dp for an SOA record ! 1263: */ ! 1264: printSOAdata(dp) ! 1265: struct databuf *dp; ! 1266: { ! 1267: register u_char *cp; ! 1268: ! 1269: if (!debug) ! 1270: return; /* Otherwise fprintf to ddt will bomb */ ! 1271: cp = (u_char *)dp->d_data; ! 1272: fprintf(ddt, "printSOAdata(%x): origin(%x)='%s'\n", dp, cp, cp); ! 1273: cp += strlen(cp) + 1; /* skip origin string */ ! 1274: fprintf(ddt, "printSOAdata: in-charge(%x)='%s'\n", cp, cp); ! 1275: cp += strlen(cp) + 1; /* skip in-charge string */ ! 1276: fprintf(ddt, "printSOAdata: serial(%x)=%d\n", cp, _getlong(cp)); ! 1277: } ! 1278: #endif DEBUG ! 1279: #endif ALLOW_UPDATES ! 1280: ! 1281: struct databuf * ! 1282: rm_datum(dp, np, pdp) ! 1283: register struct databuf *pdp, *dp; ! 1284: register struct namebuf *np; ! 1285: { ! 1286: register struct databuf *ndp = dp->d_next; ! 1287: ! 1288: #ifdef DEBUG ! 1289: if (debug > 2) ! 1290: fprintf(ddt, "rm_datum(%x, %x, %x) -> %x\n", ! 1291: dp, np->n_data, pdp, ndp); ! 1292: #endif DEBUG ! 1293: if (pdp == NULL) ! 1294: np->n_data = ndp; ! 1295: else ! 1296: pdp->d_next = ndp; ! 1297: rminv(dp); ! 1298: (void) free((char *)dp); ! 1299: return(ndp); ! 1300: } ! 1301: ! 1302: startxfr(qsp, np, msg, msglen) ! 1303: struct qstream *qsp; ! 1304: struct namebuf *np; ! 1305: char *msg; ! 1306: int msglen; ! 1307: { ! 1308: register FILE *rfp; ! 1309: int fdstat; ! 1310: ! 1311: #ifdef DEBUG ! 1312: if (debug >= 5) ! 1313: fprintf(ddt,"startxfr()\n"); ! 1314: #endif ! 1315: /* ! 1316: * child does the work while ! 1317: * the parent continues ! 1318: */ ! 1319: if (fork() == 0) { ! 1320: #ifdef DEBUG ! 1321: if (debug >= 5) ! 1322: fprintf(ddt,"startxfr: child pid %d\n", getpid()); ! 1323: #endif ! 1324: rfp = fdopen(qsp->s_rfd, "w"); ! 1325: setproctitle("zone XFR to", qsp->s_rfd); ! 1326: fdstat = fcntl(qsp->s_rfd, F_GETFL, 0); ! 1327: if (fdstat != -1) ! 1328: (void) fcntl(qsp->s_rfd, F_SETFL, fdstat & ~FNDELAY); ! 1329: fwritemsg(rfp, msg, msglen); ! 1330: doaxfr(np, rfp, 1); ! 1331: fwritemsg(rfp, msg, msglen); ! 1332: (void) fflush(rfp); ! 1333: exit(0); ! 1334: } ! 1335: sqrm(qsp); ! 1336: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.