1 | #include <machine/rtems-bsd-user-space.h> |
---|
2 | |
---|
3 | #if !defined(lint) && !defined(SABER) |
---|
4 | static const char rcsid[] = "$Id: res_findzonecut.c,v 1.10 2005/10/11 00:10:16 marka Exp $"; |
---|
5 | #endif /* not lint */ |
---|
6 | |
---|
7 | /* |
---|
8 | * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") |
---|
9 | * Copyright (c) 1999 by Internet Software Consortium. |
---|
10 | * |
---|
11 | * Permission to use, copy, modify, and distribute this software for any |
---|
12 | * purpose with or without fee is hereby granted, provided that the above |
---|
13 | * copyright notice and this permission notice appear in all copies. |
---|
14 | * |
---|
15 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
---|
16 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
---|
17 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR |
---|
18 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
---|
19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
---|
20 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT |
---|
21 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
---|
22 | */ |
---|
23 | |
---|
24 | #include <sys/cdefs.h> |
---|
25 | __FBSDID("$FreeBSD$"); |
---|
26 | |
---|
27 | /* Import. */ |
---|
28 | |
---|
29 | #include "port_before.h" |
---|
30 | |
---|
31 | #include <rtems/bsd/sys/param.h> |
---|
32 | #include <sys/socket.h> |
---|
33 | #include <sys/time.h> |
---|
34 | |
---|
35 | #include <netinet/in.h> |
---|
36 | #include <arpa/inet.h> |
---|
37 | #include <arpa/nameser.h> |
---|
38 | |
---|
39 | #include <errno.h> |
---|
40 | #include <limits.h> |
---|
41 | #include <netdb.h> |
---|
42 | #include <stdarg.h> |
---|
43 | #include <stdio.h> |
---|
44 | #include <stdlib.h> |
---|
45 | #include <string.h> |
---|
46 | |
---|
47 | #include <isc/list.h> |
---|
48 | |
---|
49 | #include "port_after.h" |
---|
50 | |
---|
51 | #include <resolv.h> |
---|
52 | |
---|
53 | /* Data structures. */ |
---|
54 | |
---|
55 | typedef struct rr_a { |
---|
56 | LINK(struct rr_a) link; |
---|
57 | union res_sockaddr_union addr; |
---|
58 | } rr_a; |
---|
59 | typedef LIST(rr_a) rrset_a; |
---|
60 | |
---|
61 | typedef struct rr_ns { |
---|
62 | LINK(struct rr_ns) link; |
---|
63 | const char * name; |
---|
64 | unsigned int flags; |
---|
65 | rrset_a addrs; |
---|
66 | } rr_ns; |
---|
67 | typedef LIST(rr_ns) rrset_ns; |
---|
68 | |
---|
69 | #define RR_NS_HAVE_V4 0x01 |
---|
70 | #define RR_NS_HAVE_V6 0x02 |
---|
71 | |
---|
72 | /* Forward. */ |
---|
73 | |
---|
74 | static int satisfy(res_state, const char *, rrset_ns *, |
---|
75 | union res_sockaddr_union *, int); |
---|
76 | static int add_addrs(res_state, rr_ns *, |
---|
77 | union res_sockaddr_union *, int); |
---|
78 | static int get_soa(res_state, const char *, ns_class, int, |
---|
79 | char *, size_t, char *, size_t, |
---|
80 | rrset_ns *); |
---|
81 | static int get_ns(res_state, const char *, ns_class, int, rrset_ns *); |
---|
82 | static int get_glue(res_state, ns_class, int, rrset_ns *); |
---|
83 | static int save_ns(res_state, ns_msg *, ns_sect, |
---|
84 | const char *, ns_class, int, rrset_ns *); |
---|
85 | static int save_a(res_state, ns_msg *, ns_sect, |
---|
86 | const char *, ns_class, int, rr_ns *); |
---|
87 | static void free_nsrrset(rrset_ns *); |
---|
88 | static void free_nsrr(rrset_ns *, rr_ns *); |
---|
89 | static rr_ns * find_ns(rrset_ns *, const char *); |
---|
90 | static int do_query(res_state, const char *, ns_class, ns_type, |
---|
91 | u_char *, ns_msg *); |
---|
92 | static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2); |
---|
93 | |
---|
94 | /* Macros. */ |
---|
95 | |
---|
96 | #define DPRINTF(x) do {\ |
---|
97 | int save_errno = errno; \ |
---|
98 | if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \ |
---|
99 | errno = save_errno; \ |
---|
100 | } while (0) |
---|
101 | |
---|
102 | /* Public. */ |
---|
103 | |
---|
104 | /*% |
---|
105 | * find enclosing zone for a <dname,class>, and some server addresses |
---|
106 | * |
---|
107 | * parameters: |
---|
108 | *\li res - resolver context to work within (is modified) |
---|
109 | *\li dname - domain name whose enclosing zone is desired |
---|
110 | *\li class - class of dname (and its enclosing zone) |
---|
111 | *\li zname - found zone name |
---|
112 | *\li zsize - allocated size of zname |
---|
113 | *\li addrs - found server addresses |
---|
114 | *\li naddrs - max number of addrs |
---|
115 | * |
---|
116 | * return values: |
---|
117 | *\li < 0 - an error occurred (check errno) |
---|
118 | *\li = 0 - zname is now valid, but addrs[] wasn't changed |
---|
119 | *\li > 0 - zname is now valid, and return value is number of addrs[] found |
---|
120 | * |
---|
121 | * notes: |
---|
122 | *\li this function calls res_nsend() which means it depends on correctly |
---|
123 | * functioning recursive nameservers (usually defined in /etc/resolv.conf |
---|
124 | * or its local equivilent). |
---|
125 | * |
---|
126 | *\li we start by asking for an SOA<dname,class>. if we get one as an |
---|
127 | * answer, that just means <dname,class> is a zone top, which is fine. |
---|
128 | * more than likely we'll be told to go pound sand, in the form of a |
---|
129 | * negative answer. |
---|
130 | * |
---|
131 | *\li note that we are not prepared to deal with referrals since that would |
---|
132 | * only come from authority servers and our correctly functioning local |
---|
133 | * recursive server would have followed the referral and got us something |
---|
134 | * more definite. |
---|
135 | * |
---|
136 | *\li if the authority section contains an SOA, this SOA should also be the |
---|
137 | * closest enclosing zone, since any intermediary zone cuts would've been |
---|
138 | * returned as referrals and dealt with by our correctly functioning local |
---|
139 | * recursive name server. but an SOA in the authority section should NOT |
---|
140 | * match our dname (since that would have been returned in the answer |
---|
141 | * section). an authority section SOA has to be "above" our dname. |
---|
142 | * |
---|
143 | *\li however, since authority section SOA's were once optional, it's |
---|
144 | * possible that we'll have to go hunting for the enclosing SOA by |
---|
145 | * ripping labels off the front of our dname -- this is known as "doing |
---|
146 | * it the hard way." |
---|
147 | * |
---|
148 | *\li ultimately we want some server addresses, which are ideally the ones |
---|
149 | * pertaining to the SOA.MNAME, but only if there is a matching NS RR. |
---|
150 | * so the second phase (after we find an SOA) is to go looking for the |
---|
151 | * NS RRset for that SOA's zone. |
---|
152 | * |
---|
153 | *\li no answer section processed by this code is allowed to contain CNAME |
---|
154 | * or DNAME RR's. for the SOA query this means we strip a label and |
---|
155 | * keep going. for the NS and A queries this means we just give up. |
---|
156 | */ |
---|
157 | |
---|
158 | #ifndef _LIBC |
---|
159 | int |
---|
160 | res_findzonecut(res_state statp, const char *dname, ns_class class, int opts, |
---|
161 | char *zname, size_t zsize, struct in_addr *addrs, int naddrs) |
---|
162 | { |
---|
163 | int result, i; |
---|
164 | union res_sockaddr_union *u; |
---|
165 | |
---|
166 | |
---|
167 | opts |= RES_IPV4ONLY; |
---|
168 | opts &= ~RES_IPV6ONLY; |
---|
169 | |
---|
170 | u = calloc(naddrs, sizeof(*u)); |
---|
171 | if (u == NULL) |
---|
172 | return(-1); |
---|
173 | |
---|
174 | result = res_findzonecut2(statp, dname, class, opts, zname, zsize, |
---|
175 | u, naddrs); |
---|
176 | |
---|
177 | for (i = 0; i < result; i++) { |
---|
178 | addrs[i] = u[i].sin.sin_addr; |
---|
179 | } |
---|
180 | free(u); |
---|
181 | return (result); |
---|
182 | } |
---|
183 | #endif |
---|
184 | |
---|
185 | int |
---|
186 | res_findzonecut2(res_state statp, const char *dname, ns_class class, int opts, |
---|
187 | char *zname, size_t zsize, union res_sockaddr_union *addrs, |
---|
188 | int naddrs) |
---|
189 | { |
---|
190 | char mname[NS_MAXDNAME]; |
---|
191 | u_long save_pfcode; |
---|
192 | rrset_ns nsrrs; |
---|
193 | int n; |
---|
194 | |
---|
195 | DPRINTF(("START dname='%s' class=%s, zsize=%ld, naddrs=%d", |
---|
196 | dname, p_class(class), (long)zsize, naddrs)); |
---|
197 | save_pfcode = statp->pfcode; |
---|
198 | statp->pfcode |= RES_PRF_HEAD2 | RES_PRF_HEAD1 | RES_PRF_HEADX | |
---|
199 | RES_PRF_QUES | RES_PRF_ANS | |
---|
200 | RES_PRF_AUTH | RES_PRF_ADD; |
---|
201 | INIT_LIST(nsrrs); |
---|
202 | |
---|
203 | DPRINTF(("get the soa, and see if it has enough glue")); |
---|
204 | if ((n = get_soa(statp, dname, class, opts, zname, zsize, |
---|
205 | mname, sizeof mname, &nsrrs)) < 0 || |
---|
206 | ((opts & RES_EXHAUSTIVE) == 0 && |
---|
207 | (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0)) |
---|
208 | goto done; |
---|
209 | |
---|
210 | DPRINTF(("get the ns rrset and see if it has enough glue")); |
---|
211 | if ((n = get_ns(statp, zname, class, opts, &nsrrs)) < 0 || |
---|
212 | ((opts & RES_EXHAUSTIVE) == 0 && |
---|
213 | (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0)) |
---|
214 | goto done; |
---|
215 | |
---|
216 | DPRINTF(("get the missing glue and see if it's finally enough")); |
---|
217 | if ((n = get_glue(statp, class, opts, &nsrrs)) >= 0) |
---|
218 | n = satisfy(statp, mname, &nsrrs, addrs, naddrs); |
---|
219 | |
---|
220 | done: |
---|
221 | DPRINTF(("FINISH n=%d (%s)", n, (n < 0) ? strerror(errno) : "OK")); |
---|
222 | free_nsrrset(&nsrrs); |
---|
223 | statp->pfcode = save_pfcode; |
---|
224 | return (n); |
---|
225 | } |
---|
226 | |
---|
227 | /* Private. */ |
---|
228 | |
---|
229 | static int |
---|
230 | satisfy(res_state statp, const char *mname, rrset_ns *nsrrsp, |
---|
231 | union res_sockaddr_union *addrs, int naddrs) |
---|
232 | { |
---|
233 | rr_ns *nsrr; |
---|
234 | int n, x; |
---|
235 | |
---|
236 | n = 0; |
---|
237 | nsrr = find_ns(nsrrsp, mname); |
---|
238 | if (nsrr != NULL) { |
---|
239 | x = add_addrs(statp, nsrr, addrs, naddrs); |
---|
240 | addrs += x; |
---|
241 | naddrs -= x; |
---|
242 | n += x; |
---|
243 | } |
---|
244 | for (nsrr = HEAD(*nsrrsp); |
---|
245 | nsrr != NULL && naddrs > 0; |
---|
246 | nsrr = NEXT(nsrr, link)) |
---|
247 | if (ns_samename(nsrr->name, mname) != 1) { |
---|
248 | x = add_addrs(statp, nsrr, addrs, naddrs); |
---|
249 | addrs += x; |
---|
250 | naddrs -= x; |
---|
251 | n += x; |
---|
252 | } |
---|
253 | DPRINTF(("satisfy(%s): %d", mname, n)); |
---|
254 | return (n); |
---|
255 | } |
---|
256 | |
---|
257 | static int |
---|
258 | add_addrs(res_state statp, rr_ns *nsrr, |
---|
259 | union res_sockaddr_union *addrs, int naddrs) |
---|
260 | { |
---|
261 | rr_a *arr; |
---|
262 | int n = 0; |
---|
263 | |
---|
264 | for (arr = HEAD(nsrr->addrs); arr != NULL; arr = NEXT(arr, link)) { |
---|
265 | if (naddrs <= 0) |
---|
266 | return (0); |
---|
267 | *addrs++ = arr->addr; |
---|
268 | naddrs--; |
---|
269 | n++; |
---|
270 | } |
---|
271 | DPRINTF(("add_addrs: %d", n)); |
---|
272 | return (n); |
---|
273 | } |
---|
274 | |
---|
275 | static int |
---|
276 | get_soa(res_state statp, const char *dname, ns_class class, int opts, |
---|
277 | char *zname, size_t zsize, char *mname, size_t msize, |
---|
278 | rrset_ns *nsrrsp) |
---|
279 | { |
---|
280 | char tname[NS_MAXDNAME]; |
---|
281 | u_char *resp = NULL; |
---|
282 | int n, i, ancount, nscount; |
---|
283 | ns_sect sect; |
---|
284 | ns_msg msg; |
---|
285 | u_int rcode; |
---|
286 | |
---|
287 | /* |
---|
288 | * Find closest enclosing SOA, even if it's for the root zone. |
---|
289 | */ |
---|
290 | |
---|
291 | /* First canonicalize dname (exactly one unescaped trailing "."). */ |
---|
292 | if (ns_makecanon(dname, tname, sizeof tname) < 0) |
---|
293 | goto cleanup; |
---|
294 | dname = tname; |
---|
295 | |
---|
296 | resp = malloc(NS_MAXMSG); |
---|
297 | if (resp == NULL) |
---|
298 | goto cleanup; |
---|
299 | |
---|
300 | /* Now grovel the subdomains, hunting for an SOA answer or auth. */ |
---|
301 | for (;;) { |
---|
302 | /* Leading or inter-label '.' are skipped here. */ |
---|
303 | while (*dname == '.') |
---|
304 | dname++; |
---|
305 | |
---|
306 | /* Is there an SOA? */ |
---|
307 | n = do_query(statp, dname, class, ns_t_soa, resp, &msg); |
---|
308 | if (n < 0) { |
---|
309 | DPRINTF(("get_soa: do_query('%s', %s) failed (%d)", |
---|
310 | dname, p_class(class), n)); |
---|
311 | goto cleanup; |
---|
312 | } |
---|
313 | if (n > 0) { |
---|
314 | DPRINTF(("get_soa: CNAME or DNAME found")); |
---|
315 | sect = ns_s_max, n = 0; |
---|
316 | } else { |
---|
317 | rcode = ns_msg_getflag(msg, ns_f_rcode); |
---|
318 | ancount = ns_msg_count(msg, ns_s_an); |
---|
319 | nscount = ns_msg_count(msg, ns_s_ns); |
---|
320 | if (ancount > 0 && rcode == ns_r_noerror) |
---|
321 | sect = ns_s_an, n = ancount; |
---|
322 | else if (nscount > 0) |
---|
323 | sect = ns_s_ns, n = nscount; |
---|
324 | else |
---|
325 | sect = ns_s_max, n = 0; |
---|
326 | } |
---|
327 | for (i = 0; i < n; i++) { |
---|
328 | const char *t; |
---|
329 | const u_char *rdata; |
---|
330 | ns_rr rr; |
---|
331 | |
---|
332 | if (ns_parserr(&msg, sect, i, &rr) < 0) { |
---|
333 | DPRINTF(("get_soa: ns_parserr(%s, %d) failed", |
---|
334 | p_section(sect, ns_o_query), i)); |
---|
335 | goto cleanup; |
---|
336 | } |
---|
337 | if (ns_rr_type(rr) == ns_t_cname || |
---|
338 | ns_rr_type(rr) == ns_t_dname) |
---|
339 | break; |
---|
340 | if (ns_rr_type(rr) != ns_t_soa || |
---|
341 | ns_rr_class(rr) != class) |
---|
342 | continue; |
---|
343 | t = ns_rr_name(rr); |
---|
344 | switch (sect) { |
---|
345 | case ns_s_an: |
---|
346 | if (ns_samedomain(dname, t) == 0) { |
---|
347 | DPRINTF( |
---|
348 | ("get_soa: ns_samedomain('%s', '%s') == 0", |
---|
349 | dname, t) |
---|
350 | ); |
---|
351 | errno = EPROTOTYPE; |
---|
352 | goto cleanup; |
---|
353 | } |
---|
354 | break; |
---|
355 | case ns_s_ns: |
---|
356 | if (ns_samename(dname, t) == 1 || |
---|
357 | ns_samedomain(dname, t) == 0) { |
---|
358 | DPRINTF( |
---|
359 | ("get_soa: ns_samename() || !ns_samedomain('%s', '%s')", |
---|
360 | dname, t) |
---|
361 | ); |
---|
362 | errno = EPROTOTYPE; |
---|
363 | goto cleanup; |
---|
364 | } |
---|
365 | break; |
---|
366 | default: |
---|
367 | abort(); |
---|
368 | } |
---|
369 | if (strlen(t) + 1 > zsize) { |
---|
370 | DPRINTF(("get_soa: zname(%lu) too small (%lu)", |
---|
371 | (unsigned long)zsize, |
---|
372 | (unsigned long)strlen(t) + 1)); |
---|
373 | errno = EMSGSIZE; |
---|
374 | goto cleanup; |
---|
375 | } |
---|
376 | strcpy(zname, t); |
---|
377 | rdata = ns_rr_rdata(rr); |
---|
378 | if (ns_name_uncompress(resp, ns_msg_end(msg), rdata, |
---|
379 | mname, msize) < 0) { |
---|
380 | DPRINTF(("get_soa: ns_name_uncompress failed") |
---|
381 | ); |
---|
382 | goto cleanup; |
---|
383 | } |
---|
384 | if (save_ns(statp, &msg, ns_s_ns, |
---|
385 | zname, class, opts, nsrrsp) < 0) { |
---|
386 | DPRINTF(("get_soa: save_ns failed")); |
---|
387 | goto cleanup; |
---|
388 | } |
---|
389 | free(resp); |
---|
390 | return (0); |
---|
391 | } |
---|
392 | |
---|
393 | /* If we're out of labels, then not even "." has an SOA! */ |
---|
394 | if (*dname == '\0') |
---|
395 | break; |
---|
396 | |
---|
397 | /* Find label-terminating "."; top of loop will skip it. */ |
---|
398 | while (*dname != '.') { |
---|
399 | if (*dname == '\\') |
---|
400 | if (*++dname == '\0') { |
---|
401 | errno = EMSGSIZE; |
---|
402 | goto cleanup; |
---|
403 | } |
---|
404 | dname++; |
---|
405 | } |
---|
406 | } |
---|
407 | DPRINTF(("get_soa: out of labels")); |
---|
408 | errno = EDESTADDRREQ; |
---|
409 | cleanup: |
---|
410 | if (resp != NULL) |
---|
411 | free(resp); |
---|
412 | return (-1); |
---|
413 | } |
---|
414 | |
---|
415 | static int |
---|
416 | get_ns(res_state statp, const char *zname, ns_class class, int opts, |
---|
417 | rrset_ns *nsrrsp) |
---|
418 | { |
---|
419 | u_char *resp; |
---|
420 | ns_msg msg; |
---|
421 | int n; |
---|
422 | |
---|
423 | resp = malloc(NS_MAXMSG); |
---|
424 | if (resp == NULL) |
---|
425 | return (-1); |
---|
426 | |
---|
427 | /* Go and get the NS RRs for this zone. */ |
---|
428 | n = do_query(statp, zname, class, ns_t_ns, resp, &msg); |
---|
429 | if (n != 0) { |
---|
430 | DPRINTF(("get_ns: do_query('%s', %s) failed (%d)", |
---|
431 | zname, p_class(class), n)); |
---|
432 | free(resp); |
---|
433 | return (-1); |
---|
434 | } |
---|
435 | |
---|
436 | /* Remember the NS RRs and associated A RRs that came back. */ |
---|
437 | if (save_ns(statp, &msg, ns_s_an, zname, class, opts, nsrrsp) < 0) { |
---|
438 | DPRINTF(("get_ns save_ns('%s', %s) failed", |
---|
439 | zname, p_class(class))); |
---|
440 | free(resp); |
---|
441 | return (-1); |
---|
442 | } |
---|
443 | |
---|
444 | free(resp); |
---|
445 | return (0); |
---|
446 | } |
---|
447 | |
---|
448 | static int |
---|
449 | get_glue(res_state statp, ns_class class, int opts, rrset_ns *nsrrsp) { |
---|
450 | rr_ns *nsrr, *nsrr_n; |
---|
451 | u_char *resp; |
---|
452 | |
---|
453 | resp = malloc(NS_MAXMSG); |
---|
454 | if (resp == NULL) |
---|
455 | return(-1); |
---|
456 | |
---|
457 | /* Go and get the A RRs for each empty NS RR on our list. */ |
---|
458 | for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = nsrr_n) { |
---|
459 | ns_msg msg; |
---|
460 | int n; |
---|
461 | |
---|
462 | nsrr_n = NEXT(nsrr, link); |
---|
463 | |
---|
464 | if ((nsrr->flags & RR_NS_HAVE_V4) == 0) { |
---|
465 | n = do_query(statp, nsrr->name, class, ns_t_a, |
---|
466 | resp, &msg); |
---|
467 | if (n < 0) { |
---|
468 | DPRINTF( |
---|
469 | ("get_glue: do_query('%s', %s') failed", |
---|
470 | nsrr->name, p_class(class))); |
---|
471 | goto cleanup; |
---|
472 | } |
---|
473 | if (n > 0) { |
---|
474 | DPRINTF(( |
---|
475 | "get_glue: do_query('%s', %s') CNAME or DNAME found", |
---|
476 | nsrr->name, p_class(class))); |
---|
477 | } |
---|
478 | if (save_a(statp, &msg, ns_s_an, nsrr->name, class, |
---|
479 | opts, nsrr) < 0) { |
---|
480 | DPRINTF(("get_glue: save_r('%s', %s) failed", |
---|
481 | nsrr->name, p_class(class))); |
---|
482 | goto cleanup; |
---|
483 | } |
---|
484 | } |
---|
485 | |
---|
486 | if ((nsrr->flags & RR_NS_HAVE_V6) == 0) { |
---|
487 | n = do_query(statp, nsrr->name, class, ns_t_aaaa, |
---|
488 | resp, &msg); |
---|
489 | if (n < 0) { |
---|
490 | DPRINTF( |
---|
491 | ("get_glue: do_query('%s', %s') failed", |
---|
492 | nsrr->name, p_class(class))); |
---|
493 | goto cleanup; |
---|
494 | } |
---|
495 | if (n > 0) { |
---|
496 | DPRINTF(( |
---|
497 | "get_glue: do_query('%s', %s') CNAME or DNAME found", |
---|
498 | nsrr->name, p_class(class))); |
---|
499 | } |
---|
500 | if (save_a(statp, &msg, ns_s_an, nsrr->name, class, |
---|
501 | opts, nsrr) < 0) { |
---|
502 | DPRINTF(("get_glue: save_r('%s', %s) failed", |
---|
503 | nsrr->name, p_class(class))); |
---|
504 | goto cleanup; |
---|
505 | } |
---|
506 | } |
---|
507 | |
---|
508 | /* If it's still empty, it's just chaff. */ |
---|
509 | if (EMPTY(nsrr->addrs)) { |
---|
510 | DPRINTF(("get_glue: removing empty '%s' NS", |
---|
511 | nsrr->name)); |
---|
512 | free_nsrr(nsrrsp, nsrr); |
---|
513 | } |
---|
514 | } |
---|
515 | free(resp); |
---|
516 | return (0); |
---|
517 | |
---|
518 | cleanup: |
---|
519 | free(resp); |
---|
520 | return (-1); |
---|
521 | } |
---|
522 | |
---|
523 | static int |
---|
524 | save_ns(res_state statp, ns_msg *msg, ns_sect sect, |
---|
525 | const char *owner, ns_class class, int opts, |
---|
526 | rrset_ns *nsrrsp) |
---|
527 | { |
---|
528 | int i; |
---|
529 | |
---|
530 | for (i = 0; i < ns_msg_count(*msg, sect); i++) { |
---|
531 | char tname[MAXDNAME]; |
---|
532 | const u_char *rdata; |
---|
533 | rr_ns *nsrr; |
---|
534 | ns_rr rr; |
---|
535 | |
---|
536 | if (ns_parserr(msg, sect, i, &rr) < 0) { |
---|
537 | DPRINTF(("save_ns: ns_parserr(%s, %d) failed", |
---|
538 | p_section(sect, ns_o_query), i)); |
---|
539 | return (-1); |
---|
540 | } |
---|
541 | if (ns_rr_type(rr) != ns_t_ns || |
---|
542 | ns_rr_class(rr) != class || |
---|
543 | ns_samename(ns_rr_name(rr), owner) != 1) |
---|
544 | continue; |
---|
545 | nsrr = find_ns(nsrrsp, ns_rr_name(rr)); |
---|
546 | if (nsrr == NULL) { |
---|
547 | nsrr = malloc(sizeof *nsrr); |
---|
548 | if (nsrr == NULL) { |
---|
549 | DPRINTF(("save_ns: malloc failed")); |
---|
550 | return (-1); |
---|
551 | } |
---|
552 | rdata = ns_rr_rdata(rr); |
---|
553 | if (ns_name_uncompress(ns_msg_base(*msg), |
---|
554 | ns_msg_end(*msg), rdata, |
---|
555 | tname, sizeof tname) < 0) { |
---|
556 | DPRINTF(("save_ns: ns_name_uncompress failed") |
---|
557 | ); |
---|
558 | free(nsrr); |
---|
559 | return (-1); |
---|
560 | } |
---|
561 | nsrr->name = strdup(tname); |
---|
562 | if (nsrr->name == NULL) { |
---|
563 | DPRINTF(("save_ns: strdup failed")); |
---|
564 | free(nsrr); |
---|
565 | return (-1); |
---|
566 | } |
---|
567 | INIT_LINK(nsrr, link); |
---|
568 | INIT_LIST(nsrr->addrs); |
---|
569 | nsrr->flags = 0; |
---|
570 | APPEND(*nsrrsp, nsrr, link); |
---|
571 | } |
---|
572 | if (save_a(statp, msg, ns_s_ar, |
---|
573 | nsrr->name, class, opts, nsrr) < 0) { |
---|
574 | DPRINTF(("save_ns: save_r('%s', %s) failed", |
---|
575 | nsrr->name, p_class(class))); |
---|
576 | return (-1); |
---|
577 | } |
---|
578 | } |
---|
579 | return (0); |
---|
580 | } |
---|
581 | |
---|
582 | static int |
---|
583 | save_a(res_state statp, ns_msg *msg, ns_sect sect, |
---|
584 | const char *owner, ns_class class, int opts, |
---|
585 | rr_ns *nsrr) |
---|
586 | { |
---|
587 | int i; |
---|
588 | |
---|
589 | for (i = 0; i < ns_msg_count(*msg, sect); i++) { |
---|
590 | ns_rr rr; |
---|
591 | rr_a *arr; |
---|
592 | |
---|
593 | if (ns_parserr(msg, sect, i, &rr) < 0) { |
---|
594 | DPRINTF(("save_a: ns_parserr(%s, %d) failed", |
---|
595 | p_section(sect, ns_o_query), i)); |
---|
596 | return (-1); |
---|
597 | } |
---|
598 | if ((ns_rr_type(rr) != ns_t_a && |
---|
599 | ns_rr_type(rr) != ns_t_aaaa) || |
---|
600 | ns_rr_class(rr) != class || |
---|
601 | ns_samename(ns_rr_name(rr), owner) != 1 || |
---|
602 | ns_rr_rdlen(rr) != NS_INADDRSZ) |
---|
603 | continue; |
---|
604 | if ((opts & RES_IPV6ONLY) != 0 && ns_rr_type(rr) != ns_t_aaaa) |
---|
605 | continue; |
---|
606 | if ((opts & RES_IPV4ONLY) != 0 && ns_rr_type(rr) != ns_t_a) |
---|
607 | continue; |
---|
608 | arr = malloc(sizeof *arr); |
---|
609 | if (arr == NULL) { |
---|
610 | DPRINTF(("save_a: malloc failed")); |
---|
611 | return (-1); |
---|
612 | } |
---|
613 | INIT_LINK(arr, link); |
---|
614 | memset(&arr->addr, 0, sizeof(arr->addr)); |
---|
615 | switch (ns_rr_type(rr)) { |
---|
616 | case ns_t_a: |
---|
617 | arr->addr.sin.sin_family = AF_INET; |
---|
618 | #ifdef HAVE_SA_LEN |
---|
619 | arr->addr.sin.sin_len = sizeof(arr->addr.sin); |
---|
620 | #endif |
---|
621 | memcpy(&arr->addr.sin.sin_addr, ns_rr_rdata(rr), |
---|
622 | NS_INADDRSZ); |
---|
623 | arr->addr.sin.sin_port = htons(NAMESERVER_PORT); |
---|
624 | nsrr->flags |= RR_NS_HAVE_V4; |
---|
625 | break; |
---|
626 | case ns_t_aaaa: |
---|
627 | arr->addr.sin6.sin6_family = AF_INET6; |
---|
628 | #ifdef HAVE_SA_LEN |
---|
629 | arr->addr.sin6.sin6_len = sizeof(arr->addr.sin6); |
---|
630 | #endif |
---|
631 | memcpy(&arr->addr.sin6.sin6_addr, ns_rr_rdata(rr), 16); |
---|
632 | arr->addr.sin.sin_port = htons(NAMESERVER_PORT); |
---|
633 | nsrr->flags |= RR_NS_HAVE_V6; |
---|
634 | break; |
---|
635 | default: |
---|
636 | abort(); |
---|
637 | } |
---|
638 | APPEND(nsrr->addrs, arr, link); |
---|
639 | } |
---|
640 | return (0); |
---|
641 | } |
---|
642 | |
---|
643 | static void |
---|
644 | free_nsrrset(rrset_ns *nsrrsp) { |
---|
645 | rr_ns *nsrr; |
---|
646 | |
---|
647 | while ((nsrr = HEAD(*nsrrsp)) != NULL) |
---|
648 | free_nsrr(nsrrsp, nsrr); |
---|
649 | } |
---|
650 | |
---|
651 | static void |
---|
652 | free_nsrr(rrset_ns *nsrrsp, rr_ns *nsrr) { |
---|
653 | rr_a *arr; |
---|
654 | char *tmp; |
---|
655 | |
---|
656 | while ((arr = HEAD(nsrr->addrs)) != NULL) { |
---|
657 | UNLINK(nsrr->addrs, arr, link); |
---|
658 | free(arr); |
---|
659 | } |
---|
660 | DE_CONST(nsrr->name, tmp); |
---|
661 | free(tmp); |
---|
662 | UNLINK(*nsrrsp, nsrr, link); |
---|
663 | free(nsrr); |
---|
664 | } |
---|
665 | |
---|
666 | static rr_ns * |
---|
667 | find_ns(rrset_ns *nsrrsp, const char *dname) { |
---|
668 | rr_ns *nsrr; |
---|
669 | |
---|
670 | for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = NEXT(nsrr, link)) |
---|
671 | if (ns_samename(nsrr->name, dname) == 1) |
---|
672 | return (nsrr); |
---|
673 | return (NULL); |
---|
674 | } |
---|
675 | |
---|
676 | static int |
---|
677 | do_query(res_state statp, const char *dname, ns_class class, ns_type qtype, |
---|
678 | u_char *resp, ns_msg *msg) |
---|
679 | { |
---|
680 | u_char req[NS_PACKETSZ]; |
---|
681 | int i, n; |
---|
682 | |
---|
683 | n = res_nmkquery(statp, ns_o_query, dname, class, qtype, |
---|
684 | NULL, 0, NULL, req, NS_PACKETSZ); |
---|
685 | if (n < 0) { |
---|
686 | DPRINTF(("do_query: res_nmkquery failed")); |
---|
687 | return (-1); |
---|
688 | } |
---|
689 | n = res_nsend(statp, req, n, resp, NS_MAXMSG); |
---|
690 | if (n < 0) { |
---|
691 | DPRINTF(("do_query: res_nsend failed")); |
---|
692 | return (-1); |
---|
693 | } |
---|
694 | if (n == 0) { |
---|
695 | DPRINTF(("do_query: res_nsend returned 0")); |
---|
696 | errno = EMSGSIZE; |
---|
697 | return (-1); |
---|
698 | } |
---|
699 | if (ns_initparse(resp, n, msg) < 0) { |
---|
700 | DPRINTF(("do_query: ns_initparse failed")); |
---|
701 | return (-1); |
---|
702 | } |
---|
703 | n = 0; |
---|
704 | for (i = 0; i < ns_msg_count(*msg, ns_s_an); i++) { |
---|
705 | ns_rr rr; |
---|
706 | |
---|
707 | if (ns_parserr(msg, ns_s_an, i, &rr) < 0) { |
---|
708 | DPRINTF(("do_query: ns_parserr failed")); |
---|
709 | return (-1); |
---|
710 | } |
---|
711 | n += (ns_rr_class(rr) == class && |
---|
712 | (ns_rr_type(rr) == ns_t_cname || |
---|
713 | ns_rr_type(rr) == ns_t_dname)); |
---|
714 | } |
---|
715 | return (n); |
---|
716 | } |
---|
717 | |
---|
718 | static void |
---|
719 | res_dprintf(const char *fmt, ...) { |
---|
720 | va_list ap; |
---|
721 | |
---|
722 | va_start(ap, fmt); |
---|
723 | fputs(";; res_findzonecut: ", stderr); |
---|
724 | vfprintf(stderr, fmt, ap); |
---|
725 | fputc('\n', stderr); |
---|
726 | va_end(ap); |
---|
727 | } |
---|
728 | |
---|
729 | /*! \file */ |
---|