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 this notice is preserved and that due credit is given
   7:  * to the University of California at Berkeley. The name of the University
   8:  * may not be used to endorse or promote products derived from this
   9:  * software without specific prior written permission. This software
  10:  * is provided ``as is'' without express or implied warranty.
  11:  */
  12: 
  13: #ifndef lint
  14: static char sccsid[] = "@(#)ns_req.c	4.32 (Berkeley) 3/31/88";
  15: #endif /* not lint */
  16: 
  17: #include <stdio.h>
  18: #include <sys/param.h>
  19: #include <sys/uio.h>
  20: #include <sys/time.h>
  21: #include <sys/socket.h>
  22: #include <netinet/in.h>
  23: #include <syslog.h>
  24: #include <sys/file.h>
  25: #include <arpa/nameser.h>
  26: #include "ns.h"
  27: #include "db.h"
  28: 
  29: #define NADDRECS    20
  30: 
  31: extern  int debug;
  32: extern  FILE    *ddt;
  33: 
  34: struct addinfo {
  35:     char    *a_dname;       /* domain name */
  36:     u_short a_class;        /* class for address */
  37: };
  38: 
  39: struct  addinfo addinfo[NADDRECS];  /* additional info records */
  40: int addcount;           /* number of names in addinfo */
  41: int xfr_disabled = 0;       /* set to disable zone xfrs */
  42: int needs_prime_cache = 0;      /* set if we need a priming */
  43: 
  44: u_char  *dnptrs[20];        /* ptrs to dnames in message for dn_comp */
  45: 
  46: extern time_t retrytime();
  47: extern struct qinfo *sysquery();
  48: extern char *localdomain;   /* XXX */
  49: extern int errno;
  50: /*
  51:  * Process request using database; assemble and send response.
  52:  */
  53: ns_req(msg, msglen, buflen, qsp, from, dfd)
  54:     u_char *msg;
  55:     int msglen, buflen;
  56:     struct qstream *qsp;
  57:     struct sockaddr_in *from;
  58:     int dfd;
  59: {
  60:     register HEADER *hp;
  61:     register u_char *cp;
  62:     struct namebuf *np;
  63:     register struct databuf *dp;
  64:     struct hashbuf *htp;
  65:     struct netinfo *lp;
  66:     char *fname, *answers;
  67:     u_char *eom, *omsg;
  68:     char dnbuf[MAXDNAME], *dname;
  69:     u_char **dpp;
  70:     int n, class, type, count, foundname, founddata, omsglen, cname = 0;
  71:     u_short id;
  72:     struct databuf *nsp[NSMAX];
  73:     struct qinfo *qp;
  74:     extern struct qinfo *qhead;
  75:     extern struct netinfo *local();
  76:     extern int nsid;
  77: 
  78: #ifdef DEBUG
  79:     if (debug > 3) {
  80:         fprintf(ddt,"ns_req()\n");
  81:         fp_query(msg, ddt);
  82:     }
  83: #endif
  84: 
  85:     hp = (HEADER *) msg;
  86:     if (hp->qr) {
  87:         ns_resp(msg, msglen);
  88: 
  89:         /* Now is a safe time for housekeeping */
  90:         if (needs_prime_cache)
  91:             prime_cache();
  92:         return;
  93:     }
  94: 
  95:     hp->rcode = NOERROR;
  96:     cp = msg + sizeof(HEADER);
  97:     eom = msg + msglen;
  98:     dpp = dnptrs;
  99:     *dpp++ = msg;
 100:     addcount = 0;
 101: 
 102:     switch (hp->opcode) {
 103:     case QUERY:
 104: #ifdef STATS
 105:         stats[S_QUERIES].cnt++;
 106: #endif
 107:         if (ntohs(hp->qdcount) != 1 ||
 108:             hp->ancount || hp->nscount || hp->arcount) {
 109: #ifdef DEBUG
 110:             if (debug)
 111:                 fprintf(ddt,"FORMERR Query header counts wrong\n");
 112: #endif
 113:             hp->qdcount = 0;
 114:             hp->ancount = 0;
 115:             hp->nscount = 0;
 116:             hp->arcount = 0;
 117:             hp->rcode = FORMERR;
 118:             goto finish;
 119:         }
 120:         /*
 121: 		 * Get domain name, class, and type.
 122: 		 */
 123:         if ((*cp & INDIR_MASK) == 0)
 124:             *dpp++ = cp;    /* remember name for compression */
 125:         *dpp = NULL;
 126:         if ((n = dn_expand(msg, eom, cp, dnbuf,
 127:             sizeof(dnbuf))) < 0) {
 128: #ifdef DEBUG
 129:             if (debug)
 130:                 fprintf(ddt,"FORMERR Query expand name failed\n");
 131: #endif
 132:             hp->rcode = FORMERR;
 133:             goto finish;
 134:         }
 135:         cp += n;
 136:         GETSHORT(type, cp);
 137:         GETSHORT(class, cp);
 138:         if (cp > eom) {
 139: #ifdef DEBUG
 140:             if (debug)
 141:                 fprintf(ddt,"FORMERR Query message length short\n");
 142: #endif
 143:             hp->rcode = FORMERR;
 144:             goto finish;
 145:         }
 146: #ifdef DEBUG
 147:         if (cp < eom)
 148:             if (debug > 5)
 149:                 fprintf(ddt,"message length > received message\n");
 150: #endif
 151: 
 152: #ifdef STATS
 153:         if ((type > T_ANY) || (type < 0))
 154:             typestats[0]++; /* Bad type */
 155:         else
 156:             typestats[type]++;
 157: #endif
 158:         /*
 159: 		 * Process query.
 160: 		 */
 161:         if (type == T_AXFR) {
 162:             /* refuse request if not a TCP connection */
 163:             if (qsp == QSTREAM_NULL || xfr_disabled) {
 164: #ifdef DEBUG
 165:                 if (debug)
 166:                     fprintf(ddt,"T_AXFR via UDP refused\n");
 167: #endif
 168:                 hp->rcode = REFUSED;
 169:                 goto finish;
 170:             }
 171:             dnptrs[0] = NULL;   /* don't compress names */
 172:             hp->rd = 0;     /* recursion not possible */
 173:         }
 174:         buflen -= msglen;
 175:         count = 0;
 176:         foundname = 0;
 177:         founddata = 0;
 178:         dname = dnbuf;
 179: try_again:
 180: #ifdef DEBUG
 181:         if (debug)
 182:             fprintf(ddt,"req: nlookup(%s) id %d type=%d\n",
 183:                 dname, hp->id, type);
 184: #endif
 185:         htp = hashtab;      /* lookup relative to root */
 186:         if ((np = nlookup(dname, &htp, &fname, 0)) == NULL)
 187:             fname = "";
 188: #ifdef DEBUG
 189:         if (debug)
 190:             fprintf(ddt,"req: %s '%s' as '%s' (cname=%d)\n",
 191:                 np == NULL ? "missed" : "found",
 192:                 dname, fname, cname);
 193: #endif
 194:         /* START XXX */
 195:         /*
 196: 		 * if nlookup failed to find address then
 197: 		 *  see if there are any '.''s in the name
 198: 		 * if not then add local domain name to the
 199: 		 * name and try again.
 200: 		 */
 201:         if (np == NULL && localdomain && index(dname, '.') == NULL) {
 202:             (void) strcat(dname,".");
 203:             (void) strcat(dname, localdomain);
 204: #ifdef DEBUG
 205:             if (debug)
 206:                 fprintf(ddt,"req: nlookup(%s) type=%d\n",
 207:                     dname, type);
 208: #endif
 209:             htp = hashtab;
 210:             np = nlookup(dname, &htp, &fname, 0);
 211:             }
 212:         /* END XXX */
 213:         if (np == NULL || fname != dname)
 214:             goto fetchns;
 215: 
 216:         foundname++;
 217:         answers = (char *)cp;
 218:         count = cp - msg;
 219:         n = finddata(np, class, type, hp, &dname, &buflen, &count);
 220:         if (n == 0)
 221:             goto fetchns;       /* NO data available */
 222:         cp += n;
 223:         buflen -= n;
 224:         msglen += n;
 225:         hp->ancount += count;
 226:         if (fname != dname && type != T_CNAME && type != T_ANY) {
 227:             cname++;
 228:             goto try_again;
 229:         }
 230:         founddata = 1;
 231: #ifdef DEBUG
 232:         if (debug >= 3) {
 233:             fprintf(ddt,"req: foundname = %d count = %d ", foundname, count);
 234:             fprintf(ddt,"founddata = %d cname = %d\n",founddata, cname);
 235:         }
 236: #endif
 237:         if ((lp = local(from)) != NULL)
 238:             sort_response(answers, count, lp, cp);
 239:         if (type == T_AXFR) {
 240:             if (founddata) {
 241:                 hp->ancount = htons(hp->ancount);
 242:                 startxfr(qsp, np, msg, cp - msg);
 243:                 return;
 244:             }
 245:             hp->rcode = REFUSED;    /* No go if unauthoritative */
 246:             goto finish;
 247:         }
 248: #ifdef notdef
 249:         /*
 250: 		 * If we found an authoritative answer,
 251: 		 * we're done.
 252: 		 */
 253:         if (hp->aa)
 254:             goto finish;
 255: #endif
 256: 
 257: fetchns:
 258:         /*
 259: 	 	 * Look for name servers to refer to and fill in the authority
 260: 	 	 * section or record the address for forwarding the query
 261: 	 	 * (recursion desired).
 262: 	 	 */
 263:         switch (findns(&np, class, nsp, &count)) {
 264:         case NXDOMAIN:
 265:             if (!foundname)
 266:                 hp->rcode = NXDOMAIN;
 267: #ifdef DEBUG
 268:             if (debug >= 3)
 269:                 fprintf(ddt,"req: leaving (%s, rcode %d)\n",
 270:                     dname, hp->rcode);
 271: #endif
 272:             if (class != C_ANY) {
 273:                 hp->aa = 1;
 274:                 /*
 275: 				 * should return SOA if founddata == 0,
 276: 				 * but old named's are confused by an SOA
 277: 				 * in the auth. section if there's no error.
 278: 				 */
 279:                 if (foundname == 0 && np) {
 280:                     n = doaddauth(hp, cp, buflen, np, nsp[0]);
 281:                     cp += n;
 282:                     buflen -= n;
 283:                 }
 284:             }
 285:             goto finish;
 286: 
 287:         case SERVFAIL:
 288:             hp->rcode = SERVFAIL;
 289:             goto finish;
 290:         }
 291: 
 292:         /*
 293: 		 *  If we successfully found the answer in the cache
 294: 		 *  or this is not a recursive query, then add the
 295: 		 *  nameserver references here and return.
 296: 		 */
 297:         if (founddata || (!hp->rd)) {
 298:             n = add_data(np, nsp, cp, buflen);
 299:             if (n < 0) {
 300:                 hp->tc = 1;
 301:                 n = (-n);
 302:             }
 303:             cp += n;
 304:             buflen -= n;
 305:             hp->nscount = htons((u_short)count);
 306:             goto finish;
 307:         }
 308: 
 309:         /*
 310: 		 *  At this point, we don't have the answer, but we do
 311: 		 *  have some NS's to try.  If the user would like us
 312: 		 *  to recurse, create the initial query.  If a cname
 313: 		 *  is involved, we need to build a new query and save
 314: 		 *  the old one in cmsg/cmsglen.
 315: 		 */
 316:         if (cname) {
 317:             omsg = (u_char *)malloc((unsigned)msglen);
 318:             if (omsg == (u_char *)NULL) {
 319: #ifdef DEBUG
 320:                 if (debug)
 321:                         fprintf(ddt,"ns_req: malloc fail\n");
 322: #endif
 323:                 syslog(LOG_ERR, "ns_req: Out Of Memory");
 324:                 hp->rcode = SERVFAIL;
 325:                 break;
 326:             }
 327:             id = hp->id;
 328:             hp->ancount = htons(hp->ancount);
 329:             bcopy(msg, omsg, omsglen = msglen);
 330:             msglen = res_mkquery(QUERY, dname, class, type,
 331:                 (char *)NULL, 0, NULL, msg, msglen+buflen);
 332:         }
 333:         n = ns_forw(nsp, msg, msglen, from, qsp, dfd, &qp);
 334:         if (n != FW_OK && cname)
 335:             free(omsg);
 336:         switch (n) {
 337:         case FW_OK:
 338:             if (cname) {
 339:                 qp->q_cname++;
 340:                 qp->q_cmsg = (char *)omsg;
 341:                 qp->q_cmsglen = omsglen;
 342:                 qp->q_id = id;
 343:             }
 344:             break;
 345:         case FW_DUP:
 346:             break;      /* Duplicate request dropped */
 347:         case FW_NOSERVER:
 348:             if(np)
 349:                 np = np->n_parent;
 350:             goto fetchns;   /* Try again. */
 351:         case FW_SERVFAIL:
 352:             hp->rcode = SERVFAIL;
 353:             goto finish;
 354:         }
 355:         /* Now is a safe time for housekeeping */
 356:         if (needs_prime_cache)
 357:             prime_cache();
 358:         return;
 359: 
 360:     case IQUERY: {
 361:         register struct invbuf *ip;
 362:         register int i;
 363:         int dlen, alen;
 364:         char anbuf[PACKETSZ], *data;
 365: 
 366: #ifdef STATS
 367:         stats[S_IQUERIES].cnt++;
 368: #endif
 369:         hp->ancount = htons(hp->ancount);
 370:         if (hp->ancount != 1 ||
 371:             hp->qdcount || hp->nscount || hp->arcount) {
 372: #ifdef DEBUG
 373:             if (debug)
 374:                 fprintf(ddt,"FORMERR IQuery header counts wrong\n");
 375: #endif
 376:             hp->qdcount = 0;
 377:             hp->ancount = 0;
 378:             hp->nscount = 0;
 379:             hp->arcount = 0;
 380:             hp->rcode = FORMERR;
 381:             goto finish;
 382:         }
 383:         /*
 384: 		 * Skip domain name, get class, and type.
 385: 		 */
 386:         if ((n = dn_skipname(cp, eom)) < 0) {
 387: #ifdef DEBUG
 388:             if (debug)
 389:                 fprintf(ddt,"FORMERR IQuery packet name problem\n");
 390: #endif
 391:             hp->rcode = FORMERR;
 392:             goto finish;
 393:         }
 394:         cp += n;
 395:         GETSHORT(type, cp);
 396:         GETSHORT(class, cp);
 397:         cp += sizeof(u_long);
 398:         GETSHORT(dlen, cp);
 399:         cp += dlen;
 400:         if (cp != eom) {
 401: #ifdef DEBUG
 402:             if (debug)
 403:                 fprintf(ddt,"FORMERR IQuery message length off\n");
 404: #endif
 405:             hp->rcode = FORMERR;
 406:             goto finish;
 407:         }
 408:         /* not all inverse queries are handled. */
 409:         switch (type) {
 410:         case T_A:
 411:         case T_UID:
 412:         case T_GID:
 413:             break;
 414: 
 415:         default:
 416:             hp->rcode = REFUSED;
 417:             goto finish;
 418:         }
 419: #ifdef DEBUG
 420:         if (debug)
 421:             fprintf(ddt,"req: IQuery class %d type %d\n",
 422:                 class, type);
 423: #endif
 424:         fname = (char *)msg + sizeof(HEADER);
 425:         bcopy(fname, anbuf, alen = (char *)cp - fname);
 426:         data = anbuf + alen - dlen;
 427:         cp = (u_char *)fname;
 428:         buflen -= sizeof(HEADER);
 429:         count = 0;
 430:         for (ip = invtab[dhash(data, dlen)]; ip != NULL;
 431:             ip = ip->i_next) {
 432:             for (i = 0; i < INVBLKSZ; i++) {
 433:             if ((np = ip->i_dname[i]) == NULL)
 434:                 break;
 435: #ifdef DEBUG
 436:             if (debug >= 5)
 437:                 fprintf(ddt,"dname = %d\n", np->n_dname);
 438: #endif
 439:             for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
 440:                 if (!match(dp, class, type))
 441:                     continue;
 442:                 if (dp->d_size != dlen ||
 443:                     bcmp(dp->d_data, data, dlen))
 444:                     continue;
 445:                 getname(np, dnbuf, sizeof(dnbuf));
 446: #ifdef DEBUG
 447:                 if (debug > 2)
 448:                     fprintf(ddt,"req: IQuery found %s\n",
 449:                         dnbuf);
 450: #endif
 451:                 buflen -= QFIXEDSZ;
 452:                 if ((n =
 453:                    dn_comp(dnbuf, cp, buflen, (char **)NULL,
 454:                       (char **)NULL)) < 0)
 455:                 {
 456:                     hp->tc = 1;
 457:                     goto finish;
 458:                 }
 459:                 cp += n;
 460:                 PUTSHORT((u_short)dp->d_type, cp);
 461:                 PUTSHORT((u_short)dp->d_class, cp);
 462:                 buflen -= n;
 463:                 count++;
 464:             }
 465:             }
 466:         }
 467: #ifdef DEBUG
 468:         if (debug)
 469:             fprintf(ddt,"req: IQuery %d records\n", count);
 470: #endif
 471:         hp->qdcount = htons((u_short)count);
 472:         if (alen > buflen) {
 473:             hp->tc = 1;
 474:             break;
 475:         }
 476:         bcopy(anbuf, cp, alen);
 477:         cp += alen;
 478:         break;
 479:         }
 480: 
 481: #ifdef ALLOW_UPDATES
 482: /*
 483:  * In a sense the following constant should be defined in <arpa/nameser.h>,
 484:  * since it is returned here in place of a response code if the update was
 485:  * forwarded, and the response codes are defined in nameser.h.  On the other
 486:  * hand, though, this constant is only seen in this file.  The assumption
 487:  * here is that none of the other return codes equals this one (a good
 488:  * assumption, since they only occupy 4 bits over-the-wire)
 489:  */
 490: #define FORWARDED 1000
 491:         /* Call InitDynUpdate for all dynamic update requests */
 492:         case UPDATEM:
 493:         case UPDATEMA:
 494:         case UPDATED:
 495:         case UPDATEDA:
 496:         case UPDATEA:
 497:                 n = InitDynUpdate(hp, nsp, msg, msglen, cp, from, qsp, dfd);
 498:                 if (n == FORWARDED)
 499:                         return; /* Return directly because InitDynUpdate
 500:                                  * forwarded the query to the primary, so we
 501:                                  * will send response later
 502:                                  */
 503:                 else
 504:                         break;  /* Either sucessful primary update or failure;
 505:                                  * return response code to client
 506:                                  */
 507: #endif ALLOW_UPDATES
 508: 
 509:     case ZONEREF:
 510: #ifdef DEBUG
 511:         if (debug)
 512:             fprintf(ddt,"Refresh Zone\n");
 513: #endif
 514: 
 515:     default:
 516: #ifdef DEBUG
 517:         if (debug >= 2)
 518:             fprintf(ddt,"Opcode %d not implemented\n", hp->opcode);
 519: #endif
 520:         hp->qdcount = 0;
 521:         hp->ancount = 0;
 522:         hp->nscount = 0;
 523:         hp->arcount = 0;
 524:         hp->rcode = NOTIMP;
 525:     }
 526: finish:
 527: #ifdef STATS
 528:     switch(hp->rcode) {
 529:     case NOERROR:
 530:         stats[S_RESPOK].cnt++;
 531:         break;
 532:     case FORMERR:
 533:         stats[S_RESPFORMERR].cnt++;
 534:         break;
 535:     default:
 536:         stats[S_RESPFAIL].cnt++;
 537:         break;
 538:     }
 539: #endif
 540:     hp->qr = 1;     /* set Response flag */
 541:     hp->ra = 1;     /* Recursion is Available */
 542:     hp->ancount = htons(hp->ancount);
 543:     if (addcount) {
 544:         n = doaddinfo(hp, cp, buflen);
 545:         cp += n;
 546:         buflen -= n;
 547:     }
 548: 
 549: #ifdef DEBUG
 550:     if (debug) {
 551:         fprintf(ddt,"req: answer -> %s %d (%d) id=%d %s\n",
 552:             inet_ntoa(from->sin_addr), dfd, ntohs(from->sin_port),
 553:         ntohs(hp->id), local(from) == NULL ? "Remote" : "Local");
 554:     }
 555:     if (debug >= 10)
 556:         fp_query(msg, ddt);
 557: #endif DEBUG
 558:     if (qsp == QSTREAM_NULL) {
 559:         if (sendto(dfd, msg, cp-msg, 0, (struct sockaddr *)from,
 560:             sizeof(*from))< 0){
 561: #ifdef DEBUG
 562:             if (debug)
 563:                 fprintf(ddt,"error returning msg errno=%d\n",errno);
 564: #endif DEBUG
 565:         }
 566: #ifdef STATS
 567:         stats[S_OUTPKTS].cnt++;
 568: #endif
 569:     } else {
 570:         (void) writemsg(qsp->s_rfd, msg, cp - msg);
 571:         qsp->s_time = tt.tv_sec;
 572:         qsp->s_refcnt--;
 573:     }
 574:     if (needs_prime_cache)
 575:         prime_cache();  /* Now is a safe time */
 576: }
 577: 
 578: fwritemsg(rfp, msg, msglen)
 579:     FILE *rfp;
 580:     char *msg;
 581:     int msglen;
 582: {
 583:     u_short len = htons((u_short)msglen);
 584: 
 585:     if (fwrite((char *)&len, sizeof(len), 1, rfp) != 1 ||
 586:         fwrite(msg, msglen, 1, rfp) != 1) {
 587: #ifdef DEBUG
 588:         if (debug)
 589:             fprintf(ddt,"fwrite failed %d\n", errno);
 590: #endif
 591:     }
 592:     return;
 593: }
 594: 
 595: writemsg(rfd, msg, msglen)
 596:     int rfd;
 597:     char *msg;
 598:     int msglen;
 599: {
 600:     struct iovec iov[2];
 601:     u_short len = htons((u_short)msglen);
 602: 
 603:     iov[0].iov_base = (caddr_t)&len;
 604:     iov[0].iov_len = sizeof(len);
 605:     iov[1].iov_base = msg;
 606:     iov[1].iov_len = msglen;
 607:     if (writev(rfd, iov, 2) != sizeof(len) + msglen) {
 608: #ifdef DEBUG
 609:         if (debug)
 610:             fprintf(ddt,"write failed %d\n", errno);
 611: #endif
 612:         return (-1);
 613:     }
 614:     return (0);
 615: }
 616: 
 617: /*
 618:  *  Test a datum for validity and return non-zero if it is out of date.
 619:  */
 620: stale(dp)
 621: register struct databuf *dp;
 622: {
 623:     register struct zoneinfo *zp = &zones[dp->d_zone];
 624: 
 625:     switch (zp->z_type) {
 626: 
 627:     case Z_PRIMARY:
 628:         return (0);
 629: 
 630:     case Z_SECONDARY:
 631:         return ((u_long)(tt.tv_sec - zp->z_lastupdate) > zp->z_expire);
 632: 
 633:     case Z_CACHE:
 634: #ifdef DEBUG
 635:         if (debug >= 3)
 636:             fprintf(ddt,"stale: ttl %ld %ld (x%x)\n",
 637:                 dp->d_ttl, dp->d_ttl - tt.tv_sec, dp->d_flags);
 638: #endif
 639:         if (dp->d_flags & DB_F_HINT)
 640:             return(0);
 641:         return(dp->d_ttl <= tt.tv_sec);
 642: 
 643:     }
 644:     /* NOTREACHED */
 645: }
 646: 
 647: /*
 648:  * Copy databuf into a resource record for replies.
 649:  * Return size of RR if OK, -1 if buffer is full.
 650:  */
 651: make_rr(name, dp, buf, buflen, doadd)
 652:     char *name;
 653:     register struct databuf *dp;
 654:     char *buf;
 655:     int buflen, doadd;
 656: {
 657:     register char *cp;
 658:     char *cp1, *sp;
 659:     struct zoneinfo *zp;
 660:     register long n;
 661:     register long ttl;
 662:     u_char **edp = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
 663: 
 664: #ifdef DEBUG
 665:     if (debug >= 5)
 666:         fprintf(ddt,"make_rr(%s, %x, %x, %d, %d) %d zone %d ttl %ld\n",
 667:             name, dp, buf,
 668:             buflen, doadd, dp->d_size, dp->d_zone, dp->d_ttl);
 669: #endif
 670: 
 671:     zp = &zones[dp->d_zone];
 672:     /* check for outdated RR before updating dnptrs by dn_comp() */
 673:     if (zp->z_type == Z_CACHE) {
 674:         ttl = dp->d_ttl - (u_long) tt.tv_sec;
 675:         if ((dp->d_flags & DB_F_HINT) || (ttl <= 0)) {
 676: #ifdef DEBUG
 677: /*XXX*/if (debug >= 3) fprintf(ddt,"make_rr: %ld=>1, x%x\n", ttl, dp->d_flags);
 678: #endif
 679:             ttl = 1;
 680:         }
 681:     } else {
 682:         ttl = zp->z_minimum;        /* really default */
 683:         if (dp->d_ttl > 0)
 684:             ttl = dp->d_ttl;
 685:         if (zp->z_type == Z_SECONDARY) {
 686:             /*
 687: 			 * Set ttl to value received from primary,
 688: 			 * less time since we verified it (but never
 689: 			 * less than a small positive value).
 690: 			 */
 691:             ttl -= tt.tv_sec - zp->z_lastupdate;
 692:             if (ttl <= 0)
 693:                 ttl = 120;
 694:         }
 695:     }
 696: 
 697:     buflen -= RRFIXEDSZ;
 698:     if ((n = dn_comp(name, buf, buflen, (char **)dnptrs, (char **)edp)) < 0)
 699:         return (-1);
 700:     cp = buf + n;
 701:     buflen -= n;
 702:     PUTSHORT((u_short)dp->d_type, cp);
 703:     PUTSHORT((u_short)dp->d_class, cp);
 704:     PUTLONG(ttl, cp);
 705:     sp = cp;
 706:     cp += sizeof(u_short);
 707:     switch (dp->d_type) {
 708:     case T_CNAME:
 709:     case T_MG:
 710:     case T_MR:
 711:     case T_PTR:
 712:         if ((n = dn_comp(dp->d_data, cp, buflen, (char **)dnptrs,
 713:            (char **)edp)) < 0)
 714:             return (-1);
 715:         PUTSHORT((u_short)n, sp);
 716:         cp += n;
 717:         break;
 718: 
 719:     case T_MB:
 720:     case T_NS:
 721:         /* Store domain name in answer */
 722:         if ((n = dn_comp(dp->d_data, cp, buflen, (char **)dnptrs,
 723:            (char **)edp)) < 0)
 724:             return (-1);
 725:         PUTSHORT((u_short)n, sp);
 726:         cp += n;
 727:         if (doadd)
 728:             addname(dp->d_data, dp->d_class);
 729:         break;
 730: 
 731:     case T_SOA:
 732:     case T_MINFO:
 733:         cp1 = dp->d_data;
 734:         if ((n = dn_comp(cp1, cp, buflen, (char **)dnptrs,
 735:             (char **)edp)) < 0)
 736:             return (-1);
 737:         cp += n;
 738:         buflen -= dp->d_type == T_MINFO ? n : n + 5 * sizeof(u_long);
 739:         cp1 += strlen(cp1) + 1;
 740:         if ((n = dn_comp(cp1, cp, buflen, (char **)dnptrs,
 741:             (char **)edp)) < 0)
 742:             return (-1);
 743:         cp += n;
 744:         if (dp->d_type == T_SOA) {
 745:             cp1 += strlen(cp1) + 1;
 746:             bcopy(cp1, cp,
 747:                (int)(n = dp->d_size - (cp1 - dp->d_data)));
 748:             cp += n;
 749:         }
 750:         n = (u_short)(cp - sp) - sizeof(u_short);
 751:         PUTSHORT((u_short)n, sp);
 752:         break;
 753: 
 754:     case T_MX:
 755:         /* cp1 == our data/ cp == data of RR */
 756:         cp1 = dp->d_data;
 757: 
 758:         /* copy preference */
 759:         bcopy(cp1,cp,sizeof(u_short));
 760:         cp += sizeof(u_short);
 761:         cp1 += sizeof(u_short);
 762:         buflen -= sizeof(u_short);
 763: 
 764:         if ((n = dn_comp(cp1, cp, buflen, (char **)dnptrs,
 765:             (char **)edp)) < 0)
 766:             return(-1);
 767:         cp += n;
 768: 
 769:         /* save data length */
 770:         n = (u_short)(cp - sp) - sizeof(u_short);
 771:         PUTSHORT((u_short)n, sp);
 772:         if (doadd)
 773:             addname(cp1, dp->d_class);
 774:         break;
 775: 
 776:     default:
 777:         if (dp->d_size > buflen)
 778:             return (-1);
 779:         bcopy(dp->d_data, cp, dp->d_size);
 780:         PUTSHORT((u_short)dp->d_size, sp);
 781:         cp += dp->d_size;
 782:     }
 783:     return (cp - buf);
 784: }
 785: 
 786: addname(name, class)
 787: register char   *name;
 788: short   class;
 789: {
 790:     register struct addinfo *ap;
 791:     register int n;
 792: 
 793:     for (ap = addinfo, n = addcount; --n >= 0; ap++)
 794:         if (strcasecmp(ap->a_dname, name) == 0)
 795:             return;
 796:     /* add domain name to additional section */
 797:     if (addcount < NADDRECS) {
 798:         addcount++;
 799:         ap->a_dname = name;
 800:         ap->a_class = class;
 801:     }
 802: }
 803: 
 804: /*
 805:  * Lookup addresses for names in addinfo and put into the message's
 806:  * additional section.
 807:  */
 808: doaddinfo(hp, msg, msglen)
 809:     HEADER *hp;
 810:     char *msg;
 811:     int msglen;
 812: {
 813:     register struct namebuf *np;
 814:     register struct databuf *dp;
 815:     register struct addinfo *ap;
 816:     register char *cp;
 817:     struct hashbuf *htp;
 818:     char *fname;
 819:     int n, count, foundstale;
 820: 
 821: #ifdef DEBUG
 822:     if (debug >= 3)
 823:         fprintf(ddt,"doaddinfo() addcount = %d\n", addcount);
 824: #endif
 825: 
 826:     count = 0;
 827:     cp = msg;
 828:     for (ap = addinfo; --addcount >= 0; ap++) {
 829: #ifdef DEBUG
 830:         if (debug >= 3)
 831:             fprintf(ddt,"do additional '%s'\n", ap->a_dname);
 832: #endif
 833:         htp = hashtab;  /* because "nlookup" stomps on arg. */
 834:         np = nlookup(ap->a_dname, &htp, &fname, 0);
 835:         if (np == NULL || fname != ap->a_dname)
 836:             continue;
 837: #ifdef DEBUG
 838:         if (debug >= 3)
 839:             fprintf(ddt,"found it\n");
 840: #endif
 841:         foundstale = 0;
 842:         /* look for the data */
 843:         for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
 844:             if (!match(dp, (int)ap->a_class, T_A))
 845:                 continue;
 846:             if (stale(dp)) {
 847:                 foundstale++;
 848: #ifdef DEBUG
 849:                 if (debug)
 850:                     fprintf(ddt,"doaddinfo: stale entry '%s'%s\n",
 851:                         np->n_dname,
 852:                         (dp->d_flags&DB_F_HINT) ? " hint":"" );
 853: #endif
 854:                 continue;
 855:             }
 856:             /*
 857: 			 *  Should be smart and eliminate duplicate
 858: 			 *  data here.	XXX
 859: 			 */
 860:             if ((n = make_rr(ap->a_dname, dp, cp, msglen, 0)) < 0)
 861:                 break;
 862: #ifdef DEBUG
 863:             if (debug >= 5)
 864:                 fprintf(ddt,"addinfo: adding address data n = %d\n",
 865:                    n);
 866: #endif
 867:             cp += n;
 868:             msglen -= n;
 869:             count++;
 870:         }
 871:         if (foundstale) {
 872:             /* Cache invalidate the address RR's */
 873:             delete_all(np, (int)ap->a_class, T_A);
 874:             (void) sysquery(ap->a_dname, (int)ap->a_class, T_A);
 875:         }
 876:     }
 877:     hp->arcount = htons((u_short)count);
 878:     return (cp - msg);
 879: }
 880: 
 881: doaddauth(hp, cp, buflen, np, dp)
 882:     register HEADER *hp;
 883:     char *cp;
 884:     int buflen;
 885:     struct namebuf *np;
 886:     struct databuf *dp;
 887: {
 888:     char dnbuf[MAXDNAME];
 889:     int n;
 890: 
 891:     getname(np, dnbuf, sizeof(dnbuf));
 892:     if (stale(dp) || (n = make_rr(dnbuf, dp, cp, buflen, 1)) <= 0) {
 893: #ifdef DEBUG
 894:         if (debug)
 895:             fprintf(ddt,"doaddauth: can't add '%s' (%d)\n",
 896:                 dnbuf, buflen);
 897: #endif
 898:         return(0);
 899:     } else {
 900:         hp->nscount = htons(1);
 901:         return(n);
 902:     }
 903: }
 904: 
 905: 
 906: /*
 907:  * Get the domain name of 'np' and put in 'buf'.  Bounds checking is done.
 908:  */
 909: getname(np, buf, buflen)
 910:     struct namebuf *np;
 911:     char *buf;
 912:     int buflen;
 913: {
 914:     register char *cp;
 915:     register int i;
 916: 
 917:     cp = buf;
 918:     while (np != NULL) {
 919:         if ((i = strlen(np->n_dname))+1 >= buflen) {
 920:             *cp = '\0';
 921:             syslog(LOG_ERR, "domain name too long: %s...\n", buf);
 922:             strcpy(buf, "Name_Too_Long");
 923:             return;
 924:         }
 925:         if (cp != buf)
 926:             *cp++ = '.';
 927:         (void) strcpy(cp, np->n_dname);
 928:         cp += i;
 929:         buflen -= (i+1);
 930:         np = np->n_parent;
 931:     }
 932:     *cp = '\0';
 933: }
 934: 
 935: /*
 936:  * Do a zone transfer. SOA record already sent.
 937:  */
 938: doaxfr(np, rfp, isroot)
 939:     register struct namebuf *np;
 940:     FILE *rfp;
 941:     int isroot;
 942: {
 943:     register struct databuf *dp;
 944:     register int n;
 945:     struct hashbuf *htp;
 946:     struct databuf *gdp;    /* glue databuf */
 947:     struct namebuf *gnp;    /* glue namebuf */
 948:     struct namebuf **npp, **nppend;
 949:     char msg[PACKETSZ];
 950:     char *cp;
 951:     char *fname;
 952:     char dname[MAXDNAME];
 953:     HEADER *hp = (HEADER *) msg;
 954:     int fndns;
 955: 
 956: #ifdef DEBUG
 957:     if (debug && isroot)
 958:         fprintf(ddt,"doaxfr()\n");
 959: #endif
 960:     fndns = 0;
 961:     hp->id = 0;
 962:     hp->opcode = QUERY;
 963:     hp->aa = hp->tc = hp->ra = hp->pr = hp->rd = 0;
 964:     hp->qr = 1;
 965:     hp->rcode = NOERROR;
 966:     hp->qdcount = 0;
 967:     hp->ancount = htons(1);
 968:     hp->nscount = 0;
 969:     hp->arcount = 0;
 970:     cp = msg + sizeof(HEADER);
 971:     getname(np, dname, sizeof(dname));
 972: 
 973:     /* first do data records */
 974:     for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
 975:         /*
 976: 		 * Skip the root SOA record (marks end of data);
 977: 		 * don't send SOA for subdomains, as we're not sending them.
 978: 		 */
 979:         if (dp->d_type == T_SOA)
 980:             continue;
 981:         if (dp->d_type == T_NS)
 982:             fndns = 1;
 983:         if (dp->d_zone == 0 || stale(dp))
 984:             continue;
 985:         if ((n = make_rr(dname, dp, cp, sizeof(msg)-sizeof(HEADER), 0)) < 0)
 986:             continue;
 987:         fwritemsg(rfp, msg, n + sizeof(HEADER));
 988: 
 989:         if (dp->d_type == T_NS) {
 990:             /*  Glue the sub domains together by sending
 991: 			 *  the address records for the sub domain
 992: 			 *  name servers along.
 993: 			 */
 994:             htp = hashtab;
 995:             cp = msg + sizeof(HEADER);
 996:             gnp = nlookup(dp->d_data, &htp, &fname, 0);
 997:             if (gnp == NULL || fname != dp->d_data)
 998:                 continue;
 999:             for(gdp=gnp->n_data; gdp != NULL; gdp=gdp->d_next) {
1000:                 if (gdp->d_type != T_A || stale(gdp))
1001:                 continue;
1002:                 if ((n = make_rr(fname, gdp, cp,
1003:                     sizeof(msg)-sizeof(HEADER), 0)) < 0)
1004:                 continue;
1005:                 fwritemsg(rfp, msg, n + sizeof(HEADER));
1006:             }
1007:         }
1008:     }
1009: 
1010:     /* next do subdomains, unless delegated */
1011:     if ((isroot == 0 && fndns) || np->n_hash == NULL)
1012:         return;
1013:     npp = np->n_hash->h_tab;
1014:     nppend = npp + np->n_hash->h_size;
1015:     while (npp < nppend) {
1016:         for (np = *npp++; np != NULL; np = np->n_next) {
1017:             doaxfr(np, rfp, 0);
1018:         }
1019:     }
1020: #ifdef DEBUG
1021:     if (debug && isroot)
1022:         fprintf(ddt,"exit doaxfr()\n");
1023: #endif
1024: }
1025: 
1026: #ifdef ALLOW_UPDATES
1027: /*
1028:  * Called by UPDATE{A,D,DA,M,MA} to initiate a dynamic update.  If this is the
1029:  * primary server for the zone being updated, we update the zone's serial
1030:  * number and then call doupdate directly. If this is a secondary, we just
1031:  * forward the update; this way, if the primary update fails (e.g., if the
1032:  * primary is unavailable), we don't update the secondary; if the primary
1033:  * update suceeds, ns_resp will get called with the response (when it comes
1034:  * in), and then update the secondary's copy.
1035:  */
1036: InitDynUpdate(hp, nsp, msg, msglen, startcp, from, qsp, dfd)
1037:     register HEADER *hp;
1038:     struct databuf *nsp[];
1039:     char *msg;
1040:     int msglen;
1041:     char *startcp;
1042:     struct sockaddr_in *from;
1043:     struct qstream *qsp;
1044:     int dfd;
1045: {
1046:     struct zoneinfo *zp;
1047:     char dnbuf[MAXDNAME];
1048:     struct hashbuf *htp = hashtab;  /* lookup relative to root */
1049:     struct namebuf *np;
1050:     struct databuf *olddp, *newdp, *dp;
1051:     struct databuf **nspp;
1052:     char *fname;
1053:     char *data;
1054:     register u_char *cp = startcp;
1055:     short class, type;
1056:     int n, size, zonenum;
1057:     char ZoneName[MAXDNAME], *znp;
1058: 
1059:     if ((n = dn_expand(msg, msg + msglen, cp, dnbuf, sizeof(dnbuf))) < 0) {
1060: #ifdef DEBUG
1061:         if (debug)
1062:             fprintf(ddt,"FORMERR InitDynUpdate expand name failed\n");
1063: #endif
1064:         hp->rcode = FORMERR;
1065:         return(FORMERR);
1066:     }
1067:     cp += n;
1068:     GETSHORT(type, cp);
1069:     if (type == T_SOA) {    /* T_SOA updates not allowed */
1070:         hp->rcode = REFUSED;
1071: #ifdef DEBUG
1072:         if (debug)
1073:             fprintf(ddt, "InitDynUpdate: REFUSED - SOA update\n");
1074: #endif
1075:         return(REFUSED);
1076:     }
1077:     GETSHORT(class, cp);
1078:     cp += sizeof(u_long);
1079:     GETSHORT(size, cp);
1080:     data = cp;
1081: /****XXX - need bounds checking here ****/
1082:     cp += size;
1083: 
1084:     if ((zonenum = findzone(dnbuf, class)) == 0) {  /* zone not found */
1085:         hp->rcode = NXDOMAIN;
1086:         return(NXDOMAIN);
1087:     }
1088:     zp = &zones[zonenum];
1089: 
1090:     /* Disallow updates for which we aren't authoratative.  Note: the
1091: 	   following test doesn't work right:  If it's for a non-local zone,
1092: 	   we will think it's a primary but be unable to lookup the namebuf,
1093: 	   thus returning 'NXDOMAIN' */
1094:     if (zp->z_type != Z_PRIMARY && zp->z_type != Z_SECONDARY) {
1095:         hp->rcode = REFUSED;
1096: #ifdef DEBUG
1097:         if (debug)
1098:             fprintf(ddt, "InitDynUpdate: REFUSED - non-primary, non-sedondary update\n");
1099: #endif
1100:         return(REFUSED);
1101:     }
1102: 
1103:     /*
1104: 	 * Lookup the zone namebuf.  Lookup "xyz" not "xyz.", since
1105: 	 * otherwise the lookup fails, because '.' may have a nil n_hash
1106: 	 * associated with it.
1107: 	 */
1108:     strcpy(ZoneName, zp->z_origin);
1109:     znp = &ZoneName[strlen(ZoneName) - 1];
1110:     if (*znp == '.')
1111:         *znp = NULL;
1112:     np = nlookup(ZoneName, &htp, &fname, 0);
1113:     if ((np == NULL) || (fname != ZoneName)) {
1114: #ifdef DEBUG
1115:         if (debug)
1116:             fprintf(ddt, "InitDynUpdate: lookup failed on zone (%s)\n",
1117:                 ZoneName);
1118: #endif DEBUG
1119:             syslog(LOG_ERR, "InitDynUpdate: lookup failed on zone (%s)\n",
1120:                ZoneName);
1121:         hp->rcode = NXDOMAIN;
1122:         return(NXDOMAIN);
1123:     }
1124: 
1125:     /*
1126: 	 * If this is the primary copy increment the serial number.  Don't
1127: 	 * increment the serial number if this is a secondary; this way, if 2
1128: 	 * different secondaries both update the primary, they will both have
1129: 	 * lower serial numbers than the primary has, and hence eventually
1130: 	 * refresh and get all updates and become consistent.
1131: 	 *
1132: 	 * Note that the serial number must be incremented in both the zone
1133: 	 * data structure and the zone's namebuf.
1134: 	 */
1135:     switch (zp->z_type) {
1136:     case Z_SECONDARY:       /* forward update to primary */
1137:         nspp = nsp;
1138:         dp = np->n_data;
1139:         while (dp != NULL) {
1140:             if (match(dp, class, T_NS)) {
1141:                 if (nspp < &nsp[NSMAX-1])
1142:                     *nspp++ = dp;
1143:                 else
1144:                     break;
1145:             }
1146:             dp = dp->d_next;
1147:         }
1148:         *nspp = NULL; /* Delimiter */
1149:         if (ns_forw(nsp, msg, msglen, from, qsp, dfd, NULL) < 0) {
1150:             hp->rcode = SERVFAIL;
1151:             return(SERVFAIL);
1152:         }
1153:         return(FORWARDED);
1154: 
1155:     case Z_PRIMARY:
1156:         zp->z_serial++;
1157:         olddp = np->n_data; /* old databuf */
1158:         /* Find the SOA record */
1159:         for (olddp = np->n_data; olddp != NULL; olddp = olddp->d_next)
1160:             if (match(olddp, class, T_SOA))
1161:                 break;
1162:         if (olddp == NULL) {
1163: #ifdef DEBUG
1164:             if (debug)
1165:                 fprintf(ddt,"InitDynUpdate: Couldn't find SOA record for '%s'\n",
1166:                         ZoneName);
1167: #endif DEBUG
1168:             syslog(LOG_ERR,
1169:                "InitDynUpdate: Couldn't find SOA record for '%s'\n"
1170: ,
1171:                ZoneName);
1172:             hp->rcode = NXDOMAIN;
1173:             return(NXDOMAIN);
1174:         }
1175:         newdp = savedata(olddp->d_class, olddp->d_type, olddp->d_ttl,
1176:                  olddp->d_data, olddp->d_size);
1177:         newdp->d_zone = olddp->d_zone;
1178:         cp = newdp->d_data;
1179:         cp += strlen(cp) + 1; /* skip origin string */
1180:         cp += strlen(cp) + 1; /* skip in-charge string */
1181:         putlong((u_long)(zp->z_serial), cp);
1182: #ifdef DEBUG
1183:         if (debug >= 4) {
1184:             fprintf(ddt, "after stuffing data into newdp:\n");
1185:             printSOAdata(newdp);
1186:         }
1187: #endif DEBUG
1188: 
1189:         if ((n = db_update(ZoneName, olddp, newdp, DB_DELETE,
1190:                    hashtab)) != NOERROR) {
1191: #ifdef DEBUG
1192:             if (debug)
1193:                 fprintf(ddt,"InitDynUpdate: SOA update failed\n");
1194: #endif DEBUG
1195:             hp->rcode = NOCHANGE;
1196:             return(NOCHANGE);
1197:         }
1198: 
1199:         /* Now update the RR itself */
1200:         if (doupdate(msg, msglen, msg + sizeof(HEADER),
1201:                  zonenum, (struct databuf *)0, DB_NODATA) < 0) {
1202: #ifdef DEBUG
1203:             if (debug)
1204:                 fprintf(ddt,"InitDynUpdate: doupdate failed\n");
1205: #endif DEBUG
1206:             /* doupdate fills in rcode */
1207:             return(hp->rcode);
1208:         }
1209:         zp->hasChanged++;
1210:         return(NOERROR);
1211:     }
1212: }
1213: 
1214: #ifdef DEBUG
1215: /*
1216:  * Print the contents of the data in databuf pointed to by dp for an SOA record
1217:  */
1218: printSOAdata(dp)
1219:     struct databuf *dp;
1220: {
1221:     register u_char *cp;
1222: 
1223:     if (!debug)
1224:         return;  /* Otherwise fprintf to ddt will bomb */
1225:     cp = dp->d_data;
1226:     fprintf(ddt, "printSOAdata(%x): origin(%x)='%s'\n", dp, cp, cp);
1227:     cp += strlen(cp) + 1; /* skip origin string */
1228:     fprintf(ddt, "printSOAdata: in-charge(%x)='%s'\n", cp, cp);
1229:     cp += strlen(cp) + 1; /* skip in-charge string */
1230:     fprintf(ddt, "printSOAdata: serial(%x)=%ld\n", cp, _getlong(cp));
1231: }
1232: #endif DEBUG
1233: #endif ALLOW_UPDATES
1234: 
1235: struct databuf *
1236: rm_datum(dp, np, pdp)
1237: register struct databuf *pdp, *dp;
1238: register struct namebuf *np;
1239: {
1240:     register struct databuf *ndp = dp->d_next;
1241: 
1242: #ifdef DEBUG
1243:     if (debug > 2)
1244:         fprintf(ddt, "rm_datum(%x, %x, %x) -> %x\n",
1245:             dp, np->n_data, pdp, ndp);
1246: #endif DEBUG
1247:     if (pdp == NULL)
1248:         np->n_data = ndp;
1249:     else
1250:         pdp->d_next = ndp;
1251:     rminv(dp);
1252:     (void) free((char *)dp);
1253:     return(ndp);
1254: }
1255: 
1256: startxfr(qsp, np, msg, msglen)
1257:     struct qstream *qsp;
1258:     struct namebuf *np;
1259:     char    *msg;
1260:     int msglen;
1261: {
1262:     register FILE *rfp;
1263:     int fdstat;
1264: 
1265: #ifdef DEBUG
1266:     if (debug >= 5)
1267:         fprintf(ddt,"startxfr()\n");
1268: #endif
1269:     /*
1270: 	 * child does the work while
1271: 	 * the parent continues
1272: 	 */
1273:     if (fork() == 0) {
1274: #ifdef DEBUG
1275:         if (debug >= 5)
1276:             fprintf(ddt,"startxfr: child pid %d\n", getpid());
1277: #endif
1278:         rfp = fdopen(qsp->s_rfd, "w");
1279:         setproctitle("zone XFR to", qsp->s_rfd);
1280:         fdstat = fcntl(qsp->s_rfd, F_GETFL, 0);
1281:         if (fdstat != -1)
1282:             (void) fcntl(qsp->s_rfd, F_SETFL, fdstat & ~FNDELAY);
1283:         fwritemsg(rfp, msg, msglen);
1284:         doaxfr(np, rfp, 1);
1285:         fwritemsg(rfp, msg, msglen);
1286:         (void) fflush(rfp);
1287:         exit(0);
1288:     }
1289:     qsp->s_time = tt.tv_sec;
1290:     qsp->s_refcnt--;
1291: }

Defined functions

InitDynUpdate defined in line 1036; used 1 times
addname defined in line 786; used 2 times
doaddauth defined in line 881; used 2 times
doaddinfo defined in line 808; used 2 times
doaxfr defined in line 938; used 2 times
fwritemsg defined in line 578; used 4 times
make_rr defined in line 651; used 6 times
ns_req defined in line 53; used 2 times
printSOAdata defined in line 1218; used 1 times
stale defined in line 620; used 6 times
startxfr defined in line 1256; used 1 times

Defined variables

addcount defined in line 40; used 7 times
addinfo defined in line 39; used 2 times
dnptrs defined in line 44; used 14 times
needs_prime_cache defined in line 42; used 5 times
sccsid defined in line 14; never used
xfr_disabled defined in line 41; used 1 times

Defined struct's

addinfo defined in line 34; used 6 times

Defined macros

FORWARDED defined in line 490; used 2 times
NADDRECS defined in line 29; used 2 times
Last modified: 1988-09-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 8167
Valid CSS Valid XHTML 1.0 Strict