Annotation of embedaddon/dhcp/minires/res_findzonecut.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>