|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)ns_forw.c 4.3 (Berkeley) 6/4/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/socket.h> ! 13: #include <sys/time.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: struct qinfo *qhead = QINFO_NULL; /* head of allocated queries */ ! 21: struct qinfo *retryqp = QINFO_NULL; /* list of queries to retry */ ! 22: ! 23: int nsid; /* next forwarded query id */ ! 24: extern int errno; ! 25: ! 26: /* ! 27: * Forward the query to get the answer since its not in the database. ! 28: */ ! 29: ns_forw(nsp, msg, msglen, fp, qsp) ! 30: struct databuf *nsp[]; ! 31: char *msg; ! 32: int msglen; ! 33: struct sockaddr_in *fp; ! 34: struct qstream *qsp; ! 35: { ! 36: register struct qinfo *qp; ! 37: HEADER *hp; ! 38: u_short id; ! 39: extern char *calloc(); ! 40: extern char *malloc(); ! 41: ! 42: #ifdef DEBUG ! 43: if (debug > 3) ! 44: fprintf(ddt,"ns_forw()\n"); ! 45: #endif ! 46: ! 47: /* Don't forward if we're already working on it. */ ! 48: hp = (HEADER *) msg; ! 49: id = hp->id; ! 50: hp->rd = 0; ! 51: /* Look at them all */ ! 52: for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) { ! 53: if (qp->q_id == id && qp->q_msglen == msglen && ! 54: bcmp((char *)qp->q_msg+2, msg+2, msglen-2) == 0) ! 55: return (0); ! 56: } ! 57: ! 58: qp = qnew(); ! 59: qp->q_naddr = 0; ! 60: if (nslookup(nsp, qp) == 0) { ! 61: #ifdef DEBUG ! 62: if (debug >= 5) ! 63: fprintf(ddt,"none found in nsp\n"); ! 64: #endif ! 65: qfree(qp); ! 66: return (-1); ! 67: } ! 68: qp->q_stream = qsp; ! 69: qp->q_curaddr = 0; ! 70: qp->q_id = id; ! 71: hp->id = qp->q_nsid = htons((u_short)++nsid); ! 72: hp->ancount = 0; ! 73: hp->nscount = 0; ! 74: hp->arcount = 0; ! 75: qp->q_from = *fp; ! 76: if ((qp->q_msg = malloc((unsigned)msglen)) == NULL) { ! 77: syslog(LOG_ERR, "forw: %m"); ! 78: exit(1); ! 79: } ! 80: bcopy(msg, qp->q_msg, qp->q_msglen = msglen); ! 81: ! 82: schedretry(qp, (time_t)RETRYTIME); ! 83: #ifdef DEBUG ! 84: if (debug) ! 85: fprintf(ddt,"forw -> %s (%d)\n", ! 86: inet_ntoa(qp->q_addr[0].sin_addr), ! 87: ntohs(qp->q_addr[0].sin_port)); ! 88: if ( debug >= 10) ! 89: fp_query(msg, ddt); ! 90: #endif ! 91: if (sendto(ds, msg, msglen, 0, &qp->q_addr[0], ! 92: sizeof(qp->q_addr[0])) < 0) { ! 93: #ifdef DEBUG ! 94: if (debug >= 5) ! 95: fprintf(ddt,"error forwarding msg\n"); ! 96: #endif ! 97: } ! 98: return (0); ! 99: } ! 100: ! 101: /* ! 102: * Lookup the address for each nameserver in `nsp' and add it to ! 103: * the list saved in the qinfo structure. ! 104: */ ! 105: nslookup(nsp, qp) ! 106: struct databuf *nsp[]; ! 107: struct qinfo *qp; ! 108: { ! 109: register struct namebuf *np; ! 110: register struct databuf *dp, *pdp; ! 111: register int n, i; ! 112: struct databuf *tmp; ! 113: struct hashbuf *htp; ! 114: char *dname, *fname; ! 115: int naddr, class; ! 116: time_t curtime; ! 117: ! 118: extern short ns_port; ! 119: ! 120: #ifdef DEBUG ! 121: if (debug >= 3) ! 122: fprintf(ddt,"nslookup(nsp=x%x,qp=x%x)\n",nsp,qp); ! 123: #endif ! 124: ! 125: naddr = n = qp->q_naddr; ! 126: curtime = (u_long) tt.tv_sec; ! 127: while ((dp = *nsp++) != NULL) { ! 128: dname = dp->d_data; ! 129: class = dp->d_class; ! 130: htp = hashtab; /* lookup relative to root */ ! 131: np = nlookup(dname, &htp, &fname, 0); ! 132: if (np == NULL || fname != dname) { ! 133: #ifdef DEBUG ! 134: if (debug >= 5) ! 135: fprintf(ddt,"%s: not found\n", dname); ! 136: #endif ! 137: continue; ! 138: } ! 139: /* look for name server addresses */ ! 140: pdp = NULL; ! 141: dp = np->n_data; ! 142: while (dp != NULL) { ! 143: if (!match(dp, class, T_A)) ! 144: goto skip; ! 145: if ((dp->d_zone == 0) && (dp->d_ttl < curtime)) { ! 146: /* delete old cache entry */ ! 147: #ifdef DEBUG ! 148: if (debug >= 5) ! 149: fprintf(ddt,"deleting cache entry\n"); ! 150: #endif ! 151: rminv(dp); ! 152: tmp = dp->d_next; ! 153: (void) free((char *)dp); ! 154: dp = tmp; ! 155: if (pdp == NULL) ! 156: np->n_data = dp; ! 157: else ! 158: pdp->d_next = dp; ! 159: continue; ! 160: } ! 161: /* don't put in duplicates */ ! 162: for (i = 0; i < n; i++) ! 163: if (bcmp((char *)&qp->q_addr[i].sin_addr, ! 164: dp->d_data, sizeof(struct in_addr)) == 0) ! 165: goto skip; ! 166: if (n >= MAXNS) ! 167: break; ! 168: qp->q_addr[n].sin_family = AF_INET; ! 169: qp->q_addr[n].sin_addr = *(struct in_addr *)dp->d_data; ! 170: qp->q_addr[n].sin_port = (u_short)ns_port; ! 171: qp->q_nretry[n] = 0; ! 172: n++; ! 173: skip: pdp = dp; ! 174: dp = dp->d_next; ! 175: } ! 176: if (n >= MAXNS) { ! 177: #ifdef DEBUG ! 178: if (debug >= 5) ! 179: fprintf(ddt,"q_addr table full\n"); ! 180: #endif ! 181: break; ! 182: } ! 183: } ! 184: qp->q_naddr = n; ! 185: return (n - naddr); ! 186: } ! 187: ! 188: /* ! 189: * Arrange that forwarded query (qp) is retried after t seconds. ! 190: */ ! 191: schedretry(qp, t) ! 192: struct qinfo *qp; ! 193: time_t t; ! 194: { ! 195: register struct qinfo *qp1, *qp2; ! 196: ! 197: #ifdef DEBUG ! 198: if (debug > 3) { ! 199: fprintf(ddt,"schedretry(%#x, %d)\n", qp, t); ! 200: if (qp->q_time) ! 201: fprintf(ddt,"WARNING: schedretry(%x,%d) q_time already %d\n", qp->q_time); ! 202: } ! 203: #endif ! 204: t += (u_long) tt.tv_sec; ! 205: qp->q_time = t; ! 206: ! 207: if ((qp1 = retryqp) == NULL) { ! 208: retryqp = qp; ! 209: qp->q_next = NULL; ! 210: return; ! 211: } ! 212: while ((qp2 = qp1->q_next) != NULL && qp2->q_time < t) ! 213: qp1 = qp2; ! 214: qp1->q_next = qp; ! 215: qp->q_next = qp2; ! 216: } ! 217: ! 218: /* ! 219: * Unsched is called to remove a forwarded query entry. ! 220: */ ! 221: unsched(qp) ! 222: struct qinfo *qp; ! 223: { ! 224: register struct qinfo *np; ! 225: ! 226: #ifdef DEBUG ! 227: if (debug > 3) { ! 228: fprintf(ddt,"unsched(%#x, %d )\n", qp, qp->q_id); ! 229: } ! 230: #endif ! 231: if( retryqp == qp ) { ! 232: retryqp = qp->q_next; ! 233: } else { ! 234: for( np=retryqp; np->q_next != QINFO_NULL; np = np->q_next ) { ! 235: if( np->q_next != qp) ! 236: continue; ! 237: np->q_next = qp->q_next; /* dequeue */ ! 238: break; ! 239: } ! 240: } ! 241: qp->q_next = QINFO_NULL; /* sanity check */ ! 242: qp->q_time = 0; ! 243: } ! 244: ! 245: /* ! 246: * Retry is called to retransmit query 'qp'. ! 247: */ ! 248: retry(qp) ! 249: register struct qinfo *qp; ! 250: { ! 251: register int n; ! 252: register HEADER *hp; ! 253: ! 254: #ifdef DEBUG ! 255: if (debug > 3) ! 256: fprintf(ddt,"retry(x%x) id=%d\n", qp, ntohs(qp->q_id)); ! 257: #endif ! 258: ! 259: /* try next address */ ! 260: n = qp->q_curaddr; ! 261: ++qp->q_nretry[n]; ! 262: do { ! 263: if (++n >= qp->q_naddr) ! 264: n = 0; ! 265: if (qp->q_nretry[n] < MAXRETRY) ! 266: goto found; ! 267: } while (n != qp->q_curaddr); ! 268: /* ! 269: * Give up. Can't reach destination. ! 270: */ ! 271: #ifdef DEBUG ! 272: if (debug >= 5) ! 273: fprintf(ddt,"give up\n"); ! 274: #endif ! 275: hp = (HEADER *)qp->q_msg; ! 276: hp->qr = 1; ! 277: hp->rcode = SERVFAIL; ! 278: hp->ra = 1; ! 279: #ifdef DEBUG ! 280: if (debug >= 10) ! 281: fp_query(qp->q_msg, ddt); ! 282: #endif ! 283: if (sendto(ds, qp->q_msg, qp->q_msglen, 0, &qp->q_from, ! 284: sizeof(qp->q_from))) { ! 285: #ifdef DEBUG ! 286: if (debug) ! 287: fprintf(ddt,"gave up retry(x%x) id=%d\n", ! 288: qp, ntohs(qp->q_id)); ! 289: #endif ! 290: } ! 291: qremove(qp); ! 292: return; ! 293: found: ! 294: qp->q_curaddr = n; ! 295: #ifdef DEBUG ! 296: if (debug) ! 297: fprintf(ddt,"resend(id=%d n=%d) -> %s (%d)\n",ntohs(qp->q_id), ! 298: n, inet_ntoa(qp->q_addr[n].sin_addr), ! 299: ntohs(qp->q_addr[n].sin_port)); ! 300: if ( debug >= 10) ! 301: fp_query(qp->q_msg, ddt); ! 302: #endif ! 303: if (sendto(ds, qp->q_msg, qp->q_msglen, 0, &qp->q_addr[n], ! 304: sizeof(qp->q_addr[0])) < 0) { ! 305: #ifdef DEBUG ! 306: if (debug > 3) ! 307: fprintf(ddt,"error returning msg\n"); ! 308: #endif ! 309: } ! 310: unsched(qp); ! 311: schedretry(qp, (time_t)RETRYTIME); ! 312: } ! 313: ! 314: qremove(qp) ! 315: register struct qinfo *qp; ! 316: { ! 317: #ifdef DEBUG ! 318: if(debug > 3) ! 319: fprintf(ddt,"qremove(x%x)\n", qp); ! 320: #endif ! 321: unsched(qp); /* get off queue first */ ! 322: free(qp->q_msg); ! 323: if (qp->q_cmsg); ! 324: free(qp->q_cmsg); ! 325: qfree(qp); ! 326: } ! 327: ! 328: struct qinfo * ! 329: qfindid(id) ! 330: register u_short id; ! 331: { ! 332: register struct qinfo *qp; ! 333: ! 334: #ifdef DEBUG ! 335: if(debug > 3) ! 336: fprintf(ddt,"qfindid(%d)\n", ntohs(id)); ! 337: #endif ! 338: for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) { ! 339: if (qp->q_nsid == id) ! 340: return(qp); ! 341: } ! 342: #ifdef DEBUG ! 343: if (debug >= 5) ! 344: fprintf(ddt,"qp not found\n"); ! 345: #endif ! 346: return(NULL); ! 347: } ! 348: ! 349: struct qinfo * ! 350: qnew() ! 351: { ! 352: register struct qinfo *qp; ! 353: ! 354: if ((qp = (struct qinfo *)calloc(1, sizeof(struct qinfo))) == NULL) { ! 355: #ifdef DEBUG ! 356: if (debug >= 5) ! 357: fprintf(ddt,"qnew: calloc error\n"); ! 358: #endif ! 359: syslog(LOG_ERR, "forw: %m"); ! 360: exit(12); ! 361: } ! 362: #ifdef DEBUG ! 363: if (debug >= 5) ! 364: fprintf(ddt,"qnew(x%x)\n", qp); ! 365: #endif ! 366: qp->q_link = qhead; ! 367: qhead = qp; ! 368: return( qp ); ! 369: } ! 370: ! 371: qfree(qp) ! 372: struct qinfo *qp; ! 373: { ! 374: register struct qinfo *np; ! 375: ! 376: #ifdef DEBUG ! 377: if(debug > 3) ! 378: fprintf(ddt,"qfree( x%x )\n", qp); ! 379: if(debug && qp->q_next) ! 380: fprintf(ddt,"WARNING: qfree of linked ptr x%x\n", qp); ! 381: #endif ! 382: if( qhead == qp ) { ! 383: qhead = qp->q_link; ! 384: } else { ! 385: for( np=qhead; np->q_link != QINFO_NULL; np = np->q_link ) { ! 386: if( np->q_link != qp ) continue; ! 387: np->q_link = qp->q_link; /* dequeue */ ! 388: break; ! 389: } ! 390: } ! 391: (void)free((char *)qp); ! 392: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.