1#ifndef __APPLE__ 2#if !defined(lint) && !defined(SABER) 3static 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 57typedef struct rr_a { 58 LINK(struct rr_a) link; 59 union res_sockaddr_union addr; 60} rr_a; 61typedef LIST(rr_a) rrset_a; 62 63typedef 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; 70typedef LIST(rr_ns) rrset_ns; 71 72/* Forward. */ 73 74static int satisfy(res_state, const char *, rrset_ns *, 75 union res_sockaddr_union *, int); 76static int add_addrs(res_state, rr_ns *, 77 union res_sockaddr_union *, int); 78static int get_soa(res_state, const char *, ns_class, int, 79 char *, size_t, char *, size_t, 80 rrset_ns *); 81static int get_ns(res_state, const char *, ns_class, int, rrset_ns *); 82static int get_glue(res_state, ns_class, int, rrset_ns *); 83static int save_ns(res_state, ns_msg *, ns_sect, 84 const char *, ns_class, int, rrset_ns *); 85static int save_a(res_state, ns_msg *, ns_sect, 86 const char *, ns_class, int, rr_ns *); 87static void free_nsrrset(rrset_ns *); 88static void free_nsrr(rrset_ns *, rr_ns *); 89static rr_ns * find_ns(rrset_ns *, const char *); 90static int do_query(res_state, const char *, ns_class, ns_type, 91 u_char *, ns_msg *); 92#ifndef __APPLE__ 93static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2); 94#else 95static 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 161int 162res_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 185int 186res_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 229static int 230satisfy(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 257static int 258add_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 275static int 276get_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 403static int 404get_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 429static int 430get_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 493static int 494save_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 554static int 555save_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 614static void 615free_nsrrset(rrset_ns *nsrrsp) { 616 rr_ns *nsrr; 617 618 while ((nsrr = HEAD(*nsrrsp)) != NULL) 619 free_nsrr(nsrrsp, nsrr); 620} 621 622static void 623free_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 641static rr_ns * 642find_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 651static int 652do_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 693static void 694res_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} 703