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