Annotation of 43BSDTahoe/etc/named/ns_forw.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1986 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_forw.c  4.27 (Berkeley) 6/18/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 <netinet/in.h>
                     27: #include <syslog.h>
                     28: #include <arpa/nameser.h>
                     29: #include "ns.h"
                     30: #include "db.h"
                     31: 
                     32: struct qinfo *qhead = QINFO_NULL;      /* head of allocated queries */
                     33: struct qinfo *retryqp = QINFO_NULL;    /* list of queries to retry */
                     34: struct fwdinfo *fwdtab;                /* list of forwarding hosts */
                     35: 
                     36: int    nsid;                           /* next forwarded query id */
                     37: extern int forward_only;               /* you are only a slave */
                     38: extern int errno;
                     39: extern short ns_port;
                     40: 
                     41: time_t retrytime();
                     42: 
                     43: /*
                     44:  * Forward the query to get the answer since its not in the database.
                     45:  * Returns FW_OK if a request struct is allocated and the query sent.
                     46:  * Returns FW_DUP if this is a duplicate of a pending request. 
                     47:  * Returns FW_NOSERVER if there were no addresses for the nameservers.
                     48:  * Returns FW_SERVFAIL on malloc error.
                     49:  * (no action is taken on errors and qpp is not filled in.)
                     50:  */
                     51: ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp)
                     52:        struct databuf *nsp[];
                     53:        char *msg;
                     54:        int msglen;
                     55:        struct sockaddr_in *fp;
                     56:        struct qstream *qsp;
                     57:        int dfd;
                     58:        struct qinfo **qpp;
                     59: {
                     60:        register struct qinfo *qp;
                     61:        HEADER *hp;
                     62:        u_short id;
                     63:        extern char *calloc();
                     64: 
                     65: #ifdef DEBUG
                     66:        if (debug >= 3)
                     67:                fprintf(ddt,"ns_forw()\n");
                     68: #endif
                     69: 
                     70:        /* Don't forward if we're already working on it. */
                     71:        hp = (HEADER *) msg;
                     72:        id = hp->id;
                     73:        hp->rd = 0;
                     74:        /* Look at them all */
                     75:        for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
                     76:                if (qp->q_id == id &&
                     77:                    bcmp((char *)&qp->q_from, fp, sizeof(qp->q_from)) == 0 &&
                     78:                    (qp->q_cmsglen == 0 && qp->q_msglen == msglen &&
                     79:                     bcmp((char *)qp->q_msg+2, msg+2, msglen-2) == 0) ||
                     80:                    (qp->q_cmsglen == msglen &&
                     81:                     bcmp((char *)qp->q_cmsg+2, msg+2, msglen-2) == 0)) {
                     82: #ifdef DEBUG
                     83:                        if (debug >= 3)
                     84:                                fprintf(ddt,"forw: dropped DUP id=%d\n", ntohs(id));
                     85: #endif
                     86: #ifdef STATS
                     87:                        stats[S_DUPQUERIES].cnt++;
                     88: #endif
                     89:                        return (FW_DUP);
                     90:                }
                     91:        }
                     92: 
                     93:        qp = qnew();
                     94:        if (nslookup(nsp, qp) == 0) {
                     95: #ifdef DEBUG
                     96:                if (debug >= 2)
                     97:                        fprintf(ddt,"forw: no nameservers found\n");
                     98: #endif
                     99:                qfree(qp);
                    100:                hp->rd = 1;
                    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:        if (qp->q_fwd)
                    113:                hp->rd = 1;
                    114:        else
                    115:                qp->q_addr[0].stime = tt;
                    116:        qp->q_from = *fp;
                    117:        if ((qp->q_msg = malloc((unsigned)msglen)) == NULL) {
                    118:                syslog(LOG_ERR, "forw: %m");
                    119:                qfree(qp);
                    120:                return (FW_SERVFAIL);
                    121:        }
                    122:        bcopy(msg, qp->q_msg, qp->q_msglen = msglen);
                    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 = 0;
                    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 = (u_short)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:        while ((qp2 = qp1->q_next) != NULL && qp2->q_time < t)
                    302:                qp1 = qp2;
                    303:        qp1->q_next = qp;
                    304:        qp->q_next = qp2;
                    305: }
                    306: 
                    307: /*
                    308:  * Unsched is called to remove a forwarded query entry.
                    309:  */
                    310: unsched(qp)
                    311:        struct qinfo *qp;
                    312: {
                    313:        register struct qinfo *np;
                    314: 
                    315: #ifdef DEBUG
                    316:        if (debug > 3) {
                    317:                fprintf(ddt,"unsched(%#x, %d )\n", qp, ntohs(qp->q_id));
                    318:        }
                    319: #endif
                    320:        if( retryqp == qp )  {
                    321:                retryqp = qp->q_next;
                    322:        } else {
                    323:                for( np=retryqp; np->q_next != QINFO_NULL; np = np->q_next ) {
                    324:                        if( np->q_next != qp)
                    325:                                continue;
                    326:                        np->q_next = qp->q_next;        /* dequeue */
                    327:                        break;
                    328:                }
                    329:        }
                    330:        qp->q_next = QINFO_NULL;                /* sanity check */
                    331:        qp->q_time = 0;
                    332: }
                    333: 
                    334: /*
                    335:  * Retry is called to retransmit query 'qp'.
                    336:  */
                    337: retry(qp)
                    338:        register struct qinfo *qp;
                    339: {
                    340:        register int n;
                    341:        register HEADER *hp;
                    342: 
                    343: #ifdef DEBUG
                    344:        if (debug > 3)
                    345:                fprintf(ddt,"retry(x%x) id=%d\n", qp, ntohs(qp->q_id));
                    346: #endif
                    347:        if((HEADER *)qp->q_msg == NULL) {               /*** XXX ***/
                    348:                qremove(qp);
                    349:                return;
                    350:        }                                               /*** XXX ***/
                    351: 
                    352:        /* try next address */
                    353:        n = qp->q_curaddr;
                    354:        if (qp->q_fwd) {
                    355:                qp->q_fwd = qp->q_fwd->next;
                    356:                if (qp->q_fwd)
                    357:                        goto found;
                    358:                /* out of forwarders, try direct queries */
                    359:        } else
                    360:                ++qp->q_addr[n].nretry;
                    361:        if (!forward_only) {
                    362:                do {
                    363:                        if (++n >= qp->q_naddr)
                    364:                                n = 0;
                    365:                        if (qp->q_addr[n].nretry < MAXRETRY)
                    366:                                goto found;
                    367:                } while (n != qp->q_curaddr);
                    368:        }
                    369:        /*
                    370:         * Give up. Can't reach destination.
                    371:         */
                    372:        hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg);
                    373:        if (qp->q_system == PRIMING_CACHE) {
                    374:                /* Can't give up priming */
                    375:                unsched(qp);
                    376:                schedretry(qp, (time_t)60*60);  /* 1 hour */
                    377:                hp->rcode = NOERROR;    /* Lets be safe, reset the query */
                    378:                hp->qr = hp->aa = 0;
                    379:                qp->q_fwd = fwdtab;
                    380:                for (n = 0; n < qp->q_naddr; n++)
                    381:                        qp->q_addr[n].nretry = 0;
                    382:                return;
                    383:        }
                    384: #ifdef DEBUG
                    385:        if (debug >= 5)
                    386:                fprintf(ddt,"give up\n");
                    387: #endif
                    388:        n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen);
                    389:        hp->id = qp->q_id;
                    390:        hp->qr = 1;
                    391:        hp->ra = 1;
                    392:        hp->rd = 1;
                    393:        hp->rcode = SERVFAIL;
                    394: #ifdef DEBUG
                    395:        if (debug >= 10)
                    396:                fp_query(qp->q_msg, ddt);
                    397: #endif
                    398:        if (send_msg((char *)hp, n, qp)) {
                    399: #ifdef DEBUG
                    400:                if (debug)
                    401:                        fprintf(ddt,"gave up retry(x%x) nsid=%d id=%d\n",
                    402:                                qp, ntohs(qp->q_nsid), ntohs(qp->q_id));
                    403: #endif
                    404:        }
                    405:        qremove(qp);
                    406:        return;
                    407: 
                    408: found:
                    409:        if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0)
                    410:                qp->q_addr[n].stime = tt;
                    411:        qp->q_curaddr = n;
                    412:        hp = (HEADER *)qp->q_msg;
                    413:        hp->rd = (qp->q_fwd ? 1 : 0);
                    414: #ifdef DEBUG
                    415:        if (debug)
                    416:                fprintf(ddt,"%s(addr=%d n=%d) -> %s %d (%d) nsid=%d id=%d %dms\n",
                    417:                        (qp->q_fwd ? "reforw" : "resend"),
                    418:                        n, qp->q_addr[n].nretry,
                    419:                        inet_ntoa(Q_NEXTADDR(qp,n)->sin_addr),
                    420:                        ds, ntohs(Q_NEXTADDR(qp,n)->sin_port),
                    421:                        ntohs(qp->q_nsid), ntohs(qp->q_id),
                    422:                        qp->q_addr[n].nsdata->d_nstime);
                    423:        if ( debug >= 10)
                    424:                fp_query(qp->q_msg, ddt);
                    425: #endif
                    426:        /* NOSTRICT */
                    427:        if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
                    428:            (struct sockaddr *)Q_NEXTADDR(qp,n),
                    429:            sizeof(struct sockaddr_in)) < 0){
                    430: #ifdef DEBUG
                    431:                if (debug > 3)
                    432:                        fprintf(ddt,"error resending msg errno=%d\n",errno);
                    433: #endif
                    434:        }
                    435:        hp->rd = 0;     /* leave set to 0 for dup detection */
                    436: #ifdef STATS
                    437:        stats[S_OUTPKTS].cnt++;
                    438: #endif
                    439:        unsched(qp);
                    440:        schedretry(qp, qp->q_fwd ? (2*RETRYBASE) : retrytime(qp));
                    441: }
                    442: 
                    443: /*
                    444:  * Compute retry time for the next server for a query.
                    445:  * Use a minimum time of RETRYBASE (4 sec.) or twice the estimated
                    446:  * service time; * back off exponentially on retries, but place a 45-sec.
                    447:  * ceiling on retry times for now.  (This is because we don't hold a reference
                    448:  * on servers or their addresses, and we have to finish before they time out.)
                    449:  */
                    450: time_t
                    451: retrytime(qp)
                    452: register struct qinfo *qp;
                    453: {
                    454:        time_t t;
                    455:        struct qserv *ns = &qp->q_addr[qp->q_curaddr];
                    456: 
                    457: #ifdef DEBUG
                    458:        if (debug > 3)
                    459:                fprintf(ddt,"retrytime: nstime %dms.\n",
                    460:                    ns->nsdata->d_nstime / 1000);
                    461: #endif
                    462:        t = (time_t) MAX(RETRYBASE, 2 * ns->nsdata->d_nstime / 1000);
                    463:        t <<= ns->nretry;
                    464:        t = MIN(t, 45);                 /* max. retry timeout for now */
                    465: #ifdef notdef
                    466:        if (qp->q_system)
                    467:                return ((2 * t) + 5);   /* system queries can wait. */
                    468: #endif
                    469:        return (t);
                    470: }
                    471: 
                    472: qflush()
                    473: {
                    474:        while (qhead)
                    475:                qremove(qhead);
                    476:        qhead = QINFO_NULL;
                    477: }
                    478: 
                    479: qremove(qp)
                    480: register struct qinfo *qp;
                    481: {
                    482: #ifdef DEBUG
                    483:        if(debug > 3)
                    484:                fprintf(ddt,"qremove(x%x)\n", qp);
                    485: #endif
                    486:        unsched(qp);                    /* get off queue first */
                    487:        qfree(qp);
                    488: }
                    489: 
                    490: struct qinfo *
                    491: qfindid(id)
                    492: register u_short id;
                    493: {
                    494:        register struct qinfo *qp;
                    495: 
                    496: #ifdef DEBUG
                    497:        if(debug > 3)
                    498:                fprintf(ddt,"qfindid(%d)\n", ntohs(id));
                    499: #endif
                    500:        for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
                    501:                if (qp->q_nsid == id)
                    502:                        return(qp);
                    503:        }
                    504: #ifdef DEBUG
                    505:        if (debug >= 5)
                    506:                fprintf(ddt,"qp not found\n");
                    507: #endif
                    508:        return(NULL);
                    509: }
                    510: 
                    511: struct qinfo *
                    512: qnew()
                    513: {
                    514:        register struct qinfo *qp;
                    515: 
                    516:        if ((qp = (struct qinfo *)calloc(1, sizeof(struct qinfo))) == NULL) {
                    517: #ifdef DEBUG
                    518:                if (debug >= 5)
                    519:                        fprintf(ddt,"qnew: calloc error\n");
                    520: #endif
                    521:                syslog(LOG_ERR, "forw: %m");
                    522:                exit(12);
                    523:        }
                    524: #ifdef DEBUG
                    525:        if (debug >= 5)
                    526:                fprintf(ddt,"qnew(x%x)\n", qp);
                    527: #endif
                    528:        qp->q_link = qhead;
                    529:        qhead = qp;
                    530:        return( qp );
                    531: }
                    532: 
                    533: qfree(qp)
                    534: struct qinfo *qp;
                    535: {
                    536:        register struct qinfo *np;
                    537: 
                    538: #ifdef DEBUG
                    539:        if(debug > 3)
                    540:                fprintf(ddt,"qfree( x%x )\n", qp);
                    541:        if(debug && qp->q_next)
                    542:                fprintf(ddt,"WARNING:  qfree of linked ptr x%x\n", qp);
                    543: #endif
                    544:        if (qp->q_msg)
                    545:                free(qp->q_msg);
                    546:        if (qp->q_cmsg)
                    547:                free(qp->q_cmsg);
                    548:        if( qhead == qp )  {
                    549:                qhead = qp->q_link;
                    550:        } else {
                    551:                for( np=qhead; np->q_link != QINFO_NULL; np = np->q_link )  {
                    552:                        if( np->q_link != qp )  continue;
                    553:                        np->q_link = qp->q_link;        /* dequeue */
                    554:                        break;
                    555:                }
                    556:        }
                    557:        (void)free((char *)qp);
                    558: }

unix.superglobalmegacorp.com

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