Annotation of 43BSDReno/usr.sbin/named/ns_resp.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1986, 1988, 1990 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms are permitted provided
        !             6:  * that: (1) source distributions retain this entire copyright notice and
        !             7:  * comment, and (2) distributions including binaries display the following
        !             8:  * acknowledgement:  ``This product includes software developed by the
        !             9:  * University of California, Berkeley and its contributors'' in the
        !            10:  * documentation or other materials provided with the distribution and in
        !            11:  * all advertising materials mentioning features or use of this software.
        !            12:  * Neither the name of the University nor the names of its contributors may
        !            13:  * be used to endorse or promote products derived from this software without
        !            14:  * specific prior written permission.
        !            15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
        !            16:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            17:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            18:  */
        !            19: 
        !            20: #ifndef lint
        !            21: static char sccsid[] = "@(#)ns_resp.c  4.63 (Berkeley) 6/1/90";
        !            22: #endif /* not lint */
        !            23: 
        !            24: #include <stdio.h>
        !            25: #include <sys/param.h>
        !            26: #include <sys/time.h>
        !            27: #include <sys/socket.h>
        !            28: #include <sys/file.h>
        !            29: #include <netinet/in.h>
        !            30: #include <syslog.h>
        !            31: #include <arpa/nameser.h>
        !            32: #include "ns.h"
        !            33: #include "db.h"
        !            34: 
        !            35: extern int     debug;
        !            36: extern FILE    *ddt;
        !            37: extern int errno;
        !            38: extern u_char *dnptrs[];
        !            39: extern time_t retrytime();
        !            40: extern struct  fwdinfo *fwdtab;
        !            41: extern struct  sockaddr_in from_addr;  /* Source addr of last packet */
        !            42: extern int needs_prime_cache;
        !            43: extern int priming;
        !            44: 
        !            45: struct qinfo *sysquery();
        !            46: 
        !            47: ns_resp(msg, msglen)
        !            48:        u_char *msg;
        !            49:        int msglen;
        !            50: {
        !            51:        register struct qinfo *qp;
        !            52:        register HEADER *hp;
        !            53:        register struct qserv *qs;
        !            54:        register struct databuf *ns, *ns2;
        !            55:        register u_char *cp;
        !            56:        struct  databuf *nsp[NSMAX], **nspp;
        !            57:        int i, c, n, ancount, aucount, nscount, arcount;
        !            58:        int type, class, dbflags;
        !            59:        int cname = 0; /* flag for processing cname response */
        !            60:        int count, founddata, foundname;
        !            61:        int buflen;
        !            62:        int newmsglen;
        !            63:        char name[MAXDNAME], *dname;
        !            64:        char *fname;
        !            65:        u_char newmsg[BUFSIZ];
        !            66:        u_char **dpp, *tp;
        !            67:        time_t rtrip;
        !            68: 
        !            69:        struct hashbuf *htp;
        !            70:        struct namebuf *np;
        !            71:        struct netinfo *lp;
        !            72:        extern struct netinfo *local();
        !            73:        extern int nsid;
        !            74:        extern int addcount;
        !            75:        struct fwdinfo *fwd;
        !            76: 
        !            77: #ifdef STATS
        !            78:        stats[S_RESPONSES].cnt++;
        !            79: #endif
        !            80:        hp = (HEADER *) msg;
        !            81:        if ((qp = qfindid(hp->id)) == NULL ) {
        !            82: #ifdef DEBUG
        !            83:                if (debug > 1)
        !            84:                        fprintf(ddt,"DUP? dropped (id %d)\n", ntohs(hp->id));
        !            85: #endif
        !            86: #ifdef STATS
        !            87:                stats[S_DUPRESP].cnt++;
        !            88: #endif
        !            89:                return;
        !            90:        }
        !            91: 
        !            92: #ifdef DEBUG
        !            93:        if (debug >= 2)
        !            94:                fprintf(ddt,"%s response nsid=%d id=%d\n",
        !            95:                        qp->q_system ? "SYSTEM" : "USER",
        !            96:                        ntohs(qp->q_nsid), ntohs(qp->q_id));
        !            97: #endif
        !            98: 
        !            99:        /*
        !           100:         *  Here we handle bad responses from servers.
        !           101:         *  Several possibilities come to mind:
        !           102:         *      The server is sick and returns SERVFAIL
        !           103:         *      The server returns some garbage opcode (its sick)
        !           104:         *      The server can't understand our query and return FORMERR
        !           105:         *  In all these cases, we simply drop the packet and force
        !           106:         *  a retry.  This will make him look bad due to unresponsiveness.
        !           107:         *  Be sure not to include authoritative NXDOMAIN
        !           108:         */
        !           109:        if ((hp->rcode != NOERROR && hp->rcode != NXDOMAIN)
        !           110:            || (hp->rcode == NXDOMAIN && !hp->aa)
        !           111:            || hp->opcode != QUERY) {
        !           112: #ifdef DEBUG
        !           113:                if (debug >= 2)
        !           114:                        fprintf(ddt,"resp: error (ret %d, op %d), dropped\n",
        !           115:                                hp->rcode, hp->opcode);
        !           116: #endif
        !           117: #ifdef STATS
        !           118:                stats[S_BADRESPONSES].cnt++;
        !           119: #endif
        !           120:                return;
        !           121:        }
        !           122: 
        !           123: #ifdef ALLOW_UPDATES
        !           124:        if ( (hp->rcode == NOERROR) &&
        !           125:             (hp->opcode == UPDATEA || hp->opcode == UPDATED ||
        !           126:              hp->opcode == UPDATEDA || hp->opcode == UPDATEM ||
        !           127:              hp->opcode == UPDATEMA) ) {
        !           128:                /*
        !           129:                 * Update the secondary's copy, now that the primary
        !           130:                 * successfully completed the update.  Zone doesn't matter
        !           131:                 * for dyn. update -- doupdate calls findzone to find it
        !           132:                 */
        !           133:                doupdate(qp->q_msg, qp->q_msglen, qp->q_msg + sizeof(HEADER),
        !           134:                         0, (struct databuf *)0, 0);
        !           135: #ifdef DEBUG
        !           136:                if (debug >= 3)
        !           137:                        fprintf(ddt,"resp: leaving, UPDATE*\n");
        !           138: #endif
        !           139:                /* return code filled in by doupdate */
        !           140:                goto return_msg;
        !           141:        }
        !           142: #endif ALLOW_UPDATES
        !           143: 
        !           144:        /*
        !           145:         * Determine if the response came from a forwarder.  Packets from
        !           146:         * anyplace not listed as a forwarder or as a server to whom we
        !           147:         * might have forwarded the query will be dropped.
        !           148:         */
        !           149:        for (fwd = fwdtab; fwd != (struct fwdinfo *)NULL; fwd = fwd->next)
        !           150:                if (bcmp((char *)&fwd->fwdaddr.sin_addr, &from_addr.sin_addr,
        !           151:                    sizeof(struct in_addr)) == 0)
        !           152:                        break;
        !           153:        /*
        !           154:         * If we were using nameservers, find the qinfo pointer and update
        !           155:         * the rtt and fact that we have called on this server before.
        !           156:         */
        !           157:        if (fwd == (struct fwdinfo *)NULL) {
        !           158:                struct timeval *stp;
        !           159: 
        !           160:                for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++)
        !           161:                        if (bcmp((char *)&qs->ns_addr.sin_addr,
        !           162:                            &from_addr.sin_addr, sizeof(struct in_addr)) == 0)
        !           163:                                break;
        !           164:                if (n >= qp->q_naddr) {
        !           165: #ifdef DEBUG
        !           166:                        if (debug)
        !           167:                            fprintf(ddt, "Response from unexpected source %s\n",
        !           168:                                inet_ntoa(from_addr.sin_addr));
        !           169: #endif DEBUG
        !           170: #ifdef STATS
        !           171:                        stats[S_MARTIANS].cnt++;
        !           172: #endif
        !           173:                        /* 
        !           174:                         * We don't know who this response came from so it
        !           175:                         * gets dropped on the floor.
        !           176:                         */
        !           177:                        return;
        !           178:                }
        !           179:                stp = &qs->stime;
        !           180: 
        !           181:                /* Handle response from different (untried) interface */
        !           182:                if (stp->tv_sec == 0) {
        !           183:                        ns = qs->ns;
        !           184:                        while (qs > qp->q_addr &&
        !           185:                            (qs->stime.tv_sec == 0 || qs->ns != ns))
        !           186:                                qs--;
        !           187:                        *stp = qs->stime;
        !           188: #ifdef DEBUG
        !           189:                        if (debug)
        !           190:                            fprintf(ddt,
        !           191:                            "Response from unused address %s, assuming %s\n",
        !           192:                                inet_ntoa(from_addr.sin_addr),
        !           193:                                inet_ntoa(qs->ns_addr.sin_addr));
        !           194: #endif DEBUG
        !           195:                }
        !           196: 
        !           197:                /* compute query round trip time */
        !           198:                rtrip = ((tt.tv_sec - stp->tv_sec) * 1000 +
        !           199:                    (tt.tv_usec - stp->tv_usec) / 1000);
        !           200:                
        !           201: #ifdef DEBUG
        !           202:                if (debug > 2)
        !           203:                        fprintf(ddt,"stime %d/%d  now %d/%d rtt %d\n",
        !           204:                            stp->tv_sec, stp->tv_usec,
        !           205:                            tt.tv_sec, tt.tv_usec, rtrip);
        !           206: #endif
        !           207:                /* prevent floating point overflow, limit to 1000 sec */
        !           208:                if (rtrip > 1000000)
        !           209:                                rtrip = 1000000;
        !           210:                ns = qs->nsdata;
        !           211:                /*
        !           212:                 * Don't update nstime if this doesn't look
        !           213:                 * like an address databuf now.                 XXX
        !           214:                 */
        !           215:                if (ns->d_type == T_A && ns->d_class == qs->ns->d_class) {
        !           216:                        if (ns->d_nstime == 0)
        !           217:                                ns->d_nstime = (u_long)rtrip;
        !           218:                        else
        !           219:                                ns->d_nstime = ns->d_nstime * ALPHA +
        !           220:                                    (1-ALPHA) * (u_long)rtrip;
        !           221:                        /* prevent floating point overflow, limit to 1000 sec */
        !           222:                        if (ns->d_nstime > 1000000)
        !           223:                                ns->d_nstime = 1000000;
        !           224:                }
        !           225: 
        !           226:                /*
        !           227:                 * Record the source so that we do not use this NS again.
        !           228:                 */
        !           229:                if(qp->q_nusedns < NSMAX) {
        !           230:                        qp->q_usedns[qp->q_nusedns++] = qs->ns;
        !           231: #ifdef DEBUG
        !           232:                        if(debug > 1)
        !           233:                            fprintf(ddt, "NS #%d addr %s used, rtt %d\n",
        !           234:                                n, inet_ntoa(qs->ns_addr.sin_addr),
        !           235:                                ns->d_nstime);
        !           236: #endif DEBUG
        !           237:                }
        !           238: 
        !           239:                /*
        !           240:                 * Penalize those who had earlier chances but failed
        !           241:                 * by multiplying round-trip times by BETA (>1).
        !           242:                 * Improve nstime for unused addresses by applying GAMMA.
        !           243:                 * The GAMMA factor makes unused entries slowly
        !           244:                 * improve, so they eventually get tried again.
        !           245:                 * GAMMA should be slightly less than 1.
        !           246:                 * Watch out for records that may have timed out
        !           247:                 * and are no longer the correct type.                  XXX
        !           248:                 */
        !           249:                
        !           250:                for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++) {
        !           251:                        ns2 = qs->nsdata;
        !           252:                        if (ns2 == ns)
        !           253:                            continue;
        !           254:                        if (ns2->d_type != T_A ||
        !           255:                            ns2->d_class != qs->ns->d_class)    /* XXX */
        !           256:                                continue;
        !           257:                        if (qs->stime.tv_sec) {
        !           258:                            if (ns2->d_nstime == 0)
        !           259:                                ns2->d_nstime = rtrip * BETA;
        !           260:                            else
        !           261:                                ns2->d_nstime =
        !           262:                                    ns2->d_nstime * BETA + (1-ALPHA) * rtrip;
        !           263:                            if (ns2->d_nstime > 1000000)
        !           264:                                ns2->d_nstime = 1000000;
        !           265:                        } else
        !           266:                            ns2->d_nstime = ns2->d_nstime * GAMMA;
        !           267: #ifdef DEBUG
        !           268:                        if(debug > 1)
        !           269:                            fprintf(ddt, "NS #%d %s rtt now %d\n", n,
        !           270:                                inet_ntoa(qs->ns_addr.sin_addr),
        !           271:                                ns2->d_nstime);
        !           272: #endif DEBUG
        !           273:                }
        !           274:        }
        !           275: 
        !           276:        /*
        !           277:         * Skip query section
        !           278:         */
        !           279:        addcount = 0;
        !           280:        cp = msg + sizeof(HEADER);
        !           281:        dpp = dnptrs;
        !           282:        *dpp++ = msg;
        !           283:        if ((*cp & INDIR_MASK) == 0)
        !           284:                *dpp++ = cp;
        !           285:        *dpp = NULL;
        !           286:        if (hp->qdcount) {
        !           287:                n = dn_skipname(cp, msg + msglen);
        !           288:                if (n <= 0)
        !           289:                        goto formerr;
        !           290:                cp += n;
        !           291:                GETSHORT(type, cp);
        !           292:                GETSHORT(class, cp);
        !           293:                if (cp - msg > msglen)
        !           294:                        goto formerr;
        !           295:        }
        !           296: 
        !           297:        /*
        !           298:         * Save answers, authority, and additional records for future use.
        !           299:         */
        !           300:        ancount = ntohs(hp->ancount);
        !           301:        aucount = ntohs(hp->nscount);
        !           302:        arcount = ntohs(hp->arcount);
        !           303:        nscount = 0;
        !           304:        tp = cp;
        !           305: #ifdef DEBUG
        !           306:        if (debug >= 3)
        !           307:                fprintf(ddt,"resp: ancount %d, aucount %d, arcount %d\n",
        !           308:                        ancount, aucount, arcount);
        !           309: #endif
        !           310: 
        !           311:        /*
        !           312:         *  If there's an answer, check if it's a CNAME response;
        !           313:         *  if no answer but aucount > 0, see if there is an NS
        !           314:         *  or just an SOA.  (NOTE: ancount might be 1 with a CNAME,
        !           315:         *  and NS records may still be in the authority section;
        !           316:         *  we don't bother counting them, as we only use nscount
        !           317:         *  if ancount == 0.)
        !           318:         */
        !           319:        if (ancount == 1 || (ancount == 0 && aucount > 0)) {
        !           320:                c = aucount;
        !           321:                do {
        !           322:                        if (tp - msg >= msglen)
        !           323:                                goto formerr;
        !           324:                        n = dn_skipname(tp, msg + msglen);
        !           325:                        if (n <= 0)
        !           326:                                goto formerr;
        !           327:                        tp += n;                /* name */
        !           328:                        GETSHORT(i, tp);        /* type */
        !           329:                        tp += sizeof(u_short);  /* class */
        !           330:                        tp += sizeof(u_long);   /* ttl */
        !           331:                        GETSHORT(count, tp);    /* dlen */
        !           332:                        if (tp - msg > msglen - count)
        !           333:                                goto formerr;
        !           334:                        tp += count;
        !           335:                        if (ancount && i == T_CNAME) {
        !           336:                                cname++;
        !           337: #ifdef DEBUG
        !           338:                                if (debug)
        !           339:                                        fprintf(ddt,"CNAME - needs more processing\n");
        !           340: #endif
        !           341:                                if (!qp->q_cmsglen) {
        !           342:                                        qp->q_cmsg = qp->q_msg;
        !           343:                                        qp->q_cmsglen = qp->q_msglen;
        !           344:                                        qp->q_msg = NULL;
        !           345:                                        qp->q_msglen = 0;
        !           346:                                }
        !           347:                        }
        !           348:                        /*
        !           349:                         * See if authority record is a nameserver.
        !           350:                         */
        !           351:                        if (ancount == 0 && i == T_NS)
        !           352:                                nscount++;
        !           353:                } while (--c > 0);
        !           354:                tp = cp;
        !           355:        }
        !           356: 
        !           357:        /*
        !           358:         * Add the info received in the response to the Data Base
        !           359:         */
        !           360:        c = ancount + aucount + arcount;
        !           361: #ifdef notdef
        !           362:        /*
        !           363:         * If the request was for a CNAME that doesn't exist,
        !           364:         * but the name is valid, fetch any other data for the name.
        !           365:         * DON'T do this now, as it will requery if data are already
        !           366:         * in the cache (maybe later with negative caching).
        !           367:         */
        !           368:        if (hp->qdcount && type == T_CNAME && c == 0 && hp->rcode == NOERROR &&
        !           369:           !qp->q_system) {
        !           370: #ifdef DEBUG
        !           371:                if (debug >= 3)
        !           372:                        fprintf(ddt,"resp: leaving, no CNAME\n");
        !           373: #endif
        !           374:                /* Cause us to put it in the cache later */
        !           375:                prime(class, T_ANY, qp);
        !           376: 
        !           377:                /* Nothing to store, just give user the answer */
        !           378:                goto return_msg;
        !           379:        }
        !           380: #endif /* notdef */
        !           381: 
        !           382:        nspp = nsp;
        !           383:        if (qp->q_system)
        !           384:                dbflags = DB_NOTAUTH | DB_NODATA;
        !           385:        else
        !           386:                dbflags = DB_NOTAUTH | DB_NODATA | DB_NOHINTS;
        !           387:        for (i = 0; i < c; i++) {
        !           388:                struct databuf *ns3;
        !           389: 
        !           390:                if (cp >= msg + msglen)
        !           391:                        goto formerr;
        !           392:                ns3 = 0;
        !           393:                if ((n = doupdate(msg, msglen, cp, 0, &ns3, dbflags)) < 0) {
        !           394: #ifdef DEBUG
        !           395:                        if (debug)
        !           396:                            fprintf(ddt,"resp: leaving, doupdate failed\n");
        !           397: #endif
        !           398:                        /* return code filled in by doupdate */
        !           399:                        goto return_msg;
        !           400:                }
        !           401:                /*
        !           402:                 * Remember nameservers from the authority section
        !           403:                 * for referrals.
        !           404:                 * (This is usually overwritten by findns below(?). XXX
        !           405:                 */
        !           406:                if (ns3 && i >= ancount && i < ancount + aucount &&
        !           407:                    nspp < &nsp[NSMAX-1])
        !           408:                        *nspp++ = ns3;
        !           409:                cp += n;
        !           410:        }
        !           411: 
        !           412:        if (qp->q_system && ancount) {
        !           413:                if (qp->q_system == PRIMING_CACHE)
        !           414:                        check_root();
        !           415: #ifdef DEBUG
        !           416:                if (debug > 2)
        !           417:                        fprintf(ddt,"resp: leaving, SYSQUERY ancount %d\n", ancount);
        !           418: #endif
        !           419:                qremove(qp);
        !           420:                return;
        !           421:        }
        !           422: 
        !           423:        if (cp > msg + msglen)
        !           424:                goto formerr;
        !           425: 
        !           426:        /*
        !           427:         *  If there are addresses and this is a local query,
        !           428:         *  sort them appropriately for the local context.
        !           429:         */
        !           430:        if (ancount > 1 && (lp = local(&qp->q_from)) != NULL) 
        !           431:                sort_response(tp, ancount, lp, msg + msglen);
        !           432: 
        !           433:        /*
        !           434:         * An answer to a T_ANY query or a successful answer to a
        !           435:         * regular query with no indirection, then just return answer.
        !           436:         */
        !           437:        if ((hp->qdcount && type == T_ANY && ancount) ||
        !           438:            (!cname && !qp->q_cmsglen && ancount)) {
        !           439: #ifdef DEBUG
        !           440:                if (debug >= 3)
        !           441:                        fprintf(ddt,"resp: got as much answer as there is\n");
        !           442: #endif
        !           443:                goto return_msg;
        !           444:        }
        !           445: 
        !           446:        /*
        !           447:         * Eventually we will want to cache this negative answer.
        !           448:         */
        !           449:        if (ancount == 0 && nscount == 0 &&
        !           450:            (hp->aa || fwd || class == C_ANY)) {
        !           451:                /* We have an authoritative NO */
        !           452: #ifdef DEBUG
        !           453:                if (debug >= 3)
        !           454:                        fprintf(ddt,"resp: leaving auth NO\n");
        !           455: #endif
        !           456:                if (qp->q_cmsglen) {
        !           457:                        msg = (u_char *)qp->q_cmsg;
        !           458:                        msglen = qp->q_cmsglen;
        !           459:                        hp = (HEADER *)msg;
        !           460:                }
        !           461:                goto return_msg;
        !           462:        }
        !           463: 
        !           464:        /*
        !           465:         * All messages in here need further processing.  i.e. they
        !           466:         * are either CNAMEs or we got referred again.
        !           467:         */
        !           468:        count = 0;
        !           469:        founddata = 0;
        !           470:        foundname = 0;
        !           471:        dname = name;
        !           472:        if (!cname && qp->q_cmsglen && ancount) {
        !           473: #ifdef DEBUG
        !           474:                if (debug)
        !           475:                        fprintf(ddt,"Cname second pass\n");
        !           476: #endif
        !           477:                newmsglen = qp->q_cmsglen;
        !           478:                bcopy(qp->q_cmsg, newmsg, newmsglen);
        !           479:        } else {
        !           480:                newmsglen = msglen;
        !           481:                bcopy(msg, newmsg, newmsglen);
        !           482:        }
        !           483:        hp = (HEADER *) newmsg;
        !           484:        hp->ancount = 0;
        !           485:        hp->nscount = 0;
        !           486:        hp->arcount = 0;
        !           487:        dnptrs[0] = newmsg;
        !           488:        dnptrs[1] = NULL;
        !           489:        cp = newmsg + sizeof(HEADER);
        !           490:        if (cname)
        !           491:                cp += dn_skipname(cp, newmsg + newmsglen) + QFIXEDSZ;
        !           492:        if ((n = dn_expand(newmsg, newmsg + newmsglen,
        !           493:                cp, dname, sizeof(name))) < 0) {
        !           494: #ifdef DEBUG
        !           495:                if (debug)
        !           496:                        fprintf(ddt,"dn_expand failed\n" );
        !           497: #endif
        !           498:                goto servfail;
        !           499:        }
        !           500:        if (!cname)
        !           501:                cp += n + QFIXEDSZ;
        !           502:        buflen = sizeof(newmsg) - (cp - newmsg);
        !           503: 
        !           504: try_again:
        !           505: #ifdef DEBUG
        !           506:        if (debug)
        !           507:                fprintf(ddt,"resp: nlookup(%s) type=%d\n",dname, type);
        !           508: #endif
        !           509:        fname = "";
        !           510:        htp = hashtab;          /* lookup relative to root */
        !           511:        np = nlookup(dname, &htp, &fname, 0);
        !           512: #ifdef DEBUG
        !           513:        if (debug)
        !           514:                fprintf(ddt,"resp: %s '%s' as '%s' (cname=%d)\n",
        !           515:                        np == NULL ? "missed" : "found", dname, fname, cname);
        !           516: #endif
        !           517:        if (np == NULL || fname != dname)
        !           518:                goto fetch_ns;
        !           519: 
        !           520:        foundname++;
        !           521:        count = cp - newmsg;
        !           522:        n = finddata(np, class, type, hp, &dname, &buflen, &count);
        !           523:        if (n == 0)
        !           524:                goto fetch_ns;          /* NO data available */
        !           525:        cp += n;
        !           526:        buflen -= n;
        !           527:        hp->ancount += count;
        !           528:        if (fname != dname && type != T_CNAME && type != T_ANY) {
        !           529:                cname++;
        !           530:                goto try_again;
        !           531:        }
        !           532:        founddata = 1;
        !           533: 
        !           534: #ifdef DEBUG
        !           535:        if (debug >= 3) {
        !           536:            fprintf(ddt,"resp: foundname = %d count = %d ", foundname, count);
        !           537:            fprintf(ddt,"founddata = %d cname = %d\n", founddata, cname);
        !           538:        }
        !           539: #endif
        !           540: 
        !           541: fetch_ns:
        !           542:        hp->ancount = htons(hp->ancount);
        !           543:        /*
        !           544:         * Look for name servers to refer to and fill in the authority
        !           545:         * section or record the address for forwarding the query
        !           546:         * (recursion desired).
        !           547:         */
        !           548:        switch (findns(&np, class, nsp, &count)) {
        !           549:        case NXDOMAIN:          /* shouldn't happen */
        !           550: #ifdef DEBUG
        !           551:                if (debug >= 3)
        !           552:                        fprintf(ddt,"req: leaving (%s, rcode %d)\n",
        !           553:                                dname, hp->rcode);
        !           554: #endif
        !           555:                if (!foundname)
        !           556:                        hp->rcode = NXDOMAIN;
        !           557:                if (class != C_ANY) {
        !           558:                        hp->aa = 1;
        !           559:                        /*
        !           560:                         * should return SOA if founddata == 0,
        !           561:                         * but old named's are confused by an SOA
        !           562:                         * in the auth. section if there's no error.
        !           563:                         */
        !           564:                        if (foundname == 0 && np) {
        !           565:                            n = doaddauth(hp, cp, buflen, np, nsp[0]);
        !           566:                            cp += n;
        !           567:                            buflen -= n;
        !           568:                        }
        !           569:                }
        !           570:                goto return_newmsg;
        !           571: 
        !           572:        case SERVFAIL:
        !           573:                goto servfail;
        !           574:        }
        !           575: 
        !           576:        if (founddata) {
        !           577:                hp = (HEADER *)newmsg;
        !           578:                n = add_data(np, nsp, cp, buflen);
        !           579:                if (n < 0) {
        !           580:                        hp->tc = 1;
        !           581:                        n = (-n);
        !           582:                }
        !           583:                cp += n;
        !           584:                buflen -= n;
        !           585:                hp->nscount = htons((u_short)count);
        !           586:                goto return_newmsg;
        !           587:        }
        !           588: 
        !           589:        /*
        !           590:         *  If we get here, we don't have the answer yet and are about
        !           591:         *  to iterate to try and get it.  First, infinite loop avoidance.
        !           592:         */
        !           593:        if (qp->q_nqueries++ > MAXQUERIES) {
        !           594: #ifdef DEBUG
        !           595:                if (debug)
        !           596:                    fprintf(ddt,"resp: MAXQUERIES exceeded (%s, class %d, type %d)\n",
        !           597:                        dname, class, type);
        !           598: #endif
        !           599:                syslog(LOG_NOTICE,
        !           600:                            "MAXQUERIES exceeded, possible data loop in resolving (%s)",
        !           601:                            dname);
        !           602:                goto servfail;
        !           603:        }
        !           604: 
        !           605:        /* Reset the query control structure */
        !           606:        qp->q_naddr = 0;
        !           607:        qp->q_curaddr = 0;
        !           608:        qp->q_fwd = fwdtab;
        !           609:        if (nslookup(nsp, qp) == 0) {
        !           610: #ifdef DEBUG
        !           611:                if (debug >= 3)
        !           612:                        fprintf(ddt,"resp: no addrs found for NS's\n");
        !           613: #endif
        !           614:                goto servfail;
        !           615:        }
        !           616:        for (n = 0; n < qp->q_naddr; n++)
        !           617:                qp->q_addr[n].stime.tv_sec = 0;
        !           618:        if (!qp->q_fwd)
        !           619:                qp->q_addr[0].stime = tt;
        !           620:        if (cname) {
        !           621:                if (qp->q_cname++ == MAXCNAMES) {
        !           622: #ifdef DEBUG
        !           623:                        if (debug >= 3)
        !           624:                                fprintf(ddt,"resp: leaving, MAXCNAMES exceeded\n");
        !           625: #endif
        !           626:                        goto servfail;
        !           627:                }
        !           628: #ifdef DEBUG
        !           629:                if (debug)
        !           630:                        fprintf(ddt,"q_cname = %d\n",qp->q_cname);
        !           631:                if (debug >= 3)
        !           632:                       fprintf(ddt,"resp: building recursive query; nslookup\n");
        !           633: #endif
        !           634:                if (qp->q_msg)
        !           635:                        (void) free(qp->q_msg);
        !           636:                if ((qp->q_msg = malloc(BUFSIZ)) == NULL) {
        !           637: #ifdef DEBUG
        !           638:                        if (debug)
        !           639:                                fprintf(ddt,"resp: malloc error\n");
        !           640: #endif
        !           641:                        goto servfail;
        !           642:                }
        !           643:                qp->q_msglen = res_mkquery(QUERY, dname, class,
        !           644:                    type, (char *)NULL, 0, NULL, qp->q_msg, BUFSIZ);
        !           645:                hp = (HEADER *) qp->q_msg;
        !           646:                hp->rd = 0;
        !           647:        } else
        !           648:                hp = (HEADER *)qp->q_msg;
        !           649:        hp->id = qp->q_nsid = htons((u_short)++nsid);
        !           650:        if (qp->q_fwd)
        !           651:                hp->rd = 1;
        !           652:        unsched(qp);
        !           653:        schedretry(qp, retrytime(qp));
        !           654: #ifdef DEBUG
        !           655:        if (debug)
        !           656:                fprintf(ddt,"resp: forw -> %s %d (%d) nsid=%d id=%d %dms\n",
        !           657:                        inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr),
        !           658:                        ds, ntohs(Q_NEXTADDR(qp,0)->sin_port),
        !           659:                        ntohs(qp->q_nsid), ntohs(qp->q_id),
        !           660:                        qp->q_addr[0].nsdata->d_nstime);
        !           661:        if ( debug >= 10)
        !           662:                fp_query(msg, ddt);
        !           663: #endif
        !           664:        if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
        !           665:                (struct sockaddr *)Q_NEXTADDR(qp,0),
        !           666:                sizeof(struct sockaddr_in)) < 0) {
        !           667: #ifdef DEBUG
        !           668:                if (debug >= 5)
        !           669:                        fprintf(ddt, "sendto error = %d\n", errno);
        !           670: #endif
        !           671:        }
        !           672:        hp->rd = 0;     /* leave set to 0 for dup detection */
        !           673: #ifdef STATS
        !           674:        stats[S_OUTPKTS].cnt++;
        !           675: #endif
        !           676: #ifdef DEBUG
        !           677:        if (debug >= 3)
        !           678:                fprintf(ddt,"resp: Query sent.\n");
        !           679: #endif
        !           680:        return;
        !           681: 
        !           682: formerr:
        !           683: #ifdef DEBUG
        !           684:        if (debug)
        !           685:            fprintf(ddt,"FORMERR resp() from %s size err %d, msglen %d\n",
        !           686:                inet_ntoa(from_addr.sin_addr),
        !           687:                cp-msg, msglen);
        !           688: #endif
        !           689:        syslog(LOG_INFO, "Malformed response from %s\n",
        !           690:                inet_ntoa(from_addr.sin_addr));
        !           691: #ifdef STATS
        !           692:        stats[S_RESPFORMERR].cnt++;
        !           693: #endif
        !           694:        return;
        !           695: 
        !           696: return_msg:
        !           697: #ifdef STATS
        !           698:        stats[S_RESPOK].cnt++;
        !           699: #endif
        !           700:        /* The "standard" return code */
        !           701:        hp->qr = 1;
        !           702:        hp->id = qp->q_id;
        !           703:        hp->rd = 1;
        !           704:        hp->ra = 1;
        !           705:        (void) send_msg(msg, msglen, qp);
        !           706:        qremove(qp);
        !           707:        return;
        !           708: 
        !           709: return_newmsg:
        !           710: #ifdef STATS
        !           711:        stats[S_RESPOK].cnt++;
        !           712: #endif
        !           713:        if (addcount) {
        !           714:                n = doaddinfo(hp, cp, buflen);
        !           715:                cp += n;
        !           716:                buflen -= n;
        !           717:        }
        !           718: 
        !           719:        hp->id = qp->q_id;
        !           720:        hp->rd = 1;
        !           721:        hp->ra = 1;
        !           722:        hp->qr = 1;
        !           723:        (void) send_msg(newmsg, cp - newmsg, qp);
        !           724:        qremove(qp);
        !           725:        return;
        !           726: 
        !           727: servfail:
        !           728: #ifdef STATS
        !           729:        stats[S_RESPFAIL].cnt++;
        !           730: #endif
        !           731:        hp = (HEADER *)(cname ? qp->q_cmsg : qp->q_msg);
        !           732:        hp->rcode = SERVFAIL;
        !           733:        hp->id = qp->q_id;
        !           734:        hp->rd = 1;
        !           735:        hp->ra = 1;
        !           736:        hp->qr = 1;
        !           737:        (void) send_msg((char *)hp, (cname ? qp->q_cmsglen : qp->q_msglen), qp);
        !           738:        qremove(qp);
        !           739:        return;
        !           740: }
        !           741: 
        !           742: /*
        !           743:  * Decode the resource record 'rrp' and update the database.
        !           744:  * If savens is true, record pointer for forwarding queries a second time.
        !           745:  */
        !           746: doupdate(msg, msglen, rrp, zone, savens, flags)
        !           747:        char *msg;
        !           748:        u_char *rrp;
        !           749:        struct databuf **savens;
        !           750:        int  msglen, zone, flags;
        !           751: {
        !           752:        register u_char *cp;
        !           753:        register int n;
        !           754:        int class, type, dlen, n1;
        !           755:        u_long ttl;
        !           756:        struct databuf *dp;
        !           757:        char dname[MAXDNAME];
        !           758:        u_char *cp1;
        !           759:        u_char data[BUFSIZ];
        !           760:        register HEADER *hp = (HEADER *) msg;
        !           761: #ifdef ALLOW_UPDATES
        !           762:        int zonenum;
        !           763: #endif
        !           764: 
        !           765: #ifdef DEBUG
        !           766:        if (debug > 2)
        !           767:                fprintf(ddt,"doupdate(zone %d, savens %x, flags %x)\n",
        !           768:                        zone, savens, flags);
        !           769: #endif
        !           770: 
        !           771:        cp = rrp;
        !           772:        if ((n = dn_expand(msg, msg + msglen, cp, dname, sizeof(dname))) < 0) {
        !           773:                hp->rcode = FORMERR;
        !           774:                return (-1);
        !           775:        }
        !           776:        cp += n;
        !           777:        GETSHORT(type, cp);
        !           778:        GETSHORT(class, cp);
        !           779:        GETLONG(ttl, cp);
        !           780:        GETSHORT(dlen, cp);
        !           781: #ifdef DEBUG
        !           782:        if (debug > 2)
        !           783:                fprintf(ddt,"doupdate: dname %s type %d class %d ttl %d\n",
        !           784:                        dname, type, class, ttl);
        !           785: #endif
        !           786:        /*
        !           787:         * Convert the resource record data into the internal
        !           788:         * database format.
        !           789:         */
        !           790:        switch (type) {
        !           791:        case T_A:
        !           792:        case T_WKS:
        !           793:        case T_HINFO:
        !           794:        case T_UINFO:
        !           795:        case T_UID:
        !           796:        case T_GID:
        !           797:        case T_TXT:
        !           798: #ifdef ALLOW_T_UNSPEC
        !           799:        case T_UNSPEC:
        !           800: #endif ALLOW_T_UNSPEC
        !           801:                cp1 = cp;
        !           802:                n = dlen;
        !           803:                cp += n;
        !           804:                break;
        !           805: 
        !           806:        case T_CNAME:
        !           807:        case T_MB:
        !           808:        case T_MG:
        !           809:        case T_MR:
        !           810:        case T_NS:
        !           811:        case T_PTR:
        !           812:                if ((n = dn_expand(msg, msg + msglen, cp, data,
        !           813:                   sizeof(data))) < 0) {
        !           814:                        hp->rcode = FORMERR;
        !           815:                        return (-1);
        !           816:                }
        !           817:                cp += n;
        !           818:                cp1 = data;
        !           819:                n = strlen(data) + 1;
        !           820:                break;
        !           821: 
        !           822:        case T_MINFO:
        !           823:        case T_SOA:
        !           824:                if ((n = dn_expand(msg, msg + msglen, cp, data,
        !           825:                    sizeof(data))) < 0) {
        !           826:                        hp->rcode = FORMERR;
        !           827:                        return (-1);
        !           828:                }
        !           829:                cp += n;
        !           830:                cp1 = data + (n = strlen(data) + 1);
        !           831:                n1 = sizeof(data) - n;
        !           832:                if (type == T_SOA)
        !           833:                        n1 -= 5 * sizeof(u_long);
        !           834:                if ((n = dn_expand(msg, msg + msglen, cp, cp1, n1)) < 0) {
        !           835:                        hp->rcode = FORMERR;
        !           836:                        return (-1);
        !           837:                }
        !           838:                cp += n;
        !           839:                cp1 += strlen(cp1) + 1;
        !           840:                if (type == T_SOA) {
        !           841:                        bcopy(cp, cp1, n = 5 * sizeof(u_long));
        !           842:                        cp += n;
        !           843:                        cp1 += n;
        !           844:                }
        !           845:                n = cp1 - data;
        !           846:                cp1 = data;
        !           847:                break;
        !           848: 
        !           849:        case T_MX:
        !           850:                /* grab preference */
        !           851:                bcopy(cp,data,sizeof(u_short));
        !           852:                cp1 = data + sizeof(u_short);
        !           853:                cp += sizeof(u_short);
        !           854: 
        !           855:                /* get name */
        !           856:                if ((n = dn_expand(msg, msg + msglen, cp, cp1,
        !           857:                    sizeof(data)-sizeof(u_short))) < 0)
        !           858:                        return(-1);
        !           859:                cp += n;
        !           860: 
        !           861:                /* compute end of data */
        !           862:                cp1 += strlen(cp1) + 1;
        !           863:                /* compute size of data */
        !           864:                n = cp1 - data;
        !           865:                cp1 = data;
        !           866:                break;
        !           867: 
        !           868:        default:
        !           869: #ifdef DEBUG
        !           870:                if (debug >= 3)
        !           871:                        fprintf(ddt,"unknown type %d\n", type);
        !           872: #endif
        !           873:                return ((cp - rrp) + dlen);
        !           874:        }
        !           875:        if (n > MAXDATA) {
        !           876: #ifdef DEBUG
        !           877:                if (debug)
        !           878:                    fprintf(ddt,
        !           879:                        "update type %d: %d bytes is too much data\n",
        !           880:                        type, n);
        !           881: #endif
        !           882:                hp->rcode = NOCHANGE;   /* XXX - FORMERR ??? */
        !           883:                return(-1);
        !           884:        }
        !           885: 
        !           886: #ifdef ALLOW_UPDATES
        !           887:        /*
        !           888:         * If this is a dynamic update request, process it specially; else,
        !           889:         * execute normal update code.
        !           890:         */
        !           891:        switch(hp->opcode) {
        !           892: 
        !           893:        /* For UPDATEM and UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA */
        !           894:        case UPDATEM:
        !           895:        case UPDATEMA:
        !           896: 
        !           897:        /*
        !           898:         * The named code for UPDATED and UPDATEDA is the same except that for
        !           899:         * UPDATEDA we we ignore any data that was passed: we just delete all
        !           900:         * RRs whose name, type, and class matches
        !           901:         */
        !           902:        case UPDATED:
        !           903:        case UPDATEDA:
        !           904:                if (type == T_SOA) {    /* Not allowed */
        !           905: #ifdef DEBUG
        !           906:                        if (debug)
        !           907:                           fprintf(ddt, "UDPATE: REFUSED - SOA delete\n");
        !           908: #endif
        !           909:                        hp->rcode = REFUSED;
        !           910:                        return(-1);
        !           911:                }
        !           912:                /*
        !           913:                 * Don't check message length if doing UPDATEM/UPDATEMA,
        !           914:                 * since the whole message wont have been demarshalled until
        !           915:                 * we reach the code for UPDATEA
        !           916:                 */
        !           917:                if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEDA) ) {
        !           918:                        if (cp != (u_char *)(msg + msglen)) {
        !           919: #ifdef DEBUG
        !           920:                            if (debug)
        !           921:                                fprintf(ddt,"FORMERR UPDATE message length off\n");
        !           922: #endif
        !           923:                            hp->rcode = FORMERR;
        !           924:                            return(-1);
        !           925:                        }
        !           926:                }
        !           927:                if ((zonenum = findzone(dname, class)) == 0) { 
        !           928:                        hp->rcode = NXDOMAIN;
        !           929:                        return(-1);
        !           930:                }
        !           931:                if (zones[zonenum].z_state & Z_DYNADDONLY) {
        !           932:                        hp->rcode = NXDOMAIN;
        !           933:                        return(-1);
        !           934:                }
        !           935:                if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEM) ) {
        !           936:                        /* Make a dp for use in db_update, as old dp */
        !           937:                        dp = savedata(class, type, 0, cp1, n);
        !           938:                        dp->d_zone = zonenum;
        !           939:                        n = db_update(dname, dp, NULL, DB_MEXIST | DB_DELETE,
        !           940:                                      hashtab);
        !           941:                        if (n != OK) {
        !           942: #ifdef DEBUG
        !           943:                                if (debug)
        !           944:                                    fprintf(ddt,"UPDATE: db_update failed\n");
        !           945: #endif DEBUG
        !           946:                                free( (struct databuf *) dp);
        !           947:                                hp->rcode = NOCHANGE;
        !           948:                                return(-1);
        !           949:                        }
        !           950:                } else {        /* UPDATEDA or UPDATEMA */
        !           951:                        int DeletedOne = 0;
        !           952:                        /* Make a dp for use in db_update, as old dp */
        !           953:                        dp = savedata(class, type, 0, NULL, 0);
        !           954:                        dp->d_zone = zonenum;
        !           955:                        do {    /* Loop and delete all matching RR(s) */
        !           956:                                n = db_update(dname, dp, NULL, DB_DELETE,
        !           957:                                              hashtab);
        !           958:                                if (n != OK)
        !           959:                                        break;
        !           960:                                DeletedOne++;
        !           961:                        } while (1);
        !           962:                        free( (struct databuf *) dp);
        !           963:                        /* Ok for UPDATEMA not to have deleted any RRs */
        !           964:                        if (!DeletedOne && hp->opcode == UPDATEDA) {
        !           965: #ifdef DEBUG
        !           966:                                if (debug)
        !           967:                                        fprintf(ddt,"UPDATE: db_update failed\n");
        !           968: #endif DEBUG
        !           969:                                hp->rcode = NOCHANGE;
        !           970:                                return(-1);
        !           971:                        }
        !           972:                }
        !           973:                if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEDA) )
        !           974:                        return (cp - rrp);;
        !           975:                /*
        !           976:                 * Else unmarshal the RR to be added and continue on to
        !           977:                 * UPDATEA code for UPDATEM/UPDATEMA
        !           978:                 */
        !           979:                if ((n =
        !           980:                   dn_expand(msg, msg+msglen, cp, dname, sizeof(dname))) < 0) {
        !           981: #ifdef DEBUG
        !           982:                        if (debug)
        !           983:                            fprintf(ddt,"FORMERR UPDATE expand name failed\n");
        !           984: #endif
        !           985:                        hp->rcode = FORMERR;
        !           986:                        return(-1);
        !           987:                }
        !           988:                cp += n;
        !           989:                GETSHORT(type, cp);
        !           990:                GETSHORT(class, cp);
        !           991:                GETLONG(ttl, cp);
        !           992:                GETSHORT(n, cp);
        !           993:                cp1 = cp;
        !           994: /**** XXX - need bounds checking here ****/
        !           995:                cp += n;
        !           996: 
        !           997:        case UPDATEA:
        !           998:                if (n > MAXDATA) {
        !           999: #ifdef DEBUG
        !          1000:                        if (debug)
        !          1001:                            fprintf(ddt,"UPDATE: too much data\n");
        !          1002: #endif
        !          1003:                        hp->rcode = NOCHANGE;
        !          1004:                        return(-1);
        !          1005:                }
        !          1006:                if (cp != (u_char *)(msg + msglen)) {
        !          1007: #ifdef DEBUG
        !          1008:                        if (debug)
        !          1009:                            fprintf(ddt,"FORMERR UPDATE message length off\n");
        !          1010: #endif
        !          1011:                        hp->rcode = FORMERR;
        !          1012:                        return(-1);
        !          1013:                }
        !          1014:                if ((zonenum = findzone(dname, class)) == 0) { 
        !          1015:                        hp->rcode = NXDOMAIN;
        !          1016:                        return(-1);
        !          1017:                }
        !          1018:                if (zones[zonenum].z_state & Z_DYNADDONLY) {
        !          1019:                        struct hashbuf *htp = hashtab;
        !          1020:                        char *fname;
        !          1021:                        if (nlookup(dname, &htp, &fname, 0) &&
        !          1022:                            !strcmp(dname, fname)) {
        !          1023: #ifdef DEBUG
        !          1024:                            if (debug)
        !          1025:                                fprintf(ddt,"refusing add of existing name\n");
        !          1026: #endif
        !          1027:                            hp->rcode = REFUSED;
        !          1028:                            return(-1);
        !          1029:                        }
        !          1030:                }
        !          1031:                dp = savedata(class, type, ttl, cp1, n);
        !          1032:                dp->d_zone = zonenum;
        !          1033:                if ((n = db_update(dname, NULL, dp, DB_NODATA,
        !          1034:                                   hashtab)) != OK) {
        !          1035: #ifdef DEBUG
        !          1036:                        if (debug)
        !          1037:                                fprintf(ddt,"UPDATE: db_update failed\n");
        !          1038: #endif
        !          1039:                        hp->rcode = NOCHANGE;
        !          1040:                        return (-1);
        !          1041:                }
        !          1042:                else
        !          1043:                        return (cp - rrp);
        !          1044:        }
        !          1045: #endif ALLOW_UPDATES
        !          1046: 
        !          1047:        if (zone == 0)
        !          1048:                ttl += tt.tv_sec;
        !          1049:        dp = savedata(class, type, ttl, cp1, n);
        !          1050:        dp->d_zone = zone;
        !          1051:        if ((n = db_update(dname, dp, dp, flags, hashtab)) < 0) {
        !          1052: #ifdef DEBUG
        !          1053:                if (debug && (n != DATAEXISTS))
        !          1054:                        fprintf(ddt,"update failed (%d)\n", n);
        !          1055:                else if (debug >= 3)
        !          1056:                        fprintf(ddt,"update failed (DATAEXISTS)\n");
        !          1057: #endif
        !          1058:                (void) free((char *)dp);
        !          1059:        } else if (type == T_NS && savens != NULL)
        !          1060:                *savens = dp;
        !          1061:        return (cp - rrp);
        !          1062: }
        !          1063: 
        !          1064: send_msg(msg, msglen, qp)
        !          1065:        char *msg;
        !          1066:        int msglen;
        !          1067:        struct qinfo *qp;
        !          1068: {
        !          1069:        extern struct qinfo *qhead;
        !          1070: #ifdef DEBUG
        !          1071:        struct qinfo *tqp;
        !          1072: #endif DEBUG
        !          1073: 
        !          1074:        if (qp->q_system)
        !          1075:                return(1);
        !          1076: #ifdef DEBUG
        !          1077:        if (debug) {
        !          1078:                fprintf(ddt,"send_msg -> %s (%s %d %d) id=%d\n",
        !          1079:                        inet_ntoa(qp->q_from.sin_addr), 
        !          1080:                        qp->q_stream == QSTREAM_NULL ? "UDP" : "TCP",
        !          1081:                        qp->q_stream == QSTREAM_NULL ? qp->q_dfd
        !          1082:                                                     : qp->q_stream->s_rfd,
        !          1083:                        ntohs(qp->q_from.sin_port),
        !          1084:                        ntohs(qp->q_id));
        !          1085:        }
        !          1086:        if (debug>4)
        !          1087:                for (tqp = qhead; tqp!=QINFO_NULL; tqp = tqp->q_link) {
        !          1088:                    fprintf(ddt, "qp %x q_id: %d  q_nsid: %d q_msglen: %d ",
        !          1089:                        tqp, tqp->q_id,tqp->q_nsid,tqp->q_msglen);
        !          1090:                    fprintf(ddt,"q_naddr: %d q_curaddr: %d\n", tqp->q_naddr,
        !          1091:                        tqp->q_curaddr);
        !          1092:                    fprintf(ddt,"q_next: %x q_link: %x\n", qp->q_next,
        !          1093:                         qp->q_link);
        !          1094:                }
        !          1095:        if (debug >= 10)
        !          1096:                fp_query(msg, ddt);
        !          1097: #endif DEBUG
        !          1098:        if (qp->q_stream == QSTREAM_NULL) {
        !          1099:                if (sendto(qp->q_dfd, msg, msglen, 0,
        !          1100:                    (struct sockaddr *)&qp->q_from, sizeof(qp->q_from)) < 0) {
        !          1101: #ifdef DEBUG
        !          1102:                        if (debug)
        !          1103:                                fprintf(ddt, "sendto error errno= %d\n",errno);
        !          1104: #endif
        !          1105:                        return(1);
        !          1106:                }
        !          1107: #ifdef STATS
        !          1108:                stats[S_OUTPKTS].cnt++;
        !          1109: #endif
        !          1110:        } else {
        !          1111:                (void) writemsg(qp->q_stream->s_rfd, msg, msglen);
        !          1112:                sq_done(qp->q_stream);
        !          1113:        }
        !          1114:        return(0);
        !          1115: }
        !          1116: 
        !          1117: prime(class, type, oqp)
        !          1118:        int class, type;
        !          1119:        register struct qinfo *oqp;
        !          1120: {
        !          1121:        char    dname[BUFSIZ];
        !          1122: 
        !          1123:        if (oqp->q_msg == NULL)
        !          1124:                return;
        !          1125:        if (dn_expand(oqp->q_msg, oqp->q_msg + oqp->q_msglen,
        !          1126:            oqp->q_msg + sizeof(HEADER), dname, sizeof(dname)) < 0)
        !          1127:                return;
        !          1128: #ifdef DEBUG
        !          1129:        if (debug >= 2)
        !          1130:               fprintf(ddt,"prime: %s\n", dname);
        !          1131: #endif
        !          1132:        (void) sysquery(dname, class, type);
        !          1133: }
        !          1134: 
        !          1135: 
        !          1136: prime_cache()
        !          1137: {
        !          1138:        register struct qinfo *qp;
        !          1139: 
        !          1140: #ifdef DEBUG
        !          1141:        if (debug)
        !          1142:                fprintf(ddt,"prime_cache: priming = %d\n", priming);
        !          1143: #endif
        !          1144: #ifdef STATS
        !          1145:        stats[S_PRIMECACHE].cnt++;
        !          1146: #endif
        !          1147:        if (!priming && fcachetab->h_tab[0] != NULL && !forward_only) {
        !          1148:                priming++;
        !          1149:                if ((qp = sysquery("", C_IN, T_NS)) == NULL)
        !          1150:                        priming = 0;
        !          1151:                else
        !          1152:                        qp->q_system = PRIMING_CACHE;
        !          1153:        }
        !          1154:        needs_prime_cache = 0;
        !          1155:        return;
        !          1156: }
        !          1157: 
        !          1158: struct qinfo *
        !          1159: sysquery(dname, class, type)
        !          1160:        char *dname;
        !          1161:        int class, type;
        !          1162: {
        !          1163:        extern struct qinfo *qhead;
        !          1164:        extern int nsid;
        !          1165:        register struct qinfo *qp, *oqp;
        !          1166:        register HEADER *hp;
        !          1167:        struct namebuf *np;
        !          1168:        struct databuf *nsp[NSMAX];
        !          1169:        struct hashbuf *htp;
        !          1170:        char *fname;
        !          1171:        int count;
        !          1172: 
        !          1173: #ifdef DEBUG
        !          1174:        if (debug > 2)
        !          1175:               fprintf(ddt,"sysquery(%s, %d, %d)\n", dname, class, type);
        !          1176: #endif
        !          1177: #ifdef STATS
        !          1178:        stats[S_SYSQUERIES].cnt++;
        !          1179: #endif
        !          1180:        htp = hashtab;
        !          1181:        if (priming && dname[0] == '\0')
        !          1182:                np = NULL;
        !          1183:        else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) {
        !          1184: #ifdef DEBUG
        !          1185:                if (debug)
        !          1186:                        fprintf(ddt,"sysquery: nlookup error on %s?\n", dname);
        !          1187: #endif
        !          1188:                return(0);
        !          1189:        }
        !          1190: 
        !          1191:        switch (findns(&np, class, nsp, &count)) {
        !          1192:        case NXDOMAIN:
        !          1193:        case SERVFAIL:
        !          1194: #ifdef DEBUG
        !          1195:                if (debug)
        !          1196:                        fprintf(ddt,"sysquery: findns error on %s?\n", dname);
        !          1197: #endif
        !          1198:                return(0);
        !          1199:        }
        !          1200: 
        !          1201:        /* build new qinfo struct */
        !          1202:        qp = qnew();
        !          1203:        qp->q_cmsg = qp->q_msg = NULL;
        !          1204:        qp->q_dfd = ds;
        !          1205:        qp->q_fwd = fwdtab;
        !          1206:        qp->q_system++;
        !          1207: 
        !          1208:        if ((qp->q_msg = malloc(BUFSIZ)) == NULL) {
        !          1209:                qfree(qp);
        !          1210:                return(0);
        !          1211:        }
        !          1212:        qp->q_msglen = res_mkquery(QUERY, dname, class,
        !          1213:            type, (char *)NULL, 0, NULL, qp->q_msg, BUFSIZ);
        !          1214:        hp = (HEADER *) qp->q_msg;
        !          1215:        hp->id = qp->q_nsid = htons((u_short)++nsid);
        !          1216:        hp->rd = (qp->q_fwd ? 1 : 0);
        !          1217: 
        !          1218:        /* First check for an already pending query for this data */
        !          1219:        for (oqp = qhead; oqp!=QINFO_NULL; oqp = oqp->q_link) {
        !          1220:                if (oqp != qp && oqp->q_msglen == qp->q_msglen &&
        !          1221:             bcmp((char *)oqp->q_msg+2, qp->q_msg+2, qp->q_msglen-2) == 0) {
        !          1222: #ifdef DEBUG
        !          1223:                        if (debug >= 3)
        !          1224:                                fprintf(ddt, "sysquery: duplicate\n");
        !          1225: #endif
        !          1226:                        qfree(qp);
        !          1227:                        return(0);
        !          1228:                }
        !          1229:        }
        !          1230: 
        !          1231:        if (nslookup(nsp, qp) == 0) {
        !          1232: #ifdef DEBUG
        !          1233:                if (debug)
        !          1234:                        fprintf(ddt,"resp: no addrs found for NS's\n");
        !          1235: #endif
        !          1236:                qfree(qp);
        !          1237:                return(0);
        !          1238:        }
        !          1239: 
        !          1240:        schedretry(qp, retrytime(qp));
        !          1241:        if (qp->q_fwd == 0)
        !          1242:                qp->q_addr[0].stime = tt;
        !          1243: 
        !          1244: #ifdef DEBUG
        !          1245:        if (debug)
        !          1246:            fprintf(ddt,"sysquery: send -> %s %d (%d), nsid=%d id=%d %dms\n",
        !          1247:                inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr),
        !          1248:                qp->q_dfd, ntohs(Q_NEXTADDR(qp,0)->sin_port),
        !          1249:                ntohs(qp->q_nsid), ntohs(qp->q_id),
        !          1250:                qp->q_addr[0].nsdata->d_nstime);
        !          1251:        if ( debug >= 10)
        !          1252:            fp_query(qp->q_msg, ddt);
        !          1253: #endif
        !          1254:        if (sendto(qp->q_dfd, qp->q_msg, qp->q_msglen, 0,
        !          1255:            (struct sockaddr *)Q_NEXTADDR(qp,0),
        !          1256:            sizeof(struct sockaddr_in)) < 0){
        !          1257: #ifdef DEBUG
        !          1258:            if (debug)
        !          1259:                fprintf(ddt, "sendto error errno= %d\n",errno);
        !          1260: #endif
        !          1261:        }
        !          1262: #ifdef STATS
        !          1263:        stats[S_OUTPKTS].cnt++;
        !          1264: #endif
        !          1265:        return(qp);
        !          1266: }
        !          1267: 
        !          1268: /*
        !          1269:  * Check the list of root servers after receiving a response
        !          1270:  * to a query for the root servers.
        !          1271:  */
        !          1272: check_root()
        !          1273: {
        !          1274:        register struct databuf *dp, *pdp;
        !          1275:        register struct namebuf *np;
        !          1276:        int count = 0;
        !          1277: 
        !          1278:        priming = 0;
        !          1279:        for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next)
        !          1280:                if (np->n_dname[0] == '\0')
        !          1281:                        break;
        !          1282:        if (np == NULL) {
        !          1283:                syslog(LOG_ERR, "check_root: Can't find root!\n");
        !          1284:                return;
        !          1285:        }
        !          1286:        for (dp = np->n_data; dp != NULL; dp = dp->d_next)
        !          1287:                if (dp->d_type == T_NS)
        !          1288:                        count++;
        !          1289: #ifdef DEBUG
        !          1290:        if (debug)
        !          1291:            fprintf(ddt,"%d root servers\n", count);
        !          1292: #endif
        !          1293:        if (count < MINROOTS) {
        !          1294:                syslog(LOG_WARNING,
        !          1295:                "check_root: %d root servers after query to root server < min",
        !          1296:                    count);
        !          1297:                return;
        !          1298:        }
        !          1299:        pdp = NULL;
        !          1300:        dp = np->n_data;
        !          1301:        while (dp != NULL) {
        !          1302:                if (dp->d_type == T_NS && dp->d_zone == 0 &&
        !          1303:                    dp->d_ttl < tt.tv_sec) {
        !          1304: #ifdef DEBUG
        !          1305:                        if (debug)
        !          1306:                            fprintf(ddt,"deleting old root server '%s'\n",
        !          1307:                                dp->d_data);
        !          1308: #endif
        !          1309:                        dp = rm_datum(dp, np, pdp);
        !          1310:                        /* SHOULD DELETE FROM HINTS ALSO */
        !          1311:                        continue;
        !          1312:                }
        !          1313:                pdp = dp;
        !          1314:                dp = dp->d_next;
        !          1315:        }
        !          1316:        check_ns();
        !          1317: }
        !          1318: 
        !          1319: /* 
        !          1320:  * Check the root to make sure that for each NS record we have a A RR
        !          1321:  */
        !          1322: check_ns()
        !          1323: {
        !          1324:        register struct databuf *dp, *tdp;
        !          1325:        register struct namebuf *np, *tnp;
        !          1326:        struct hashbuf *htp;
        !          1327:        char *dname;
        !          1328:        int found_arr;
        !          1329:        char *fname;
        !          1330:        time_t curtime;
        !          1331: 
        !          1332: #ifdef DEBUG
        !          1333:        if (debug >= 2)
        !          1334:               fprintf(ddt,"check_ns()\n");
        !          1335: #endif
        !          1336: #ifdef STATS
        !          1337:        stats[S_CHECKNS].cnt++;
        !          1338: #endif
        !          1339: 
        !          1340:        curtime = (u_long) tt.tv_sec;
        !          1341:        for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next) {
        !          1342:                if (np->n_dname[0] != 0)
        !          1343:                        continue;
        !          1344:                for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
        !          1345:                        if (dp->d_type != T_NS)
        !          1346:                            continue;
        !          1347: 
        !          1348:                        /* look for A records */
        !          1349:                        dname = dp->d_data;
        !          1350:                        htp = hashtab;
        !          1351:                        tnp = nlookup(dname, &htp, &fname, 0);
        !          1352:                        if (tnp == NULL || fname != dname) {
        !          1353: #ifdef DEBUG
        !          1354:                            if (debug >= 3)
        !          1355:                                fprintf(ddt,"check_ns: %s: not found %s %x\n",
        !          1356:                                        dname, fname, tnp);
        !          1357: #endif
        !          1358:                            (void) sysquery(dname, dp->d_class, T_A);
        !          1359:                            continue;
        !          1360:                        }
        !          1361:                        /* look for name server addresses */
        !          1362:                        found_arr = 0;
        !          1363:                        for (tdp=tnp->n_data; tdp!=NULL; tdp=tdp->d_next) {
        !          1364:                            if (tdp->d_type != T_A ||
        !          1365:                               tdp->d_class != dp->d_class)
        !          1366:                                continue;
        !          1367:                            if ((tdp->d_zone == 0) &&
        !          1368:                                (tdp->d_ttl < curtime)) {
        !          1369: #ifdef DEBUG
        !          1370:                                if (debug >= 3)
        !          1371:                                    fprintf(ddt,"check_ns: stale entry '%s'\n",
        !          1372:                                        tnp->n_dname);
        !          1373: #endif
        !          1374:                                /* Cache invalidate the address RR's */
        !          1375:                                delete_all(tnp, dp->d_class, T_A);
        !          1376:                                found_arr = 0;
        !          1377:                                break;
        !          1378:                            }
        !          1379:                            found_arr++;
        !          1380:                        }
        !          1381:                        if (!found_arr)
        !          1382:                            (void) sysquery(dname, dp->d_class, T_A);
        !          1383:                }
        !          1384:        }
        !          1385: }
        !          1386: 
        !          1387: #define        MAXCLASS 255            /* belongs elsewhere */
        !          1388: int    norootlogged[MAXCLASS];
        !          1389: 
        !          1390: /*
        !          1391:  *  Find NS's or an SOA for the given dname (np) and fill in the
        !          1392:  *  nsp array.  Returns OK on success, and SERVFAIL on error.
        !          1393:  *  We return NXDOMAIN to indicate we are authoritative.
        !          1394:  */
        !          1395: findns(npp, class, nsp, countp)
        !          1396:        register struct namebuf **npp;
        !          1397:        struct databuf **nsp;
        !          1398:        int *countp;
        !          1399: {
        !          1400:        register struct namebuf *np = *npp;
        !          1401:        register struct databuf *dp;
        !          1402:        register struct databuf **nspp;
        !          1403:        struct hashbuf *htp = hashtab;
        !          1404:        
        !          1405:        if (priming && (np == NULL || np->n_dname[0] == '\0'))
        !          1406:                htp = fcachetab;
        !          1407: try_again:
        !          1408:        if (htp == fcachetab)
        !          1409:                needs_prime_cache = 1;
        !          1410:        while (np == NULL && htp != NULL) {
        !          1411: #ifdef DEBUG
        !          1412:                if (debug > 2)
        !          1413:                        fprintf(ddt, "findns: using %s\n", htp == hashtab ?
        !          1414:                                "cache" : "hints");
        !          1415: #endif
        !          1416:                for (np = htp->h_tab[0]; np != NULL; np = np->n_next)
        !          1417:                        if (np->n_dname[0] == '\0')
        !          1418:                                break;
        !          1419:                htp = (htp == hashtab ? fcachetab : NULL);      /* Fallback */
        !          1420:        }
        !          1421:        while(np != NULL) {
        !          1422: #ifdef DEBUG
        !          1423:                if (debug >= 5)
        !          1424:                        fprintf(ddt, "findns: np 0x%x\n", np);
        !          1425: #endif
        !          1426:                /* Look first for SOA records. */
        !          1427:                for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
        !          1428:                        if (dp->d_zone != 0 && match(dp, class, T_SOA)) {
        !          1429: #ifdef DEBUG
        !          1430:                                if (debug >= 3)
        !          1431:                                        fprintf(ddt,"findns: SOA found\n");
        !          1432: #endif
        !          1433:                                if (zones[dp->d_zone].z_auth) {
        !          1434:                                        *npp = np;
        !          1435:                                        nsp[0] = dp;
        !          1436:                                        return(NXDOMAIN);
        !          1437:                                } else
        !          1438:                                        return (SERVFAIL);
        !          1439:                        }
        !          1440:                }
        !          1441: 
        !          1442:                /* If no SOA records, look for NS records. */
        !          1443:                nspp = &nsp[0];
        !          1444:                *nspp = NULL;
        !          1445:                for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
        !          1446:                        if (dp->d_type != T_NS ||
        !          1447:                            (dp->d_class != class && class != C_ANY))
        !          1448:                                continue;
        !          1449:                        /*
        !          1450:                         * Don't use records that may become invalid to
        !          1451:                         * reference later when we do the rtt computation.
        !          1452:                         * Never delete our safety-belt information!
        !          1453:                         */
        !          1454:                        if ((dp->d_zone == 0) &&
        !          1455:                            (dp->d_ttl < (tt.tv_sec+900)) &&
        !          1456:                            !(dp->d_flags & DB_F_HINT)) {
        !          1457: #ifdef DEBUG
        !          1458:                                if (debug)
        !          1459:                                        fprintf(ddt,"findns: stale entry '%s'\n",
        !          1460:                                                    np->n_dname);
        !          1461: #endif
        !          1462:                                /* Cache invalidate the NS RR's */
        !          1463:                                if (dp->d_ttl < tt.tv_sec)
        !          1464:                                        delete_all(np, class, T_NS);
        !          1465:                                goto try_parent;
        !          1466:                        }
        !          1467:                        if (nspp < &nsp[NSMAX-1])
        !          1468:                                *nspp++ = dp;
        !          1469:                }
        !          1470: 
        !          1471:                *countp = nspp - nsp;
        !          1472:                if (*countp > 0) {
        !          1473: #ifdef DEBUG
        !          1474:                        if (debug >= 3)
        !          1475:                                fprintf(ddt,"findns: %d NS's added for '%s'\n",
        !          1476:                                        *countp, np->n_dname);
        !          1477: #endif
        !          1478:                        *nspp = NULL;
        !          1479:                        *npp = np;
        !          1480:                        return(OK);     /* Success, got some NS's */
        !          1481:                }
        !          1482: try_parent:
        !          1483:                np = np->n_parent;
        !          1484:        }
        !          1485:        if (htp)
        !          1486:                goto try_again;
        !          1487: #ifdef DEBUG
        !          1488:        if (debug)
        !          1489:                fprintf(ddt, "findns: No root nameservers for class %d?\n",
        !          1490:                    class);
        !          1491: #endif
        !          1492:        if ((unsigned)class < MAXCLASS && norootlogged[class] == 0) {
        !          1493:                norootlogged[class] = 1;
        !          1494:                syslog(LOG_ERR, "No root nameservers for class %d\n", class);
        !          1495:        }
        !          1496:        return(SERVFAIL);
        !          1497: }
        !          1498: 
        !          1499: /*
        !          1500:  *  Extract RR's from the given node that match class and type.
        !          1501:  *  Return number of bytes added to response.
        !          1502:  *  If no matching data is found, then 0 is returned.
        !          1503:  */
        !          1504: finddata(np, class, type, hp, dnamep, lenp, countp)
        !          1505:        struct namebuf *np;
        !          1506:        int class, type;
        !          1507:        register HEADER *hp;
        !          1508:        char **dnamep;
        !          1509:        int *lenp, *countp;
        !          1510: {
        !          1511:        register struct databuf *dp;
        !          1512:        register char *cp;
        !          1513:        int buflen, n, count = 0, foundstale = 0;
        !          1514: 
        !          1515:        buflen = *lenp;
        !          1516:        cp = ((char *)hp) + *countp;
        !          1517:        for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
        !          1518:                if (!wanted(dp, class, type)) {
        !          1519:                        if (type == T_CNAME && class == dp->d_class) {
        !          1520:                                /* any data means no CNAME exists */
        !          1521:                                *countp = 0;
        !          1522:                                return(0);
        !          1523:                        }
        !          1524:                        continue;
        !          1525:                }
        !          1526:                if (stale(dp)) {
        !          1527:                        /*
        !          1528:                         * Don't use stale data.
        !          1529:                         * Would like to call delete_all here
        !          1530:                         * and continue, but the data chain would get
        !          1531:                         * munged; can't restart, as make_rr has side
        !          1532:                         * effects (leaving pointers in dnptr).
        !          1533:                         * Just skip this entry for now
        !          1534:                         * and call delete_all at the end.
        !          1535:                         */
        !          1536: #ifdef DEBUG
        !          1537:                        if (debug >=3)
        !          1538:                           fprintf(ddt,"finddata: stale entry '%s'\n",np->n_dname);
        !          1539: #endif
        !          1540:                        if (dp->d_zone == 0)
        !          1541:                                foundstale++;
        !          1542:                        continue;
        !          1543:                }
        !          1544:                if ((n = make_rr(*dnamep, dp, cp, buflen, 1)) < 0) {
        !          1545:                        hp->tc = 1;
        !          1546:                        *countp = count;
        !          1547:                        return(*lenp - buflen);
        !          1548:                }
        !          1549: 
        !          1550:                cp += n;
        !          1551:                buflen -= n;
        !          1552:                count++;
        !          1553: #ifdef notdef
        !          1554:                /* this isn't right for glue records, aa is set in ns_req */
        !          1555:                if (dp->d_zone && zones[dp->d_zone].z_auth && class != C_ANY)
        !          1556:                        hp->aa = 1;                     /* XXX */
        !          1557: #endif
        !          1558:                if (dp->d_type == T_CNAME) {
        !          1559:                        if (type != T_ANY) {    /* or T_NS? */
        !          1560:                                *dnamep = dp->d_data;
        !          1561:                                if (dp->d_zone && zones[dp->d_zone].z_auth &&
        !          1562:                                    class != C_ANY)             /* XXX */
        !          1563:                                        hp->aa = 1;             /* XXX */
        !          1564:                        }
        !          1565:                        break;
        !          1566:                }
        !          1567:        }
        !          1568:        /*
        !          1569:         * Cache invalidate the other RR's of same type
        !          1570:         * if some have timed out
        !          1571:         */
        !          1572:        if (foundstale)
        !          1573:                delete_all(np, class, type);
        !          1574: #ifdef DEBUG
        !          1575:        if (debug >=3)
        !          1576:                fprintf(ddt,"finddata: added %d class %d type %d RRs\n",
        !          1577:                        count, class, type);
        !          1578: #endif
        !          1579:        *countp = count;
        !          1580:        return(*lenp - buflen);
        !          1581: }
        !          1582: 
        !          1583: /*
        !          1584:  * Do we want this data record based on the class and type?
        !          1585:  */
        !          1586: wanted(dp, class, type)
        !          1587:        struct databuf *dp;
        !          1588:        int class, type;
        !          1589: {
        !          1590: 
        !          1591: #ifdef DEBUG
        !          1592:        if (debug > 3)
        !          1593:                fprintf(ddt,"wanted(%x, %d, %d) %d, %d\n", dp, class, type,
        !          1594:                        dp->d_class, dp->d_type);
        !          1595: #endif
        !          1596: 
        !          1597:        if (dp->d_class != class && class != C_ANY)
        !          1598:                return (0);
        !          1599:        if (type == dp->d_type)
        !          1600:                return (1);
        !          1601:        switch (dp->d_type) {
        !          1602:        case T_ANY:
        !          1603:        case T_CNAME:
        !          1604:                return (1);
        !          1605:        }
        !          1606:        switch (type) {
        !          1607:        case T_ANY:
        !          1608:                return (1);
        !          1609: 
        !          1610:        case T_MAILB:
        !          1611:                switch (dp->d_type) {
        !          1612:                case T_MR:
        !          1613:                case T_MB:
        !          1614:                case T_MG:
        !          1615:                case T_MINFO:
        !          1616:                        return (1);
        !          1617:                }
        !          1618:                break;
        !          1619: 
        !          1620:        case T_AXFR:
        !          1621:                if (dp->d_type == T_SOA)
        !          1622:                        return (1);
        !          1623:        }
        !          1624:        return (0);
        !          1625: }
        !          1626: 
        !          1627: /*
        !          1628:  *  Add RR entries from dpp array to a query/response.
        !          1629:  *  Return the number of bytes added or negative the amount
        !          1630:  *  added if truncation was required.  Typically you are
        !          1631:  *  adding NS records to a response.
        !          1632:  */
        !          1633: add_data(np, dpp, cp, buflen)
        !          1634:        struct namebuf *np;
        !          1635:        struct databuf **dpp;
        !          1636:        register char *cp;
        !          1637:        int buflen;
        !          1638: {
        !          1639:        register struct databuf *dp;
        !          1640:        char dname[MAXDNAME];
        !          1641:        register int n, count = 0;
        !          1642: 
        !          1643:        getname(np, dname, sizeof(dname));
        !          1644:        for(dp = *dpp++; dp != NULL; dp = *dpp++) {
        !          1645:                if (stale(dp))
        !          1646:                        continue;       /* ignore old cache entry */
        !          1647:                if ((n = make_rr(dname, dp, cp, buflen, 1)) < 0)
        !          1648:                        return(-count);         /* Truncation */
        !          1649:                cp += n;
        !          1650:                buflen -= n;
        !          1651:                count += n;
        !          1652:        }
        !          1653:        return(count);
        !          1654: }
        !          1655: 
        !          1656: /*
        !          1657:  *  This is best thought of as a "cache invalidate" function.
        !          1658:  *  It is called whenever a piece of data is determined to have
        !          1659:  *  timed out.  It is better to have no information, than to
        !          1660:  *  have partial information you pass off as complete.
        !          1661:  */
        !          1662: delete_all(np, class, type)
        !          1663: register struct namebuf *np;
        !          1664: int class, type;
        !          1665: {
        !          1666:        register struct databuf *dp, *pdp;
        !          1667: 
        !          1668: #ifdef DEBUG
        !          1669:        if (debug > 2)
        !          1670:                fprintf(ddt,"delete_all: '%s' 0x%x class %d type %d\n",
        !          1671:                            np->n_dname, np, class, type);
        !          1672: #endif
        !          1673:        pdp = NULL;
        !          1674:        dp = np->n_data;
        !          1675:        while (dp != NULL) {
        !          1676:                if ((dp->d_zone == 0) && !(dp->d_flags & DB_F_HINT)
        !          1677:                    && match(dp, class, type)) {
        !          1678:                        dp = rm_datum(dp, np, pdp);
        !          1679:                        continue;
        !          1680:                }
        !          1681:                pdp = dp;
        !          1682:                dp = dp->d_next;
        !          1683:        }
        !          1684: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.