1: #ifndef lint 2: static char sccsid[] = "@(#)ns_req.c 4.3 (Berkeley) 5/30/86"; 3: #endif 4: 5: /* 6: * Copyright (c) 1986 Regents of the University of California 7: * All Rights Reserved 8: */ 9: 10: #include <stdio.h> 11: #include <sys/types.h> 12: #include <sys/uio.h> 13: #include <sys/time.h> 14: #include <netinet/in.h> 15: #include <syslog.h> 16: #include <sys/file.h> 17: #include <arpa/nameser.h> 18: #include "ns.h" 19: #include "db.h" 20: 21: #define NADDRECS 20 22: 23: struct addinfo { 24: char *a_dname; /* domain name */ 25: u_short a_class; /* class for address */ 26: }; 27: 28: struct addinfo addinfo[NADDRECS]; /* additional info records */ 29: int addcount; /* number of names in addinfo */ 30: 31: char *dnptrs[20]; /* ptrs to dnames in message for dn_comp */ 32: 33: extern char *malloc(); 34: extern int errno; 35: /* 36: * Process request using database; assemble and send response. 37: */ 38: ns_req(msg, msglen, buflen, qsp, from) 39: char *msg; 40: int msglen, buflen; 41: struct qstream *qsp; 42: struct sockaddr_in *from; 43: { 44: register HEADER *hp; 45: register char *cp; 46: register struct namebuf *np; 47: register struct databuf *dp; 48: struct databuf *tmp; 49: struct databuf *pdp; 50: struct hashbuf *htp; 51: struct zoneinfo *zp; 52: char *fname; 53: char dnbuf[MAXDNAME], *dname; 54: char **dpp; 55: char *dnp; 56: char *newmsg; 57: int n, class, type, count, foundname, founddata, cname = 0; 58: int newmsglen; 59: u_short id; 60: struct databuf *nsp[MAXNS], **nspp; 61: struct qinfo *qp; 62: time_t curtime; 63: extern struct qinfo *qhead; 64: extern int nsid; 65: 66: #ifdef DEBUG 67: if (debug > 3) { 68: fprintf(ddt,"ns_req()\n"); 69: fp_query(msg, ddt); 70: } 71: #endif 72: 73: hp = (HEADER *) msg; 74: if (hp->qr) { 75: ns_resp(msg, msglen); 76: return; 77: } 78: 79: cp = msg + sizeof(HEADER); 80: hp->rcode = NOERROR; 81: dpp = dnptrs; 82: *dpp++ = msg; 83: addcount = 0; 84: 85: 86: switch (hp->opcode) { 87: case QUERY: 88: if (ntohs(hp->qdcount) != 1 || 89: hp->ancount || hp->nscount || hp->arcount) { 90: #ifdef DEBUG 91: if (debug) 92: fprintf(ddt,"FORMERR Query header counts wrong\n"); 93: #endif 94: hp->qdcount = 0; 95: hp->ancount = 0; 96: hp->nscount = 0; 97: hp->arcount = 0; 98: hp->rcode = FORMERR; 99: break; 100: } 101: /* 102: * Get domain name, class, and type. 103: */ 104: if ((*cp & INDIR_MASK) == 0) 105: *dpp++ = cp; /* remember name for compression */ 106: *dpp = NULL; 107: if ((n = dn_expand(msg, msg + msglen, cp, dnbuf, 108: sizeof(dnbuf))) < 0) { 109: #ifdef DEBUG 110: if (debug) 111: fprintf(ddt,"FORMERR Query expand name failed\n"); 112: #endif 113: hp->rcode = FORMERR; 114: break; 115: } 116: cp += n; 117: type = getshort(cp); 118: cp += sizeof(u_short); 119: class = getshort(cp); 120: cp += sizeof(u_short); 121: if (cp < msg + msglen) { 122: #ifdef DEBUG 123: if (debug) 124: fprintf(ddt,"FORMERR Query message length off\n"); 125: #endif 126: hp->rcode = FORMERR; 127: break; 128: } 129: #ifdef DEBUG 130: if (cp > msg + msglen) 131: if (debug > 5) 132: fprintf(ddt,"message length > recived message\n"); 133: #endif 134: #ifdef notdef 135: if (!check_class(quest.qtype->class)) { 136: if (debug) 137: fprintf(ddt,"FORMERR Query class is wrong\n"); 138: hp->rcode = FORMERR; 139: break; 140: } 141: if (!check_type(quest.qtype->type)) { 142: if (debug) 143: fprintf(ddt,"proc_query FORMERR Query type wrong\n"); 144: hp->rcode = FORMERR; 145: break; 146: } 147: #endif 148: /* 149: * Process query. 150: */ 151: if (type == T_AXFR) { 152: /* refuse request if not a TCP connection */ 153: if (qsp == QSTREAM_NULL) { 154: hp->rcode = REFUSED; 155: break; 156: } 157: /* don't compress names */ 158: dnptrs[0] = NULL; 159: } 160: buflen -= msglen; 161: count = 0; 162: foundname = 0; 163: founddata = 0; 164: dname = dnbuf; 165: again: 166: #ifdef DEBUG 167: if (debug) 168: fprintf(ddt,"nlookup(%s)\n", dname); 169: #endif 170: htp = hashtab; /* lookup relative to root */ 171: np = nlookup(dname, &htp, &fname, 0); 172: /* 173: * if nlookup failed to find address then 174: * see if there are any '.''s in the name 175: * if not then add local domain name to the 176: * name and try again. 177: */ 178: if (np == NULL) { 179: fname = ""; 180: dnp = &dname[strlen(dname)]; 181: if ( index(dname, '.') == NULL) 182: for (zp = zones; zp < &zones[nzones]; zp++) { 183: if ( zp->z_type == Z_DOMAIN){ 184: #ifdef DEBUG 185: if (debug >= 5) 186: fprintf(ddt,"domain = %s\n", 187: zp->z_origin); 188: #endif 189: (void) strcat(dname,"."); 190: (void) strcat(dname,zp->z_origin); 191: #ifdef DEBUG 192: if (debug) 193: fprintf(ddt,"nlookup(%s)\n", dname); 194: #endif 195: np = nlookup(dname, &htp, &fname, 0); 196: if (np != NULL) 197: break; 198: fname = ""; 199: *dnp = '\0'; 200: } 201: } 202: } 203: if (fname != dname) { 204: #ifdef DEBUG 205: if (debug && cname) { 206: if (founddata) 207: fprintf(ddt,"CNAME with data\n"); 208: else 209: fprintf(ddt,"CNAME without data %s\n", dname); 210: } 211: #endif 212: goto findns; 213: } 214: #ifdef DEBUG 215: if (debug) 216: fprintf(ddt,"found '%s'\n", dname); 217: #endif 218: foundname++; 219: pdp = NULL; 220: dp = np->n_data; 221: /* look for the data */ 222: while (dp != NULL) { 223: if (!wanted(dp, class, type)) { 224: pdp = dp; 225: dp = dp->d_next; 226: continue; 227: } 228: if ((n = make_rr(dname, dp, cp, buflen, 1)) < 0) { 229: if (n == -1) { 230: hp->tc = 1; 231: break; 232: } 233: 234: /* delete old cache entry */ 235: #ifdef DEBUG 236: if (debug) 237: fprintf(ddt,"deleting cache entry\n"); 238: #endif 239: rminv(dp); 240: tmp = dp->d_next; 241: (void) free((char *)dp); 242: dp = tmp; 243: if (pdp == NULL) 244: np->n_data = dp; 245: else 246: pdp->d_next = dp; 247: continue; 248: 249: } 250: cp += n; 251: buflen -= n; 252: count++; 253: if (dp->d_zone) 254: hp->aa = 1; 255: if (dp->d_type == T_CNAME) { 256: if (type == T_ANY) 257: break; 258: cname++; 259: dname = dp->d_data; 260: goto again; 261: } 262: founddata++; 263: pdp = dp; 264: dp = dp->d_next; 265: } 266: #ifdef DEBUG 267: if (debug >= 5) { 268: fprintf(ddt,"foundname = %d count = %d ", foundname, count); 269: fprintf(ddt,"founddata = %d cname = %d\n",founddata, cname); 270: } 271: #endif 272: if (count) { 273: hp->ancount = htons((u_short)count); 274: if (type == T_AXFR && founddata) { 275: #ifdef DEBUG 276: if (debug >= 5) 277: fprintf(ddt,"doing axfr()\n"); 278: #endif 279: /* 280: * child does the work while 281: * the parent continues 282: */ 283: if (fork() == 0) { 284: register FILE *rfp; 285: int fdstat; 286: 287: rfp = fdopen(qsp->s_rfd, "w"); 288: setproctitle("zone XFR to", qsp->s_rfd); 289: fdstat = fcntl(qsp->s_rfd, F_GETFL, 0); 290: if (fdstat != -1) 291: (void) fcntl(qsp->s_rfd, F_SETFL, 292: fdstat & ~FNDELAY); 293: fwritemsg(rfp, msg, cp - msg); 294: doaxfr(np, rfp, 1); 295: fwritemsg(rfp, msg, cp - msg); 296: (void) fflush(rfp); 297: exit(0); 298: } 299: qsp->s_time = tt.tv_sec; 300: qsp->s_refcnt--; 301: return; 302: } 303: if (hp->aa) 304: break; 305: } 306: findns: 307: /* 308: * Look for name servers to refer to and 309: * fill in the authority section or record the address 310: * for forwarding the query (recursion desired). 311: */ 312: for (count = 0; ; np = np->n_parent) { 313: #ifdef DEBUG 314: if (debug >= 5) 315: fprintf(ddt,"fname = '%s'\n", fname); 316: #endif 317: if (*fname == '\0') { 318: for (np = hashtab->h_tab[0]; np != NULL; 319: np = np->n_next) 320: if ( np->n_dname[0] == '\0') 321: goto foundns; 322: #ifdef DEBUG 323: if (debug) 324: fprintf(ddt,"No root nameserver?\n"); 325: #endif 326: syslog(LOG_ERR,"No root Nameserver\n"); 327: hp->rcode = SERVFAIL; 328: break; 329: } 330: foundns: 331: nspp = nsp; /* record ns records if forwarding */ 332: pdp = NULL; 333: dp = np->n_data; 334: curtime =(u_long) tt.tv_sec; 335: while (dp != NULL) { 336: if (dp->d_zone && match(dp, class, T_SOA)) { 337: if (!foundname) 338: hp->rcode = NXDOMAIN; 339: hp->aa = 1; 340: goto finish; 341: } 342: if (!match(dp, class, T_NS)) { 343: pdp = dp; 344: dp = dp->d_next; 345: continue; 346: } 347: if ((dp->d_zone == 0) && 348: (dp->d_ttl < curtime)) { 349: /* delete old cache entry */ 350: #ifdef DEBUG 351: if (debug) 352: fprintf(ddt,"deleting cache entry\n"); 353: #endif 354: rminv(dp); 355: tmp = dp->d_next; 356: (void) free((char *)dp); 357: dp = tmp; 358: if (pdp == NULL) 359: np->n_data = dp; 360: else 361: pdp->d_next = dp; 362: continue; 363: } 364: if (hp->rd && !founddata) { 365: if (nspp < &nsp[MAXNS-1]) 366: *nspp++ = dp; 367: pdp = dp; 368: dp = dp->d_next; 369: continue; 370: } 371: if ((n = make_rr(fname, dp, cp, buflen, 1)) < 0) { 372: if (n == -1) { 373: hp->tc = 1; 374: break; 375: } 376: /* delete old cache entry */ 377: #ifdef DEBUG 378: if (debug) 379: fprintf(ddt,"deleting cache entry\n"); 380: #endif 381: rminv(dp); 382: tmp = dp->d_next; 383: (void) free((char *)dp); 384: dp = tmp; 385: if (pdp == NULL) 386: np->n_data = dp; 387: else 388: pdp->d_next = dp; 389: continue; 390: } 391: cp += n; 392: buflen -= n; 393: count++; 394: pdp = dp; 395: dp = dp->d_next; 396: } 397: if (count && founddata) { 398: hp->nscount = htons((u_short)count); 399: break; 400: } 401: if (nspp != nsp) { 402: *nspp = NULL; 403: if (cname) { 404: id = hp->id; 405: for (qp = qhead; qp!=QINFO_NULL; 406: qp = qp->q_link) { 407: if (qp->q_id == id && 408: qp->q_cmsglen == msglen && 409: bcmp((char *)qp->q_cmsg+2, 410: msg+2, msglen-2) == 0) 411: return; 412: } 413: /* build new qinfo struct */ 414: qp = qnew(); 415: qp->q_naddr = 0; 416: if (nslookup(nsp, qp) == 0) { 417: #ifdef DEBUG 418: if (debug >= 5) 419: fprintf(ddt,"none found in nsp\n"); 420: #endif 421: qfree(qp); 422: hp->rcode = SERVFAIL; 423: break; 424: } 425: qp->q_cname++; 426: qp->q_stream = qsp; 427: qp->q_curaddr = 0; 428: qp->q_id = id; 429: qp->q_from = *from; 430: if ((qp->q_cmsg = malloc((unsigned)msglen)) 431: == NULL) { 432: #if DEBUG 433: if (debug) 434: fprintf(ddt,"ns_req: malloc fail\n"); 435: #endif 436: syslog(LOG_ERR, "ns_req: Out Of Memory"); 437: hp->rcode = SERVFAIL; 438: break; 439: } 440: bcopy(msg, qp->q_cmsg, qp->q_cmsglen = msglen); 441: if ((newmsg = malloc(BUFSIZ)) == NULL) { 442: #if DEBUG 443: if (debug) 444: fprintf(ddt,"ns_req: malloc error\n"); 445: #endif 446: syslog(LOG_ERR, "ns_req: Out Of Memory"); 447: hp->rcode = SERVFAIL; 448: goto finish; 449: } 450: buflen = BUFSIZ; 451: dnptrs[0] = newmsg; 452: dnptrs[1] = NULL; 453: newmsglen = res_mkquery(QUERY, dname, class, 454: type, (char *)NULL, 0, NULL, 455: newmsg, buflen); 456: qp->q_msg = newmsg; 457: qp->q_msglen = newmsglen; 458: hp = (HEADER *) newmsg; 459: hp->id = qp->q_nsid = htons((u_short)++nsid); 460: hp->ancount = 0; 461: hp->nscount = 0; 462: hp->arcount = 0; 463: schedretry(qp, (time_t)RETRYTIME); 464: 465: #ifdef DEBUG 466: if (debug) 467: fprintf(ddt,"forw -> %s (%d)\n", 468: inet_ntoa(qp->q_addr[0].sin_addr), 469: ntohs(qp->q_addr[0].sin_port)); 470: if ( debug >= 10) 471: fp_query(newmsg, ddt); 472: #endif 473: if (sendto(ds, newmsg, newmsglen, 0, 474: &qp->q_addr[0], sizeof(qp->q_addr[0])) < 0){ 475: #ifdef DEBUG 476: if (debug) 477: fprintf(ddt,"sendto error \n"); 478: #endif 479: } 480: return; 481: } 482: if ((n = ns_forw(nsp, msg, msglen, from, qsp)) == 0) 483: return; 484: if (n == -2) { 485: hp->rcode = SERVFAIL; 486: break; 487: } 488: } 489: if (*fname == '\0') 490: break; 491: if ((fname = index(fname, '.')) == NULL) 492: fname = ""; 493: else 494: fname++; 495: } 496: break; 497: 498: case IQUERY: { 499: register struct invbuf *ip; 500: register int i; 501: int dlen, alen; 502: char anbuf[PACKETSZ], *data; 503: 504: if (ntohs(hp->ancount) != 1 || 505: hp->qdcount || hp->nscount || hp->arcount) { 506: #ifdef DEBUG 507: if (debug) 508: fprintf(ddt,"FORMERR IQuery header counts wrong\n"); 509: #endif 510: hp->qdcount = 0; 511: hp->ancount = 0; 512: hp->nscount = 0; 513: hp->arcount = 0; 514: hp->rcode = FORMERR; 515: break; 516: } 517: /* 518: * Skip domain name, get class, and type. 519: */ 520: if ((n = dn_skip(cp)) < 0) { 521: #ifdef DEBUG 522: if (debug) 523: fprintf(ddt,"FORMERR IQuery packet name problem\n"); 524: #endif 525: hp->rcode = FORMERR; 526: break; 527: } 528: cp += n; 529: type = getshort(cp); 530: cp += sizeof(u_short); 531: class = getshort(cp); 532: cp += sizeof(u_short) + sizeof(u_long); 533: dlen = getshort(cp); 534: cp += sizeof(u_short) + dlen; 535: if (cp != msg + msglen) { 536: #ifdef DEBUG 537: if (debug) 538: fprintf(ddt,"FORMERR IQuery message length off\n"); 539: #endif 540: hp->rcode = FORMERR; 541: break; 542: } 543: /* not all inverse queries are handled. */ 544: switch (type) { 545: case T_A: 546: case T_UID: 547: case T_GID: 548: break; 549: 550: default: 551: hp->rcode = REFUSED; 552: goto finish; 553: } 554: fname = msg + sizeof(HEADER); 555: bcopy(fname, anbuf, alen = cp - fname); 556: data = anbuf + alen - dlen; 557: cp = fname; 558: buflen -= sizeof(HEADER); 559: count = 0; 560: for (ip = invtab[dhash(data, dlen)]; ip != NULL; 561: ip = ip->i_next) { 562: for (i = 0; i < INVBLKSZ; i++) { 563: if ((np = ip->i_dname[i]) == NULL) 564: break; 565: #ifdef DEBUG 566: if (debug >= 5) 567: fprintf(ddt,"dname = %d\n", np->n_dname); 568: #endif 569: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { 570: if (!match(dp, class, type)) 571: continue; 572: if (dp->d_size != dlen || 573: bcmp(dp->d_data, data, dlen)) 574: continue; 575: getname(np, dnbuf, sizeof(dnbuf)); 576: buflen -= QFIXEDSZ; 577: if ((n = 578: dn_comp(dnbuf, cp, buflen, (char **)NULL, 579: (char **)NULL)) < 0) 580: { 581: hp->tc = 1; 582: goto finish; 583: } 584: cp += n; 585: putshort((u_short)dp->d_type, cp); 586: cp += sizeof(u_short); 587: putshort((u_short)dp->d_class, cp); 588: cp += sizeof(u_short); 589: buflen -= n; 590: count++; 591: } 592: } 593: } 594: hp->qdcount = htons((u_short)count); 595: if (alen > buflen) { 596: hp->tc = 1; 597: break; 598: } 599: bcopy(anbuf, cp, alen); 600: cp += alen; 601: break; 602: } 603: 604: #ifdef notdef 605: case UPDATEA: 606: if ((n = 607: dn_expand(msg, msg + msglen, cp, dnbuf, sizeof(dnbuf))) < 0) 608: { 609: #ifdef DEBUG 610: if (debug) 611: fprintf(ddt,"FORMERR UpdateA expand name failed\n"); 612: #endif 613: hp->rcode = FORMERR; 614: break; 615: } 616: cp += n; 617: type = getshort(cp); 618: cp += sizeof(u_short); 619: class = getshort(cp); 620: cp += sizeof(u_short); 621: ttl = getlong(cp); 622: cp += sizeof(u_long); 623: n = getshort(cp); 624: cp += sizeof(u_short); 625: if (cp + n != msg + msglen) { 626: #ifdef DEBUG 627: if (debug) 628: fprintf(ddt,"FORMERR UpdateA expand name failed\n"); 629: #endif 630: hp->rcode = FORMERR; 631: break; 632: } 633: dp = savedata(class, type, ttl, cp, n); 634: dp->d_zone = findzone(dnbuf, class); 635: if ((n = updatedb(dnbuf, NULL, dp, DB_NODATA)) != NOERROR) { 636: #ifdef DEBUG 637: if (debug) 638: fprintf(ddt,"update failed\n"); 639: #endif 640: hp->rcode = n; 641: } 642: hp->rcode = NOERROR; 643: break; 644: 645: case UPDATED: 646: if ((n = 647: dn_expand(msg, msg + msglen, cp, dnbuf, sizeof(dnbuf))) < 0) 648: { 649: #ifdef DEBUG 650: if (debug) 651: fprintf(ddt,"FORMERR UpdateD expand name failed\n"); 652: #endif 653: hp->rcode = FORMERR; 654: break; 655: } 656: cp += n; 657: rrec.r_type = getshort(cp); 658: cp += sizeof(u_short); 659: rrec.r_class = getshort(cp); 660: cp += sizeof(u_short) + sizeof(u_long); 661: rrec.r_size = getshort(cp); 662: rrec.r_data = cp += sizeof(u_short); 663: if (cp + rrec.r_size != msg + msglen) { 664: #ifdef DEBUG 665: if (debug) 666: fprintf(ddt,"FORMERR UpdateD message length off\n"); 667: #endif 668: hp->rcode = FORMERR; 669: break; 670: } 671: if (updatedb(dnbuf, &rrec, NULL, DB_DELETE) < 0) { 672: #ifdef DEBUG 673: if (debug) 674: fprintf(ddt,"update failed\n"); 675: #endif 676: } 677: hp->rcode = NOERROR; 678: break; 679: 680: case UPDATEM: 681: if ((n = dn_expand(msg, msg + msglen, cp, addbuf, 682: sizeof(addbuf))) < 0) { 683: #ifdef DEBUG 684: if (debug) 685: fprintf(ddt,"FORMERR UpdateM expand name 1 failed\n"); 686: #endif 687: hp->rcode = FORMERR; 688: break; 689: } 690: cp += n; 691: rrec.r_type = getshort(cp); 692: cp += sizeof(u_short); 693: rrec.r_class = getshort(cp); 694: cp += sizeof(u_short) + sizeof(u_long); 695: rrec.r_size = getshort(cp); 696: rrec.r_data = cp += sizeof(u_short); 697: cp += rrec.r_size; 698: if ((n = 699: dn_expand(msg, msg + msglen, cp, dnbuf, sizeof(dnbuf))) < 0) 700: { 701: #ifdef DEBUG 702: if (debug) 703: fprintf(ddt,"FORMERR UpdateM expand name 2 failed\n"); 704: #endif 705: hp->rcode = FORMERR; 706: break; 707: } 708: if (cistrcmp(dnbuf, addbuf) != 0) { 709: #ifdef DEBUG 710: if (debug) 711: fprintf(ddt,"FORMERR UpdateM string compair failed\n"); 712: #endif 713: hp->rcode = FORMERR; 714: break; 715: } 716: cp += n; 717: type = getshort(cp); 718: cp += sizeof(u_short); 719: class = getshort(cp); 720: cp += sizeof(u_short); 721: ttl = getlong(cp); 722: cp += sizeof(u_long); 723: n = getshort(cp); 724: cp += sizeof(u_short); 725: if (cp + n != msg + msglen) { 726: #ifdef DEBUG 727: if (debug) 728: fprintf(ddt,"FORMERR UpdateM message length off\n"); 729: #endif 730: hp->rcode = FORMERR; 731: break; 732: } 733: dp = savedata(class, type, ttl, cp, n); 734: dp->d_zone = findzone(dnbuf, class); 735: if ((n = 736: updatedb(dnbuf, &rrec, dp, DB_MEXIST|DB_DELETE)) != NOERROR) 737: { 738: #ifdef DEBUG 739: if (debug) 740: fprintf(ddt,"update failed\n"); 741: #endif 742: hp->rcode = n; 743: } 744: hp->rcode = NOERROR; 745: break; 746: #endif 747: 748: case ZONEREF: 749: #ifdef DEBUG 750: if (debug) 751: fprintf(ddt,"Refresh Zone\n"); 752: #endif 753: 754: default: 755: hp->rcode = NOTIMP; 756: hp->qdcount = 0; 757: hp->ancount = 0; 758: hp->nscount = 0; 759: hp->arcount = 0; 760: } 761: finish: 762: hp->qr = 1; /* set Response flag */ 763: hp->ra = 1; /* Recursion is Available */ 764: if (addcount) 765: cp += doaddinfo(hp, cp, buflen - (cp - msg)); 766: #ifdef DEBUG 767: if (debug >= 10) 768: fp_query(msg, ddt); 769: #endif 770: if (qsp == QSTREAM_NULL) { 771: if (sendto(ds, msg, cp-msg, 0, from, sizeof(*from)) < 0) { 772: #ifdef DEBUG 773: if (debug) 774: fprintf(ddt,"error returning msg\n"); 775: #endif 776: } 777: } else { 778: (void) writemsg(qsp->s_rfd, msg, cp - msg); 779: qsp->s_time = tt.tv_sec; 780: qsp->s_refcnt--; 781: } 782: } 783: 784: fwritemsg(rfp, msg, msglen) 785: FILE *rfp; 786: char *msg; 787: int msglen; 788: { 789: u_short len = htons((u_short)msglen); 790: 791: if (fwrite((char *)&len, sizeof(len), 1, rfp) != 1 || 792: fwrite(msg, msglen, 1, rfp) != 1) { 793: #ifdef DEBUG 794: if (debug) 795: fprintf(ddt,"fwrite failed %d\n", errno); 796: #endif 797: /* 798: syslog(LOG_ERR, "fwritemsg: write failed: %m"); 799: */ 800: } 801: return; 802: } 803: 804: writemsg(rfd, msg, msglen) 805: int rfd; 806: char *msg; 807: int msglen; 808: { 809: struct iovec iov[2]; 810: u_short len = htons((u_short)msglen); 811: 812: iov[0].iov_base = (caddr_t)&len; 813: iov[0].iov_len = sizeof(len); 814: iov[1].iov_base = msg; 815: iov[1].iov_len = msglen; 816: if (writev(rfd, iov, 2) != sizeof(len) + msglen) { 817: #ifdef DEBUG 818: if (debug) 819: fprintf(ddt,"write failed %d\n", errno); 820: #endif 821: /* 822: syslog(LOG_ERR, "writemsg: write failed: %m"); 823: */ 824: return (-1); 825: } 826: return (0); 827: } 828: 829: /* 830: * Copy databuf into a resource record for replies. 831: * Return size of RR if OK, -1 if buffer is full and 832: * -2 if its an outdated cache entry. 833: */ 834: make_rr(name, dp, buf, buflen, doadd) 835: char *name; 836: register struct databuf *dp; 837: char *buf; 838: int buflen, doadd; 839: { 840: register char *cp; 841: register struct addinfo *ap; 842: char *cp1, *sp; 843: register long n; 844: u_long ttl; 845: char **edp = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]); 846: 847: #ifdef DEBUG 848: if (debug >= 5) 849: fprintf(ddt,"make_rr(%s, %x, %x, %d, %d) %d\n", name, dp, buf, 850: buflen, doadd, dp->d_size); 851: #endif 852: 853: /* check for outdated RR before updating dnptrs by dn_comp() */ 854: if (dp->d_zone == 0) { 855: ttl = dp->d_ttl - (u_long) tt.tv_sec; 856: if (dp->d_ttl < (u_long)tt.tv_sec) 857: return (-2); 858: } else { 859: ttl = zones[dp->d_zone].z_minimum; 860: if (dp->d_ttl > ttl) 861: ttl = dp->d_ttl; 862: } 863: 864: buflen -= RRFIXEDSZ; 865: if ((n = dn_comp(name, buf, buflen, (char **)dnptrs, (char **)edp)) < 0) 866: return (-1); 867: cp = buf + n; 868: buflen -= n; 869: putshort((u_short)dp->d_type, cp); 870: cp += sizeof(u_short); 871: putshort((u_short)dp->d_class, cp); 872: cp += sizeof(u_short); 873: putlong(ttl, cp); 874: cp += sizeof(u_long); 875: sp = cp; 876: cp += sizeof(u_short); 877: switch (dp->d_type) { 878: case T_CNAME: 879: case T_MG: 880: case T_MR: 881: case T_PTR: 882: if ((n = dn_comp(dp->d_data, cp, buflen, (char **)dnptrs, 883: (char **)edp)) < 0) 884: return (-1); 885: putshort((u_short)n, sp); 886: cp += n; 887: break; 888: 889: case T_MB: 890: case T_NS: 891: /* Store domain name in answer */ 892: if ((n = dn_comp(dp->d_data, cp, buflen, (char **)dnptrs, 893: (char **)edp)) < 0) 894: return (-1); 895: putshort((u_short)n, sp); 896: cp += n; 897: if (!doadd) 898: break; 899: for (ap = addinfo, n = addcount; --n >= 0; ap++) 900: if (cistrcmp(ap->a_dname, dp->d_data) == 0) 901: goto found; 902: /* add domain name to additional section */ 903: if (addcount >= NADDRECS) 904: break; 905: addcount++; 906: ap->a_dname = dp->d_data; 907: ap->a_class = dp->d_class; 908: found: 909: break; 910: 911: case T_SOA: 912: case T_MINFO: 913: cp1 = dp->d_data; 914: if ((n = dn_comp(cp1, cp, buflen, (char **)dnptrs, 915: (char **)edp)) < 0) 916: return (-1); 917: cp += n; 918: buflen -= dp->d_type == T_MINFO ? n : n + 5 * sizeof(u_long); 919: cp1 += strlen(cp1) + 1; 920: if ((n = dn_comp(cp1, cp, buflen, (char **)dnptrs, 921: (char **)edp)) < 0) 922: return (-1); 923: cp += n; 924: if (dp->d_type == T_SOA) { 925: cp1 += strlen(cp1) + 1; 926: bcopy(cp1, cp, 927: (int)(n = dp->d_size - (cp1 - dp->d_data))); 928: cp += n; 929: } 930: putshort((u_short)(cp - sp) - sizeof(u_short), sp); 931: break; 932: 933: case T_MX: 934: /* cp1 == our data/ cp == data of RR */ 935: cp1 = dp->d_data; 936: 937: /* copy preference */ 938: bcopy(cp1,cp,sizeof(u_short)); 939: cp += sizeof(u_short); 940: cp1 += sizeof(u_short); 941: buflen -= sizeof(u_short); 942: 943: if ((n = dn_comp(cp1, cp, buflen, (char **)dnptrs, 944: (char **)edp)) < 0) 945: return(-1); 946: cp += n; 947: 948: /* save data length */ 949: putshort((u_short)(cp-sp)-sizeof(u_short),sp); 950: break; 951: 952: default: 953: if (dp->d_size > buflen) 954: return (-1); 955: bcopy(dp->d_data, cp, dp->d_size); 956: putshort((u_short)dp->d_size, sp); 957: cp += dp->d_size; 958: } 959: return (cp - buf); 960: } 961: 962: /* 963: * Lookup addresses for names in addinfo and put into the message's 964: * additional section. 965: */ 966: doaddinfo(hp, msg, msglen) 967: HEADER *hp; 968: char *msg; 969: int msglen; 970: { 971: register char *cp; 972: register struct namebuf *np; 973: register struct databuf *dp; 974: register struct databuf *tmp; 975: struct hashbuf *htp; 976: struct databuf *pdp; 977: struct addinfo *ap; 978: char *fname; 979: int n, count; 980: 981: #ifdef DEBUG 982: if (debug >= 3) 983: fprintf(ddt,"doaddinfo() addcount = %d\n", addcount); 984: #endif 985: 986: count = 0; 987: cp = msg; 988: for (ap = addinfo; --addcount >= 0; ap++) { 989: #ifdef DEBUG 990: if (debug >= 5) 991: fprintf(ddt,"do additional '%s'\n", ap->a_dname); 992: #endif 993: htp = hashtab; /* lookup relative to root */ 994: np = nlookup(ap->a_dname, &htp, &fname, 0); 995: if (np == NULL || fname != ap->a_dname) 996: continue; 997: #ifdef DEBUG 998: if (debug >= 5) 999: fprintf(ddt,"found it\n"); 1000: #endif 1001: pdp = NULL; 1002: dp = np->n_data; 1003: /* look for the data */ 1004: while (dp != NULL) { 1005: if (!match(dp, (int)ap->a_class, T_A)) { 1006: pdp = dp; 1007: dp = dp->d_next; 1008: continue; 1009: } 1010: if ((n = make_rr(ap->a_dname, dp, cp, msglen, 0)) < 0) 1011: { 1012: if (n == -1) 1013: break; 1014: /* delete old cache entry */ 1015: #ifdef DEBUG 1016: if (debug) 1017: fprintf(ddt,"deleting cache entry\n"); 1018: #endif 1019: rminv(dp); 1020: tmp = dp->d_next; 1021: (void) free((char *)dp); 1022: dp = tmp; 1023: if (pdp == NULL) 1024: np->n_data = dp; 1025: else 1026: pdp->d_next = dp; 1027: continue; 1028: } 1029: #ifdef DEBUG 1030: if (debug >= 5) 1031: fprintf(ddt,"n = %d\n", n); 1032: #endif 1033: cp += n; 1034: msglen -= n; 1035: count++; 1036: pdp = dp; 1037: dp = dp->d_next; 1038: } 1039: } 1040: hp->arcount = htons((u_short)count); 1041: return (cp - msg); 1042: } 1043: 1044: /* 1045: * Do we want this data record based on the class and type? 1046: */ 1047: wanted(dp, class, type) 1048: struct databuf *dp; 1049: int class, type; 1050: { 1051: 1052: #ifdef DEBUG 1053: if (debug > 3) 1054: fprintf(ddt,"wanted(%x, %d, %d) %d, %d\n", dp, class, type, 1055: dp->d_class, dp->d_type); 1056: #endif 1057: 1058: if (dp->d_class != class && class != C_ANY) 1059: return (0); 1060: if (type == dp->d_type) 1061: return (1); 1062: switch (dp->d_type) { 1063: case T_ANY: 1064: case T_CNAME: 1065: return (1); 1066: } 1067: switch (type) { 1068: case T_ANY: 1069: return (1); 1070: 1071: case T_MAILB: 1072: switch (dp->d_type) { 1073: case T_MR: 1074: case T_MB: 1075: case T_MG: 1076: case T_MINFO: 1077: return (1); 1078: } 1079: break; 1080: 1081: case T_AXFR: 1082: if (dp->d_type == T_SOA) 1083: return (1); 1084: } 1085: return (0); 1086: } 1087: 1088: /* 1089: * Get the domain name of 'np' and put in 'buf'. 1090: */ 1091: getname(np, buf, buflen) 1092: struct namebuf *np; 1093: char *buf; 1094: int buflen; 1095: { 1096: register char *cp; 1097: 1098: cp = buf; 1099: while (np != NULL) { 1100: if (cp != buf) 1101: *cp++ = '.'; 1102: (void) strcpy(cp, np->n_dname); 1103: cp += strlen(cp); 1104: np = np->n_parent; 1105: } 1106: *cp = '\0'; 1107: } 1108: 1109: /* 1110: * Do a zone transfer. SOA record already sent. 1111: */ 1112: doaxfr(np, rfp, isroot) 1113: register struct namebuf *np; 1114: FILE *rfp; 1115: int isroot; 1116: { 1117: register struct databuf *dp; 1118: register int n; 1119: struct namebuf **npp, **nppend; 1120: char msg[PACKETSZ]; 1121: HEADER *hp = (HEADER *) msg; 1122: char *cp; 1123: char dname[MAXDNAME]; 1124: int fndns; 1125: 1126: #ifdef DEBUG 1127: if (debug && isroot) 1128: fprintf(ddt,"doaxfr()\n"); 1129: #endif 1130: fndns = 0; 1131: hp->id = 0; 1132: hp->opcode = QUERY; 1133: hp->qr = hp->aa = hp->tc = hp->ra = hp->pr = hp->rd = 0; 1134: hp->rcode = NOERROR; 1135: hp->qdcount = 0; 1136: hp->ancount = htons(1); 1137: hp->nscount = 0; 1138: hp->arcount = 0; 1139: cp = msg + sizeof(HEADER); 1140: getname(np, dname, sizeof(dname)); 1141: 1142: /* first do data records */ 1143: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { 1144: /* skip the root SOA record (marks end of data) */ 1145: if (isroot) { 1146: if (dp->d_type == T_SOA) 1147: continue; 1148: } else if (dp->d_type == T_NS) 1149: fndns = 1; 1150: if (dp->d_zone == 0) 1151: continue; 1152: if ((n = make_rr(dname, dp, cp, 1153: sizeof(msg)-sizeof(HEADER), 0)) < 0) 1154: continue; 1155: fwritemsg(rfp, msg, n + sizeof(HEADER)); 1156: } 1157: 1158: /* next do subdomains */ 1159: if (fndns || np->n_hash == NULL) 1160: return; 1161: npp = np->n_hash->h_tab; 1162: nppend = npp + np->n_hash->h_size; 1163: while (npp < nppend) { 1164: for (np = *npp++; np != NULL; np = np->n_next) { 1165: doaxfr(np, rfp, 0); 1166: } 1167: } 1168: #ifdef DEBUG 1169: if (debug && isroot) 1170: fprintf(ddt,"exit doaxfr()\n"); 1171: #endif 1172: }