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