1: /* 2: * Copyright (c) 1986 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_forw.c 4.26 (Berkeley) 3/28/88"; 15: #endif /* not lint */ 16: 17: #include <stdio.h> 18: #include <sys/param.h> 19: #include <sys/time.h> 20: #include <sys/socket.h> 21: #include <netinet/in.h> 22: #include <syslog.h> 23: #include <arpa/nameser.h> 24: #include "ns.h" 25: #include "db.h" 26: 27: struct qinfo *qhead = QINFO_NULL; /* head of allocated queries */ 28: struct qinfo *retryqp = QINFO_NULL; /* list of queries to retry */ 29: struct fwdinfo *fwdtab; /* list of forwarding hosts */ 30: 31: int nsid; /* next forwarded query id */ 32: extern int forward_only; /* you are only a slave */ 33: extern int errno; 34: extern short ns_port; 35: 36: time_t retrytime(); 37: 38: /* 39: * Forward the query to get the answer since its not in the database. 40: * Returns FW_OK if a request struct is allocated and the query sent. 41: * Returns FW_DUP if this is a duplicate of a pending request. 42: * Returns FW_NOSERVER if there were no addresses for the nameservers. 43: * Returns FW_SERVFAIL on malloc error. 44: * (no action is taken on errors and qpp is not filled in.) 45: */ 46: ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp) 47: struct databuf *nsp[]; 48: char *msg; 49: int msglen; 50: struct sockaddr_in *fp; 51: struct qstream *qsp; 52: int dfd; 53: struct qinfo **qpp; 54: { 55: register struct qinfo *qp; 56: HEADER *hp; 57: u_short id; 58: extern char *calloc(); 59: 60: #ifdef DEBUG 61: if (debug >= 3) 62: fprintf(ddt,"ns_forw()\n"); 63: #endif 64: 65: /* Don't forward if we're already working on it. */ 66: hp = (HEADER *) msg; 67: id = hp->id; 68: hp->rd = 0; 69: /* Look at them all */ 70: for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) { 71: if (qp->q_id == id && 72: bcmp((char *)&qp->q_from, fp, sizeof(qp->q_from)) == 0 && 73: (qp->q_cmsglen == 0 && qp->q_msglen == msglen && 74: bcmp((char *)qp->q_msg+2, msg+2, msglen-2) == 0) || 75: (qp->q_cmsglen == msglen && 76: bcmp((char *)qp->q_cmsg+2, msg+2, msglen-2) == 0)) { 77: #ifdef DEBUG 78: if (debug >= 3) 79: fprintf(ddt,"forw: dropped DUP id=%d\n", ntohs(id)); 80: #endif 81: #ifdef STATS 82: stats[S_DUPQUERIES].cnt++; 83: #endif 84: return (FW_DUP); 85: } 86: } 87: 88: qp = qnew(); 89: if (nslookup(nsp, qp) == 0) { 90: #ifdef DEBUG 91: if (debug >= 2) 92: fprintf(ddt,"forw: no nameservers found\n"); 93: #endif 94: qfree(qp); 95: hp->rd = 1; 96: return (FW_NOSERVER); 97: } 98: qp->q_stream = qsp; 99: qp->q_curaddr = 0; 100: qp->q_fwd = fwdtab; 101: qp->q_dfd = dfd; 102: qp->q_id = id; 103: hp->id = qp->q_nsid = htons((u_short)++nsid); 104: hp->ancount = 0; 105: hp->nscount = 0; 106: hp->arcount = 0; 107: if (qp->q_fwd) 108: hp->rd = 1; 109: else 110: qp->q_addr[0].stime = tt; 111: qp->q_from = *fp; 112: if ((qp->q_msg = malloc((unsigned)msglen)) == NULL) { 113: syslog(LOG_ERR, "forw: %m"); 114: qfree(qp); 115: return (FW_SERVFAIL); 116: } 117: bcopy(msg, qp->q_msg, qp->q_msglen = msglen); 118: 119: schedretry(qp, retrytime(qp)); 120: #ifdef DEBUG 121: if (debug) 122: fprintf(ddt, 123: "forw: forw -> %s %d (%d) nsid=%d id=%d %ldms retry %ld sec\n", 124: inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr), 125: ds, ntohs(Q_NEXTADDR(qp,0)->sin_port), 126: ntohs(qp->q_nsid), ntohs(qp->q_id), 127: qp->q_addr[0].nsdata->d_nstime, 128: qp->q_time - tt.tv_sec); 129: if ( debug >= 10) 130: fp_query(msg, ddt); 131: #endif 132: if (sendto(ds, msg, msglen, 0, (struct sockaddr *)Q_NEXTADDR(qp,0), 133: sizeof(struct sockaddr_in)) < 0){ 134: #ifdef DEBUG 135: if (debug >= 5) 136: fprintf(ddt,"error returning msg errno=%d\n",errno); 137: #endif 138: } 139: #ifdef STATS 140: stats[S_OUTPKTS].cnt++; 141: #endif 142: if (qpp) 143: *qpp = qp; 144: hp->rd = 0; 145: return (0); 146: } 147: 148: /* 149: * Lookup the address for each nameserver in `nsp' and add it to 150: * the list saved in the qinfo structure. 151: */ 152: nslookup(nsp, qp) 153: struct databuf *nsp[]; 154: register struct qinfo *qp; 155: { 156: register struct namebuf *np; 157: register struct databuf *dp, *nsdp; 158: register struct qserv *qs; 159: register int n, i; 160: struct hashbuf *tmphtp; 161: char *dname, *fname; 162: int oldn, naddr, class, found_arr; 163: time_t curtime; 164: int qcomp(); 165: 166: #ifdef DEBUG 167: if (debug >= 3) 168: fprintf(ddt,"nslookup(nsp=x%x,qp=x%x)\n",nsp,qp); 169: #endif 170: 171: naddr = n = qp->q_naddr; 172: curtime = (u_long) tt.tv_sec; 173: while ((nsdp = *nsp++) != NULL) { 174: class = nsdp->d_class; 175: dname = nsdp->d_data; 176: #ifdef DEBUG 177: if (debug >= 3) 178: fprintf(ddt,"nslookup: NS %s c%d t%d (x%x)\n", 179: dname, class, nsdp->d_type, nsdp->d_flags); 180: #endif 181: /* don't put in people we have tried */ 182: for (i = 0; i < qp->q_nusedns; i++) 183: if (qp->q_usedns[i] == nsdp) { 184: #ifdef DEBUG 185: if (debug >= 2) 186: fprintf(ddt, "skipping used NS w/name %s\n", nsdp->d_data); 187: #endif DEBUG 188: goto skipserver; 189: } 190: 191: tmphtp = ((nsdp->d_flags & DB_F_HINT) ? fcachetab : hashtab); 192: np = nlookup(dname, &tmphtp, &fname, 1); 193: if (np == NULL || fname != dname) { 194: #ifdef DEBUG 195: if (debug >= 3) 196: fprintf(ddt,"%s: not found %s %x\n",dname,fname,np); 197: #endif 198: continue; 199: } 200: found_arr = 0; 201: oldn = n; 202: /* look for name server addresses */ 203: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { 204: if (dp->d_type != T_A || dp->d_class != class) 205: continue; 206: /* 207: * Don't use records that may become invalid to 208: * reference later when we do the rtt computation. 209: * Never delete our safety-belt information! 210: */ 211: if ((dp->d_zone == 0) && 212: (dp->d_ttl < (curtime+900)) && 213: !(dp->d_flags & DB_F_HINT) ) 214: { 215: #ifdef DEBUG 216: if (debug >= 3) 217: fprintf(ddt,"nslookup: stale entry '%s'\n", 218: np->n_dname); 219: #endif 220: /* Cache invalidate the NS RR's */ 221: if (dp->d_ttl < curtime) 222: delete_all(np, class, T_A); 223: n = oldn; 224: break; 225: } 226: 227: found_arr++; 228: /* don't put in duplicates */ 229: qs = qp->q_addr; 230: for (i = 0; i < n; i++, qs++) 231: if (bcmp((char *)&qs->ns_addr.sin_addr, 232: dp->d_data, sizeof(struct in_addr)) == 0) 233: goto skipaddr; 234: qs->ns_addr.sin_family = AF_INET; 235: qs->ns_addr.sin_port = (u_short)ns_port; 236: qs->ns_addr.sin_addr = 237: *(struct in_addr *)dp->d_data; 238: qs->ns = nsdp; 239: qs->nsdata = dp; 240: qp->q_addr[n].nretry = 0; 241: n++; 242: if (n >= NSMAX) 243: goto out; 244: skipaddr: ; 245: } 246: #ifdef DEBUG 247: if (debug >= 3) 248: fprintf(ddt,"nslookup: %d ns addrs\n", n); 249: #endif 250: if (found_arr == 0 && qp->q_system == 0) 251: (void) sysquery(dname, class, T_A); 252: skipserver: ; 253: } 254: out: 255: #ifdef DEBUG 256: if (debug >= 3) 257: fprintf(ddt,"nslookup: %d ns addrs total\n", n); 258: #endif 259: qp->q_naddr = n; 260: if (n > 1) 261: qsort((char *)qp->q_addr, n, sizeof(struct qserv), qcomp); 262: return (n - naddr); 263: } 264: 265: qcomp(qs1, qs2) 266: struct qserv *qs1, *qs2; 267: { 268: register u_long qservcmp = 269: qs1->nsdata->d_nstime - qs2->nsdata->d_nstime; 270: 271: return (qservcmp > 0 ? 1 : (qservcmp == 0 ? 0 : -1)); 272: } 273: 274: /* 275: * Arrange that forwarded query (qp) is retried after t seconds. 276: */ 277: schedretry(qp, t) 278: struct qinfo *qp; 279: time_t t; 280: { 281: register struct qinfo *qp1, *qp2; 282: 283: #ifdef DEBUG 284: if (debug > 3) { 285: fprintf(ddt,"schedretry(%x, %ldsec)\n", qp, t); 286: if (qp->q_time) 287: fprintf(ddt,"WARNING: schedretry(%x,%ld) q_time already %ld\n", qp, t, qp->q_time); 288: } 289: #endif 290: t += (u_long) tt.tv_sec; 291: qp->q_time = t; 292: 293: if ((qp1 = retryqp) == NULL) { 294: retryqp = qp; 295: qp->q_next = NULL; 296: return; 297: } 298: while ((qp2 = qp1->q_next) != NULL && qp2->q_time < t) 299: qp1 = qp2; 300: qp1->q_next = qp; 301: qp->q_next = qp2; 302: } 303: 304: /* 305: * Unsched is called to remove a forwarded query entry. 306: */ 307: unsched(qp) 308: struct qinfo *qp; 309: { 310: register struct qinfo *np; 311: 312: #ifdef DEBUG 313: if (debug > 3) { 314: fprintf(ddt,"unsched(%x, %d )\n", qp, ntohs(qp->q_id)); 315: } 316: #endif 317: if( retryqp == qp ) { 318: retryqp = qp->q_next; 319: } else { 320: for( np=retryqp; np->q_next != QINFO_NULL; np = np->q_next ) { 321: if( np->q_next != qp) 322: continue; 323: np->q_next = qp->q_next; /* dequeue */ 324: break; 325: } 326: } 327: qp->q_next = QINFO_NULL; /* sanity check */ 328: qp->q_time = 0; 329: } 330: 331: /* 332: * Retry is called to retransmit query 'qp'. 333: */ 334: retry(qp) 335: register struct qinfo *qp; 336: { 337: register int n; 338: register HEADER *hp; 339: 340: #ifdef DEBUG 341: if (debug > 3) 342: fprintf(ddt,"retry(x%x) id=%d\n", qp, ntohs(qp->q_id)); 343: #endif 344: if((HEADER *)qp->q_msg == NULL) { /*** XXX ***/ 345: qremove(qp); 346: return; 347: } /*** XXX ***/ 348: 349: /* try next address */ 350: n = qp->q_curaddr; 351: if (qp->q_fwd) { 352: qp->q_fwd = qp->q_fwd->next; 353: if (qp->q_fwd) 354: goto found; 355: /* out of forwarders, try direct queries */ 356: } else 357: ++qp->q_addr[n].nretry; 358: if (!forward_only) { 359: do { 360: if (++n >= qp->q_naddr) 361: n = 0; 362: if (qp->q_addr[n].nretry < MAXRETRY) 363: goto found; 364: } while (n != qp->q_curaddr); 365: } 366: /* 367: * Give up. Can't reach destination. 368: */ 369: hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg); 370: if (qp->q_system == PRIMING_CACHE) { 371: /* Can't give up priming */ 372: unsched(qp); 373: schedretry(qp, (time_t)60*60); /* 1 hour */ 374: hp->rcode = NOERROR; /* Lets be safe, reset the query */ 375: hp->qr = hp->aa = 0; 376: qp->q_fwd = fwdtab; 377: for (n = 0; n < qp->q_naddr; n++) 378: qp->q_addr[n].nretry = 0; 379: return; 380: } 381: #ifdef DEBUG 382: if (debug >= 5) 383: fprintf(ddt,"give up\n"); 384: #endif 385: n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen); 386: hp->id = qp->q_id; 387: hp->qr = 1; 388: hp->ra = 1; 389: hp->rd = 1; 390: hp->rcode = SERVFAIL; 391: #ifdef DEBUG 392: if (debug >= 10) 393: fp_query(qp->q_msg, ddt); 394: #endif 395: if (send_msg((char *)hp, n, qp)) { 396: #ifdef DEBUG 397: if (debug) 398: fprintf(ddt,"gave up retry(x%x) nsid=%d id=%d\n", 399: qp, ntohs(qp->q_nsid), ntohs(qp->q_id)); 400: #endif 401: } 402: qremove(qp); 403: return; 404: 405: found: 406: if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0) 407: qp->q_addr[n].stime = tt; 408: qp->q_curaddr = n; 409: hp = (HEADER *)qp->q_msg; 410: hp->rd = (qp->q_fwd ? 1 : 0); 411: #ifdef DEBUG 412: if (debug) 413: fprintf(ddt,"%s(addr=%d n=%d) -> %s %d (%d) nsid=%d id=%d %ldms\n", 414: (qp->q_fwd ? "reforw" : "resend"), 415: n, qp->q_addr[n].nretry, 416: inet_ntoa(Q_NEXTADDR(qp,n)->sin_addr), 417: ds, ntohs(Q_NEXTADDR(qp,n)->sin_port), 418: ntohs(qp->q_nsid), ntohs(qp->q_id), 419: qp->q_addr[n].nsdata->d_nstime); 420: if ( debug >= 10) 421: fp_query(qp->q_msg, ddt); 422: #endif 423: /* NOSTRICT */ 424: if (sendto(ds, qp->q_msg, qp->q_msglen, 0, 425: (struct sockaddr *)Q_NEXTADDR(qp,n), 426: sizeof(struct sockaddr_in)) < 0){ 427: #ifdef DEBUG 428: if (debug > 3) 429: fprintf(ddt,"error resending msg errno=%d\n",errno); 430: #endif 431: } 432: hp->rd = 0; /* leave set to 0 for dup detection */ 433: #ifdef STATS 434: stats[S_OUTPKTS].cnt++; 435: #endif 436: unsched(qp); 437: schedretry(qp, (time_t)(qp->q_fwd ? (2*RETRYBASE) : retrytime(qp))); 438: } 439: 440: /* 441: * Compute retry time for the next server for a query. 442: * Use a minimum time of RETRYBASE (4 sec.) or twice the estimated 443: * service time; * back off exponentially on retries, but place a 45-sec. 444: * ceiling on retry times for now. (This is because we don't hold a reference 445: * on servers or their addresses, and we have to finish before they time out.) 446: */ 447: time_t 448: retrytime(qp) 449: register struct qinfo *qp; 450: { 451: time_t t; 452: struct qserv *ns = &qp->q_addr[qp->q_curaddr]; 453: 454: #ifdef DEBUG 455: if (debug > 3) 456: fprintf(ddt,"retrytime: nstime %ldms.\n", 457: ns->nsdata->d_nstime / 1000); 458: #endif 459: t = (time_t) MAX(RETRYBASE, 2 * ns->nsdata->d_nstime / 1000); 460: t <<= ns->nretry; 461: t = MIN(t, 45); /* max. retry timeout for now */ 462: #ifdef notdef 463: if (qp->q_system) 464: return ((2 * t) + 5); /* system queries can wait. */ 465: #endif 466: return (t); 467: } 468: 469: qflush() 470: { 471: while (qhead) 472: qremove(qhead); 473: qhead = QINFO_NULL; 474: } 475: 476: qremove(qp) 477: register struct qinfo *qp; 478: { 479: #ifdef DEBUG 480: if(debug > 3) 481: fprintf(ddt,"qremove(x%x)\n", qp); 482: #endif 483: unsched(qp); /* get off queue first */ 484: qfree(qp); 485: } 486: 487: struct qinfo * 488: qfindid(id) 489: register u_short id; 490: { 491: register struct qinfo *qp; 492: 493: #ifdef DEBUG 494: if(debug > 3) 495: fprintf(ddt,"qfindid(%d)\n", ntohs(id)); 496: #endif 497: for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) { 498: if (qp->q_nsid == id) 499: return(qp); 500: } 501: #ifdef DEBUG 502: if (debug >= 5) 503: fprintf(ddt,"qp not found\n"); 504: #endif 505: return(NULL); 506: } 507: 508: struct qinfo * 509: qnew() 510: { 511: register struct qinfo *qp; 512: 513: if ((qp = (struct qinfo *)calloc(1, sizeof(struct qinfo))) == NULL) { 514: #ifdef DEBUG 515: if (debug >= 5) 516: fprintf(ddt,"qnew: calloc error\n"); 517: #endif 518: syslog(LOG_ERR, "forw: %m"); 519: exit(12); 520: } 521: #ifdef DEBUG 522: if (debug >= 5) 523: fprintf(ddt,"qnew(x%x)\n", qp); 524: #endif 525: qp->q_link = qhead; 526: qhead = qp; 527: return( qp ); 528: } 529: 530: qfree(qp) 531: struct qinfo *qp; 532: { 533: register struct qinfo *np; 534: 535: #ifdef DEBUG 536: if(debug > 3) 537: fprintf(ddt,"qfree( x%x )\n", qp); 538: if(debug && qp->q_next) 539: fprintf(ddt,"WARNING: qfree of linked ptr x%x\n", qp); 540: #endif 541: if (qp->q_msg) 542: free(qp->q_msg); 543: if (qp->q_cmsg) 544: free(qp->q_cmsg); 545: if( qhead == qp ) { 546: qhead = qp->q_link; 547: } else { 548: for( np=qhead; np->q_link != QINFO_NULL; np = np->q_link ) { 549: if( np->q_link != qp ) continue; 550: np->q_link = qp->q_link; /* dequeue */ 551: break; 552: } 553: } 554: (void)free((char *)qp); 555: }