Commit | Line | Data |
---|---|---|
0aef8126 WJ |
1 | /* |
2 | * Copyright (c) 1986, 1988, 1990 Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #ifndef lint | |
35 | static char sccsid[] = "@(#)ns_resp.c 4.65 (Berkeley) 3/3/91"; | |
36 | #endif /* not lint */ | |
37 | ||
38 | #include <sys/param.h> | |
39 | #include <sys/time.h> | |
40 | #include <sys/socket.h> | |
41 | #include <sys/file.h> | |
42 | #include <netinet/in.h> | |
43 | #include <syslog.h> | |
44 | #include <arpa/nameser.h> | |
45 | #include <resolv.h> | |
46 | #include <stdio.h> | |
47 | #include "ns.h" | |
48 | #include "db.h" | |
49 | ||
50 | extern int debug; | |
51 | extern FILE *ddt; | |
52 | extern int errno; | |
53 | extern u_char *dnptrs[]; | |
54 | extern time_t retrytime(); | |
55 | extern struct fwdinfo *fwdtab; | |
56 | extern struct sockaddr_in from_addr; /* Source addr of last packet */ | |
57 | extern int needs_prime_cache; | |
58 | extern int priming; | |
59 | ||
60 | struct qinfo *sysquery(); | |
61 | ||
62 | ns_resp(msg, msglen) | |
63 | u_char *msg; | |
64 | int msglen; | |
65 | { | |
66 | register struct qinfo *qp; | |
67 | register HEADER *hp; | |
68 | register struct qserv *qs; | |
69 | register struct databuf *ns, *ns2; | |
70 | register u_char *cp; | |
71 | struct databuf *nsp[NSMAX], **nspp; | |
72 | int i, c, n, ancount, aucount, nscount, arcount; | |
73 | int type, class, dbflags; | |
74 | int cname = 0; /* flag for processing cname response */ | |
75 | int count, founddata, foundname; | |
76 | int buflen; | |
77 | int newmsglen; | |
78 | char name[MAXDNAME], *dname; | |
79 | char *fname; | |
80 | u_char newmsg[BUFSIZ]; | |
81 | u_char **dpp, *tp; | |
82 | time_t rtrip; | |
83 | ||
84 | struct hashbuf *htp; | |
85 | struct namebuf *np; | |
86 | struct netinfo *lp; | |
87 | extern struct netinfo *local(); | |
88 | extern int nsid; | |
89 | extern int addcount; | |
90 | struct fwdinfo *fwd; | |
91 | ||
92 | #ifdef STATS | |
93 | stats[S_RESPONSES].cnt++; | |
94 | #endif | |
95 | hp = (HEADER *) msg; | |
96 | if ((qp = qfindid(hp->id)) == NULL ) { | |
97 | #ifdef DEBUG | |
98 | if (debug > 1) | |
99 | fprintf(ddt,"DUP? dropped (id %d)\n", ntohs(hp->id)); | |
100 | #endif | |
101 | #ifdef STATS | |
102 | stats[S_DUPRESP].cnt++; | |
103 | #endif | |
104 | return; | |
105 | } | |
106 | ||
107 | #ifdef DEBUG | |
108 | if (debug >= 2) | |
109 | fprintf(ddt,"%s response nsid=%d id=%d\n", | |
110 | qp->q_system ? "SYSTEM" : "USER", | |
111 | ntohs(qp->q_nsid), ntohs(qp->q_id)); | |
112 | #endif | |
113 | ||
114 | /* | |
115 | * Here we handle bad responses from servers. | |
116 | * Several possibilities come to mind: | |
117 | * The server is sick and returns SERVFAIL | |
118 | * The server returns some garbage opcode (its sick) | |
119 | * The server can't understand our query and return FORMERR | |
120 | * In all these cases, we simply drop the packet and force | |
121 | * a retry. This will make him look bad due to unresponsiveness. | |
122 | * Be sure not to include authoritative NXDOMAIN | |
123 | */ | |
124 | if ((hp->rcode != NOERROR && hp->rcode != NXDOMAIN) | |
125 | || (hp->rcode == NXDOMAIN && !hp->aa) | |
126 | || hp->opcode != QUERY) { | |
127 | #ifdef DEBUG | |
128 | if (debug >= 2) | |
129 | fprintf(ddt,"resp: error (ret %d, op %d), dropped\n", | |
130 | hp->rcode, hp->opcode); | |
131 | #endif | |
132 | #ifdef STATS | |
133 | stats[S_BADRESPONSES].cnt++; | |
134 | #endif | |
135 | return; | |
136 | } | |
137 | ||
138 | #ifdef ALLOW_UPDATES | |
139 | if ( (hp->rcode == NOERROR) && | |
140 | (hp->opcode == UPDATEA || hp->opcode == UPDATED || | |
141 | hp->opcode == UPDATEDA || hp->opcode == UPDATEM || | |
142 | hp->opcode == UPDATEMA) ) { | |
143 | /* | |
144 | * Update the secondary's copy, now that the primary | |
145 | * successfully completed the update. Zone doesn't matter | |
146 | * for dyn. update -- doupdate calls findzone to find it | |
147 | */ | |
148 | doupdate(qp->q_msg, qp->q_msglen, qp->q_msg + sizeof(HEADER), | |
149 | 0, (struct databuf *)0, 0); | |
150 | #ifdef DEBUG | |
151 | if (debug >= 3) | |
152 | fprintf(ddt,"resp: leaving, UPDATE*\n"); | |
153 | #endif | |
154 | /* return code filled in by doupdate */ | |
155 | goto return_msg; | |
156 | } | |
157 | #endif ALLOW_UPDATES | |
158 | ||
159 | /* | |
160 | * Determine if the response came from a forwarder. Packets from | |
161 | * anyplace not listed as a forwarder or as a server to whom we | |
162 | * might have forwarded the query will be dropped. | |
163 | */ | |
164 | for (fwd = fwdtab; fwd != (struct fwdinfo *)NULL; fwd = fwd->next) | |
165 | if (bcmp((char *)&fwd->fwdaddr.sin_addr, &from_addr.sin_addr, | |
166 | sizeof(struct in_addr)) == 0) | |
167 | break; | |
168 | /* | |
169 | * If we were using nameservers, find the qinfo pointer and update | |
170 | * the rtt and fact that we have called on this server before. | |
171 | */ | |
172 | if (fwd == (struct fwdinfo *)NULL) { | |
173 | struct timeval *stp; | |
174 | ||
175 | for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++) | |
176 | if (bcmp((char *)&qs->ns_addr.sin_addr, | |
177 | &from_addr.sin_addr, sizeof(struct in_addr)) == 0) | |
178 | break; | |
179 | if (n >= qp->q_naddr) { | |
180 | #ifdef DEBUG | |
181 | if (debug) | |
182 | fprintf(ddt, "Response from unexpected source %s\n", | |
183 | inet_ntoa(from_addr.sin_addr)); | |
184 | #endif DEBUG | |
185 | #ifdef STATS | |
186 | stats[S_MARTIANS].cnt++; | |
187 | #endif | |
188 | /* | |
189 | * We don't know who this response came from so it | |
190 | * gets dropped on the floor. | |
191 | */ | |
192 | return; | |
193 | } | |
194 | stp = &qs->stime; | |
195 | ||
196 | /* Handle response from different (untried) interface */ | |
197 | if (stp->tv_sec == 0) { | |
198 | ns = qs->ns; | |
199 | while (qs > qp->q_addr && | |
200 | (qs->stime.tv_sec == 0 || qs->ns != ns)) | |
201 | qs--; | |
202 | *stp = qs->stime; | |
203 | #ifdef DEBUG | |
204 | if (debug) | |
205 | fprintf(ddt, | |
206 | "Response from unused address %s, assuming %s\n", | |
207 | inet_ntoa(from_addr.sin_addr), | |
208 | inet_ntoa(qs->ns_addr.sin_addr)); | |
209 | #endif DEBUG | |
210 | } | |
211 | ||
212 | /* compute query round trip time */ | |
213 | rtrip = ((tt.tv_sec - stp->tv_sec) * 1000 + | |
214 | (tt.tv_usec - stp->tv_usec) / 1000); | |
215 | ||
216 | #ifdef DEBUG | |
217 | if (debug > 2) | |
218 | fprintf(ddt,"stime %d/%d now %d/%d rtt %d\n", | |
219 | stp->tv_sec, stp->tv_usec, | |
220 | tt.tv_sec, tt.tv_usec, rtrip); | |
221 | #endif | |
222 | /* prevent floating point overflow, limit to 1000 sec */ | |
223 | if (rtrip > 1000000) | |
224 | rtrip = 1000000; | |
225 | ns = qs->nsdata; | |
226 | /* | |
227 | * Don't update nstime if this doesn't look | |
228 | * like an address databuf now. XXX | |
229 | */ | |
230 | if (ns->d_type == T_A && ns->d_class == qs->ns->d_class) { | |
231 | if (ns->d_nstime == 0) | |
232 | ns->d_nstime = (u_long)rtrip; | |
233 | else | |
234 | ns->d_nstime = ns->d_nstime * ALPHA + | |
235 | (1-ALPHA) * (u_long)rtrip; | |
236 | /* prevent floating point overflow, limit to 1000 sec */ | |
237 | if (ns->d_nstime > 1000000) | |
238 | ns->d_nstime = 1000000; | |
239 | } | |
240 | ||
241 | /* | |
242 | * Record the source so that we do not use this NS again. | |
243 | */ | |
244 | if(qp->q_nusedns < NSMAX) { | |
245 | qp->q_usedns[qp->q_nusedns++] = qs->ns; | |
246 | #ifdef DEBUG | |
247 | if(debug > 1) | |
248 | fprintf(ddt, "NS #%d addr %s used, rtt %d\n", | |
249 | n, inet_ntoa(qs->ns_addr.sin_addr), | |
250 | ns->d_nstime); | |
251 | #endif DEBUG | |
252 | } | |
253 | ||
254 | /* | |
255 | * Penalize those who had earlier chances but failed | |
256 | * by multiplying round-trip times by BETA (>1). | |
257 | * Improve nstime for unused addresses by applying GAMMA. | |
258 | * The GAMMA factor makes unused entries slowly | |
259 | * improve, so they eventually get tried again. | |
260 | * GAMMA should be slightly less than 1. | |
261 | * Watch out for records that may have timed out | |
262 | * and are no longer the correct type. XXX | |
263 | */ | |
264 | ||
265 | for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++) { | |
266 | ns2 = qs->nsdata; | |
267 | if (ns2 == ns) | |
268 | continue; | |
269 | if (ns2->d_type != T_A || | |
270 | ns2->d_class != qs->ns->d_class) /* XXX */ | |
271 | continue; | |
272 | if (qs->stime.tv_sec) { | |
273 | if (ns2->d_nstime == 0) | |
274 | ns2->d_nstime = rtrip * BETA; | |
275 | else | |
276 | ns2->d_nstime = | |
277 | ns2->d_nstime * BETA + (1-ALPHA) * rtrip; | |
278 | if (ns2->d_nstime > 1000000) | |
279 | ns2->d_nstime = 1000000; | |
280 | } else | |
281 | ns2->d_nstime = ns2->d_nstime * GAMMA; | |
282 | #ifdef DEBUG | |
283 | if(debug > 1) | |
284 | fprintf(ddt, "NS #%d %s rtt now %d\n", n, | |
285 | inet_ntoa(qs->ns_addr.sin_addr), | |
286 | ns2->d_nstime); | |
287 | #endif DEBUG | |
288 | } | |
289 | } | |
290 | ||
291 | /* | |
292 | * Skip query section | |
293 | */ | |
294 | addcount = 0; | |
295 | cp = msg + sizeof(HEADER); | |
296 | dpp = dnptrs; | |
297 | *dpp++ = msg; | |
298 | if ((*cp & INDIR_MASK) == 0) | |
299 | *dpp++ = cp; | |
300 | *dpp = NULL; | |
301 | if (hp->qdcount) { | |
302 | n = dn_skipname(cp, msg + msglen); | |
303 | if (n <= 0) | |
304 | goto formerr; | |
305 | cp += n; | |
306 | GETSHORT(type, cp); | |
307 | GETSHORT(class, cp); | |
308 | if (cp - msg > msglen) | |
309 | goto formerr; | |
310 | } | |
311 | ||
312 | /* | |
313 | * Save answers, authority, and additional records for future use. | |
314 | */ | |
315 | ancount = ntohs(hp->ancount); | |
316 | aucount = ntohs(hp->nscount); | |
317 | arcount = ntohs(hp->arcount); | |
318 | nscount = 0; | |
319 | tp = cp; | |
320 | #ifdef DEBUG | |
321 | if (debug >= 3) | |
322 | fprintf(ddt,"resp: ancount %d, aucount %d, arcount %d\n", | |
323 | ancount, aucount, arcount); | |
324 | #endif | |
325 | ||
326 | /* | |
327 | * If there's an answer, check if it's a CNAME response; | |
328 | * if no answer but aucount > 0, see if there is an NS | |
329 | * or just an SOA. (NOTE: ancount might be 1 with a CNAME, | |
330 | * and NS records may still be in the authority section; | |
331 | * we don't bother counting them, as we only use nscount | |
332 | * if ancount == 0.) | |
333 | */ | |
334 | if (ancount == 1 || (ancount == 0 && aucount > 0)) { | |
335 | c = aucount; | |
336 | do { | |
337 | if (tp - msg >= msglen) | |
338 | goto formerr; | |
339 | n = dn_skipname(tp, msg + msglen); | |
340 | if (n <= 0) | |
341 | goto formerr; | |
342 | tp += n; /* name */ | |
343 | GETSHORT(i, tp); /* type */ | |
344 | tp += sizeof(u_short); /* class */ | |
345 | tp += sizeof(u_long); /* ttl */ | |
346 | GETSHORT(count, tp); /* dlen */ | |
347 | if (tp - msg > msglen - count) | |
348 | goto formerr; | |
349 | tp += count; | |
350 | if (ancount && i == T_CNAME) { | |
351 | cname++; | |
352 | #ifdef DEBUG | |
353 | if (debug) | |
354 | fprintf(ddt,"CNAME - needs more processing\n"); | |
355 | #endif | |
356 | if (!qp->q_cmsglen) { | |
357 | qp->q_cmsg = qp->q_msg; | |
358 | qp->q_cmsglen = qp->q_msglen; | |
359 | qp->q_msg = NULL; | |
360 | qp->q_msglen = 0; | |
361 | } | |
362 | } | |
363 | /* | |
364 | * See if authority record is a nameserver. | |
365 | */ | |
366 | if (ancount == 0 && i == T_NS) | |
367 | nscount++; | |
368 | } while (--c > 0); | |
369 | tp = cp; | |
370 | } | |
371 | ||
372 | /* | |
373 | * Add the info received in the response to the Data Base | |
374 | */ | |
375 | c = ancount + aucount + arcount; | |
376 | #ifdef notdef | |
377 | /* | |
378 | * If the request was for a CNAME that doesn't exist, | |
379 | * but the name is valid, fetch any other data for the name. | |
380 | * DON'T do this now, as it will requery if data are already | |
381 | * in the cache (maybe later with negative caching). | |
382 | */ | |
383 | if (hp->qdcount && type == T_CNAME && c == 0 && hp->rcode == NOERROR && | |
384 | !qp->q_system) { | |
385 | #ifdef DEBUG | |
386 | if (debug >= 3) | |
387 | fprintf(ddt,"resp: leaving, no CNAME\n"); | |
388 | #endif | |
389 | /* Cause us to put it in the cache later */ | |
390 | prime(class, T_ANY, qp); | |
391 | ||
392 | /* Nothing to store, just give user the answer */ | |
393 | goto return_msg; | |
394 | } | |
395 | #endif /* notdef */ | |
396 | ||
397 | nspp = nsp; | |
398 | if (qp->q_system) | |
399 | dbflags = DB_NOTAUTH | DB_NODATA; | |
400 | else | |
401 | dbflags = DB_NOTAUTH | DB_NODATA | DB_NOHINTS; | |
402 | for (i = 0; i < c; i++) { | |
403 | struct databuf *ns3; | |
404 | ||
405 | if (cp >= msg + msglen) | |
406 | goto formerr; | |
407 | ns3 = 0; | |
408 | if ((n = doupdate(msg, msglen, cp, 0, &ns3, dbflags)) < 0) { | |
409 | #ifdef DEBUG | |
410 | if (debug) | |
411 | fprintf(ddt,"resp: leaving, doupdate failed\n"); | |
412 | #endif | |
413 | /* return code filled in by doupdate */ | |
414 | goto return_msg; | |
415 | } | |
416 | /* | |
417 | * Remember nameservers from the authority section | |
418 | * for referrals. | |
419 | * (This is usually overwritten by findns below(?). XXX | |
420 | */ | |
421 | if (ns3 && i >= ancount && i < ancount + aucount && | |
422 | nspp < &nsp[NSMAX-1]) | |
423 | *nspp++ = ns3; | |
424 | cp += n; | |
425 | } | |
426 | ||
427 | if (qp->q_system && ancount) { | |
428 | if (qp->q_system == PRIMING_CACHE) | |
429 | check_root(); | |
430 | #ifdef DEBUG | |
431 | if (debug > 2) | |
432 | fprintf(ddt,"resp: leaving, SYSQUERY ancount %d\n", ancount); | |
433 | #endif | |
434 | qremove(qp); | |
435 | return; | |
436 | } | |
437 | ||
438 | if (cp > msg + msglen) | |
439 | goto formerr; | |
440 | ||
441 | /* | |
442 | * If there are addresses and this is a local query, | |
443 | * sort them appropriately for the local context. | |
444 | */ | |
445 | if (ancount > 1 && (lp = local(&qp->q_from)) != NULL) | |
446 | sort_response(tp, ancount, lp, msg + msglen); | |
447 | ||
448 | /* | |
449 | * An answer to a T_ANY query or a successful answer to a | |
450 | * regular query with no indirection, then just return answer. | |
451 | */ | |
452 | if ((hp->qdcount && type == T_ANY && ancount) || | |
453 | (!cname && !qp->q_cmsglen && ancount)) { | |
454 | #ifdef DEBUG | |
455 | if (debug >= 3) | |
456 | fprintf(ddt,"resp: got as much answer as there is\n"); | |
457 | #endif | |
458 | goto return_msg; | |
459 | } | |
460 | ||
461 | /* | |
462 | * Eventually we will want to cache this negative answer. | |
463 | */ | |
464 | if (ancount == 0 && nscount == 0 && | |
465 | (hp->aa || fwd || class == C_ANY)) { | |
466 | /* We have an authoritative NO */ | |
467 | #ifdef DEBUG | |
468 | if (debug >= 3) | |
469 | fprintf(ddt,"resp: leaving auth NO\n"); | |
470 | #endif | |
471 | if (qp->q_cmsglen) { | |
472 | msg = (u_char *)qp->q_cmsg; | |
473 | msglen = qp->q_cmsglen; | |
474 | hp = (HEADER *)msg; | |
475 | } | |
476 | goto return_msg; | |
477 | } | |
478 | ||
479 | /* | |
480 | * All messages in here need further processing. i.e. they | |
481 | * are either CNAMEs or we got referred again. | |
482 | */ | |
483 | count = 0; | |
484 | founddata = 0; | |
485 | foundname = 0; | |
486 | dname = name; | |
487 | if (!cname && qp->q_cmsglen && ancount) { | |
488 | #ifdef DEBUG | |
489 | if (debug) | |
490 | fprintf(ddt,"Cname second pass\n"); | |
491 | #endif | |
492 | newmsglen = qp->q_cmsglen; | |
493 | bcopy(qp->q_cmsg, newmsg, newmsglen); | |
494 | } else { | |
495 | newmsglen = msglen; | |
496 | bcopy(msg, newmsg, newmsglen); | |
497 | } | |
498 | hp = (HEADER *) newmsg; | |
499 | hp->ancount = 0; | |
500 | hp->nscount = 0; | |
501 | hp->arcount = 0; | |
502 | dnptrs[0] = newmsg; | |
503 | dnptrs[1] = NULL; | |
504 | cp = newmsg + sizeof(HEADER); | |
505 | if (cname) | |
506 | cp += dn_skipname(cp, newmsg + newmsglen) + QFIXEDSZ; | |
507 | if ((n = dn_expand(newmsg, newmsg + newmsglen, | |
508 | cp, (u_char *)dname, sizeof(name))) < 0) { | |
509 | #ifdef DEBUG | |
510 | if (debug) | |
511 | fprintf(ddt,"dn_expand failed\n" ); | |
512 | #endif | |
513 | goto servfail; | |
514 | } | |
515 | if (!cname) | |
516 | cp += n + QFIXEDSZ; | |
517 | buflen = sizeof(newmsg) - (cp - newmsg); | |
518 | ||
519 | try_again: | |
520 | #ifdef DEBUG | |
521 | if (debug) | |
522 | fprintf(ddt,"resp: nlookup(%s) type=%d\n",dname, type); | |
523 | #endif | |
524 | fname = ""; | |
525 | htp = hashtab; /* lookup relative to root */ | |
526 | np = nlookup(dname, &htp, &fname, 0); | |
527 | #ifdef DEBUG | |
528 | if (debug) | |
529 | fprintf(ddt,"resp: %s '%s' as '%s' (cname=%d)\n", | |
530 | np == NULL ? "missed" : "found", dname, fname, cname); | |
531 | #endif | |
532 | if (np == NULL || fname != dname) | |
533 | goto fetch_ns; | |
534 | ||
535 | foundname++; | |
536 | count = cp - newmsg; | |
537 | n = finddata(np, class, type, hp, &dname, &buflen, &count); | |
538 | if (n == 0) | |
539 | goto fetch_ns; /* NO data available */ | |
540 | cp += n; | |
541 | buflen -= n; | |
542 | hp->ancount += count; | |
543 | if (fname != dname && type != T_CNAME && type != T_ANY) { | |
544 | cname++; | |
545 | goto try_again; | |
546 | } | |
547 | founddata = 1; | |
548 | ||
549 | #ifdef DEBUG | |
550 | if (debug >= 3) { | |
551 | fprintf(ddt,"resp: foundname = %d count = %d ", foundname, count); | |
552 | fprintf(ddt,"founddata = %d cname = %d\n", founddata, cname); | |
553 | } | |
554 | #endif | |
555 | ||
556 | fetch_ns: | |
557 | hp->ancount = htons(hp->ancount); | |
558 | /* | |
559 | * Look for name servers to refer to and fill in the authority | |
560 | * section or record the address for forwarding the query | |
561 | * (recursion desired). | |
562 | */ | |
563 | switch (findns(&np, class, nsp, &count)) { | |
564 | case NXDOMAIN: /* shouldn't happen */ | |
565 | #ifdef DEBUG | |
566 | if (debug >= 3) | |
567 | fprintf(ddt,"req: leaving (%s, rcode %d)\n", | |
568 | dname, hp->rcode); | |
569 | #endif | |
570 | if (!foundname) | |
571 | hp->rcode = NXDOMAIN; | |
572 | if (class != C_ANY) { | |
573 | hp->aa = 1; | |
574 | /* | |
575 | * should return SOA if founddata == 0, | |
576 | * but old named's are confused by an SOA | |
577 | * in the auth. section if there's no error. | |
578 | */ | |
579 | if (foundname == 0 && np) { | |
580 | n = doaddauth(hp, cp, buflen, np, nsp[0]); | |
581 | cp += n; | |
582 | buflen -= n; | |
583 | } | |
584 | } | |
585 | goto return_newmsg; | |
586 | ||
587 | case SERVFAIL: | |
588 | goto servfail; | |
589 | } | |
590 | ||
591 | if (founddata) { | |
592 | hp = (HEADER *)newmsg; | |
593 | n = add_data(np, nsp, cp, buflen); | |
594 | if (n < 0) { | |
595 | hp->tc = 1; | |
596 | n = (-n); | |
597 | } | |
598 | cp += n; | |
599 | buflen -= n; | |
600 | hp->nscount = htons((u_short)count); | |
601 | goto return_newmsg; | |
602 | } | |
603 | ||
604 | /* | |
605 | * If we get here, we don't have the answer yet and are about | |
606 | * to iterate to try and get it. First, infinite loop avoidance. | |
607 | */ | |
608 | if (qp->q_nqueries++ > MAXQUERIES) { | |
609 | #ifdef DEBUG | |
610 | if (debug) | |
611 | fprintf(ddt,"resp: MAXQUERIES exceeded (%s, class %d, type %d)\n", | |
612 | dname, class, type); | |
613 | #endif | |
614 | syslog(LOG_NOTICE, | |
615 | "MAXQUERIES exceeded, possible data loop in resolving (%s)", | |
616 | dname); | |
617 | goto servfail; | |
618 | } | |
619 | ||
620 | /* Reset the query control structure */ | |
621 | qp->q_naddr = 0; | |
622 | qp->q_curaddr = 0; | |
623 | qp->q_fwd = fwdtab; | |
624 | if (nslookup(nsp, qp) == 0) { | |
625 | #ifdef DEBUG | |
626 | if (debug >= 3) | |
627 | fprintf(ddt,"resp: no addrs found for NS's\n"); | |
628 | #endif | |
629 | goto servfail; | |
630 | } | |
631 | for (n = 0; n < qp->q_naddr; n++) | |
632 | qp->q_addr[n].stime.tv_sec = 0; | |
633 | if (!qp->q_fwd) | |
634 | qp->q_addr[0].stime = tt; | |
635 | if (cname) { | |
636 | if (qp->q_cname++ == MAXCNAMES) { | |
637 | #ifdef DEBUG | |
638 | if (debug >= 3) | |
639 | fprintf(ddt,"resp: leaving, MAXCNAMES exceeded\n"); | |
640 | #endif | |
641 | goto servfail; | |
642 | } | |
643 | #ifdef DEBUG | |
644 | if (debug) | |
645 | fprintf(ddt,"q_cname = %d\n",qp->q_cname); | |
646 | if (debug >= 3) | |
647 | fprintf(ddt,"resp: building recursive query; nslookup\n"); | |
648 | #endif | |
649 | if (qp->q_msg) | |
650 | (void) free(qp->q_msg); | |
651 | if ((qp->q_msg = malloc(BUFSIZ)) == NULL) { | |
652 | #ifdef DEBUG | |
653 | if (debug) | |
654 | fprintf(ddt,"resp: malloc error\n"); | |
655 | #endif | |
656 | goto servfail; | |
657 | } | |
658 | qp->q_msglen = res_mkquery(QUERY, dname, class, | |
659 | type, (char *)NULL, 0, NULL, qp->q_msg, BUFSIZ); | |
660 | hp = (HEADER *) qp->q_msg; | |
661 | hp->rd = 0; | |
662 | } else | |
663 | hp = (HEADER *)qp->q_msg; | |
664 | hp->id = qp->q_nsid = htons((u_short)++nsid); | |
665 | if (qp->q_fwd) | |
666 | hp->rd = 1; | |
667 | unsched(qp); | |
668 | schedretry(qp, retrytime(qp)); | |
669 | #ifdef DEBUG | |
670 | if (debug) | |
671 | fprintf(ddt,"resp: forw -> %s %d (%d) nsid=%d id=%d %dms\n", | |
672 | inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr), | |
673 | ds, ntohs(Q_NEXTADDR(qp,0)->sin_port), | |
674 | ntohs(qp->q_nsid), ntohs(qp->q_id), | |
675 | qp->q_addr[0].nsdata->d_nstime); | |
676 | if ( debug >= 10) | |
677 | fp_query((char *)msg, ddt); | |
678 | #endif | |
679 | if (sendto(ds, qp->q_msg, qp->q_msglen, 0, | |
680 | (struct sockaddr *)Q_NEXTADDR(qp,0), | |
681 | sizeof(struct sockaddr_in)) < 0) { | |
682 | #ifdef DEBUG | |
683 | if (debug >= 5) | |
684 | fprintf(ddt, "sendto error = %d\n", errno); | |
685 | #endif | |
686 | } | |
687 | hp->rd = 0; /* leave set to 0 for dup detection */ | |
688 | #ifdef STATS | |
689 | stats[S_OUTPKTS].cnt++; | |
690 | #endif | |
691 | #ifdef DEBUG | |
692 | if (debug >= 3) | |
693 | fprintf(ddt,"resp: Query sent.\n"); | |
694 | #endif | |
695 | return; | |
696 | ||
697 | formerr: | |
698 | #ifdef DEBUG | |
699 | if (debug) | |
700 | fprintf(ddt,"FORMERR resp() from %s size err %d, msglen %d\n", | |
701 | inet_ntoa(from_addr.sin_addr), | |
702 | cp-msg, msglen); | |
703 | #endif | |
704 | syslog(LOG_INFO, "Malformed response from %s\n", | |
705 | inet_ntoa(from_addr.sin_addr)); | |
706 | #ifdef STATS | |
707 | stats[S_RESPFORMERR].cnt++; | |
708 | #endif | |
709 | return; | |
710 | ||
711 | return_msg: | |
712 | #ifdef STATS | |
713 | stats[S_RESPOK].cnt++; | |
714 | #endif | |
715 | /* The "standard" return code */ | |
716 | hp->qr = 1; | |
717 | hp->id = qp->q_id; | |
718 | hp->rd = 1; | |
719 | hp->ra = 1; | |
720 | (void) send_msg(msg, msglen, qp); | |
721 | qremove(qp); | |
722 | return; | |
723 | ||
724 | return_newmsg: | |
725 | #ifdef STATS | |
726 | stats[S_RESPOK].cnt++; | |
727 | #endif | |
728 | if (addcount) { | |
729 | n = doaddinfo(hp, cp, buflen); | |
730 | cp += n; | |
731 | buflen -= n; | |
732 | } | |
733 | ||
734 | hp->id = qp->q_id; | |
735 | hp->rd = 1; | |
736 | hp->ra = 1; | |
737 | hp->qr = 1; | |
738 | (void) send_msg(newmsg, cp - newmsg, qp); | |
739 | qremove(qp); | |
740 | return; | |
741 | ||
742 | servfail: | |
743 | #ifdef STATS | |
744 | stats[S_RESPFAIL].cnt++; | |
745 | #endif | |
746 | hp = (HEADER *)(cname ? qp->q_cmsg : qp->q_msg); | |
747 | hp->rcode = SERVFAIL; | |
748 | hp->id = qp->q_id; | |
749 | hp->rd = 1; | |
750 | hp->ra = 1; | |
751 | hp->qr = 1; | |
752 | (void) send_msg((char *)hp, (cname ? qp->q_cmsglen : qp->q_msglen), qp); | |
753 | qremove(qp); | |
754 | return; | |
755 | } | |
756 | ||
757 | /* | |
758 | * Decode the resource record 'rrp' and update the database. | |
759 | * If savens is true, record pointer for forwarding queries a second time. | |
760 | */ | |
761 | doupdate(msg, msglen, rrp, zone, savens, flags) | |
762 | char *msg; | |
763 | u_char *rrp; | |
764 | struct databuf **savens; | |
765 | int msglen, zone, flags; | |
766 | { | |
767 | register u_char *cp; | |
768 | register int n; | |
769 | int class, type, dlen, n1; | |
770 | u_long ttl; | |
771 | struct databuf *dp; | |
772 | char dname[MAXDNAME]; | |
773 | u_char *cp1; | |
774 | u_char data[BUFSIZ]; | |
775 | register HEADER *hp = (HEADER *) msg; | |
776 | #ifdef ALLOW_UPDATES | |
777 | int zonenum; | |
778 | #endif | |
779 | ||
780 | #ifdef DEBUG | |
781 | if (debug > 2) | |
782 | fprintf(ddt,"doupdate(zone %d, savens %x, flags %x)\n", | |
783 | zone, savens, flags); | |
784 | #endif | |
785 | ||
786 | cp = rrp; | |
787 | if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen, cp, | |
788 | (u_char *)dname, sizeof(dname))) < 0) { | |
789 | hp->rcode = FORMERR; | |
790 | return (-1); | |
791 | } | |
792 | cp += n; | |
793 | GETSHORT(type, cp); | |
794 | GETSHORT(class, cp); | |
795 | GETLONG(ttl, cp); | |
796 | GETSHORT(dlen, cp); | |
797 | #ifdef DEBUG | |
798 | if (debug > 2) | |
799 | fprintf(ddt,"doupdate: dname %s type %d class %d ttl %d\n", | |
800 | dname, type, class, ttl); | |
801 | #endif | |
802 | /* | |
803 | * Convert the resource record data into the internal | |
804 | * database format. | |
805 | */ | |
806 | switch (type) { | |
807 | case T_A: | |
808 | case T_WKS: | |
809 | case T_HINFO: | |
810 | case T_UINFO: | |
811 | case T_UID: | |
812 | case T_GID: | |
813 | case T_TXT: | |
814 | #ifdef ALLOW_T_UNSPEC | |
815 | case T_UNSPEC: | |
816 | #endif ALLOW_T_UNSPEC | |
817 | cp1 = cp; | |
818 | n = dlen; | |
819 | cp += n; | |
820 | break; | |
821 | ||
822 | case T_CNAME: | |
823 | case T_MB: | |
824 | case T_MG: | |
825 | case T_MR: | |
826 | case T_NS: | |
827 | case T_PTR: | |
828 | if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen, | |
829 | cp, data, sizeof(data))) < 0) { | |
830 | hp->rcode = FORMERR; | |
831 | return (-1); | |
832 | } | |
833 | cp += n; | |
834 | cp1 = data; | |
835 | n = strlen((char *)data) + 1; | |
836 | break; | |
837 | ||
838 | case T_MINFO: | |
839 | case T_SOA: | |
840 | if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen, | |
841 | cp, data, sizeof(data))) < 0) { | |
842 | hp->rcode = FORMERR; | |
843 | return (-1); | |
844 | } | |
845 | cp += n; | |
846 | cp1 = data + (n = strlen((char *)data) + 1); | |
847 | n1 = sizeof(data) - n; | |
848 | if (type == T_SOA) | |
849 | n1 -= 5 * sizeof(u_long); | |
850 | if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen, | |
851 | cp, cp1, n1)) < 0) { | |
852 | hp->rcode = FORMERR; | |
853 | return (-1); | |
854 | } | |
855 | cp += n; | |
856 | cp1 += strlen((char *)cp1) + 1; | |
857 | if (type == T_SOA) { | |
858 | bcopy(cp, cp1, n = 5 * sizeof(u_long)); | |
859 | cp += n; | |
860 | cp1 += n; | |
861 | } | |
862 | n = cp1 - data; | |
863 | cp1 = data; | |
864 | break; | |
865 | ||
866 | case T_MX: | |
867 | /* grab preference */ | |
868 | bcopy(cp,data,sizeof(u_short)); | |
869 | cp1 = data + sizeof(u_short); | |
870 | cp += sizeof(u_short); | |
871 | ||
872 | /* get name */ | |
873 | if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen, | |
874 | cp, cp1, sizeof(data) - sizeof(u_short))) < 0) | |
875 | return(-1); | |
876 | cp += n; | |
877 | ||
878 | /* compute end of data */ | |
879 | cp1 += strlen((char *)cp1) + 1; | |
880 | /* compute size of data */ | |
881 | n = cp1 - data; | |
882 | cp1 = data; | |
883 | break; | |
884 | ||
885 | default: | |
886 | #ifdef DEBUG | |
887 | if (debug >= 3) | |
888 | fprintf(ddt,"unknown type %d\n", type); | |
889 | #endif | |
890 | return ((cp - rrp) + dlen); | |
891 | } | |
892 | if (n > MAXDATA) { | |
893 | #ifdef DEBUG | |
894 | if (debug) | |
895 | fprintf(ddt, | |
896 | "update type %d: %d bytes is too much data\n", | |
897 | type, n); | |
898 | #endif | |
899 | hp->rcode = NOCHANGE; /* XXX - FORMERR ??? */ | |
900 | return(-1); | |
901 | } | |
902 | ||
903 | #ifdef ALLOW_UPDATES | |
904 | /* | |
905 | * If this is a dynamic update request, process it specially; else, | |
906 | * execute normal update code. | |
907 | */ | |
908 | switch(hp->opcode) { | |
909 | ||
910 | /* For UPDATEM and UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA */ | |
911 | case UPDATEM: | |
912 | case UPDATEMA: | |
913 | ||
914 | /* | |
915 | * The named code for UPDATED and UPDATEDA is the same except that for | |
916 | * UPDATEDA we we ignore any data that was passed: we just delete all | |
917 | * RRs whose name, type, and class matches | |
918 | */ | |
919 | case UPDATED: | |
920 | case UPDATEDA: | |
921 | if (type == T_SOA) { /* Not allowed */ | |
922 | #ifdef DEBUG | |
923 | if (debug) | |
924 | fprintf(ddt, "UDPATE: REFUSED - SOA delete\n"); | |
925 | #endif | |
926 | hp->rcode = REFUSED; | |
927 | return(-1); | |
928 | } | |
929 | /* | |
930 | * Don't check message length if doing UPDATEM/UPDATEMA, | |
931 | * since the whole message wont have been demarshalled until | |
932 | * we reach the code for UPDATEA | |
933 | */ | |
934 | if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEDA) ) { | |
935 | if (cp != (u_char *)(msg + msglen)) { | |
936 | #ifdef DEBUG | |
937 | if (debug) | |
938 | fprintf(ddt,"FORMERR UPDATE message length off\n"); | |
939 | #endif | |
940 | hp->rcode = FORMERR; | |
941 | return(-1); | |
942 | } | |
943 | } | |
944 | if ((zonenum = findzone(dname, class)) == 0) { | |
945 | hp->rcode = NXDOMAIN; | |
946 | return(-1); | |
947 | } | |
948 | if (zones[zonenum].z_state & Z_DYNADDONLY) { | |
949 | hp->rcode = NXDOMAIN; | |
950 | return(-1); | |
951 | } | |
952 | if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEM) ) { | |
953 | /* Make a dp for use in db_update, as old dp */ | |
954 | dp = savedata(class, type, 0, cp1, n); | |
955 | dp->d_zone = zonenum; | |
956 | n = db_update(dname, dp, NULL, DB_MEXIST | DB_DELETE, | |
957 | hashtab); | |
958 | if (n != OK) { | |
959 | #ifdef DEBUG | |
960 | if (debug) | |
961 | fprintf(ddt,"UPDATE: db_update failed\n"); | |
962 | #endif DEBUG | |
963 | free( (struct databuf *) dp); | |
964 | hp->rcode = NOCHANGE; | |
965 | return(-1); | |
966 | } | |
967 | } else { /* UPDATEDA or UPDATEMA */ | |
968 | int DeletedOne = 0; | |
969 | /* Make a dp for use in db_update, as old dp */ | |
970 | dp = savedata(class, type, 0, NULL, 0); | |
971 | dp->d_zone = zonenum; | |
972 | do { /* Loop and delete all matching RR(s) */ | |
973 | n = db_update(dname, dp, NULL, DB_DELETE, | |
974 | hashtab); | |
975 | if (n != OK) | |
976 | break; | |
977 | DeletedOne++; | |
978 | } while (1); | |
979 | free( (struct databuf *) dp); | |
980 | /* Ok for UPDATEMA not to have deleted any RRs */ | |
981 | if (!DeletedOne && hp->opcode == UPDATEDA) { | |
982 | #ifdef DEBUG | |
983 | if (debug) | |
984 | fprintf(ddt,"UPDATE: db_update failed\n"); | |
985 | #endif DEBUG | |
986 | hp->rcode = NOCHANGE; | |
987 | return(-1); | |
988 | } | |
989 | } | |
990 | if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEDA) ) | |
991 | return (cp - rrp);; | |
992 | /* | |
993 | * Else unmarshal the RR to be added and continue on to | |
994 | * UPDATEA code for UPDATEM/UPDATEMA | |
995 | */ | |
996 | if ((n = | |
997 | dn_expand(msg, msg+msglen, cp, dname, sizeof(dname))) < 0) { | |
998 | #ifdef DEBUG | |
999 | if (debug) | |
1000 | fprintf(ddt,"FORMERR UPDATE expand name failed\n"); | |
1001 | #endif | |
1002 | hp->rcode = FORMERR; | |
1003 | return(-1); | |
1004 | } | |
1005 | cp += n; | |
1006 | GETSHORT(type, cp); | |
1007 | GETSHORT(class, cp); | |
1008 | GETLONG(ttl, cp); | |
1009 | GETSHORT(n, cp); | |
1010 | cp1 = cp; | |
1011 | /**** XXX - need bounds checking here ****/ | |
1012 | cp += n; | |
1013 | ||
1014 | case UPDATEA: | |
1015 | if (n > MAXDATA) { | |
1016 | #ifdef DEBUG | |
1017 | if (debug) | |
1018 | fprintf(ddt,"UPDATE: too much data\n"); | |
1019 | #endif | |
1020 | hp->rcode = NOCHANGE; | |
1021 | return(-1); | |
1022 | } | |
1023 | if (cp != (u_char *)(msg + msglen)) { | |
1024 | #ifdef DEBUG | |
1025 | if (debug) | |
1026 | fprintf(ddt,"FORMERR UPDATE message length off\n"); | |
1027 | #endif | |
1028 | hp->rcode = FORMERR; | |
1029 | return(-1); | |
1030 | } | |
1031 | if ((zonenum = findzone(dname, class)) == 0) { | |
1032 | hp->rcode = NXDOMAIN; | |
1033 | return(-1); | |
1034 | } | |
1035 | if (zones[zonenum].z_state & Z_DYNADDONLY) { | |
1036 | struct hashbuf *htp = hashtab; | |
1037 | char *fname; | |
1038 | if (nlookup(dname, &htp, &fname, 0) && | |
1039 | !strcmp(dname, fname)) { | |
1040 | #ifdef DEBUG | |
1041 | if (debug) | |
1042 | fprintf(ddt,"refusing add of existing name\n"); | |
1043 | #endif | |
1044 | hp->rcode = REFUSED; | |
1045 | return(-1); | |
1046 | } | |
1047 | } | |
1048 | dp = savedata(class, type, ttl, cp1, n); | |
1049 | dp->d_zone = zonenum; | |
1050 | if ((n = db_update(dname, NULL, dp, DB_NODATA, | |
1051 | hashtab)) != OK) { | |
1052 | #ifdef DEBUG | |
1053 | if (debug) | |
1054 | fprintf(ddt,"UPDATE: db_update failed\n"); | |
1055 | #endif | |
1056 | hp->rcode = NOCHANGE; | |
1057 | return (-1); | |
1058 | } | |
1059 | else | |
1060 | return (cp - rrp); | |
1061 | } | |
1062 | #endif ALLOW_UPDATES | |
1063 | ||
1064 | if (zone == 0) | |
1065 | ttl += tt.tv_sec; | |
1066 | dp = savedata(class, type, ttl, cp1, n); | |
1067 | dp->d_zone = zone; | |
1068 | if ((n = db_update(dname, dp, dp, flags, hashtab)) < 0) { | |
1069 | #ifdef DEBUG | |
1070 | if (debug && (n != DATAEXISTS)) | |
1071 | fprintf(ddt,"update failed (%d)\n", n); | |
1072 | else if (debug >= 3) | |
1073 | fprintf(ddt,"update failed (DATAEXISTS)\n"); | |
1074 | #endif | |
1075 | (void) free((char *)dp); | |
1076 | } else if (type == T_NS && savens != NULL) | |
1077 | *savens = dp; | |
1078 | return (cp - rrp); | |
1079 | } | |
1080 | ||
1081 | send_msg(msg, msglen, qp) | |
1082 | char *msg; | |
1083 | int msglen; | |
1084 | struct qinfo *qp; | |
1085 | { | |
1086 | extern struct qinfo *qhead; | |
1087 | #ifdef DEBUG | |
1088 | struct qinfo *tqp; | |
1089 | #endif DEBUG | |
1090 | ||
1091 | if (qp->q_system) | |
1092 | return(1); | |
1093 | #ifdef DEBUG | |
1094 | if (debug) { | |
1095 | fprintf(ddt,"send_msg -> %s (%s %d %d) id=%d\n", | |
1096 | inet_ntoa(qp->q_from.sin_addr), | |
1097 | qp->q_stream == QSTREAM_NULL ? "UDP" : "TCP", | |
1098 | qp->q_stream == QSTREAM_NULL ? qp->q_dfd | |
1099 | : qp->q_stream->s_rfd, | |
1100 | ntohs(qp->q_from.sin_port), | |
1101 | ntohs(qp->q_id)); | |
1102 | } | |
1103 | if (debug>4) | |
1104 | for (tqp = qhead; tqp!=QINFO_NULL; tqp = tqp->q_link) { | |
1105 | fprintf(ddt, "qp %x q_id: %d q_nsid: %d q_msglen: %d ", | |
1106 | tqp, tqp->q_id,tqp->q_nsid,tqp->q_msglen); | |
1107 | fprintf(ddt,"q_naddr: %d q_curaddr: %d\n", tqp->q_naddr, | |
1108 | tqp->q_curaddr); | |
1109 | fprintf(ddt,"q_next: %x q_link: %x\n", qp->q_next, | |
1110 | qp->q_link); | |
1111 | } | |
1112 | if (debug >= 10) | |
1113 | fp_query(msg, ddt); | |
1114 | #endif DEBUG | |
1115 | if (qp->q_stream == QSTREAM_NULL) { | |
1116 | if (sendto(qp->q_dfd, msg, msglen, 0, | |
1117 | (struct sockaddr *)&qp->q_from, sizeof(qp->q_from)) < 0) { | |
1118 | #ifdef DEBUG | |
1119 | if (debug) | |
1120 | fprintf(ddt, "sendto error errno= %d\n",errno); | |
1121 | #endif | |
1122 | return(1); | |
1123 | } | |
1124 | #ifdef STATS | |
1125 | stats[S_OUTPKTS].cnt++; | |
1126 | #endif | |
1127 | } else { | |
1128 | (void) writemsg(qp->q_stream->s_rfd, msg, msglen); | |
1129 | sq_done(qp->q_stream); | |
1130 | } | |
1131 | return(0); | |
1132 | } | |
1133 | ||
1134 | prime(class, type, oqp) | |
1135 | int class, type; | |
1136 | register struct qinfo *oqp; | |
1137 | { | |
1138 | char dname[BUFSIZ]; | |
1139 | ||
1140 | if (oqp->q_msg == NULL) | |
1141 | return; | |
1142 | if (dn_expand((u_char *)oqp->q_msg, | |
1143 | (u_char *)oqp->q_msg + oqp->q_msglen, | |
1144 | (u_char *)oqp->q_msg + sizeof(HEADER), (u_char *)dname, | |
1145 | sizeof(dname)) < 0) | |
1146 | return; | |
1147 | #ifdef DEBUG | |
1148 | if (debug >= 2) | |
1149 | fprintf(ddt,"prime: %s\n", dname); | |
1150 | #endif | |
1151 | (void) sysquery(dname, class, type); | |
1152 | } | |
1153 | ||
1154 | ||
1155 | prime_cache() | |
1156 | { | |
1157 | register struct qinfo *qp; | |
1158 | ||
1159 | #ifdef DEBUG | |
1160 | if (debug) | |
1161 | fprintf(ddt,"prime_cache: priming = %d\n", priming); | |
1162 | #endif | |
1163 | #ifdef STATS | |
1164 | stats[S_PRIMECACHE].cnt++; | |
1165 | #endif | |
1166 | if (!priming && fcachetab->h_tab[0] != NULL && !forward_only) { | |
1167 | priming++; | |
1168 | if ((qp = sysquery("", C_IN, T_NS)) == NULL) | |
1169 | priming = 0; | |
1170 | else | |
1171 | qp->q_system = PRIMING_CACHE; | |
1172 | } | |
1173 | needs_prime_cache = 0; | |
1174 | return; | |
1175 | } | |
1176 | ||
1177 | struct qinfo * | |
1178 | sysquery(dname, class, type) | |
1179 | char *dname; | |
1180 | int class, type; | |
1181 | { | |
1182 | extern struct qinfo *qhead; | |
1183 | extern int nsid; | |
1184 | register struct qinfo *qp, *oqp; | |
1185 | register HEADER *hp; | |
1186 | struct namebuf *np; | |
1187 | struct databuf *nsp[NSMAX]; | |
1188 | struct hashbuf *htp; | |
1189 | char *fname; | |
1190 | int count; | |
1191 | ||
1192 | #ifdef DEBUG | |
1193 | if (debug > 2) | |
1194 | fprintf(ddt,"sysquery(%s, %d, %d)\n", dname, class, type); | |
1195 | #endif | |
1196 | #ifdef STATS | |
1197 | stats[S_SYSQUERIES].cnt++; | |
1198 | #endif | |
1199 | htp = hashtab; | |
1200 | if (priming && dname[0] == '\0') | |
1201 | np = NULL; | |
1202 | else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) { | |
1203 | #ifdef DEBUG | |
1204 | if (debug) | |
1205 | fprintf(ddt,"sysquery: nlookup error on %s?\n", dname); | |
1206 | #endif | |
1207 | return(0); | |
1208 | } | |
1209 | ||
1210 | switch (findns(&np, class, nsp, &count)) { | |
1211 | case NXDOMAIN: | |
1212 | case SERVFAIL: | |
1213 | #ifdef DEBUG | |
1214 | if (debug) | |
1215 | fprintf(ddt,"sysquery: findns error on %s?\n", dname); | |
1216 | #endif | |
1217 | return(0); | |
1218 | } | |
1219 | ||
1220 | /* build new qinfo struct */ | |
1221 | qp = qnew(); | |
1222 | qp->q_cmsg = qp->q_msg = NULL; | |
1223 | qp->q_dfd = ds; | |
1224 | qp->q_fwd = fwdtab; | |
1225 | qp->q_system++; | |
1226 | ||
1227 | if ((qp->q_msg = malloc(BUFSIZ)) == NULL) { | |
1228 | qfree(qp); | |
1229 | return(0); | |
1230 | } | |
1231 | qp->q_msglen = res_mkquery(QUERY, dname, class, | |
1232 | type, (char *)NULL, 0, NULL, qp->q_msg, BUFSIZ); | |
1233 | hp = (HEADER *) qp->q_msg; | |
1234 | hp->id = qp->q_nsid = htons((u_short)++nsid); | |
1235 | hp->rd = (qp->q_fwd ? 1 : 0); | |
1236 | ||
1237 | /* First check for an already pending query for this data */ | |
1238 | for (oqp = qhead; oqp!=QINFO_NULL; oqp = oqp->q_link) { | |
1239 | if (oqp != qp && oqp->q_msglen == qp->q_msglen && | |
1240 | bcmp((char *)oqp->q_msg+2, qp->q_msg+2, qp->q_msglen-2) == 0) { | |
1241 | #ifdef DEBUG | |
1242 | if (debug >= 3) | |
1243 | fprintf(ddt, "sysquery: duplicate\n"); | |
1244 | #endif | |
1245 | qfree(qp); | |
1246 | return(0); | |
1247 | } | |
1248 | } | |
1249 | ||
1250 | if (nslookup(nsp, qp) == 0) { | |
1251 | #ifdef DEBUG | |
1252 | if (debug) | |
1253 | fprintf(ddt,"resp: no addrs found for NS's\n"); | |
1254 | #endif | |
1255 | qfree(qp); | |
1256 | return(0); | |
1257 | } | |
1258 | ||
1259 | schedretry(qp, retrytime(qp)); | |
1260 | if (qp->q_fwd == 0) | |
1261 | qp->q_addr[0].stime = tt; | |
1262 | ||
1263 | #ifdef DEBUG | |
1264 | if (debug) | |
1265 | fprintf(ddt,"sysquery: send -> %s %d (%d), nsid=%d id=%d %dms\n", | |
1266 | inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr), | |
1267 | qp->q_dfd, ntohs(Q_NEXTADDR(qp,0)->sin_port), | |
1268 | ntohs(qp->q_nsid), ntohs(qp->q_id), | |
1269 | qp->q_addr[0].nsdata->d_nstime); | |
1270 | if ( debug >= 10) | |
1271 | fp_query(qp->q_msg, ddt); | |
1272 | #endif | |
1273 | if (sendto(qp->q_dfd, qp->q_msg, qp->q_msglen, 0, | |
1274 | (struct sockaddr *)Q_NEXTADDR(qp,0), | |
1275 | sizeof(struct sockaddr_in)) < 0){ | |
1276 | #ifdef DEBUG | |
1277 | if (debug) | |
1278 | fprintf(ddt, "sendto error errno= %d\n",errno); | |
1279 | #endif | |
1280 | } | |
1281 | #ifdef STATS | |
1282 | stats[S_OUTPKTS].cnt++; | |
1283 | #endif | |
1284 | return(qp); | |
1285 | } | |
1286 | ||
1287 | /* | |
1288 | * Check the list of root servers after receiving a response | |
1289 | * to a query for the root servers. | |
1290 | */ | |
1291 | check_root() | |
1292 | { | |
1293 | register struct databuf *dp, *pdp; | |
1294 | register struct namebuf *np; | |
1295 | int count = 0; | |
1296 | ||
1297 | priming = 0; | |
1298 | for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next) | |
1299 | if (np->n_dname[0] == '\0') | |
1300 | break; | |
1301 | if (np == NULL) { | |
1302 | syslog(LOG_ERR, "check_root: Can't find root!\n"); | |
1303 | return; | |
1304 | } | |
1305 | for (dp = np->n_data; dp != NULL; dp = dp->d_next) | |
1306 | if (dp->d_type == T_NS) | |
1307 | count++; | |
1308 | #ifdef DEBUG | |
1309 | if (debug) | |
1310 | fprintf(ddt,"%d root servers\n", count); | |
1311 | #endif | |
1312 | if (count < MINROOTS) { | |
1313 | syslog(LOG_WARNING, | |
1314 | "check_root: %d root servers after query to root server < min", | |
1315 | count); | |
1316 | return; | |
1317 | } | |
1318 | pdp = NULL; | |
1319 | dp = np->n_data; | |
1320 | while (dp != NULL) { | |
1321 | if (dp->d_type == T_NS && dp->d_zone == 0 && | |
1322 | dp->d_ttl < tt.tv_sec) { | |
1323 | #ifdef DEBUG | |
1324 | if (debug) | |
1325 | fprintf(ddt,"deleting old root server '%s'\n", | |
1326 | dp->d_data); | |
1327 | #endif | |
1328 | dp = rm_datum(dp, np, pdp); | |
1329 | /* SHOULD DELETE FROM HINTS ALSO */ | |
1330 | continue; | |
1331 | } | |
1332 | pdp = dp; | |
1333 | dp = dp->d_next; | |
1334 | } | |
1335 | check_ns(); | |
1336 | } | |
1337 | ||
1338 | /* | |
1339 | * Check the root to make sure that for each NS record we have a A RR | |
1340 | */ | |
1341 | check_ns() | |
1342 | { | |
1343 | register struct databuf *dp, *tdp; | |
1344 | register struct namebuf *np, *tnp; | |
1345 | struct hashbuf *htp; | |
1346 | char *dname; | |
1347 | int found_arr; | |
1348 | char *fname; | |
1349 | time_t curtime; | |
1350 | ||
1351 | #ifdef DEBUG | |
1352 | if (debug >= 2) | |
1353 | fprintf(ddt,"check_ns()\n"); | |
1354 | #endif | |
1355 | #ifdef STATS | |
1356 | stats[S_CHECKNS].cnt++; | |
1357 | #endif | |
1358 | ||
1359 | curtime = (u_long) tt.tv_sec; | |
1360 | for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next) { | |
1361 | if (np->n_dname[0] != 0) | |
1362 | continue; | |
1363 | for (dp = np->n_data; dp != NULL; dp = dp->d_next) { | |
1364 | if (dp->d_type != T_NS) | |
1365 | continue; | |
1366 | ||
1367 | /* look for A records */ | |
1368 | dname = dp->d_data; | |
1369 | htp = hashtab; | |
1370 | tnp = nlookup(dname, &htp, &fname, 0); | |
1371 | if (tnp == NULL || fname != dname) { | |
1372 | #ifdef DEBUG | |
1373 | if (debug >= 3) | |
1374 | fprintf(ddt,"check_ns: %s: not found %s %x\n", | |
1375 | dname, fname, tnp); | |
1376 | #endif | |
1377 | (void) sysquery(dname, dp->d_class, T_A); | |
1378 | continue; | |
1379 | } | |
1380 | /* look for name server addresses */ | |
1381 | found_arr = 0; | |
1382 | for (tdp=tnp->n_data; tdp!=NULL; tdp=tdp->d_next) { | |
1383 | if (tdp->d_type != T_A || | |
1384 | tdp->d_class != dp->d_class) | |
1385 | continue; | |
1386 | if ((tdp->d_zone == 0) && | |
1387 | (tdp->d_ttl < curtime)) { | |
1388 | #ifdef DEBUG | |
1389 | if (debug >= 3) | |
1390 | fprintf(ddt,"check_ns: stale entry '%s'\n", | |
1391 | tnp->n_dname); | |
1392 | #endif | |
1393 | /* Cache invalidate the address RR's */ | |
1394 | delete_all(tnp, dp->d_class, T_A); | |
1395 | found_arr = 0; | |
1396 | break; | |
1397 | } | |
1398 | found_arr++; | |
1399 | } | |
1400 | if (!found_arr) | |
1401 | (void) sysquery(dname, dp->d_class, T_A); | |
1402 | } | |
1403 | } | |
1404 | } | |
1405 | ||
1406 | #define MAXCLASS 255 /* belongs elsewhere */ | |
1407 | int norootlogged[MAXCLASS]; | |
1408 | ||
1409 | /* | |
1410 | * Find NS's or an SOA for the given dname (np) and fill in the | |
1411 | * nsp array. Returns OK on success, and SERVFAIL on error. | |
1412 | * We return NXDOMAIN to indicate we are authoritative. | |
1413 | */ | |
1414 | findns(npp, class, nsp, countp) | |
1415 | register struct namebuf **npp; | |
1416 | struct databuf **nsp; | |
1417 | int *countp; | |
1418 | { | |
1419 | register struct namebuf *np = *npp; | |
1420 | register struct databuf *dp; | |
1421 | register struct databuf **nspp; | |
1422 | struct hashbuf *htp = hashtab; | |
1423 | ||
1424 | if (priming && (np == NULL || np->n_dname[0] == '\0')) | |
1425 | htp = fcachetab; | |
1426 | try_again: | |
1427 | if (htp == fcachetab) | |
1428 | needs_prime_cache = 1; | |
1429 | while (np == NULL && htp != NULL) { | |
1430 | #ifdef DEBUG | |
1431 | if (debug > 2) | |
1432 | fprintf(ddt, "findns: using %s\n", htp == hashtab ? | |
1433 | "cache" : "hints"); | |
1434 | #endif | |
1435 | for (np = htp->h_tab[0]; np != NULL; np = np->n_next) | |
1436 | if (np->n_dname[0] == '\0') | |
1437 | break; | |
1438 | htp = (htp == hashtab ? fcachetab : NULL); /* Fallback */ | |
1439 | } | |
1440 | while(np != NULL) { | |
1441 | #ifdef DEBUG | |
1442 | if (debug >= 5) | |
1443 | fprintf(ddt, "findns: np 0x%x\n", np); | |
1444 | #endif | |
1445 | /* Look first for SOA records. */ | |
1446 | for (dp = np->n_data; dp != NULL; dp = dp->d_next) { | |
1447 | if (dp->d_zone != 0 && match(dp, class, T_SOA)) { | |
1448 | #ifdef DEBUG | |
1449 | if (debug >= 3) | |
1450 | fprintf(ddt,"findns: SOA found\n"); | |
1451 | #endif | |
1452 | if (zones[dp->d_zone].z_auth) { | |
1453 | *npp = np; | |
1454 | nsp[0] = dp; | |
1455 | return(NXDOMAIN); | |
1456 | } else | |
1457 | return (SERVFAIL); | |
1458 | } | |
1459 | } | |
1460 | ||
1461 | /* If no SOA records, look for NS records. */ | |
1462 | nspp = &nsp[0]; | |
1463 | *nspp = NULL; | |
1464 | for (dp = np->n_data; dp != NULL; dp = dp->d_next) { | |
1465 | if (dp->d_type != T_NS || | |
1466 | (dp->d_class != class && class != C_ANY)) | |
1467 | continue; | |
1468 | /* | |
1469 | * Don't use records that may become invalid to | |
1470 | * reference later when we do the rtt computation. | |
1471 | * Never delete our safety-belt information! | |
1472 | */ | |
1473 | if ((dp->d_zone == 0) && | |
1474 | (dp->d_ttl < (tt.tv_sec+900)) && | |
1475 | !(dp->d_flags & DB_F_HINT)) { | |
1476 | #ifdef DEBUG | |
1477 | if (debug) | |
1478 | fprintf(ddt,"findns: stale entry '%s'\n", | |
1479 | np->n_dname); | |
1480 | #endif | |
1481 | /* Cache invalidate the NS RR's */ | |
1482 | if (dp->d_ttl < tt.tv_sec) | |
1483 | delete_all(np, class, T_NS); | |
1484 | goto try_parent; | |
1485 | } | |
1486 | if (nspp < &nsp[NSMAX-1]) | |
1487 | *nspp++ = dp; | |
1488 | } | |
1489 | ||
1490 | *countp = nspp - nsp; | |
1491 | if (*countp > 0) { | |
1492 | #ifdef DEBUG | |
1493 | if (debug >= 3) | |
1494 | fprintf(ddt,"findns: %d NS's added for '%s'\n", | |
1495 | *countp, np->n_dname); | |
1496 | #endif | |
1497 | *nspp = NULL; | |
1498 | *npp = np; | |
1499 | return(OK); /* Success, got some NS's */ | |
1500 | } | |
1501 | try_parent: | |
1502 | np = np->n_parent; | |
1503 | } | |
1504 | if (htp) | |
1505 | goto try_again; | |
1506 | #ifdef DEBUG | |
1507 | if (debug) | |
1508 | fprintf(ddt, "findns: No root nameservers for class %d?\n", | |
1509 | class); | |
1510 | #endif | |
1511 | if ((unsigned)class < MAXCLASS && norootlogged[class] == 0) { | |
1512 | norootlogged[class] = 1; | |
1513 | syslog(LOG_ERR, "No root nameservers for class %d\n", class); | |
1514 | } | |
1515 | return(SERVFAIL); | |
1516 | } | |
1517 | ||
1518 | /* | |
1519 | * Extract RR's from the given node that match class and type. | |
1520 | * Return number of bytes added to response. | |
1521 | * If no matching data is found, then 0 is returned. | |
1522 | */ | |
1523 | finddata(np, class, type, hp, dnamep, lenp, countp) | |
1524 | struct namebuf *np; | |
1525 | int class, type; | |
1526 | register HEADER *hp; | |
1527 | char **dnamep; | |
1528 | int *lenp, *countp; | |
1529 | { | |
1530 | register struct databuf *dp; | |
1531 | register char *cp; | |
1532 | int buflen, n, count = 0, foundstale = 0; | |
1533 | ||
1534 | buflen = *lenp; | |
1535 | cp = ((char *)hp) + *countp; | |
1536 | for (dp = np->n_data; dp != NULL; dp = dp->d_next) { | |
1537 | if (!wanted(dp, class, type)) { | |
1538 | if (type == T_CNAME && class == dp->d_class) { | |
1539 | /* any data means no CNAME exists */ | |
1540 | *countp = 0; | |
1541 | return(0); | |
1542 | } | |
1543 | continue; | |
1544 | } | |
1545 | if (stale(dp)) { | |
1546 | /* | |
1547 | * Don't use stale data. | |
1548 | * Would like to call delete_all here | |
1549 | * and continue, but the data chain would get | |
1550 | * munged; can't restart, as make_rr has side | |
1551 | * effects (leaving pointers in dnptr). | |
1552 | * Just skip this entry for now | |
1553 | * and call delete_all at the end. | |
1554 | */ | |
1555 | #ifdef DEBUG | |
1556 | if (debug >=3) | |
1557 | fprintf(ddt,"finddata: stale entry '%s'\n",np->n_dname); | |
1558 | #endif | |
1559 | if (dp->d_zone == 0) | |
1560 | foundstale++; | |
1561 | continue; | |
1562 | } | |
1563 | if ((n = make_rr(*dnamep, dp, cp, buflen, 1)) < 0) { | |
1564 | hp->tc = 1; | |
1565 | *countp = count; | |
1566 | return(*lenp - buflen); | |
1567 | } | |
1568 | ||
1569 | cp += n; | |
1570 | buflen -= n; | |
1571 | count++; | |
1572 | #ifdef notdef | |
1573 | /* this isn't right for glue records, aa is set in ns_req */ | |
1574 | if (dp->d_zone && zones[dp->d_zone].z_auth && class != C_ANY) | |
1575 | hp->aa = 1; /* XXX */ | |
1576 | #endif | |
1577 | if (dp->d_type == T_CNAME) { | |
1578 | if (type != T_ANY) { /* or T_NS? */ | |
1579 | *dnamep = dp->d_data; | |
1580 | if (dp->d_zone && zones[dp->d_zone].z_auth && | |
1581 | class != C_ANY) /* XXX */ | |
1582 | hp->aa = 1; /* XXX */ | |
1583 | } | |
1584 | break; | |
1585 | } | |
1586 | } | |
1587 | /* | |
1588 | * Cache invalidate the other RR's of same type | |
1589 | * if some have timed out | |
1590 | */ | |
1591 | if (foundstale) | |
1592 | delete_all(np, class, type); | |
1593 | #ifdef DEBUG | |
1594 | if (debug >=3) | |
1595 | fprintf(ddt,"finddata: added %d class %d type %d RRs\n", | |
1596 | count, class, type); | |
1597 | #endif | |
1598 | *countp = count; | |
1599 | return(*lenp - buflen); | |
1600 | } | |
1601 | ||
1602 | /* | |
1603 | * Do we want this data record based on the class and type? | |
1604 | */ | |
1605 | wanted(dp, class, type) | |
1606 | struct databuf *dp; | |
1607 | int class, type; | |
1608 | { | |
1609 | ||
1610 | #ifdef DEBUG | |
1611 | if (debug > 3) | |
1612 | fprintf(ddt,"wanted(%x, %d, %d) %d, %d\n", dp, class, type, | |
1613 | dp->d_class, dp->d_type); | |
1614 | #endif | |
1615 | ||
1616 | if (dp->d_class != class && class != C_ANY) | |
1617 | return (0); | |
1618 | if (type == dp->d_type) | |
1619 | return (1); | |
1620 | switch (dp->d_type) { | |
1621 | case T_ANY: | |
1622 | case T_CNAME: | |
1623 | return (1); | |
1624 | } | |
1625 | switch (type) { | |
1626 | case T_ANY: | |
1627 | return (1); | |
1628 | ||
1629 | case T_MAILB: | |
1630 | switch (dp->d_type) { | |
1631 | case T_MR: | |
1632 | case T_MB: | |
1633 | case T_MG: | |
1634 | case T_MINFO: | |
1635 | return (1); | |
1636 | } | |
1637 | break; | |
1638 | ||
1639 | case T_AXFR: | |
1640 | if (dp->d_type == T_SOA) | |
1641 | return (1); | |
1642 | } | |
1643 | return (0); | |
1644 | } | |
1645 | ||
1646 | /* | |
1647 | * Add RR entries from dpp array to a query/response. | |
1648 | * Return the number of bytes added or negative the amount | |
1649 | * added if truncation was required. Typically you are | |
1650 | * adding NS records to a response. | |
1651 | */ | |
1652 | add_data(np, dpp, cp, buflen) | |
1653 | struct namebuf *np; | |
1654 | struct databuf **dpp; | |
1655 | register char *cp; | |
1656 | int buflen; | |
1657 | { | |
1658 | register struct databuf *dp; | |
1659 | char dname[MAXDNAME]; | |
1660 | register int n, count = 0; | |
1661 | ||
1662 | getname(np, dname, sizeof(dname)); | |
1663 | for(dp = *dpp++; dp != NULL; dp = *dpp++) { | |
1664 | if (stale(dp)) | |
1665 | continue; /* ignore old cache entry */ | |
1666 | if ((n = make_rr(dname, dp, cp, buflen, 1)) < 0) | |
1667 | return(-count); /* Truncation */ | |
1668 | cp += n; | |
1669 | buflen -= n; | |
1670 | count += n; | |
1671 | } | |
1672 | return(count); | |
1673 | } | |
1674 | ||
1675 | /* | |
1676 | * This is best thought of as a "cache invalidate" function. | |
1677 | * It is called whenever a piece of data is determined to have | |
1678 | * timed out. It is better to have no information, than to | |
1679 | * have partial information you pass off as complete. | |
1680 | */ | |
1681 | delete_all(np, class, type) | |
1682 | register struct namebuf *np; | |
1683 | int class, type; | |
1684 | { | |
1685 | register struct databuf *dp, *pdp; | |
1686 | ||
1687 | #ifdef DEBUG | |
1688 | if (debug > 2) | |
1689 | fprintf(ddt,"delete_all: '%s' 0x%x class %d type %d\n", | |
1690 | np->n_dname, np, class, type); | |
1691 | #endif | |
1692 | pdp = NULL; | |
1693 | dp = np->n_data; | |
1694 | while (dp != NULL) { | |
1695 | if ((dp->d_zone == 0) && !(dp->d_flags & DB_F_HINT) | |
1696 | && match(dp, class, type)) { | |
1697 | dp = rm_datum(dp, np, pdp); | |
1698 | continue; | |
1699 | } | |
1700 | pdp = dp; | |
1701 | dp = dp->d_next; | |
1702 | } | |
1703 | } |