Annotation of 43BSDTahoe/etc/named/ns_resp.c, revision 1.1

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

unix.superglobalmegacorp.com

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