1 /* $NetBSD: res_findzonecut.c,v 1.1 2012/11/15 18:48:48 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (c) 1999 by Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 #include <sys/cdefs.h> 20 #if 0 21 static const char rcsid[] = "Id: res_findzonecut.c,v 1.10 2005/10/11 00:10:16 marka Exp "; 22 #else 23 __RCSID("$NetBSD: res_findzonecut.c,v 1.1 2012/11/15 18:48:48 christos Exp $"); 24 #endif 25 26 27 /* Import. */ 28 29 #include "port_before.h" 30 31 #include <sys/param.h> 32 #include <sys/socket.h> 33 #include <sys/time.h> 34 #include <sys/queue.h> 35 36 #include <netinet/in.h> 37 #include <arpa/inet.h> 38 #include <arpa/nameser.h> 39 40 #include <errno.h> 41 #include <limits.h> 42 #include <netdb.h> 43 #include <stdarg.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 48 #include "port_after.h" 49 50 #include <resolv.h> 51 52 /* Data structures. */ 53 54 typedef struct rr_a { 55 TAILQ_ENTRY(rr_a) link; 56 union res_sockaddr_union addr; 57 } rr_a; 58 typedef TAILQ_HEAD(rrset_a, rr_a) rrset_a; 59 60 typedef struct rr_ns { 61 TAILQ_ENTRY(rr_ns) link; 62 const char * name; 63 unsigned int flags; 64 rrset_a addrs; 65 } rr_ns; 66 typedef TAILQ_HEAD(rrset_ns, rr_ns) rrset_ns; 67 68 #define RR_NS_HAVE_V4 0x01 69 #define RR_NS_HAVE_V6 0x02 70 71 /* Forward. */ 72 73 static int satisfy(res_state, const char *, rrset_ns *, 74 union res_sockaddr_union *, int); 75 static int add_addrs(res_state, rr_ns *, 76 union res_sockaddr_union *, int); 77 static int get_soa(res_state, const char *, ns_class, int, 78 char *, size_t, char *, size_t, 79 rrset_ns *); 80 static int get_ns(res_state, const char *, ns_class, int, rrset_ns *); 81 static int get_glue(res_state, ns_class, int, rrset_ns *); 82 static int save_ns(res_state, ns_msg *, ns_sect, 83 const char *, ns_class, int, rrset_ns *); 84 static int save_a(res_state, ns_msg *, ns_sect, 85 const char *, ns_class, int, rr_ns *); 86 static void free_nsrrset(rrset_ns *); 87 static void free_nsrr(rrset_ns *, rr_ns *); 88 static rr_ns * find_ns(rrset_ns *, const char *); 89 static int do_query(res_state, const char *, ns_class, ns_type, 90 u_char *, ns_msg *); 91 static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2); 92 93 /* Macros. */ 94 95 #define DPRINTF(x) do {\ 96 int save_errno = errno; \ 97 if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \ 98 errno = save_errno; \ 99 } while (/*CONSTCOND*/0) 100 101 /* Public. */ 102 103 /*% 104 * find enclosing zone for a <dname,class>, and some server addresses 105 * 106 * parameters: 107 *\li res - resolver context to work within (is modified) 108 *\li dname - domain name whose enclosing zone is desired 109 *\li class - class of dname (and its enclosing zone) 110 *\li zname - found zone name 111 *\li zsize - allocated size of zname 112 *\li addrs - found server addresses 113 *\li naddrs - max number of addrs 114 * 115 * return values: 116 *\li < 0 - an error occurred (check errno) 117 *\li = 0 - zname is now valid, but addrs[] wasn't changed 118 *\li > 0 - zname is now valid, and return value is number of addrs[] found 119 * 120 * notes: 121 *\li this function calls res_nsend() which means it depends on correctly 122 * functioning recursive nameservers (usually defined in /etc/resolv.conf 123 * or its local equivilent). 124 * 125 *\li we start by asking for an SOA<dname,class>. if we get one as an 126 * answer, that just means <dname,class> is a zone top, which is fine. 127 * more than likely we'll be told to go pound sand, in the form of a 128 * negative answer. 129 * 130 *\li note that we are not prepared to deal with referrals since that would 131 * only come from authority servers and our correctly functioning local 132 * recursive server would have followed the referral and got us something 133 * more definite. 134 * 135 *\li if the authority section contains an SOA, this SOA should also be the 136 * closest enclosing zone, since any intermediary zone cuts would've been 137 * returned as referrals and dealt with by our correctly functioning local 138 * recursive name server. but an SOA in the authority section should NOT 139 * match our dname (since that would have been returned in the answer 140 * section). an authority section SOA has to be "above" our dname. 141 * 142 *\li however, since authority section SOA's were once optional, it's 143 * possible that we'll have to go hunting for the enclosing SOA by 144 * ripping labels off the front of our dname -- this is known as "doing 145 * it the hard way." 146 * 147 *\li ultimately we want some server addresses, which are ideally the ones 148 * pertaining to the SOA.MNAME, but only if there is a matching NS RR. 149 * so the second phase (after we find an SOA) is to go looking for the 150 * NS RRset for that SOA's zone. 151 * 152 *\li no answer section processed by this code is allowed to contain CNAME 153 * or DNAME RR's. for the SOA query this means we strip a label and 154 * keep going. for the NS and A queries this means we just give up. 155 */ 156 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 182 int 183 res_findzonecut2(res_state statp, const char *dname, ns_class class, int opts, 184 char *zname, size_t zsize, union res_sockaddr_union *addrs, 185 int naddrs) 186 { 187 char mname[NS_MAXDNAME]; 188 u_long save_pfcode; 189 rrset_ns nsrrs; 190 int n; 191 192 DPRINTF(("START dname='%s' class=%s, zsize=%ld, naddrs=%d", 193 dname, p_class(class), (long)zsize, naddrs)); 194 save_pfcode = statp->pfcode; 195 statp->pfcode |= RES_PRF_HEAD2 | RES_PRF_HEAD1 | RES_PRF_HEADX | 196 RES_PRF_QUES | RES_PRF_ANS | 197 RES_PRF_AUTH | RES_PRF_ADD; 198 TAILQ_INIT(&nsrrs); 199 200 DPRINTF(("get the soa, and see if it has enough glue")); 201 if ((n = get_soa(statp, dname, class, opts, zname, zsize, 202 mname, sizeof mname, &nsrrs)) < 0 || 203 ((opts & RES_EXHAUSTIVE) == 0 && 204 (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0)) 205 goto done; 206 207 DPRINTF(("get the ns rrset and see if it has enough glue")); 208 if ((n = get_ns(statp, zname, class, opts, &nsrrs)) < 0 || 209 ((opts & RES_EXHAUSTIVE) == 0 && 210 (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0)) 211 goto done; 212 213 DPRINTF(("get the missing glue and see if it's finally enough")); 214 if ((n = get_glue(statp, class, opts, &nsrrs)) >= 0) 215 n = satisfy(statp, mname, &nsrrs, addrs, naddrs); 216 217 done: 218 DPRINTF(("FINISH n=%d (%s)", n, (n < 0) ? strerror(errno) : "OK")); 219 free_nsrrset(&nsrrs); 220 statp->pfcode = save_pfcode; 221 return (n); 222 } 223 224 /* Private. */ 225 226 static int 227 satisfy(res_state statp, const char *mname, rrset_ns *nsrrsp, 228 union res_sockaddr_union *addrs, int naddrs) 229 { 230 rr_ns *nsrr; 231 int n, x; 232 233 n = 0; 234 nsrr = find_ns(nsrrsp, mname); 235 if (nsrr != NULL) { 236 x = add_addrs(statp, nsrr, addrs, naddrs); 237 addrs += x; 238 naddrs -= x; 239 n += x; 240 } 241 TAILQ_FOREACH(nsrr, nsrrsp, link) { 242 if (naddrs <= 0) 243 break; 244 if (ns_samename(nsrr->name, mname) != 1) { 245 x = add_addrs(statp, nsrr, addrs, naddrs); 246 addrs += x; 247 naddrs -= x; 248 n += x; 249 } 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 TAILQ_FOREACH(arr, &nsrr->addrs, 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 TAILQ_FOREACH_SAFE(nsrr, nsrrsp, link, nsrr_n) { 457 ns_msg msg; 458 int n; 459 460 if ((nsrr->flags & RR_NS_HAVE_V4) == 0) { 461 n = do_query(statp, nsrr->name, class, ns_t_a, 462 resp, &msg); 463 if (n < 0) { 464 DPRINTF( 465 ("get_glue: do_query('%s', %s') failed", 466 nsrr->name, p_class(class))); 467 goto cleanup; 468 } 469 if (n > 0) { 470 DPRINTF(( 471 "get_glue: do_query('%s', %s') CNAME or DNAME found", 472 nsrr->name, p_class(class))); 473 } 474 if (save_a(statp, &msg, ns_s_an, nsrr->name, class, 475 opts, nsrr) < 0) { 476 DPRINTF(("get_glue: save_r('%s', %s) failed", 477 nsrr->name, p_class(class))); 478 goto cleanup; 479 } 480 } 481 482 if ((nsrr->flags & RR_NS_HAVE_V6) == 0) { 483 n = do_query(statp, nsrr->name, class, ns_t_aaaa, 484 resp, &msg); 485 if (n < 0) { 486 DPRINTF( 487 ("get_glue: do_query('%s', %s') failed", 488 nsrr->name, p_class(class))); 489 goto cleanup; 490 } 491 if (n > 0) { 492 DPRINTF(( 493 "get_glue: do_query('%s', %s') CNAME or DNAME found", 494 nsrr->name, p_class(class))); 495 } 496 if (save_a(statp, &msg, ns_s_an, nsrr->name, class, 497 opts, nsrr) < 0) { 498 DPRINTF(("get_glue: save_r('%s', %s) failed", 499 nsrr->name, p_class(class))); 500 goto cleanup; 501 } 502 } 503 504 /* If it's still empty, it's just chaff. */ 505 if (TAILQ_EMPTY(&nsrr->addrs)) { 506 DPRINTF(("get_glue: removing empty '%s' NS", 507 nsrr->name)); 508 free_nsrr(nsrrsp, nsrr); 509 } 510 } 511 free(resp); 512 return (0); 513 514 cleanup: 515 free(resp); 516 return (-1); 517 } 518 519 static int 520 save_ns(res_state statp, ns_msg *msg, ns_sect sect, 521 const char *owner, ns_class class, int opts, 522 rrset_ns *nsrrsp) 523 { 524 int i; 525 526 for (i = 0; i < ns_msg_count(*msg, sect); i++) { 527 char tname[MAXDNAME]; 528 const u_char *rdata; 529 rr_ns *nsrr; 530 ns_rr rr; 531 532 if (ns_parserr(msg, sect, i, &rr) < 0) { 533 DPRINTF(("save_ns: ns_parserr(%s, %d) failed", 534 p_section(sect, ns_o_query), i)); 535 return (-1); 536 } 537 if (ns_rr_type(rr) != ns_t_ns || 538 ns_rr_class(rr) != class || 539 ns_samename(ns_rr_name(rr), owner) != 1) 540 continue; 541 nsrr = find_ns(nsrrsp, ns_rr_name(rr)); 542 if (nsrr == NULL) { 543 nsrr = malloc(sizeof *nsrr); 544 if (nsrr == NULL) { 545 DPRINTF(("save_ns: malloc failed")); 546 return (-1); 547 } 548 rdata = ns_rr_rdata(rr); 549 if (ns_name_uncompress(ns_msg_base(*msg), 550 ns_msg_end(*msg), rdata, 551 tname, sizeof tname) < 0) { 552 DPRINTF(("save_ns: ns_name_uncompress failed") 553 ); 554 free(nsrr); 555 return (-1); 556 } 557 nsrr->name = strdup(tname); 558 if (nsrr->name == NULL) { 559 DPRINTF(("save_ns: strdup failed")); 560 free(nsrr); 561 return (-1); 562 } 563 TAILQ_INIT(&nsrr->addrs); 564 nsrr->flags = 0; 565 TAILQ_INSERT_TAIL(nsrrsp, nsrr, link); 566 } 567 if (save_a(statp, msg, ns_s_ar, 568 nsrr->name, class, opts, nsrr) < 0) { 569 DPRINTF(("save_ns: save_r('%s', %s) failed", 570 nsrr->name, p_class(class))); 571 return (-1); 572 } 573 } 574 return (0); 575 } 576 577 static int 578 save_a(res_state statp, ns_msg *msg, ns_sect sect, 579 const char *owner, ns_class class, int opts, 580 rr_ns *nsrr) 581 { 582 int i; 583 584 for (i = 0; i < ns_msg_count(*msg, sect); i++) { 585 ns_rr rr; 586 rr_a *arr; 587 588 if (ns_parserr(msg, sect, i, &rr) < 0) { 589 DPRINTF(("save_a: ns_parserr(%s, %d) failed", 590 p_section(sect, ns_o_query), i)); 591 return (-1); 592 } 593 if ((ns_rr_type(rr) != ns_t_a && 594 ns_rr_type(rr) != ns_t_aaaa) || 595 ns_rr_class(rr) != class || 596 ns_samename(ns_rr_name(rr), owner) != 1 || 597 ns_rr_rdlen(rr) != NS_INADDRSZ) 598 continue; 599 if ((opts & RES_IPV6ONLY) != 0 && ns_rr_type(rr) != ns_t_aaaa) 600 continue; 601 if ((opts & RES_IPV4ONLY) != 0 && ns_rr_type(rr) != ns_t_a) 602 continue; 603 arr = malloc(sizeof *arr); 604 if (arr == NULL) { 605 DPRINTF(("save_a: malloc failed")); 606 return (-1); 607 } 608 memset(&arr->addr, 0, sizeof(arr->addr)); 609 switch (ns_rr_type(rr)) { 610 case ns_t_a: 611 arr->addr.sin.sin_family = AF_INET; 612 #ifdef HAVE_SA_LEN 613 arr->addr.sin.sin_len = sizeof(arr->addr.sin); 614 #endif 615 memcpy(&arr->addr.sin.sin_addr, ns_rr_rdata(rr), 616 NS_INADDRSZ); 617 arr->addr.sin.sin_port = htons(NAMESERVER_PORT); 618 nsrr->flags |= RR_NS_HAVE_V4; 619 break; 620 case ns_t_aaaa: 621 arr->addr.sin6.sin6_family = AF_INET6; 622 #ifdef HAVE_SA_LEN 623 arr->addr.sin6.sin6_len = sizeof(arr->addr.sin6); 624 #endif 625 memcpy(&arr->addr.sin6.sin6_addr, ns_rr_rdata(rr), 16); 626 arr->addr.sin.sin_port = htons(NAMESERVER_PORT); 627 nsrr->flags |= RR_NS_HAVE_V6; 628 break; 629 default: 630 abort(); 631 } 632 TAILQ_INSERT_TAIL(&nsrr->addrs, arr, link); 633 } 634 return (0); 635 } 636 637 static void 638 free_nsrrset(rrset_ns *nsrrsp) { 639 rr_ns *nsrr, *tmp; 640 641 TAILQ_FOREACH_SAFE(nsrr, nsrrsp, link, tmp) 642 free_nsrr(nsrrsp, nsrr); 643 } 644 645 static void 646 free_nsrr(rrset_ns *nsrrsp, rr_ns *nsrr) { 647 rr_a *arr, *n_arr; 648 char *tmp; 649 650 TAILQ_FOREACH_SAFE(arr, &nsrr->addrs, link, n_arr) { 651 TAILQ_REMOVE(&nsrr->addrs, arr, link); 652 free(arr); 653 } 654 DE_CONST(nsrr->name, tmp); 655 free(tmp); 656 TAILQ_REMOVE(nsrrsp, nsrr, link); 657 free(nsrr); 658 } 659 660 static rr_ns * 661 find_ns(rrset_ns *nsrrsp, const char *dname) { 662 rr_ns *nsrr; 663 664 TAILQ_FOREACH(nsrr, nsrrsp, link) 665 if (ns_samename(nsrr->name, dname) == 1) 666 return (nsrr); 667 return (NULL); 668 } 669 670 static int 671 do_query(res_state statp, const char *dname, ns_class class, ns_type qtype, 672 u_char *resp, ns_msg *msg) 673 { 674 u_char req[NS_PACKETSZ]; 675 int i, n; 676 677 n = res_nmkquery(statp, ns_o_query, dname, class, qtype, 678 NULL, 0, NULL, req, NS_PACKETSZ); 679 if (n < 0) { 680 DPRINTF(("do_query: res_nmkquery failed")); 681 return (-1); 682 } 683 n = res_nsend(statp, req, n, resp, NS_MAXMSG); 684 if (n < 0) { 685 DPRINTF(("do_query: res_nsend failed")); 686 return (-1); 687 } 688 if (n == 0) { 689 DPRINTF(("do_query: res_nsend returned 0")); 690 errno = EMSGSIZE; 691 return (-1); 692 } 693 if (ns_initparse(resp, n, msg) < 0) { 694 DPRINTF(("do_query: ns_initparse failed")); 695 return (-1); 696 } 697 n = 0; 698 for (i = 0; i < ns_msg_count(*msg, ns_s_an); i++) { 699 ns_rr rr; 700 701 if (ns_parserr(msg, ns_s_an, i, &rr) < 0) { 702 DPRINTF(("do_query: ns_parserr failed")); 703 return (-1); 704 } 705 n += (ns_rr_class(rr) == class && 706 (ns_rr_type(rr) == ns_t_cname || 707 ns_rr_type(rr) == ns_t_dname)); 708 } 709 return (n); 710 } 711 712 static void 713 res_dprintf(const char *fmt, ...) { 714 va_list ap; 715 716 va_start(ap, fmt); 717 fputs(";; res_findzonecut: ", stderr); 718 vfprintf(stderr, fmt, ap); 719 fputc('\n', stderr); 720 va_end(ap); 721 } 722 723 /*! \file */ 724