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