|
|
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_resp.c 4.51 (Berkeley) 7/9/88"; ! 20: #endif /* not lint */ ! 21: ! 22: #include <stdio.h> ! 23: #include <sys/param.h> ! 24: #include <sys/time.h> ! 25: #include <sys/socket.h> ! 26: #include <sys/file.h> ! 27: #include <netinet/in.h> ! 28: #include <syslog.h> ! 29: #include <arpa/nameser.h> ! 30: #include "ns.h" ! 31: #include "db.h" ! 32: ! 33: extern int debug; ! 34: extern FILE *ddt; ! 35: extern int errno; ! 36: extern u_char *dnptrs[]; ! 37: extern time_t retrytime(); ! 38: extern struct fwdinfo *fwdtab; ! 39: extern struct sockaddr_in from_addr; /* Source addr of last packet */ ! 40: extern int needs_prime_cache; ! 41: extern int priming; ! 42: ! 43: struct qinfo *sysquery(); ! 44: ! 45: ns_resp(msg, msglen) ! 46: u_char *msg; ! 47: int msglen; ! 48: { ! 49: register struct qinfo *qp; ! 50: register HEADER *hp; ! 51: register struct qserv *qs; ! 52: register struct databuf *ns, *ns2; ! 53: register u_char *cp; ! 54: struct databuf *nsp[NSMAX], **nspp; ! 55: int i, c, n, ancount, aucount, nscount, arcount; ! 56: int type, class, dbflags; ! 57: int cname = 0; /* flag for processing cname response */ ! 58: int count, founddata, foundname; ! 59: int buflen; ! 60: int newmsglen; ! 61: char name[MAXDNAME], *dname; ! 62: char *fname; ! 63: u_char newmsg[BUFSIZ]; ! 64: u_char **dpp, *tp; ! 65: time_t rtrip; ! 66: ! 67: struct hashbuf *htp; ! 68: struct namebuf *np; ! 69: struct netinfo *lp; ! 70: extern struct netinfo *local(); ! 71: extern int nsid; ! 72: extern int addcount; ! 73: ! 74: #ifdef STATS ! 75: stats[S_RESPONSES].cnt++; ! 76: #endif ! 77: hp = (HEADER *) msg; ! 78: if ((qp = qfindid(hp->id)) == NULL ) { ! 79: #ifdef DEBUG ! 80: if (debug > 1) ! 81: fprintf(ddt,"DUP? dropped (id %d)\n", ntohs(hp->id)); ! 82: #endif ! 83: #ifdef STATS ! 84: stats[S_DUPRESP].cnt++; ! 85: #endif ! 86: return; ! 87: } ! 88: ! 89: #ifdef DEBUG ! 90: if (debug >= 2) ! 91: fprintf(ddt,"%s response nsid=%d id=%d\n", ! 92: qp->q_system ? "SYSTEM" : "USER", ! 93: ntohs(qp->q_nsid), ntohs(qp->q_id)); ! 94: #endif ! 95: ! 96: /* ! 97: * Here we handle bad responses from servers. ! 98: * Several possibilities come to mind: ! 99: * The server is sick and returns SERVFAIL ! 100: * The server returns some garbage opcode (its sick) ! 101: * The server can't understand our query and return FORMERR ! 102: * In all these cases, we simply drop the packet and force ! 103: * a retry. This will make him look bad due to unresponsiveness. ! 104: * Be sure not to include authoritative NXDOMAIN ! 105: */ ! 106: if ((hp->rcode != NOERROR && hp->rcode != NXDOMAIN) ! 107: || (hp->rcode == NXDOMAIN && !hp->aa) ! 108: || hp->opcode != QUERY) { ! 109: #ifdef DEBUG ! 110: if (debug >= 2) ! 111: fprintf(ddt,"resp: error (ret %d, op %d), dropped\n", ! 112: hp->rcode, hp->opcode); ! 113: #endif ! 114: #ifdef STATS ! 115: stats[S_BADRESPONSES].cnt++; ! 116: #endif ! 117: return; ! 118: } ! 119: ! 120: #ifdef ALLOW_UPDATES ! 121: if ( (hp->rcode == NOERROR) && ! 122: (hp->opcode == UPDATEA || hp->opcode == UPDATED || ! 123: hp->opcode == UPDATEDA || hp->opcode == UPDATEM || ! 124: hp->opcode == UPDATEMA) ) { ! 125: /* ! 126: * Update the secondary's copy, now that the primary ! 127: * successfully completed the update. Zone doesn't matter ! 128: * for dyn. update -- doupdate calls findzone to find it ! 129: */ ! 130: doupdate(qp->q_msg, qp->q_msglen, qp->q_msg + sizeof(HEADER), ! 131: 0, (struct databuf *)0, 0); ! 132: #ifdef DEBUG ! 133: if (debug >= 3) ! 134: fprintf(ddt,"resp: leaving, UPDATE*\n"); ! 135: #endif ! 136: /* return code filled in by doupdate */ ! 137: goto return_msg; ! 138: } ! 139: #endif ALLOW_UPDATES ! 140: ! 141: /* ! 142: * If we were using nameservers, find the qinfo pointer and update ! 143: * the rtt and fact that we have called on this server before. ! 144: */ ! 145: if (qp->q_fwd == (struct fwdinfo *)0) { ! 146: struct timeval *stp; ! 147: ! 148: for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++) ! 149: if (bcmp((char *)&qs->ns_addr.sin_addr, ! 150: &from_addr.sin_addr, sizeof(struct in_addr)) == 0) ! 151: break; ! 152: if (n >= qp->q_naddr) { ! 153: #ifdef DEBUG ! 154: if (debug) ! 155: fprintf(ddt, "Response from unexpected source %s\n", ! 156: inet_ntoa(from_addr.sin_addr)); ! 157: #endif DEBUG ! 158: #ifdef STATS ! 159: stats[S_MARTIANS].cnt++; ! 160: #endif ! 161: /* assume response to have come from last query */ ! 162: qs = &qp->q_addr[qp->q_curaddr]; ! 163: } ! 164: stp = &qs->stime; ! 165: ! 166: /* Handle response from different (untried) interface */ ! 167: if (stp->tv_sec == 0) { ! 168: ns = qs->ns; ! 169: while (qs > qp->q_addr && ! 170: (qs->stime.tv_sec == 0 || qs->ns != ns)) ! 171: qs--; ! 172: *stp = qs->stime; ! 173: #ifdef DEBUG ! 174: if (debug) ! 175: fprintf(ddt, ! 176: "Response from unused address %s, assuming %s\n", ! 177: inet_ntoa(from_addr.sin_addr), ! 178: inet_ntoa(qs->ns_addr.sin_addr)); ! 179: #endif DEBUG ! 180: } ! 181: ! 182: /* compute query round trip time */ ! 183: rtrip = ((tt.tv_sec - stp->tv_sec) * 1000 + ! 184: (tt.tv_usec - stp->tv_usec) / 1000); ! 185: ! 186: #ifdef DEBUG ! 187: if (debug > 2) ! 188: fprintf(ddt,"stime %d/%d now %d/%d rtt %d\n", ! 189: stp->tv_sec, stp->tv_usec, ! 190: tt.tv_sec, tt.tv_usec, rtrip); ! 191: #endif ! 192: ns = qs->nsdata; ! 193: /* ! 194: * Don't update nstime if this doesn't look ! 195: * like an address databuf now. XXX ! 196: */ ! 197: if (ns->d_type == T_A && ns->d_class == qs->ns->d_class) { ! 198: if (ns->d_nstime == 0) ! 199: ns->d_nstime = (u_long)rtrip; ! 200: else ! 201: ns->d_nstime = ns->d_nstime * ALPHA + ! 202: (1-ALPHA) * (u_long)rtrip; ! 203: /* prevent floating point overflow, limit to 1000 sec */ ! 204: if (ns->d_nstime > 1000000) ! 205: ns->d_nstime = 1000000; ! 206: } ! 207: ! 208: /* ! 209: * Record the source so that we do not use this NS again. ! 210: */ ! 211: if(qp->q_nusedns < NSMAX) { ! 212: qp->q_usedns[qp->q_nusedns++] = qs->ns; ! 213: #ifdef DEBUG ! 214: if(debug > 1) ! 215: fprintf(ddt, "NS #%d addr %s used, rtt %d\n", ! 216: n, inet_ntoa(qs->ns_addr.sin_addr), ! 217: ns->d_nstime); ! 218: #endif DEBUG ! 219: } ! 220: ! 221: /* ! 222: * Penalize those who had earlier chances but failed ! 223: * by multiplying round-trip times by BETA (>1). ! 224: * Improve nstime for unused addresses by applying GAMMA. ! 225: * The GAMMA factor makes unused entries slowly ! 226: * improve, so they eventually get tried again. ! 227: * GAMMA should be slightly less than 1. ! 228: * Watch out for records that may have timed out ! 229: * and are no longer the correct type. XXX ! 230: */ ! 231: ! 232: for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++) { ! 233: ns2 = qs->nsdata; ! 234: if (ns2 == ns) ! 235: continue; ! 236: if (ns2->d_type != T_A || ! 237: ns2->d_class != qs->ns->d_class) /* XXX */ ! 238: continue; ! 239: if (qs->stime.tv_sec) { ! 240: if (ns2->d_nstime == 0) ! 241: ns2->d_nstime = rtrip * BETA; ! 242: else ! 243: ns2->d_nstime = ! 244: ns2->d_nstime * BETA + (1-ALPHA) * rtrip; ! 245: if (ns2->d_nstime > 1000000) ! 246: ns2->d_nstime = 1000000; ! 247: } else ! 248: ns2->d_nstime = ns2->d_nstime * GAMMA; ! 249: #ifdef DEBUG ! 250: if(debug > 1) ! 251: fprintf(ddt, "NS #%d %s rtt now %d\n", n, ! 252: inet_ntoa(qs->ns_addr.sin_addr), ! 253: ns2->d_nstime); ! 254: #endif DEBUG ! 255: } ! 256: } ! 257: ! 258: /* ! 259: * Skip query section ! 260: */ ! 261: addcount = 0; ! 262: cp = msg + sizeof(HEADER); ! 263: dpp = dnptrs; ! 264: *dpp++ = msg; ! 265: if ((*cp & INDIR_MASK) == 0) ! 266: *dpp++ = cp; ! 267: *dpp = NULL; ! 268: if (hp->qdcount) { ! 269: n = dn_skipname(cp, msg + msglen); ! 270: if (n <= 0) ! 271: goto formerr; ! 272: cp += n; ! 273: GETSHORT(type, cp); ! 274: GETSHORT(class, cp); ! 275: if (cp - msg > msglen) ! 276: goto formerr; ! 277: } ! 278: ! 279: /* ! 280: * Save answers, authority, and additional records for future use. ! 281: */ ! 282: ancount = ntohs(hp->ancount); ! 283: aucount = ntohs(hp->nscount); ! 284: arcount = ntohs(hp->arcount); ! 285: nscount = 0; ! 286: tp = cp; ! 287: #ifdef DEBUG ! 288: if (debug >= 3) ! 289: fprintf(ddt,"resp: ancount %d, aucount %d, arcount %d\n", ! 290: ancount, aucount, arcount); ! 291: #endif ! 292: ! 293: /* ! 294: * If there's an answer, check if it's a CNAME response; ! 295: * if no answer but aucount > 0, see if there is an NS ! 296: * or just an SOA. (NOTE: ancount might be 1 with a CNAME, ! 297: * and NS records may still be in the authority section; ! 298: * we don't bother counting them, as we only use nscount ! 299: * if ancount == 0.) ! 300: */ ! 301: if (ancount == 1 || (ancount == 0 && aucount > 0)) { ! 302: c = aucount; ! 303: do { ! 304: if (tp - msg >= msglen) ! 305: goto formerr; ! 306: n = dn_skipname(tp, msg + msglen); ! 307: if (n <= 0) ! 308: goto formerr; ! 309: tp += n; /* name */ ! 310: GETSHORT(i, tp); /* type */ ! 311: tp += sizeof(u_short); /* class */ ! 312: tp += sizeof(u_long); /* ttl */ ! 313: GETSHORT(count, tp); /* dlen */ ! 314: if (tp - msg > msglen - count) ! 315: goto formerr; ! 316: tp += count; ! 317: if (ancount && i == T_CNAME) { ! 318: cname++; ! 319: #ifdef DEBUG ! 320: if (debug) ! 321: fprintf(ddt,"CNAME - needs more processing\n"); ! 322: #endif ! 323: if (!qp->q_cmsglen) { ! 324: qp->q_cmsg = qp->q_msg; ! 325: qp->q_cmsglen = qp->q_msglen; ! 326: qp->q_msg = NULL; ! 327: qp->q_msglen = 0; ! 328: } ! 329: } ! 330: /* ! 331: * See if authority record is a nameserver. ! 332: */ ! 333: if (ancount == 0 && i == T_NS) ! 334: nscount++; ! 335: } while (--c > 0); ! 336: tp = cp; ! 337: } ! 338: ! 339: /* ! 340: * Add the info received in the response to the Data Base ! 341: */ ! 342: c = ancount + aucount + arcount; ! 343: #ifdef notdef ! 344: /* ! 345: * If the request was for a CNAME that doesn't exist, ! 346: * but the name is valid, fetch any other data for the name. ! 347: * DON'T do this now, as it will requery if data are already ! 348: * in the cache (maybe later with negative caching). ! 349: */ ! 350: if (hp->qdcount && type == T_CNAME && c == 0 && hp->rcode == NOERROR && ! 351: !qp->q_system) { ! 352: #ifdef DEBUG ! 353: if (debug >= 3) ! 354: fprintf(ddt,"resp: leaving, no CNAME\n"); ! 355: #endif ! 356: /* Cause us to put it in the cache later */ ! 357: prime(class, T_ANY, qp); ! 358: ! 359: /* Nothing to store, just give user the answer */ ! 360: goto return_msg; ! 361: } ! 362: #endif /* notdef */ ! 363: ! 364: nspp = nsp; ! 365: if (qp->q_system) ! 366: dbflags = DB_NOTAUTH | DB_NODATA; ! 367: else ! 368: dbflags = DB_NOTAUTH | DB_NODATA | DB_NOHINTS; ! 369: for (i = 0; i < c; i++) { ! 370: struct databuf *ns3; ! 371: ! 372: if (cp >= msg + msglen) ! 373: goto formerr; ! 374: ns3 = 0; ! 375: if ((n = doupdate(msg, msglen, cp, 0, &ns3, dbflags)) < 0) { ! 376: #ifdef DEBUG ! 377: if (debug) ! 378: fprintf(ddt,"resp: leaving, doupdate failed\n"); ! 379: #endif ! 380: /* return code filled in by doupdate */ ! 381: goto return_msg; ! 382: } ! 383: /* ! 384: * Remember nameservers from the authority section ! 385: * for referrals. ! 386: * (This is usually overwritten by findns below(?). XXX ! 387: */ ! 388: if (ns3 && i >= ancount && i < ancount + aucount && ! 389: nspp < &nsp[NSMAX-1]) ! 390: *nspp++ = ns3; ! 391: cp += n; ! 392: } ! 393: ! 394: if (qp->q_system && ancount) { ! 395: if (qp->q_system == PRIMING_CACHE) ! 396: check_root(); ! 397: #ifdef DEBUG ! 398: if (debug > 2) ! 399: fprintf(ddt,"resp: leaving, SYSQUERY ancount %d\n", ancount); ! 400: #endif ! 401: qremove(qp); ! 402: return; ! 403: } ! 404: ! 405: if (cp > msg + msglen) ! 406: goto formerr; ! 407: ! 408: /* ! 409: * If there are addresses and this is a local query, ! 410: * sort them appropriately for the local context. ! 411: */ ! 412: if (ancount > 1 && (lp = local(&qp->q_from)) != NULL) ! 413: sort_response(tp, ancount, lp, msg + msglen); ! 414: ! 415: /* ! 416: * An answer to a C_ANY query or a successful answer to a ! 417: * regular query with no indirection, then just return answer. ! 418: */ ! 419: if ((type == C_ANY && ancount) || ! 420: (!cname && !qp->q_cmsglen && ancount)) { ! 421: #ifdef DEBUG ! 422: if (debug >= 3) ! 423: fprintf(ddt,"resp: got as much answer as there is\n"); ! 424: #endif ! 425: goto return_msg; ! 426: } ! 427: ! 428: /* ! 429: * Eventually we will want to cache this negative answer. ! 430: */ ! 431: if (ancount == 0 && nscount == 0 && ! 432: (hp->aa || qp->q_fwd || class == C_ANY)) { ! 433: /* We have an authoritative NO */ ! 434: #ifdef DEBUG ! 435: if (debug >= 3) ! 436: fprintf(ddt,"resp: leaving auth NO\n"); ! 437: #endif ! 438: if (qp->q_cmsglen) { ! 439: msg = (u_char *)qp->q_cmsg; ! 440: msglen = qp->q_cmsglen; ! 441: hp = (HEADER *)msg; ! 442: } ! 443: goto return_msg; ! 444: } ! 445: ! 446: /* ! 447: * All messages in here need further processing. i.e. they ! 448: * are either CNAMEs or we got referred again. ! 449: */ ! 450: count = 0; ! 451: founddata = 0; ! 452: foundname = 0; ! 453: dname = name; ! 454: if (!cname && qp->q_cmsglen && ancount) { ! 455: #ifdef DEBUG ! 456: if (debug) ! 457: fprintf(ddt,"Cname second pass\n"); ! 458: #endif ! 459: newmsglen = qp->q_cmsglen; ! 460: bcopy(qp->q_cmsg, newmsg, newmsglen); ! 461: } else { ! 462: newmsglen = msglen; ! 463: bcopy(msg, newmsg, newmsglen); ! 464: } ! 465: hp = (HEADER *) newmsg; ! 466: hp->ancount = 0; ! 467: hp->nscount = 0; ! 468: hp->arcount = 0; ! 469: dnptrs[0] = newmsg; ! 470: dnptrs[1] = NULL; ! 471: cp = newmsg + sizeof(HEADER); ! 472: if (cname) ! 473: cp += dn_skipname(cp, newmsg + newmsglen) + QFIXEDSZ; ! 474: if ((n = dn_expand(newmsg, newmsg + newmsglen, ! 475: cp, dname, sizeof(name))) < 0) { ! 476: #ifdef DEBUG ! 477: if (debug) ! 478: fprintf(ddt,"dn_expand failed\n" ); ! 479: #endif ! 480: goto servfail; ! 481: } ! 482: cp = newmsg + sizeof(HEADER) + ! 483: (cname ? dn_skipname(cp, newmsg + newmsglen) : n) + QFIXEDSZ; ! 484: buflen = sizeof(newmsg) - (cp - newmsg); ! 485: ! 486: try_again: ! 487: #ifdef DEBUG ! 488: if (debug) ! 489: fprintf(ddt,"resp: nlookup(%s) type=%d\n",dname, type); ! 490: #endif ! 491: fname = ""; ! 492: htp = hashtab; /* lookup relative to root */ ! 493: np = nlookup(dname, &htp, &fname, 0); ! 494: #ifdef DEBUG ! 495: if (debug) ! 496: fprintf(ddt,"resp: %s '%s' as '%s' (cname=%d)\n", ! 497: np == NULL ? "missed" : "found", dname, fname, cname); ! 498: #endif ! 499: if (np == NULL || fname != dname) ! 500: goto fetch_ns; ! 501: ! 502: foundname++; ! 503: count = cp - newmsg; ! 504: n = finddata(np, class, type, hp, &dname, &buflen, &count); ! 505: if (n == 0) ! 506: goto fetch_ns; /* NO data available */ ! 507: cp += n; ! 508: buflen -= n; ! 509: hp->ancount += count; ! 510: if (fname != dname && type != T_CNAME && type != T_ANY) { ! 511: cname++; ! 512: goto try_again; ! 513: } ! 514: founddata = 1; ! 515: ! 516: #ifdef DEBUG ! 517: if (debug >= 3) { ! 518: fprintf(ddt,"resp: foundname = %d count = %d ", foundname, count); ! 519: fprintf(ddt,"founddata = %d cname = %d\n", founddata, cname); ! 520: } ! 521: #endif ! 522: ! 523: fetch_ns: ! 524: hp->ancount = htons(hp->ancount); ! 525: /* ! 526: * Look for name servers to refer to and fill in the authority ! 527: * section or record the address for forwarding the query ! 528: * (recursion desired). ! 529: */ ! 530: switch (findns(&np, class, nsp, &count)) { ! 531: case NXDOMAIN: /* shouldn't happen */ ! 532: #ifdef DEBUG ! 533: if (debug >= 3) ! 534: fprintf(ddt,"req: leaving (%s, rcode %d)\n", ! 535: dname, hp->rcode); ! 536: #endif ! 537: if (!foundname) ! 538: hp->rcode = NXDOMAIN; ! 539: if (class != C_ANY) { ! 540: hp->aa = 1; ! 541: /* ! 542: * should return SOA if founddata == 0, ! 543: * but old named's are confused by an SOA ! 544: * in the auth. section if there's no error. ! 545: */ ! 546: if (foundname == 0 && np) { ! 547: n = doaddauth(hp, cp, buflen, np, nsp[0]); ! 548: cp += n; ! 549: buflen -= n; ! 550: } ! 551: } ! 552: goto return_newmsg; ! 553: ! 554: case SERVFAIL: ! 555: goto servfail; ! 556: } ! 557: ! 558: if (founddata) { ! 559: hp = (HEADER *)newmsg; ! 560: n = add_data(np, nsp, cp, buflen); ! 561: if (n < 0) { ! 562: hp->tc = 1; ! 563: n = (-n); ! 564: } ! 565: cp += n; ! 566: buflen -= n; ! 567: hp->nscount = htons((u_short)count); ! 568: goto return_newmsg; ! 569: } ! 570: ! 571: /* ! 572: * If we get here, we don't have the answer yet and are about ! 573: * to iterate to try and get it. First, infinite loop avoidance. ! 574: */ ! 575: if (qp->q_nqueries++ > MAXQUERIES) { ! 576: #ifdef DEBUG ! 577: if (debug) ! 578: fprintf(ddt,"resp: MAXQUERIES exceeded (%s, class %d, type %d)\n", ! 579: dname, class, type); ! 580: #endif ! 581: syslog(LOG_NOTICE, ! 582: "MAXQUERIES exceeded, possible data loop in resolving (%s)", ! 583: dname); ! 584: goto servfail; ! 585: } ! 586: ! 587: /* Reset the query control structure */ ! 588: qp->q_naddr = 0; ! 589: qp->q_curaddr = 0; ! 590: qp->q_fwd = fwdtab; ! 591: qp->q_addr[0].stime = tt; ! 592: if (nslookup(nsp, qp) == 0) { ! 593: #ifdef DEBUG ! 594: if (debug >= 3) ! 595: fprintf(ddt,"resp: no addrs found for NS's\n"); ! 596: #endif ! 597: goto servfail; ! 598: } ! 599: if (cname) { ! 600: if (qp->q_cname++ == MAXCNAMES) { ! 601: #ifdef DEBUG ! 602: if (debug >= 3) ! 603: fprintf(ddt,"resp: leaving, MAXCNAMES exceeded\n"); ! 604: #endif ! 605: goto servfail; ! 606: } ! 607: #ifdef DEBUG ! 608: if (debug) ! 609: fprintf(ddt,"q_cname = %d\n",qp->q_cname); ! 610: if (debug >= 3) ! 611: fprintf(ddt,"resp: building recursive query; nslookup\n"); ! 612: #endif ! 613: if (qp->q_msg) ! 614: (void) free(qp->q_msg); ! 615: if ((qp->q_msg = malloc(BUFSIZ)) == NULL) { ! 616: #ifdef DEBUG ! 617: if (debug) ! 618: fprintf(ddt,"resp: malloc error\n"); ! 619: #endif ! 620: goto servfail; ! 621: } ! 622: qp->q_msglen = res_mkquery(QUERY, dname, class, ! 623: type, (char *)NULL, 0, NULL, qp->q_msg, BUFSIZ); ! 624: hp = (HEADER *) qp->q_msg; ! 625: hp->rd = 0; ! 626: } else ! 627: hp = (HEADER *)qp->q_msg; ! 628: hp->id = qp->q_nsid = htons((u_short)++nsid); ! 629: unsched(qp); ! 630: schedretry(qp, retrytime(qp)); ! 631: #ifdef DEBUG ! 632: if (debug) ! 633: fprintf(ddt,"resp: forw -> %s %d (%d) nsid=%d id=%d %dms\n", ! 634: inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr), ! 635: ds, ntohs(Q_NEXTADDR(qp,0)->sin_port), ! 636: ntohs(qp->q_nsid), ntohs(qp->q_id), ! 637: qp->q_addr[0].nsdata->d_nstime); ! 638: if ( debug >= 10) ! 639: fp_query(msg, ddt); ! 640: #endif ! 641: if (sendto(ds, qp->q_msg, qp->q_msglen, 0, ! 642: (struct sockaddr *)Q_NEXTADDR(qp,0), ! 643: sizeof(struct sockaddr_in)) < 0) { ! 644: #ifdef DEBUG ! 645: if (debug >= 5) ! 646: fprintf(ddt, "sendto error = %d\n", errno); ! 647: #endif ! 648: } ! 649: #ifdef STATS ! 650: stats[S_OUTPKTS].cnt++; ! 651: #endif ! 652: #ifdef DEBUG ! 653: if (debug >= 3) ! 654: fprintf(ddt,"resp: Query sent.\n"); ! 655: #endif ! 656: return; ! 657: ! 658: formerr: ! 659: #ifdef DEBUG ! 660: if (debug) ! 661: fprintf(ddt,"FORMERR resp() from %s size err %d, msglen %d\n", ! 662: inet_ntoa(from_addr.sin_addr), ! 663: cp-msg, msglen); ! 664: #endif ! 665: syslog(LOG_INFO, "Malformed response from %s\n", ! 666: inet_ntoa(from_addr.sin_addr)); ! 667: #ifdef STATS ! 668: stats[S_RESPFORMERR].cnt++; ! 669: #endif ! 670: return; ! 671: ! 672: return_msg: ! 673: #ifdef STATS ! 674: stats[S_RESPOK].cnt++; ! 675: #endif ! 676: /* The "standard" return code */ ! 677: hp->qr = 1; ! 678: hp->id = qp->q_id; ! 679: hp->rd = 1; ! 680: hp->ra = 1; ! 681: (void) send_msg(msg, msglen, qp); ! 682: qremove(qp); ! 683: return; ! 684: ! 685: return_newmsg: ! 686: #ifdef STATS ! 687: stats[S_RESPOK].cnt++; ! 688: #endif ! 689: if (addcount) { ! 690: n = doaddinfo(hp, cp, buflen); ! 691: cp += n; ! 692: buflen -= n; ! 693: } ! 694: ! 695: hp->id = qp->q_id; ! 696: hp->rd = 1; ! 697: hp->ra = 1; ! 698: hp->qr = 1; ! 699: (void) send_msg(newmsg, cp - newmsg, qp); ! 700: qremove(qp); ! 701: return; ! 702: ! 703: servfail: ! 704: #ifdef STATS ! 705: stats[S_RESPFAIL].cnt++; ! 706: #endif ! 707: hp = (HEADER *)(cname ? qp->q_cmsg : qp->q_msg); ! 708: hp->rcode = SERVFAIL; ! 709: hp->id = qp->q_id; ! 710: hp->rd = 1; ! 711: hp->ra = 1; ! 712: hp->qr = 1; ! 713: (void) send_msg((char *)hp, (cname ? qp->q_cmsglen : qp->q_msglen), qp); ! 714: qremove(qp); ! 715: return; ! 716: } ! 717: ! 718: /* ! 719: * Decode the resource record 'rrp' and update the database. ! 720: * If savens is true, record pointer for forwarding queries a second time. ! 721: */ ! 722: doupdate(msg, msglen, rrp, zone, savens, flags) ! 723: char *msg ; ! 724: u_char *rrp; ! 725: struct databuf **savens; ! 726: int msglen, zone, flags; ! 727: { ! 728: register u_char *cp; ! 729: register int n; ! 730: int class, type, dlen, n1; ! 731: u_long ttl; ! 732: struct databuf *dp; ! 733: char dname[MAXDNAME]; ! 734: u_char *cp1; ! 735: u_char data[BUFSIZ]; ! 736: register HEADER *hp = (HEADER *) msg; ! 737: ! 738: #ifdef DEBUG ! 739: if (debug > 2) ! 740: fprintf(ddt,"doupdate(zone %d, savens %x, flags %x)\n", ! 741: zone, savens, flags); ! 742: #endif ! 743: ! 744: cp = rrp; ! 745: if ((n = dn_expand(msg, msg + msglen, cp, dname, sizeof(dname))) < 0) { ! 746: hp->rcode = FORMERR; ! 747: return (-1); ! 748: } ! 749: cp += n; ! 750: GETSHORT(type, cp); ! 751: GETSHORT(class, cp); ! 752: GETLONG(ttl, cp); ! 753: GETSHORT(dlen, cp); ! 754: #ifdef DEBUG ! 755: if (debug > 2) ! 756: fprintf(ddt,"doupdate: dname %s type %d class %d ttl %d\n", ! 757: dname, type, class, ttl); ! 758: #endif ! 759: /* ! 760: * Convert the resource record data into the internal ! 761: * database format. ! 762: */ ! 763: switch (type) { ! 764: case T_A: ! 765: case T_WKS: ! 766: case T_HINFO: ! 767: case T_UINFO: ! 768: case T_UID: ! 769: case T_GID: ! 770: #ifdef ALLOW_T_UNSPEC ! 771: case T_UNSPEC: ! 772: #endif ALLOW_T_UNSPEC ! 773: cp1 = cp; ! 774: n = dlen; ! 775: cp += n; ! 776: break; ! 777: ! 778: case T_CNAME: ! 779: case T_MB: ! 780: case T_MG: ! 781: case T_MR: ! 782: case T_NS: ! 783: case T_PTR: ! 784: if ((n = dn_expand(msg, msg + msglen, cp, data, ! 785: sizeof(data))) < 0) { ! 786: hp->rcode = FORMERR; ! 787: return (-1); ! 788: } ! 789: cp += n; ! 790: cp1 = data; ! 791: n = strlen(data) + 1; ! 792: break; ! 793: ! 794: case T_MINFO: ! 795: case T_SOA: ! 796: if ((n = dn_expand(msg, msg + msglen, cp, data, ! 797: sizeof(data))) < 0) { ! 798: hp->rcode = FORMERR; ! 799: return (-1); ! 800: } ! 801: cp += n; ! 802: cp1 = data + (n = strlen(data) + 1); ! 803: n1 = sizeof(data) - n; ! 804: if (type == T_SOA) ! 805: n1 -= 5 * sizeof(u_long); ! 806: if ((n = dn_expand(msg, msg + msglen, cp, cp1, n1)) < 0) { ! 807: hp->rcode = FORMERR; ! 808: return (-1); ! 809: } ! 810: cp += n; ! 811: cp1 += strlen(cp1) + 1; ! 812: if (type == T_SOA) { ! 813: bcopy(cp, cp1, n = 5 * sizeof(u_long)); ! 814: cp += n; ! 815: cp1 += n; ! 816: } ! 817: n = cp1 - data; ! 818: cp1 = data; ! 819: break; ! 820: ! 821: case T_MX: ! 822: /* grab preference */ ! 823: bcopy(cp,data,sizeof(u_short)); ! 824: cp1 = data + sizeof(u_short); ! 825: cp += sizeof(u_short); ! 826: ! 827: /* get name */ ! 828: if ((n = dn_expand(msg, msg + msglen, cp, cp1, ! 829: sizeof(data)-sizeof(u_short))) < 0) ! 830: return(-1); ! 831: cp += n; ! 832: ! 833: /* compute end of data */ ! 834: cp1 += strlen(cp1) + 1; ! 835: /* compute size of data */ ! 836: n = cp1 - data; ! 837: cp1 = data; ! 838: break; ! 839: ! 840: default: ! 841: #ifdef DEBUG ! 842: if (debug >= 3) ! 843: fprintf(ddt,"unknown type %d\n", type); ! 844: #endif ! 845: return ((cp - rrp) + dlen); ! 846: } ! 847: if (n > MAXDATA) { ! 848: #ifdef DEBUG ! 849: if (debug) ! 850: fprintf(ddt, ! 851: "update type %d: %d bytes is too much data\n", ! 852: type, n); ! 853: #endif ! 854: hp->rcode = NOCHANGE; /* XXX - FORMERR ??? */ ! 855: return(-1); ! 856: } ! 857: ! 858: #ifdef ALLOW_UPDATES ! 859: /* ! 860: * If this is a dynamic update request, process it specially; else, ! 861: * execute normal update code. ! 862: */ ! 863: switch(opcode) { ! 864: ! 865: /* For UPDATEM and UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA */ ! 866: case UPDATEM: ! 867: case UPDATEMA: ! 868: ! 869: /* ! 870: * The named code for UPDATED and UPDATEDA is the same except that for ! 871: * UPDATEDA we we ignore any data that was passed: we just delete all ! 872: * RRs whose name, type, and class matches ! 873: */ ! 874: case UPDATED: ! 875: case UPDATEDA: ! 876: if (type == T_SOA) { /* Not allowed */ ! 877: #ifdef DEBUG ! 878: if (debug) ! 879: fprintf(ddt, "UDPATE: REFUSED - SOA delete\n"); ! 880: #endif ! 881: hp->rcode = REFUSED; ! 882: return(-1); ! 883: } ! 884: /* ! 885: * Don't check message length if doing UPDATEM/UPDATEMA, ! 886: * since the whole message wont have been demarshalled until ! 887: * we reach the code for UPDATEA ! 888: */ ! 889: if ( (opcode == UPDATED) || (opcode == UPDATEDA) ) { ! 890: if (cp != msg + msglen) { ! 891: #ifdef DEBUG ! 892: if (debug) ! 893: fprintf(ddt,"FORMERR UPDATE message length off\n"); ! 894: #endif ! 895: hp->rcode = FORMERR; ! 896: return(-1); ! 897: } ! 898: } ! 899: if ((zonenum = findzone(dname, class)) == 0) { ! 900: hp->rcode = NXDOMAIN; ! 901: return(-1); ! 902: } ! 903: if ( (opcode == UPDATED) || (opcode == UPDATEM) ) { ! 904: /* Make a dp for use in db_update, as old dp */ ! 905: dp = savedata(class, type, 0, cp1, n); ! 906: dp->d_zone = zonenum; ! 907: n = db_update(dname, dp, NULL, DB_MEXIST | DB_DELETE, ! 908: hashtab); ! 909: if (n != OK) { ! 910: #ifdef DEBUG ! 911: if (debug) ! 912: fprintf(ddt,"UPDATE: db_update failed\n"); ! 913: #endif DEBUG ! 914: free( (struct databuf *) dp); ! 915: hp->rcode = NOCHANGE; ! 916: return(-1); ! 917: } ! 918: } else { /* UPDATEDA or UPDATEMA */ ! 919: int DeletedOne = 0; ! 920: /* Make a dp for use in db_update, as old dp */ ! 921: dp = savedata(class, type, 0, NULL, 0); ! 922: dp->d_zone = zonenum; ! 923: do { /* Loop and delete all matching RR(s) */ ! 924: n = db_update(dname, dp, NULL, DB_DELETE, ! 925: hashtab); ! 926: if (n != OK) ! 927: break; ! 928: DeletedOne++; ! 929: } while (1); ! 930: free( (struct databuf *) dp); ! 931: /* Ok for UPDATEMA not to have deleted any RRs */ ! 932: if (!DeletedOne && opcode == UPDATEDA) { ! 933: #ifdef DEBUG ! 934: if (debug) ! 935: fprintf(ddt,"UPDATE: db_update failed\n"); ! 936: #endif DEBUG ! 937: hp->rcode = NOCHANGE; ! 938: return(-1); ! 939: } ! 940: } ! 941: if ( (opcode == UPDATED) || (opcode == UPDATEDA) ) ! 942: return (cp - rrp);; ! 943: /* ! 944: * Else unmarshal the RR to be added and continue on to ! 945: * UPDATEA code for UPDATEM/UPDATEMA ! 946: */ ! 947: if ((n = ! 948: dn_expand(msg, msg+msglen, cp, dname, sizeof(dname))) < 0) { ! 949: #ifdef DEBUG ! 950: if (debug) ! 951: fprintf(ddt,"FORMERR UPDATE expand name failed\n"); ! 952: #endif ! 953: hp->rcode = FORMERR; ! 954: return(-1); ! 955: } ! 956: cp += n; ! 957: GETSHORT(type, cp); ! 958: GETSHORT(class, cp); ! 959: GETLONG(ttl, cp); ! 960: GETSHORT(n, cp); ! 961: cp1 = cp; ! 962: /**** XXX - need bounds checking here ****/ ! 963: cp += n; ! 964: ! 965: case UPDATEA: ! 966: if (n > MAXDATA) { ! 967: #ifdef DEBUG ! 968: if (debug) ! 969: fprintf(ddt,"UPDATE: too much data\n"); ! 970: #endif ! 971: hp->rcode = NOCHANGE; ! 972: return(-1); ! 973: } ! 974: if (cp != msg + msglen) { ! 975: #ifdef DEBUG ! 976: if (debug) ! 977: fprintf(ddt,"FORMERR UPDATE message length off\n"); ! 978: #endif ! 979: hp->rcode = FORMERR; ! 980: return(-1); ! 981: } ! 982: if ((zonenum = findzone(dname, class)) == 0) { ! 983: hp->rcode = NXDOMAIN; ! 984: return(-1); ! 985: } ! 986: dp = savedata(class, type, ttl, cp1, n); ! 987: dp->d_zone = zonenum; ! 988: if ((n = db_update(dname, NULL, dp, DB_NODATA, ! 989: hashtab)) != OK) { ! 990: #ifdef DEBUG ! 991: if (debug) ! 992: fprintf(ddt,"UPDATE: db_update failed\n"); ! 993: #endif ! 994: hp->rcode = NOCHANGE; ! 995: return (-1); ! 996: } ! 997: else ! 998: return (cp - rrp); ! 999: } ! 1000: #endif ALLOW_UPDATES ! 1001: ! 1002: if (zone == 0) ! 1003: ttl += tt.tv_sec; ! 1004: dp = savedata(class, type, ttl, cp1, n); ! 1005: dp->d_zone = zone; ! 1006: if ((n = db_update(dname, dp, dp, flags, hashtab)) < 0) { ! 1007: #ifdef DEBUG ! 1008: if (debug && (n != DATAEXISTS)) ! 1009: fprintf(ddt,"update failed (%d)\n", n); ! 1010: else if (debug >= 3) ! 1011: fprintf(ddt,"update failed (DATAEXISTS)\n"); ! 1012: #endif ! 1013: (void) free((char *)dp); ! 1014: } else if (type == T_NS && savens != NULL) ! 1015: *savens = dp; ! 1016: return (cp - rrp); ! 1017: } ! 1018: ! 1019: send_msg(msg, msglen, qp) ! 1020: char *msg; ! 1021: int msglen; ! 1022: struct qinfo *qp; ! 1023: { ! 1024: extern struct qinfo *qhead; ! 1025: #ifdef DEBUG ! 1026: struct qinfo *tqp; ! 1027: #endif DEBUG ! 1028: ! 1029: if (qp->q_system) ! 1030: return(1); ! 1031: #ifdef DEBUG ! 1032: if (debug) { ! 1033: fprintf(ddt,"send_msg -> %s (%s %d %d) id=%d\n", ! 1034: inet_ntoa(qp->q_from.sin_addr), ! 1035: qp->q_stream == QSTREAM_NULL ? "UDP" : "TCP", qp->q_dfd, ! 1036: ntohs(qp->q_from.sin_port), ! 1037: ntohs(qp->q_id)); ! 1038: } ! 1039: if (debug>4) ! 1040: for (tqp = qhead; tqp!=QINFO_NULL; tqp = tqp->q_link) { ! 1041: fprintf(ddt, "qp %x q_id: %d q_nsid: %d q_msglen: %d ", ! 1042: tqp, tqp->q_id,tqp->q_nsid,tqp->q_msglen); ! 1043: fprintf(ddt,"q_naddr: %d q_curaddr: %d\n", tqp->q_naddr, ! 1044: tqp->q_curaddr); ! 1045: fprintf(ddt,"q_next: %x q_link: %x\n", qp->q_next, ! 1046: qp->q_link); ! 1047: } ! 1048: if (debug >= 10) ! 1049: fp_query(msg, ddt); ! 1050: #endif DEBUG ! 1051: if (qp->q_stream == QSTREAM_NULL) { ! 1052: if (sendto(qp->q_dfd, msg, msglen, 0, ! 1053: (struct sockaddr *)&qp->q_from, sizeof(qp->q_from)) < 0) { ! 1054: #ifdef DEBUG ! 1055: if (debug) ! 1056: fprintf(ddt, "sendto error errno= %d\n",errno); ! 1057: #endif ! 1058: return(1); ! 1059: } ! 1060: #ifdef STATS ! 1061: stats[S_OUTPKTS].cnt++; ! 1062: #endif ! 1063: } else { ! 1064: (void) writemsg(qp->q_stream->s_rfd, msg, msglen); ! 1065: qp->q_stream->s_time = tt.tv_sec; ! 1066: qp->q_stream->s_refcnt--; ! 1067: } ! 1068: return(0); ! 1069: } ! 1070: ! 1071: prime(class, type, oqp) ! 1072: int class, type; ! 1073: register struct qinfo *oqp; ! 1074: { ! 1075: char dname[BUFSIZ]; ! 1076: ! 1077: if (oqp->q_msg == NULL) ! 1078: return; ! 1079: if (dn_expand(oqp->q_msg, oqp->q_msg + oqp->q_msglen, ! 1080: oqp->q_msg + sizeof(HEADER), dname, sizeof(dname)) < 0) ! 1081: return; ! 1082: #ifdef DEBUG ! 1083: if (debug >= 2) ! 1084: fprintf(ddt,"prime: %s\n", dname); ! 1085: #endif ! 1086: (void) sysquery(dname, class, type); ! 1087: } ! 1088: ! 1089: ! 1090: prime_cache() ! 1091: { ! 1092: register struct qinfo *qp; ! 1093: ! 1094: #ifdef DEBUG ! 1095: if (debug) ! 1096: fprintf(ddt,"prime_cache: priming = %d\n", priming); ! 1097: #endif ! 1098: #ifdef STATS ! 1099: stats[S_PRIMECACHE].cnt++; ! 1100: #endif ! 1101: if (!priming && fcachetab->h_tab[0] != NULL) { ! 1102: priming++; ! 1103: if ((qp = sysquery("", C_IN, T_NS)) == NULL) ! 1104: priming = 0; ! 1105: else ! 1106: qp->q_system = PRIMING_CACHE; ! 1107: } ! 1108: needs_prime_cache = 0; ! 1109: return; ! 1110: } ! 1111: ! 1112: struct qinfo * ! 1113: sysquery(dname, class, type) ! 1114: char *dname; ! 1115: int class, type; ! 1116: { ! 1117: extern struct qinfo *qhead; ! 1118: extern int nsid; ! 1119: register struct qinfo *qp, *oqp; ! 1120: register HEADER *hp; ! 1121: struct namebuf *np; ! 1122: struct databuf *nsp[NSMAX]; ! 1123: struct hashbuf *htp; ! 1124: char *fname; ! 1125: int count; ! 1126: ! 1127: #ifdef DEBUG ! 1128: if (debug > 2) ! 1129: fprintf(ddt,"sysquery(%s, %d, %d)\n", dname, class, type); ! 1130: #endif ! 1131: #ifdef STATS ! 1132: stats[S_SYSQUERIES].cnt++; ! 1133: #endif ! 1134: htp = hashtab; ! 1135: if (priming && dname[0] == '\0') ! 1136: np = NULL; ! 1137: else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) { ! 1138: #ifdef DEBUG ! 1139: if (debug) ! 1140: fprintf(ddt,"sysquery: nlookup error on %s?\n", dname); ! 1141: #endif ! 1142: return(0); ! 1143: } ! 1144: ! 1145: switch (findns(&np, class, nsp, &count)) { ! 1146: case NXDOMAIN: ! 1147: case SERVFAIL: ! 1148: #ifdef DEBUG ! 1149: if (debug) ! 1150: fprintf(ddt,"sysquery: findns error on %s?\n", dname); ! 1151: #endif ! 1152: return(0); ! 1153: } ! 1154: ! 1155: /* build new qinfo struct */ ! 1156: qp = qnew(); ! 1157: qp->q_cmsg = qp->q_msg = NULL; ! 1158: qp->q_dfd = ds; ! 1159: qp->q_fwd = fwdtab; ! 1160: qp->q_addr[0].stime = tt; ! 1161: qp->q_system++; ! 1162: ! 1163: if ((qp->q_msg = malloc(BUFSIZ)) == NULL) { ! 1164: qfree(qp); ! 1165: return(0); ! 1166: } ! 1167: qp->q_msglen = res_mkquery(QUERY, dname, class, ! 1168: type, (char *)NULL, 0, NULL, qp->q_msg, BUFSIZ); ! 1169: hp = (HEADER *) qp->q_msg; ! 1170: hp->id = qp->q_nsid = htons((u_short)++nsid); ! 1171: hp->rd = (qp->q_fwd ? 1 : 0); ! 1172: ! 1173: /* First check for an already pending query for this data */ ! 1174: for (oqp = qhead; oqp!=QINFO_NULL; oqp = oqp->q_link) { ! 1175: if (oqp != qp && oqp->q_msglen == qp->q_msglen && ! 1176: bcmp((char *)oqp->q_msg+2, qp->q_msg+2, qp->q_msglen-2) == 0) { ! 1177: #ifdef DEBUG ! 1178: if (debug >= 3) ! 1179: fprintf(ddt, "sysquery: duplicate\n"); ! 1180: #endif ! 1181: qfree(qp); ! 1182: return(0); ! 1183: } ! 1184: } ! 1185: ! 1186: if (nslookup(nsp, qp) == 0) { ! 1187: #ifdef DEBUG ! 1188: if (debug) ! 1189: fprintf(ddt,"resp: no addrs found for NS's\n"); ! 1190: #endif ! 1191: qfree(qp); ! 1192: return(0); ! 1193: } ! 1194: ! 1195: schedretry(qp, retrytime(qp)); ! 1196: if (qp->q_fwd == 0) ! 1197: qp->q_addr[0].stime = tt; ! 1198: ! 1199: #ifdef DEBUG ! 1200: if (debug) ! 1201: fprintf(ddt,"sysquery: send -> %s %d (%d), nsid=%d id=%d %dms\n", ! 1202: inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr), ! 1203: qp->q_dfd, ntohs(Q_NEXTADDR(qp,0)->sin_port), ! 1204: ntohs(qp->q_nsid), ntohs(qp->q_id), ! 1205: qp->q_addr[0].nsdata->d_nstime); ! 1206: if ( debug >= 10) ! 1207: fp_query(qp->q_msg, ddt); ! 1208: #endif ! 1209: if (sendto(qp->q_dfd, qp->q_msg, qp->q_msglen, 0, ! 1210: (struct sockaddr *)Q_NEXTADDR(qp,0), ! 1211: sizeof(struct sockaddr_in)) < 0){ ! 1212: #ifdef DEBUG ! 1213: if (debug) ! 1214: fprintf(ddt, "sendto error errno= %d\n",errno); ! 1215: #endif ! 1216: } ! 1217: #ifdef STATS ! 1218: stats[S_OUTPKTS].cnt++; ! 1219: #endif ! 1220: return(qp); ! 1221: } ! 1222: ! 1223: /* ! 1224: * Check the list of root servers after receiving a response ! 1225: * to a query for the root servers. ! 1226: */ ! 1227: check_root() ! 1228: { ! 1229: register struct databuf *dp, *pdp; ! 1230: register struct namebuf *np; ! 1231: int count = 0; ! 1232: ! 1233: priming = 0; ! 1234: for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next) ! 1235: if (np->n_dname[0] == '\0') ! 1236: break; ! 1237: if (np == NULL) { ! 1238: syslog(LOG_ERR, "check_root: Can't find root!\n"); ! 1239: return; ! 1240: } ! 1241: for (dp = np->n_data; dp != NULL; dp = dp->d_next) ! 1242: if (dp->d_type == T_NS) ! 1243: count++; ! 1244: #ifdef DEBUG ! 1245: if (debug) ! 1246: fprintf(ddt,"%d root servers\n", count); ! 1247: #endif ! 1248: if (count < MINROOTS) { ! 1249: syslog(LOG_WARNING, ! 1250: "check_root: %d root servers after query to root server < min", ! 1251: count); ! 1252: return; ! 1253: } ! 1254: pdp = NULL; ! 1255: dp = np->n_data; ! 1256: while (dp != NULL) { ! 1257: if (dp->d_type == T_NS && dp->d_zone == 0 && ! 1258: dp->d_ttl < tt.tv_sec) { ! 1259: #ifdef DEBUG ! 1260: if (debug) ! 1261: fprintf(ddt,"deleting old root server '%s'\n", ! 1262: dp->d_data); ! 1263: #endif ! 1264: dp = rm_datum(dp, np, pdp); ! 1265: /* SHOULD DELETE FROM HINTS ALSO */ ! 1266: continue; ! 1267: } ! 1268: pdp = dp; ! 1269: dp = dp->d_next; ! 1270: } ! 1271: check_ns(); ! 1272: } ! 1273: ! 1274: /* ! 1275: * Check the root to make sure that for each NS record we have a A RR ! 1276: */ ! 1277: check_ns() ! 1278: { ! 1279: register struct databuf *dp, *tdp; ! 1280: register struct namebuf *np, *tnp; ! 1281: struct hashbuf *htp; ! 1282: char *dname; ! 1283: int found_arr; ! 1284: char *fname; ! 1285: time_t curtime; ! 1286: ! 1287: #ifdef DEBUG ! 1288: if (debug >= 2) ! 1289: fprintf(ddt,"check_ns()\n"); ! 1290: #endif ! 1291: #ifdef STATS ! 1292: stats[S_CHECKNS].cnt++; ! 1293: #endif ! 1294: ! 1295: curtime = (u_long) tt.tv_sec; ! 1296: for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next) { ! 1297: if (np->n_dname[0] != 0) ! 1298: continue; ! 1299: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { ! 1300: if (dp->d_type != T_NS) ! 1301: continue; ! 1302: ! 1303: /* look for A records */ ! 1304: dname = dp->d_data; ! 1305: htp = hashtab; ! 1306: tnp = nlookup(dname, &htp, &fname, 0); ! 1307: if (tnp == NULL || fname != dname) { ! 1308: #ifdef DEBUG ! 1309: if (debug >= 3) ! 1310: fprintf(ddt,"check_ns: %s: not found %s %x\n", ! 1311: dname, fname, tnp); ! 1312: #endif ! 1313: (void) sysquery(dname, dp->d_class, T_A); ! 1314: continue; ! 1315: } ! 1316: /* look for name server addresses */ ! 1317: found_arr = 0; ! 1318: for (tdp=tnp->n_data; tdp!=NULL; tdp=tdp->d_next) { ! 1319: if (tdp->d_type != T_A || ! 1320: tdp->d_class != dp->d_class) ! 1321: continue; ! 1322: if ((tdp->d_zone == 0) && ! 1323: (tdp->d_ttl < curtime)) { ! 1324: #ifdef DEBUG ! 1325: if (debug >= 3) ! 1326: fprintf(ddt,"check_ns: stale entry '%s'\n", ! 1327: tnp->n_dname); ! 1328: #endif ! 1329: /* Cache invalidate the address RR's */ ! 1330: delete_all(tnp, dp->d_class, T_A); ! 1331: found_arr = 0; ! 1332: break; ! 1333: } ! 1334: found_arr++; ! 1335: } ! 1336: if (!found_arr) ! 1337: (void) sysquery(dname, dp->d_class, T_A); ! 1338: } ! 1339: } ! 1340: } ! 1341: ! 1342: #define MAXCLASS 255 /* belongs elsewhere */ ! 1343: int norootlogged[MAXCLASS]; ! 1344: ! 1345: /* ! 1346: * Find NS's or an SOA for the given dname (np) and fill in the ! 1347: * nsp array. Returns OK on success, and SERVFAIL on error. ! 1348: * We return NXDOMAIN to indicate we are authoritative. ! 1349: */ ! 1350: findns(npp, class, nsp, countp) ! 1351: register struct namebuf **npp; ! 1352: struct databuf **nsp; ! 1353: int *countp; ! 1354: { ! 1355: register struct namebuf *np = *npp; ! 1356: register struct databuf *dp; ! 1357: register struct databuf **nspp; ! 1358: struct hashbuf *htp = hashtab; ! 1359: ! 1360: if (priming && (np == NULL || np->n_dname[0] == '\0')) ! 1361: htp = fcachetab; ! 1362: try_again: ! 1363: if (htp == fcachetab) ! 1364: needs_prime_cache = 1; ! 1365: while (np == NULL && htp != NULL) { ! 1366: #ifdef DEBUG ! 1367: if (debug > 2) ! 1368: fprintf(ddt, "findns: using %s\n", htp == hashtab ? ! 1369: "cache" : "hints"); ! 1370: #endif ! 1371: for (np = htp->h_tab[0]; np != NULL; np = np->n_next) ! 1372: if (np->n_dname[0] == '\0') ! 1373: break; ! 1374: htp = (htp == hashtab ? fcachetab : NULL); /* Fallback */ ! 1375: } ! 1376: while(np != NULL) { ! 1377: #ifdef DEBUG ! 1378: if (debug >= 5) ! 1379: fprintf(ddt, "findns: np 0x%x\n", np); ! 1380: #endif ! 1381: /* Look first for SOA records. */ ! 1382: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { ! 1383: if (dp->d_zone != 0 && match(dp, class, T_SOA)) { ! 1384: #ifdef DEBUG ! 1385: if (debug >= 3) ! 1386: fprintf(ddt,"findns: SOA found\n"); ! 1387: #endif ! 1388: if (zones[dp->d_zone].z_auth) { ! 1389: *npp = np; ! 1390: nsp[0] = dp; ! 1391: return(NXDOMAIN); ! 1392: } else ! 1393: return (SERVFAIL); ! 1394: } ! 1395: } ! 1396: ! 1397: /* If no SOA records, look for NS records. */ ! 1398: nspp = &nsp[0]; ! 1399: *nspp = NULL; ! 1400: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { ! 1401: if (dp->d_type != T_NS || ! 1402: (dp->d_class != class && class != C_ANY)) ! 1403: continue; ! 1404: /* ! 1405: * Don't use records that may become invalid to ! 1406: * reference later when we do the rtt computation. ! 1407: * Never delete our safety-belt information! ! 1408: */ ! 1409: if ((dp->d_zone == 0) && ! 1410: (dp->d_ttl < (tt.tv_sec+900)) && ! 1411: !(dp->d_flags & DB_F_HINT)) { ! 1412: #ifdef DEBUG ! 1413: if (debug) ! 1414: fprintf(ddt,"findns: stale entry '%s'\n", ! 1415: np->n_dname); ! 1416: #endif ! 1417: /* Cache invalidate the NS RR's */ ! 1418: if (dp->d_ttl < tt.tv_sec) ! 1419: delete_all(np, class, T_NS); ! 1420: goto try_parent; ! 1421: } ! 1422: if (nspp < &nsp[NSMAX-1]) ! 1423: *nspp++ = dp; ! 1424: } ! 1425: ! 1426: *countp = nspp - nsp; ! 1427: if (*countp > 0) { ! 1428: #ifdef DEBUG ! 1429: if (debug >= 3) ! 1430: fprintf(ddt,"findns: %d NS's added for '%s'\n", ! 1431: *countp, np->n_dname); ! 1432: #endif ! 1433: *nspp = NULL; ! 1434: *npp = np; ! 1435: return(OK); /* Success, got some NS's */ ! 1436: } ! 1437: try_parent: ! 1438: np = np->n_parent; ! 1439: } ! 1440: if (htp) ! 1441: goto try_again; ! 1442: #ifdef DEBUG ! 1443: if (debug) ! 1444: fprintf(ddt, "findns: No root nameservers for class %d?\n", ! 1445: class); ! 1446: #endif ! 1447: if ((unsigned)class < MAXCLASS && norootlogged[class] == 0) { ! 1448: norootlogged[class] = 1; ! 1449: syslog(LOG_ERR, "No root nameservers for class %d\n", class); ! 1450: } ! 1451: return(SERVFAIL); ! 1452: } ! 1453: ! 1454: /* ! 1455: * Extract RR's from the given node that match class and type. ! 1456: * Return number of bytes added to response. ! 1457: * If no matching data is found, then 0 is returned. ! 1458: * Authoritative answer bit is set in response if appropriate. ! 1459: */ ! 1460: finddata(np, class, type, hp, dnamep, lenp, countp) ! 1461: struct namebuf *np; ! 1462: int class, type; ! 1463: register HEADER *hp; ! 1464: char **dnamep; ! 1465: int *lenp, *countp; ! 1466: { ! 1467: register struct databuf *dp; ! 1468: register char *cp; ! 1469: int buflen, n, count = 0, foundstale = 0; ! 1470: ! 1471: buflen = *lenp; ! 1472: cp = ((char *)hp) + *countp; ! 1473: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { ! 1474: if (!wanted(dp, class, type)) { ! 1475: #ifdef notdef ! 1476: if (type == T_CNAME && class == dp->d_class) { ! 1477: /* any data means no CNAME exists */ ! 1478: *countp = 0; ! 1479: return(0); ! 1480: } ! 1481: #endif ! 1482: continue; ! 1483: } ! 1484: if (stale(dp)) { ! 1485: /* ! 1486: * Don't use stale data. ! 1487: * Would like to call delete_all here ! 1488: * and continue, but the data chain would get ! 1489: * munged; can't restart, as make_rr has side ! 1490: * effects (leaving pointers in dnptr). ! 1491: * Just skip this entry for now ! 1492: * and call delete_all at the end. ! 1493: */ ! 1494: #ifdef DEBUG ! 1495: if (debug >=3) ! 1496: fprintf(ddt,"finddata: stale entry '%s'\n",np->n_dname); ! 1497: #endif ! 1498: if (dp->d_zone == 0) ! 1499: foundstale++; ! 1500: continue; ! 1501: } ! 1502: if ((n = make_rr(*dnamep, dp, cp, buflen, 1)) < 0) { ! 1503: hp->tc = 1; ! 1504: *countp = count; ! 1505: return(*lenp - buflen); ! 1506: } ! 1507: ! 1508: cp += n; ! 1509: buflen -= n; ! 1510: count++; ! 1511: #ifdef notdef ! 1512: /* this isn't right for glue records, aa is set in ns_req */ ! 1513: if (dp->d_zone && zones[dp->d_zone].z_auth && class != C_ANY) ! 1514: hp->aa = 1; /* XXX */ ! 1515: #endif ! 1516: if (dp->d_type == T_CNAME) { ! 1517: if (type != T_ANY) { /* or T_NS? */ ! 1518: *dnamep = dp->d_data; ! 1519: if (dp->d_zone && zones[dp->d_zone].z_auth && ! 1520: class != C_ANY) /* XXX */ ! 1521: hp->aa = 1; /* XXX */ ! 1522: } ! 1523: break; ! 1524: } ! 1525: } ! 1526: /* ! 1527: * Cache invalidate the other RR's of same type ! 1528: * if some have timed out ! 1529: */ ! 1530: if (foundstale) ! 1531: delete_all(np, class, type); ! 1532: #ifdef DEBUG ! 1533: if (debug >=3) ! 1534: fprintf(ddt,"finddata: added %d class %d type %d RRs\n", ! 1535: count, class, type); ! 1536: #endif ! 1537: *countp = count; ! 1538: return(*lenp - buflen); ! 1539: } ! 1540: ! 1541: /* ! 1542: * Do we want this data record based on the class and type? ! 1543: */ ! 1544: wanted(dp, class, type) ! 1545: struct databuf *dp; ! 1546: int class, type; ! 1547: { ! 1548: ! 1549: #ifdef DEBUG ! 1550: if (debug > 3) ! 1551: fprintf(ddt,"wanted(%x, %d, %d) %d, %d\n", dp, class, type, ! 1552: dp->d_class, dp->d_type); ! 1553: #endif ! 1554: ! 1555: if (dp->d_class != class && class != C_ANY) ! 1556: return (0); ! 1557: if (type == dp->d_type) ! 1558: return (1); ! 1559: switch (dp->d_type) { ! 1560: case T_ANY: ! 1561: case T_CNAME: ! 1562: return (1); ! 1563: } ! 1564: switch (type) { ! 1565: case T_ANY: ! 1566: return (1); ! 1567: ! 1568: case T_MAILB: ! 1569: switch (dp->d_type) { ! 1570: case T_MR: ! 1571: case T_MB: ! 1572: case T_MG: ! 1573: case T_MINFO: ! 1574: return (1); ! 1575: } ! 1576: break; ! 1577: ! 1578: case T_AXFR: ! 1579: if (dp->d_type == T_SOA) ! 1580: return (1); ! 1581: } ! 1582: return (0); ! 1583: } ! 1584: ! 1585: /* ! 1586: * Add RR entries from dpp array to a query/response. ! 1587: * Return the number of bytes added or negative the amount ! 1588: * added if truncation was required. Typically you are ! 1589: * adding NS records to a response. ! 1590: */ ! 1591: add_data(np, dpp, cp, buflen) ! 1592: struct namebuf *np; ! 1593: struct databuf **dpp; ! 1594: register char *cp; ! 1595: int buflen; ! 1596: { ! 1597: register struct databuf *dp; ! 1598: char dname[MAXDNAME]; ! 1599: register int n, count = 0; ! 1600: ! 1601: getname(np, dname, sizeof(dname)); ! 1602: for(dp = *dpp++; dp != NULL; dp = *dpp++) { ! 1603: if (stale(dp)) ! 1604: continue; /* ignore old cache entry */ ! 1605: if ((n = make_rr(dname, dp, cp, buflen, 1)) < 0) ! 1606: return(-count); /* Truncation */ ! 1607: cp += n; ! 1608: buflen -= n; ! 1609: count += n; ! 1610: } ! 1611: return(count); ! 1612: } ! 1613: ! 1614: /* ! 1615: * This is best thought of as a "cache invalidate" function. ! 1616: * It is called whenever a piece of data is determined to have ! 1617: * timed out. It is better to have no information, than to ! 1618: * have partial information you pass off as complete. ! 1619: */ ! 1620: delete_all(np, class, type) ! 1621: register struct namebuf *np; ! 1622: int class, type; ! 1623: { ! 1624: register struct databuf *dp, *pdp; ! 1625: ! 1626: #ifdef DEBUG ! 1627: if (debug > 2) ! 1628: fprintf(ddt,"delete_all: '%s' 0x%x class %d type %d\n", ! 1629: np->n_dname, np, class, type); ! 1630: #endif ! 1631: pdp = NULL; ! 1632: dp = np->n_data; ! 1633: while (dp != NULL) { ! 1634: if ((dp->d_zone == 0) && !(dp->d_flags & DB_F_HINT) ! 1635: && match(dp, class, type)) { ! 1636: dp = rm_datum(dp, np, pdp); ! 1637: continue; ! 1638: } ! 1639: pdp = dp; ! 1640: dp = dp->d_next; ! 1641: } ! 1642: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.