[BACK]Return to res_findzonecut.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libresolv

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>