Annotation of src/lib/libresolv/res_findzonecut.c, Revision 1.1
1.1 ! christos 1: /* $NetBSD: res_findzonecut.c,v 1.1.1.2 2012/09/09 16:08:08 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$");
! 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 */
CVSweb <webmaster@jp.NetBSD.org>