|
|
1.1 root 1: /*-
2: * Copyright (c) 1986 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: static char sccsid[] = "@(#)ns_forw.c 4.30 (Berkeley) 6/27/90";
22: #endif /* not lint */
23:
24: #include <sys/param.h>
25: #include <sys/time.h>
26: #include <sys/socket.h>
27: #include <netinet/in.h>
28: #include <syslog.h>
29: #include <arpa/nameser.h>
30: #include <stdio.h>
31: #include "ns.h"
32: #include "db.h"
33:
34: struct qinfo *qhead = QINFO_NULL; /* head of allocated queries */
35: struct qinfo *retryqp = QINFO_NULL; /* list of queries to retry */
36: struct fwdinfo *fwdtab; /* list of forwarding hosts */
37:
38: int nsid; /* next forwarded query id */
39: extern int forward_only; /* you are only a slave */
40: extern int errno;
41: extern u_short ns_port;
42:
43: time_t retrytime();
44:
45: /*
46: * Forward the query to get the answer since its not in the database.
47: * Returns FW_OK if a request struct is allocated and the query sent.
48: * Returns FW_DUP if this is a duplicate of a pending request.
49: * Returns FW_NOSERVER if there were no addresses for the nameservers.
50: * Returns FW_SERVFAIL on malloc error.
51: * (no action is taken on errors and qpp is not filled in.)
52: */
53: ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp)
54: struct databuf *nsp[];
55: char *msg;
56: int msglen;
57: struct sockaddr_in *fp;
58: struct qstream *qsp;
59: int dfd;
60: struct qinfo **qpp;
61: {
62: register struct qinfo *qp;
63: HEADER *hp;
64: u_short id;
65: extern char *calloc();
66:
67: #ifdef DEBUG
68: if (debug >= 3)
69: fprintf(ddt,"ns_forw()\n");
70: #endif
71:
72: /* Don't forward if we're already working on it. */
73: hp = (HEADER *) msg;
74: id = hp->id;
75: /* Look at them all */
76: for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
77: if (qp->q_id == id &&
78: bcmp((char *)&qp->q_from, fp, sizeof(qp->q_from)) == 0 &&
79: ((qp->q_cmsglen == 0 && qp->q_msglen == msglen &&
80: bcmp((char *)qp->q_msg+2, msg+2, msglen-2) == 0) ||
81: (qp->q_cmsglen == msglen &&
82: bcmp((char *)qp->q_cmsg+2, msg+2, msglen-2) == 0))) {
83: #ifdef DEBUG
84: if (debug >= 3)
85: fprintf(ddt,"forw: dropped DUP id=%d\n", ntohs(id));
86: #endif
87: #ifdef STATS
88: stats[S_DUPQUERIES].cnt++;
89: #endif
90: return (FW_DUP);
91: }
92: }
93:
94: qp = qnew();
95: if (nslookup(nsp, qp) == 0) {
96: #ifdef DEBUG
97: if (debug >= 2)
98: fprintf(ddt,"forw: no nameservers found\n");
99: #endif
100: qfree(qp);
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: qp->q_from = *fp;
113: if ((qp->q_msg = malloc((unsigned)msglen)) == NULL) {
114: syslog(LOG_ERR, "forw: %m");
115: qfree(qp);
116: return (FW_SERVFAIL);
117: }
118: bcopy(msg, qp->q_msg, qp->q_msglen = msglen);
119: if (!qp->q_fwd) {
120: hp->rd = 0;
121: qp->q_addr[0].stime = tt;
122: }
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 = 1;
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 = 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: if (t < qp1->q_time) {
302: qp->q_next = qp1;
303: retryqp = qp;
304: return;
305: }
306: while ((qp2 = qp1->q_next) != NULL && qp2->q_time < t)
307: qp1 = qp2;
308: qp1->q_next = qp;
309: qp->q_next = qp2;
310: }
311:
312: /*
313: * Unsched is called to remove a forwarded query entry.
314: */
315: unsched(qp)
316: struct qinfo *qp;
317: {
318: register struct qinfo *np;
319:
320: #ifdef DEBUG
321: if (debug > 3) {
322: fprintf(ddt,"unsched(%#x, %d )\n", qp, ntohs(qp->q_id));
323: }
324: #endif
325: if( retryqp == qp ) {
326: retryqp = qp->q_next;
327: } else {
328: for( np=retryqp; np->q_next != QINFO_NULL; np = np->q_next ) {
329: if( np->q_next != qp)
330: continue;
331: np->q_next = qp->q_next; /* dequeue */
332: break;
333: }
334: }
335: qp->q_next = QINFO_NULL; /* sanity check */
336: qp->q_time = 0;
337: }
338:
339: /*
340: * Retry is called to retransmit query 'qp'.
341: */
342: retry(qp)
343: register struct qinfo *qp;
344: {
345: register int n;
346: register HEADER *hp;
347:
348: #ifdef DEBUG
349: if (debug > 3)
350: fprintf(ddt,"retry(x%x) id=%d\n", qp, ntohs(qp->q_id));
351: #endif
352: if((HEADER *)qp->q_msg == NULL) { /*** XXX ***/
353: qremove(qp);
354: return;
355: } /*** XXX ***/
356:
357: /* try next address */
358: n = qp->q_curaddr;
359: if (qp->q_fwd) {
360: qp->q_fwd = qp->q_fwd->next;
361: if (qp->q_fwd)
362: goto found;
363: /* out of forwarders, try direct queries */
364: } else
365: ++qp->q_addr[n].nretry;
366: if (!forward_only) {
367: do {
368: if (++n >= qp->q_naddr)
369: n = 0;
370: if (qp->q_addr[n].nretry < MAXRETRY)
371: goto found;
372: } while (n != qp->q_curaddr);
373: }
374: /*
375: * Give up. Can't reach destination.
376: */
377: hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg);
378: if (qp->q_system == PRIMING_CACHE) {
379: /* Can't give up priming */
380: unsched(qp);
381: schedretry(qp, (time_t)60*60); /* 1 hour */
382: hp->rcode = NOERROR; /* Lets be safe, reset the query */
383: hp->qr = hp->aa = 0;
384: qp->q_fwd = fwdtab;
385: for (n = 0; n < qp->q_naddr; n++)
386: qp->q_addr[n].nretry = 0;
387: return;
388: }
389: #ifdef DEBUG
390: if (debug >= 5)
391: fprintf(ddt,"give up\n");
392: #endif
393: n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen);
394: hp->id = qp->q_id;
395: hp->qr = 1;
396: hp->ra = 1;
397: hp->rd = 1;
398: hp->rcode = SERVFAIL;
399: #ifdef DEBUG
400: if (debug >= 10)
401: fp_query(qp->q_msg, ddt);
402: #endif
403: if (send_msg((char *)hp, n, qp)) {
404: #ifdef DEBUG
405: if (debug)
406: fprintf(ddt,"gave up retry(x%x) nsid=%d id=%d\n",
407: qp, ntohs(qp->q_nsid), ntohs(qp->q_id));
408: #endif
409: }
410: qremove(qp);
411: return;
412:
413: found:
414: if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0)
415: qp->q_addr[n].stime = tt;
416: qp->q_curaddr = n;
417: hp = (HEADER *)qp->q_msg;
418: hp->rd = (qp->q_fwd ? 1 : 0);
419: #ifdef DEBUG
420: if (debug)
421: fprintf(ddt,"%s(addr=%d n=%d) -> %s %d (%d) nsid=%d id=%d %dms\n",
422: (qp->q_fwd ? "reforw" : "resend"),
423: n, qp->q_addr[n].nretry,
424: inet_ntoa(Q_NEXTADDR(qp,n)->sin_addr),
425: ds, ntohs(Q_NEXTADDR(qp,n)->sin_port),
426: ntohs(qp->q_nsid), ntohs(qp->q_id),
427: qp->q_addr[n].nsdata->d_nstime);
428: if ( debug >= 10)
429: fp_query(qp->q_msg, ddt);
430: #endif
431: /* NOSTRICT */
432: if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
433: (struct sockaddr *)Q_NEXTADDR(qp,n),
434: sizeof(struct sockaddr_in)) < 0){
435: #ifdef DEBUG
436: if (debug > 3)
437: fprintf(ddt,"error resending msg errno=%d\n",errno);
438: #endif
439: }
440: hp->rd = 1; /* leave set to 1 for dup detection */
441: #ifdef STATS
442: stats[S_OUTPKTS].cnt++;
443: #endif
444: unsched(qp);
445: schedretry(qp, qp->q_fwd ? (2*RETRYBASE) : retrytime(qp));
446: }
447:
448: /*
449: * Compute retry time for the next server for a query.
450: * Use a minimum time of RETRYBASE (4 sec.) or twice the estimated
451: * service time; * back off exponentially on retries, but place a 45-sec.
452: * ceiling on retry times for now. (This is because we don't hold a reference
453: * on servers or their addresses, and we have to finish before they time out.)
454: */
455: time_t
456: retrytime(qp)
457: register struct qinfo *qp;
458: {
459: time_t t;
460: struct qserv *ns = &qp->q_addr[qp->q_curaddr];
461:
462: #ifdef DEBUG
463: if (debug > 3)
464: fprintf(ddt,"retrytime: nstime %dms.\n",
465: ns->nsdata->d_nstime / 1000);
466: #endif
467: t = (time_t) MAX(RETRYBASE, 2 * ns->nsdata->d_nstime / 1000);
468: t <<= ns->nretry;
469: t = MIN(t, 45); /* max. retry timeout for now */
470: #ifdef notdef
471: if (qp->q_system)
472: return ((2 * t) + 5); /* system queries can wait. */
473: #endif
474: return (t);
475: }
476:
477: qflush()
478: {
479: while (qhead)
480: qremove(qhead);
481: qhead = QINFO_NULL;
482: }
483:
484: qremove(qp)
485: register struct qinfo *qp;
486: {
487: #ifdef DEBUG
488: if(debug > 3)
489: fprintf(ddt,"qremove(x%x)\n", qp);
490: #endif
491: unsched(qp); /* get off queue first */
492: qfree(qp);
493: }
494:
495: struct qinfo *
496: qfindid(id)
497: register u_short id;
498: {
499: register struct qinfo *qp;
500:
501: #ifdef DEBUG
502: if(debug > 3)
503: fprintf(ddt,"qfindid(%d)\n", ntohs(id));
504: #endif
505: for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
506: if (qp->q_nsid == id)
507: return(qp);
508: }
509: #ifdef DEBUG
510: if (debug >= 5)
511: fprintf(ddt,"qp not found\n");
512: #endif
513: return(NULL);
514: }
515:
516: struct qinfo *
517: qnew()
518: {
519: register struct qinfo *qp;
520:
521: if ((qp = (struct qinfo *)calloc(1, sizeof(struct qinfo))) == NULL) {
522: #ifdef DEBUG
523: if (debug >= 5)
524: fprintf(ddt,"qnew: calloc error\n");
525: #endif
526: syslog(LOG_ERR, "forw: %m");
527: exit(12);
528: }
529: #ifdef DEBUG
530: if (debug >= 5)
531: fprintf(ddt,"qnew(x%x)\n", qp);
532: #endif
533: qp->q_link = qhead;
534: qhead = qp;
535: return( qp );
536: }
537:
538: qfree(qp)
539: struct qinfo *qp;
540: {
541: register struct qinfo *np;
542:
543: #ifdef DEBUG
544: if(debug > 3)
545: fprintf(ddt,"qfree( x%x )\n", qp);
546: if(debug && qp->q_next)
547: fprintf(ddt,"WARNING: qfree of linked ptr x%x\n", qp);
548: #endif
549: if (qp->q_msg)
550: free(qp->q_msg);
551: if (qp->q_cmsg)
552: free(qp->q_cmsg);
553: if( qhead == qp ) {
554: qhead = qp->q_link;
555: } else {
556: for( np=qhead; np->q_link != QINFO_NULL; np = np->q_link ) {
557: if( np->q_link != qp ) continue;
558: np->q_link = qp->q_link; /* dequeue */
559: break;
560: }
561: }
562: (void)free((char *)qp);
563: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.