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