1: #ifndef lint 2: static char sccsid[] = "@(#)ns_resp.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/time.h> 13: #include <sys/socket.h> 14: #include <netinet/in.h> 15: #include <syslog.h> 16: #include <arpa/nameser.h> 17: #include "ns.h" 18: #include "db.h" 19: 20: extern int errno; 21: extern char *dnptrs[]; 22: extern char *malloc(); 23: struct databuf *nsp[MAXNS], **nspp; 24: 25: /* 26: * Handle a response from a forwarded query. 27: */ 28: ns_resp(msg, msglen) 29: char *msg; 30: int msglen; 31: { 32: register struct qinfo *qp; 33: register HEADER *hp; 34: register char *cp, *tp; 35: int i, c, n, ancount, nscount, arcount; 36: int type; 37: int qtype, qclass; 38: int cname = 0; /* flag for processing cname response */ 39: int count, founddata; 40: int buflen; 41: int newmsglen; 42: char name[MAXDNAME], *dname; 43: char *fname; 44: char *newmsg; 45: 46: struct hashbuf *htp; 47: struct databuf *dp, *tmp, *pdp; 48: struct namebuf *np; 49: 50: #ifdef DEBUG 51: if (debug >= 3) 52: fprintf(ddt,"ns_resp(%x, %d)\n", msg, msglen); 53: #endif 54: hp = (HEADER *) msg; 55: if( (qp = qfindid(hp->id)) == NULL ) 56: return; 57: 58: if (hp->rcode != NOERROR || hp->opcode != QUERY) 59: goto retmsg; 60: /* 61: * Skip query section 62: */ 63: cp = msg + sizeof(HEADER); 64: if (hp->qdcount) { 65: if ((n = dn_skip(cp)) < 0) { 66: #ifdef DEBUG 67: if (debug) 68: fprintf(ddt,"FORMERR ns_resp() dn_skip failed\n"); 69: #endif 70: hp->rcode = FORMERR; 71: goto retmsg; 72: } 73: cp += n; 74: qtype = getshort(cp); 75: cp += sizeof(u_short); 76: qclass = getshort(cp); 77: cp += sizeof(u_short); 78: } 79: /* 80: * Save answers, name server, and additional records for future use. 81: */ 82: ancount = ntohs(hp->ancount); 83: nscount = ntohs(hp->nscount); 84: arcount = ntohs(hp->arcount); 85: if (ancount == 1 || nscount) { 86: /* 87: * Check if it's a CNAME responce 88: */ 89: tp = cp; 90: tp += dn_skip(tp); /* name */ 91: type = getshort(tp); 92: tp += sizeof(u_short); /* type */ 93: if (type == T_CNAME) { 94: tp += sizeof(u_short); /* class */ 95: tp += sizeof(u_long); /* ttl */ 96: tp += sizeof(u_short); /* dlen */ 97: cname++; 98: #ifdef DEBUG 99: if (debug) { 100: fprintf(ddt,"CNAME - needs more processing\n"); 101: } 102: #endif 103: if (!qp->q_cmsglen) { 104: qp->q_cmsg = qp->q_msg; 105: qp->q_cmsglen = qp->q_msglen; 106: } 107: } 108: } 109: /* 110: * Add the info recived in the responce to the Data Base 111: */ 112: c = ancount + nscount + arcount; 113: nspp = nsp; 114: for (i = 0; i < c; i++) { 115: if (cp >= msg + msglen) { 116: #ifdef DEBUG 117: if (debug) 118: fprintf(ddt, "FORMERR ns_resp() message bad count?\n"); 119: #endif 120: hp->rcode = FORMERR; 121: goto retmsg; 122: } 123: if ((n = doupdate(msg, msglen, cp, 0, 124: !ancount && i < nscount)) < 0) { 125: #ifdef DEBUG 126: if (debug) 127: fprintf(ddt,"FORMERR ns_resp() doupdate failed\n"); 128: #endif 129: hp->rcode = FORMERR; 130: goto retmsg; 131: } 132: cp += n; 133: } 134: if (cp > msg + msglen) { 135: #ifdef DEBUG 136: if (debug) 137: fprintf(ddt,"FORMERR ns_resp() packet size err %d, %d\n", 138: cp-msg, msglen); 139: #endif 140: hp->rcode = FORMERR; 141: goto retmsg; 142: } 143: if ((qtype == C_ANY) && ancount) 144: goto retmsg; 145: if ((!cname && !qp->q_cmsglen) && (ancount || nscount == 0)) 146: goto retmsg; 147: 148: /* 149: * All messages in here need further processing. i.e. they 150: * are either CNAMEs or we got referred again. 151: */ 152: count = 0; 153: founddata = 0; 154: dname = name; 155: if ((newmsg = malloc(BUFSIZ)) == NULL) { 156: #if DEBUG 157: if (debug) 158: fprintf(ddt,"ns_resp: malloc error\n"); 159: #endif 160: syslog(LOG_ERR, "ns_resp: Out Of Memory"); 161: hp->rcode = SERVFAIL; 162: goto retmsg; 163: } 164: buflen = BUFSIZ; 165: if ((!cname && qp->q_cmsglen) && ancount) { 166: #if DEBUG 167: if (debug) { 168: fprintf(ddt,"Cname second pass\n"); 169: } 170: #endif 171: newmsglen = qp->q_cmsglen; 172: bcopy(qp->q_cmsg, newmsg, newmsglen); 173: } else { 174: newmsglen = msglen; 175: bcopy(msg, newmsg, newmsglen); 176: } 177: buflen = buflen - newmsglen; 178: hp = (HEADER *) newmsg; 179: dnptrs[0] = newmsg; 180: dnptrs[1] = NULL; 181: cp = newmsg + sizeof(HEADER); 182: if (cname) 183: cp += dn_skip(cp) + QFIXEDSZ; 184: if ((n = dn_expand(newmsg, newmsg + newmsglen, 185: cp, dname, sizeof(name))) < 0) { 186: #ifdef DEBUG 187: if (debug) 188: fprintf(ddt,"dn_expand failed\n" ); 189: #endif 190: hp->rcode = SERVFAIL; 191: free(newmsg); 192: goto retmsg; 193: } 194: cp = newmsg + sizeof(HEADER); 195: if (cname) 196: cp += dn_skip(cp); 197: else 198: cp += n; 199: cp += QFIXEDSZ; 200: 201: again: 202: htp = hashtab; /* lookup relative to root */ 203: #ifdef DEBUG 204: if (debug) 205: fprintf(ddt,"ns_resp() nlookup(%s)\n",dname); 206: #endif 207: np = nlookup(dname, &htp, &fname, 0); 208: if (np == (struct namebuf *)NULL) 209: fname = ""; 210: if (fname != dname) 211: goto findns; 212: #ifdef DEBUG 213: if (debug) 214: fprintf(ddt,"found '%s'\n", dname); 215: #endif 216: pdp = NULL; 217: dp = np->n_data; 218: /* look for the data */ 219: while (dp != NULL) { 220: if (!wanted(dp, qclass, qtype)) { 221: pdp = dp; 222: dp = dp->d_next; 223: continue; 224: } 225: if ((n = make_rr(dname, dp, cp, buflen, 1)) < 0) { 226: if (n == -1) { 227: hp->tc = 1; 228: break; 229: } 230: /* delete old cache entry */ 231: #ifdef DEBUG 232: if (debug >= 5) 233: fprintf(ddt,"deleting cache entry\n"); 234: #endif 235: rminv(dp); 236: tmp = dp->d_next; 237: free((char *)dp); 238: dp = tmp; 239: if (pdp == NULL) 240: np->n_data = dp; 241: else 242: pdp->d_next = dp; 243: continue; 244: } 245: cp += n; 246: buflen -= n; 247: count++; 248: if (dp->d_zone) 249: hp->aa = 1; 250: if (dp->d_type == T_CNAME) { 251: if (type == T_ANY) 252: break; 253: dname = dp->d_data; 254: goto again; 255: } 256: founddata++; 257: pdp = dp; 258: dp = dp->d_next; 259: } 260: #ifdef DEBUG 261: if (debug >= 5) 262: fprintf(ddt,"count = %d, founddata = %d\n", count, founddata); 263: #endif 264: if (count) 265: hp->ancount = htons((u_short)count); 266: 267: findns: 268: 269: /* 270: * Look for name servers to refer to and fill in the authority 271: * section or record the address for forwarding the query 272: * (recursion desired). 273: */ 274: for (count = 0;; np = np->n_parent) { 275: #ifdef DEBUG 276: if (debug >= 5) 277: fprintf(ddt, "fname = '%s'\n", fname); 278: #endif 279: if (*fname == '\0') { 280: for (np = hashtab->h_tab[0]; np != NULL; 281: np = np->n_next) 282: if (np->n_dname[0] == '\0') 283: goto foundns; 284: #ifdef DEBUG 285: if (debug) 286: fprintf(ddt, "No root nameserver?\n"); 287: #endif 288: syslog(LOG_ERR, "No root Nameserver\n"); 289: hp->rcode = SERVFAIL; 290: break; 291: } 292: foundns: 293: nspp = nsp; 294: pdp = NULL; 295: dp = np->n_data; 296: while (dp != NULL) { 297: if (!match(dp, qclass, T_NS)) { 298: pdp = dp; 299: dp = dp->d_next; 300: continue; 301: } 302: if (!founddata) { 303: if (nspp < &nsp[MAXNS-1]) 304: *nspp++ = dp; 305: pdp = dp; 306: dp = dp->d_next; 307: continue; 308: } 309: if ((n = make_rr(fname, dp, cp, buflen, 1)) < 0) { 310: if (n == -1) { 311: hp->tc = 1; 312: break; 313: } 314: /* delete old cache entry */ 315: #ifdef DEBUG 316: if (debug) 317: fprintf(ddt,"deleting cache entry\n"); 318: #endif 319: rminv(dp); 320: tmp = dp->d_next; 321: free((char *)dp); 322: dp = tmp; 323: if (pdp == NULL) 324: np->n_data = dp; 325: else 326: pdp->d_next = dp; 327: continue; 328: } 329: cp += n; 330: buflen -= n; 331: count++; 332: pdp = dp; 333: dp = dp->d_next; 334: } 335: if ((*fname == '\0') || (count > 0)) 336: break; 337: if (nspp != nsp) 338: break; 339: if ((fname = index(fname, '.')) == NULL) 340: fname = ""; 341: else 342: fname++; 343: } 344: 345: if (count && founddata) { 346: hp->nscount = htons((u_short)count); 347: cp += doaddinfo(hp, cp, buflen); 348: buflen = cp - newmsg; 349: msg = newmsg; 350: msglen = buflen; 351: hp = (HEADER *) msg; 352: goto retmsg; 353: } 354: 355: *nspp = NULL; 356: if (cname) { 357: newmsglen = res_mkquery(QUERY, dname, C_ANY, T_A, (char *)NULL, 358: 0, NULL, newmsg, BUFSIZ); 359: qp->q_msglen = newmsglen; 360: hp->id = qp->q_nsid; 361: } else { 362: hp->ancount = 0; 363: hp->nscount = 0; 364: hp->arcount = 0; 365: hp->qr = 0; 366: } 367: qp->q_naddr = 0; 368: qp->q_curaddr = 0; 369: n = nslookup(nsp, qp); 370: 371: #ifdef DEBUG 372: if (debug > 7) { 373: int kjd; 374: 375: fprintf(ddt,"n = %d\n",n); 376: for (kjd = 0; kjd < qp->q_naddr; kjd++ ) 377: fprintf(ddt,"list %d-> %s (%d)\n", kjd, 378: inet_ntoa(qp->q_addr[kjd].sin_addr), 379: ntohs(qp->q_addr[kjd].sin_port)); 380: } 381: #endif DEBUG 382: qp->q_msg = newmsg; 383: if (qp->q_cname++ == MAXCNAMES) { 384: hp->id = qp->q_id; 385: hp->rd = 1; 386: hp->ra = 1; 387: if (qp->q_stream != QSTREAM_NULL) { 388: (void) writemsg(qp->q_stream->s_rfd, newmsg, newmsglen); 389: qp->q_stream->s_time = tt.tv_sec; 390: qp->q_stream->s_refcnt--; 391: } else { 392: if (sendto(ds, newmsg, newmsglen, 0, &qp->q_from, 393: sizeof(qp->q_from)) < 0) { 394: #ifdef DEBUG 395: if (debug) 396: fprintf(ddt,"sendto failed\n"); 397: #endif 398: } 399: } 400: qremove(qp); 401: return; 402: } 403: #ifdef DEBUG 404: if (debug) 405: fprintf(ddt,"q_cname = %d\n",qp->q_cname); 406: #endif 407: unsched(qp); 408: schedretry(qp, (time_t)RETRYTIME); 409: 410: #ifdef DEBUG 411: if (debug >= 3) 412: fp_query(qp->q_msg, ddt); 413: if (debug) 414: fprintf(ddt,"try -> %s (%d)\n", 415: inet_ntoa(qp->q_addr[0].sin_addr), 416: ntohs(qp->q_addr[0].sin_port)); 417: #endif 418: if (sendto(ds, qp->q_msg, qp->q_msglen, 0, 419: &qp->q_addr[0], sizeof(qp->q_addr[0])) < 0) { 420: #ifdef DEBUG 421: if (debug) 422: fprintf(ddt, "error returning msg errno=%d\n",errno); 423: #endif 424: } 425: return; 426: 427: retmsg: 428: /* 429: * Pass answer back to original requestor. 430: */ 431: hp->id = qp->q_id; 432: hp->rd = 1; /* restore Recursion Desired bit */ 433: hp->ra = 1; /* Recursion is Available */ 434: #ifdef DEBUG 435: if (debug) 436: fprintf(ddt,"respond -> %s (%d)\n", 437: inet_ntoa(qp->q_from.sin_addr), 438: ntohs(qp->q_from.sin_port)); 439: if (debug >= 10) 440: fp_query(msg, ddt); 441: #endif 442: if (qp->q_stream == QSTREAM_NULL) { 443: if (sendto(ds, msg, msglen, 0, 444: &qp->q_from, sizeof(qp->q_from)) < 0) { 445: #ifdef DEBUG 446: if (debug) 447: fprintf(ddt,"sendto failed\n"); 448: #endif 449: } 450: 451: } else { 452: (void) writemsg(qp->q_stream->s_rfd, msg, msglen); 453: qp->q_stream->s_time = tt.tv_sec; 454: qp->q_stream->s_refcnt--; 455: } 456: if (msg == newmsg) 457: (void) free(newmsg); 458: /* 459: * Remove from table 460: */ 461: qremove(qp); 462: } 463: 464: /* 465: * Decode the resource record 'rrp' and update the database. 466: * If savens is true, record pointer for forwarding queries a second time. 467: */ 468: doupdate(msg, msglen, rrp, zone, savens) 469: char *msg ; 470: char *rrp; 471: int msglen, zone, savens; 472: { 473: register char *cp; 474: register int n; 475: int class, type, dlen, n1; 476: u_long ttl; 477: struct databuf *dp; 478: char dname[MAXDNAME]; 479: char data[BUFSIZ], *cp1; 480: 481: #ifdef DEBUG 482: if (debug >= 3) 483: fprintf(ddt,"doupdate(%d, %d)\n", zone, savens); 484: #endif 485: 486: cp = rrp; 487: if ((n = dn_expand(msg, msg + msglen, cp, dname, sizeof(dname))) < 0) 488: return (-1); 489: cp += n; 490: type = getshort(cp); 491: cp += sizeof(u_short); 492: class = getshort(cp); 493: cp += sizeof(u_short); 494: ttl = getlong(cp); 495: cp += sizeof(u_long); 496: dlen = getshort(cp); 497: cp += sizeof(u_short); 498: if (zone == 0) { 499: if (ttl == 0) 500: ttl = 5 * 60; 501: ttl += (u_long) tt.tv_sec; 502: } 503: /* 504: * Convert the resource record data into the internal 505: * database format. 506: */ 507: switch (type) { 508: case T_A: 509: case T_HINFO: 510: case T_UINFO: 511: case T_UID: 512: case T_GID: 513: cp1 = cp; 514: n = dlen; 515: cp += n; 516: break; 517: 518: case T_CNAME: 519: case T_MB: 520: case T_MG: 521: case T_MR: 522: case T_NS: 523: case T_PTR: 524: if ((n = dn_expand(msg, msg + msglen, cp, data, 525: sizeof(data))) < 0) 526: return (-1); 527: cp += n; 528: cp1 = data; 529: n = strlen(data) + 1; 530: break; 531: 532: case T_MINFO: 533: case T_SOA: 534: if ((n = dn_expand(msg, msg + msglen, cp, data, 535: sizeof(data))) < 0) 536: return (-1); 537: cp += n; 538: cp1 = data + (n = strlen(data) + 1); 539: n1 = sizeof(data) - n; 540: if (type == T_SOA) 541: n1 -= 5 * sizeof(u_long); 542: if ((n = dn_expand(msg, msg + msglen, cp, cp1, n1)) < 0) 543: return (-1); 544: cp += n; 545: cp1 += strlen(cp1) + 1; 546: if (type == T_SOA) { 547: bcopy(cp, cp1, n = 5 * sizeof(u_long)); 548: cp += n; 549: cp1 += n; 550: } 551: n = cp1 - data; 552: cp1 = data; 553: break; 554: 555: case T_MX: 556: /* grab preference */ 557: bcopy(cp,data,sizeof(u_short)); 558: cp1 = data + sizeof(u_short); 559: cp += sizeof(u_short); 560: 561: /* get name */ 562: if ((n = dn_expand(msg, msg + msglen, cp, cp1, 563: sizeof(data)-sizeof(u_short))) < 0) 564: return(-1); 565: cp += n; 566: 567: /* compute end of data */ 568: cp1 += strlen(cp1) + 1; 569: /* compute size of data */ 570: n = cp1 - data; 571: cp1 = data; 572: break; 573: 574: default: 575: #ifdef DEBUG 576: if (debug >= 3) 577: fprintf(ddt,"unknown type %d\n", type); 578: #endif 579: return ((cp - rrp) + dlen); 580: } 581: dp = savedata(class, type, ttl, cp1, n); 582: dp->d_zone = zone; 583: if ((n = db_update(dname, dp, dp, DB_NODATA)) < 0) { 584: #ifdef DEBUG 585: if (debug && (n != DATAEXISTS)) 586: fprintf(ddt,"update failed (%d)\n", n); 587: else if (debug >= 3) 588: fprintf(ddt,"update failed (DATAEXISTS)\n"); 589: #endif 590: (void) free((char *)dp); 591: } else if (savens && type == T_NS && nspp < &nsp[MAXNS-1]) 592: *nspp++ = dp; 593: return (cp - rrp); 594: }