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: }