386BSD 0.0 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Thu, 25 Apr 1991 00:58:50 +0000 (16:58 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Thu, 25 Apr 1991 00:58:50 +0000 (16:58 -0800)
Work on file usr/src/usr.sbin/named/db_glue.c
Work on file usr/src/usr.sbin/named/db_dump.c
Work on file usr/src/usr.sbin/named/db.h
Work on file usr/src/usr.sbin/named/db_lookup.c
Work on file usr/src/usr.sbin/named/db_reload.c
Work on file usr/src/usr.sbin/named/db_load.c
Work on file usr/src/usr.sbin/named/db_update.c
Work on file usr/src/usr.sbin/named/named.8
Work on file usr/src/usr.sbin/named/db_save.c
Work on file usr/src/usr.sbin/named/ns.h
Work on file usr/src/usr.sbin/named/ns_forw.c
Work on file usr/src/usr.sbin/named/ns_init.c
Work on file usr/src/usr.sbin/named/ns_maint.c
Work on file usr/src/usr.sbin/named/ns_resp.c
Work on file usr/src/usr.sbin/named/ns_sort.c
Work on file usr/src/usr.sbin/named/pathnames.h
Work on file usr/src/usr.sbin/named/ns_stats.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.0/src

17 files changed:
usr/src/usr.sbin/named/db.h [new file with mode: 0644]
usr/src/usr.sbin/named/db_dump.c [new file with mode: 0644]
usr/src/usr.sbin/named/db_glue.c [new file with mode: 0644]
usr/src/usr.sbin/named/db_load.c [new file with mode: 0644]
usr/src/usr.sbin/named/db_lookup.c [new file with mode: 0644]
usr/src/usr.sbin/named/db_reload.c [new file with mode: 0644]
usr/src/usr.sbin/named/db_save.c [new file with mode: 0644]
usr/src/usr.sbin/named/db_update.c [new file with mode: 0644]
usr/src/usr.sbin/named/named.8 [new file with mode: 0644]
usr/src/usr.sbin/named/ns.h [new file with mode: 0644]
usr/src/usr.sbin/named/ns_forw.c [new file with mode: 0644]
usr/src/usr.sbin/named/ns_init.c [new file with mode: 0644]
usr/src/usr.sbin/named/ns_maint.c [new file with mode: 0644]
usr/src/usr.sbin/named/ns_resp.c [new file with mode: 0644]
usr/src/usr.sbin/named/ns_sort.c [new file with mode: 0644]
usr/src/usr.sbin/named/ns_stats.c [new file with mode: 0644]
usr/src/usr.sbin/named/pathnames.h [new file with mode: 0644]

diff --git a/usr/src/usr.sbin/named/db.h b/usr/src/usr.sbin/named/db.h
new file mode 100644 (file)
index 0000000..e065b7a
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 1985, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)db.h        4.16 (Berkeley) 6/1/90
+ */
+
+/*
+ * Global structures and variables for data base routines.
+ */
+
+#define INVBLKSZ       7       /* # of namebuf pointers per block */
+#define INVHASHSZ      919     /* size of inverse hash table */
+
+       /* max length of data in RR data field */
+#define MAXDATA                2048
+
+/*
+ * Hash table structures.
+ */
+struct databuf {
+       struct  databuf *d_next;        /* linked list */
+       u_long  d_ttl;                  /* time to live */
+       short   d_flags;
+       short   d_zone;                 /* zone number */
+       short   d_class;                /* class number */
+       short   d_type;                 /* type number */
+       short   d_mark;                 /* place to mark data */
+       short   d_size;                 /* size of data area */
+       u_long  d_nstime;               /* NS response time, milliseconds */
+       char    d_data[1];              /* the data is malloc'ed to size */
+};
+#define DATASIZE(n) (sizeof(struct databuf) - 1 + n)
+
+/*
+ * d_flags definitions
+ */
+#define DB_F_HINT       0x01   /* databuf belongs to fcachetab */
+
+struct namebuf {
+       char    *n_dname;               /* domain name */
+       u_int   n_hashval;              /* hash value of n_dname */
+       struct  namebuf *n_next;        /* linked list */
+       struct  databuf *n_data;        /* data records */
+       struct  namebuf *n_parent;      /* parent domain */
+       struct  hashbuf *n_hash;        /* hash table for children */
+};
+
+struct invbuf {
+       struct  invbuf *i_next;         /* linked list */
+       struct  namebuf *i_dname[INVBLKSZ];     /* domain name */
+};
+
+struct hashbuf {
+       int     h_size;                 /* size of hash table */
+       int     h_cnt;                  /* number of entries */
+       struct  namebuf *h_tab[1];      /* malloc'ed as needed */
+};
+#define HASHSIZE(s) (s*sizeof(struct namebuf *) + 2*sizeof(int))
+
+#define HASHSHIFT      3
+#define HASHMASK       0x1f
+
+/*
+ * Flags to updatedb
+ */
+#define DB_NODATA      0x01    /* data should not exist */
+#define DB_MEXIST      0x02    /* data must exist */
+#define DB_DELETE      0x04    /* delete data if it exists */
+#define DB_NOTAUTH     0x08    /* must not update authoritative data */
+#define DB_NOHINTS      0x10   /* don't reflect update in fcachetab */
+
+#define DB_Z_CACHE      (0)    /* cache-zone-only db_dump()  */
+#define DB_Z_ALL        (-1)   /* normal db_dump() */
+
+/*
+ * Error return codes
+ */
+#define OK             0
+#define NONAME         -1
+#define NOCLASS                -2
+#define NOTYPE         -3
+#define NODATA         -4
+#define DATAEXISTS     -5
+#define NODBFILE       -6
+#define TOOMANYZONES   -7
+#define GOODDB         -8
+#define NEWDB          -9
+#define AUTH           -10
+
+extern struct hashbuf *hashtab;                /* root hash table */
+extern struct invbuf *invtab[];                /* inverse hash table */
+extern struct hashbuf *fcachetab;      /* hash table for cache read from file*/
+
+extern struct namebuf *nlookup();
+extern struct namebuf *savename();
+extern struct databuf *savedata();
+extern struct databuf *rm_datum();
+extern struct hashbuf *savehash();
+extern struct invbuf *saveinv();
+extern char *savestr();
+extern char *malloc(), *realloc(), *calloc();
diff --git a/usr/src/usr.sbin/named/db_dump.c b/usr/src/usr.sbin/named/db_dump.c
new file mode 100644 (file)
index 0000000..2aa2e4c
--- /dev/null
@@ -0,0 +1,782 @@
+/*
+ * Copyright (c) 1986, 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)db_dump.c  4.33 (Berkeley) 3/3/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ns.h"
+#include "db.h"
+#include "pathnames.h"
+
+#ifdef DUMPFILE
+char   *dumpfile = DUMPFILE;
+#else
+char   *dumpfile = _PATH_DUMPFILE;
+#endif
+
+extern char *cache_file;
+
+/*
+ * Dump current cache in a format similar to RFC 883.
+ *
+ * We try to be careful and determine whether the operation succeeded
+ * so that the new cache file can be installed.
+ */
+
+#define DB_ROOT_TIMBUF 3600
+
+doachkpt()
+{
+    extern int errno;
+    FILE *fp;
+    char tmpcheckfile[256];
+
+    /* nowhere to checkpoint cache... */
+    if (cache_file == NULL) {
+#ifdef DEBUG
+        if (debug >= 3)
+            fprintf(ddt,"doachkpt(to where?)\n");
+#endif
+        return;
+    }
+
+#ifdef DEBUG
+    if (debug >= 3)
+        fprintf(ddt,"doachkpt()\n");
+#endif
+
+    (void) sprintf(tmpcheckfile, "%s.chk", cache_file);
+    if ((fp = fopen(tmpcheckfile, "w")) == NULL) {
+#ifdef DEBUG
+        if (debug >= 3)
+            fprintf(ddt,"doachkpt(can't open %s for write)\n", tmpcheckfile);
+#endif
+        return;
+    }
+
+    (void) gettime(&tt);
+    fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec));
+    fflush(fp);
+    if (ferror(fp)) {
+#ifdef DEBUG
+        if (debug >= 3)
+            fprintf(ddt,"doachkpt(write to checkpoint file failed)\n");
+#endif
+        return;
+    }
+
+    if (fcachetab != NULL) {
+       int n;
+       if ((n = scan_root(hashtab)) < MINROOTS) {
+           syslog(LOG_ERR, "%d root hints... (too low)", n);
+           fprintf(fp, "; ---- Root hint cache dump ----\n");
+           (void) db_dump(fcachetab, fp, DB_Z_CACHE, "");
+       }
+    }
+
+    if (hashtab != NULL) {
+        fprintf(fp, "; ---- Cache dump ----\n");
+        if (db_dump(hashtab, fp, DB_Z_CACHE, "") == NODBFILE) {
+#ifdef DEBUG
+            if (debug >= 3)
+                fprintf(ddt,"doachkpt(checkpoint failed)\n");
+#endif
+            (void) fclose(fp);
+            return;
+        }
+    }
+
+    (void) fsync(fileno(fp));
+    if (fclose(fp) == EOF) {
+#ifdef DEBUG
+        if (debug >= 3)
+            fprintf(ddt,"doachkpt(close failed)\n");
+#endif
+        return;
+    }
+
+    if (rename(tmpcheckfile, cache_file)) {
+#ifdef DEBUG
+        if (debug >= 3)
+            fprintf(ddt,"doachkpt(install %s to %s failed, %d)\n",
+                    tmpcheckfile,cache_file, errno);
+#endif
+    }
+}
+
+/*
+ * What we do is scan the root hint cache to make sure there are at least
+ * MINROOTS root pointers with non-0 TTL's so that the checkpoint will not
+ * lose the root.  Failing this, all pointers are written out w/ TTL ~0
+ * (root pointers timed out and prime_cache() not done or failed).
+ */
+#define TIMBUF 300
+
+int
+scan_root(htp)
+       struct hashbuf *htp;
+{
+       register struct databuf *dp;
+       register struct namebuf *np;
+       struct timeval soon;
+       int roots = 0;
+
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"scan_root(0x%x)\n", htp);
+#endif
+
+       /* metric by which we determine whether a root NS pointer is still */
+       /* valid (will be written out if we do a dump).  we also add some */
+       /* time buffer for safety... */
+       (void) gettime(&soon);
+       soon.tv_sec += TIMBUF;
+
+       for (np = htp->h_tab[0]; np != NULL; np = np->n_next) {
+               if (np->n_dname[0] == '\0') {
+                       dp = np->n_data;
+                       while (dp != NULL) {
+                               if (dp->d_type == T_NS &&
+                                   dp->d_ttl > soon.tv_sec) {
+                                       roots++;
+                                       if (roots >= MINROOTS)
+                                               return (roots);
+                               }
+                               dp = dp->d_next;
+                       }
+               }
+       }
+       return (roots);
+}
+
+#ifdef notdef
+mark_cache(htp, ttl)
+    struct hashbuf *htp;
+    int ttl;
+{
+    register struct databuf *dp;
+    register struct namebuf *np;
+    struct namebuf **npp, **nppend;
+    struct timeval soon;
+
+#ifdef DEBUG
+    if (debug)
+        fprintf(ddt,"mark_cache()\n");
+#endif
+
+    (void) gettime(&soon);
+    soon.tv_sec += TIMBUF;
+
+    npp = htp->h_tab;
+    nppend = npp + htp->h_size;
+    while (npp < nppend) {
+        for (np = *npp++; np != NULL; np = np->n_next) {
+            if (np->n_data == NULL)
+                continue;
+            for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+                if (dp->d_ttl < soon.tv_sec)
+                    dp->d_ttl = ttl;
+            }
+        }
+    }
+
+    npp = htp->h_tab;
+    nppend = npp + htp->h_size;
+    while (npp < nppend) {
+        for (np = *npp++; np != NULL; np = np->n_next) {
+            if (np->n_hash == NULL)
+                continue;
+            mark_cache(np->n_hash, ttl);
+        }
+    }
+}
+#endif notdef
+
+/*
+ * Dump current data base in a format similar to RFC 883.
+ */
+
+doadump()
+{
+       FILE    *fp;
+
+#ifdef DEBUG
+       if (debug >= 3)
+               fprintf(ddt,"doadump()\n");
+#endif
+
+       if ((fp = fopen(dumpfile, "w")) == NULL)
+               return;
+       gettime(&tt);
+       fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec));
+       fprintf(fp, "; --- Cache & Data ---\n");
+       if (hashtab != NULL)
+               (void) db_dump(hashtab, fp, DB_Z_ALL, "");
+       fprintf(fp, "; --- Hints ---\n");
+       if (fcachetab != NULL)
+               (void) db_dump(fcachetab, fp, DB_Z_ALL, "");
+       (void) fclose(fp);
+}
+
+#ifdef ALLOW_UPDATES
+/* Create a disk database to back up zones 
+ */
+zonedump(zp)
+    register struct zoneinfo *zp;
+{
+       FILE    *fp;
+       char *fname;
+       struct hashbuf *htp;
+       char *op;
+       struct stat st;
+
+       /* Only dump zone if there is a cache specified */
+       if (zp->z_source && *(zp->z_source)) {
+#ifdef DEBUG
+           if (debug)
+                   fprintf(ddt, "zonedump(%s)\n", zp->z_source);
+#endif
+
+           if ((fp = fopen(zp->z_source, "w")) == NULL)
+                   return;
+           if (op = index(zp->z_origin, '.'))
+               op++;
+           gettime(&tt);
+           htp = hashtab;
+           if (nlookup(zp->z_origin, &htp, &fname, 0) != NULL) {
+                   db_dump(htp, fp, zp-zones, (op == NULL ? "" : op));
+#ifdef ALLOW_UPDATES
+                   zp->hasChanged = 0;         /* Checkpointed */
+#endif ALLOW_UPDATES
+           }
+           (void) fclose(fp);
+           if (stat(zp->z_source, &st) == 0)
+                   zp->z_ftime = st.st_mtime;
+       }
+#ifdef DEBUG
+           else if (debug)
+               fprintf(ddt, "zonedump: no zone to dump\n");
+#endif
+}
+#endif
+
+int
+db_dump(htp, fp, zone, origin)
+       int zone;
+       struct hashbuf *htp;
+       FILE *fp;
+       char *origin;
+{
+       register struct databuf *dp;
+       register struct namebuf *np;
+       struct namebuf **npp, **nppend;
+       char dname[MAXDNAME];
+       u_long n;
+       u_long addr;
+       u_short i;
+       int j;
+       register u_char *cp;
+       u_char *end;
+       char *proto;
+       extern char *inet_ntoa(), *protocolname(), *servicename();
+       int found_data, tab, printed_origin = 0;
+
+       npp = htp->h_tab;
+       nppend = npp + htp->h_size;
+       while (npp < nppend) {
+           for (np = *npp++; np != NULL; np = np->n_next) {
+               if (np->n_data == NULL)
+                       continue;
+               /* Blecch - can't tell if there is data here for the
+                * right zone, so can't print name yet
+                */
+               found_data = 0;
+               /* we want a snapshot in time... */
+               for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+                       /* Is the data for this zone? */
+                       if (zone != DB_Z_ALL && dp->d_zone != zone)
+                           continue;
+                       if (dp->d_zone == DB_Z_CACHE &&
+                           dp->d_ttl <= tt.tv_sec &&
+                           (dp->d_flags & DB_F_HINT) == 0)
+                               continue;
+                       if (!printed_origin) {
+                           fprintf(fp, "$ORIGIN %s.\n", origin);
+                           printed_origin++;
+                       }
+                       tab = 0;
+                       if (!found_data) {
+                           if (np->n_dname[0] == 0) {
+                               if (origin[0] == 0)
+                                   fprintf(fp, ".\t");
+                               else
+                                   fprintf(fp, ".%s.\t", origin); /* ??? */
+                           } else
+                               fprintf(fp, "%s\t", np->n_dname);
+                           if (strlen(np->n_dname) < 8)
+                               tab = 1;
+                           found_data++;
+                       } else {
+                           (void) putc('\t', fp);
+                           tab = 1;
+                       }
+                       if (dp->d_zone == DB_Z_CACHE) {
+                           if (dp->d_flags & DB_F_HINT &&
+                               (long)(dp->d_ttl - tt.tv_sec) < DB_ROOT_TIMBUF)
+                                   fprintf(fp, "%d\t", DB_ROOT_TIMBUF);
+                           else
+                                   fprintf(fp, "%d\t",
+                                       (int)(dp->d_ttl - tt.tv_sec));
+                       } else if (dp->d_ttl != 0 &&
+                           dp->d_ttl != zones[dp->d_zone].z_minimum)
+                               fprintf(fp, "%d\t", (int)dp->d_ttl);
+                       else if (tab)
+                           (void) putc('\t', fp);
+                       fprintf(fp, "%s\t%s\t", p_class(dp->d_class),
+                               p_type(dp->d_type));
+                       cp = (u_char *)dp->d_data;
+                       /*
+                        * Print type specific data
+                        */
+                       switch (dp->d_type) {
+                       case T_A:
+                               switch (dp->d_class) {
+                               case C_IN:
+                               case C_HS:
+                                       GETLONG(n, cp);
+                                       n = htonl(n);
+                                       fprintf(fp, "%s",
+                                          inet_ntoa(*(struct in_addr *)&n));
+                                       break;
+                               }
+                               if (dp->d_nstime)
+                                       fprintf(fp, "\t; %d", dp->d_nstime);
+                               fprintf(fp, "\n");
+                               break;
+                       case T_CNAME:
+                       case T_MB:
+                       case T_MG:
+                       case T_MR:
+                       case T_PTR:
+                               if (cp[0] == '\0')
+                                       fprintf(fp, ".\n");
+                               else
+                                       fprintf(fp, "%s.\n", cp);
+                               break;
+
+                       case T_NS:
+                               cp = (u_char *)dp->d_data;
+                               if (cp[0] == '\0')
+                                       fprintf(fp, ".\t");
+                               else
+                                       fprintf(fp, "%s.", cp);
+                               if (dp->d_nstime)
+                                       fprintf(fp, "\t; %d???", dp->d_nstime);
+                               fprintf(fp, "\n");
+                               break;
+
+                       case T_HINFO:
+                               if (n = *cp++) {
+                                       fprintf(fp, "\"%.*s\"", (int)n, cp);
+                                       cp += n;
+                               } else
+                                       fprintf(fp, "\"\"");
+                               if (n = *cp++)
+                                       fprintf(fp, " \"%.*s\"", (int)n, cp);
+                               else
+                                       fprintf(fp, " \"\"");
+                               (void) putc('\n', fp);
+                               break;
+
+                       case T_SOA:
+                               fprintf(fp, "%s.", cp);
+                               cp += strlen((char *)cp) + 1;
+                               fprintf(fp, " %s. (\n", cp);
+                               cp += strlen((char *)cp) + 1;
+                               GETLONG(n, cp);
+                               fprintf(fp, "\t\t%lu", n);
+                               GETLONG(n, cp);
+                               fprintf(fp, " %lu", n);
+                               GETLONG(n, cp);
+                               fprintf(fp, " %lu", n);
+                               GETLONG(n, cp);
+                               fprintf(fp, " %lu", n);
+                               GETLONG(n, cp);
+                               fprintf(fp, " %lu )\n", n);
+                               break;
+
+                       case T_MX:
+                               GETSHORT(n, cp);
+                               fprintf(fp,"%lu", n);
+                               fprintf(fp," %s.\n", cp);
+                               break;
+
+                       case T_TXT:
+                               end = (u_char *)dp->d_data + dp->d_size;
+                               (void) putc('"', fp);
+                               while (cp < end) {
+                                   if (n = *cp++) {
+                                       for (j = n ; j > 0 && cp < end ; j--)
+                                           if (*cp == '\n') {
+                                               (void) putc('\\', fp);
+                                               (void) putc(*cp++, fp);
+                                           } else
+                                               (void) putc(*cp++, fp);
+                                   }
+                               }
+                               (void) fputs("\"\n", fp);
+                               break;
+
+                       case T_UINFO:
+                               fprintf(fp, "\"%s\"\n", cp);
+                               break;
+
+                       case T_UID:
+                       case T_GID:
+                               if (dp->d_size == sizeof(u_long)) {
+                                       GETLONG(n, cp);
+                                       fprintf(fp, "%lu\n", n);
+                               }
+                               break;
+
+                       case T_WKS:
+                               GETLONG(addr, cp);      
+                               addr = htonl(addr);     
+                               fprintf(fp,"%s ",
+                                   inet_ntoa(*(struct in_addr *)&addr));
+                               proto = protocolname(*cp);
+                               cp += sizeof(char); 
+                               fprintf(fp, "%s ", proto);
+                               i = 0;
+                               while(cp < (u_char *)dp->d_data + dp->d_size) {
+                                       j = *cp++;
+                                       do {
+                                           if (j & 0200)
+                                               fprintf(fp," %s",
+                                                  servicename(i, proto));
+                                           j <<= 1;
+                                       } while(++i & 07);
+                               } 
+                               fprintf(fp,"\n");
+                               break;
+
+                       case T_MINFO:
+                               fprintf(fp, "%s.", cp);
+                               cp += strlen((char *)cp) + 1;
+                               fprintf(fp, " %s.\n", cp);
+                               break;
+#ifdef ALLOW_T_UNSPEC
+                       case T_UNSPEC:
+                               /* Dump binary data out in an ASCII-encoded
+                                  format */
+                               {
+                                       /* Allocate more than enough space:
+                                        *  actually need 5/4 size + 20 or so
+                                        */
+                                       int TmpSize = 2 * dp->d_size + 30;
+                                       char *TmpBuf = (char *) malloc(TmpSize);
+                                       if (TmpBuf == NULL) {
+#ifdef DEBUG
+                                           if (debug)
+                                               fprintf(ddt, "Dump T_UNSPEC: malloc returned NULL\n");
+#endif DEBUG
+                                               syslog(LOG_ERR, "Dump T_UNSPEC: malloc: %m");
+                                       }
+                                       if (btoa(cp, dp->d_size, TmpBuf,
+                                                TmpSize) == CONV_OVERFLOW) {
+#ifdef DEBUG
+                                               if (debug)
+                                                   fprintf(ddt, "Dump T_UNSPEC: Output buffer overflow\n");
+#endif DEBUG
+                                                   syslog(LOG_ERR, "Dump T_UNSPEC: Output buffer overflow\n");
+                                       } else
+                                               fprintf(fp, "%s\n", TmpBuf);
+                               }
+                               break;
+#endif ALLOW_T_UNSPEC
+                       default:
+                               fprintf(fp, "???\n");
+                       }
+               }
+           }
+       }
+        if (ferror(fp))
+            return(NODBFILE);
+
+       npp = htp->h_tab;
+       nppend = npp + htp->h_size;
+       while (npp < nppend) {
+           for (np = *npp++; np != NULL; np = np->n_next) {
+               if (np->n_hash == NULL)
+                       continue;
+               getname(np, dname, sizeof(dname));
+               if (db_dump(np->n_hash, fp, zone, dname) == NODBFILE)
+                   return(NODBFILE);
+           }
+       }
+       return(OK);
+}
+
+#ifdef ALLOW_T_UNSPEC
+/*
+ * Subroutines to convert between 8 bit binary bytes and printable ASCII.
+ * Computes the number of bytes, and three kinds of simple checksums.
+ * Incoming bytes are collected into 32-bit words, then printed in base 85:
+ *     exp(85,5) > exp(2,32)
+ * The ASCII characters used are between '!' and 'u';
+ * 'z' encodes 32-bit zero; 'x' is used to mark the end of encoded data.
+ *
+ * Originally by Paul Rutter (philabs!per) and Joe Orost (petsd!joe) for
+ * the atob/btoa programs, released with the compress program, in mod.sources.
+ * Modified by Mike Schwartz 8/19/86 for use in BIND.
+ */
+
+/* Make sure global variable names are unique */
+#define Ceor T_UNSPEC_Ceor
+#define Csum T_UNSPEC_Csum
+#define Crot T_UNSPEC_Crot
+#define word T_UNSPEC_word
+#define bcount T_UNSPEC_bcount
+
+static long int Ceor, Csum, Crot, word, bcount;
+
+#define EN(c)  ((int) ((c) + '!'))
+#define DE(c) ((c) - '!')
+#define AddToBuf(bufp, c) **bufp = c; (*bufp)++;
+#define streq(s0, s1)  strcmp(s0, s1) == 0
+#define times85(x)     ((((((x<<2)+x)<<2)+x)<<2)+x)
+
+
+/* Decode ASCII-encoded byte c into binary representation and 
+ * place into *bufp, advancing bufp 
+ */
+static int
+byte_atob(c, bufp)
+       register c;
+       char **bufp;
+{
+       if (c == 'z') {
+               if (bcount != 0)
+                       return(CONV_BADFMT);
+               else {
+                       putbyte(0, bufp);
+                       putbyte(0, bufp);
+                       putbyte(0, bufp);
+                       putbyte(0, bufp);
+               }
+       } else if ((c >= '!') && (c < ('!' + 85))) {
+               if (bcount == 0) {
+                       word = DE(c);
+                       ++bcount;
+               } else if (bcount < 4) {
+                       word = times85(word);
+                       word += DE(c);
+                       ++bcount;
+               } else {
+                       word = times85(word) + DE(c);
+                       putbyte((int)((word >> 24) & 255), bufp);
+                       putbyte((int)((word >> 16) & 255), bufp);
+                       putbyte((int)((word >> 8) & 255), bufp);
+                       putbyte((int)(word & 255), bufp);
+                       word = 0;
+                       bcount = 0;
+               }
+       } else
+               return(CONV_BADFMT);
+       return(CONV_SUCCESS);
+}
+
+/* Compute checksum info and place c into *bufp, advancing bufp */
+static
+putbyte(c, bufp)
+       register c;
+       char **bufp;
+{
+       Ceor ^= c;
+       Csum += c;
+       Csum += 1;
+       if ((Crot & 0x80000000)) {
+               Crot <<= 1;
+               Crot += 1;
+       } else {
+               Crot <<= 1;
+       }
+       Crot += c;
+       AddToBuf(bufp, c);
+}
+
+/* Read the ASCII-encoded data from inbuf, of length inbuflen, and convert
+   it into T_UNSPEC (binary data) in outbuf, not to exceed outbuflen bytes;
+   outbuflen must be divisible by 4.  (Note: this is because outbuf is filled
+   in 4 bytes at a time.  If the actual data doesn't end on an even 4-byte
+   boundary, there will be no problem...it will be padded with 0 bytes, and
+   numbytes will indicate the correct number of bytes.  The main point is
+   that since the buffer is filled in 4 bytes at a time, even if there is
+   not a full 4 bytes of data at the end, there has to be room to 0-pad the
+   data, so the buffer must be of size divisible by 4).  Place the number of
+   output bytes in numbytes, and return a failure/success status  */
+int
+atob(inbuf, inbuflen, outbuf, outbuflen, numbytes)
+       char *inbuf;
+       int inbuflen;
+       char *outbuf;
+       int outbuflen;
+       int *numbytes;
+{
+       int inc, nb;
+       long int oeor, osum, orot;
+       char *inp, *outp = outbuf, *endoutp = &outbuf[outbuflen];
+
+       if ( (outbuflen % 4) != 0)
+               return(CONV_BADBUFLEN);
+       Ceor = Csum = Crot = word = bcount = 0;
+       for (inp = inbuf, inc = 0; inc < inbuflen; inp++, inc++) {
+               if (outp > endoutp)
+                       return(CONV_OVERFLOW);
+               if (*inp == 'x') {
+                       inp +=2;
+                       break;
+               } else {
+                       if (byte_atob(*inp, &outp) == CONV_BADFMT)
+                               return(CONV_BADFMT);
+               }
+       }
+
+       /* Get byte count and checksum information from end of buffer */
+       if(sscanf(inp, "%ld %lx %lx %lx", numbytes, &oeor, &osum, &orot) != 4)
+               return(CONV_BADFMT);
+       if ((oeor != Ceor) || (osum != Csum) || (orot != Crot))
+               return(CONV_BADCKSUM);
+       return(CONV_SUCCESS);
+}
+
+/* Encode binary byte c into ASCII representation and place into *bufp,
+   advancing bufp */
+static
+byte_btoa(c, bufp)
+       register c;
+       char **bufp;
+{
+       Ceor ^= c;
+       Csum += c;
+       Csum += 1;
+       if ((Crot & 0x80000000)) {
+               Crot <<= 1;
+               Crot += 1;
+       } else {
+               Crot <<= 1;
+       }
+       Crot += c;
+
+       word <<= 8;
+       word |= c;
+       if (bcount == 3) {
+               if (word == 0) {
+                       AddToBuf(bufp, 'z');
+               } else {
+                   register int tmp = 0;
+                   register long int tmpword = word;
+                       
+                   if (tmpword < 0) {  
+                          /* Because some don't support unsigned long */
+                       tmp = 32;
+                       tmpword -= (long)(85 * 85 * 85 * 85 * 32);
+                   }
+                   if (tmpword < 0) {
+                       tmp = 64;
+                       tmpword -= (long)(85 * 85 * 85 * 85 * 32);
+                   }
+                   AddToBuf(bufp,
+                        EN((tmpword / (long)(85 * 85 * 85 * 85)) + tmp));
+                   tmpword %= (long)(85 * 85 * 85 * 85);
+                   AddToBuf(bufp, EN(tmpword / (85 * 85 * 85)));
+                   tmpword %= (85 * 85 * 85);
+                   AddToBuf(bufp, EN(tmpword / (85 * 85)));
+                   tmpword %= (85 * 85);
+                   AddToBuf(bufp, EN(tmpword / 85));
+                   tmpword %= 85;
+                   AddToBuf(bufp, EN(tmpword));
+               }
+               bcount = 0;
+       } else {
+               bcount += 1;
+       }
+}
+
+
+/*
+ * Encode the binary data from inbuf, of length inbuflen, into a
+ * null-terminated ASCII representation in outbuf, not to exceed outbuflen
+ * bytes. Return success/failure status
+ */
+int
+btoa(inbuf, inbuflen, outbuf, outbuflen)
+       char *inbuf;
+       int inbuflen;
+       char *outbuf;
+       int outbuflen;
+{
+       long int inc, nb;
+       long int oeor, osum, orot;
+       char *inp, *outp = outbuf, *endoutp = &outbuf[outbuflen -1];
+
+       Ceor = Csum = Crot = word = bcount = 0;
+       for (inp = inbuf, inc = 0; inc < inbuflen; inp++, inc++) {
+               byte_btoa((unsigned char) (*inp), &outp);
+               if (outp >= endoutp)
+                       return(CONV_OVERFLOW);
+       }
+       while (bcount != 0) {
+               byte_btoa(0, &outp);
+               if (outp >= endoutp)
+                       return(CONV_OVERFLOW);
+       }
+       /* Put byte count and checksum information at end of buffer, delimited
+          by 'x' */
+       (void) sprintf(outp, "x %ld %lx %lx %lx", inbuflen, Ceor, Csum, Crot);
+       if (&outp[strlen(outp) - 1] >= endoutp)
+               return(CONV_OVERFLOW);
+       else
+               return(CONV_SUCCESS);
+}
+#endif ALLOW_T_UNSPEC
diff --git a/usr/src/usr.sbin/named/db_glue.c b/usr/src/usr.sbin/named/db_glue.c
new file mode 100644 (file)
index 0000000..03b3135
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)db_glue.c  4.4 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include "ns.h"
+#include "db.h"
+
+struct valuelist {
+       struct valuelist *next, *prev;
+       char    *name;
+       char    *proto;
+       short   port;
+} *servicelist, *protolist;
+
+buildservicelist()
+{
+       struct servent *sp;
+       struct valuelist *slp;
+
+       setservent(1);
+       while (sp = getservent()) {
+               slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+               slp->name = savestr(sp->s_name);
+               slp->proto = savestr(sp->s_proto);
+               slp->port = ntohs((u_short)sp->s_port);
+               slp->next = servicelist;
+               slp->prev = NULL;
+               if (servicelist)
+                       servicelist->prev = slp;
+               servicelist = slp;
+       }
+       endservent();
+}
+
+buildprotolist()
+{
+       struct protoent *pp;
+       struct valuelist *slp;
+
+       setprotoent(1);
+       while (pp = getprotoent()) {
+               slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+               slp->name = savestr(pp->p_name);
+               slp->port = pp->p_proto;
+               slp->next = protolist;
+               slp->prev = NULL;
+               if (protolist)
+                       protolist->prev = slp;
+               protolist = slp;
+       }
+       endprotoent();
+}
+
+/*
+ * Convert service name or (ascii) number to int.
+ */
+servicenumber(p)
+       char *p;
+{
+
+       return (findservice(p, &servicelist));
+}
+
+/*
+ * Convert protocol name or (ascii) number to int.
+ */
+protocolnumber(p)
+       char *p;
+{
+
+       return (findservice(p, &protolist));
+}
+
+findservice(s, list)
+       register char *s;
+       register struct valuelist **list;
+{
+       register struct valuelist *lp = *list;
+       int n;
+
+       for (; lp != NULL; lp = lp->next)
+               if (strcasecmp(lp->name, s) == 0) {
+                       if (lp != *list) {
+                               lp->prev->next = lp->next;
+                               if (lp->next)
+                                       lp->next->prev = lp->prev;
+                               (*list)->prev = lp;
+                               lp->next = *list;
+                               *list = lp;
+                       }
+                       return(lp->port);
+               }
+       if (sscanf(s, "%d", &n) != 1 || n <= 0)
+               n = -1;
+       return(n);
+}
+
+struct servent *
+cgetservbyport(port, proto)
+       u_short port;
+       char *proto;
+{
+       register struct valuelist **list = &servicelist;
+       register struct valuelist *lp = *list;
+       static struct servent serv;
+
+       port = htons(port);
+       for (; lp != NULL; lp = lp->next) {
+               if (port != lp->port)
+                       continue;
+               if (strcasecmp(lp->proto, proto) == 0) {
+                       if (lp != *list) {
+                               lp->prev->next = lp->next;
+                               if (lp->next)
+                                       lp->next->prev = lp->prev;
+                               (*list)->prev = lp;
+                               lp->next = *list;
+                               *list = lp;
+                       }
+                       serv.s_name = lp->name;
+                       serv.s_port = htons((u_short)lp->port);
+                       serv.s_proto = lp->proto;
+                       return(&serv);
+               }
+       }
+       return(0);
+}
+
+struct protoent *
+cgetprotobynumber(proto)
+       register int proto;
+{
+
+       register struct valuelist **list = &protolist;
+       register struct valuelist *lp = *list;
+       static struct protoent prot;
+
+       for (; lp != NULL; lp = lp->next)
+               if (lp->port == proto) {
+                       if (lp != *list) {
+                               lp->prev->next = lp->next;
+                               if (lp->next)
+                                       lp->next->prev = lp->prev;
+                               (*list)->prev = lp;
+                               lp->next = *list;
+                               *list = lp;
+                       }
+                       prot.p_name = lp->name;
+                       prot.p_proto = lp->port;
+                       return(&prot);
+               }
+       return(0);
+}
+
+char *
+protocolname(num)
+       int num;
+{
+       static  char number[8];
+       struct protoent *pp;
+
+       pp = cgetprotobynumber(num);
+       if(pp == 0)  {
+               (void) sprintf(number, "%d", num);
+               return(number);
+       }
+       return(pp->p_name);
+}
+
+char *
+servicename(port, proto)
+       u_short port;
+       char *proto;
+{
+       static  char number[8];
+       struct servent *ss;
+
+       ss = cgetservbyport(htons(port), proto);
+       if(ss == 0)  {
+               (void) sprintf(number, "%d", port);
+               return(number);
+       }
+       return(ss->s_name);
+}
diff --git a/usr/src/usr.sbin/named/db_load.c b/usr/src/usr.sbin/named/db_load.c
new file mode 100644 (file)
index 0000000..10709ff
--- /dev/null
@@ -0,0 +1,968 @@
+/*
+ * Copyright (c) 1986, 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)db_load.c  4.38 (Berkeley) 3/2/91";
+#endif /* not lint */
+
+/*
+ * Load data base from ascii backupfile.  Format similar to RFC 883.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include "ns.h"
+#include "db.h"
+
+extern char *index();
+extern int max_cache_ttl;
+
+/*
+ * Map class and type names to number
+ */
+struct map {
+       char    token[8];
+       int     val;
+};
+
+struct map m_class[] = {
+       "in",           C_IN,
+#ifdef notdef
+       "any",          C_ANY,          /* any is a QCLASS, not CLASS */
+#endif
+       "chaos",        C_CHAOS,
+       "hs",           C_HS,
+};
+#define NCLASS (sizeof(m_class)/sizeof(struct map))
+
+struct map m_type[] = {
+       "a",            T_A,
+       "ns",           T_NS,
+       "cname",        T_CNAME,
+       "soa",          T_SOA,
+       "mb",           T_MB,
+       "mg",           T_MG,
+       "mr",           T_MR,
+       "null",         T_NULL,
+       "wks",          T_WKS,
+       "ptr",          T_PTR,
+       "hinfo",        T_HINFO,
+       "minfo",        T_MINFO,
+       "mx",           T_MX,
+       "uinfo",        T_UINFO,
+       "txt",          T_TXT,
+       "uid",          T_UID,
+       "gid",          T_GID,
+#ifdef notdef
+       "any",          T_ANY,          /* any is a QTYPE, not TYPE */
+#endif
+#ifdef ALLOW_T_UNSPEC
+        "unspec",       T_UNSPEC,
+#endif ALLOW_T_UNSPEC
+};
+#define NTYPE (sizeof(m_type)/sizeof(struct map))
+
+/*
+ * Parser token values
+ */
+#define CURRENT        1
+#define DOT    2
+#define AT     3
+#define DNAME  4
+#define INCLUDE        5
+#define ORIGIN 6
+#define ERROR  7
+
+int    lineno;         /* current line number */
+
+/*
+ * Load the database from 'filename'. Origin is appended to all domain
+ * names in the file.
+ */
+db_load(filename, in_origin, zp, doinginclude)
+       char *filename, *in_origin;
+       struct zoneinfo *zp;
+{
+       register u_char *cp;
+       register struct map *mp;
+       char domain[MAXDNAME];
+       char origin[MAXDNAME];
+       char tmporigin[MAXDNAME];
+       u_char buf[MAXDATA];
+       u_char data[MAXDATA];
+       u_char *cp1;
+       char *op;
+       int c;
+       int class, type, ttl, dbflags, dataflags;
+        int read_soa = 0;      /* number of soa's read */
+       struct databuf *dp;
+       FILE *fp;
+       int slineno, i, errs = 0, didinclude = 0;
+       register u_long n;
+       struct stat sb;
+
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"db_load(%s, %s, %d, %d)\n",
+                   filename, in_origin, zp - zones, doinginclude);
+#endif
+
+       (void) strcpy(origin, in_origin);
+       if ((fp = fopen(filename, "r")) == NULL) {
+               syslog(LOG_ERR, "%s: %m", filename);
+#ifdef DEBUG
+               if (debug)
+                   fprintf(ddt,"db_load: error opening file %s\n", filename);
+#endif
+               return (-1);
+       }
+       if (zp->z_type == Z_CACHE) {
+           dbflags = DB_NODATA | DB_NOHINTS;
+           dataflags = DB_F_HINT;
+       } else {
+           dbflags = DB_NODATA;
+           dataflags = 0;
+       }
+       gettime(&tt);
+       if (fstat(fileno(fp), &sb) < 0) {
+           syslog(LOG_ERR, "%s: %m", filename);
+           sb.st_mtime = (int)tt.tv_sec;
+       }
+       slineno = lineno;
+       lineno = 1;
+       domain[0] = '\0';
+       class = C_IN;
+       zp->z_state &= ~(Z_INCLUDE|Z_DB_BAD);
+       while ((c = gettoken(fp)) != EOF) {
+               switch (c) {
+               case INCLUDE:
+                       if (!getword(buf, sizeof(buf), fp)) /* file name */
+                               break;
+                       if (!getword(tmporigin, sizeof(tmporigin), fp))
+                               strcpy(tmporigin, origin);
+                       else {
+                               makename(tmporigin, origin);
+                               endline(fp);
+                       }
+                       didinclude = 1;
+                       errs += db_load(buf, tmporigin, zp, 1);
+                       continue;
+
+               case ORIGIN:
+                       (void) strcpy((char *)buf, origin);
+                       if (!getword(origin, sizeof(origin), fp))
+                               break;
+#ifdef DEBUG
+                       if (debug > 3)
+                               fprintf(ddt,"db_load: origin %s, buf %s\n",
+                                   origin, buf);
+#endif
+                       makename(origin, buf);
+#ifdef DEBUG
+                       if (debug > 3)
+                               fprintf(ddt,"db_load: origin now %s\n", origin);
+#endif
+                       continue;
+
+               case DNAME:
+                       if (!getword(domain, sizeof(domain), fp))
+                               break;
+                       n = strlen(domain) - 1;
+                       if (domain[n] == '.')
+                               domain[n] = '\0';
+                       else if (*origin) {
+                               (void) strcat(domain, ".");
+                               (void) strcat(domain, origin);
+                       }
+                       goto gotdomain;
+
+               case AT:
+                       (void) strcpy(domain, origin);
+                       goto gotdomain;
+
+               case DOT:
+                       domain[0] = '\0';
+                       /* fall thru ... */
+               case CURRENT:
+               gotdomain:
+                       if (!getword(buf, sizeof(buf), fp)) {
+                               if (c == CURRENT)
+                                       continue;
+                               break;
+                       }
+                       cp = buf;
+                       ttl = 0;
+                       if (isdigit(*cp)) {
+                               n = 0;
+                               do
+                                       n = n * 10 + (*cp++ - '0');
+                               while (isdigit(*cp));
+                               if (zp->z_type == Z_CACHE) {
+                                   /* this allows the cache entry to age */
+                                   /* while sitting on disk (powered off) */
+                                   if (n > max_cache_ttl)
+                                       n = max_cache_ttl;
+                                   n += sb.st_mtime;
+                               }
+                               ttl = n;
+                               if (!getword(buf, sizeof(buf), fp))
+                                       break;
+                       }
+                       for (mp = m_class; mp < m_class+NCLASS; mp++)
+                               if (!strcasecmp((char *)buf, mp->token)) {
+                                       class = mp->val;
+                                       (void) getword(buf, sizeof(buf), fp);
+                                       break;
+                               }
+                       for (mp = m_type; mp < m_type+NTYPE; mp++)
+                               if (!strcasecmp((char *)buf, mp->token)) {
+                                       type = mp->val;
+                                       goto fndtype;
+                               }
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt,"Line %d: Unknown type: %s.\n",
+                                       lineno, buf);
+#endif
+                       errs++;
+                       syslog(LOG_ERR, "Line %d: Unknown type: %s.\n",
+                               lineno, buf);
+                       break;
+               fndtype:
+#ifdef ALLOW_T_UNSPEC
+                       /* Don't do anything here for T_UNSPEC...
+                        * read input separately later
+                        */
+                        if (type != T_UNSPEC) {
+#endif ALLOW_T_UNSPEC
+                           if (!getword(buf, sizeof(buf), fp))
+                               break;
+#ifdef DEBUG
+                           if (debug >= 3)
+                               fprintf(ddt,
+                                   "d='%s', c=%d, t=%d, ttl=%d, data='%s'\n",
+                                   domain, class, type, ttl, buf);
+#endif
+#ifdef ALLOW_T_UNSPEC
+                        }
+#endif ALLOW_T_UNSPEC
+                       /*
+                        * Convert the ascii data 'buf' to the proper format
+                        * based on the type and pack into 'data'.
+                        */
+                       switch (type) {
+                       case T_A:
+                               n = ntohl((u_long)inet_addr((char *)buf));
+                               cp = data;
+                               PUTLONG(n, cp);
+                               n = sizeof(u_long);
+                               break;
+
+                       case T_HINFO:
+                               n = strlen((char *)buf);
+                               if (n > 255) {
+                                   syslog(LOG_WARNING,
+                                       "%s: line %d: CPU type too long",
+                                       filename, lineno);
+                                   n = 255;
+                               }
+                               data[0] = n;
+                               bcopy(buf, (char *)data + 1, (int)n);
+                               n++;
+                               if (!getword(buf, sizeof(buf), fp))
+                                       break;
+                               i = strlen((char *)buf);
+                               if (i > 255) {
+                                   syslog(LOG_WARNING,
+                                       "%s: line %d: OS type too long",
+                                       filename, lineno);
+                                   i = 255;
+                               }
+                               data[n] = i;
+                               bcopy(buf, data + n + 1, i);
+                               n += i + 1;
+                               endline(fp);
+                               break;
+
+                       case T_SOA:
+                       case T_MINFO:
+                               (void) strcpy((char *)data, (char *)buf);
+                               makename(data, origin);
+                               cp = data + strlen((char *)data) + 1;
+                               if (!getword(cp,
+                                   sizeof(data) - (cp - data),fp)) {
+                                       n = cp - data;
+                                       break;
+                               }
+                               makename(cp, origin);
+                               cp += strlen((char *)cp) + 1;
+                               if (type == T_MINFO) {
+                                       n = cp - data;
+                                       break;
+                               }
+                               if (getnonblank(fp) != '(')
+                                       goto err;
+                               zp->z_serial = getnum(fp);
+                               n = (u_long) zp->z_serial;
+                               PUTLONG(n, cp);
+                               zp->z_refresh = getnum(fp);
+                               n = (u_long) zp->z_refresh;
+                               PUTLONG(n, cp);
+                               if (zp->z_type == Z_SECONDARY)
+                                       zp->z_time = sb.st_mtime + zp->z_refresh;
+                               zp->z_retry = getnum(fp);
+                               n = (u_long) zp->z_retry;
+                               PUTLONG(n, cp);
+                               zp->z_expire = getnum(fp);
+                               n = (u_long) zp->z_expire;
+                               PUTLONG (n, cp);
+                               zp->z_minimum = getnum(fp);
+                               n = (u_long) zp->z_minimum;
+                               PUTLONG (n, cp);
+                               n = cp - data;
+                               if (getnonblank(fp) != ')')
+                                       goto err;
+                                read_soa++;
+                               endline(fp);
+                               break;
+
+                       case T_UID:
+                       case T_GID:
+                               n = 0;
+                               cp = buf;
+                               while (isdigit(*cp))
+                                       n = n * 10 + (*cp++ - '0');
+                               if (cp == buf)
+                                       goto err;
+                               cp = data;
+                               PUTLONG(n, cp);
+                               n = sizeof(long);
+                               break;
+
+                       case T_WKS:
+                               /* Address */
+                               n = ntohl((u_long)inet_addr((char *)buf));
+                               cp = data;
+                               PUTLONG(n, cp);
+                               *cp = getprotocol(fp, filename);
+                               /* Protocol */
+                               n = sizeof(u_long) + sizeof(char);
+                               /* Services */
+                               n = getservices((int)n, data, fp, filename);
+                               break;
+
+                       case T_NS:
+                       case T_CNAME:
+                       case T_MB:
+                       case T_MG:
+                       case T_MR:
+                       case T_PTR:
+                               (void) strcpy((char *)data, (char *)buf);
+                               makename(data, origin);
+                               n = strlen((char *)data) + 1;
+                               break;
+
+                       case T_UINFO:
+                               cp = (u_char *)index((char *)buf, '&');
+                               bzero(data, sizeof(data));
+                               if ( cp != NULL) {
+                                       (void) strncpy((char *)data,
+                                           (char *)buf, cp - buf);
+                                       op = index(domain, '.');
+                                       if ( op != NULL)
+                                           (void) strncat((char *)data,
+                                               domain,op-domain);
+                                       else
+                                               (void) strcat((char *)data,
+                                                   domain);
+                                       (void) strcat((char *)data,
+                                           (char *)++cp);
+                               } else
+                                       (void) strcpy((char *)data,
+                                           (char *)buf);
+                               n = strlen((char *)data) + 1;
+                               break;
+                       case T_MX:
+                               n = 0;
+                               cp = buf;
+                               while (isdigit(*cp))
+                                       n = n * 10 + (*cp++ - '0');
+                               /* catch bad values */
+                               if ((cp == buf) || (n > 65535))
+                                       goto err;
+
+                               cp = data;
+                               PUTSHORT((u_short)n, cp);
+
+                               if (!getword(buf, sizeof(buf), fp))
+                                           break;
+                               (void) strcpy((char *)cp, (char *)buf);
+                               makename(cp, origin);
+                               /* get pointer to place in data */
+                               cp += strlen((char *)cp) +1;
+
+                               /* now save length */
+                               n = (cp - data);
+                               break;
+
+                       case T_TXT:
+                               i = strlen((char *)buf);
+                               cp = data;
+                               cp1 = buf;
+                               /*
+                                * there is expansion here so make sure we
+                                * don't overflow data
+                                */
+                               if (i > sizeof(data) * 255 / 256) {
+                                   syslog(LOG_WARNING,
+                                       "%s: line %d: TXT record truncated",
+                                       filename, lineno);
+                                   i = sizeof(data) * 255 / 256;
+                               }
+                               while (i > 255) {
+                                   *cp++ = 255;
+                                   bcopy(cp1, cp, 255);
+                                   cp += 255;
+                                   cp1 += 255;
+                                   i -= 255;
+                               }
+                               *cp++ = i;
+                               bcopy(cp1, cp, i);
+                               cp += i;
+                               n = cp - data;
+                               endline(fp);
+                               break;
+#ifdef ALLOW_T_UNSPEC
+                        case T_UNSPEC:
+                                {
+                                    int rcode;
+                                    fgets(buf, sizeof(buf), fp);
+#ifdef DEBUG
+                                   if (debug)
+                                       fprintf(ddt, "loading T_UNSPEC\n");
+#endif DEBUG
+                                    if (rcode = atob(buf,
+                                       strlen((char *)buf), data,
+                                       sizeof(data), &n)) {
+                                        if (rcode == CONV_OVERFLOW) {
+#ifdef DEBUG
+                                            if (debug)
+                                               fprintf(ddt,
+                                                  "Load T_UNSPEC: input buffer overflow\n");
+#endif DEBUG
+                                           errs++;
+                                            syslog(LOG_ERR,
+                                                "Load T_UNSPEC: input buffer overflow");
+                                         } else {
+#ifdef DEBUG
+                                            if (debug)
+                                                fprintf(ddt,
+                                                  "Load T_UNSPEC: Data in bad atob format\n");
+#endif DEBUG
+                                           errs++;
+                                            syslog(LOG_ERR,
+                                                  "Load T_UNSPEC: Data in bad atob format");
+                                         }
+                                    }
+                                }
+                                break;
+#endif ALLOW_T_UNSPEC
+
+                       default:
+                               goto err;
+                       }
+                       dp = savedata(class, type, (u_long)ttl, data, (int)n);
+                       dp->d_zone = zp - zones;
+                       dp->d_flags = dataflags;
+                       if ((c = db_update(domain, dp, dp, dbflags,
+                          (zp->z_type == Z_CACHE)? fcachetab : hashtab)) < 0) {
+#ifdef DEBUG
+                               if (debug && (c != DATAEXISTS))
+                                       fprintf(ddt,"update failed\n");
+#endif
+                       }
+                       continue;
+
+               case ERROR:
+                       break;
+               }
+       err:
+               errs++;
+               syslog(LOG_ERR, "%s: line %d: database format error (%s)",
+                       filename, lineno, buf);
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt,"%s: line %d: database format error ('%s', %d)\n",
+                               filename, lineno, buf, n);
+#endif
+               while ((c = getc(fp)) != EOF && c != '\n')
+                       ;
+               if (c == '\n')
+                       lineno++;
+       }
+       (void) fclose(fp);
+       lineno = slineno;
+       if (doinginclude == 0) {
+               if (didinclude) {
+                       zp->z_state |= Z_INCLUDE;
+                       zp->z_ftime = 0;
+               } else
+                       zp->z_ftime = sb.st_mtime;
+               zp->z_lastupdate = sb.st_mtime;
+               if (zp->z_type != Z_CACHE && read_soa != 1) {
+                       errs++;
+                       if (read_soa == 0)
+                               syslog(LOG_ERR, "%s: no SOA record", filename);
+                       else
+                               syslog(LOG_ERR, "%s: multiple SOA records",
+                                   filename);
+               }
+       }
+       if (errs)
+               zp->z_state |= Z_DB_BAD;
+       return (errs);
+}
+
+int gettoken(fp)
+       register FILE *fp;
+{
+       register int c;
+       char op[32];
+
+       for (;;) {
+               c = getc(fp);
+       top:
+               switch (c) {
+               case EOF:
+                       return (EOF);
+
+               case '$':
+                       if (getword(op, sizeof(op), fp)) {
+                               if (!strcasecmp("include", op))
+                                       return (INCLUDE);
+                               if (!strcasecmp("origin", op))
+                                       return (ORIGIN);
+                       }
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt,"Line %d: Unknown $ option: $%s\n", 
+                                   lineno, op);
+#endif
+                       syslog(LOG_ERR,"Line %d: Unknown $ option: $%s\n", 
+                           lineno, op);
+                       return (ERROR);
+
+               case ';':
+                       while ((c = getc(fp)) != EOF && c != '\n')
+                               ;
+                       goto top;
+
+               case ' ':
+               case '\t':
+                       return (CURRENT);
+
+               case '.':
+                       return (DOT);
+
+               case '@':
+                       return (AT);
+
+               case '\n':
+                       lineno++;
+                       continue;
+
+               default:
+                       (void) ungetc(c, fp);
+                       return (DNAME);
+               }
+       }
+}
+
+/*
+ * Get next word, skipping blanks & comments.
+ */
+getword(buf, size, fp)
+       char *buf;
+       int size;
+       FILE *fp;
+{
+       register char *cp;
+       register int c;
+
+       for (cp = buf; (c = getc(fp)) != EOF; ) {
+               if (c == ';') {
+                       while ((c = getc(fp)) != EOF && c != '\n')
+                               ;
+                       c = '\n';
+               }
+               if (c == '\n') {
+                       if (cp != buf)
+                               ungetc(c, fp);
+                       else
+                               lineno++;
+                       break;
+               }
+               if (isspace(c)) {
+                       while (isspace(c = getc(fp)) && c != '\n')
+                               ;
+                       ungetc(c, fp);
+                       if (cp != buf)          /* Trailing whitespace */
+                               break;
+                       continue;               /* Leading whitespace */
+               }
+               if (c == '"') {
+                       while ((c = getc(fp)) != EOF && c != '"' && c != '\n') {
+                               if (c == '\\') {
+                                       if ((c = getc(fp)) == EOF)
+                                               c = '\\';
+                                       if (c == '\n')
+                                               lineno++;
+                               }
+                               if (cp >= buf+size-1)
+                                       break;
+                               *cp++ = c;
+                       }
+                       if (c == '\n') {
+                               lineno++;
+                               break;
+                       }
+                       continue;
+               }
+               if (c == '\\') {
+                       if ((c = getc(fp)) == EOF)
+                               c = '\\';
+                       if (c == '\n')
+                               lineno++;
+               }
+               if (cp >= buf+size-1)
+                       break;
+               *cp++ = c;
+       }
+       *cp = '\0';
+       return (cp != buf);
+}
+
+getnum(fp)
+       FILE *fp;
+{
+       register int c, n;
+       int seendigit = 0;
+       int seendecimal = 0;
+
+       for (n = 0; (c = getc(fp)) != EOF; ) {
+               if (isspace(c)) {
+                       if (c == '\n')
+                               lineno++;
+                       if (seendigit)
+                               break;
+                       continue;
+               }
+               if (c == ';') {
+                       while ((c = getc(fp)) != EOF && c != '\n')
+                               ;
+                       if (c == '\n')
+                               lineno++;
+                       if (seendigit)
+                               break;
+                       continue;
+               }
+               if (!isdigit(c)) {
+                       if (c == ')' && seendigit) {
+                               (void) ungetc(c, fp);
+                               break;
+                       }
+                       if (seendecimal || c != '.') {
+                               syslog(LOG_ERR, "line %d: expected a number",
+                               lineno);
+#ifdef DEBUG
+                               if (debug)
+                                   fprintf(ddt,"line %d: expected a number",
+                                       lineno);
+#endif
+                               exit(1);        /* XXX why exit */
+                       } else {
+                               if (!seendigit)
+                                       n = 1;
+                               n = n * 1000 ;
+                               seendigit = 1;
+                               seendecimal = 1;
+                       }
+                       continue;
+               }
+               n = n * 10 + (c - '0');
+               seendigit = 1;
+       }
+       return (n);
+}
+
+getnonblank(fp)
+       FILE *fp;
+{
+       register int c;
+
+       while ( (c = getc(fp)) != EOF ) {
+               if (isspace(c)) {
+                       if (c == '\n')
+                               lineno++;
+                       continue;
+               }
+               if (c == ';') {
+                       while ((c = getc(fp)) != EOF && c != '\n')
+                               ;
+                       if (c == '\n')
+                               lineno++;
+                       continue;
+               }
+               return(c);
+       }
+       syslog(LOG_ERR, "line %d: unexpected EOF", lineno);
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt, "line %d: unexpected EOF", lineno);
+#endif
+       return (EOF);
+}
+
+/*
+ * Take name and fix it according to following rules:
+ * "." means root.
+ * "@" means current origin.
+ * "name." means no changes.
+ * "name" means append origin.
+ */
+makename(name, origin)
+       char *name, *origin;
+{
+       int n;
+
+       if (origin[0] == '.')
+               origin++;
+       n = strlen(name);
+       if (n == 1) {
+               if (name[0] == '.') {
+                       name[0] = '\0';
+                       return;
+               }
+               if (name[0] == '@') {
+                       (void) strcpy(name, origin);
+                       return;
+               }
+       }
+       if (n > 0) {
+               if (name[n - 1] == '.')
+                       name[n - 1] = '\0';
+               else if (origin[0] != '\0') {
+                       name[n] = '.';
+                       (void) strcpy(name + n + 1, origin);
+               }
+       }
+}
+
+endline(fp)
+       register FILE *fp;
+{
+     register int c;
+     while (c = getc(fp))
+       if (c == '\n') {
+           (void) ungetc(c,fp);
+           break;
+       } else if (c == EOF)
+           break;
+}
+
+#define MAXPORT 256
+#define MAXLEN 24
+
+getprotocol(fp, src)
+       FILE *fp;
+       char *src;
+{
+       int  k;
+       char b[MAXLEN];
+
+       (void) getword(b, sizeof(b), fp);
+               
+       k = protocolnumber(b);
+       if(k == -1)
+               syslog(LOG_ERR, "%s: line %d: unknown protocol: %s.",
+                       src, lineno, b);
+       return(k);
+}
+
+int
+getservices(n, data, fp, src)
+       int n;
+       char *data, *src;
+       FILE *fp;
+{
+       int j, ch;
+       int k;
+       int maxl;
+       int bracket;
+       char b[MAXLEN];
+       char bm[MAXPORT/8];
+
+       for (j = 0; j < MAXPORT/8; j++)
+               bm[j] = 0;
+       maxl = 0;
+       bracket = 0;
+       while (getword(b, sizeof(b), fp) || bracket) {
+               if (feof(fp) || ferror(fp))
+                       break;
+               if (strlen(b) == 0)
+                       continue;
+               if ( b[0] == '(') {
+                       bracket++;
+                       continue;
+               }
+               if ( b[0] == ')') {
+                       bracket = 0;
+                       while ((ch = getc(fp)) != EOF && ch != '\n')
+                               ;
+                       if (ch == '\n')
+                               lineno++;
+                       break;
+               }
+               k = servicenumber(b);
+               if (k == -1) {
+                       syslog(LOG_WARNING, "%s: line %d: Unknown service '%s'",
+                           src, lineno, b);
+                       continue;
+               }
+               if ((k < MAXPORT) && (k)) {
+                       bm[k/8] |= (0x80>>(k%8));
+                       if (k > maxl)
+                               maxl=k;
+               }
+               else {
+                       syslog(LOG_WARNING,
+                           "%s: line %d: port no. (%d) too big\n",
+                               src, lineno, k);
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt,
+                                   "%s: line %d: port no. (%d) too big\n",
+                                       src, lineno, k);
+#endif
+               }
+       }
+       if (bracket)
+               syslog(LOG_WARNING, "%s: line %d: missing close paren\n",
+                   src, lineno);
+       maxl = maxl/8+1;
+       bcopy(bm, data+n, maxl);
+       return(maxl+n);
+}
+
+get_sort_list(fp)
+       FILE *fp;
+{
+       extern struct netinfo **enettab;
+       register struct netinfo *ntp, **end = enettab;
+       extern struct netinfo *findnetinfo();
+       struct in_addr addr;
+       char buf[BUFSIZ];
+
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"sortlist ");
+#endif
+       while (getword(buf, sizeof(buf), fp)) {
+               if (strlen(buf) == 0)
+                       break;
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt," %s",buf);
+#endif
+               addr.s_addr = inet_addr(buf);
+               if (addr.s_addr == (unsigned)-1) {
+                       /* resolve name to address - XXX */
+                       continue;       
+               }
+               /* Check for duplicates, then add to linked list */
+               if (findnetinfo(addr))
+                       continue;
+               ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
+               ntp->my_addr = addr;
+               ntp->next = NULL;
+               ntp->mask = net_mask(ntp->my_addr);
+               ntp->net = ntp->my_addr.s_addr & ntp->mask;
+               if (ntp->net != addr.s_addr) {
+                       struct in_addr tmpaddr;
+
+                       tmpaddr.s_addr = ntp->net;
+                       syslog(LOG_WARNING, "sortlist: addr %s != %s", buf,
+                               inet_ntoa(tmpaddr));
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt, "\nsortlist: addr %s != %s\n", buf,
+                                       inet_ntoa(tmpaddr));
+#endif
+               }
+
+               *end = ntp;
+               end = &ntp->next;
+       }
+       
+#ifdef DEBUG
+       if (debug) 
+               fprintf(ddt,"\n");
+       if (debug > 2)
+               printnetinfo(*enettab);
+       if (debug > 4) {
+               extern struct netinfo *nettab;
+
+               fprintf(ddt, "\nFull sort list:\n");
+               printnetinfo(nettab);
+       }
+#endif
+}
+
+free_sort_list()
+{
+       extern struct netinfo **enettab;
+       register struct netinfo *ntp, *next;
+
+       for (ntp = *enettab; ntp != NULL; ntp = next) {
+               next = ntp->next;
+               free((char *)ntp);
+       }
+       *enettab = NULL;
+}
diff --git a/usr/src/usr.sbin/named/db_lookup.c b/usr/src/usr.sbin/named/db_lookup.c
new file mode 100644 (file)
index 0000000..5d17396
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)db_lookup.c        4.18 (Berkeley) 3/21/91";
+#endif /* not lint */
+
+/*
+ * Table lookup routines.
+ */
+
+#include <sys/param.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include "db.h"
+
+struct hashbuf *hashtab;       /* root hash table */
+struct hashbuf *fcachetab;     /* hash table of cache read from file */
+
+#ifdef DEBUG
+extern int debug;
+extern FILE *ddt;
+#endif
+
+/* 
+ * Lookup 'name' and return a pointer to the namebuf;
+ * NULL otherwise. If 'insert', insert name into tables.
+ * Wildcard lookups are handled.
+ */
+struct namebuf *
+nlookup(name, htpp, fname, insert)
+       char *name;
+       struct hashbuf **htpp;
+       char **fname;
+       int insert;
+{
+       register struct namebuf *np;
+       register char *cp;
+       register int c;
+       register unsigned hval;
+       register struct hashbuf *htp;
+       struct namebuf *parent = NULL;
+
+       htp = *htpp;
+       hval = 0;
+       *fname = "???";
+       for (cp = name; c = *cp++; ) {
+               if (c == '.') {
+                       parent = np = nlookup(cp, htpp, fname, insert);
+                       if (np == NULL)
+                               return (NULL);
+                       if (*fname != cp)
+                               return (np);
+                       if ((htp = np->n_hash) == NULL) {
+                               if (!insert) {
+                                       if (np->n_dname[0] == '*' && 
+                                           np->n_dname[1] == '\0')
+                                               *fname = name;
+                                       return (np);
+                               }
+                               htp = savehash((struct hashbuf *)NULL);
+                               np->n_hash = htp;
+                       }
+                       *htpp = htp;
+                       break;
+               }
+               hval <<= HASHSHIFT;
+               hval += c & HASHMASK;
+       }
+       c = *--cp;
+       *cp = '\0';
+       /*
+        * Lookup this label in current hash table.
+        */
+       for (np = htp->h_tab[hval % htp->h_size]; np != NULL; np = np->n_next) {
+               if (np->n_hashval == hval &&
+                   strcasecmp(name, np->n_dname) == 0) {
+                       *cp = c;
+                       *fname = name;
+                       return (np);
+               }
+       }
+       if (!insert) {
+               /*
+                * Look for wildcard in this hash table.
+                * Don't use a cached "*" name as a wildcard,
+                * only authoritative.
+                */
+               hval = ('*' & HASHMASK)  % htp->h_size;
+               for (np = htp->h_tab[hval]; np != NULL; np = np->n_next) {
+                       if (np->n_dname[0] == '*'  && np->n_dname[1] == '\0' &&
+                           np->n_data && np->n_data->d_zone != 0) {
+                               *cp = c;
+                               *fname = name;
+                               return (np);
+                       }
+               }
+               *cp = c;
+               return (parent);
+       }
+       np = savename(name);
+       np->n_parent = parent;
+       np->n_hashval = hval;
+       hval %= htp->h_size;
+       np->n_next = htp->h_tab[hval];
+       htp->h_tab[hval] = np;
+       /* increase hash table size */
+       if (++htp->h_cnt > htp->h_size * 2) {
+               *htpp = savehash(htp);
+               if (parent == NULL) {
+                       if (htp == hashtab)
+                           hashtab = *htpp;
+                       else
+                           fcachetab = *htpp;
+               }
+               else
+                       parent->n_hash = *htpp;
+               htp = *htpp;
+       }
+       *cp = c;
+       *fname = name;
+       return (np);
+}
+
+/*
+ * Does the data record match the class and type?
+ */
+match(dp, class, type)
+       register struct databuf *dp;
+       register int class, type;
+{
+#ifdef DEBUG
+       if (debug >= 5)
+               fprintf(ddt,"match(0x%x, %d, %d) %d, %d\n", dp, class, type,
+                       dp->d_class, dp->d_type);
+#endif
+       if (dp->d_class != class && class != C_ANY)
+               return (0);
+       if (dp->d_type != type && type != T_ANY)
+               return (0);
+       return (1);
+}
diff --git a/usr/src/usr.sbin/named/db_reload.c b/usr/src/usr.sbin/named/db_reload.c
new file mode 100644 (file)
index 0000000..7a69d78
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)db_reload.c        4.22 (Berkeley) 3/21/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <syslog.h>
+#include "ns.h"
+#include "db.h"
+
+extern time_t  resettime;
+
+/*
+ * Flush and reload data base.
+ */
+
+db_reload()
+{
+       extern char *bootfile;
+
+#ifdef DEBUG
+       if (debug >= 3)
+               fprintf(ddt,"reload()\n");
+#endif
+       syslog(LOG_NOTICE, "reloading nameserver\n");
+
+       qflush();
+       sqflush();
+       fwdtab_free();
+       free_sort_list();
+       getnetconf();
+       ns_init(bootfile);
+       time(&resettime);
+}
+
+db_free(htp)
+       struct hashbuf *htp;
+{
+       register struct databuf *dp, *nextdp;
+       register struct namebuf *np, *nextnp;
+       struct namebuf **npp, **nppend;
+
+       npp = htp->h_tab;
+       nppend = npp + htp->h_size;
+       while (npp < nppend) {
+           for (np = *npp++; np != NULL; np = nextnp) {
+               if (np->n_hash != NULL)
+                       db_free(np->n_hash);
+               (void) free((char *)np->n_dname);
+               for (dp = np->n_data; dp != NULL; ) {
+                       nextdp = dp->d_next;
+                       (void) free((char *)dp);
+                       dp = nextdp;
+               }
+               nextnp = np->n_next;
+               free((char *)np);
+           }
+       }
+       (void) free((char *)htp);
+}
+
+db_inv_free()
+{
+       register struct invbuf *ip;
+       register int i, j;
+
+       for (i = 0; i < INVHASHSZ; i++)
+               for (ip = invtab[i]; ip != NULL; ip = ip->i_next)
+                       for (j = 0; j < INVBLKSZ; j++)
+                               ip->i_dname[j] = NULL;
+}
+
+fwdtab_free()
+{
+       extern  struct fwdinfo *fwdtab;
+       struct fwdinfo *fp, *nextfp;
+
+       for (fp = fwdtab; fp != NULL; fp = nextfp) {
+               nextfp = fp->next;
+               free((char *)fp);
+       }
+       fwdtab = NULL;
+}
diff --git a/usr/src/usr.sbin/named/db_save.c b/usr/src/usr.sbin/named/db_save.c
new file mode 100644 (file)
index 0000000..eff0057
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)db_save.c  4.16 (Berkeley) 3/21/91";
+#endif /* not lint */
+
+/*
+ * Buffer allocation and deallocation routines.
+ */
+
+#include <sys/param.h>
+#include <arpa/nameser.h>
+#include <syslog.h>
+#include <stdio.h>
+#include "db.h"
+
+#ifdef DEBUG
+extern int debug;
+extern FILE *ddt;
+#endif
+
+extern char *strcpy();
+
+/*
+ * Allocate a name buffer & save name.
+ */
+struct namebuf *
+savename(name)
+       char *name;
+{
+       register struct namebuf *np;
+
+       np = (struct namebuf *) malloc(sizeof(struct namebuf));
+       if (np == NULL) {
+               syslog(LOG_ERR, "savename: %m");
+               exit(1);
+       }
+       np->n_dname = savestr(name);
+       np->n_next = NULL;
+       np->n_data = NULL;
+       np->n_hash = NULL;
+       return (np);
+}
+
+/*
+ * Allocate a data buffer & save data.
+ */
+struct databuf *
+savedata(class, type, ttl, data, size)
+       int class, type;
+       u_long ttl;
+       char *data;
+       int size;
+{
+       register struct databuf *dp;
+
+       if (type == T_NS)
+               dp = (struct databuf *) 
+                   malloc((unsigned)DATASIZE(size)+sizeof(u_long));
+       else
+               dp = (struct databuf *) malloc((unsigned)DATASIZE(size));
+       if (dp == NULL) {
+               syslog(LOG_ERR, "savedata: %m");
+               exit(1);
+       }
+       dp->d_next = NULL;
+       dp->d_type = type;
+       dp->d_class = class;
+       dp->d_ttl = ttl;
+       dp->d_size = size;
+       dp->d_mark = 0;
+       dp->d_flags = 0;
+       dp->d_nstime = 0;
+       bcopy(data, dp->d_data, dp->d_size);
+       return (dp);
+}
+
+int hashsizes[] = {    /* hashtable sizes */
+       2,
+       11,
+       113,
+       337,
+       977,
+       2053,
+       4073,
+       8011,
+       16001,
+       0
+};
+
+/*
+ * Allocate a data buffer & save data.
+ */
+struct hashbuf *
+savehash(oldhtp)
+       register struct hashbuf *oldhtp;
+{
+       register struct hashbuf *htp;
+       register struct namebuf *np, *nnp, **hp;
+       register int n;
+       int newsize;
+
+       if (oldhtp == NULL)
+               newsize = hashsizes[0];
+       else {
+               for (n = 0; newsize = hashsizes[n++]; )
+                       if (oldhtp->h_size == newsize) {
+                               newsize = hashsizes[n];
+                               break;
+                       }
+               if (newsize == 0)
+                       newsize = oldhtp->h_size * 2 + 1;
+       }
+#ifdef DEBUG
+       if(debug > 3)
+               fprintf(ddt, "savehash GROWING to %d\n", newsize);
+#endif
+       htp = (struct hashbuf *) malloc((unsigned)HASHSIZE(newsize));
+       if (htp == NULL) {
+               syslog(LOG_ERR, "savehash: %m");
+               exit(1);
+       }
+       htp->h_size = newsize;
+       bzero((char *) htp->h_tab, newsize * sizeof(struct hashbuf *));
+       if (oldhtp == NULL) {
+               htp->h_cnt = 0;
+               return (htp);
+       }
+#ifdef DEBUG
+       if (debug > 3)
+               fprintf(ddt,"savehash(%#x) cnt=%d, sz=%d, newsz=%d\n",
+                       oldhtp, oldhtp->h_cnt, oldhtp->h_size, newsize);
+#endif
+       htp->h_cnt = oldhtp->h_cnt;
+       for (n = 0; n < oldhtp->h_size; n++) {
+               for (np = oldhtp->h_tab[n]; np != NULL; np = nnp) {
+                       nnp = np->n_next;
+                       hp = &htp->h_tab[np->n_hashval % htp->h_size];
+                       np->n_next = *hp;
+                       *hp = np;
+               }
+       }
+       free((char *) oldhtp);
+       return (htp);
+}
+
+/*
+ * Allocate an inverse query buffer.
+ */
+struct invbuf *
+saveinv()
+{
+       register struct invbuf *ip;
+
+       ip = (struct invbuf *) malloc(sizeof(struct invbuf));
+       if (ip == NULL) {
+               syslog(LOG_ERR, "saveinv: %m");
+               exit(1);
+       }
+       ip->i_next = NULL;
+       bzero((char *)ip->i_dname, sizeof(ip->i_dname));
+       return (ip);
+}
+
+/*
+ * Make a copy of a string and return a pointer to it.
+ */
+char *
+savestr(str)
+       char *str;
+{
+       char *cp;
+
+       cp = malloc((unsigned)strlen(str) + 1);
+       if (cp == NULL) {
+               syslog(LOG_ERR, "savestr: %m");
+               exit(1);
+       }
+       (void) strcpy(cp, str);
+       return (cp);
+}
diff --git a/usr/src/usr.sbin/named/db_update.c b/usr/src/usr.sbin/named/db_update.c
new file mode 100644 (file)
index 0000000..cc450b4
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 1986, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)db_update.c        4.28 (Berkeley) 3/21/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <syslog.h>
+#include "ns.h"
+#include "db.h"
+
+extern struct timeval  tt;
+extern FILE *ddt;
+extern struct sockaddr_in from_addr;   /* Source addr of last packet */
+extern int needs_prime_cache;
+
+int    max_cache_ttl = (7*24*60*60);   /* ONE_WEEK maximum ttl */
+int    min_cache_ttl = (5*60);         /* 5 minute minimum ttl */
+
+/*
+ * Update data base. Flags control the action.
+ * Inverse query tables modified.
+ */
+db_update(name, odp, newdp, flags, htp)
+       char name[];
+       struct databuf *odp, *newdp;
+       int flags;
+       struct hashbuf *htp;
+{
+       register struct namebuf *np;
+       register struct databuf *dp, *pdp;
+       char *fname;
+        int foundRR = 0;
+
+#ifdef DEBUG
+       if (debug >= 3)
+               fprintf(ddt,"db_update(%s, 0x%x, 0x%x, 0%o, 0x%x)%s\n",
+                   name, odp, newdp, flags, htp,
+                   (odp && (odp->d_flags&DB_F_HINT)) ? " hint":"" );
+#endif
+       np = nlookup(name, &htp, &fname, newdp != NULL);
+       if (np == NULL || fname != name)
+               return (NONAME);
+
+        /* Reflect certain updates in hint cache also... */
+       /* Don't stick data we are authoritative for in hints. */
+        if (!(flags & DB_NOHINTS) && (odp != NULL) &&
+           (odp->d_zone <= 0) && !(odp->d_flags & DB_F_HINT) &&
+            ((name[0] == '\0' && odp->d_type == T_NS) ||
+            (odp->d_type == T_A)))
+        {
+               register struct databuf *dp;
+#ifdef DEBUG
+               if (debug >= 3)
+                       fprintf(ddt,"db_update: hint '%s' %d\n",
+                               name, odp->d_ttl);
+#endif
+               dp = savedata(odp->d_class, odp->d_type, odp->d_ttl,
+                       odp->d_data, odp->d_size);
+               dp->d_zone = DB_Z_CACHE;
+               dp->d_flags = DB_F_HINT;
+               if (db_update(name, dp,dp, (flags|DB_NOHINTS), fcachetab) != OK) {
+#ifdef DEBUG           
+                       if (debug > 2)
+                               fprintf(ddt, "db_update: hint %x freed\n", dp);
+#endif
+                       (void) free((char *)dp);
+               }
+        }
+
+       if (odp != NULL) {
+               pdp = NULL;
+               for (dp = np->n_data; dp != NULL; ) {
+                       if (!match(dp, odp->d_class, odp->d_type)) {
+                               if ((dp->d_type == T_CNAME ||
+                                   odp->d_type == T_CNAME) &&
+                                   odp->d_mark == dp->d_mark &&
+                                   zones[odp->d_zone].z_type != Z_CACHE) {
+                                       syslog(LOG_ERR,
+                               "%s has CNAME and other data (illegal)\n",
+                                           name);
+#ifdef DEBUG
+                                       if (debug)
+                                           fprintf(ddt,
+                               "db_update: %s: CNAME and more (%d, %d)\n",
+                                               name, odp->d_type, dp->d_type);
+#endif
+                               }
+                               goto skip;
+                       }
+#ifdef DEBUG
+                       if (debug >= 5)
+                               fprintf(ddt,"db_update: flags = %#x, sizes = %d, %d (%d)\n",
+                                   flags, odp->d_size, dp->d_size,
+                                   db_cmp(dp, odp));
+#endif
+                       if (flags & DB_NOTAUTH && dp->d_zone) {
+#ifdef DEBUG
+                               if (debug)
+                                       fprintf(ddt,
+                                       "%s attempted update to auth zone %d '%s'\n",
+                                   inet_ntoa(from_addr.sin_addr),
+                                   dp->d_zone, zones[dp->d_zone].z_origin);
+#endif
+                               return (AUTH);
+                       }
+                       if ((flags & DB_NODATA) && !db_cmp(dp, odp)) {
+                               /* refresh ttl if cache entry */
+                               if (dp->d_zone == 0) {
+                                       if (odp->d_zone != 0) { /* XXX */
+                                               /* changing cache->auth */
+                                               dp->d_zone = odp->d_zone;
+                                               dp->d_ttl = odp->d_ttl;
+#ifdef DEBUG
+                                               if (debug > 3)
+                                                       fprintf(ddt,
+                               "db_update: cache entry now in auth zone\n");
+#endif
+                                               return (DATAEXISTS);
+                                       }
+                                       fixttl(odp);
+                                       if (odp->d_ttl > dp->d_ttl)
+                                               dp->d_ttl = odp->d_ttl;
+#ifdef DEBUG
+                                       if (debug >= 3)
+                                       fprintf(ddt,"db_update: new ttl %d, +%d\n",
+                                               dp->d_ttl, dp->d_ttl - tt.tv_sec);
+#endif
+                               }
+                               return (DATAEXISTS);
+                       }
+                       /*
+                        * If the old databuf has some data, check that the
+                        * data matches that in the new databuf (so UPDATED
+                        * will delete only the matching RR)
+                        */
+                       if (odp->d_size > 0) {
+                               if (db_cmp(dp, odp))
+                                       goto skip;
+                       }
+                       foundRR = 1;
+                       if (flags & DB_DELETE)
+                               dp = rm_datum(dp, np, pdp);
+                       else {
+skip:                          pdp = dp;
+                               dp = dp->d_next;
+                       }
+               }
+                if (!foundRR) {
+                       if (flags & DB_DELETE)
+                               return(NODATA);
+                       if (flags & DB_MEXIST)
+                               return(NODATA);
+               }
+       }
+       if (newdp == NULL)
+               return (OK);
+       fixttl(newdp);
+#ifdef DEBUG
+        if (debug >= 3)
+               fprintf(ddt,"db_update: adding%s %x\n",
+                       (newdp->d_flags&DB_F_HINT) ? " hint":"", newdp);
+#endif
+       if (!(newdp->d_flags & DB_F_HINT))
+               addinv(np, newdp);      /* modify inverse query tables */
+
+       /* Add to end of list, generally preserving order */
+       newdp->d_next = NULL;
+       if ((dp = np->n_data) == NULL)  {
+               np->n_data = newdp;
+               return (OK);
+       }
+       /* XXX: need to check for duplicate WKS records and flag error */
+       while (dp->d_next != NULL) {
+               if ((flags & DB_NODATA) && !db_cmp(dp, newdp))
+                       return (DATAEXISTS);
+               dp = dp->d_next;
+       }
+       if ((flags & DB_NODATA) && !db_cmp(dp, newdp))
+               return (DATAEXISTS);
+       dp->d_next = newdp;
+       return (OK);
+}
+
+fixttl(dp)
+register struct databuf *dp;
+{
+       if (dp->d_zone == 0 && !(dp->d_flags & DB_F_HINT)) {
+               if (dp->d_ttl <= tt.tv_sec)
+                       return;
+               else if (dp->d_ttl < tt.tv_sec+min_cache_ttl)
+                       dp->d_ttl = tt.tv_sec+min_cache_ttl;
+               else if (dp->d_ttl > tt.tv_sec+max_cache_ttl)
+                       dp->d_ttl = tt.tv_sec+max_cache_ttl;
+       }
+       return;
+}
+
+struct invbuf *invtab[INVHASHSZ];      /* Inverse query hash table */
+
+/*
+ * Add data 'dp' to inverse query tables for name 'np'.
+ */
+addinv(np, dp)
+       struct namebuf *np;
+       struct databuf *dp;
+{
+       register struct invbuf *ip;
+       register int hval, i;
+
+       switch (dp->d_type) {
+       case T_A:
+       case T_UID:
+       case T_GID:
+               break;
+
+       default:
+               return;
+       }
+
+       hval = dhash(dp->d_data, dp->d_size);
+       for (ip = invtab[hval]; ip != NULL; ip = ip->i_next)
+               for (i = 0; i < INVBLKSZ; i++)
+                       if (ip->i_dname[i] == NULL) {
+                               ip->i_dname[i] = np;
+                               return;
+                       }
+       ip = saveinv();
+       ip->i_next = invtab[hval];
+       invtab[hval] = ip;
+       ip->i_dname[0] = np;
+}
+
+/*
+ * Remove data 'odp' from inverse query table.
+ */
+rminv(odp)
+       struct databuf *odp;
+{
+       register struct invbuf *ip;
+       register struct databuf *dp;
+       struct namebuf *np;
+       register int i;
+
+       for (ip = invtab[dhash(odp->d_data, odp->d_size)]; ip != NULL;
+           ip = ip->i_next) {
+               for (i = 0; i < INVBLKSZ; i++) {
+                       if ((np = ip->i_dname[i]) == NULL)
+                               break;
+                       for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+                               if (!match(dp, odp->d_class, odp->d_type))
+                                       continue;
+                               if (db_cmp(dp, odp))
+                                       continue;
+                               while (i < INVBLKSZ-1) {
+                                       ip->i_dname[i] = ip->i_dname[i+1];
+                                       i++;
+                               }
+                               ip->i_dname[i] = NULL;
+                               return;
+                       }
+               }
+       }
+}
+
+/*
+ * Compute hash value from data.
+ */
+dhash(dp, dlen)
+       char *dp;
+       int dlen;
+{
+       register char *cp;
+       register unsigned hval;
+       register int n;
+
+       n = dlen;
+       if (n > 8)
+               n = 8;
+       hval = 0;
+       for (cp = dp; --n >= 0; ) {
+               hval <<= 1;
+               hval += *cp++;
+       }
+       return (hval % INVHASHSZ);
+}
+
+/*
+ * Compare type, class and data from databufs for equivalence.
+ * Must be case insensitive for some domain names.
+ * Return 0 if equivalent, nonzero otherwise.
+ */
+db_cmp(dp1, dp2)
+       register struct databuf *dp1, *dp2;
+
+{
+       register char *cp1, *cp2;
+       int len;
+
+       if (dp1->d_type != dp2->d_type || dp1->d_class != dp2->d_class)
+               return(1);
+       if (dp1->d_size != dp2->d_size)
+               return(1);
+       if (dp1->d_mark != dp2->d_mark)
+               return(1);              /* old and new RR's are distinct */
+       switch (dp1->d_type) {
+
+       case T_A:
+       case T_UID:
+       case T_GID:
+       case T_WKS:
+       case T_NULL:
+#ifdef ALLOW_T_UNSPEC
+        case T_UNSPEC:
+#endif ALLOW_T_UNSPEC
+               return(bcmp(dp1->d_data, dp2->d_data, dp1->d_size));
+
+       case T_NS:
+       case T_CNAME:
+       case T_PTR:
+       case T_MB:
+       case T_MG:
+       case T_MR:
+       case T_UINFO:
+               return(strcasecmp(dp1->d_data, dp2->d_data));
+
+       case T_HINFO:
+               cp1 = dp1->d_data;
+               cp2 = dp2->d_data;
+               len = *cp1;
+               if (strncasecmp(++cp1, ++cp2, len))
+                       return(1);
+               cp1 += len;
+               cp2 += len;
+               len = *cp1;
+               return(strncasecmp(++cp1, ++cp2, len));
+
+       case T_SOA:
+       case T_MINFO:
+               if (strcasecmp(dp1->d_data, dp2->d_data))
+                       return(1);
+               cp1 = dp1->d_data + strlen(dp1->d_data) + 1;
+               cp2 = dp2->d_data + strlen(dp2->d_data) + 1;
+               if (dp1->d_type != T_SOA)
+                       return(strcasecmp(cp1, cp2));
+               if (strcasecmp(cp1, cp2))
+                       return(1);
+               cp1 += strlen(cp1) + 1;
+               cp2 += strlen(cp2) + 1;
+               return(bcmp(cp1, cp2, sizeof(u_long) * 5));
+       
+       case T_MX:
+               cp1 = dp1->d_data;
+               cp2 = dp2->d_data;
+               if (*cp1++ != *cp2++ || *cp1++ != *cp2++)       /* cmp prio */
+                       return(1);
+               return(strcasecmp(cp1, cp2));
+
+       case T_TXT:
+               if (dp1->d_size != dp2->d_size)
+                       return(1);
+               return(bcmp(dp1->d_data, dp2->d_data, dp1->d_size));
+
+       default:
+               return (1);
+       }
+}
diff --git a/usr/src/usr.sbin/named/named.8 b/usr/src/usr.sbin/named/named.8
new file mode 100644 (file)
index 0000000..2d506c4
--- /dev/null
@@ -0,0 +1,439 @@
+.\" Copyright (c) 1985, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"    This product includes software developed by the University of
+.\"    California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)named.8    6.9 (Berkeley) 3/16/91
+.\"
+.Dd March 16, 1991
+.Dt NAMED 8
+.Os BSD 4
+.Sh NAME
+.Nm named
+.Nd Internet domain name server
+.Sh SYNOPSIS
+.Nm named
+.Op Fl d Ar debuglevel
+.Op Fl p Ar port#
+.Oo Op Fl b
+.Ar bootfile Oc
+.Sh DESCRIPTION
+.Nm Named
+is the Internet domain name server.
+See
+.%T RFC883
+for more information on the Internet name-domain system.
+Without any arguments,
+.Nm named
+will read the default boot file
+.Pa /etc/named.boot ,
+read any initial data and listen for queries.
+.Pp
+Options are:
+.Bl -tag -width Ds
+.It Fl d
+Print debugging information.
+A number after the
+.Fl d
+determines the level of
+messages printed.
+.It Fl p
+Use a different port number.  The default is the standard port number
+as listed in
+.Pa /etc/services .
+.It Fl b
+Use an alternate boot file.  This is optional and allows you to
+specify a file with a leading dash.
+.El
+.Pp
+Any additional argument is taken as the name of the boot file.
+The boot file contains information about where the name server is to get
+its initial data.  If multiple boot files are specified, only the last
+is used.
+Lines in the boot file cannot be continued on subsequent lines.
+The following is a small example:
+.Bd -literal
+;
+;      boot file for name server
+;
+directory      /etc/namedb
+
+; type domain  source host/file                      backup file
+
+cache  .                                             root.cache
+primary   Berkeley.EDU          berkeley.edu.zone
+primary   32.128.IN-ADDR.ARPA   ucbhosts.rev
+secondary CC.Berkeley.EDU 128.32.137.8 128.32.137.3 cc.zone.bak
+secondary 6.32.128.IN-ADDR.ARPA 128.32.137.8 128.32.137.3 cc.rev.bak
+primary   0.0.127.IN-ADDR.ARPA localhost.rev
+forwarders 10.0.0.78 10.2.0.78
+; slave
+.Ed
+.Pp
+The ``directory'' line causes the server to change its
+working directory to the directory specified.  This can
+be important for the correct processing of
+.Li $INCLUDE
+files
+in primary zone files.
+.Pp
+The
+.Dq cache
+line specifies that data in
+.Dq Pa root.cache
+is to be
+placed in the backup cache.
+Its main use is to specify data such as locations of root domain servers.
+This cache is not used during normal operation,
+but is used as
+.Dq hints
+to find the current root servers.
+The file
+.Dq Pa root.cache
+is in the same format as
+.Dq Pa berkeley.edu.zone .
+There can be more than one
+.Dq cache
+file specified.
+.\"The first such file will be updated under certain conditions to snapshot the
+.\"cache (see
+.\" .Dv SIGQUIT
+.\" below).
+.\"The cache line can also have an optional interval argument after
+.\"the filename.
+.\"If an interval is listed,
+.\"it requests the nameserver to dump the cache contents
+.\"at that interval (in seconds).
+.\"The example above requests the nameserver to dump the cache content
+.\"every 3600 seconds (once an hour).
+.\"The use of automatic cache file updates is not currently recommended
+.\"because of the way the cache is currently managed by the server;
+.\"although the entire cache will be dumped for later reloading,
+.\"most of the cache contents will be ignored when reloaded.
+.\"The exact dump interval will vary
+.\"based on the minimum maintence interval time which is typically about
+.\"5 minutes.
+The cache files are processed in such a way as to preserve the
+time-to-live's
+of data dumped out.  Data for the root nameservers is kept artificially
+valid if necessary.
+.Pp
+The first
+.Dq primary
+line states that the file
+.Dq Pa berkeley.edu.zone
+contains
+authoritative data for the
+.Dq Berkeley. Ns Em EDU
+zone.
+The file
+.Dq Pa berkeley.edu.zone
+contains data in the master file format described in
+.%T RFC883 .
+All domain names are relative to the origin, in this
+case,
+.Dq Berkeley. Ns Em EDU
+(see below for a more detailed description).
+The second
+.Dq primary
+line states that the file
+.Dq Pa ucbhosts.rev
+contains
+authoritative data for the domain
+.Dq 32.128.IN-ADDR.ARPA ,
+which is used
+to translate addresses in network 128.32 to hostnames.
+Each master file should begin with an
+.Tn SOA
+record for the zone
+(see below).
+.Pp
+The first ``secondary'' line specifies that all authoritative data
+under
+.Dq CC.Berkeley. Ns Em EDU
+is to be transferred from the name server
+at 128.32.137.8.  If the transfer fails it will try 128.32.137.3 and
+continue trying the addresses, up to 10, listed on this line.
+The secondary copy is also authoritative for the specified domain.
+The first non-dotted-quad address on this line will be taken
+as a filename in which to backup the transfered zone.
+The name server will load the zone from this backup file if it exists
+when it boots, providing a complete copy even if the master servers
+are unreachable.
+Whenever a new copy of the domain is received by automatic zone transfer
+from one of the master servers, this file will be updated.
+The second
+.Dq secondary
+line states that the address-to-hostname
+mapping for the subnet 128.32.136 should be obtained from the same list
+of master servers as the previous zone.
+.Pp
+The
+.Dq forwarders
+line specifies the addresses of sitewide servers
+that will accept recursive queries from other servers.
+If the boot file specifies one or more forwarders, then the
+server will send all queries for data not in the cache to the forwarders first.
+Each forwarder will be asked in turn until an answer is returned
+or the list is exhausted.  If no answer is forthcoming from a
+forwarder, the server will continue as it would have without
+the forwarders line unless it is in ``slave'' mode.
+The forwarding facility is useful
+to cause a large sitewide cache to be generated on a master,
+and to reduce traffic over links to outside servers.
+It can also be used to allow servers to run that do not have
+access directly to the Internet, but wish to act as though
+they do.
+.Pp
+The ``slave'' line (shown commented out) is used to put the server
+in slave mode.  In this mode, the server will only make queries to
+forwarders.  This option is normally used on machine that wish to
+run a server but for physical or administrative reasons cannot
+be given access to the Internet, but have access to a host that
+does have access.
+.Pp
+The ``sortlist'' line can be used to indicate networks that are to be
+preferred over other, unlisted networks.
+Queries for host addresses from hosts on the same network as the server
+will receive responses with local network addresses listed first,
+then addresses on the sort list, then other addresses.
+This line is only acted on at initial startup.
+When reloading the nameserver with
+a
+.Dv SIGHUP ,
+this line will be ignored.
+.Pp
+The master file consists of control information
+and a list of resource records for objects in the zone
+of the forms:
+.Bd -literal
+$INCLUDE <filename> <opt_domain>
+$ORIGIN <domain>
+<domain> <opt_ttl> <opt_class> <type> <resource_record_data>
+.Ed
+.Pp
+where
+.Em domain
+is
+.Ql \&.
+for root,
+.Ql \&@
+for the current origin, or a standard domain
+name. If
+.Em domain
+is a standard domain name that does not end with
+.Ql \&. ,
+the current origin
+is appended to the domain. Domain names ending with
+.Ql \&.
+are
+unmodified.
+The
+.Em opt_domain
+field is used to define an origin for the data in an included file.
+It is equivalent to placing a
+.Li $ORIGIN
+statement before the first
+line of the included file.  The field is optional.
+Neither the
+.Em opt_domain
+field nor
+.Li $ORIGIN
+statements in the included file modify the current origin
+for this file.
+The
+.Em opt_ttl
+field is an optional integer number for the time-to-live field.
+It defaults to zero, meaning the minimum value specified in the
+SOA record for the zone.
+The
+.Em opt_class
+field is the object address type; currently only one type is supported,
+.Sy IN ,
+for objects connected to the
+.Tn DARPA
+Internet. 
+The
+.Em type
+field contains one of the following tokens; the data expected in the
+.Em resource_record_data
+field is in parentheses.
+.Bl -tag -width Fl
+.It A
+a host address (dotted quad)
+.It \&NS
+an authoritative name server (domain)
+.It \&MX
+a mail exchanger (domain)
+.It CNAME
+the canonical name for an alias (domain)
+.It SOA
+marks the start of a zone of authority (domain of originating host,
+domain address of maintainer, a serial number and the following
+parameters in seconds: refresh, retry, expire and minimum TTL
+(see
+.%T RFC883 ) )
+.It \&MB
+a mailbox domain name (domain)
+.It \&MG
+a mail group member (domain)
+.It \&MR
+a mail rename domain name (domain)
+.It NULL
+ra null resource record (no format or data)
+.It \&WKS
+a well know service description (not implemented yet)
+.It \&PTR
+a domain name pointer (domain)
+.It HINFO
+host information (cpu_type OS_type )
+.It MINFO
+mailbox or mail list information (request_domain error_domain)
+.El
+.Pp
+Resource records normally end at the end of a line,
+but may be continued across lines between opening and closing parentheses.
+Comments are introduced by semicolons and continue to the end of the line.
+.Pp
+Each master zone file should begin with an SOA
+record for the zone.
+An example SOA
+record is as follows:
+.Bd -literal
+@  IN  SOA  ucbvax.Berkeley.EDU. rwh.ucbvax.Berkeley.EDU. (
+                             2.89      ; serial
+                             10800     ; refresh
+                             3600      ; retry
+                             3600000   ; expire
+                             86400 )   ; minimum
+.Ed
+.Pp
+The SOA
+lists a serial number, which should be changed each time the master
+file is changed.
+Secondary servers check the serial number at intervals specified by the refresh
+time in seconds; if the serial number changes, a zone transfer will be done
+to load the new data.
+If a master server cannot be contacted when a refresh is due, the retry time
+specifies the interval at which refreshes should be attempted until successful.
+If a master server cannot be contacted within the interval given by the
+expire time, all data from the zone is discarded by secondary servers.
+The minimum value is the time-to-live used by records in the file
+with no explicit time-to-live value.
+.Sh NOTES
+The boot file directives ``domain'' and ``suffixes'' have been
+obsoleted by a more useful resolver based implementation of
+suffixing for partially qualified domain names.  The prior mechanisms
+could fail under a number of situations, especially when then local
+nameserver did not have complete information.
+.Pp
+The following signals have the specified effect when sent to the
+server process using the
+.Xr kill 1
+command.
+.Bl -tag -width Fl
+.It Dv SIGHUP
+Causes server to read
+.Pa named.boot
+and reload database.
+.It Dv SIGINT
+Dumps current data base and cache to
+.Pa /var/tmp/named_dump.db
+.\".IP
+.\" .Dv SIGQUIT
+.\"Causes the server to checkpoint the cache into the first ``cache'' file.
+.It Dv SIGIOT
+Dumps statistics data into
+.Pa /var/tmp/named.stats
+if the server is
+compiled
+.Dv \-DSTATS .
+Statistics data is appended to the file.
+.It Dv SIGSYS
+Dumps the profiling data in
+.Pa /var/tmp
+if the server is compiled
+with profiling (server forks, chdirs and exits).
+.It Dv SIGTERM
+Dumps the primary and secondary database files.
+Used to save modified data on shutdown if the
+server is compiled with dynamic updating enabled.
+.It Dv SIGUSR1
+urnsTurns on debugging; each
+.Dv SIGUSR1
+increments debug level.
+.Pf ( Dv SIGEMT
+on older systems without
+.Dv SIGUSR1 )
+.It Dv SIGUSR2
+Turns off debugging completely.
+.Pf ( Dv SIGFPE
+on older systems without
+.Dv SIGUSR2 )
+.El
+.Sh FILES
+.Bl -tag -width /var/tmp/named_dump.db -compact
+.It Pa /etc/named.boot
+name server configuration boot file
+.It Pa /etc/named.pid
+the process id
+.It Pa /var/tmp/named.run
+debug output
+.It Pa /var/tmp/named_dump.db
+dump of the name server database
+.It Pa /var/tmp/named.stats
+nameserver statistics data
+.El
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr gethostbyname 3 ,
+.Xr signal 3 ,
+.Xr resolver 3 ,
+.Xr resolver 5 ,
+.Xr hostname 7 ,
+.Rs
+.%T RFC882
+.Re
+.Rs
+.%T RFC883
+.Re
+.Rs
+.%T RFC973
+.Re
+.Rs
+.%T RFC974
+.Re
+.Rs
+.%T "Name Server Operations Guide for BIND"
+.Re
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/usr/src/usr.sbin/named/ns.h b/usr/src/usr.sbin/named/ns.h
new file mode 100644 (file)
index 0000000..1d0f264
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 1985, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ns.h        4.33 (Berkeley) 8/23/90
+ */
+
+/*
+ * Global definitions and variables for the name server.
+ */
+
+#include <arpa/inet.h>
+#include <string.h>
+
+/*
+ * Timeout time should be around 1 minute or so.  Using the
+ * the current simplistic backoff strategy, the sequence
+ * retrys after 4, 8, and 16 seconds.  With 3 servers, this
+ * dies out in a little more than a minute.
+ * (sequence RETRYBASE, 2*RETRYBASE, 4*RETRYBASE... for MAXRETRY)
+ */
+#define MINROOTS       2               /* min number of root hints */
+#define NSMAX          16              /* max number of NS addrs to try */
+#define RETRYBASE      4               /* base time between retries */
+#define MAXRETRY       3               /* max number of retries per addr */
+#define MAXCNAMES      8               /* max # of CNAMES tried per addr */
+#define MAXQUERIES     20              /* max # of queries to be made */
+                                       /* (prevent "recursive" loops) */
+#define        INIT_REFRESH    600             /* retry time for initial secondary */
+                                       /* contact (10 minutes) */
+
+#define ALPHA    0.7   /* How much to preserver of old response time */
+#define        BETA     1.2    /* How much to penalize response time on failure */
+#define        GAMMA    0.98   /* How much to decay unused response times */
+
+struct zoneinfo {
+       int     z_type;                 /* type of zone */
+       int     z_auth;                 /* zone is authoritative */
+       char    *z_origin;              /* root domain name of zone */
+       time_t  z_time;                 /* time for next refresh */
+       time_t  z_lastupdate;           /* time of last refresh */
+       u_long  z_refresh;              /* refresh interval */
+       u_long  z_retry;                /* refresh retry interval */
+       u_long  z_expire;               /* expiration time for cached info */
+       u_long  z_minimum;              /* minimum TTL value */
+       u_long  z_serial;               /* changes if zone modified */
+       char    *z_source;              /* source location of data */
+       time_t  z_ftime;                /* modification time of source file */
+       int     z_addrcnt;              /* address count */
+       struct  in_addr z_addr[NSMAX];  /* list of master servers for zone */
+       int     z_state;                /* state bits; see below */
+       u_short z_xferpid;              /* xfer child pid */
+#ifdef ALLOW_UPDATES
+       int     hasChanged;             /* non-zero if zone has been updated
+                                        * since last checkpoint
+                                        */
+#endif ALLOW_UPDATES
+};
+
+       /* zone types (z_type) */
+#define Z_PRIMARY      1
+#define Z_SECONDARY    2
+#define Z_CACHE                3
+
+       /* zone state bits */
+#define        Z_AUTH          0x01            /* should replace z_auth */
+#define        Z_NEED_XFER     0x02            /* waiting to do xfer */
+#define        Z_XFER_RUNNING  0x04            /* asynch. xfer is running */
+#define        Z_NEED_RELOAD   0x08            /* waiting to do reload */
+#define        Z_SYSLOGGED     0x10            /* have logged timeout */
+#define        Z_CHANGED       0x20            /* should replace hasChanged */
+#define        Z_FOUND         0x40            /* found in boot file when reloading */
+#define        Z_INCLUDE       0x80            /* set if include used in file */
+#define        Z_DB_BAD        0x100           /* errors when loading file */
+#define        Z_TMP_FILE      0x200           /* backup file for xfer is temporary */
+#ifdef ALLOW_UPDATES
+#define        Z_DYNAMIC       0x400           /* allow dynamic updates */
+#define        Z_DYNADDONLY    0x800           /* dynamic mode: add new data only */
+#endif ALLOW_UPDATES
+
+       /* xfer exit codes */
+#define        XFER_UPTODATE   0               /* zone is up-to-date */
+#define        XFER_SUCCESS    1               /* performed transfer successfully */
+#define        XFER_TIMEOUT    2               /* no server reachable/xfer timeout */
+#define        XFER_FAIL       3               /* other failure, has been logged */
+
+/*
+ * Structure for recording info on forwarded queries.
+ */
+struct qinfo {
+       u_short q_id;                   /* id of query */
+       u_short q_nsid;                 /* id of forwarded query */
+       int     q_dfd;                  /* UDP file descriptor */
+       struct  sockaddr_in q_from;     /* requestor's address */
+       char    *q_msg;                 /* the message */
+       int     q_msglen;               /* len of message */
+       int     q_naddr;                /* number of addr's in q_addr */
+       int     q_curaddr;              /* last addr sent to */
+       struct  fwdinfo *q_fwd;         /* last forwarder used */
+       time_t  q_time;                 /* time to retry */
+       struct  qinfo *q_next;          /* rexmit list (sorted by time) */
+       struct  qinfo *q_link;          /* storage list (random order) */
+       struct  qserv {
+               struct  sockaddr_in ns_addr;    /* addresses of NS's */
+               struct  databuf *ns;    /* databuf for NS record */
+               struct  databuf *nsdata; /* databuf for server address */
+               struct  timeval stime;  /* time first query started */
+               int     nretry;         /* # of times addr retried */
+       } q_addr[NSMAX];                /* addresses of NS's */
+       struct  databuf *q_usedns[NSMAX]; /* databuf for NS that we've tried */
+       int     q_nusedns;
+       int     q_cname;                /* # of cnames found */
+       int     q_nqueries;             /* # of queries required */
+       char    *q_cmsg;                /* the cname message */
+       int     q_cmsglen;              /* len of cname message */
+       struct  qstream *q_stream;      /* TCP stream, null if UDP */
+       int     q_system;               /* boolean, system query */
+};
+
+#define        Q_NEXTADDR(qp,n)        \
+       (((qp)->q_fwd == (struct fwdinfo *)0) ? \
+        &(qp)->q_addr[n].ns_addr : &(qp)->q_fwd->fwdaddr)
+
+#define PRIMING_CACHE  42
+#define QINFO_NULL     ((struct qinfo *)0)
+
+#ifndef XFER
+extern struct qinfo *qfindid();
+extern struct qinfo *qnew();
+extern struct qinfo *retryqp;          /* next query to retry */
+#endif /* XFER */
+
+/*
+ * Return codes from ns_forw:
+ */
+#define        FW_OK           0
+#define        FW_DUP          1
+#define        FW_NOSERVER     2
+#define        FW_SERVFAIL     3
+
+struct qstream {
+       int     s_rfd;                  /* stream file descriptor */
+       int     s_size;                 /* expected amount of data to recive */
+       int     s_bufsize;              /* amount of data recived in s_buf */
+       char    *s_buf;                 /* buffer of recived data */
+       char    *s_bufp;                /* pointer into s_buf of recived data */
+       struct  qstream *s_next;        /* next stream */
+       struct  sockaddr_in s_from;     /* address query came from */
+       u_long  s_time;                 /* time stamp of last transaction */
+       int     s_refcnt;               /* number of outstanding queries */
+       u_short s_tempsize;             /* temporary for size from net */
+};
+
+#define QSTREAM_NULL   ((struct qstream *)0)
+extern struct qstream *streamq;                /* stream queue */
+
+struct qdatagram {
+       int     dq_dfd;                 /* datagram file descriptor */
+       struct  qdatagram *dq_next;     /* next datagram */
+       struct  in_addr  dq_addr;       /* address of interface */
+};
+
+#define QDATAGRAM_NULL ((struct qdatagram *)0)
+extern struct qdatagram *datagramq;    /* datagram queue */
+
+struct netinfo {
+       struct netinfo *next;
+       u_long net;
+       u_long mask;
+       struct in_addr my_addr;
+};
+
+struct fwdinfo {
+       struct fwdinfo *next;
+       struct sockaddr_in fwdaddr;
+};
+
+struct nets {
+       char *name;
+       long net;
+       struct nets *next;
+}; 
+
+/*
+ *  Statistics Defines
+ */
+struct stats {
+       unsigned long   cnt;
+       char    *description;
+};
+
+/* gross count of UDP packets in and out */
+#define        S_INPKTS        0
+#define        S_OUTPKTS       1
+/* gross count of queries and inverse queries received */
+#define        S_QUERIES       2
+#define        S_IQUERIES      3
+#define S_DUPQUERIES   4
+#define        S_RESPONSES     5
+#define        S_DUPRESP       6
+#define        S_RESPOK        7
+#define        S_RESPFAIL      8
+#define        S_RESPFORMERR   9
+#define        S_SYSQUERIES    10
+#define        S_PRIMECACHE    11
+#define        S_CHECKNS       12
+#define        S_BADRESPONSES  13
+#define        S_MARTIANS      14
+#define S_NSTATS       15      /* Careful! */
+#ifdef STATS
+extern struct stats stats[S_NSTATS];
+extern unsigned long typestats[T_ANY+1];
+#endif
+
+/*
+ * Attempt to configure for type of function returned by signal-catching
+ * functions (which signal and sigvec.sv_handler take a pointer to).
+ * This can guess for BSD; otherwise, define SIG_FN externally.
+ */
+#ifndef        SIG_FN
+#ifdef BSD
+#if BSD >= 199006
+#define SIG_FN void            /* signal-catching functions return void */
+#else
+#define SIG_FN int             /* signal-catching functions return int */
+#endif
+#else  /* BSD */
+#define SIG_FN void            /* signal-catching functions return void */
+#endif /* BSD */
+#endif
+
+
+#ifdef DEBUG
+extern int debug;                      /* debug flag */
+extern FILE *ddt;                      /* debug file discriptor */
+#endif
+#ifndef XFER
+extern int ds;                         /* datagram socket */
+extern struct qdatagram *dqp;
+extern struct timeval tt;              /* place to store time */
+
+extern struct itimerval ival;          /* maintenance interval */
+extern struct zoneinfo *zones;         /* zone information */
+extern int nzones;                     /* number of zones in use */
+
+extern int forward_only;               /* true on slave server */
+#endif /* XFER */
+
+#ifdef vax
+extern u_short htons(), ntohs();
+extern u_long htonl(), ntohl();
+#endif
+
+#define MAX_XFER_TIME         60 * 60 * 2  /* max seconds for an xfer */
+#define XFER_TIME_FUDGE              10           /* MAX_XFER_TIME fudge */
+
+#ifndef XFER
+extern int xfer_running_cnt;             /* number of xfers running */
+extern int xfer_deferred_cnt;            /* number of deferred xfers */
+#define MAX_XFERS_RUNNING     4           /* max value of xfer_running_cnt */
+#endif /* XFER */
diff --git a/usr/src/usr.sbin/named/ns_forw.c b/usr/src/usr.sbin/named/ns_forw.c
new file mode 100644 (file)
index 0000000..2f1907a
--- /dev/null
@@ -0,0 +1,578 @@
+/*-
+ * Copyright (c) 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ns_forw.c  4.32 (Berkeley) 3/3/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <syslog.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdio.h>
+#include "ns.h"
+#include "db.h"
+
+struct qinfo *qhead = QINFO_NULL;      /* head of allocated queries */
+struct qinfo *retryqp = QINFO_NULL;    /* list of queries to retry */
+struct fwdinfo *fwdtab;                /* list of forwarding hosts */
+
+int    nsid;                           /* next forwarded query id */
+extern int forward_only;               /* you are only a slave */
+extern int errno;
+extern u_short ns_port;
+
+time_t retrytime();
+
+/*
+ * Forward the query to get the answer since its not in the database.
+ * Returns FW_OK if a request struct is allocated and the query sent.
+ * Returns FW_DUP if this is a duplicate of a pending request. 
+ * Returns FW_NOSERVER if there were no addresses for the nameservers.
+ * Returns FW_SERVFAIL on malloc error.
+ * (no action is taken on errors and qpp is not filled in.)
+ */
+ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp)
+       struct databuf *nsp[];
+       char *msg;
+       int msglen;
+       struct sockaddr_in *fp;
+       struct qstream *qsp;
+       int dfd;
+       struct qinfo **qpp;
+{
+       register struct qinfo *qp;
+       HEADER *hp;
+       u_short id;
+       extern char *calloc();
+
+#ifdef DEBUG
+       if (debug >= 3)
+               fprintf(ddt,"ns_forw()\n");
+#endif
+
+       /* Don't forward if we're already working on it. */
+       hp = (HEADER *) msg;
+       id = hp->id;
+       /* Look at them all */
+       for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
+               if (qp->q_id == id &&
+                   bcmp((char *)&qp->q_from, fp, sizeof(qp->q_from)) == 0 &&
+                   ((qp->q_cmsglen == 0 && qp->q_msglen == msglen &&
+                    bcmp((char *)qp->q_msg+2, msg+2, msglen-2) == 0) ||
+                   (qp->q_cmsglen == msglen &&
+                    bcmp((char *)qp->q_cmsg+2, msg+2, msglen-2) == 0))) {
+#ifdef DEBUG
+                       if (debug >= 3)
+                               fprintf(ddt,"forw: dropped DUP id=%d\n", ntohs(id));
+#endif
+#ifdef STATS
+                       stats[S_DUPQUERIES].cnt++;
+#endif
+                       return (FW_DUP);
+               }
+       }
+
+       qp = qnew();
+       if (nslookup(nsp, qp) == 0) {
+#ifdef DEBUG
+               if (debug >= 2)
+                       fprintf(ddt,"forw: no nameservers found\n");
+#endif
+               qfree(qp);
+               return (FW_NOSERVER);
+       }
+       qp->q_stream = qsp;
+       qp->q_curaddr = 0;
+       qp->q_fwd = fwdtab;
+       qp->q_dfd = dfd;
+       qp->q_id = id;
+       hp->id = qp->q_nsid = htons((u_short)++nsid);
+       hp->ancount = 0;
+       hp->nscount = 0;
+       hp->arcount = 0;
+       qp->q_from = *fp;
+       if ((qp->q_msg = malloc((unsigned)msglen)) == NULL) {
+               syslog(LOG_ERR, "forw: %m");
+               qfree(qp);
+               return (FW_SERVFAIL);
+       }
+       bcopy(msg, qp->q_msg, qp->q_msglen = msglen);
+       if (!qp->q_fwd) {
+               hp->rd = 0;
+               qp->q_addr[0].stime = tt;
+       }
+
+       schedretry(qp, retrytime(qp));
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,
+                  "forw: forw -> %s %d (%d) nsid=%d id=%d %dms retry %d sec\n",
+                       inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr),
+                       ds, ntohs(Q_NEXTADDR(qp,0)->sin_port),
+                       ntohs(qp->q_nsid), ntohs(qp->q_id),
+                       qp->q_addr[0].nsdata->d_nstime,
+                       qp->q_time - tt.tv_sec);
+       if ( debug >= 10)
+               fp_query(msg, ddt);
+#endif
+       if (sendto(ds, msg, msglen, 0, (struct sockaddr *)Q_NEXTADDR(qp,0),
+                  sizeof(struct sockaddr_in)) < 0){
+#ifdef DEBUG
+               if (debug >= 5)
+                       fprintf(ddt,"error returning msg errno=%d\n",errno);
+#endif
+       }
+#ifdef STATS
+       stats[S_OUTPKTS].cnt++;
+#endif
+       if (qpp)
+               *qpp = qp;
+       hp->rd = 1;
+       return (0);
+}
+
+/*
+ * Lookup the address for each nameserver in `nsp' and add it to
+ * the list saved in the qinfo structure.
+ */
+nslookup(nsp, qp)
+       struct databuf *nsp[];
+       register struct qinfo *qp;
+{
+       register struct namebuf *np;
+       register struct databuf *dp, *nsdp;
+       register struct qserv *qs;
+       register int n, i;
+       struct hashbuf *tmphtp;
+       char *dname, *fname;
+       int oldn, naddr, class, found_arr;
+       time_t curtime;
+       int qcomp();
+
+#ifdef DEBUG
+       if (debug >= 3)
+               fprintf(ddt,"nslookup(nsp=x%x,qp=x%x)\n",nsp,qp);
+#endif
+
+       naddr = n = qp->q_naddr;
+       curtime = (u_long) tt.tv_sec;
+       while ((nsdp = *nsp++) != NULL) {
+               class = nsdp->d_class;
+               dname = nsdp->d_data;
+#ifdef DEBUG
+               if (debug >= 3)
+                       fprintf(ddt,"nslookup: NS %s c%d t%d (x%x)\n",
+                               dname, class, nsdp->d_type, nsdp->d_flags);
+#endif
+               /* don't put in people we have tried */
+               for (i = 0; i < qp->q_nusedns; i++)
+                       if (qp->q_usedns[i] == nsdp) {
+#ifdef DEBUG
+                               if (debug >= 2)
+fprintf(ddt, "skipping used NS w/name %s\n", nsdp->d_data);
+#endif DEBUG
+                               goto skipserver;
+                       }
+
+               tmphtp = ((nsdp->d_flags & DB_F_HINT) ? fcachetab : hashtab);
+               np = nlookup(dname, &tmphtp, &fname, 1);
+               if (np == NULL || fname != dname) {
+#ifdef DEBUG
+                       if (debug >= 3)
+                           fprintf(ddt,"%s: not found %s %x\n",dname,fname,np);
+#endif
+                       continue;
+               }
+               found_arr = 0;
+               oldn = n;
+               /* look for name server addresses */
+               for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+                       if (dp->d_type != T_A || dp->d_class != class)
+                               continue;
+                       /*
+                        * Don't use records that may become invalid to
+                        * reference later when we do the rtt computation.
+                        * Never delete our safety-belt information!
+                        */
+                       if ((dp->d_zone == 0) &&
+                           (dp->d_ttl < (curtime+900)) &&
+                           !(dp->d_flags & DB_F_HINT) )
+                       {
+#ifdef DEBUG
+                               if (debug >= 3)
+                                       fprintf(ddt,"nslookup: stale entry '%s'\n",
+                                           np->n_dname);
+#endif
+                               /* Cache invalidate the NS RR's */
+                               if (dp->d_ttl < curtime)
+                                       delete_all(np, class, T_A);
+                               n = oldn;
+                               break;
+                       }
+
+                       found_arr++;
+                       /* don't put in duplicates */
+                       qs = qp->q_addr;
+                       for (i = 0; i < n; i++, qs++)
+                               if (bcmp((char *)&qs->ns_addr.sin_addr,
+                                   dp->d_data, sizeof(struct in_addr)) == 0)
+                                       goto skipaddr;
+                       qs->ns_addr.sin_family = AF_INET;
+                       qs->ns_addr.sin_port = ns_port;
+                       qs->ns_addr.sin_addr = 
+                                   *(struct in_addr *)dp->d_data;
+                       qs->ns = nsdp;
+                       qs->nsdata = dp;
+                       qp->q_addr[n].nretry = 0;
+                       n++;
+                       if (n >= NSMAX)
+                               goto out;
+       skipaddr:       ;
+               }
+#ifdef DEBUG
+               if (debug >= 3)
+                       fprintf(ddt,"nslookup: %d ns addrs\n", n);
+#endif
+               if (found_arr == 0 && qp->q_system == 0)
+                       (void) sysquery(dname, class, T_A);
+skipserver:    ;
+       }
+out:
+#ifdef DEBUG
+       if (debug >= 3)
+               fprintf(ddt,"nslookup: %d ns addrs total\n", n);
+#endif
+       qp->q_naddr = n;
+       if (n > 1)
+               qsort((char *)qp->q_addr, n, sizeof(struct qserv), qcomp);
+       return (n - naddr);
+}
+
+qcomp(qs1, qs2)
+       struct qserv *qs1, *qs2;
+{
+
+       return (qs1->nsdata->d_nstime - qs2->nsdata->d_nstime);
+}
+
+/*
+ * Arrange that forwarded query (qp) is retried after t seconds.
+ */
+schedretry(qp, t)
+       struct qinfo *qp;
+       time_t t;
+{
+       register struct qinfo *qp1, *qp2;
+
+#ifdef DEBUG
+       if (debug > 3) {
+               fprintf(ddt,"schedretry(%#x, %dsec)\n", qp, t);
+               if (qp->q_time)
+                  fprintf(ddt,"WARNING: schedretry(%x,%d) q_time already %d\n", qp->q_time);
+       }
+#endif
+       t += (u_long) tt.tv_sec;
+       qp->q_time = t;
+
+       if ((qp1 = retryqp) == NULL) {
+               retryqp = qp;
+               qp->q_next = NULL;
+               return;
+       }
+       if (t < qp1->q_time) {
+               qp->q_next = qp1;
+               retryqp = qp;
+               return;
+       }
+       while ((qp2 = qp1->q_next) != NULL && qp2->q_time < t)
+               qp1 = qp2;
+       qp1->q_next = qp;
+       qp->q_next = qp2;
+}
+
+/*
+ * Unsched is called to remove a forwarded query entry.
+ */
+unsched(qp)
+       struct qinfo *qp;
+{
+       register struct qinfo *np;
+
+#ifdef DEBUG
+       if (debug > 3) {
+               fprintf(ddt,"unsched(%#x, %d )\n", qp, ntohs(qp->q_id));
+       }
+#endif
+       if( retryqp == qp )  {
+               retryqp = qp->q_next;
+       } else {
+               for( np=retryqp; np->q_next != QINFO_NULL; np = np->q_next ) {
+                       if( np->q_next != qp)
+                               continue;
+                       np->q_next = qp->q_next;        /* dequeue */
+                       break;
+               }
+       }
+       qp->q_next = QINFO_NULL;                /* sanity check */
+       qp->q_time = 0;
+}
+
+/*
+ * Retry is called to retransmit query 'qp'.
+ */
+retry(qp)
+       register struct qinfo *qp;
+{
+       register int n;
+       register HEADER *hp;
+
+#ifdef DEBUG
+       if (debug > 3)
+               fprintf(ddt,"retry(x%x) id=%d\n", qp, ntohs(qp->q_id));
+#endif
+       if((HEADER *)qp->q_msg == NULL) {               /*** XXX ***/
+               qremove(qp);
+               return;
+       }                                               /*** XXX ***/
+
+       /* try next address */
+       n = qp->q_curaddr;
+       if (qp->q_fwd) {
+               qp->q_fwd = qp->q_fwd->next;
+               if (qp->q_fwd)
+                       goto found;
+               /* out of forwarders, try direct queries */
+       } else
+               ++qp->q_addr[n].nretry;
+       if (!forward_only) {
+               do {
+                       if (++n >= qp->q_naddr)
+                               n = 0;
+                       if (qp->q_addr[n].nretry < MAXRETRY)
+                               goto found;
+               } while (n != qp->q_curaddr);
+       }
+       /*
+        * Give up. Can't reach destination.
+        */
+       hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg);
+       if (qp->q_system == PRIMING_CACHE) {
+               /* Can't give up priming */
+               unsched(qp);
+               schedretry(qp, (time_t)60*60);  /* 1 hour */
+               hp->rcode = NOERROR;    /* Lets be safe, reset the query */
+               hp->qr = hp->aa = 0;
+               qp->q_fwd = fwdtab;
+               for (n = 0; n < qp->q_naddr; n++)
+                       qp->q_addr[n].nretry = 0;
+               return;
+       }
+#ifdef DEBUG
+       if (debug >= 5)
+               fprintf(ddt,"give up\n");
+#endif
+       n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen);
+       hp->id = qp->q_id;
+       hp->qr = 1;
+       hp->ra = 1;
+       hp->rd = 1;
+       hp->rcode = SERVFAIL;
+#ifdef DEBUG
+       if (debug >= 10)
+               fp_query(qp->q_msg, ddt);
+#endif
+       if (send_msg((char *)hp, n, qp)) {
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt,"gave up retry(x%x) nsid=%d id=%d\n",
+                               qp, ntohs(qp->q_nsid), ntohs(qp->q_id));
+#endif
+       }
+       qremove(qp);
+       return;
+
+found:
+       if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0)
+               qp->q_addr[n].stime = tt;
+       qp->q_curaddr = n;
+       hp = (HEADER *)qp->q_msg;
+       hp->rd = (qp->q_fwd ? 1 : 0);
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"%s(addr=%d n=%d) -> %s %d (%d) nsid=%d id=%d %dms\n",
+                       (qp->q_fwd ? "reforw" : "resend"),
+                       n, qp->q_addr[n].nretry,
+                       inet_ntoa(Q_NEXTADDR(qp,n)->sin_addr),
+                       ds, ntohs(Q_NEXTADDR(qp,n)->sin_port),
+                       ntohs(qp->q_nsid), ntohs(qp->q_id),
+                       qp->q_addr[n].nsdata->d_nstime);
+       if ( debug >= 10)
+               fp_query(qp->q_msg, ddt);
+#endif
+       /* NOSTRICT */
+       if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
+           (struct sockaddr *)Q_NEXTADDR(qp,n),
+           sizeof(struct sockaddr_in)) < 0){
+#ifdef DEBUG
+               if (debug > 3)
+                       fprintf(ddt,"error resending msg errno=%d\n",errno);
+#endif
+       }
+       hp->rd = 1;     /* leave set to 1 for dup detection */
+#ifdef STATS
+       stats[S_OUTPKTS].cnt++;
+#endif
+       unsched(qp);
+       schedretry(qp, qp->q_fwd ? (2*RETRYBASE) : retrytime(qp));
+}
+
+/*
+ * Compute retry time for the next server for a query.
+ * Use a minimum time of RETRYBASE (4 sec.) or twice the estimated
+ * service time; * back off exponentially on retries, but place a 45-sec.
+ * ceiling on retry times for now.  (This is because we don't hold a reference
+ * on servers or their addresses, and we have to finish before they time out.)
+ */
+time_t
+retrytime(qp)
+register struct qinfo *qp;
+{
+       time_t t;
+       struct qserv *ns = &qp->q_addr[qp->q_curaddr];
+
+#ifdef DEBUG
+       if (debug > 3)
+               fprintf(ddt,"retrytime: nstime %dms.\n",
+                   ns->nsdata->d_nstime / 1000);
+#endif
+       t = (time_t) MAX(RETRYBASE, 2 * ns->nsdata->d_nstime / 1000);
+       t <<= ns->nretry;
+       t = MIN(t, 45);                 /* max. retry timeout for now */
+#ifdef notdef
+       if (qp->q_system)
+               return ((2 * t) + 5);   /* system queries can wait. */
+#endif
+       return (t);
+}
+
+qflush()
+{
+       while (qhead)
+               qremove(qhead);
+       qhead = QINFO_NULL;
+}
+
+qremove(qp)
+register struct qinfo *qp;
+{
+#ifdef DEBUG
+       if(debug > 3)
+               fprintf(ddt,"qremove(x%x)\n", qp);
+#endif
+       unsched(qp);                    /* get off queue first */
+       qfree(qp);
+}
+
+struct qinfo *
+qfindid(id)
+register u_short id;
+{
+       register struct qinfo *qp;
+
+#ifdef DEBUG
+       if(debug > 3)
+               fprintf(ddt,"qfindid(%d)\n", ntohs(id));
+#endif
+       for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
+               if (qp->q_nsid == id)
+                       return(qp);
+       }
+#ifdef DEBUG
+       if (debug >= 5)
+               fprintf(ddt,"qp not found\n");
+#endif
+       return(NULL);
+}
+
+struct qinfo *
+qnew()
+{
+       register struct qinfo *qp;
+
+       if ((qp = (struct qinfo *)calloc(1, sizeof(struct qinfo))) == NULL) {
+#ifdef DEBUG
+               if (debug >= 5)
+                       fprintf(ddt,"qnew: calloc error\n");
+#endif
+               syslog(LOG_ERR, "forw: %m");
+               exit(12);
+       }
+#ifdef DEBUG
+       if (debug >= 5)
+               fprintf(ddt,"qnew(x%x)\n", qp);
+#endif
+       qp->q_link = qhead;
+       qhead = qp;
+       return( qp );
+}
+
+qfree(qp)
+struct qinfo *qp;
+{
+       register struct qinfo *np;
+
+#ifdef DEBUG
+       if(debug > 3)
+               fprintf(ddt,"qfree( x%x )\n", qp);
+       if(debug && qp->q_next)
+               fprintf(ddt,"WARNING:  qfree of linked ptr x%x\n", qp);
+#endif
+       if (qp->q_msg)
+               free(qp->q_msg);
+       if (qp->q_cmsg)
+               free(qp->q_cmsg);
+       if( qhead == qp )  {
+               qhead = qp->q_link;
+       } else {
+               for( np=qhead; np->q_link != QINFO_NULL; np = np->q_link )  {
+                       if( np->q_link != qp )  continue;
+                       np->q_link = qp->q_link;        /* dequeue */
+                       break;
+               }
+       }
+       (void)free((char *)qp);
+}
diff --git a/usr/src/usr.sbin/named/ns_init.c b/usr/src/usr.sbin/named/ns_init.c
new file mode 100644 (file)
index 0000000..d418ada
--- /dev/null
@@ -0,0 +1,703 @@
+/*-
+ * Copyright (c) 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ns_init.c  4.38 (Berkeley) 3/21/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <syslog.h>
+#include <signal.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#undef nsaddr
+#include "pathnames.h"
+#include "ns.h"
+#include "db.h"
+
+struct zoneinfo *zones;                /* zone information */
+int    nzones;                         /* number of zones in use */
+int    forward_only = 0;               /* run only as a slave */
+char   *cache_file;
+char   *localdomain;                   /* "default" for non-dotted names */
+int    maint_interval = 15*60;         /* minimum ns_maint() interval */
+
+extern int lineno;
+
+
+/*
+ * Read boot file for configuration info.
+ */
+
+ns_init(bootfile)
+       char *bootfile;
+{
+       register struct zoneinfo *zp;
+       struct zoneinfo *find_zone();
+       char buf[BUFSIZ], obuf[BUFSIZ], *source;
+       extern char *calloc();
+       FILE *fp;
+       int type;
+       extern int needmaint;
+       struct stat f_time;
+       static int loads = 0;                   /* number of times loaded */
+       static int tmpnum = 0;          /* unique number for tmp zone files */
+#ifdef ALLOW_UPDATES
+       char *cp, *flag;
+#endif
+
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"\nns_init(%s)\n", bootfile);
+#endif
+       gettime(&tt);
+
+       if ((fp = fopen(bootfile, "r")) == NULL) {
+               syslog(LOG_ERR, "%s: %m", bootfile);
+               exit(1);
+       }
+       lineno = 0;
+        if (loads == 0) {
+               if ((zones =
+                       (struct zoneinfo *)calloc(64, sizeof(struct zoneinfo)))
+                                           == NULL) {
+                   syslog(LOG_ERR,
+                       "Not enough memory to allocate initial zones array");
+                   exit(1);
+               }
+               nzones = 1;             /* zone zero is cache data */
+               /* allocate cache hash table, formerly the root hash table. */
+               hashtab = savehash((struct hashbuf *)NULL);
+
+               /* allocate root-hints/file-cache hash table */
+               fcachetab = savehash((struct hashbuf *)NULL);
+               /* init zone data */
+               zones[0].z_type = Z_CACHE;
+        } else {
+               /* Mark previous zones as not yet found in boot file. */
+               for (zp = &zones[1]; zp < &zones[nzones]; zp++)
+                       zp->z_state &= ~Z_FOUND;
+               if (localdomain)
+                       free(localdomain);
+               localdomain = NULL;
+               free_forwarders();
+               forward_only = 0;
+       }
+
+#ifdef DEBUG
+        if (debug >= 3) {
+               fprintf(ddt,"\n content of zones before loading \n");
+               content_zone(nzones - 1);
+        }
+#endif
+       while (!feof(fp) && !ferror(fp)) {
+               if (!getword(buf, sizeof(buf), fp))
+                       continue;
+               /* read named.boot keyword and process args */
+               if (strcasecmp(buf, "directory") == 0) {
+                       (void) getword(buf, sizeof(buf), fp);
+                       if (chdir(buf) < 0) {
+                               syslog(LOG_CRIT, "directory %s: %m\n",
+                                       buf);
+                               exit(1);
+                       }
+                       continue;
+               } else if (strcasecmp(buf, "sortlist") == 0) {
+                       get_sort_list(fp);
+                       continue;
+               } else if (strcasecmp(buf, "forwarders") == 0) {
+                       get_forwarders(fp);
+                       continue;
+               } else if (strcasecmp(buf, "slave") == 0) {
+                       forward_only++;
+                       endline(fp);
+                       continue;
+               } else if (strcasecmp(buf, "domain") == 0) {
+                       if (getword(buf, sizeof(buf), fp))
+                               localdomain = savestr(buf);
+                       endline(fp);
+                       continue;
+               } else if (strcasecmp(buf, "cache") == 0)
+                       type = Z_CACHE;
+               else if (strcasecmp(buf, "primary") == 0)
+                       type = Z_PRIMARY;
+               else if (strcasecmp(buf, "secondary") == 0)
+                       type = Z_SECONDARY;
+               else {
+                       syslog(LOG_ERR, "%s: line %d: unknown field '%s'\n",
+                               bootfile, lineno, buf);
+                       endline(fp);
+                       continue;
+               }
+
+               /*
+                * read zone origin
+                */
+               if (!getword(obuf, sizeof(obuf), fp)) {
+                       syslog(LOG_ERR, "%s: line %d: missing origin\n",
+                           bootfile, lineno);
+                       continue;
+               }
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt, "zone origin %s", obuf);
+#endif
+               if (obuf[0] == '.' && obuf[1] == '\0')
+                       obuf[0] = '\0';
+               /*
+                * read source file or host address
+                */
+               if (!getword(buf, sizeof(buf), fp)) {
+                       syslog(LOG_ERR,
+                           "%s: line %d: missing source or addr\n",
+                           bootfile, lineno);
+                       continue;
+               }
+
+               /* check for previous instance of this zone (reload) */
+               if ((zp = find_zone(obuf, type)) == 0) {
+                       if (type == Z_CACHE) {
+                               zp = &zones[0];
+                               zp->z_origin = "";
+                               goto gotzone;
+                       }
+                       for (zp = &zones[1]; zp < &zones[nzones]; zp++)
+                               if (zp->z_type == 0)
+                                       goto gotzone;
+                       /*
+                        * this code assume that nzones never decreases
+                        */
+                       if (nzones % 64  == 0) {
+#ifdef DEBUG
+                           if (debug > 1)
+                               fprintf(ddt, "Reallocating zones structure\n");
+#endif DEBUG
+                           /*
+                            * Realloc() not used since it might damage zones
+                            * if an error occurs
+                            */
+                           if ((zp = (struct zoneinfo *)
+                               malloc((64 + nzones) * sizeof(struct zoneinfo)))
+                                           == NULL) {
+                                   syslog(LOG_ERR, "no memory for more zones");
+#ifdef DEBUG
+                                   if (debug)
+                                       fprintf(ddt,
+                                           "Out of memory for new zones\n");
+#endif DEBUG
+                                   endline(fp);
+                                   continue;
+                           }
+                           bcopy((char *)zones, (char *)zp,
+                                           nzones * sizeof(struct zoneinfo));
+                           bzero((char *)&zp[nzones],
+                                           64 * sizeof(struct zoneinfo));
+                           free(zones);
+                           zones = zp;
+                       }
+                       zp = &zones[nzones++];
+       gotzone:
+                       zp->z_origin = savestr(obuf);
+                       zp->z_type = type;
+               }
+               zp->z_addrcnt = 0;
+
+               switch (type) {
+               case Z_CACHE:
+                       source = savestr(buf);
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt,", source = %s\n", source);
+#endif
+                       zp->z_refresh = 0;      /* by default, no dumping */
+                       if (getword(buf, sizeof(buf), fp)) {
+#ifdef notyet
+                               zp->z_refresh = atoi(buf);
+                               if (zp->z_refresh <= 0) {
+                                       syslog(LOG_ERR,
+                               "%s: line %d: bad refresh time '%s', ignored\n",
+                                               bootfile, lineno, buf);
+                                       zp->z_refresh = 0;
+                               } else if (cache_file == NULL)
+                                       cache_file = source;
+#else
+                               syslog(LOG_WARNING,
+                               "%s: line %d: cache refresh ignored\n",
+                                       bootfile, lineno);
+#endif
+                               endline(fp);
+                       }
+                       /*
+                        * If we've loaded this file, and the file has
+                        * not been modified and contains no $include,
+                        * then there's no need to reload.
+                        */
+                       if (zp->z_source && strcmp(source, zp->z_source) == 0 &&
+                           (zp->z_state & Z_INCLUDE) == 0 && 
+                           stat(zp->z_source, &f_time) == 0 &&
+                           zp->z_ftime == f_time.st_mtime) {
+#ifdef DEBUG
+                               if (debug)
+                                       fprintf(ddt, "cache is up to date\n");
+#endif
+                               break; /* zone is already up to date */
+                       }
+
+                       /* file has changed, or hasn't been loaded yet */
+                       if (zp->z_source) {
+                               free(zp->z_source);
+                               remove_zone(fcachetab, 0);
+                       }
+                       zp->z_source = source;
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt, "reloading zone\n");
+#endif
+                       (void) db_load(zp->z_source, zp->z_origin, zp, 0);
+                       break;
+
+               case Z_PRIMARY:
+                       source = savestr(buf);
+#ifdef ALLOW_UPDATES
+                       if (getword(buf, sizeof(buf), fp)) {
+                               endline(fp);
+                               flag = buf;
+                               while (flag) {
+                                   cp = index(flag, ',');
+                                   if (cp)
+                                       *cp++ = 0;
+                                   if (strcasecmp(flag, "dynamic") == 0)
+                                       zp->z_state |= Z_DYNAMIC;
+                                   else if (strcasecmp(flag, "addonly") == 0)
+                                       zp->z_state |= Z_DYNADDONLY;
+                                   else {
+                                       syslog(LOG_ERR,
+                                              "%s: line %d: bad flag '%s'\n",
+                                              bootfile, lineno, flag);
+                                   }
+                                   flag = cp;
+                               }
+                       }
+#else ALLOW_UPDATES
+                       endline(fp);
+#endif
+
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt,", source = %s\n", source);
+#endif
+                       /*
+                        * If we've loaded this file, and the file has
+                        * not been modified and contains no $include,
+                        * then there's no need to reload.
+                        */
+                       if (zp->z_source && strcmp(source, zp->z_source) == 0 &&
+                           (zp->z_state & Z_INCLUDE) == 0 && 
+                           stat(zp->z_source, &f_time) == 0 &&
+                           zp->z_ftime == f_time.st_mtime) {
+#ifdef DEBUG
+                               if (debug)
+                                       fprintf(ddt, "zone is up to date\n");
+#endif
+                               break; /* zone is already up to date */
+                       }
+                       if (zp->z_source) {
+                               free(zp->z_source);
+                               remove_zone(hashtab, zp - zones);
+                       }
+                        zp->z_source = source;
+                        zp->z_auth = 0;
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt, "reloading zone\n");
+#endif
+                       if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0)
+                               zp->z_auth = 1;
+#ifdef ALLOW_UPDATES
+                       /* Guarantee calls to ns_maint() */
+                       zp->z_refresh = maint_interval;
+#else ALLOW_UPDATES
+                       zp->z_refresh = 0;      /* no maintenance needed */
+                       zp->z_time = 0;
+#endif ALLOW_UPDATES
+                       break;
+
+               case Z_SECONDARY:
+                       source = 0;
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt,"\n\taddrs: ");
+#endif
+                       do {
+                               zp->z_addr[zp->z_addrcnt].s_addr =
+                                       inet_addr(buf);
+                               if (zp->z_addr[zp->z_addrcnt].s_addr ==
+                                               (u_long)-1) {
+                                       source = savestr(buf);
+                                       endline(fp);
+                                       break;
+                               }
+#ifdef DEBUG
+                               if (debug)
+                                       fprintf(ddt,"%s, ",buf);
+#endif
+                               if (++zp->z_addrcnt > NSMAX - 1) {
+                                       zp->z_addrcnt = NSMAX - 1;
+#ifdef DEBUG
+                                       if (debug)
+                                           fprintf(ddt,
+                                               "\nns.h NSMAX reached\n");
+#endif
+                               }
+                       } while (getword(buf, sizeof(buf), fp));
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt,"addrcnt = %d\n", zp->z_addrcnt);
+#endif
+                       if (source == 0) {
+                               /*
+                                * We will always transfer this zone again
+                                * after a reload.
+                                */
+                               sprintf(buf, "/%s/NsTmp%d", _PATH_TMPDIR,
+                                               tmpnum++);
+                               source = savestr(buf);
+                               zp->z_state |= Z_TMP_FILE;
+                       } else
+                               zp->z_state &= ~Z_TMP_FILE;
+                       /*
+                        * If we had a backup file name, and it was changed,
+                        * free old zone and start over.  If we don't have
+                        * current zone contents, try again now in case
+                        * we have a new server on the list.
+                        */
+                       if (zp->z_source && strcmp(source, zp->z_source)) {
+#ifdef DEBUG
+                               if (debug)
+                                       fprintf(ddt,"backup file changed\n");
+#endif
+                               free(zp->z_source);
+                               zp->z_source = 0;
+                               zp->z_auth = 0;
+                               zp->z_serial = 0;       /* force xfer */
+                               remove_zone(hashtab, zp - zones);
+                       }
+                       if (zp->z_source)
+                               free(source);
+                       else
+                               zp->z_source = source;
+                       if (zp->z_auth == 0)
+                               zoneinit(zp);
+                       break;
+
+               }
+                zp->z_state |= Z_FOUND;
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt,"zone[%d] type %d: '%s'",
+                               zp-zones, type,
+                               *(zp->z_origin) == '\0' ? "." : zp->z_origin);
+#endif
+               if (zp->z_refresh && zp->z_time == 0)
+                       zp->z_time = zp->z_refresh + tt.tv_sec;
+               if (zp->z_time <= tt.tv_sec)
+                       needmaint = 1;
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt, " z_time %d, z_refresh %d\n",
+                           zp->z_time, zp->z_refresh);
+#endif
+       }
+       (void) fclose(fp);
+        /* erase all old zones that were not found */
+        for (zp = &zones[1]; zp < &zones[nzones]; zp++)
+            if (zp->z_type && (zp->z_state & Z_FOUND) == 0) {
+               remove_zone(hashtab, zp - zones);
+               bzero((char *) zp, sizeof(*zp));
+#ifdef DEBUG
+               if(debug >=2)
+                       fprintf(ddt,"\n zone no %d was removed \n", zp - zones);
+#endif
+        }
+#ifdef DEBUG
+        if(debug >= 2) {
+               fprintf(ddt,"\n content of zones after loading \n");
+               content_zone(nzones-1);
+        }
+#endif
+
+       /*
+        * Schedule calls to ns_maint().
+        */
+       if (needmaint == 0)
+               sched_maint();
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"exit ns_init()%s\n", needmaint ?
+                   ", need maintenance immediately" : "");
+#endif
+       loads++;
+}
+
+zoneinit(zp)
+       register struct zoneinfo *zp;
+{
+       extern int needmaint;
+       struct stat sb;
+
+       /*
+        * Try to load zone from backup file,
+        * if one was specified and it exists.
+        * If not, or if the data are out of date,
+        * we will refresh the zone from a primary
+        * immediately.
+        */
+       if (zp->z_source == NULL)
+               return;
+       if (stat(zp->z_source, &sb) == -1 ||
+           db_load(zp->z_source, zp->z_origin, zp, 0) != 0) {
+               /*
+                * Set zone to be refreshed immediately.
+                */
+               zp->z_refresh = INIT_REFRESH;
+               zp->z_retry = INIT_REFRESH;
+               zp->z_time = tt.tv_sec;
+               needmaint = 1;
+       } else
+               zp->z_auth = 1;
+}
+
+#ifdef ALLOW_UPDATES
+/*
+ * Look for the authoritative zone with the longest matching RHS of dname
+ * and return its zone # or zero if not found.
+ */
+findzone(dname, class)
+       char *dname;
+       int class;
+{
+       char *dZoneName, *zoneName, *index();
+       int dZoneNameLen, zoneNameLen;
+       int maxMatchLen = 0;
+       int maxMatchZoneNum = 0;
+       int zoneNum;
+
+#ifdef DEBUG
+       if (debug >= 4)
+               fprintf(ddt, "findzone(dname=%s, class=%d)\n", dname, class);
+       if (debug >= 5) {
+               fprintf(ddt, "zone dump:\n");
+               for (zoneNum = 1; zoneNum < nzones; zoneNum++)
+                       printzoneinfo(zoneNum);
+       }
+#endif DEBUG
+
+       dZoneName = index(dname, '.');
+       if (dZoneName == NULL)
+               dZoneName = ""; /* root */
+       else
+               dZoneName++;    /* There is a '.' in dname, so use remainder of
+                                  string as the zone name */
+       dZoneNameLen = strlen(dZoneName);
+       for (zoneNum = 1; zoneNum < nzones; zoneNum++) {
+               zoneName = (zones[zoneNum]).z_origin;
+               zoneNameLen = strlen(zoneName);
+               /* The zone name may or may not end with a '.' */
+               if (zoneName[zoneNameLen - 1] == '.')
+                       zoneNameLen--;
+               if (dZoneNameLen != zoneNameLen)
+                       continue;
+#ifdef DEBUG
+               if (debug >= 5)
+                       fprintf(ddt, "about to strncasecmp('%s', '%s', %d)\n",
+                               dZoneName, zoneName, dZoneNameLen);
+#endif
+               if (strncasecmp(dZoneName, zoneName, dZoneNameLen) == 0) {
+#ifdef DEBUG
+                       if (debug >= 5)
+                               fprintf(ddt, "match\n");
+#endif
+                       /*
+                        * See if this is as long a match as any so far.
+                        * Check if "<=" instead of just "<" so that if
+                        * root domain (whose name length is 0) matches,
+                        * we use it's zone number instead of just 0
+                        */
+                       if (maxMatchLen <= zoneNameLen) {
+                               maxMatchZoneNum = zoneNum;
+                               maxMatchLen = zoneNameLen;
+                       }
+               }
+#ifdef DEBUG
+               else
+                       if (debug >= 5)
+                               fprintf(ddt, "no match\n");
+#endif
+       }
+#ifdef DEBUG
+       if (debug >= 4)
+               fprintf(ddt, "findzone: returning %d\n", maxMatchZoneNum);
+#endif DEBUG
+       return (maxMatchZoneNum);
+}
+#endif ALLOW_UPDATES
+
+soa_zinfo(zp, cp, eom)
+       register struct zoneinfo *zp;
+       register u_char *cp;
+       u_char *eom;
+{
+       cp += 3 * sizeof(u_short);
+       cp += sizeof(u_long);
+       cp += dn_skipname(cp, eom);
+       cp += dn_skipname(cp, eom);
+       GETLONG(zp->z_serial, cp);
+       GETLONG(zp->z_refresh, cp);
+       gettime(&tt);
+       zp->z_time = tt.tv_sec + zp->z_refresh;
+       GETLONG(zp->z_retry, cp);
+       GETLONG(zp->z_expire, cp);
+       GETLONG(zp->z_minimum, cp);
+}
+
+get_forwarders(fp)
+       FILE *fp;
+{
+       char buf[BUFSIZ];
+       register struct fwdinfo *fip = NULL, *ftp = NULL;
+       extern struct sockaddr_in nsaddr;
+       extern struct fwdinfo *fwdtab;
+
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"forwarders ");
+#endif
+
+       /* on mulitple forwarder lines, move to end of the list */
+       if (fwdtab != NULL)
+               for (fip = fwdtab; fip->next != NULL; fip = fip->next)
+                       ;
+
+       while (getword(buf, sizeof(buf), fp)) {
+               if (strlen(buf) == 0)
+                       break;
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt," %s",buf);
+#endif
+               if (ftp == NULL)
+                       ftp = (struct fwdinfo *)malloc(sizeof(struct fwdinfo));
+               if (isdigit(buf[0]) &&
+                   (ftp->fwdaddr.sin_addr.s_addr = inet_addr(buf)) !=
+                   (u_long)-1) {
+                       ftp->fwdaddr.sin_port = nsaddr.sin_port;
+                       ftp->fwdaddr.sin_family = AF_INET;
+               } else {
+                       syslog(LOG_ERR, "'%s' (ignored, NOT dotted quad)", buf);
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt," (ignored, NOT dotted quad)");
+#endif
+                       continue;       
+               }
+               ftp->next = NULL;
+               if (fwdtab == NULL)
+                       fwdtab = ftp;   /* First time only */
+               else
+                       fip->next = ftp;
+               fip = ftp;
+               ftp = NULL;
+       }
+       if (ftp)
+               free((char *)ftp);
+       
+#ifdef DEBUG
+       if (debug) 
+               fprintf(ddt,"\n");
+       if (debug > 2)
+               for (ftp = fwdtab; ftp != NULL; ftp = ftp->next)
+                       fprintf(ddt,"ftp x%x %s next x%x\n", ftp,
+                               inet_ntoa(ftp->fwdaddr.sin_addr), ftp->next);
+#endif
+}
+
+free_forwarders()
+{
+       extern struct fwdinfo *fwdtab;
+       register struct fwdinfo *ftp, *fnext;
+
+       for (ftp = fwdtab; ftp != NULL; ftp = fnext) {
+               fnext = ftp->next;
+               free((char *)ftp);
+       }
+       fwdtab = NULL;
+}
+
+struct zoneinfo *
+find_zone(name, type) 
+       char *name;
+       int type;
+{
+       register struct zoneinfo *zp;
+
+        for (zp = &zones[1]; zp < &zones[nzones]; zp++)
+               if (zp->z_type == type && strcasecmp(name, zp->z_origin) == 0) {
+#ifdef DEBUG
+                       if (debug > 1)
+                               fprintf(ddt, ", old zone (%d)", zp - zones);
+#endif
+                       return (zp);
+               }
+#ifdef DEBUG
+       if(debug > 1)
+               fprintf(ddt, ", new zone");
+#endif
+       return ((struct zoneinfo *)NULL);
+}
+
+/* prints out the content of zones */
+content_zone(end) 
+       int  end;
+{
+       int i;
+       for (i = 1; i <= end; i++)
+               printzoneinfo(i);
+}
diff --git a/usr/src/usr.sbin/named/ns_maint.c b/usr/src/usr.sbin/named/ns_maint.c
new file mode 100644 (file)
index 0000000..48bc78a
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ns_maint.c 4.39 (Berkeley) 3/2/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#if defined(SYSV)
+#include <unistd.h>
+#endif SYSV
+#include <netinet/in.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <signal.h>
+#include <errno.h>
+#include <arpa/nameser.h>
+#include <sys/wait.h>
+#include "ns.h"
+#include "db.h"
+#include "pathnames.h"
+
+extern int errno;
+extern int maint_interval;
+extern int needzoneload;
+extern u_short ns_port;
+extern char *ctime();
+
+int xfers_running;            /* number of xfers running */
+int xfers_deferred;           /* number of needed xfers not run yet */
+static int alarm_pending;
+
+
+/*
+ * Invoked at regular intervals by signal interrupt; refresh all secondary
+ * zones from primary name server and remove old cache entries.  Also,
+ * ifdef'd ALLOW_UPDATES, dump database if it has changed since last
+ * dump/bootup.
+ */
+ns_maint()
+{
+       register struct zoneinfo *zp;
+       struct itimerval ival;
+       time_t next_refresh = 0;
+       int zonenum;
+
+       gettime(&tt);
+
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"\nns_maint(); now %s", ctime(&tt.tv_sec));
+#endif
+
+       xfers_deferred = 0;
+       alarm_pending = 0;
+       for (zp = zones, zonenum = 0; zp < &zones[nzones]; zp++, zonenum++) {
+#ifdef DEBUG
+               if (debug >= 2)
+                       printzoneinfo(zonenum);
+#endif
+               if (tt.tv_sec >= zp->z_time && zp->z_refresh > 0) {
+                       /*
+                        * Set default time for next action first,
+                        * so that it can be changed later if necessary.
+                        */
+                       zp->z_time = tt.tv_sec + zp->z_refresh;
+
+                       switch (zp->z_type) {
+
+                       case Z_CACHE:
+                               doachkpt();
+                               break;
+
+                       case Z_SECONDARY:
+                               if ((zp->z_state & Z_NEED_RELOAD) == 0) {
+                                   if (zp->z_state & Z_XFER_RUNNING)
+                                       abortxfer(zp);
+                                   else if (xfers_running < MAX_XFERS_RUNNING)
+                                       startxfer(zp);
+                                   else {
+                                       zp->z_state |= Z_NEED_XFER;
+                                       ++xfers_deferred;
+#ifdef DEBUG
+                                       if (debug > 1)
+                                           fprintf(ddt,
+                                               "xfer deferred for %s\n",
+                                               zp->z_origin);
+#endif
+                                   }
+                               }
+                               break;
+#ifdef ALLOW_UPDATES
+                       case Z_PRIMARY:
+                               /*
+                                * Checkpoint the zone if it has changed
+                                * since we last checkpointed
+                                */
+                               if (zp->hasChanged)
+                                       zonedump(zp);
+                               break;
+#endif ALLOW_UPDATES
+                       }
+                       gettime(&tt);
+               }
+       }
+       sched_maint();
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"exit ns_maint()\n");
+#endif
+}
+
+/*
+ * Find when the next refresh needs to be and set
+ * interrupt time accordingly.
+ */
+sched_maint()
+{
+       register struct zoneinfo *zp;
+       struct itimerval ival;
+       time_t next_refresh = 0;
+       static time_t next_alarm;
+
+       for (zp = zones; zp < &zones[nzones]; zp++)
+               if (zp->z_time != 0 &&
+                   (next_refresh == 0 || next_refresh > zp->z_time))
+                       next_refresh = zp->z_time;
+        /*
+        *  Schedule the next call to ns_maint.
+        *  Don't visit any sooner than maint_interval.
+        */
+       bzero((char *)&ival, sizeof (ival));
+       if (next_refresh != 0) {
+               if (next_refresh == next_alarm && alarm_pending) {
+#ifdef DEBUG
+                       if (debug)
+                           fprintf(ddt,"sched_maint: no schedule change\n");
+#endif
+                       return;
+               }
+               ival.it_value.tv_sec = next_refresh - tt.tv_sec;
+               if (ival.it_value.tv_sec < maint_interval)
+                       ival.it_value.tv_sec = maint_interval;
+               next_alarm = next_refresh;
+               alarm_pending = 1;
+       }
+       (void) setitimer(ITIMER_REAL, &ival, (struct itimerval *)NULL);
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"sched_maint: Next interrupt in %d sec\n",
+                       ival.it_value.tv_sec);
+#endif
+}
+
+/*
+ * Start an asynchronous zone transfer for a zone.
+ * Depends on current time being in tt.
+ * The caller must call sched_maint after startxfer.
+ */
+startxfer(zp)
+       struct zoneinfo *zp;
+{
+       static char *argv[NSMAX + 20], argv_ns[NSMAX][MAXDNAME];
+       int cnt, argc = 0, argc_ns = 0, pid, omask;
+       char debug_str[10];
+       char serial_str[10];
+       char port_str[10];
+
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"startxfer() %s\n", zp->z_origin);
+#endif
+
+       argv[argc++] = "named-xfer";
+       argv[argc++] = "-z";
+       argv[argc++] = zp->z_origin;
+       argv[argc++] = "-f";
+       argv[argc++] = zp->z_source;
+       argv[argc++] = "-s";
+       sprintf(serial_str, "%d", zp->z_serial);
+       argv[argc++] = serial_str;
+       if (zp->z_state & Z_SYSLOGGED)
+               argv[argc++] = "-q";
+       argv[argc++] = "-P";
+       sprintf(port_str, "%d", ns_port);
+       argv[argc++] = port_str;
+#ifdef DEBUG
+       if (debug) {
+               argv[argc++] = "-d";
+               sprintf(debug_str, "%d", debug);
+               argv[argc++] = debug_str;
+               argv[argc++] = "-l";
+               argv[argc++] = "/usr/tmp/xfer.ddt";
+               if (debug > 5) {
+                       argv[argc++] = "-t";
+                       argv[argc++] = "/usr/tmp/xfer.trace";
+               }
+       }
+#endif
+       
+       /*
+        * Copy the server ip addresses into argv, after converting
+        * to ascii and saving the static inet_ntoa result
+        */
+       for (cnt = 0; cnt < zp->z_addrcnt; cnt++)
+               argv[argc++] = strcpy(argv_ns[argc_ns++],
+                   inet_ntoa(zp->z_addr[cnt]));
+
+       argv[argc] = 0;
+
+#ifdef DEBUG
+#ifdef ECHOARGS
+       if (debug) {
+               int i;
+               for (i = 0; i < argc; i++) 
+                       fprintf(ddt, "Arg %d=%s\n", i, argv[i]);
+        }
+#endif /* ECHOARGS */
+#endif /* DEBUG */
+
+#ifdef SYSV
+#define vfork fork
+#else
+       gettime(&tt);
+       omask = sigblock(sigmask(SIGCHLD));
+#endif
+       if ((pid = vfork()) == -1) {
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt, "xfer [v]fork: %d\n", errno);
+#endif
+               syslog(LOG_ERR, "xfer [v]fork: %m");
+#ifndef SYSV
+               (void) sigsetmask(omask);
+#endif
+               zp->z_time = tt.tv_sec + 10;
+               return;
+       }
+
+       if (pid) {
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt, "started xfer child %d\n", pid);
+#endif
+               zp->z_state &= ~Z_NEED_XFER;
+               zp->z_state |= Z_XFER_RUNNING;
+               zp->z_xferpid = pid;
+               xfers_running++;
+               zp->z_time = tt.tv_sec + MAX_XFER_TIME;
+#ifndef SYSV
+               (void) sigsetmask(omask);
+#endif
+       } else {
+               execve(_PATH_XFER, argv, NULL);
+               syslog(LOG_ERR, "can't exec %s: %m", _PATH_XFER);
+               _exit(XFER_FAIL);       /* avoid duplicate buffer flushes */
+       }
+}
+
+#ifdef DEBUG
+printzoneinfo(zonenum)
+int zonenum;
+{
+       struct timeval  tt;
+       struct zoneinfo *zp = &zones[zonenum];
+       char *ZoneType;
+
+       if (!debug)
+               return; /* Else fprintf to ddt will bomb */
+       fprintf(ddt, "printzoneinfo(%d):\n", zonenum);
+
+       gettime(&tt);
+       switch (zp->z_type) {
+               case Z_PRIMARY: ZoneType = "Primary"; break;
+               case Z_SECONDARY: ZoneType = "Secondary"; break;
+               case Z_CACHE: ZoneType = "Cache"; break;
+               default: ZoneType = "Unknown";
+       }
+       if (zp->z_origin[0] == '\0')
+               fprintf(ddt,"origin ='.'");
+       else
+               fprintf(ddt,"origin ='%s'", zp->z_origin);
+       fprintf(ddt,", type = %s", ZoneType);
+       fprintf(ddt,", source = %s\n", zp->z_source);
+       fprintf(ddt,"z_refresh = %ld", zp->z_refresh);
+       fprintf(ddt,", retry = %ld", zp->z_retry);
+       fprintf(ddt,", expire = %ld", zp->z_expire);
+       fprintf(ddt,", minimum = %ld", zp->z_minimum);
+       fprintf(ddt,", serial = %ld\n", zp->z_serial);
+       fprintf(ddt,"z_time = %d", zp->z_time);
+       if (zp->z_time) {
+               fprintf(ddt,", now time : %d sec", tt.tv_sec);
+               fprintf(ddt,", time left: %d sec", zp->z_time - tt.tv_sec);
+       }
+       fprintf(ddt,"; state %x\n", zp->z_state);
+}
+#endif DEBUG
+
+/*
+ * remove_zone (htp, zone) --
+ *     Delete all RR's in the zone "zone" under specified hash table.
+ */
+remove_zone(htp, zone)
+       register struct hashbuf *htp;
+       register int zone;
+{
+       register struct databuf *dp, *pdp;
+       register struct namebuf *np;
+       struct namebuf **npp, **nppend;
+
+       nppend = htp->h_tab + htp->h_size;
+       for (npp = htp->h_tab; npp < nppend; npp++)
+           for (np = *npp; np != NULL; np = np->n_next) {
+               for (pdp = NULL, dp = np->n_data; dp != NULL; ) {
+                       if (dp->d_zone == zone)
+                               dp = rm_datum(dp, np, pdp);
+                       else {
+                               pdp = dp;
+                               dp = dp->d_next;
+                       }
+               }
+               /* Call recursively to remove subdomains. */
+               if (np->n_hash)
+                       remove_zone(np->n_hash, zone);
+           }
+}
+   
+/*
+ * Abort an xfer that has taken too long.
+ */
+abortxfer(zp)
+       register struct zoneinfo *zp;
+{
+
+       kill(zp->z_xferpid, SIGKILL); /* don't trust it at all */
+#ifdef DEBUG
+       if (debug)
+         fprintf(ddt, "Killed child %d (zone %s) due to timeout\n",
+            zp->z_xferpid, zp->z_origin);
+#endif /* DEBUG */
+       zp->z_time = tt.tv_sec + zp->z_retry;
+}
+
+#ifdef SYSV
+union wait {
+       unsigned short  w_termsig:7;    /* termination signal */
+       unsigned short  w_coredump:1;   /* core dump indicator */
+       unsigned short  w_retcode:8;    /* exit code if w_termsig==0 */
+};
+#endif
+
+/*
+ * SIGCHLD signal handler: process exit of xfer's.
+ * (Note: also called when outgoing transfer completes.)
+ */
+SIG_FN
+endxfer()
+{
+       register struct zoneinfo *zp;   
+       int pid, xfers = 0;
+       union wait status;
+
+       gettime(&tt);
+#if defined(SYSV)
+       { int stat;
+       pid = wait(&stat);
+       status.w_termsig = stat & 0x7f;
+       status.w_retcode = stat >> 8;
+       }
+#else /* SYSV */
+       while ((pid =
+           wait3((int *)&status, WNOHANG, (struct rusage *)NULL)) > 0) {
+#endif /* SYSV */
+               for (zp = zones; zp < &zones[nzones]; zp++)
+                   if (zp->z_xferpid == pid) {
+                       xfers++;
+                       xfers_running--;
+                       zp->z_xferpid = 0;
+                       zp->z_state &= ~Z_XFER_RUNNING;
+#ifdef DEBUG
+                       if (debug) 
+                           fprintf(ddt,
+               "\nendxfer: child %d zone %s returned status=%d termsig=%d\n", 
+                               pid, zp->z_origin, status.w_retcode,
+                               status.w_termsig);
+#endif
+                       if (status.w_termsig != 0) {
+                               if (status.w_termsig != SIGKILL) {
+                                       syslog(LOG_ERR,
+                                          "named-xfer exited with signal %d\n",
+                                          status.w_termsig);
+#ifdef DEBUG
+                                       if (debug)
+                                           fprintf(ddt,
+                                        "\tchild termination with signal %d\n",
+                                               status.w_termsig);
+#endif
+                               }
+                               zp->z_time = tt.tv_sec + zp->z_retry;
+                       } else switch (status.w_retcode) {
+                               case XFER_UPTODATE:
+                                       zp->z_state &= ~Z_SYSLOGGED;
+                                       zp->z_lastupdate = tt.tv_sec;
+                                       zp->z_time = tt.tv_sec + zp->z_refresh;
+                                       /*
+                                        * Restore z_auth in case expired,
+                                        * but only if there were no errors
+                                        * in the zone file.
+                                        */
+                                       if ((zp->z_state & Z_DB_BAD) == 0)
+                                               zp->z_auth = 1;
+                                       if (zp->z_source) {
+#if defined(SYSV)
+                                               struct utimbuf t;
+
+                                               t.actime = tt.tv_sec;
+                                               t.modtime = tt.tv_sec;
+                                               (void) utime(zp->z_source, &t);
+#else
+                                               struct timeval t[2];
+
+                                               t[0] = tt;
+                                               t[1] = tt;
+                                               (void) utimes(zp->z_source, t);
+#endif /* SYSV */
+                                       }
+                                       break;
+
+                               case XFER_SUCCESS:
+                                       zp->z_state |= Z_NEED_RELOAD;
+                                       zp->z_state &= ~Z_SYSLOGGED;
+                                       needzoneload++;
+                                       break;
+
+                               case XFER_TIMEOUT:
+#ifdef DEBUG
+                                       if (debug) fprintf(ddt,
+                   "zoneref: Masters for secondary zone %s unreachable\n",
+                                           zp->z_origin);
+#endif
+                                       if ((zp->z_state & Z_SYSLOGGED) == 0) {
+                                               zp->z_state |= Z_SYSLOGGED;
+                                               syslog(LOG_WARNING,
+                     "zoneref: Masters for secondary zone %s unreachable",
+                                                   zp->z_origin);
+                                       }
+                                       zp->z_time = tt.tv_sec + zp->z_retry;
+                                       break;
+
+                               default:
+                                       if ((zp->z_state & Z_SYSLOGGED) == 0) {
+                                               zp->z_state |= Z_SYSLOGGED;
+                                               syslog(LOG_ERR,
+                                                   "named-xfer exit code %d",
+                                                   status.w_retcode);
+                                       }
+                                       /* FALLTHROUGH */
+                               case XFER_FAIL:
+                                       zp->z_state |= Z_SYSLOGGED;
+                                       zp->z_time = tt.tv_sec + zp->z_retry;
+                                       break;
+                       }
+                       break;
+               }
+#ifndef SYSV
+       }
+#endif /* SYSV */
+       if (xfers) {
+               for (zp = zones;
+                   xfers_deferred != 0 && xfers_running < MAX_XFERS_RUNNING &&
+                   zp < &zones[nzones]; zp++)
+                       if (zp->z_state & Z_NEED_XFER) {
+                               xfers_deferred--;
+                               startxfer(zp);
+                       }
+               sched_maint();
+       }
+#if defined(SYSV)
+       (void)signal(SIGCLD, endxfer);
+#endif
+}
+
+/*
+ * Reload zones whose transfers have completed.
+ */
+loadxfer()
+{
+       register struct zoneinfo *zp;   
+
+       gettime(&tt);
+       for (zp = zones; zp < &zones[nzones]; zp++)
+           if (zp->z_state & Z_NEED_RELOAD) {
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt, "loadxfer() '%s'\n",
+                       zp->z_origin[0] ? zp->z_origin : ".");
+#endif
+               zp->z_state &= ~Z_NEED_RELOAD;
+               zp->z_auth = 0;
+               remove_zone(hashtab, zp - zones);
+               if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0)
+                       zp->z_auth = 1;
+               if (zp->z_state & Z_TMP_FILE)
+                       (void) unlink(zp->z_source);
+           }
+       sched_maint();
+}
diff --git a/usr/src/usr.sbin/named/ns_resp.c b/usr/src/usr.sbin/named/ns_resp.c
new file mode 100644 (file)
index 0000000..c016c02
--- /dev/null
@@ -0,0 +1,1703 @@
+/*
+ * Copyright (c) 1986, 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ns_resp.c  4.65 (Berkeley) 3/3/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <syslog.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdio.h>
+#include "ns.h"
+#include "db.h"
+
+extern int     debug;
+extern FILE    *ddt;
+extern int errno;
+extern u_char *dnptrs[];
+extern time_t retrytime();
+extern struct  fwdinfo *fwdtab;
+extern struct  sockaddr_in from_addr;  /* Source addr of last packet */
+extern int needs_prime_cache;
+extern int priming;
+
+struct qinfo *sysquery();
+
+ns_resp(msg, msglen)
+       u_char *msg;
+       int msglen;
+{
+       register struct qinfo *qp;
+       register HEADER *hp;
+       register struct qserv *qs;
+       register struct databuf *ns, *ns2;
+       register u_char *cp;
+       struct  databuf *nsp[NSMAX], **nspp;
+       int i, c, n, ancount, aucount, nscount, arcount;
+       int type, class, dbflags;
+       int cname = 0; /* flag for processing cname response */
+       int count, founddata, foundname;
+       int buflen;
+       int newmsglen;
+       char name[MAXDNAME], *dname;
+       char *fname;
+       u_char newmsg[BUFSIZ];
+       u_char **dpp, *tp;
+       time_t rtrip;
+
+       struct hashbuf *htp;
+       struct namebuf *np;
+       struct netinfo *lp;
+       extern struct netinfo *local();
+       extern int nsid;
+       extern int addcount;
+       struct fwdinfo *fwd;
+
+#ifdef STATS
+       stats[S_RESPONSES].cnt++;
+#endif
+       hp = (HEADER *) msg;
+       if ((qp = qfindid(hp->id)) == NULL ) {
+#ifdef DEBUG
+               if (debug > 1)
+                       fprintf(ddt,"DUP? dropped (id %d)\n", ntohs(hp->id));
+#endif
+#ifdef STATS
+               stats[S_DUPRESP].cnt++;
+#endif
+               return;
+       }
+
+#ifdef DEBUG
+       if (debug >= 2)
+               fprintf(ddt,"%s response nsid=%d id=%d\n",
+                       qp->q_system ? "SYSTEM" : "USER",
+                       ntohs(qp->q_nsid), ntohs(qp->q_id));
+#endif
+
+       /*
+        *  Here we handle bad responses from servers.
+        *  Several possibilities come to mind:
+        *      The server is sick and returns SERVFAIL
+        *      The server returns some garbage opcode (its sick)
+        *      The server can't understand our query and return FORMERR
+        *  In all these cases, we simply drop the packet and force
+        *  a retry.  This will make him look bad due to unresponsiveness.
+        *  Be sure not to include authoritative NXDOMAIN
+        */
+       if ((hp->rcode != NOERROR && hp->rcode != NXDOMAIN)
+           || (hp->rcode == NXDOMAIN && !hp->aa)
+           || hp->opcode != QUERY) {
+#ifdef DEBUG
+               if (debug >= 2)
+                       fprintf(ddt,"resp: error (ret %d, op %d), dropped\n",
+                               hp->rcode, hp->opcode);
+#endif
+#ifdef STATS
+               stats[S_BADRESPONSES].cnt++;
+#endif
+               return;
+       }
+
+#ifdef ALLOW_UPDATES
+       if ( (hp->rcode == NOERROR) &&
+            (hp->opcode == UPDATEA || hp->opcode == UPDATED ||
+             hp->opcode == UPDATEDA || hp->opcode == UPDATEM ||
+             hp->opcode == UPDATEMA) ) {
+               /*
+                * Update the secondary's copy, now that the primary
+                * successfully completed the update.  Zone doesn't matter
+                * for dyn. update -- doupdate calls findzone to find it
+                */
+               doupdate(qp->q_msg, qp->q_msglen, qp->q_msg + sizeof(HEADER),
+                        0, (struct databuf *)0, 0);
+#ifdef DEBUG
+               if (debug >= 3)
+                       fprintf(ddt,"resp: leaving, UPDATE*\n");
+#endif
+               /* return code filled in by doupdate */
+               goto return_msg;
+       }
+#endif ALLOW_UPDATES
+
+       /*
+        * Determine if the response came from a forwarder.  Packets from
+        * anyplace not listed as a forwarder or as a server to whom we
+        * might have forwarded the query will be dropped.
+        */
+       for (fwd = fwdtab; fwd != (struct fwdinfo *)NULL; fwd = fwd->next)
+               if (bcmp((char *)&fwd->fwdaddr.sin_addr, &from_addr.sin_addr,
+                   sizeof(struct in_addr)) == 0)
+                       break;
+       /*
+        * If we were using nameservers, find the qinfo pointer and update
+        * the rtt and fact that we have called on this server before.
+        */
+       if (fwd == (struct fwdinfo *)NULL) {
+               struct timeval *stp;
+
+               for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++)
+                       if (bcmp((char *)&qs->ns_addr.sin_addr,
+                           &from_addr.sin_addr, sizeof(struct in_addr)) == 0)
+                               break;
+               if (n >= qp->q_naddr) {
+#ifdef DEBUG
+                       if (debug)
+                           fprintf(ddt, "Response from unexpected source %s\n",
+                               inet_ntoa(from_addr.sin_addr));
+#endif DEBUG
+#ifdef STATS
+                       stats[S_MARTIANS].cnt++;
+#endif
+                       /* 
+                        * We don't know who this response came from so it
+                        * gets dropped on the floor.
+                        */
+                       return;
+               }
+               stp = &qs->stime;
+
+               /* Handle response from different (untried) interface */
+               if (stp->tv_sec == 0) {
+                       ns = qs->ns;
+                       while (qs > qp->q_addr &&
+                           (qs->stime.tv_sec == 0 || qs->ns != ns))
+                               qs--;
+                       *stp = qs->stime;
+#ifdef DEBUG
+                       if (debug)
+                           fprintf(ddt,
+                           "Response from unused address %s, assuming %s\n",
+                               inet_ntoa(from_addr.sin_addr),
+                               inet_ntoa(qs->ns_addr.sin_addr));
+#endif DEBUG
+               }
+
+               /* compute query round trip time */
+               rtrip = ((tt.tv_sec - stp->tv_sec) * 1000 +
+                   (tt.tv_usec - stp->tv_usec) / 1000);
+               
+#ifdef DEBUG
+               if (debug > 2)
+                       fprintf(ddt,"stime %d/%d  now %d/%d rtt %d\n",
+                           stp->tv_sec, stp->tv_usec,
+                           tt.tv_sec, tt.tv_usec, rtrip);
+#endif
+               /* prevent floating point overflow, limit to 1000 sec */
+               if (rtrip > 1000000)
+                               rtrip = 1000000;
+               ns = qs->nsdata;
+               /*
+                * Don't update nstime if this doesn't look
+                * like an address databuf now.                 XXX
+                */
+               if (ns->d_type == T_A && ns->d_class == qs->ns->d_class) {
+                       if (ns->d_nstime == 0)
+                               ns->d_nstime = (u_long)rtrip;
+                       else
+                               ns->d_nstime = ns->d_nstime * ALPHA +
+                                   (1-ALPHA) * (u_long)rtrip;
+                       /* prevent floating point overflow, limit to 1000 sec */
+                       if (ns->d_nstime > 1000000)
+                               ns->d_nstime = 1000000;
+               }
+
+               /*
+                * Record the source so that we do not use this NS again.
+                */
+               if(qp->q_nusedns < NSMAX) {
+                       qp->q_usedns[qp->q_nusedns++] = qs->ns;
+#ifdef DEBUG
+                       if(debug > 1)
+                           fprintf(ddt, "NS #%d addr %s used, rtt %d\n",
+                               n, inet_ntoa(qs->ns_addr.sin_addr),
+                               ns->d_nstime);
+#endif DEBUG
+               }
+
+               /*
+                * Penalize those who had earlier chances but failed
+                * by multiplying round-trip times by BETA (>1).
+                * Improve nstime for unused addresses by applying GAMMA.
+                * The GAMMA factor makes unused entries slowly
+                * improve, so they eventually get tried again.
+                * GAMMA should be slightly less than 1.
+                * Watch out for records that may have timed out
+                * and are no longer the correct type.                  XXX
+                */
+               
+               for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++) {
+                       ns2 = qs->nsdata;
+                       if (ns2 == ns)
+                           continue;
+                       if (ns2->d_type != T_A ||
+                           ns2->d_class != qs->ns->d_class)    /* XXX */
+                               continue;
+                       if (qs->stime.tv_sec) {
+                           if (ns2->d_nstime == 0)
+                               ns2->d_nstime = rtrip * BETA;
+                           else
+                               ns2->d_nstime =
+                                   ns2->d_nstime * BETA + (1-ALPHA) * rtrip;
+                           if (ns2->d_nstime > 1000000)
+                               ns2->d_nstime = 1000000;
+                       } else
+                           ns2->d_nstime = ns2->d_nstime * GAMMA;
+#ifdef DEBUG
+                       if(debug > 1)
+                           fprintf(ddt, "NS #%d %s rtt now %d\n", n,
+                               inet_ntoa(qs->ns_addr.sin_addr),
+                               ns2->d_nstime);
+#endif DEBUG
+               }
+       }
+
+       /*
+        * Skip query section
+        */
+       addcount = 0;
+       cp = msg + sizeof(HEADER);
+       dpp = dnptrs;
+       *dpp++ = msg;
+       if ((*cp & INDIR_MASK) == 0)
+               *dpp++ = cp;
+       *dpp = NULL;
+       if (hp->qdcount) {
+               n = dn_skipname(cp, msg + msglen);
+               if (n <= 0)
+                       goto formerr;
+               cp += n;
+               GETSHORT(type, cp);
+               GETSHORT(class, cp);
+               if (cp - msg > msglen)
+                       goto formerr;
+       }
+
+       /*
+        * Save answers, authority, and additional records for future use.
+        */
+       ancount = ntohs(hp->ancount);
+       aucount = ntohs(hp->nscount);
+       arcount = ntohs(hp->arcount);
+       nscount = 0;
+       tp = cp;
+#ifdef DEBUG
+       if (debug >= 3)
+               fprintf(ddt,"resp: ancount %d, aucount %d, arcount %d\n",
+                       ancount, aucount, arcount);
+#endif
+
+       /*
+        *  If there's an answer, check if it's a CNAME response;
+        *  if no answer but aucount > 0, see if there is an NS
+        *  or just an SOA.  (NOTE: ancount might be 1 with a CNAME,
+        *  and NS records may still be in the authority section;
+        *  we don't bother counting them, as we only use nscount
+        *  if ancount == 0.)
+        */
+       if (ancount == 1 || (ancount == 0 && aucount > 0)) {
+               c = aucount;
+               do {
+                       if (tp - msg >= msglen)
+                               goto formerr;
+                       n = dn_skipname(tp, msg + msglen);
+                       if (n <= 0)
+                               goto formerr;
+                       tp += n;                /* name */
+                       GETSHORT(i, tp);        /* type */
+                       tp += sizeof(u_short);  /* class */
+                       tp += sizeof(u_long);   /* ttl */
+                       GETSHORT(count, tp);    /* dlen */
+                       if (tp - msg > msglen - count)
+                               goto formerr;
+                       tp += count;
+                       if (ancount && i == T_CNAME) {
+                               cname++;
+#ifdef DEBUG
+                               if (debug)
+                                       fprintf(ddt,"CNAME - needs more processing\n");
+#endif
+                               if (!qp->q_cmsglen) {
+                                       qp->q_cmsg = qp->q_msg;
+                                       qp->q_cmsglen = qp->q_msglen;
+                                       qp->q_msg = NULL;
+                                       qp->q_msglen = 0;
+                               }
+                       }
+                       /*
+                        * See if authority record is a nameserver.
+                        */
+                       if (ancount == 0 && i == T_NS)
+                               nscount++;
+               } while (--c > 0);
+               tp = cp;
+       }
+
+       /*
+        * Add the info received in the response to the Data Base
+        */
+       c = ancount + aucount + arcount;
+#ifdef notdef
+       /*
+        * If the request was for a CNAME that doesn't exist,
+        * but the name is valid, fetch any other data for the name.
+        * DON'T do this now, as it will requery if data are already
+        * in the cache (maybe later with negative caching).
+        */
+       if (hp->qdcount && type == T_CNAME && c == 0 && hp->rcode == NOERROR &&
+          !qp->q_system) {
+#ifdef DEBUG
+               if (debug >= 3)
+                       fprintf(ddt,"resp: leaving, no CNAME\n");
+#endif
+               /* Cause us to put it in the cache later */
+               prime(class, T_ANY, qp);
+
+               /* Nothing to store, just give user the answer */
+               goto return_msg;
+       }
+#endif /* notdef */
+
+       nspp = nsp;
+       if (qp->q_system)
+               dbflags = DB_NOTAUTH | DB_NODATA;
+       else
+               dbflags = DB_NOTAUTH | DB_NODATA | DB_NOHINTS;
+       for (i = 0; i < c; i++) {
+               struct databuf *ns3;
+
+               if (cp >= msg + msglen)
+                       goto formerr;
+               ns3 = 0;
+               if ((n = doupdate(msg, msglen, cp, 0, &ns3, dbflags)) < 0) {
+#ifdef DEBUG
+                       if (debug)
+                           fprintf(ddt,"resp: leaving, doupdate failed\n");
+#endif
+                       /* return code filled in by doupdate */
+                       goto return_msg;
+               }
+               /*
+                * Remember nameservers from the authority section
+                * for referrals.
+                * (This is usually overwritten by findns below(?). XXX
+                */
+               if (ns3 && i >= ancount && i < ancount + aucount &&
+                   nspp < &nsp[NSMAX-1])
+                       *nspp++ = ns3;
+               cp += n;
+       }
+
+       if (qp->q_system && ancount) {
+               if (qp->q_system == PRIMING_CACHE)
+                       check_root();
+#ifdef DEBUG
+               if (debug > 2)
+                       fprintf(ddt,"resp: leaving, SYSQUERY ancount %d\n", ancount);
+#endif
+               qremove(qp);
+               return;
+       }
+
+       if (cp > msg + msglen)
+               goto formerr;
+
+       /*
+        *  If there are addresses and this is a local query,
+        *  sort them appropriately for the local context.
+        */
+       if (ancount > 1 && (lp = local(&qp->q_from)) != NULL) 
+               sort_response(tp, ancount, lp, msg + msglen);
+
+       /*
+        * An answer to a T_ANY query or a successful answer to a
+        * regular query with no indirection, then just return answer.
+        */
+       if ((hp->qdcount && type == T_ANY && ancount) ||
+           (!cname && !qp->q_cmsglen && ancount)) {
+#ifdef DEBUG
+               if (debug >= 3)
+                       fprintf(ddt,"resp: got as much answer as there is\n");
+#endif
+               goto return_msg;
+       }
+
+       /*
+        * Eventually we will want to cache this negative answer.
+        */
+       if (ancount == 0 && nscount == 0 &&
+           (hp->aa || fwd || class == C_ANY)) {
+               /* We have an authoritative NO */
+#ifdef DEBUG
+               if (debug >= 3)
+                       fprintf(ddt,"resp: leaving auth NO\n");
+#endif
+               if (qp->q_cmsglen) {
+                       msg = (u_char *)qp->q_cmsg;
+                       msglen = qp->q_cmsglen;
+                       hp = (HEADER *)msg;
+               }
+               goto return_msg;
+       }
+
+       /*
+        * All messages in here need further processing.  i.e. they
+        * are either CNAMEs or we got referred again.
+        */
+       count = 0;
+       founddata = 0;
+       foundname = 0;
+       dname = name;
+       if (!cname && qp->q_cmsglen && ancount) {
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt,"Cname second pass\n");
+#endif
+               newmsglen = qp->q_cmsglen;
+               bcopy(qp->q_cmsg, newmsg, newmsglen);
+       } else {
+               newmsglen = msglen;
+               bcopy(msg, newmsg, newmsglen);
+       }
+       hp = (HEADER *) newmsg;
+       hp->ancount = 0;
+       hp->nscount = 0;
+       hp->arcount = 0;
+       dnptrs[0] = newmsg;
+       dnptrs[1] = NULL;
+       cp = newmsg + sizeof(HEADER);
+       if (cname)
+               cp += dn_skipname(cp, newmsg + newmsglen) + QFIXEDSZ;
+       if ((n = dn_expand(newmsg, newmsg + newmsglen,
+               cp, (u_char *)dname, sizeof(name))) < 0) {
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt,"dn_expand failed\n" );
+#endif
+               goto servfail;
+       }
+       if (!cname)
+               cp += n + QFIXEDSZ;
+       buflen = sizeof(newmsg) - (cp - newmsg);
+
+try_again:
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"resp: nlookup(%s) type=%d\n",dname, type);
+#endif
+       fname = "";
+       htp = hashtab;          /* lookup relative to root */
+       np = nlookup(dname, &htp, &fname, 0);
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"resp: %s '%s' as '%s' (cname=%d)\n",
+                       np == NULL ? "missed" : "found", dname, fname, cname);
+#endif
+       if (np == NULL || fname != dname)
+               goto fetch_ns;
+
+       foundname++;
+       count = cp - newmsg;
+       n = finddata(np, class, type, hp, &dname, &buflen, &count);
+       if (n == 0)
+               goto fetch_ns;          /* NO data available */
+       cp += n;
+       buflen -= n;
+       hp->ancount += count;
+       if (fname != dname && type != T_CNAME && type != T_ANY) {
+               cname++;
+               goto try_again;
+       }
+       founddata = 1;
+
+#ifdef DEBUG
+       if (debug >= 3) {
+           fprintf(ddt,"resp: foundname = %d count = %d ", foundname, count);
+           fprintf(ddt,"founddata = %d cname = %d\n", founddata, cname);
+       }
+#endif
+
+fetch_ns:
+       hp->ancount = htons(hp->ancount);
+       /*
+        * Look for name servers to refer to and fill in the authority
+        * section or record the address for forwarding the query
+        * (recursion desired).
+        */
+       switch (findns(&np, class, nsp, &count)) {
+       case NXDOMAIN:          /* shouldn't happen */
+#ifdef DEBUG
+               if (debug >= 3)
+                       fprintf(ddt,"req: leaving (%s, rcode %d)\n",
+                               dname, hp->rcode);
+#endif
+               if (!foundname)
+                       hp->rcode = NXDOMAIN;
+               if (class != C_ANY) {
+                       hp->aa = 1;
+                       /*
+                        * should return SOA if founddata == 0,
+                        * but old named's are confused by an SOA
+                        * in the auth. section if there's no error.
+                        */
+                       if (foundname == 0 && np) {
+                           n = doaddauth(hp, cp, buflen, np, nsp[0]);
+                           cp += n;
+                           buflen -= n;
+                       }
+               }
+               goto return_newmsg;
+
+       case SERVFAIL:
+               goto servfail;
+       }
+
+       if (founddata) {
+               hp = (HEADER *)newmsg;
+               n = add_data(np, nsp, cp, buflen);
+               if (n < 0) {
+                       hp->tc = 1;
+                       n = (-n);
+               }
+               cp += n;
+               buflen -= n;
+               hp->nscount = htons((u_short)count);
+               goto return_newmsg;
+       }
+
+       /*
+        *  If we get here, we don't have the answer yet and are about
+        *  to iterate to try and get it.  First, infinite loop avoidance.
+        */
+       if (qp->q_nqueries++ > MAXQUERIES) {
+#ifdef DEBUG
+               if (debug)
+                   fprintf(ddt,"resp: MAXQUERIES exceeded (%s, class %d, type %d)\n",
+                       dname, class, type);
+#endif
+               syslog(LOG_NOTICE,
+                           "MAXQUERIES exceeded, possible data loop in resolving (%s)",
+                           dname);
+               goto servfail;
+       }
+
+       /* Reset the query control structure */
+       qp->q_naddr = 0;
+       qp->q_curaddr = 0;
+       qp->q_fwd = fwdtab;
+       if (nslookup(nsp, qp) == 0) {
+#ifdef DEBUG
+               if (debug >= 3)
+                       fprintf(ddt,"resp: no addrs found for NS's\n");
+#endif
+               goto servfail;
+       }
+       for (n = 0; n < qp->q_naddr; n++)
+               qp->q_addr[n].stime.tv_sec = 0;
+       if (!qp->q_fwd)
+               qp->q_addr[0].stime = tt;
+       if (cname) {
+               if (qp->q_cname++ == MAXCNAMES) {
+#ifdef DEBUG
+                       if (debug >= 3)
+                               fprintf(ddt,"resp: leaving, MAXCNAMES exceeded\n");
+#endif
+                       goto servfail;
+               }
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt,"q_cname = %d\n",qp->q_cname);
+               if (debug >= 3)
+                      fprintf(ddt,"resp: building recursive query; nslookup\n");
+#endif
+               if (qp->q_msg)
+                       (void) free(qp->q_msg);
+               if ((qp->q_msg = malloc(BUFSIZ)) == NULL) {
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt,"resp: malloc error\n");
+#endif
+                       goto servfail;
+               }
+               qp->q_msglen = res_mkquery(QUERY, dname, class,
+                   type, (char *)NULL, 0, NULL, qp->q_msg, BUFSIZ);
+               hp = (HEADER *) qp->q_msg;
+               hp->rd = 0;
+       } else
+               hp = (HEADER *)qp->q_msg;
+       hp->id = qp->q_nsid = htons((u_short)++nsid);
+       if (qp->q_fwd)
+               hp->rd = 1;
+       unsched(qp);
+       schedretry(qp, retrytime(qp));
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"resp: forw -> %s %d (%d) nsid=%d id=%d %dms\n",
+                       inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr),
+                       ds, ntohs(Q_NEXTADDR(qp,0)->sin_port),
+                       ntohs(qp->q_nsid), ntohs(qp->q_id),
+                       qp->q_addr[0].nsdata->d_nstime);
+       if ( debug >= 10)
+               fp_query((char *)msg, ddt);
+#endif
+       if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
+               (struct sockaddr *)Q_NEXTADDR(qp,0),
+               sizeof(struct sockaddr_in)) < 0) {
+#ifdef DEBUG
+               if (debug >= 5)
+                       fprintf(ddt, "sendto error = %d\n", errno);
+#endif
+       }
+       hp->rd = 0;     /* leave set to 0 for dup detection */
+#ifdef STATS
+       stats[S_OUTPKTS].cnt++;
+#endif
+#ifdef DEBUG
+       if (debug >= 3)
+               fprintf(ddt,"resp: Query sent.\n");
+#endif
+       return;
+
+formerr:
+#ifdef DEBUG
+       if (debug)
+           fprintf(ddt,"FORMERR resp() from %s size err %d, msglen %d\n",
+               inet_ntoa(from_addr.sin_addr),
+               cp-msg, msglen);
+#endif
+       syslog(LOG_INFO, "Malformed response from %s\n",
+               inet_ntoa(from_addr.sin_addr));
+#ifdef STATS
+       stats[S_RESPFORMERR].cnt++;
+#endif
+       return;
+
+return_msg:
+#ifdef STATS
+       stats[S_RESPOK].cnt++;
+#endif
+       /* The "standard" return code */
+       hp->qr = 1;
+       hp->id = qp->q_id;
+       hp->rd = 1;
+       hp->ra = 1;
+       (void) send_msg(msg, msglen, qp);
+       qremove(qp);
+       return;
+
+return_newmsg:
+#ifdef STATS
+       stats[S_RESPOK].cnt++;
+#endif
+       if (addcount) {
+               n = doaddinfo(hp, cp, buflen);
+               cp += n;
+               buflen -= n;
+       }
+
+       hp->id = qp->q_id;
+       hp->rd = 1;
+       hp->ra = 1;
+       hp->qr = 1;
+       (void) send_msg(newmsg, cp - newmsg, qp);
+       qremove(qp);
+       return;
+
+servfail:
+#ifdef STATS
+       stats[S_RESPFAIL].cnt++;
+#endif
+       hp = (HEADER *)(cname ? qp->q_cmsg : qp->q_msg);
+       hp->rcode = SERVFAIL;
+       hp->id = qp->q_id;
+       hp->rd = 1;
+       hp->ra = 1;
+       hp->qr = 1;
+       (void) send_msg((char *)hp, (cname ? qp->q_cmsglen : qp->q_msglen), qp);
+       qremove(qp);
+       return;
+}
+
+/*
+ * Decode the resource record 'rrp' and update the database.
+ * If savens is true, record pointer for forwarding queries a second time.
+ */
+doupdate(msg, msglen, rrp, zone, savens, flags)
+       char *msg;
+       u_char *rrp;
+       struct databuf **savens;
+       int  msglen, zone, flags;
+{
+       register u_char *cp;
+       register int n;
+       int class, type, dlen, n1;
+       u_long ttl;
+       struct databuf *dp;
+       char dname[MAXDNAME];
+       u_char *cp1;
+       u_char data[BUFSIZ];
+       register HEADER *hp = (HEADER *) msg;
+#ifdef ALLOW_UPDATES
+       int zonenum;
+#endif
+
+#ifdef DEBUG
+       if (debug > 2)
+               fprintf(ddt,"doupdate(zone %d, savens %x, flags %x)\n",
+                       zone, savens, flags);
+#endif
+
+       cp = rrp;
+       if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen, cp,
+           (u_char *)dname, sizeof(dname))) < 0) {
+               hp->rcode = FORMERR;
+               return (-1);
+       }
+       cp += n;
+       GETSHORT(type, cp);
+       GETSHORT(class, cp);
+       GETLONG(ttl, cp);
+       GETSHORT(dlen, cp);
+#ifdef DEBUG
+       if (debug > 2)
+               fprintf(ddt,"doupdate: dname %s type %d class %d ttl %d\n",
+                       dname, type, class, ttl);
+#endif
+       /*
+        * Convert the resource record data into the internal
+        * database format.
+        */
+       switch (type) {
+       case T_A:
+       case T_WKS:
+       case T_HINFO:
+       case T_UINFO:
+       case T_UID:
+       case T_GID:
+       case T_TXT:
+#ifdef ALLOW_T_UNSPEC
+       case T_UNSPEC:
+#endif ALLOW_T_UNSPEC
+               cp1 = cp;
+               n = dlen;
+               cp += n;
+               break;
+
+       case T_CNAME:
+       case T_MB:
+       case T_MG:
+       case T_MR:
+       case T_NS:
+       case T_PTR:
+               if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen,
+                   cp, data, sizeof(data))) < 0) {
+                       hp->rcode = FORMERR;
+                       return (-1);
+               }
+               cp += n;
+               cp1 = data;
+               n = strlen((char *)data) + 1;
+               break;
+
+       case T_MINFO:
+       case T_SOA:
+               if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen,
+                   cp, data, sizeof(data))) < 0) {
+                       hp->rcode = FORMERR;
+                       return (-1);
+               }
+               cp += n;
+               cp1 = data + (n = strlen((char *)data) + 1);
+               n1 = sizeof(data) - n;
+               if (type == T_SOA)
+                       n1 -= 5 * sizeof(u_long);
+               if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen,
+                   cp, cp1, n1)) < 0) {
+                       hp->rcode = FORMERR;
+                       return (-1);
+               }
+               cp += n;
+               cp1 += strlen((char *)cp1) + 1;
+               if (type == T_SOA) {
+                       bcopy(cp, cp1, n = 5 * sizeof(u_long));
+                       cp += n;
+                       cp1 += n;
+               }
+               n = cp1 - data;
+               cp1 = data;
+               break;
+
+       case T_MX:
+               /* grab preference */
+               bcopy(cp,data,sizeof(u_short));
+               cp1 = data + sizeof(u_short);
+               cp += sizeof(u_short);
+
+               /* get name */
+               if ((n = dn_expand((u_char *)msg, (u_char *)msg + msglen,
+                   cp, cp1, sizeof(data) - sizeof(u_short))) < 0)
+                       return(-1);
+               cp += n;
+
+               /* compute end of data */
+               cp1 += strlen((char *)cp1) + 1;
+               /* compute size of data */
+               n = cp1 - data;
+               cp1 = data;
+               break;
+
+       default:
+#ifdef DEBUG
+               if (debug >= 3)
+                       fprintf(ddt,"unknown type %d\n", type);
+#endif
+               return ((cp - rrp) + dlen);
+       }
+       if (n > MAXDATA) {
+#ifdef DEBUG
+               if (debug)
+                   fprintf(ddt,
+                       "update type %d: %d bytes is too much data\n",
+                       type, n);
+#endif
+               hp->rcode = NOCHANGE;   /* XXX - FORMERR ??? */
+               return(-1);
+       }
+
+#ifdef ALLOW_UPDATES
+       /*
+        * If this is a dynamic update request, process it specially; else,
+        * execute normal update code.
+        */
+       switch(hp->opcode) {
+
+       /* For UPDATEM and UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA */
+       case UPDATEM:
+       case UPDATEMA:
+
+       /*
+        * The named code for UPDATED and UPDATEDA is the same except that for
+        * UPDATEDA we we ignore any data that was passed: we just delete all
+        * RRs whose name, type, and class matches
+        */
+       case UPDATED:
+       case UPDATEDA:
+               if (type == T_SOA) {    /* Not allowed */
+#ifdef DEBUG
+                       if (debug)
+                          fprintf(ddt, "UDPATE: REFUSED - SOA delete\n");
+#endif
+                       hp->rcode = REFUSED;
+                       return(-1);
+               }
+               /*
+                * Don't check message length if doing UPDATEM/UPDATEMA,
+                * since the whole message wont have been demarshalled until
+                * we reach the code for UPDATEA
+                */
+               if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEDA) ) {
+                       if (cp != (u_char *)(msg + msglen)) {
+#ifdef DEBUG
+                           if (debug)
+                               fprintf(ddt,"FORMERR UPDATE message length off\n");
+#endif
+                           hp->rcode = FORMERR;
+                           return(-1);
+                       }
+               }
+               if ((zonenum = findzone(dname, class)) == 0) { 
+                       hp->rcode = NXDOMAIN;
+                       return(-1);
+               }
+               if (zones[zonenum].z_state & Z_DYNADDONLY) {
+                       hp->rcode = NXDOMAIN;
+                       return(-1);
+               }
+               if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEM) ) {
+                       /* Make a dp for use in db_update, as old dp */
+                       dp = savedata(class, type, 0, cp1, n);
+                       dp->d_zone = zonenum;
+                       n = db_update(dname, dp, NULL, DB_MEXIST | DB_DELETE,
+                                     hashtab);
+                       if (n != OK) {
+#ifdef DEBUG
+                               if (debug)
+                                   fprintf(ddt,"UPDATE: db_update failed\n");
+#endif DEBUG
+                               free( (struct databuf *) dp);
+                               hp->rcode = NOCHANGE;
+                               return(-1);
+                       }
+               } else {        /* UPDATEDA or UPDATEMA */
+                       int DeletedOne = 0;
+                       /* Make a dp for use in db_update, as old dp */
+                       dp = savedata(class, type, 0, NULL, 0);
+                       dp->d_zone = zonenum;
+                       do {    /* Loop and delete all matching RR(s) */
+                               n = db_update(dname, dp, NULL, DB_DELETE,
+                                             hashtab);
+                               if (n != OK)
+                                       break;
+                               DeletedOne++;
+                       } while (1);
+                       free( (struct databuf *) dp);
+                       /* Ok for UPDATEMA not to have deleted any RRs */
+                       if (!DeletedOne && hp->opcode == UPDATEDA) {
+#ifdef DEBUG
+                               if (debug)
+                                       fprintf(ddt,"UPDATE: db_update failed\n");
+#endif DEBUG
+                               hp->rcode = NOCHANGE;
+                               return(-1);
+                       }
+               }
+               if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEDA) )
+                       return (cp - rrp);;
+               /*
+                * Else unmarshal the RR to be added and continue on to
+                * UPDATEA code for UPDATEM/UPDATEMA
+                */
+               if ((n =
+                  dn_expand(msg, msg+msglen, cp, dname, sizeof(dname))) < 0) {
+#ifdef DEBUG
+                       if (debug)
+                           fprintf(ddt,"FORMERR UPDATE expand name failed\n");
+#endif
+                       hp->rcode = FORMERR;
+                       return(-1);
+               }
+               cp += n;
+               GETSHORT(type, cp);
+               GETSHORT(class, cp);
+               GETLONG(ttl, cp);
+               GETSHORT(n, cp);
+               cp1 = cp;
+/**** XXX - need bounds checking here ****/
+               cp += n;
+
+       case UPDATEA:
+               if (n > MAXDATA) {
+#ifdef DEBUG
+                       if (debug)
+                           fprintf(ddt,"UPDATE: too much data\n");
+#endif
+                       hp->rcode = NOCHANGE;
+                       return(-1);
+               }
+               if (cp != (u_char *)(msg + msglen)) {
+#ifdef DEBUG
+                       if (debug)
+                           fprintf(ddt,"FORMERR UPDATE message length off\n");
+#endif
+                       hp->rcode = FORMERR;
+                       return(-1);
+               }
+               if ((zonenum = findzone(dname, class)) == 0) { 
+                       hp->rcode = NXDOMAIN;
+                       return(-1);
+               }
+               if (zones[zonenum].z_state & Z_DYNADDONLY) {
+                       struct hashbuf *htp = hashtab;
+                       char *fname;
+                       if (nlookup(dname, &htp, &fname, 0) &&
+                           !strcmp(dname, fname)) {
+#ifdef DEBUG
+                           if (debug)
+                               fprintf(ddt,"refusing add of existing name\n");
+#endif
+                           hp->rcode = REFUSED;
+                           return(-1);
+                       }
+               }
+               dp = savedata(class, type, ttl, cp1, n);
+               dp->d_zone = zonenum;
+               if ((n = db_update(dname, NULL, dp, DB_NODATA,
+                                  hashtab)) != OK) {
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt,"UPDATE: db_update failed\n");
+#endif
+                       hp->rcode = NOCHANGE;
+                       return (-1);
+               }
+               else
+                       return (cp - rrp);
+       }
+#endif ALLOW_UPDATES
+
+       if (zone == 0)
+               ttl += tt.tv_sec;
+       dp = savedata(class, type, ttl, cp1, n);
+       dp->d_zone = zone;
+       if ((n = db_update(dname, dp, dp, flags, hashtab)) < 0) {
+#ifdef DEBUG
+               if (debug && (n != DATAEXISTS))
+                       fprintf(ddt,"update failed (%d)\n", n);
+               else if (debug >= 3)
+                       fprintf(ddt,"update failed (DATAEXISTS)\n");
+#endif
+               (void) free((char *)dp);
+       } else if (type == T_NS && savens != NULL)
+               *savens = dp;
+       return (cp - rrp);
+}
+
+send_msg(msg, msglen, qp)
+       char *msg;
+       int msglen;
+       struct qinfo *qp;
+{
+       extern struct qinfo *qhead;
+#ifdef DEBUG
+       struct qinfo *tqp;
+#endif DEBUG
+
+       if (qp->q_system)
+               return(1);
+#ifdef DEBUG
+       if (debug) {
+               fprintf(ddt,"send_msg -> %s (%s %d %d) id=%d\n",
+                       inet_ntoa(qp->q_from.sin_addr), 
+                       qp->q_stream == QSTREAM_NULL ? "UDP" : "TCP",
+                       qp->q_stream == QSTREAM_NULL ? qp->q_dfd
+                                                    : qp->q_stream->s_rfd,
+                       ntohs(qp->q_from.sin_port),
+                       ntohs(qp->q_id));
+       }
+       if (debug>4)
+               for (tqp = qhead; tqp!=QINFO_NULL; tqp = tqp->q_link) {
+                   fprintf(ddt, "qp %x q_id: %d  q_nsid: %d q_msglen: %d ",
+                       tqp, tqp->q_id,tqp->q_nsid,tqp->q_msglen);
+                   fprintf(ddt,"q_naddr: %d q_curaddr: %d\n", tqp->q_naddr,
+                       tqp->q_curaddr);
+                   fprintf(ddt,"q_next: %x q_link: %x\n", qp->q_next,
+                        qp->q_link);
+               }
+       if (debug >= 10)
+               fp_query(msg, ddt);
+#endif DEBUG
+       if (qp->q_stream == QSTREAM_NULL) {
+               if (sendto(qp->q_dfd, msg, msglen, 0,
+                   (struct sockaddr *)&qp->q_from, sizeof(qp->q_from)) < 0) {
+#ifdef DEBUG
+                       if (debug)
+                               fprintf(ddt, "sendto error errno= %d\n",errno);
+#endif
+                       return(1);
+               }
+#ifdef STATS
+               stats[S_OUTPKTS].cnt++;
+#endif
+       } else {
+               (void) writemsg(qp->q_stream->s_rfd, msg, msglen);
+               sq_done(qp->q_stream);
+       }
+       return(0);
+}
+
+prime(class, type, oqp)
+       int class, type;
+       register struct qinfo *oqp;
+{
+       char    dname[BUFSIZ];
+
+       if (oqp->q_msg == NULL)
+               return;
+       if (dn_expand((u_char *)oqp->q_msg,
+           (u_char *)oqp->q_msg + oqp->q_msglen,
+           (u_char *)oqp->q_msg + sizeof(HEADER), (u_char *)dname,
+           sizeof(dname)) < 0)
+               return;
+#ifdef DEBUG
+       if (debug >= 2)
+              fprintf(ddt,"prime: %s\n", dname);
+#endif
+       (void) sysquery(dname, class, type);
+}
+
+
+prime_cache()
+{
+       register struct qinfo *qp;
+
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt,"prime_cache: priming = %d\n", priming);
+#endif
+#ifdef STATS
+       stats[S_PRIMECACHE].cnt++;
+#endif
+       if (!priming && fcachetab->h_tab[0] != NULL && !forward_only) {
+               priming++;
+               if ((qp = sysquery("", C_IN, T_NS)) == NULL)
+                       priming = 0;
+               else
+                       qp->q_system = PRIMING_CACHE;
+       }
+       needs_prime_cache = 0;
+       return;
+}
+
+struct qinfo *
+sysquery(dname, class, type)
+       char *dname;
+       int class, type;
+{
+       extern struct qinfo *qhead;
+       extern int nsid;
+       register struct qinfo *qp, *oqp;
+       register HEADER *hp;
+       struct namebuf *np;
+       struct databuf *nsp[NSMAX];
+       struct hashbuf *htp;
+       char *fname;
+       int count;
+
+#ifdef DEBUG
+       if (debug > 2)
+              fprintf(ddt,"sysquery(%s, %d, %d)\n", dname, class, type);
+#endif
+#ifdef STATS
+       stats[S_SYSQUERIES].cnt++;
+#endif
+       htp = hashtab;
+       if (priming && dname[0] == '\0')
+               np = NULL;
+       else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) {
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt,"sysquery: nlookup error on %s?\n", dname);
+#endif
+               return(0);
+       }
+
+       switch (findns(&np, class, nsp, &count)) {
+       case NXDOMAIN:
+       case SERVFAIL:
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt,"sysquery: findns error on %s?\n", dname);
+#endif
+               return(0);
+       }
+
+       /* build new qinfo struct */
+       qp = qnew();
+       qp->q_cmsg = qp->q_msg = NULL;
+       qp->q_dfd = ds;
+       qp->q_fwd = fwdtab;
+       qp->q_system++;
+
+       if ((qp->q_msg = malloc(BUFSIZ)) == NULL) {
+               qfree(qp);
+               return(0);
+       }
+       qp->q_msglen = res_mkquery(QUERY, dname, class,
+           type, (char *)NULL, 0, NULL, qp->q_msg, BUFSIZ);
+       hp = (HEADER *) qp->q_msg;
+       hp->id = qp->q_nsid = htons((u_short)++nsid);
+       hp->rd = (qp->q_fwd ? 1 : 0);
+
+       /* First check for an already pending query for this data */
+       for (oqp = qhead; oqp!=QINFO_NULL; oqp = oqp->q_link) {
+               if (oqp != qp && oqp->q_msglen == qp->q_msglen &&
+            bcmp((char *)oqp->q_msg+2, qp->q_msg+2, qp->q_msglen-2) == 0) {
+#ifdef DEBUG
+                       if (debug >= 3)
+                               fprintf(ddt, "sysquery: duplicate\n");
+#endif
+                       qfree(qp);
+                       return(0);
+               }
+       }
+
+       if (nslookup(nsp, qp) == 0) {
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt,"resp: no addrs found for NS's\n");
+#endif
+               qfree(qp);
+               return(0);
+       }
+
+       schedretry(qp, retrytime(qp));
+       if (qp->q_fwd == 0)
+               qp->q_addr[0].stime = tt;
+
+#ifdef DEBUG
+       if (debug)
+           fprintf(ddt,"sysquery: send -> %s %d (%d), nsid=%d id=%d %dms\n",
+               inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr),
+               qp->q_dfd, ntohs(Q_NEXTADDR(qp,0)->sin_port),
+               ntohs(qp->q_nsid), ntohs(qp->q_id),
+               qp->q_addr[0].nsdata->d_nstime);
+       if ( debug >= 10)
+           fp_query(qp->q_msg, ddt);
+#endif
+       if (sendto(qp->q_dfd, qp->q_msg, qp->q_msglen, 0,
+           (struct sockaddr *)Q_NEXTADDR(qp,0),
+           sizeof(struct sockaddr_in)) < 0){
+#ifdef DEBUG
+           if (debug)
+               fprintf(ddt, "sendto error errno= %d\n",errno);
+#endif
+       }
+#ifdef STATS
+       stats[S_OUTPKTS].cnt++;
+#endif
+       return(qp);
+}
+
+/*
+ * Check the list of root servers after receiving a response
+ * to a query for the root servers.
+ */
+check_root()
+{
+       register struct databuf *dp, *pdp;
+       register struct namebuf *np;
+       int count = 0;
+
+       priming = 0;
+       for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next)
+               if (np->n_dname[0] == '\0')
+                       break;
+       if (np == NULL) {
+               syslog(LOG_ERR, "check_root: Can't find root!\n");
+               return;
+       }
+       for (dp = np->n_data; dp != NULL; dp = dp->d_next)
+               if (dp->d_type == T_NS)
+                       count++;
+#ifdef DEBUG
+       if (debug)
+           fprintf(ddt,"%d root servers\n", count);
+#endif
+       if (count < MINROOTS) {
+               syslog(LOG_WARNING,
+               "check_root: %d root servers after query to root server < min",
+                   count);
+               return;
+       }
+       pdp = NULL;
+       dp = np->n_data;
+       while (dp != NULL) {
+               if (dp->d_type == T_NS && dp->d_zone == 0 &&
+                   dp->d_ttl < tt.tv_sec) {
+#ifdef DEBUG
+                       if (debug)
+                           fprintf(ddt,"deleting old root server '%s'\n",
+                               dp->d_data);
+#endif
+                       dp = rm_datum(dp, np, pdp);
+                       /* SHOULD DELETE FROM HINTS ALSO */
+                       continue;
+               }
+               pdp = dp;
+               dp = dp->d_next;
+       }
+       check_ns();
+}
+
+/* 
+ * Check the root to make sure that for each NS record we have a A RR
+ */
+check_ns()
+{
+       register struct databuf *dp, *tdp;
+       register struct namebuf *np, *tnp;
+       struct hashbuf *htp;
+       char *dname;
+       int found_arr;
+       char *fname;
+       time_t curtime;
+
+#ifdef DEBUG
+       if (debug >= 2)
+              fprintf(ddt,"check_ns()\n");
+#endif
+#ifdef STATS
+       stats[S_CHECKNS].cnt++;
+#endif
+
+       curtime = (u_long) tt.tv_sec;
+       for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next) {
+               if (np->n_dname[0] != 0)
+                       continue;
+               for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+                       if (dp->d_type != T_NS)
+                           continue;
+
+                       /* look for A records */
+                       dname = dp->d_data;
+                       htp = hashtab;
+                       tnp = nlookup(dname, &htp, &fname, 0);
+                       if (tnp == NULL || fname != dname) {
+#ifdef DEBUG
+                           if (debug >= 3)
+                               fprintf(ddt,"check_ns: %s: not found %s %x\n",
+                                       dname, fname, tnp);
+#endif
+                           (void) sysquery(dname, dp->d_class, T_A);
+                           continue;
+                       }
+                       /* look for name server addresses */
+                       found_arr = 0;
+                       for (tdp=tnp->n_data; tdp!=NULL; tdp=tdp->d_next) {
+                           if (tdp->d_type != T_A ||
+                              tdp->d_class != dp->d_class)
+                               continue;
+                           if ((tdp->d_zone == 0) &&
+                               (tdp->d_ttl < curtime)) {
+#ifdef DEBUG
+                               if (debug >= 3)
+                                   fprintf(ddt,"check_ns: stale entry '%s'\n",
+                                       tnp->n_dname);
+#endif
+                               /* Cache invalidate the address RR's */
+                               delete_all(tnp, dp->d_class, T_A);
+                               found_arr = 0;
+                               break;
+                           }
+                           found_arr++;
+                       }
+                       if (!found_arr)
+                           (void) sysquery(dname, dp->d_class, T_A);
+               }
+       }
+}
+
+#define        MAXCLASS 255            /* belongs elsewhere */
+int    norootlogged[MAXCLASS];
+
+/*
+ *  Find NS's or an SOA for the given dname (np) and fill in the
+ *  nsp array.  Returns OK on success, and SERVFAIL on error.
+ *  We return NXDOMAIN to indicate we are authoritative.
+ */
+findns(npp, class, nsp, countp)
+       register struct namebuf **npp;
+       struct databuf **nsp;
+       int *countp;
+{
+       register struct namebuf *np = *npp;
+       register struct databuf *dp;
+       register struct databuf **nspp;
+       struct hashbuf *htp = hashtab;
+       
+       if (priming && (np == NULL || np->n_dname[0] == '\0'))
+               htp = fcachetab;
+try_again:
+       if (htp == fcachetab)
+               needs_prime_cache = 1;
+       while (np == NULL && htp != NULL) {
+#ifdef DEBUG
+               if (debug > 2)
+                       fprintf(ddt, "findns: using %s\n", htp == hashtab ?
+                               "cache" : "hints");
+#endif
+               for (np = htp->h_tab[0]; np != NULL; np = np->n_next)
+                       if (np->n_dname[0] == '\0')
+                               break;
+               htp = (htp == hashtab ? fcachetab : NULL);      /* Fallback */
+       }
+       while(np != NULL) {
+#ifdef DEBUG
+               if (debug >= 5)
+                       fprintf(ddt, "findns: np 0x%x\n", np);
+#endif
+               /* Look first for SOA records. */
+               for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+                       if (dp->d_zone != 0 && match(dp, class, T_SOA)) {
+#ifdef DEBUG
+                               if (debug >= 3)
+                                       fprintf(ddt,"findns: SOA found\n");
+#endif
+                               if (zones[dp->d_zone].z_auth) {
+                                       *npp = np;
+                                       nsp[0] = dp;
+                                       return(NXDOMAIN);
+                               } else
+                                       return (SERVFAIL);
+                       }
+               }
+
+               /* If no SOA records, look for NS records. */
+               nspp = &nsp[0];
+               *nspp = NULL;
+               for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+                       if (dp->d_type != T_NS ||
+                           (dp->d_class != class && class != C_ANY))
+                               continue;
+                       /*
+                        * Don't use records that may become invalid to
+                        * reference later when we do the rtt computation.
+                        * Never delete our safety-belt information!
+                        */
+                       if ((dp->d_zone == 0) &&
+                           (dp->d_ttl < (tt.tv_sec+900)) &&
+                           !(dp->d_flags & DB_F_HINT)) {
+#ifdef DEBUG
+                               if (debug)
+                                       fprintf(ddt,"findns: stale entry '%s'\n",
+                                                   np->n_dname);
+#endif
+                               /* Cache invalidate the NS RR's */
+                               if (dp->d_ttl < tt.tv_sec)
+                                       delete_all(np, class, T_NS);
+                               goto try_parent;
+                       }
+                       if (nspp < &nsp[NSMAX-1])
+                               *nspp++ = dp;
+               }
+
+               *countp = nspp - nsp;
+               if (*countp > 0) {
+#ifdef DEBUG
+                       if (debug >= 3)
+                               fprintf(ddt,"findns: %d NS's added for '%s'\n",
+                                       *countp, np->n_dname);
+#endif
+                       *nspp = NULL;
+                       *npp = np;
+                       return(OK);     /* Success, got some NS's */
+               }
+try_parent:
+               np = np->n_parent;
+       }
+       if (htp)
+               goto try_again;
+#ifdef DEBUG
+       if (debug)
+               fprintf(ddt, "findns: No root nameservers for class %d?\n",
+                   class);
+#endif
+       if ((unsigned)class < MAXCLASS && norootlogged[class] == 0) {
+               norootlogged[class] = 1;
+               syslog(LOG_ERR, "No root nameservers for class %d\n", class);
+       }
+       return(SERVFAIL);
+}
+
+/*
+ *  Extract RR's from the given node that match class and type.
+ *  Return number of bytes added to response.
+ *  If no matching data is found, then 0 is returned.
+ */
+finddata(np, class, type, hp, dnamep, lenp, countp)
+       struct namebuf *np;
+       int class, type;
+       register HEADER *hp;
+       char **dnamep;
+       int *lenp, *countp;
+{
+       register struct databuf *dp;
+       register char *cp;
+       int buflen, n, count = 0, foundstale = 0;
+
+       buflen = *lenp;
+       cp = ((char *)hp) + *countp;
+       for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+               if (!wanted(dp, class, type)) {
+                       if (type == T_CNAME && class == dp->d_class) {
+                               /* any data means no CNAME exists */
+                               *countp = 0;
+                               return(0);
+                       }
+                       continue;
+               }
+               if (stale(dp)) {
+                       /*
+                        * Don't use stale data.
+                        * Would like to call delete_all here
+                        * and continue, but the data chain would get
+                        * munged; can't restart, as make_rr has side
+                        * effects (leaving pointers in dnptr).
+                        * Just skip this entry for now
+                        * and call delete_all at the end.
+                        */
+#ifdef DEBUG
+                       if (debug >=3)
+                          fprintf(ddt,"finddata: stale entry '%s'\n",np->n_dname);
+#endif
+                       if (dp->d_zone == 0)
+                               foundstale++;
+                       continue;
+               }
+               if ((n = make_rr(*dnamep, dp, cp, buflen, 1)) < 0) {
+                       hp->tc = 1;
+                       *countp = count;
+                       return(*lenp - buflen);
+               }
+
+               cp += n;
+               buflen -= n;
+               count++;
+#ifdef notdef
+               /* this isn't right for glue records, aa is set in ns_req */
+               if (dp->d_zone && zones[dp->d_zone].z_auth && class != C_ANY)
+                       hp->aa = 1;                     /* XXX */
+#endif
+               if (dp->d_type == T_CNAME) {
+                       if (type != T_ANY) {    /* or T_NS? */
+                               *dnamep = dp->d_data;
+                               if (dp->d_zone && zones[dp->d_zone].z_auth &&
+                                   class != C_ANY)             /* XXX */
+                                       hp->aa = 1;             /* XXX */
+                       }
+                       break;
+               }
+       }
+       /*
+        * Cache invalidate the other RR's of same type
+        * if some have timed out
+        */
+       if (foundstale)
+               delete_all(np, class, type);
+#ifdef DEBUG
+       if (debug >=3)
+               fprintf(ddt,"finddata: added %d class %d type %d RRs\n",
+                       count, class, type);
+#endif
+       *countp = count;
+       return(*lenp - buflen);
+}
+
+/*
+ * Do we want this data record based on the class and type?
+ */
+wanted(dp, class, type)
+       struct databuf *dp;
+       int class, type;
+{
+
+#ifdef DEBUG
+       if (debug > 3)
+               fprintf(ddt,"wanted(%x, %d, %d) %d, %d\n", dp, class, type,
+                       dp->d_class, dp->d_type);
+#endif
+
+       if (dp->d_class != class && class != C_ANY)
+               return (0);
+       if (type == dp->d_type)
+               return (1);
+       switch (dp->d_type) {
+       case T_ANY:
+       case T_CNAME:
+               return (1);
+       }
+       switch (type) {
+       case T_ANY:
+               return (1);
+
+       case T_MAILB:
+               switch (dp->d_type) {
+               case T_MR:
+               case T_MB:
+               case T_MG:
+               case T_MINFO:
+                       return (1);
+               }
+               break;
+
+       case T_AXFR:
+               if (dp->d_type == T_SOA)
+                       return (1);
+       }
+       return (0);
+}
+
+/*
+ *  Add RR entries from dpp array to a query/response.
+ *  Return the number of bytes added or negative the amount
+ *  added if truncation was required.  Typically you are
+ *  adding NS records to a response.
+ */
+add_data(np, dpp, cp, buflen)
+       struct namebuf *np;
+       struct databuf **dpp;
+       register char *cp;
+       int buflen;
+{
+       register struct databuf *dp;
+       char dname[MAXDNAME];
+       register int n, count = 0;
+
+       getname(np, dname, sizeof(dname));
+       for(dp = *dpp++; dp != NULL; dp = *dpp++) {
+               if (stale(dp))
+                       continue;       /* ignore old cache entry */
+               if ((n = make_rr(dname, dp, cp, buflen, 1)) < 0)
+                       return(-count);         /* Truncation */
+               cp += n;
+               buflen -= n;
+               count += n;
+       }
+       return(count);
+}
+
+/*
+ *  This is best thought of as a "cache invalidate" function.
+ *  It is called whenever a piece of data is determined to have
+ *  timed out.  It is better to have no information, than to
+ *  have partial information you pass off as complete.
+ */
+delete_all(np, class, type)
+register struct namebuf *np;
+int class, type;
+{
+       register struct databuf *dp, *pdp;
+
+#ifdef DEBUG
+       if (debug > 2)
+               fprintf(ddt,"delete_all: '%s' 0x%x class %d type %d\n",
+                           np->n_dname, np, class, type);
+#endif
+       pdp = NULL;
+       dp = np->n_data;
+       while (dp != NULL) {
+               if ((dp->d_zone == 0) && !(dp->d_flags & DB_F_HINT)
+                   && match(dp, class, type)) {
+                       dp = rm_datum(dp, np, pdp);
+                       continue;
+               }
+               pdp = dp;
+               dp = dp->d_next;
+       }
+}
diff --git a/usr/src/usr.sbin/named/ns_sort.c b/usr/src/usr.sbin/named/ns_sort.c
new file mode 100644 (file)
index 0000000..9956476
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 1986, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ns_sort.c  4.10 (Berkeley) 3/3/91";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <syslog.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ns.h"
+#include "db.h"
+
+extern int     debug;
+extern  FILE   *ddt;
+
+struct netinfo* 
+local(from)
+       struct sockaddr_in *from;
+{
+       extern struct netinfo *nettab, netloop, **enettab;
+       struct netinfo *ntp;
+
+       if (from->sin_addr.s_addr == netloop.my_addr.s_addr)
+               return( &netloop);
+       for (ntp = nettab; ntp != *enettab; ntp = ntp->next) {
+               if (ntp->net == (from->sin_addr.s_addr & ntp->mask))
+                       return(ntp);
+       }
+       return(NULL);
+}
+
+
+sort_response(cp, ancount, lp, eom)
+       register char *cp;
+       register int ancount;
+       struct netinfo *lp;
+       u_char *eom;
+{
+       register struct netinfo *ntp;
+       extern struct netinfo *nettab;
+
+#ifdef DEBUG
+       if (debug > 2)
+           fprintf(ddt,"sort_response(%d)\n", ancount);
+#endif DEBUG
+       if (ancount > 1) {
+               if (sort_rr(cp, ancount, lp, eom))
+                       return;
+               for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+                       if ((ntp->net == lp->net) && (ntp->mask == lp->mask))
+                               continue;
+                       if (sort_rr(cp, ancount, ntp, eom))
+                               break;
+               }
+       }
+}
+
+int
+sort_rr(cp, count, ntp, eom)
+       register u_char *cp;
+       int count;
+       register struct netinfo *ntp;
+       u_char *eom;
+{
+       int type, class, dlen, n, c;
+       struct in_addr inaddr;
+       u_char *rr1;
+
+#ifdef DEBUG
+       if (debug > 2) {
+           inaddr.s_addr = ntp->net;
+           fprintf(ddt,"sort_rr( x%x, %d, %s)\n",cp, count,
+               inet_ntoa(inaddr));
+       }
+#endif DEBUG
+       rr1 = NULL;
+       for (c = count; c > 0; --c) {
+           n = dn_skipname(cp, eom);
+           if (n < 0)
+               return (1);             /* bogus, stop processing */
+           cp += n;
+           if (cp + QFIXEDSZ > eom)
+               return (1);
+           GETSHORT(type, cp);
+           GETSHORT(class, cp);
+           cp += sizeof(u_long);
+           GETSHORT(dlen, cp);
+           if (dlen > eom - cp)
+               return (1);             /* bogus, stop processing */
+           switch (type) {
+           case T_A:
+               switch (class) {
+               case C_IN:
+               case C_HS:
+                       bcopy(cp, (char *)&inaddr, sizeof(inaddr));
+                       if (rr1 == NULL)
+                               rr1 = cp;
+                       if ((ntp->mask & inaddr.s_addr) == ntp->net) {
+#ifdef DEBUG
+                           if (debug > 1) {
+                               fprintf(ddt,"net %s best choice\n",
+                                       inet_ntoa(inaddr));
+                           }
+#endif DEBUG
+                           if (rr1 != cp) {
+                               bcopy(rr1, cp, sizeof(inaddr));
+                               bcopy((char *)&inaddr, rr1, sizeof(inaddr));
+                           }
+                           return(1);
+                       }
+                       break;
+               }
+               break;
+           }
+           cp += dlen;
+       }
+       return(0);
+}
diff --git a/usr/src/usr.sbin/named/ns_stats.c b/usr/src/usr.sbin/named/ns_stats.c
new file mode 100644 (file)
index 0000000..418d9aa
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ns_stats.c 4.10 (Berkeley) 6/27/90";
+#endif /* not lint */
+
+/**************************************************************************/
+/*                simple monitoring of named behavior                     */
+/*            dumps a bunch of values into a well-know file               */
+/*                                                                        */
+/**************************************************************************/
+
+#ifdef STATS
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <arpa/nameser.h>
+#include "ns.h"
+#include "pathnames.h"
+
+#ifdef STATSFILE
+char *statsfile = STATSFILE;
+#else
+char *statsfile = _PATH_STATS;
+#endif /* STATSFILE */
+
+extern time_t  boottime, resettime;
+extern int     needStatsDump;
+
+/*
+ * General statistics gathered
+ */
+/* The position in this table must agree with the defines in ns.h */
+struct stats stats[S_NSTATS] = {
+       { 0, "input packets" },
+       { 0, "output packets" },
+       { 0, "queries" },
+       { 0, "iqueries" },
+       { 0, "duplicate queries" },
+       { 0, "responses" },
+       { 0, "duplicate responses" },
+       { 0, "OK answers" },
+       { 0, "FAIL answers" },
+       { 0, "FORMERR answers" },
+       { 0, "system queries" },
+       { 0, "prime cache calls" },
+       { 0, "check_ns calls" },
+       { 0, "bad responses dropped" },
+       { 0, "martian responses" },
+};
+
+/*
+ *  Statistics for queries (by type)
+ */
+unsigned long typestats[T_ANY+1];
+char *typenames[T_ANY+1] = {
+       /* 5 types per line */
+       "Unknown", "A", "NS", "invalid(MD)", "invalid(MF)",
+       "CNAME", "SOA", "MB", "MG", "MR",
+       "NULL", "WKS", "PTR", "HINFO", "MINFO",
+       "MX", "TXT", 0, 0, 0,
+       /* 20 per line */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 100 */
+       "UINFO", "UID", "GID", "UNSPEC", 0, 0, 0, 0, 0, 0,
+       /* 110 */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 120 */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 200 */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 240 */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 250 */
+       0, 0, "AXFR", "MAILB", "MAILA", "ANY" 
+};
+
+ns_stats()
+{
+       time_t timenow;
+       register FILE *f;
+       register int i;
+
+       if ((f = fopen(statsfile,"a")) == 0)
+       {
+#ifdef DEBUG
+               if (debug)
+                       fprintf(ddt,"can't open stat file, \"%s\"\n",statsfile);
+#endif
+               syslog(LOG_ERR, "cannot open stat file, \"%s\"\n",statsfile);
+               return;
+       }
+
+       time(&timenow);
+       fprintf(f, "###  %s", ctime(&timenow));
+       fprintf(f, "%d\ttime since boot (secs)\n", timenow - boottime);
+       fprintf(f, "%d\ttime since reset (secs)\n", timenow - resettime);
+
+       /* general statistics */
+       for (i = 0; i < S_NSTATS; i++)
+               fprintf(f,"%lu\t%s\n", stats[i].cnt, stats[i].description);
+
+       /* query type statistics */
+       fprintf(f, "%d\tUnknown query types\n", typestats[0]);
+       for(i=1; i < T_ANY+1; i++)
+               if (typestats[i])
+                       if (typenames[i])
+                               fprintf(f, "%lu\t%s queries\n", typestats[i],
+                                       typenames[i]);
+                       else
+                               fprintf(f, "%lu\ttype %d queries\n",
+                                       typestats[i], i);
+       (void) fclose(f);
+}
+#endif STATS
diff --git a/usr/src/usr.sbin/named/pathnames.h b/usr/src/usr.sbin/named/pathnames.h
new file mode 100644 (file)
index 0000000..88718ba
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)pathnames.h 5.4 (Berkeley) 6/1/90
+ */
+
+
+#define        _PATH_BOOT      "/etc/named.boot"
+
+#if defined(BSD) && BSD >= 198810
+#include <paths.h>
+#define        _PATH_XFER      "/usr/libexec/named-xfer"
+#define        _PATH_DEBUG     "/var/tmp/named.run"
+#define        _PATH_DUMPFILE  "/var/tmp/named_dump.db"
+#define        _PATH_PIDFILE   "/var/run/named.pid"
+#define        _PATH_STATS     "/var/tmp/named.stats"
+#define        _PATH_TMPXFER   "/var/tmp/xfer.ddt.XXXXXX"
+#define        _PATH_TMPDIR    "/var/tmp"
+
+#else /* BSD */
+#define        _PATH_DEVNULL   "/dev/null"
+#define        _PATH_TTY       "/dev/tty"
+#define        _PATH_XFER      "/etc/named-xfer"
+#define        _PATH_DEBUG     "/usr/tmp/named.run"
+#define        _PATH_DUMPFILE  "/usr/tmp/named_dump.db"
+#define        _PATH_PIDFILE   "/etc/named.pid"
+#define        _PATH_STATS     "/usr/tmp/named.stats"
+#define        _PATH_TMPXFER   "/usr/tmp/xfer.ddt.XXXXXX"
+#define        _PATH_TMPDIR    "/usr/tmp"
+#endif /* BSD */