Annotation of 43BSDReno/usr.sbin/named/ns_forw.c, revision 1.1.1.1

1.1       root        1: /*-
                      2:  * Copyright (c) 1986 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms are permitted provided
                      6:  * that: (1) source distributions retain this entire copyright notice and
                      7:  * comment, and (2) distributions including binaries display the following
                      8:  * acknowledgement:  ``This product includes software developed by the
                      9:  * University of California, Berkeley and its contributors'' in the
                     10:  * documentation or other materials provided with the distribution and in
                     11:  * all advertising materials mentioning features or use of this software.
                     12:  * Neither the name of the University nor the names of its contributors may
                     13:  * be used to endorse or promote products derived from this software without
                     14:  * specific prior written permission.
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
                     16:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     17:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     18:  */
                     19: 
                     20: #ifndef lint
                     21: static char sccsid[] = "@(#)ns_forw.c  4.30 (Berkeley) 6/27/90";
                     22: #endif /* not lint */
                     23: 
                     24: #include <sys/param.h>
                     25: #include <sys/time.h>
                     26: #include <sys/socket.h>
                     27: #include <netinet/in.h>
                     28: #include <syslog.h>
                     29: #include <arpa/nameser.h>
                     30: #include <stdio.h>
                     31: #include "ns.h"
                     32: #include "db.h"
                     33: 
                     34: struct qinfo *qhead = QINFO_NULL;      /* head of allocated queries */
                     35: struct qinfo *retryqp = QINFO_NULL;    /* list of queries to retry */
                     36: struct fwdinfo *fwdtab;                /* list of forwarding hosts */
                     37: 
                     38: int    nsid;                           /* next forwarded query id */
                     39: extern int forward_only;               /* you are only a slave */
                     40: extern int errno;
                     41: extern u_short ns_port;
                     42: 
                     43: time_t retrytime();
                     44: 
                     45: /*
                     46:  * Forward the query to get the answer since its not in the database.
                     47:  * Returns FW_OK if a request struct is allocated and the query sent.
                     48:  * Returns FW_DUP if this is a duplicate of a pending request. 
                     49:  * Returns FW_NOSERVER if there were no addresses for the nameservers.
                     50:  * Returns FW_SERVFAIL on malloc error.
                     51:  * (no action is taken on errors and qpp is not filled in.)
                     52:  */
                     53: ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp)
                     54:        struct databuf *nsp[];
                     55:        char *msg;
                     56:        int msglen;
                     57:        struct sockaddr_in *fp;
                     58:        struct qstream *qsp;
                     59:        int dfd;
                     60:        struct qinfo **qpp;
                     61: {
                     62:        register struct qinfo *qp;
                     63:        HEADER *hp;
                     64:        u_short id;
                     65:        extern char *calloc();
                     66: 
                     67: #ifdef DEBUG
                     68:        if (debug >= 3)
                     69:                fprintf(ddt,"ns_forw()\n");
                     70: #endif
                     71: 
                     72:        /* Don't forward if we're already working on it. */
                     73:        hp = (HEADER *) msg;
                     74:        id = hp->id;
                     75:        /* Look at them all */
                     76:        for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
                     77:                if (qp->q_id == id &&
                     78:                    bcmp((char *)&qp->q_from, fp, sizeof(qp->q_from)) == 0 &&
                     79:                    ((qp->q_cmsglen == 0 && qp->q_msglen == msglen &&
                     80:                     bcmp((char *)qp->q_msg+2, msg+2, msglen-2) == 0) ||
                     81:                    (qp->q_cmsglen == msglen &&
                     82:                     bcmp((char *)qp->q_cmsg+2, msg+2, msglen-2) == 0))) {
                     83: #ifdef DEBUG
                     84:                        if (debug >= 3)
                     85:                                fprintf(ddt,"forw: dropped DUP id=%d\n", ntohs(id));
                     86: #endif
                     87: #ifdef STATS
                     88:                        stats[S_DUPQUERIES].cnt++;
                     89: #endif
                     90:                        return (FW_DUP);
                     91:                }
                     92:        }
                     93: 
                     94:        qp = qnew();
                     95:        if (nslookup(nsp, qp) == 0) {
                     96: #ifdef DEBUG
                     97:                if (debug >= 2)
                     98:                        fprintf(ddt,"forw: no nameservers found\n");
                     99: #endif
                    100:                qfree(qp);
                    101:                return (FW_NOSERVER);
                    102:        }
                    103:        qp->q_stream = qsp;
                    104:        qp->q_curaddr = 0;
                    105:        qp->q_fwd = fwdtab;
                    106:        qp->q_dfd = dfd;
                    107:        qp->q_id = id;
                    108:        hp->id = qp->q_nsid = htons((u_short)++nsid);
                    109:        hp->ancount = 0;
                    110:        hp->nscount = 0;
                    111:        hp->arcount = 0;
                    112:        qp->q_from = *fp;
                    113:        if ((qp->q_msg = malloc((unsigned)msglen)) == NULL) {
                    114:                syslog(LOG_ERR, "forw: %m");
                    115:                qfree(qp);
                    116:                return (FW_SERVFAIL);
                    117:        }
                    118:        bcopy(msg, qp->q_msg, qp->q_msglen = msglen);
                    119:        if (!qp->q_fwd) {
                    120:                hp->rd = 0;
                    121:                qp->q_addr[0].stime = tt;
                    122:        }
                    123: 
                    124:        schedretry(qp, retrytime(qp));
                    125: #ifdef DEBUG
                    126:        if (debug)
                    127:                fprintf(ddt,
                    128:                   "forw: forw -> %s %d (%d) nsid=%d id=%d %dms retry %d sec\n",
                    129:                        inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr),
                    130:                        ds, ntohs(Q_NEXTADDR(qp,0)->sin_port),
                    131:                        ntohs(qp->q_nsid), ntohs(qp->q_id),
                    132:                        qp->q_addr[0].nsdata->d_nstime,
                    133:                        qp->q_time - tt.tv_sec);
                    134:        if ( debug >= 10)
                    135:                fp_query(msg, ddt);
                    136: #endif
                    137:        if (sendto(ds, msg, msglen, 0, (struct sockaddr *)Q_NEXTADDR(qp,0),
                    138:                   sizeof(struct sockaddr_in)) < 0){
                    139: #ifdef DEBUG
                    140:                if (debug >= 5)
                    141:                        fprintf(ddt,"error returning msg errno=%d\n",errno);
                    142: #endif
                    143:        }
                    144: #ifdef STATS
                    145:        stats[S_OUTPKTS].cnt++;
                    146: #endif
                    147:        if (qpp)
                    148:                *qpp = qp;
                    149:        hp->rd = 1;
                    150:        return (0);
                    151: }
                    152: 
                    153: /*
                    154:  * Lookup the address for each nameserver in `nsp' and add it to
                    155:  * the list saved in the qinfo structure.
                    156:  */
                    157: nslookup(nsp, qp)
                    158:        struct databuf *nsp[];
                    159:        register struct qinfo *qp;
                    160: {
                    161:        register struct namebuf *np;
                    162:        register struct databuf *dp, *nsdp;
                    163:        register struct qserv *qs;
                    164:        register int n, i;
                    165:        struct hashbuf *tmphtp;
                    166:        char *dname, *fname;
                    167:        int oldn, naddr, class, found_arr;
                    168:        time_t curtime;
                    169:        int qcomp();
                    170: 
                    171: #ifdef DEBUG
                    172:        if (debug >= 3)
                    173:                fprintf(ddt,"nslookup(nsp=x%x,qp=x%x)\n",nsp,qp);
                    174: #endif
                    175: 
                    176:        naddr = n = qp->q_naddr;
                    177:        curtime = (u_long) tt.tv_sec;
                    178:        while ((nsdp = *nsp++) != NULL) {
                    179:                class = nsdp->d_class;
                    180:                dname = nsdp->d_data;
                    181: #ifdef DEBUG
                    182:                if (debug >= 3)
                    183:                        fprintf(ddt,"nslookup: NS %s c%d t%d (x%x)\n",
                    184:                                dname, class, nsdp->d_type, nsdp->d_flags);
                    185: #endif
                    186:                /* don't put in people we have tried */
                    187:                for (i = 0; i < qp->q_nusedns; i++)
                    188:                        if (qp->q_usedns[i] == nsdp) {
                    189: #ifdef DEBUG
                    190:                                if (debug >= 2)
                    191: fprintf(ddt, "skipping used NS w/name %s\n", nsdp->d_data);
                    192: #endif DEBUG
                    193:                                goto skipserver;
                    194:                        }
                    195: 
                    196:                tmphtp = ((nsdp->d_flags & DB_F_HINT) ? fcachetab : hashtab);
                    197:                np = nlookup(dname, &tmphtp, &fname, 1);
                    198:                if (np == NULL || fname != dname) {
                    199: #ifdef DEBUG
                    200:                        if (debug >= 3)
                    201:                            fprintf(ddt,"%s: not found %s %x\n",dname,fname,np);
                    202: #endif
                    203:                        continue;
                    204:                }
                    205:                found_arr = 0;
                    206:                oldn = n;
                    207:                /* look for name server addresses */
                    208:                for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
                    209:                        if (dp->d_type != T_A || dp->d_class != class)
                    210:                                continue;
                    211:                        /*
                    212:                         * Don't use records that may become invalid to
                    213:                         * reference later when we do the rtt computation.
                    214:                         * Never delete our safety-belt information!
                    215:                         */
                    216:                        if ((dp->d_zone == 0) &&
                    217:                            (dp->d_ttl < (curtime+900)) &&
                    218:                            !(dp->d_flags & DB_F_HINT) )
                    219:                        {
                    220: #ifdef DEBUG
                    221:                                if (debug >= 3)
                    222:                                        fprintf(ddt,"nslookup: stale entry '%s'\n",
                    223:                                            np->n_dname);
                    224: #endif
                    225:                                /* Cache invalidate the NS RR's */
                    226:                                if (dp->d_ttl < curtime)
                    227:                                        delete_all(np, class, T_A);
                    228:                                n = oldn;
                    229:                                break;
                    230:                        }
                    231: 
                    232:                        found_arr++;
                    233:                        /* don't put in duplicates */
                    234:                        qs = qp->q_addr;
                    235:                        for (i = 0; i < n; i++, qs++)
                    236:                                if (bcmp((char *)&qs->ns_addr.sin_addr,
                    237:                                    dp->d_data, sizeof(struct in_addr)) == 0)
                    238:                                        goto skipaddr;
                    239:                        qs->ns_addr.sin_family = AF_INET;
                    240:                        qs->ns_addr.sin_port = ns_port;
                    241:                        qs->ns_addr.sin_addr = 
                    242:                                    *(struct in_addr *)dp->d_data;
                    243:                        qs->ns = nsdp;
                    244:                        qs->nsdata = dp;
                    245:                        qp->q_addr[n].nretry = 0;
                    246:                        n++;
                    247:                        if (n >= NSMAX)
                    248:                                goto out;
                    249:        skipaddr:       ;
                    250:                }
                    251: #ifdef DEBUG
                    252:                if (debug >= 3)
                    253:                        fprintf(ddt,"nslookup: %d ns addrs\n", n);
                    254: #endif
                    255:                if (found_arr == 0 && qp->q_system == 0)
                    256:                        (void) sysquery(dname, class, T_A);
                    257: skipserver:    ;
                    258:        }
                    259: out:
                    260: #ifdef DEBUG
                    261:        if (debug >= 3)
                    262:                fprintf(ddt,"nslookup: %d ns addrs total\n", n);
                    263: #endif
                    264:        qp->q_naddr = n;
                    265:        if (n > 1)
                    266:                qsort((char *)qp->q_addr, n, sizeof(struct qserv), qcomp);
                    267:        return (n - naddr);
                    268: }
                    269: 
                    270: qcomp(qs1, qs2)
                    271:        struct qserv *qs1, *qs2;
                    272: {
                    273: 
                    274:        return (qs1->nsdata->d_nstime - qs2->nsdata->d_nstime);
                    275: }
                    276: 
                    277: /*
                    278:  * Arrange that forwarded query (qp) is retried after t seconds.
                    279:  */
                    280: schedretry(qp, t)
                    281:        struct qinfo *qp;
                    282:        time_t t;
                    283: {
                    284:        register struct qinfo *qp1, *qp2;
                    285: 
                    286: #ifdef DEBUG
                    287:        if (debug > 3) {
                    288:                fprintf(ddt,"schedretry(%#x, %dsec)\n", qp, t);
                    289:                if (qp->q_time)
                    290:                   fprintf(ddt,"WARNING: schedretry(%x,%d) q_time already %d\n", qp->q_time);
                    291:        }
                    292: #endif
                    293:        t += (u_long) tt.tv_sec;
                    294:        qp->q_time = t;
                    295: 
                    296:        if ((qp1 = retryqp) == NULL) {
                    297:                retryqp = qp;
                    298:                qp->q_next = NULL;
                    299:                return;
                    300:        }
                    301:        if (t < qp1->q_time) {
                    302:                qp->q_next = qp1;
                    303:                retryqp = qp;
                    304:                return;
                    305:        }
                    306:        while ((qp2 = qp1->q_next) != NULL && qp2->q_time < t)
                    307:                qp1 = qp2;
                    308:        qp1->q_next = qp;
                    309:        qp->q_next = qp2;
                    310: }
                    311: 
                    312: /*
                    313:  * Unsched is called to remove a forwarded query entry.
                    314:  */
                    315: unsched(qp)
                    316:        struct qinfo *qp;
                    317: {
                    318:        register struct qinfo *np;
                    319: 
                    320: #ifdef DEBUG
                    321:        if (debug > 3) {
                    322:                fprintf(ddt,"unsched(%#x, %d )\n", qp, ntohs(qp->q_id));
                    323:        }
                    324: #endif
                    325:        if( retryqp == qp )  {
                    326:                retryqp = qp->q_next;
                    327:        } else {
                    328:                for( np=retryqp; np->q_next != QINFO_NULL; np = np->q_next ) {
                    329:                        if( np->q_next != qp)
                    330:                                continue;
                    331:                        np->q_next = qp->q_next;        /* dequeue */
                    332:                        break;
                    333:                }
                    334:        }
                    335:        qp->q_next = QINFO_NULL;                /* sanity check */
                    336:        qp->q_time = 0;
                    337: }
                    338: 
                    339: /*
                    340:  * Retry is called to retransmit query 'qp'.
                    341:  */
                    342: retry(qp)
                    343:        register struct qinfo *qp;
                    344: {
                    345:        register int n;
                    346:        register HEADER *hp;
                    347: 
                    348: #ifdef DEBUG
                    349:        if (debug > 3)
                    350:                fprintf(ddt,"retry(x%x) id=%d\n", qp, ntohs(qp->q_id));
                    351: #endif
                    352:        if((HEADER *)qp->q_msg == NULL) {               /*** XXX ***/
                    353:                qremove(qp);
                    354:                return;
                    355:        }                                               /*** XXX ***/
                    356: 
                    357:        /* try next address */
                    358:        n = qp->q_curaddr;
                    359:        if (qp->q_fwd) {
                    360:                qp->q_fwd = qp->q_fwd->next;
                    361:                if (qp->q_fwd)
                    362:                        goto found;
                    363:                /* out of forwarders, try direct queries */
                    364:        } else
                    365:                ++qp->q_addr[n].nretry;
                    366:        if (!forward_only) {
                    367:                do {
                    368:                        if (++n >= qp->q_naddr)
                    369:                                n = 0;
                    370:                        if (qp->q_addr[n].nretry < MAXRETRY)
                    371:                                goto found;
                    372:                } while (n != qp->q_curaddr);
                    373:        }
                    374:        /*
                    375:         * Give up. Can't reach destination.
                    376:         */
                    377:        hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg);
                    378:        if (qp->q_system == PRIMING_CACHE) {
                    379:                /* Can't give up priming */
                    380:                unsched(qp);
                    381:                schedretry(qp, (time_t)60*60);  /* 1 hour */
                    382:                hp->rcode = NOERROR;    /* Lets be safe, reset the query */
                    383:                hp->qr = hp->aa = 0;
                    384:                qp->q_fwd = fwdtab;
                    385:                for (n = 0; n < qp->q_naddr; n++)
                    386:                        qp->q_addr[n].nretry = 0;
                    387:                return;
                    388:        }
                    389: #ifdef DEBUG
                    390:        if (debug >= 5)
                    391:                fprintf(ddt,"give up\n");
                    392: #endif
                    393:        n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen);
                    394:        hp->id = qp->q_id;
                    395:        hp->qr = 1;
                    396:        hp->ra = 1;
                    397:        hp->rd = 1;
                    398:        hp->rcode = SERVFAIL;
                    399: #ifdef DEBUG
                    400:        if (debug >= 10)
                    401:                fp_query(qp->q_msg, ddt);
                    402: #endif
                    403:        if (send_msg((char *)hp, n, qp)) {
                    404: #ifdef DEBUG
                    405:                if (debug)
                    406:                        fprintf(ddt,"gave up retry(x%x) nsid=%d id=%d\n",
                    407:                                qp, ntohs(qp->q_nsid), ntohs(qp->q_id));
                    408: #endif
                    409:        }
                    410:        qremove(qp);
                    411:        return;
                    412: 
                    413: found:
                    414:        if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0)
                    415:                qp->q_addr[n].stime = tt;
                    416:        qp->q_curaddr = n;
                    417:        hp = (HEADER *)qp->q_msg;
                    418:        hp->rd = (qp->q_fwd ? 1 : 0);
                    419: #ifdef DEBUG
                    420:        if (debug)
                    421:                fprintf(ddt,"%s(addr=%d n=%d) -> %s %d (%d) nsid=%d id=%d %dms\n",
                    422:                        (qp->q_fwd ? "reforw" : "resend"),
                    423:                        n, qp->q_addr[n].nretry,
                    424:                        inet_ntoa(Q_NEXTADDR(qp,n)->sin_addr),
                    425:                        ds, ntohs(Q_NEXTADDR(qp,n)->sin_port),
                    426:                        ntohs(qp->q_nsid), ntohs(qp->q_id),
                    427:                        qp->q_addr[n].nsdata->d_nstime);
                    428:        if ( debug >= 10)
                    429:                fp_query(qp->q_msg, ddt);
                    430: #endif
                    431:        /* NOSTRICT */
                    432:        if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
                    433:            (struct sockaddr *)Q_NEXTADDR(qp,n),
                    434:            sizeof(struct sockaddr_in)) < 0){
                    435: #ifdef DEBUG
                    436:                if (debug > 3)
                    437:                        fprintf(ddt,"error resending msg errno=%d\n",errno);
                    438: #endif
                    439:        }
                    440:        hp->rd = 1;     /* leave set to 1 for dup detection */
                    441: #ifdef STATS
                    442:        stats[S_OUTPKTS].cnt++;
                    443: #endif
                    444:        unsched(qp);
                    445:        schedretry(qp, qp->q_fwd ? (2*RETRYBASE) : retrytime(qp));
                    446: }
                    447: 
                    448: /*
                    449:  * Compute retry time for the next server for a query.
                    450:  * Use a minimum time of RETRYBASE (4 sec.) or twice the estimated
                    451:  * service time; * back off exponentially on retries, but place a 45-sec.
                    452:  * ceiling on retry times for now.  (This is because we don't hold a reference
                    453:  * on servers or their addresses, and we have to finish before they time out.)
                    454:  */
                    455: time_t
                    456: retrytime(qp)
                    457: register struct qinfo *qp;
                    458: {
                    459:        time_t t;
                    460:        struct qserv *ns = &qp->q_addr[qp->q_curaddr];
                    461: 
                    462: #ifdef DEBUG
                    463:        if (debug > 3)
                    464:                fprintf(ddt,"retrytime: nstime %dms.\n",
                    465:                    ns->nsdata->d_nstime / 1000);
                    466: #endif
                    467:        t = (time_t) MAX(RETRYBASE, 2 * ns->nsdata->d_nstime / 1000);
                    468:        t <<= ns->nretry;
                    469:        t = MIN(t, 45);                 /* max. retry timeout for now */
                    470: #ifdef notdef
                    471:        if (qp->q_system)
                    472:                return ((2 * t) + 5);   /* system queries can wait. */
                    473: #endif
                    474:        return (t);
                    475: }
                    476: 
                    477: qflush()
                    478: {
                    479:        while (qhead)
                    480:                qremove(qhead);
                    481:        qhead = QINFO_NULL;
                    482: }
                    483: 
                    484: qremove(qp)
                    485: register struct qinfo *qp;
                    486: {
                    487: #ifdef DEBUG
                    488:        if(debug > 3)
                    489:                fprintf(ddt,"qremove(x%x)\n", qp);
                    490: #endif
                    491:        unsched(qp);                    /* get off queue first */
                    492:        qfree(qp);
                    493: }
                    494: 
                    495: struct qinfo *
                    496: qfindid(id)
                    497: register u_short id;
                    498: {
                    499:        register struct qinfo *qp;
                    500: 
                    501: #ifdef DEBUG
                    502:        if(debug > 3)
                    503:                fprintf(ddt,"qfindid(%d)\n", ntohs(id));
                    504: #endif
                    505:        for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
                    506:                if (qp->q_nsid == id)
                    507:                        return(qp);
                    508:        }
                    509: #ifdef DEBUG
                    510:        if (debug >= 5)
                    511:                fprintf(ddt,"qp not found\n");
                    512: #endif
                    513:        return(NULL);
                    514: }
                    515: 
                    516: struct qinfo *
                    517: qnew()
                    518: {
                    519:        register struct qinfo *qp;
                    520: 
                    521:        if ((qp = (struct qinfo *)calloc(1, sizeof(struct qinfo))) == NULL) {
                    522: #ifdef DEBUG
                    523:                if (debug >= 5)
                    524:                        fprintf(ddt,"qnew: calloc error\n");
                    525: #endif
                    526:                syslog(LOG_ERR, "forw: %m");
                    527:                exit(12);
                    528:        }
                    529: #ifdef DEBUG
                    530:        if (debug >= 5)
                    531:                fprintf(ddt,"qnew(x%x)\n", qp);
                    532: #endif
                    533:        qp->q_link = qhead;
                    534:        qhead = qp;
                    535:        return( qp );
                    536: }
                    537: 
                    538: qfree(qp)
                    539: struct qinfo *qp;
                    540: {
                    541:        register struct qinfo *np;
                    542: 
                    543: #ifdef DEBUG
                    544:        if(debug > 3)
                    545:                fprintf(ddt,"qfree( x%x )\n", qp);
                    546:        if(debug && qp->q_next)
                    547:                fprintf(ddt,"WARNING:  qfree of linked ptr x%x\n", qp);
                    548: #endif
                    549:        if (qp->q_msg)
                    550:                free(qp->q_msg);
                    551:        if (qp->q_cmsg)
                    552:                free(qp->q_cmsg);
                    553:        if( qhead == qp )  {
                    554:                qhead = qp->q_link;
                    555:        } else {
                    556:                for( np=qhead; np->q_link != QINFO_NULL; np = np->q_link )  {
                    557:                        if( np->q_link != qp )  continue;
                    558:                        np->q_link = qp->q_link;        /* dequeue */
                    559:                        break;
                    560:                }
                    561:        }
                    562:        (void)free((char *)qp);
                    563: }

unix.superglobalmegacorp.com

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