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