|
|
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.