summaryrefslogtreecommitdiffstats
path: root/usr.sbin/named
diff options
context:
space:
mode:
authorpst <pst@FreeBSD.org>1994-09-22 19:46:15 +0000
committerpst <pst@FreeBSD.org>1994-09-22 19:46:15 +0000
commit3866fef02d12ce18b3b81e010ac2af997ce350a8 (patch)
tree34c210f7b31ea37b062599209869c309ddfca8ee /usr.sbin/named
parent8b1c40bc18615379af063dfafe0085ffa594da60 (diff)
downloadFreeBSD-src-3866fef02d12ce18b3b81e010ac2af997ce350a8.zip
FreeBSD-src-3866fef02d12ce18b3b81e010ac2af997ce350a8.tar.gz
NAMED from BIND 4.9.3 BETA9 pl1 (no local changes)
Diffstat (limited to 'usr.sbin/named')
-rw-r--r--usr.sbin/named/Version.c88
-rw-r--r--usr.sbin/named/db_defs.h172
-rw-r--r--usr.sbin/named/db_dump.c892
-rw-r--r--usr.sbin/named/db_func.h102
-rw-r--r--usr.sbin/named/db_glob.h93
-rw-r--r--usr.sbin/named/db_glue.c710
-rw-r--r--usr.sbin/named/db_load.c1214
-rw-r--r--usr.sbin/named/db_lookup.c196
-rw-r--r--usr.sbin/named/db_reload.c125
-rw-r--r--usr.sbin/named/db_save.c214
-rw-r--r--usr.sbin/named/db_secure.c170
-rw-r--r--usr.sbin/named/db_update.c638
-rw-r--r--usr.sbin/named/dmalloc.c312
-rw-r--r--usr.sbin/named/dmalloc.h68
-rw-r--r--usr.sbin/named/named.h19
-rw-r--r--usr.sbin/named/ns_defs.h368
-rw-r--r--usr.sbin/named/ns_forw.c909
-rw-r--r--usr.sbin/named/ns_func.h140
-rw-r--r--usr.sbin/named/ns_glob.h245
-rw-r--r--usr.sbin/named/ns_init.c808
-rw-r--r--usr.sbin/named/ns_main.c1581
-rw-r--r--usr.sbin/named/ns_maint.c784
-rw-r--r--usr.sbin/named/ns_ncache.c152
-rw-r--r--usr.sbin/named/ns_req.c1793
-rw-r--r--usr.sbin/named/ns_resp.c2190
-rw-r--r--usr.sbin/named/ns_sort.c169
-rw-r--r--usr.sbin/named/ns_stats.c325
-rw-r--r--usr.sbin/named/ns_validate.c1161
-rw-r--r--usr.sbin/named/pathnames.h122
-rw-r--r--usr.sbin/named/storage.c207
-rw-r--r--usr.sbin/named/tools/named.reload/named.reload.sh6
-rw-r--r--usr.sbin/named/tools/named.restart/named.restart.sh12
-rw-r--r--usr.sbin/named/tools/nsquery/nsquery.c140
-rw-r--r--usr.sbin/named/tools/nstest/nstest.c424
-rw-r--r--usr.sbin/named/tree.c570
-rw-r--r--usr.sbin/named/tree.h48
-rw-r--r--usr.sbin/named/tree.man3154
-rw-r--r--usr.sbin/named/xfer/named-xfer.c1481
38 files changed, 18802 insertions, 0 deletions
diff --git a/usr.sbin/named/Version.c b/usr.sbin/named/Version.c
new file mode 100644
index 0000000..7cbce28
--- /dev/null
+++ b/usr.sbin/named/Version.c
@@ -0,0 +1,88 @@
+/*
+ * @(#)Version.c 4.9 (Berkeley) 7/21/90
+ * $Id: Version.c,v 4.9.1.3 1994/06/01 21:09:39 vixie Exp $
+ */
+
+#ifndef lint
+char sccsid[] = "@(#)named %VERSION% %WHEN% %WHOANDWHERE%";
+char rcsid[] = "$Id: Version.c,v 4.9.1.3 1994/06/01 21:09:39 vixie Exp $";
+#endif /* not lint */
+
+char Version[] = "named %VERSION% %WHEN%\n\t%WHOANDWHERE%";
+
+#ifdef COMMENT
+
+SCCS/s.Version.c:
+
+D 4.8.3 90/06/27 17:05:21 bloom 37 35 00031/00028/00079
+Version distributed with 4.3 Reno tape (June 1990)
+
+D 4.8.2 89/09/18 13:57:11 bloom 35 34 00020/00014/00087
+Interim fixes release
+
+D 4.8.1 89/02/08 17:12:15 karels 34 33 00026/00017/00075
+branch for 4.8.1
+
+D 4.8 88/07/09 14:27:00 karels 33 28 00043/00031/00049
+4.8 is here!
+
+D 4.7 87/11/20 13:15:52 karels 25 24 00000/00000/00062
+4.7.3 beta
+
+D 4.6 87/07/21 12:15:52 karels 25 24 00000/00000/00062
+4.6 declared stillborn
+
+D 4.5 87/02/10 12:33:25 kjd 24 18 00000/00000/00062
+February 1987, Network Release. Child (bind) grows up, parent (kevin) leaves home.
+
+D 4.4 86/10/01 10:06:26 kjd 18 12 00020/00017/00042
+October 1, 1986 Network Distribution
+
+D 4.3 86/06/04 12:12:18 kjd 12 7 00015/00028/00044
+Version distributed with 4.3BSD
+
+D 4.2 86/04/30 20:57:16 kjd 7 1 00056/00000/00016
+Network distribution Freeze and one more version until 4.3BSD
+
+D 1.1 86/04/30 19:30:00 kjd 1 0 00016/00000/00000
+date and time created 86/04/30 19:30:00 by kjd
+
+code versions:
+
+Makefile
+ Makefile 4.14 (Berkeley) 2/28/88
+db.h
+ db.h 4.13 (Berkeley) 2/17/88
+db_dump.c
+ db_dump.c 4.20 (Berkeley) 2/17/88
+db_load.c
+ db_load.c 4.26 (Berkeley) 2/28/88
+db_lookup.c
+ db_lookup.c 4.14 (Berkeley) 2/17/88
+db_reload.c
+ db_reload.c 4.15 (Berkeley) 2/28/88
+db_save.c
+ db_save.c 4.13 (Berkeley) 2/17/88
+db_update.c
+ db_update.c 4.16 (Berkeley) 2/28/88
+ns_forw.c
+ ns_forw.c 4.26 (Berkeley) 3/28/88
+ns_init.c
+ ns_init.c 4.23 (Berkeley) 2/28/88
+ns_main.c
+ Copyright (c) 1986 Regents of the University of California.\n\
+ ns_main.c 4.30 (Berkeley) 3/7/88
+ns_maint.c
+ ns_maint.c 4.23 (Berkeley) 2/28/88
+ns_req.c
+ ns_req.c 4.32 (Berkeley) 3/31/88
+ns_resp.c
+ ns_resp.c 4.50 (Berkeley) 4/7/88
+ns_sort.c
+ ns_sort.c 4.3 (Berkeley) 2/17/88
+ns_stats.c
+ ns_stats.c 4.3 (Berkeley) 2/17/88
+newvers.sh
+ newvers.sh 4.4 (Berkeley) 3/28/88
+
+#endif /* COMMENT */
diff --git a/usr.sbin/named/db_defs.h b/usr.sbin/named/db_defs.h
new file mode 100644
index 0000000..db9b32c
--- /dev/null
+++ b/usr.sbin/named/db_defs.h
@@ -0,0 +1,172 @@
+/*
+ * from db.h 4.16 (Berkeley) 6/1/90
+ * $Id: db_defs.h,v 1.11 1994/07/22 08:42:39 vixie Exp $
+ */
+
+/*
+ * ++Copyright++ 1985, 1990
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+/*
+ * Global definitions 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
+
+#define DB_ROOT_TIMBUF 3600
+#define TIMBUF 300
+
+/*
+ * Hash table structures.
+ */
+struct databuf {
+ struct databuf *d_next; /* linked list */
+ u_int32_t d_ttl; /* time to live */
+ /* if d_zone == DB_Z_CACHE, then
+ * d_ttl is actually the time when
+ * the record will expire.
+ * otherwise (for authoritative
+ * primary and secondary zones),
+ * d_ttl is the time to live.
+ */
+ unsigned d_flags :7; /* see below */
+ unsigned d_cred :3; /* DB_C_{??????} */
+ unsigned d_clev :6;
+ int16_t d_zone; /* zone number or 0 for the cache */
+ int16_t d_class; /* class number */
+ int16_t d_type; /* type number */
+ int16_t d_mark; /* place to mark data */
+ int16_t d_size; /* size of data area */
+#ifdef NCACHE
+ int16_t d_rcode; /* rcode added for negative caching */
+#endif
+ int16_t d_rcnt;
+#ifdef STATS
+ struct nameser *d_ns; /* NS from whence this came */
+#endif
+/*XXX*/ u_int32_t d_nstime; /* NS response time, milliseconds */
+ u_char d_data[sizeof(char*)]; /* malloc'd (padded) */
+};
+#define DATASIZE(n) (sizeof(struct databuf) - sizeof(char*) + n)
+
+/*
+ * d_flags definitions
+ */
+#define DB_F_HINT 0x01 /* databuf belongs to fcachetab */
+
+/*
+ * d_cred definitions
+ */
+#define DB_C_ZONE 4 /* authoritative zone - best */
+#define DB_C_AUTH 3 /* authoritative answer */
+#define DB_C_ANSWER 2 /* non-authoritative answer */
+#define DB_C_ADDITIONAL 1 /* additional data */
+#define DB_C_CACHE 0 /* cache - worst */
+
+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 */
+};
+
+#ifdef INVQ
+struct invbuf {
+ struct invbuf *i_next; /* linked list */
+ struct namebuf *i_dname[INVBLKSZ]; /* domain name */
+};
+#endif
+
+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
diff --git a/usr.sbin/named/db_dump.c b/usr.sbin/named/db_dump.c
new file mode 100644
index 0000000..4a0d2c9
--- /dev/null
+++ b/usr.sbin/named/db_dump.c
@@ -0,0 +1,892 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_dump.c 4.33 (Berkeley) 3/3/91";
+static char rcsid[] = "$Id: db_dump.c,v 4.9.1.12 1994/07/22 08:42:39 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988, 1990
+ * -
+ * Copyright (c) 1986, 1988, 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <resolv.h>
+#include <errno.h>
+
+#include "named.h"
+
+static int scan_root __P((struct hashbuf *));
+static const char *MkCredStr __P((int));
+
+#ifdef ALLOW_T_UNSPEC
+static void putbyte __P((int, char **));
+#endif
+
+/*
+ * 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.
+ */
+
+void
+doachkpt()
+{
+ FILE *fp;
+ char tmpcheckfile[256];
+
+ /* nowhere to checkpoint cache... */
+ if (cache_file == NULL) {
+ dprintf(3, (ddt, "skipping doachkpt (cache_file == NULL)\n"));
+ return;
+ }
+
+ dprintf(3, (ddt, "doachkpt()\n"));
+
+ (void) sprintf(tmpcheckfile, "%s.chk", cache_file);
+ if ((fp = fopen(tmpcheckfile, "w")) == NULL) {
+ dprintf(3, (ddt,
+ "doachkpt(can't open %s for write)\n", tmpcheckfile));
+ return;
+ }
+
+ (void) gettime(&tt);
+ fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec));
+ fflush(fp);
+ if (ferror(fp)) {
+ dprintf(3, (ddt, "doachkpt(write to checkpoint file failed)\n"));
+ return;
+ }
+
+ if (fcachetab != NULL) {
+ int n = scan_root(hashtab);
+
+ if (n < 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) {
+ dprintf(3, (ddt, "doachkpt(checkpoint failed)\n"));
+ (void) my_fclose(fp);
+ return;
+ }
+ }
+
+ (void) fsync(fileno(fp));
+ if (my_fclose(fp) == EOF) {
+ return;
+ }
+
+ if (rename(tmpcheckfile, cache_file)) {
+ dprintf(3, (ddt, "doachkpt(install %s to %s failed, %d)\n",
+ tmpcheckfile, cache_file, errno));
+ }
+}
+
+/*
+ * 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).
+ */
+
+static int
+scan_root(htp)
+ struct hashbuf *htp;
+{
+ register struct databuf *dp;
+ register struct namebuf *np;
+ struct timeval soon;
+ int roots = 0;
+
+ dprintf(1, (ddt, "scan_root(0x%x)\n", htp));
+
+ /* 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;
+
+ dprintf(1, (ddt, "mark_cache()\n"));
+
+ (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.
+ */
+
+void
+doadump()
+{
+ FILE *fp;
+
+ dprintf(3, (ddt, "doadump()\n"));
+
+ if ((fp = fopen(dumpfile, "w")) == NULL)
+ return;
+ gettime(&tt);
+ fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec));
+ if (zones && nzones)
+ zt_dump(fp);
+ fputs(
+"; Note: Cr=(auth,answer,addtnl,cache) tag only shown for non-auth RR's\n",
+ fp);
+ fputs(
+"; Note: NT=milliseconds for any A RR which we've used as a nameserver\n",
+ fp);
+ 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) my_fclose(fp);
+}
+
+#ifdef ALLOW_UPDATES
+/* Create a disk database to back up zones
+ */
+void
+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)) {
+ dprintf(1, (ddt, "zonedump(%s)\n", zp->z_source));
+
+ if ((fp = fopen(zp->z_source, "w")) == NULL)
+ return;
+ if (op = strchr(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));
+ zp->z_flags &= ~Z_CHANGED; /* Checkpointed */
+ }
+ (void) my_fclose(fp);
+ if (stat(zp->z_source, &st) == 0)
+ zp->z_ftime = st.st_mtime;
+ } else {
+ dprintf(1, (ddt, "zonedump: no zone to dump\n"));
+ }
+}
+#endif
+
+int
+zt_dump(fp)
+ FILE *fp;
+{
+ register struct zoneinfo *zp;
+
+ fprintf(fp, ";; ++zone table++\n");
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++) {
+ char *pre, buf[64];
+ u_int cnt;
+
+ fprintf(fp, "; %s (type %d, class %d, source %s)\n",
+ zp->z_origin, zp->z_type, zp->z_class,
+ zp->z_source ? zp->z_source : "Nil");
+ fprintf(fp, ";\ttime=%ld, lastupdate=%ld, serial=%u,\n",
+ zp->z_time, zp->z_lastupdate, zp->z_serial);
+ fprintf(fp, ";\trefresh=%u, retry=%u, expire=%u, minimum=%u\n",
+ zp->z_refresh, zp->z_retry,
+ zp->z_expire, zp->z_minimum);
+ fprintf(fp, ";\tftime=%ld, xaddr=[%s], state=%04x, pid=%d\n",
+ zp->z_ftime, inet_ntoa(zp->z_xaddr),
+ zp->z_flags, zp->z_xferpid);
+ sprintf(buf, ";\tz_addr[%d]: ", zp->z_addrcnt);
+ pre = buf;
+ for (cnt = 0; cnt < zp->z_addrcnt; cnt++) {
+ fprintf(fp, "%s[%s]", pre, inet_ntoa(zp->z_addr[cnt]));
+ pre = ", ";
+ }
+ if (zp->z_addrcnt)
+ fputc('\n', fp);
+ }
+ fprintf(fp, ";; --zone table--\n");
+}
+
+int
+db_dump(htp, fp, zone, origin)
+ struct hashbuf *htp;
+ FILE *fp;
+ int zone;
+ char *origin;
+{
+ register struct databuf *dp = NULL;
+ register struct namebuf *np;
+ struct namebuf **npp, **nppend;
+ char dname[MAXDNAME];
+ u_int32_t n;
+ u_int32_t addr;
+ int j, i;
+ register u_char *cp;
+ u_char *end;
+ char *proto, *sep;
+ int found_data = 0, 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;
+#ifdef NCACHE
+ if (dp->d_rcode == NXDOMAIN ||
+ dp->d_rcode == NOERROR_NODATA) {
+ fputc(';', fp);
+ } else if (found_data == 0 || found_data == 1) {
+ found_data = 2;
+ }
+#endif /*NCACHE*/
+ if (found_data == 0 || found_data == 2) {
+ 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
+ && (int32_t)(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;
+ sep = "\t;";
+#ifdef NCACHE
+#ifdef RETURNSOA
+ if (dp->d_rcode == NOERROR_NODATA) {
+ fprintf(fp, "NODATA%s-$", sep);
+ goto eoln;
+ }
+#else
+ if (dp->d_rcode == NXDOMAIN ||
+ dp->d_rcode == NOERROR_NODATA) {
+ fprintf(fp, "%s%s-$",
+ (dp->d_rcode == NXDOMAIN)
+ ?"NXDOMAIN" :"NODATA",
+ sep);
+ goto eoln;
+ }
+#endif
+#endif
+ /*
+ * 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, "%sNT=%d",
+ sep, dp->d_nstime);
+ sep = " ";
+ }
+ break;
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ fprintf(fp, "%s.", cp);
+ break;
+
+ case T_NS:
+ cp = (u_char *)dp->d_data;
+ if (cp[0] == '\0')
+ fprintf(fp, ".\t");
+ else
+ fprintf(fp, "%s.", cp);
+ break;
+
+ case T_HINFO:
+ case T_ISDN:
+ 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, " \"\"");
+ break;
+
+ case T_SOA:
+ fprintf(fp, "%s.", cp);
+ cp += strlen((char *)cp) + 1;
+ fprintf(fp, " %s. (\n", cp);
+#if defined(RETURNSOA) && defined(NCACHE)
+ if (dp->d_rcode == NXDOMAIN)
+ fputs(";", fp);
+#endif
+ 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);
+#if defined(RETURNSOA) && defined(NCACHE)
+ if (dp->d_rcode == NXDOMAIN) {
+ fprintf(fp,";%s.;NXDOMAIN%s-$",cp,sep);
+ }
+#endif
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ GETSHORT(n, cp);
+ fprintf(fp,"%lu", n);
+ fprintf(fp," %s.", cp);
+ break;
+
+ case T_TXT:
+ case T_X25:
+ 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("\"", fp);
+ break;
+
+ case T_NSAP:
+ (void) fputs(inet_nsap_ntoa(dp->d_size,
+ dp->d_data, NULL),
+ fp);
+ break;
+
+ case T_UINFO:
+ fprintf(fp, "\"%s\"", cp);
+ break;
+
+ case T_UID:
+ case T_GID:
+ if (dp->d_size == INT32SZ) {
+ GETLONG(n, cp);
+ } else {
+ n = -2; /* XXX - hack */
+ }
+ fprintf(fp, "%u", 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);
+ }
+ break;
+
+ case T_MINFO:
+ case T_RP:
+ fprintf(fp, "%s.", cp);
+ cp += strlen((char *)cp) + 1;
+ fprintf(fp, " %s.", 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) {
+ dprintf(1,
+ (ddt,
+ "Dump T_UNSPEC: bad malloc\n"
+ )
+ );
+ syslog(LOG_ERR,
+ "Dump T_UNSPEC: malloc: %m");
+ TmpBuf = "BAD_MALLOC";
+ }
+ if (btoa(cp, dp->d_size, TmpBuf, TmpSize)
+ == CONV_OVERFLOW) {
+ dprintf(1, (ddt,
+ "Dump T_UNSPEC: Output buffer overflow\n"
+ )
+ );
+ syslog(LOG_ERR,
+ "Dump T_UNSPEC: Output buffer overflow\n");
+ TmpBuf = "OVERFLOW";
+ }
+ fprintf(fp, "%s", TmpBuf);
+ }
+ break;
+#endif /* ALLOW_T_UNSPEC */
+ default:
+ fprintf(fp, "%s?d_type=%d?",
+ sep, dp->d_type);
+ sep = " ";
+ }
+ if (dp->d_cred < DB_C_ZONE) {
+ fprintf(fp, "%sCr=%s",
+ sep, MkCredStr(dp->d_cred));
+ sep = " ";
+ } else {
+ fprintf(fp, "%sCl=%d",
+ sep, dp->d_clev);
+ sep = " ";
+ }
+eoln:
+#ifdef STATS
+ if (dp->d_ns) {
+ fprintf(fp, "%s[%s]",
+ sep, inet_ntoa(dp->d_ns->addr));
+ sep = " ";
+ }
+#endif
+ putc('\n', fp);
+ }
+ }
+ }
+ 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);
+}
+
+static const char *
+MkCredStr(cred)
+ int cred;
+{
+ static char badness[20];
+
+ switch (cred) {
+ case DB_C_ZONE: return "zone";
+ case DB_C_AUTH: return "auth";
+ case DB_C_ANSWER: return "answer";
+ case DB_C_ADDITIONAL: return "addtnl";
+ case DB_C_CACHE: return "cache";
+ default: break;
+ }
+ sprintf(badness, "?%d?", cred);
+ return (badness);
+}
+
+#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 int32_t Ceor, Csum, Crot, word, bcount;
+
+#define EN(c) ((int) ((c) + '!'))
+#define DE(c) ((c) - '!')
+#define AddToBuf(bufp, c) **bufp = c; (*bufp)++;
+#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 void
+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;
+ int32_t 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 void
+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 int32_t tmpword = word;
+
+ if (tmpword < 0) {
+ /* Because some don't support unsigned long */
+ tmp = 32;
+ tmpword -= (int32_t)(85 * 85 * 85 * 85 * 32);
+ }
+ if (tmpword < 0) {
+ tmp = 64;
+ tmpword -= (int32_t)(85 * 85 * 85 * 85 * 32);
+ }
+ AddToBuf(bufp,
+ EN((tmpword / (int32_t)(85 * 85 * 85 * 85)) + tmp));
+ tmpword %= (int32_t)(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
+ */
+static int
+btoa(inbuf, inbuflen, outbuf, outbuflen)
+ char *inbuf;
+ int inbuflen;
+ char *outbuf;
+ int outbuflen;
+{
+ int32_t inc, nb;
+ int32_t 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.sbin/named/db_func.h b/usr.sbin/named/db_func.h
new file mode 100644
index 0000000..1c7275c
--- /dev/null
+++ b/usr.sbin/named/db_func.h
@@ -0,0 +1,102 @@
+/* db_proc.h - prototypes for functions in db_*.c
+ *
+ * $Id: db_func.h,v 1.8 1994/07/23 23:23:56 vixie Exp $
+ */
+
+/* ++from db_update.c++ */
+extern int db_update __P((char name[],
+ struct databuf *odp,
+ struct databuf *newdp,
+ int flags,
+ struct hashbuf *htp));
+/* --from db_update.c-- */
+
+/* ++from db_reload.c++ */
+extern void db_reload __P((void));
+/* --from db_reload.c-- */
+
+/* ++from db_save.c++ */
+extern struct namebuf *savename __P((char *));
+#ifdef DMALLOC
+extern struct databuf *savedata_tagged __P((char *, int,
+ int, int, u_int32_t,
+ u_char *, int));
+#define savedata(class, type, ttl, data, size) \
+ savedata_tagged(__FILE__, __LINE__, class, type, ttl, data, size)
+#else
+extern struct databuf *savedata __P((int, int, u_int32_t,
+ u_char *, int));
+#endif
+extern struct hashbuf *savehash __P((struct hashbuf *));
+/* --from db_save.c-- */
+
+/* ++from db_dump.c++ */
+extern int db_dump __P((struct hashbuf *, FILE *, int, char *)),
+ zt_dump __P((FILE *)),
+ atob __P((char *, int, char *, int, int *));
+extern void doachkpt __P((void)),
+ doadump __P((void));
+#ifdef ALLOW_UPDATES
+extern void zonedump __P((struct zoneinfo *));
+#endif
+/* --from db_dump.c-- */
+
+/* ++from db_load.c++ */
+extern void endline __P((FILE *)),
+ get_netlist __P((FILE *, struct netinfo **,
+ int, char *)),
+ free_netlist __P((struct netinfo **));
+extern int getword __P((char *, int, FILE *)),
+ getnum __P((FILE *, char *, int)),
+ db_load __P((char *, char *, struct zoneinfo *, int)),
+ position_on_netlist __P((struct in_addr,
+ struct netinfo *));
+extern struct netinfo *addr_on_netlist __P((struct in_addr,
+ struct netinfo *));
+/* --from db_load.c-- */
+
+/* ++from db_glue.c++ */
+extern void buildservicelist __P((void)),
+ buildprotolist __P((void)),
+ gettime __P((struct timeval *)),
+ getname __P((struct namebuf *, char *, int));
+extern int servicenumber __P((char *)),
+ protocolnumber __P((char *)),
+ my_close __P((int)),
+ my_fclose __P((FILE *)),
+#ifdef GEN_AXFR
+ get_class __P((char *)),
+#endif
+ writemsg __P((int, u_char *, int)),
+ dhash __P((u_char *, int)),
+ samedomain __P((const char *, const char *));
+extern char *protocolname __P((int)),
+ *servicename __P((u_int16_t, char *)),
+ *savestr __P((char *));
+#ifndef BSD
+extern int getdtablesize __P((void));
+#endif
+extern struct databuf *rm_datum __P((struct databuf *,
+ struct namebuf *,
+ struct databuf *));
+extern struct namebuf *rm_name __P((struct namebuf *,
+ struct namebuf **,
+ struct namebuf *));
+#ifdef INVQ
+extern void addinv __P((struct namebuf *, struct databuf *)),
+ rminv __P((struct databuf *));
+struct invbuf *saveinv __P((void));
+#endif
+/* --from db_glue.c-- */
+
+/* ++from db_lookup.c++ */
+extern struct namebuf *nlookup __P((char *, struct hashbuf **,
+ char **, int));
+extern int match __P((struct databuf *, int, int));
+/* --from db_lookup.c-- */
+
+/* ++from db_secure.c++ */
+#ifdef SECURE_ZONES
+extern int build_secure_netlist __P((struct zoneinfo *));
+#endif
+/* --from db_secure.c-- */
diff --git a/usr.sbin/named/db_glob.h b/usr.sbin/named/db_glob.h
new file mode 100644
index 0000000..74ae45d
--- /dev/null
+++ b/usr.sbin/named/db_glob.h
@@ -0,0 +1,93 @@
+/*
+ * from db.h 4.16 (Berkeley) 6/1/90
+ * $Id: db_glob.h,v 1.2 1994/04/12 08:57:50 vixie Exp $
+ */
+
+/*
+ * ++Copyright++ 1985, 1990
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+/*
+ * Global variables for data base routines.
+ */
+
+ /* ONE_WEEK maximum ttl */
+DECL int max_cache_ttl INIT(7*24*60*60);
+
+ /* 5 minute minimum ttl */
+DECL int min_cache_ttl INIT(5*60);
+
+ /* current line number */
+DECL int lineno;
+
+#ifdef DUMPFILE
+DECL char *dumpfile INIT(DUMPFILE);
+#else
+DECL char *dumpfile INIT(_PATH_DUMPFILE);
+#endif
+
+ /* root hash table */
+DECL struct hashbuf *hashtab INIT(NULL);
+
+ /* hash table of cache read from file */
+DECL struct hashbuf *fcachetab INIT(NULL);
+
+#ifdef INVQ
+ /* Inverse query hash table */
+DECL struct invbuf *invtab[INVHASHSZ];
+#endif
+
+#ifdef FORCED_RELOAD
+DECL int reloading INIT(0);
+#endif /* FORCED_RELOAD */
diff --git a/usr.sbin/named/db_glue.c b/usr.sbin/named/db_glue.c
new file mode 100644
index 0000000..f3f3069
--- /dev/null
+++ b/usr.sbin/named/db_glue.c
@@ -0,0 +1,710 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_glue.c 4.4 (Berkeley) 6/1/90";
+static char rcsid[] = "$Id: db_glue.c,v 4.9.1.12 1994/07/22 08:42:39 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988
+ * -
+ * Copyright (c) 1986, 1988
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <errno.h>
+
+#include "named.h"
+
+struct valuelist {
+ struct valuelist *next, *prev;
+ char *name;
+ char *proto;
+ int port;
+} *servicelist, *protolist;
+
+#if defined(ultrix)
+/* ultrix 4.0 has some icky packaging details. work around them here.
+ * since this module is linked into named and named-xfer, we end up
+ * forcing both to drag in our own res_send rather than ultrix's hesiod
+ * version of that.
+ */
+static const int (*unused_junk)__P((const u_char *, int, u_char *, int)) =
+ res_send;
+;
+#endif
+
+void
+buildservicelist()
+{
+ struct servent *sp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setservent(0);
+#else
+ setservent(1);
+#endif
+ 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_int16_t)sp->s_port);
+ slp->next = servicelist;
+ slp->prev = NULL;
+ if (servicelist)
+ servicelist->prev = slp;
+ servicelist = slp;
+ }
+ endservent();
+}
+
+void
+buildprotolist()
+{
+ struct protoent *pp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setprotoent(0);
+#else
+ setprotoent(1);
+#endif
+ 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();
+}
+
+static int
+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);
+}
+
+/*
+ * Convert service name or (ascii) number to int.
+ */
+int
+servicenumber(p)
+ char *p;
+{
+ return (findservice(p, &servicelist));
+}
+
+/*
+ * Convert protocol name or (ascii) number to int.
+ */
+int
+protocolnumber(p)
+ char *p;
+{
+ return (findservice(p, &protolist));
+}
+
+#if defined(__STDC__) || defined(__GNUC__)
+static struct servent *
+cgetservbyport(u_int16_t port,
+ char *proto)
+#else
+static struct servent *
+cgetservbyport(port, proto)
+ u_int16_t port;
+ char *proto;
+#endif
+{
+ 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 != (u_int16_t)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_int16_t)lp->port);
+ serv.s_proto = lp->proto;
+ return (&serv);
+ }
+ }
+ return (0);
+}
+
+static 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);
+}
+
+#if defined(__STDC__) || defined(__GNUC__)
+char *
+servicename(u_int16_t port, char *proto)
+#else
+char *
+servicename(port, proto)
+ u_int16_t port;
+ char *proto;
+#endif
+{
+ 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);
+}
+
+int
+db_getclev(origin)
+ char *origin;
+{
+ int lev = 0;
+ dprintf(1, (ddt, "db_getclev of \"%s\"", origin));
+ if (origin && *origin)
+ lev++;
+ while (origin && (origin = strchr(origin, '.'))) {
+ origin++;
+ lev++;
+ }
+ dprintf(1, (ddt, " = %d\n", lev));
+ return (lev);
+}
+
+void
+gettime(ttp)
+ struct timeval *ttp;
+{
+ if (gettimeofday(ttp, NULL) < 0)
+ syslog(LOG_ERR, "gettimeofday: %m");
+ return;
+}
+
+#if !defined(BSD)
+int
+getdtablesize()
+{
+#if defined(USE_POSIX)
+ int j = (int) sysconf(_SC_OPEN_MAX);
+
+ if (j >= 0)
+ return (j);
+#endif /* POSIX */
+ return (FD_SETSIZE);
+}
+#endif /* BSD */
+
+int
+my_close(fd)
+ int fd;
+{
+ int s = close(fd);
+
+ if (s < 0) {
+ syslog(LOG_ERR, "close(%d) failed: %m", fd);
+ dprintf(3, (ddt, "close(%d) failed: %s\n",
+ fd, strerror(errno)));
+ } else {
+ dprintf(3, (ddt, "close(%d) succeeded\n", fd));
+ }
+ return (s);
+}
+
+#ifdef GEN_AXFR
+/*
+ * Map class names to number
+ */
+struct map {
+ char *token;
+ int val;
+};
+
+static struct map map_class[] = {
+ "in", C_IN,
+ "chaos", C_CHAOS,
+ "hs", C_HS,
+ NULL, 0,
+};
+
+int
+get_class(class)
+ char *class;
+{
+ struct map *mp;
+
+ if (isdigit(*class))
+ return (atoi(class));
+ for (mp = map_class; mp->token != NULL; mp++)
+ if (strcasecmp(class, mp->token) == 0)
+ return (mp->val);
+ return (C_IN);
+}
+#endif
+
+int
+my_fclose(fp)
+ FILE *fp;
+{
+ int fd = fileno(fp),
+ s = fclose(fp);
+
+ if (s < 0) {
+ syslog(LOG_ERR, "fclose(%d) failed: %m", fd);
+ dprintf(3, (ddt, "fclose(%d) failed: %s\n",
+ fd, strerror(errno)));
+ } else {
+ dprintf(3, (ddt, "fclose(%d) succeeded\n", fd));
+ }
+ return (s);
+}
+
+/*
+ * Make a copy of a string and return a pointer to it.
+ */
+char *
+savestr(str)
+ char *str;
+{
+ char *cp;
+
+ cp = (char *)malloc(strlen(str) + 1);
+ if (cp == NULL) {
+ syslog(LOG_ERR, "savestr: %m");
+ exit(1);
+ }
+ (void) strcpy(cp, str);
+ return (cp);
+}
+
+int
+writemsg(rfd, msg, msglen)
+ int rfd;
+ u_char *msg;
+ int msglen;
+{
+ struct iovec iov[2];
+ u_char len[INT16SZ];
+
+ __putshort(msglen, len);
+ iov[0].iov_base = (char *)len;
+ iov[0].iov_len = INT16SZ;
+ iov[1].iov_base = (char *)msg;
+ iov[1].iov_len = msglen;
+ if (writev(rfd, iov, 2) != INT16SZ + msglen) {
+ dprintf(1, (ddt, "write failed %d\n", errno));
+ return (-1);
+ }
+ return (0);
+}
+
+/* rm_datum(dp, np, pdp)
+ * remove datum 'dp' from name 'np'. pdp is previous data pointer.
+ * return value:
+ * "next" field from removed datum, suitable for relinking
+ */
+struct databuf *
+rm_datum(dp, np, pdp)
+ register struct databuf *dp;
+ register struct namebuf *np;
+ register struct databuf *pdp;
+{
+ register struct databuf *ndp = dp->d_next;
+
+ dprintf(3, (ddt, "rm_datum(%x, %x, %x) -> %x\n",
+ dp, np->n_data, pdp, ndp));
+#ifdef INVQ
+ rminv(dp);
+#endif
+ if (pdp == NULL)
+ np->n_data = ndp;
+ else
+ pdp->d_next = ndp;
+#ifdef DATUMREFCNT
+ if (--(dp->d_rcnt)) {
+ switch(dp->d_type) {
+ case T_NS:
+ dprintf(1, (ddt, "rm_datum: %s rcnt = %d\n",
+ dp->d_data, dp->d_rcnt));
+ break;
+ case T_A:
+ dprintf(1, (ddt, "rm_datum: %08.8X rcnt = %d\n",
+ *(int32_t*)(dp->d_data), dp->d_rcnt));
+ break;
+ default:
+ dprintf(1, (ddt, "rm_datum: rcnt = %d\n", dp->d_rcnt));
+ }
+ } else
+#endif
+ free((char *)dp);
+ return (ndp);
+}
+
+/* rm_name(np, he, pnp)
+ * remove name 'np' from parent 'pp'. pnp is previous name pointer.
+ * return value:
+ * "next" field from removed name, suitable for relinking
+ */
+struct namebuf *
+rm_name(np, pp, pnp)
+ struct namebuf *np, **pp, *pnp;
+{
+ struct namebuf *nnp = np->n_next;
+ char *msg;
+
+ /* verify */
+ if ( (np->n_data && (msg = "data"))
+ || (np->n_hash && (msg = "hash"))
+ ) {
+ dprintf(1, (ddt,
+ "rm_name(%x(%s)): non-nil %s pointer\n",
+ np, np->n_dname?np->n_dname:"Nil", msg));
+ syslog(LOG_ERR,
+ "rm_name(%x(%s)): non-nil %s pointer\n",
+ np, np->n_dname?np->n_dname:"Nil", msg);
+ abort();
+ }
+
+ /* unlink */
+ if (pnp) {
+ pnp->n_next = nnp;
+ } else {
+ *pp = nnp;
+ }
+
+ /* deallocate */
+ free(np->n_dname);
+ free((char*) np);
+
+ /* done */
+ return (nnp);
+}
+
+/*
+ * Get the domain name of 'np' and put in 'buf'. Bounds checking is done.
+ */
+void
+getname(np, buf, buflen)
+ struct namebuf *np;
+ char *buf;
+ int buflen;
+{
+ register char *cp;
+ register int i;
+
+ cp = buf;
+ while (np != NULL) {
+ if ((i = strlen(np->n_dname))+1 >= buflen) {
+ *cp = '\0';
+ syslog(LOG_ERR, "domain name too long: %s...\n", buf);
+ strcpy(buf, "Name_Too_Long");
+ return;
+ }
+ if (cp != buf)
+ *cp++ = '.';
+ (void) strcpy(cp, np->n_dname);
+ cp += i;
+ buflen -= (i+1);
+ np = np->n_parent;
+ }
+ *cp = '\0';
+}
+
+#ifdef INVQ
+/*
+ * Add data 'dp' to inverse query tables for name 'np'.
+ */
+void
+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.
+ */
+void
+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 (dp != odp)
+ continue;
+ while (i < INVBLKSZ-1) {
+ ip->i_dname[i] = ip->i_dname[i+1];
+ i++;
+ }
+ ip->i_dname[i] = NULL;
+ return;
+ }
+ }
+ }
+}
+
+/*
+ * 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);
+}
+#endif /*INVQ*/
+
+/*
+ * Compute hash value from data.
+ */
+int
+dhash(dp, dlen)
+ u_char *dp;
+ int dlen;
+{
+ register u_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);
+}
+
+/*
+** SAMEDOMAIN -- Check whether a name belongs to a domain
+** ------------------------------------------------------
+**
+** Returns:
+** TRUE if the given name lies in the domain.
+** FALSE otherwise.
+**
+** Trailing dots are first removed from name and domain.
+** Always compare complete subdomains, not only whether the
+** domain name is the trailing string of the given name.
+**
+** "host.foobar.top" lies in "foobar.top" and in "top" and in ""
+** but NOT in "bar.top"
+**
+** this implementation of samedomain() is thanks to Bob Heiney.
+*/
+
+int
+samedomain(a, b)
+ const char *a, *b;
+{
+ size_t la, lb;
+ const char *cp;
+
+ la = strlen(a);
+ lb = strlen(b);
+
+ /* don't count trailing dots, if any. */
+ if (la && a[la-1]=='.')
+ la--;
+ if (lb && b[lb-1]=='.')
+ lb--;
+
+ /* lb==0 means b is the root domain, so a must be in b. */
+ if (lb == 0)
+ return (1);
+
+ /* b longer than a means a can't be in b. */
+ if (lb > la)
+ return (0);
+
+ /* We use strncasecmp because we might be trying to
+ * ignore trailing dots. */
+ if (lb == la)
+ return (strncasecmp(a, b, lb) == 0);
+
+ /* Ok, we know la > lb. */
+
+ /* Point at the character before the last 'lb' characters of a. */
+ cp = a + (la - lb - 1);
+
+ /* If it isn't '.', can't be a match (this lets us avoid
+ * having "foobar.com" match "bar.com"). */
+ if (*cp != '.')
+ return (0);
+
+ cp++;
+
+ /* We use strncasecmp because we might be trying to
+ * ignore trailing dots. */
+ return (strncasecmp(cp, b, lb)==0);
+}
diff --git a/usr.sbin/named/db_load.c b/usr.sbin/named/db_load.c
new file mode 100644
index 0000000..dfd46e3
--- /dev/null
+++ b/usr.sbin/named/db_load.c
@@ -0,0 +1,1214 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_load.c 4.38 (Berkeley) 3/2/91";
+static char rcsid[] = "$Id: db_load.c,v 4.9.1.18 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988, 1990
+ * -
+ * Copyright (c) 1986, 1988, 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+/*
+ * Load data base from ascii backupfile. Format similar to RFC 883.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <netdb.h>
+
+#include "named.h"
+
+static int gettoken __P((register FILE *, char *)),
+ getnonblank __P((FILE *, char *)),
+ getprotocol __P((FILE *, char *)),
+ getservices __P((int, char *, FILE *, char *));
+static void makename __P((char *, char *));
+static int empty_token = 0;
+
+/*
+ * 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,
+ "rp", T_RP,
+ "afsdb", T_AFSDB,
+ "x25", T_X25,
+ "isdn", T_ISDN,
+ "rt", T_RT,
+ "nsap", T_NSAP,
+ "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
+
+static int clev; /* a zone deeper in a heirachy has more credability */
+
+/* int
+ * db_load(filename, in_origin, zp, doinginclude)
+ * load a database from `filename' into zone `zp'. append `origin'
+ * to all nonterminal domain names in the file. `doinginclude' is
+ * true if this is a $INCLUDE file.
+ * returns:
+ * -1 = can't open file
+ * 0 = success
+ * >0 = number of errors encountered
+ */
+int
+db_load(filename, in_origin, zp, doinginclude)
+ char *filename, *in_origin;
+ struct zoneinfo *zp;
+ int doinginclude;
+{
+ register char *cp;
+ register struct map *mp;
+ char domain[MAXDNAME];
+ char origin[MAXDNAME];
+ char tmporigin[MAXDNAME];
+ char buf[MAXDATA];
+ char data[MAXDATA];
+ char *cp1;
+ char *op;
+ int c, class, type, ttl, dbflags, dataflags, multiline;
+ static int read_soa; /* number of soa's read */
+ struct databuf *dp;
+ FILE *fp;
+ int slineno, i, errs = 0, didinclude = 0;
+ register u_int32_t n;
+ struct stat sb;
+ struct in_addr ina;
+
+ if (!doinginclude) {
+ read_soa = 0;
+ clev = db_getclev(in_origin);
+ }
+
+ dprintf(1, (ddt,"db_load(%s, %s, %d, %d)\n",
+ filename, in_origin, zp - zones, doinginclude));
+
+ (void) strcpy(origin, in_origin);
+ if ((fp = fopen(filename, "r")) == NULL) {
+ syslog(LOG_ERR, "%s: %m", filename);
+ dprintf(1, (ddt, "db_load: error opening file %s\n",
+ filename));
+ 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 = zp->z_class;
+ zp->z_flags &= ~(Z_INCLUDE|Z_DB_BAD);
+ while ((c = gettoken(fp, filename)) != EOF) {
+ switch (c) {
+ case INCLUDE:
+ if (!getword((char *)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((char *)buf, tmporigin, zp, 1);
+ continue;
+
+ case ORIGIN:
+ (void) strcpy((char *)buf, origin);
+ if (!getword(origin, sizeof(origin), fp))
+ break;
+ dprintf(3, (ddt, "db_load: origin %s, buf %s\n",
+ origin, buf));
+ makename(origin, buf);
+ dprintf(3, (ddt, "db_load: origin now %s\n", origin));
+ 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((char *)buf, sizeof(buf), fp)) {
+ if (c == CURRENT)
+ continue;
+ break;
+ }
+ cp = buf;
+ ttl = 0;
+ if (isdigit(*cp)) {
+ n = 0;
+ do {
+ if (n > (INT_MAX - (*cp - '0')) / 10) {
+ syslog(LOG_ERR,
+ "%s: line %d: number > %lu\n",
+ filename, lineno, INT_MAX);
+ dprintf(1, (ddt,
+ "%s: line %d: number > %lu\n",
+ filename, lineno, INT_MAX));
+ n = INT_MAX;
+ cp++;
+ } else
+ 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((char *)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((char *)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;
+ }
+ dprintf(1, (ddt, "%s: Line %d: Unknown type: %s.\n",
+ filename, lineno, buf));
+ errs++;
+ syslog(LOG_ERR, "%s: Line %d: Unknown type: %s.\n",
+ filename, 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
+ if (!getword((char *)buf, sizeof(buf), fp))
+ break;
+ dprintf(3,
+ (ddt,
+ "d='%s', c=%d, t=%d, ttl=%d, data='%s'\n",
+ domain, class, type, ttl, buf));
+#ifdef ALLOW_T_UNSPEC
+ }
+#endif
+ /*
+ * Convert the ascii data 'buf' to the proper format
+ * based on the type and pack into 'data'.
+ */
+ switch (type) {
+ case T_A:
+ if (!inet_aton(buf, &ina))
+ goto err;
+ n = ntohl(ina.s_addr);
+ cp = data;
+ PUTLONG(n, cp);
+ n = INT32SZ;
+ break;
+
+ case T_HINFO:
+ case T_ISDN:
+ 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);
+ if (n == 0)
+ goto err;
+ n++;
+ if (!getword((char *)buf, sizeof(buf), fp))
+ i = 0;
+ else {
+ endline(fp);
+ i = strlen((char *)buf);
+ }
+ if (i == 0) {
+ /* goto err; */
+ /* XXX tolerate for now */
+ data[n++] = 1;
+ data[n++] = '?';
+ break;
+ }
+ if (i > 255) {
+ syslog(LOG_WARNING,
+ "%s:%d: OS type too long",
+ filename, lineno);
+ i = 255;
+ }
+ data[n] = i;
+ bcopy(buf, data + n + 1, i);
+ n += i + 1;
+ break;
+
+ case T_SOA:
+ case T_MINFO:
+ case T_RP:
+ (void) strcpy((char *)data, (char *)buf);
+ makename(data, origin);
+ cp = data + strlen((char *)data) + 1;
+ if (!getword((char *)cp,
+ sizeof(data) - (cp - data), fp))
+ goto err;
+ makename(cp, origin);
+ cp += strlen((char *)cp) + 1;
+ if (type != T_SOA) {
+ n = cp - data;
+ break;
+ }
+ if (class != zp->z_class) {
+ syslog(LOG_WARNING,
+ "%s:%d: %s",
+ filename, lineno,
+ "SOA class not same as zone's");
+ }
+ c = getnonblank(fp, filename);
+ if (c == '(') {
+ multiline = 1;
+ } else {
+ multiline = 0;
+ ungetc(c, fp);
+ }
+ zp->z_serial = getnum(fp, filename, 1);
+ n = (u_int32_t) zp->z_serial;
+ PUTLONG(n, cp);
+ zp->z_refresh = getnum(fp, filename, 0);
+ n = (u_int32_t) zp->z_refresh;
+ PUTLONG(n, cp);
+ if (zp->z_type == Z_SECONDARY
+#if defined(STUBS)
+ || zp->z_type == Z_STUB
+#endif
+ ) {
+ zp->z_time = sb.st_mtime
+ + zp->z_refresh;
+ }
+ zp->z_retry = getnum(fp, filename, 0);
+ n = (u_int32_t) zp->z_retry;
+ PUTLONG(n, cp);
+ zp->z_expire = getnum(fp, filename, 0);
+ n = (u_int32_t) zp->z_expire;
+ PUTLONG (n, cp);
+ zp->z_minimum = getnum(fp, filename, 0);
+ n = (u_int32_t) zp->z_minimum;
+ PUTLONG (n, cp);
+ n = cp - data;
+ if (multiline) {
+ if (getnonblank(fp, filename) != ')')
+ 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 = INT32SZ;
+ break;
+
+ case T_WKS:
+ /* Address */
+ if (!inet_aton(buf, &ina))
+ goto err;
+ n = ntohl(ina.s_addr);
+ cp = data;
+ PUTLONG(n, cp);
+ *cp = (char)getprotocol(fp, filename);
+ /* Protocol */
+ n = INT32SZ + 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 = strchr((char *)buf, '&');
+ bzero(data, sizeof(data));
+ if ( cp != NULL) {
+ (void) strncpy((char *)data,
+ (char *)buf, cp - buf);
+ op = strchr(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:
+ case T_AFSDB:
+ case T_RT:
+ 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_int16_t)n, cp);
+
+ if (!getword((char *)buf, sizeof(buf), fp))
+ goto err;
+ (void) strcpy((char *)cp, (char *)buf);
+ makename(cp, origin);
+ /* advance pointer to end of data */
+ cp += strlen((char *)cp) +1;
+
+ /* now save length */
+ n = (cp - data);
+ break;
+
+ case T_TXT:
+ case T_X25:
+ cp = buf + (n = strlen(buf));
+ while ((i = getc(fp), *cp = i, i != EOF)
+ && *cp != '\n'
+ && (n < MAXDATA)) {
+ cp++; n++;
+ }
+ if (*cp == '\n') /* leave \n for getword */
+ ungetc(*cp, fp);
+ *cp = '\0';
+ /* now do normal processing */
+
+ 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;
+
+ case T_NSAP:
+ n = inet_nsap_addr(buf, data, MAXDATA);
+ if (n == 0)
+ goto err;
+ endline(fp);
+ break;
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+ {
+ int rcode;
+ fgets(buf, sizeof(buf), fp);
+ dprintf(1, (ddt, "loading T_UNSPEC\n"));
+ if (rcode = atob(buf,
+ strlen((char*)buf),
+ data, sizeof(data),
+ &n)) {
+ if (rcode == CONV_OVERFLOW) {
+ dprintf(1,
+ (ddt,
+ "Load T_UNSPEC: input buffer overflow\n"
+ )
+ );
+ errs++;
+ syslog(LOG_ERR,
+ "Load T_UNSPEC: input buffer overflow");
+ } else {
+ dprintf(1,
+ (ddt,
+ "Load T_UNSPEC: Data in bad atob format\n"
+ )
+ );
+ errs++;
+ syslog(LOG_ERR,
+ "Load T_UNSPEC: Data in bad atob format");
+ }
+ }
+ }
+ break;
+#endif /* ALLOW_T_UNSPEC */
+
+ default:
+ goto err;
+ }
+#ifdef STUBS
+ if (type == T_SOA && zp->z_type == Z_STUB)
+ continue;
+#endif
+#ifdef NO_GLUE
+ /*
+ * Ignore data outside the zone.
+ */
+ if (zp->z_type != Z_CACHE &&
+ !samedomain(domain, zp->z_origin))
+ {
+ syslog(LOG_WARNING,
+ "%s:%d: data \"%s\" outside zone \"%s\" (ignored)",
+ filename, lineno, domain, zp->z_origin);
+ continue;
+ }
+#endif /*NO_GLUE*/
+
+ dp = savedata(class, type, (u_int32_t)ttl,
+ (u_char *)data, (int)n);
+ dp->d_zone = zp - zones;
+ dp->d_flags = dataflags;
+ dp->d_cred = DB_C_ZONE;
+ dp->d_clev = clev;
+ if ((c = db_update(domain, dp, dp, dbflags,
+ (zp->z_type == Z_CACHE)
+ ? fcachetab
+ : hashtab))
+ != OK) {
+#ifdef DEBUG
+ if (debug && (c != DATAEXISTS))
+ fprintf(ddt, "update failed %s %d\n",
+ domain, type);
+#endif
+ free((char*) dp);
+ }
+ continue;
+
+ case ERROR:
+ break;
+ }
+ err:
+ errs++;
+ syslog(LOG_ERR, "%s: line %d: database format error (%s)",
+ filename, empty_token ? (lineno - 1) : lineno, buf);
+ dprintf(1, (ddt,
+ "%s: line %d: database format error ('%s', %d)\n",
+ filename, empty_token ? (lineno - 1) : lineno,
+ buf, n));
+ while ((c = getc(fp)) != EOF && c != '\n')
+ ;
+ if (c == '\n')
+ lineno++;
+ }
+ (void) my_fclose(fp);
+ lineno = slineno;
+ if (doinginclude == 0) {
+ if (didinclude) {
+ zp->z_flags |= 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);
+ }
+ }
+#ifdef SECURE_ZONES
+ build_secure_netlist(zp);
+#endif
+ if (errs)
+ zp->z_flags |= Z_DB_BAD;
+ return (errs);
+}
+
+static int
+gettoken(fp, src)
+ register FILE *fp;
+ char *src;
+{
+ 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);
+ }
+ dprintf(1, (ddt,
+ "%s: line %d: Unknown $ option: $%s\n",
+ src, lineno, op));
+ syslog(LOG_ERR,"%s: line %d: Unknown $ option: $%s\n",
+ src, 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);
+ }
+ }
+}
+
+/* int
+ * getword(buf, size, fp)
+ * get next word, skipping blanks & comments.
+ * parameters:
+ * buf - destination
+ * size - of destination
+ * fp - file to read from
+ * return value:
+ * 0 = no word; perhaps EOL or EOF
+ * 1 = word was read
+ */
+int
+getword(buf, size, fp)
+ char *buf;
+ int size;
+ FILE *fp;
+{
+ register char *cp;
+ register int c;
+
+ empty_token = 0;
+ 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;
+ }
+ if ((c = getc(fp)) != EOF)
+ ungetc(c, fp);
+ if (c == EOF || isspace(c) || c == '\n') {
+ *cp = '\0';
+ return (1);
+ }
+ else
+ continue;
+ }
+ if (c == '\\') {
+ if ((c = getc(fp)) == EOF)
+ c = '\\';
+ if (c == '\n')
+ lineno++;
+ }
+ if (cp >= buf+size-1)
+ break;
+ *cp++ = (char)c;
+ }
+ *cp = '\0';
+ if (cp == buf)
+ empty_token = 1;
+ return (cp != buf);
+}
+
+/*
+From: kagotani@cs.titech.ac.jp
+Message-Id: <9007040716.AA26646@saeko.cs.titech.ac.jp>
+Subject: named bug report and fix
+Date: Wed, 04 Jul 90 16:16:52 JST
+
+I found a bug in the BIND source code. Named with this bug parses
+the serial_no field of SOA records incorrectly. For example:
+ expression internal
+ in files expression I expect
+ 1. 1000 10000
+ 1.2 10002 10002
+ 1.23 100023 10023
+ 2.3 20003 20003
+Especially I can not accept that "2.3" is treated as if it is
+smaller than "1.23" in their internal expressions.
+
+[ if you define SENSIBLE_DOTS in ../conf/options.h, you get
+ m. kagotani's expected behaviour. this is NOT compatible
+ with pre-4.9 versions of BIND. --vix ]
+*/
+
+int
+getnum(fp, src, is_serial)
+ FILE *fp;
+ char *src;
+ int is_serial;
+{
+ register int c, n;
+ int seendigit = 0;
+ int seendecimal = 0;
+ int m = 0;
+ int allow_dots = 0;
+
+#ifdef DOTTED_SERIAL
+ allow_dots += is_serial;
+#endif
+ 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 != '.' || !allow_dots) {
+ syslog(LOG_ERR, "%s:%d: expected a number",
+ src, lineno);
+ dprintf(1, (ddt, "%s:%d: expected a number",
+ src, lineno));
+ exit(1); /* XXX why exit here?? */
+ } else {
+ if (!seendigit)
+ n = 1;
+#ifdef SENSIBLE_DOTS
+ n = n * 10000;
+#else
+ n = n * 1000;
+#endif
+ seendigit = 1;
+ seendecimal = 1;
+ }
+ continue;
+ }
+#ifdef SENSIBLE_DOTS
+ if (seendecimal)
+ m = m * 10 + (c - '0');
+ else
+ n = n * 10 + (c - '0');
+#else
+ n = n * 10 + (c - '0');
+#endif
+ seendigit = 1;
+ }
+ if (m > 9999) {
+ syslog(LOG_ERR,
+ "%s:%d: number after the decimal point exceeds 9999",
+ src, lineno);
+ dprintf(1, (ddt,
+ "%s:%d: number after the decimal point exceeds 9999",
+ src, lineno));
+ exit(1); /* XXX why exit here?? */
+ }
+ if (seendecimal) {
+ syslog(LOG_INFO,
+ "%s:%d: decimal serial number interpreted as %d",
+ src, lineno, n+m);
+ }
+ return (n + m);
+}
+
+static int
+getnonblank(fp, src)
+ FILE *fp;
+ char *src;
+{
+ 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, "%s: line %d: unexpected EOF", src, lineno);
+ dprintf(1, (ddt, "%s: line %d: unexpected EOF", src, lineno));
+ return (EOF);
+}
+
+/*
+ * Take name and fix it according to following rules:
+ * "." means root.
+ * "@" means current origin.
+ * "name." means no changes.
+ * "name" means append origin.
+ */
+static void
+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);
+ }
+ }
+}
+
+void
+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
+
+static int
+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);
+}
+
+static 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);
+ dprintf(1, (ddt,
+ "%s: line %d: port no. (%d) too big\n",
+ src, lineno, k));
+ }
+ }
+ 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_netlist(fp, netlistp, allow)
+ * get list of nets from 'fp', put on *netlistp, 'allow' controls
+ * whether hosts, nets, or both shall be accepted without warnings.
+ * (note that they are always accepted; 'allow' just controls the
+ * warnings.)
+ */
+void
+get_netlist(fp, netlistp, allow, print_tag)
+ FILE *fp;
+ struct netinfo **netlistp;
+ int allow;
+ char *print_tag;
+{
+ struct netinfo *ntp = NULL, **end = netlistp;
+ char buf[BUFSIZ], *maskp;
+ struct in_addr ina;
+
+ dprintf(1, (ddt, "get_netlist(%s)", print_tag));
+ while (getword(buf, sizeof(buf), fp)) {
+ if (strlen(buf) == 0)
+ break;
+ if ((maskp = strchr(buf, '&')) != NULL)
+ *maskp++ = '\0';
+ dprintf(1, (ddt," %s", buf));
+ if (ntp == NULL) {
+ ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
+ }
+ if (!inet_aton(buf, &ntp->my_addr)) {
+ syslog(LOG_ERR, "%s contains bogus element (%s)",
+ print_tag, buf);
+ continue;
+ }
+ if (maskp) {
+ if (!inet_aton(maskp, &ina)) {
+ syslog(LOG_ERR,
+ "%s element %s has bad mask (%s)",
+ print_tag, buf, maskp);
+ continue;
+ }
+ } else {
+ if (allow & ALLOW_HOSTS)
+ ina.s_addr = 0xffffffff; /* "exact" */
+ else
+ ina.s_addr = net_mask(ntp->my_addr);
+ }
+ ntp->next = NULL;
+ ntp->mask = ina.s_addr;
+ ntp->addr = ntp->my_addr.s_addr & ntp->mask;
+
+ /* Check for duplicates */
+ if (addr_on_netlist(ntp->my_addr, *netlistp))
+ continue;
+
+ if (ntp->addr != ntp->my_addr.s_addr) {
+ ina.s_addr = ntp->addr;
+ syslog(LOG_WARNING,
+ "%s element (%s) mask problem (%s)",
+ print_tag, buf, inet_ntoa(ina));
+ }
+
+ *end = ntp;
+ end = &ntp->next;
+ ntp = NULL;
+ }
+ if (ntp)
+ free((char *)ntp);
+
+ dprintf(1, (ddt, "\n"));
+#ifdef DEBUG
+ if (debug > 2)
+ for (ntp = *netlistp; ntp != NULL; ntp = ntp->next) {
+ fprintf(ddt, "ntp x%x addr x%x mask x%x",
+ ntp, ntp->addr, ntp->mask);
+ fprintf(ddt, " my_addr x%x", ntp->my_addr);
+ fprintf(ddt, " %s", inet_ntoa(ntp->my_addr));
+ fprintf(ddt, " next x%x\n", ntp->next);
+ }
+#endif
+}
+
+struct netinfo *
+addr_on_netlist(addr, netlist)
+ struct in_addr addr;
+ struct netinfo *netlist;
+{
+ u_int32_t a = addr.s_addr;
+ struct netinfo *t;
+
+ for (t = netlist; t != NULL; t = t->next)
+ if (t->addr == (a & t->mask))
+ return t;
+ return NULL;
+}
+
+int
+position_on_netlist(addr, netlist)
+ struct in_addr addr;
+ struct netinfo *netlist;
+{
+ u_int32_t a = addr.s_addr;
+ struct netinfo *t;
+ int position = 0;
+
+ for (t = netlist; t != NULL; t = t->next)
+ if (t->addr == (a & t->mask))
+ break;
+ else
+ position++;
+ return position;
+}
+
+void
+free_netlist(netlistp)
+ struct netinfo **netlistp;
+{
+ register struct netinfo *ntp, *next;
+
+ for (ntp = *netlistp; ntp != NULL; ntp = next) {
+ next = ntp->next;
+ free((char *)ntp);
+ }
+ *netlistp = NULL;
+}
diff --git a/usr.sbin/named/db_lookup.c b/usr.sbin/named/db_lookup.c
new file mode 100644
index 0000000..9084491
--- /dev/null
+++ b/usr.sbin/named/db_lookup.c
@@ -0,0 +1,196 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_lookup.c 4.18 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: db_lookup.c,v 4.9.1.5 1994/06/01 21:09:39 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+/*
+ * Table lookup routines.
+ */
+
+#include <syslog.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "named.h"
+
+/*
+ * 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 += (isupper(c) ? tolower(c) : 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) {
+ *fname = name;
+ *cp = c;
+ 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) {
+ *fname = name;
+ *cp = c;
+ 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;
+ }
+ *fname = name;
+ *cp = c;
+ return (np);
+}
+
+/* int
+ * match(dp, class, type)
+ * Does data record `dp' match the class and type?
+ * return value:
+ * boolean
+ */
+int
+match(dp, class, type)
+ register struct databuf *dp;
+ register int class, type;
+{
+ dprintf(5, (ddt, "match(0x%x, %d, %d) %d, %d\n",
+ dp, class, type, dp->d_class, dp->d_type));
+ 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.sbin/named/db_reload.c b/usr.sbin/named/db_reload.c
new file mode 100644
index 0000000..1b962a6
--- /dev/null
+++ b/usr.sbin/named/db_reload.c
@@ -0,0 +1,125 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_reload.c 4.22 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: db_reload.c,v 4.9.1.4 1994/07/02 16:28:11 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988
+ * -
+ * Copyright (c) 1986, 1988
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <syslog.h>
+
+#include "named.h"
+
+/*
+ * Flush and reload data base.
+ */
+void
+db_reload()
+{
+ dprintf(3, (ddt, "reload()\n"));
+ syslog(LOG_NOTICE, "reloading nameserver\n");
+
+ qflush();
+ sqflush(NULL);
+ getnetconf();
+#ifdef FORCED_RELOAD
+ reloading = 1; /* to force transfer if secondary and backing up */
+#endif
+ ns_init(bootfile);
+ time(&resettime);
+#ifdef FORCED_RELOAD
+ reloading = 0;
+ if (!needmaint)
+ sched_maint();
+#endif /* FORCED_RELOAD */
+
+ dprintf(1, (ddt, "Ready to answer queries.\n"));
+ syslog(LOG_NOTICE, "Ready to answer queries.\n");
+}
+
+#if 0
+/* someday we'll need this.. (untested since before 1990) */
+void
+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);
+}
+#endif
diff --git a/usr.sbin/named/db_save.c b/usr.sbin/named/db_save.c
new file mode 100644
index 0000000..cd1639d
--- /dev/null
+++ b/usr.sbin/named/db_save.c
@@ -0,0 +1,214 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_save.c 4.16 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: db_save.c,v 4.9.1.7 1994/07/22 08:42:39 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+/*
+ * Buffer allocation and deallocation routines.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <syslog.h>
+#include <stdio.h>
+
+#include "named.h"
+
+/*
+ * 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 *
+#ifdef DMALLOC
+savedata_tagged(file, line, class, type, ttl, data, size)
+ char *file;
+ int line;
+#else
+savedata(class, type, ttl, data, size)
+#endif
+ int class, type;
+ u_int32_t ttl;
+ u_char *data;
+ int size;
+{
+ register struct databuf *dp;
+
+ if (type == T_NS)
+ dp = (struct databuf *)
+#ifdef DMALLOC
+ dmalloc(file, line,
+#else
+ malloc(
+#endif
+ (unsigned)DATASIZE(size)+INT32SZ);
+ else
+ dp = (struct databuf *)
+#ifdef DMALLOC
+ dmalloc(file, line,
+#else
+ malloc(
+#endif
+ (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_cred = 0;
+ dp->d_clev = 0;
+#ifdef NCACHE
+ dp->d_rcode = NOERROR;
+#endif
+#ifdef STATS
+ dp->d_ns = NULL;
+#endif
+ 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;
+ }
+ dprintf(4, (ddt, "savehash GROWING to %d\n", newsize));
+ 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 namebuf *));
+ if (oldhtp == NULL) {
+ htp->h_cnt = 0;
+ return (htp);
+ }
+ dprintf(4, (ddt, "savehash(%#x) cnt=%d, sz=%d, newsz=%d\n",
+ oldhtp, oldhtp->h_cnt, oldhtp->h_size, newsize));
+ 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);
+}
diff --git a/usr.sbin/named/db_secure.c b/usr.sbin/named/db_secure.c
new file mode 100644
index 0000000..b3eb731
--- /dev/null
+++ b/usr.sbin/named/db_secure.c
@@ -0,0 +1,170 @@
+#ifndef LINT
+static char rcsid[] = "$Id: db_secure.c,v 1.6 1994/07/23 23:23:56 vixie Exp $";
+#endif
+
+/* this file was contributed by Gregory Neil Shapiro of WPI in August 1993 */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <syslog.h>
+
+#include "named.h"
+
+#ifdef SECURE_ZONES
+
+#ifndef SECURE_ZONE_RR
+#define SECURE_ZONE_RR "secure_zone"
+#endif
+#ifndef MASK_SEP
+#define MASK_SEP ':'
+#endif
+
+int
+build_secure_netlist(zp)
+ struct zoneinfo *zp;
+{
+ struct netinfo *ntp = NULL, **netlistp, **end;
+ char buf[BUFSIZ];
+ struct hashbuf *htp;
+ struct namebuf *snp;
+ struct databuf *dp;
+ char *fname, *dname, dnbuf[MAXDNAME];
+ int errs = 0, securezone = 0;
+
+ if (zp->secure_nets) {
+ free_netlist(&zp->secure_nets);
+ }
+ netlistp = &zp->secure_nets;
+ end = netlistp;
+ strcat(strcat(strcpy(dnbuf, SECURE_ZONE_RR), "."), zp->z_origin);
+
+ dname = dnbuf;
+ htp = hashtab;
+ if ((snp = nlookup(dname, &htp, &fname, 0)) == NULL) {
+ dprintf(1, (ddt,
+ "build_secure_netlist(%s): FAIL on nlookup %s\n",
+ zp->z_origin, dname));
+ zp->secure_nets=NULL;
+ return(0);
+ }
+ /* A parent's RR's aren't valid */
+ if (strcasecmp(snp->n_dname, SECURE_ZONE_RR)) {
+ zp->secure_nets=NULL;
+ return(0);
+ }
+ /* Collect secure nets into secure_nets */
+ for (dp = snp->n_data; dp != NULL; dp = dp->d_next) {
+ char *maskptr = NULL;
+ if (!match(dp, C_ANY, T_TXT)) {
+ continue;
+ }
+ bzero(buf, sizeof(buf));
+ bcopy(dp->d_data+1, buf, dp->d_size-1);
+ maskptr=strchr(buf, MASK_SEP);
+ if (maskptr) {
+ *maskptr++ = 0;
+ }
+ dprintf(3, (ddt,
+ "build_secure_netlist(%s): Found secure zone %s\n",
+ zp->z_origin, buf));
+ if (ntp == NULL) {
+ ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
+ if (!ntp) {
+ dprintf(1, (ddt,
+ "build_secure_netlist (%s): malloc fail\n",
+ zp->z_origin));
+ syslog(LOG_ERR,
+ "build_secure_netlist (%s): Out of Memory",
+ zp->z_origin);
+ if (!securezone) {
+ zp->secure_nets=NULL;
+ }
+ return(1);
+ }
+ }
+ if (!inet_aton(buf, &ntp->my_addr)) {
+ dprintf(1, (ddt,
+ "build_secure_netlist (%s): Bad address: %s\n",
+ zp->z_origin, buf));
+ syslog(LOG_ERR,
+ "build_secure_netlist (%s): Bad address: %s",
+ zp->z_origin, buf);
+ errs++;
+ continue;
+ }
+ if (maskptr && *maskptr) {
+ if (*maskptr == 'h' || *maskptr == 'H') {
+ ntp->mask = (u_int32_t)-1;
+ } else {
+ if (!inet_aton(maskptr,
+ (struct in_addr *)&ntp->mask)) {
+ dprintf(1, (ddt,
+ "build_secure_netlist (%s): Bad mask: %s\n",
+ zp->z_origin, maskptr));
+ syslog(LOG_ERR,
+ "build_secure_netlist (%s): Bad mask: %s",
+ zp->z_origin, maskptr);
+ errs++;
+ continue;
+ }
+ }
+ } else {
+ ntp->mask = net_mask(ntp->my_addr);
+ }
+ if (ntp->my_addr.s_addr & ~(ntp->mask)) {
+ dprintf(1, (ddt,
+ "build_secure_netlist (%s): addr (%s) is not in mask (x%x)\n",
+ zp->z_origin,
+ inet_ntoa(ntp->my_addr),
+ ntp->mask));
+ syslog(LOG_WARNING,
+ "build_secure_netlist (%s): addr (%s) is not in mask (x%x)",
+ zp->z_origin,
+ inet_ntoa(ntp->my_addr),
+ ntp->mask);
+ errs++;
+ }
+ ntp->next = NULL;
+ ntp->addr = ntp->my_addr.s_addr & ntp->mask;
+
+ /* Check for duplicates */
+ if (addr_on_netlist(ntp->my_addr, *netlistp)) {
+ dprintf(1, (ddt,
+ "build_secure_netlist (%s): duplicate address %s\n",
+ zp->z_origin, inet_ntoa(ntp->my_addr)));
+ syslog(LOG_WARNING,
+ "build_secure_netlist (%s): duplicate address %s\n",
+ zp->z_origin, inet_ntoa(ntp->my_addr));
+ errs++;
+ continue;
+ }
+ *end = ntp;
+ end = &ntp->next;
+ ntp = NULL;
+ securezone++;
+ }
+ if (ntp) {
+ free((char *)ntp);
+ }
+ if (!securezone) {
+ zp->secure_nets=NULL;
+ }
+
+#ifdef DEBUG
+ if (debug > 1) {
+ for (ntp = *netlistp; ntp != NULL; ntp = ntp->next) {
+ fprintf(ddt, "ntp x%x addr x%x mask x%x",
+ ntp, ntp->addr, ntp->mask);
+ fprintf(ddt, " my_addr x%x", ntp->my_addr);
+ fprintf(ddt, " %s", inet_ntoa(ntp->my_addr));
+ fprintf(ddt, " next x%x\n", ntp->next);
+ }
+ }
+#endif
+ return(errs);
+}
+#endif /*SECURE_ZONES*/
diff --git a/usr.sbin/named/db_update.c b/usr.sbin/named/db_update.c
new file mode 100644
index 0000000..9324493
--- /dev/null
+++ b/usr.sbin/named/db_update.c
@@ -0,0 +1,638 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_update.c 4.28 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: db_update.c,v 4.9.1.19 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1990
+ * -
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include "named.h"
+
+static void fixttl __P((struct databuf *));
+static int db_cmp __P((struct databuf *,
+ struct databuf *));
+
+/* int
+ * isRefByNS(name, htp)
+ * recurse through all of `htp' looking for NS RR's that refer to `name'.
+ * returns:
+ * nonzero if at least one such NS RR exists
+ * cautions:
+ * this is very expensive; probably you only want to use on fcachetab.
+ */
+static int
+isRefByNS(name, htp)
+ char name[];
+ struct hashbuf *htp;
+{
+ register struct namebuf *np;
+ register struct databuf *dp;
+
+ for (np = htp->h_tab[0]; np != NULL; np = np->n_next) {
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if ((dp->d_class == C_ANY || dp->d_class == C_IN) &&
+ (dp->d_type == T_NS) &&
+#ifdef NCACHE
+ (!dp->d_rcode) &&
+#endif
+ !strcasecmp(name, (char *)dp->d_data)) {
+ return (1);
+ }
+ }
+ if (np->n_hash && isRefByNS(name, np->n_hash)) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+
+/* int
+ * findMyZone(struct namebuf *np)
+ * surf the zone cuts and find this zone the hard way
+ * return value:
+ * zone number or DB_Z_CACHE if it's outside a zone
+ * interesting cases:
+ * DEC.COM SOA (primary)
+ * CRL.DEC.COM NS (in primary)
+ * if you start at CRL.. here, you find the DEC.COM zone
+ * if you start at NS.CRL.. here, you're in the cache
+ * DEC.COM SOA (primary)
+ * CRL.DEC.COM NS (in primary)
+ * CRL.DEC.COM SOA (secondary)
+ * CRL.DEC.COM NS (in secondary)
+ * if you start at CRL.. here, you find the CRL.DEC.COM zone
+ * if you start at NS.CRL.. here, you're in the CRL.. zone
+ */
+int
+findMyZone(np, class)
+ struct namebuf *np;
+ register int class;
+{
+ for (; np; np = np->n_parent) {
+ register struct databuf *dp;
+
+ /* if we encounter an SOA, we're in its zone (which can be
+ * the cache or an authoritative zone, depending).
+ */
+ for (dp = np->n_data; dp; dp = dp->d_next)
+ if (match(dp, class, T_SOA))
+ return (dp->d_zone);
+
+ /* if we find an NS at some node without having seen an SOA
+ * (above), then we're out in the cache somewhere.
+ */
+ for (dp = np->n_data; dp; dp = dp->d_next)
+ if (match(dp, class, T_NS))
+ return (DB_Z_CACHE);
+ }
+
+ /* getting all the way to the root without finding an NS or SOA
+ * probably means that we are in deep dip, but we'll treat it as
+ * being in the cache. (XXX?)
+ */
+ return (DB_Z_CACHE);
+}
+
+
+/* int
+ * db_update(name, odp, newdp, flags, htp)
+ * update data base node at `name'. `flags' controls the action.
+ * side effects:
+ * inverse query tables modified, if we're using them.
+ * return value:
+ * OK - success
+ * NONAME - name doesn't exist
+ * AUTH - you can't do that
+ * DATAEXISTS - there's something there and DB_NODATA was specified
+ * NODATA - there's no data, and (DB_DELETE or DB_MEXIST) was spec'd
+ *
+ * Policy: How to add data if one more RR is -ve data
+ *
+ * NEND NOERROR_NODATA
+ * NXD NXDOMAIN
+ *
+ * match
+ * old
+ * Data NEND NXD
+ * Data Merge Data Data
+ * new NEND NEND NEND NEND
+ * NXD NXD NXD NXD
+ *
+ * no match
+ * old
+ * Data NEND NXD
+ * Data Merge Merge Data
+ * new NEND Merge Merge NEND
+ * NXD NXD NXD NXD
+ *
+ */
+/* XXX: this code calls nlookup, which can create namebuf's. if this code
+ * has to exit with a fatal error, it should scan from the new np upward
+ * and for each node which has no children and no data it should remove
+ * the namebuf. design notes: (1) there's no harm in doing this even if
+ * success occurred; (2) stopping on the first nonremovable np is optimal;
+ * the code for removal should be taken out of remove_zone() and made
+ * general enough for this use, and for remove_zone()'s continued use.
+ * vix, 21jul94
+ */
+int
+db_update(name, odp, newdp, flags, htp)
+ char name[];
+ struct databuf *odp, *newdp;
+ int flags;
+ struct hashbuf *htp;
+{
+ register struct databuf *dp, *pdp;
+ register struct namebuf *np;
+ int zn, isHintNS;
+ char *fname;
+
+ dprintf(3, (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":"" ));
+ np = nlookup(name, &htp, &fname, newdp != NULL);
+ if (np == NULL || fname != name)
+ return (NONAME);
+
+ /* don't let nonauthoritative updates write in authority zones */
+ if (newdp && (flags & DB_NOTAUTH) &&
+ (zn = findMyZone(np, newdp->d_class)) != DB_Z_CACHE) {
+ int foundRR = 0;
+
+ /* don't generate the warning if we've done so recently or
+ * if the update would have been harmless (identical data).
+ */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!db_cmp(dp, newdp)) {
+ foundRR++;
+ break;
+ }
+ }
+ if (!foundRR &&
+ !haveComplained((char*)from_addr.sin_addr.s_addr,
+ (char*)dhash((u_char*)name, strlen(name))))
+ syslog(LOG_NOTICE,
+ "[%s].%d attempted update to auth zone \"%s\" (%s)",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port),
+ zones[zn].z_origin,
+ name);
+ return (AUTH);
+ }
+
+ /* some special checks for root NS' A RR's */
+ isHintNS = isRefByNS(name, fcachetab);
+ if (newdp && isHintNS && newdp->d_type == T_A) {
+ /* obviously bogus addresses die here */
+ if (
+#ifdef NCACHE
+ (!newdp->d_rcode) &&
+#endif
+ (((struct in_addr *)newdp->d_data)->s_addr == INADDR_ANY))
+ {
+ syslog(LOG_INFO, "bogus (0.0.0.0) root A RR received");
+ return (AUTH);
+ }
+ /* upgrade credibility of additional data for rootsrv addrs */
+ if (newdp->d_cred == DB_C_ADDITIONAL) {
+ dprintf(3, (ddt,
+ "upgrading credibility for A RR (%s)\n",
+ name));
+ /* XXX: should copy NS RR's, but we really just want
+ * to prevent deprecation later so this will do.
+ */
+ newdp->d_cred = DB_C_ANSWER;
+ newdp->d_clev = 0;
+ }
+ }
+
+ /* Reflect certain updates in hint cache also... */
+ /* Don't stick data we are authoritative for in hints. */
+ if (!(flags & DB_NOHINTS) &&
+ (odp != NULL) &&
+ (htp != fcachetab) &&
+ (odp->d_zone <= 0) &&
+ !(odp->d_flags & DB_F_HINT) &&
+#ifdef NCACHE
+ (!newdp || !newdp->d_rcode) &&
+#endif
+ ((name[0] == '\0' && odp->d_type == T_NS) ||
+ (odp->d_type == T_A && isHintNS)
+ )
+ )
+ {
+ dprintf(3, (ddt, "db_update: hint '%s' %d\n",
+ name, odp->d_ttl));
+ 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;
+ dp->d_cred = DB_C_CACHE;
+ dp->d_clev = 0;
+ if (db_update(name,
+ dp, dp,
+ (flags|DB_NOHINTS),
+ fcachetab)
+ != OK) {
+ dprintf(3, (ddt, "db_update: hint %x freed\n", dp));
+ (void) free((char *)dp);
+ }
+ }
+
+ if (odp != NULL) {
+ int foundRR = 0;
+
+ pdp = NULL;
+ for (dp = np->n_data; dp != NULL; ) {
+ if (!match(dp, odp->d_class, odp->d_type)) {
+ /* {class,type} doesn't match. these are
+ * the aggregation cases.
+ */
+ if ((dp->d_type == T_CNAME ||
+ odp->d_type == T_CNAME) &&
+ odp->d_class == dp->d_class &&
+ odp->d_mark == dp->d_mark &&
+#ifdef NCACHE
+ /* neither the odp nor the new dp are
+ * negatively cached records...
+ */
+ !dp->d_rcode &&
+ !odp->d_rcode &&
+#endif /*NCACHE*/
+ zones[odp->d_zone].z_type != Z_CACHE) {
+ syslog(LOG_ERR,
+ "%s has CNAME and other data (illegal)\n",
+ name);
+ dprintf(1, (ddt,
+ "db_update: %s: CNAME and more (%d, %d)\n",
+ name, odp->d_type,
+ dp->d_type));
+ goto skip;
+ }
+ if (!newdp || newdp->d_class != dp->d_class)
+ goto skip;
+
+ /* XXX:
+ * The next three clauses do not deal
+ * correctly with glue records. mpa.
+ */
+
+ /* if the new data is authorative
+ * remove any data for this domain with
+ * the same class that isn't as credable
+ */
+ if (newdp->d_cred == DB_C_ZONE &&
+ newdp->d_cred > dp->d_cred)
+ /* better credibility and the old datum
+ * was not from a zone file. remove
+ * the old datum.
+ */
+ goto delete;
+
+ /* if we have authoritative data for a
+ * node, don't add in other data.
+ */
+ if (dp->d_cred == DB_C_ZONE &&
+ newdp->d_cred < dp->d_cred)
+ return (AUTH);
+
+ /* if the new data is authoritative but
+ * but isn't as credible, reject it.
+ */
+ if (newdp->d_cred == DB_C_ZONE &&
+ newdp->d_cred == dp->d_cred &&
+ newdp->d_clev < dp->d_clev)
+ return (AUTH);
+#ifdef NCACHE
+ /* process NXDOMAIN */
+ /* policy */
+ if (newdp->d_rcode == NXDOMAIN) {
+ if (dp->d_cred < DB_C_AUTH)
+ goto delete;
+ else
+ return (DATAEXISTS);
+ }
+
+ if (dp->d_rcode == NXDOMAIN)
+ goto delete;
+
+ /* process NOERROR_NODATA */
+ /* NO PROCESSING REQUIRED */
+#endif /*NCACHE*/
+ goto skip;
+ } /*if {class,type} did not match*/
+
+ /* {type,class} did match. this is the replace case.
+ */
+ dprintf(5, (ddt,
+ "db_update: flags = %#x, sizes = %d, %d (cmp %d)\n",
+ flags, odp->d_size, dp->d_size,
+ db_cmp(dp, odp)));
+ if (newdp) {
+ dprintf(4, (ddt,
+ "credibility for %s is %d(%d) from [%s].%d, is %d(%d) in cache\n",
+ *name? name : ".",
+ newdp->d_cred,
+ newdp->d_clev,
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port),
+ dp->d_cred,
+ dp->d_clev));
+ if (newdp->d_cred > dp->d_cred ||
+ (newdp->d_cred == DB_C_ZONE &&
+ newdp->d_clev > dp->d_clev)) {
+ /* better credibility and the old datum
+ * was not from a zone file. remove
+ * the old datum.
+ */
+ goto delete;
+ }
+ if (newdp->d_cred < dp->d_cred) {
+ /* credibility is worse. ignore it. */
+ return (AUTH);
+ }
+ if (newdp->d_cred == DB_C_ZONE &&
+ newdp->d_cred == dp->d_cred &&
+ newdp->d_clev < dp->d_clev)
+ return (AUTH);
+
+ /* credibility is the same.
+ * let it aggregate in the normal way.
+ */
+#ifdef NCACHE
+ /*
+ * if the new or old RR is -ve, delete old.
+ */
+ if (dp->d_rcode || newdp->d_rcode) {
+ /* XXX: how can a zone rr be neg? */
+ if (dp->d_cred != DB_C_ZONE)
+ goto delete;
+ else
+ return (DATAEXISTS);
+ }
+#endif
+ /*
+ * Some RR types should not be aggregated.
+ */
+ if (dp->d_type == T_SOA)
+ goto delete;
+ if (dp->d_type == T_WKS &&
+ !bcmp(dp->d_data, newdp->d_data, INT16SZ))
+ goto delete;
+ }
+ 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;
+ dprintf(4, (ddt,
+ "db_update: cache entry now in auth zone\n"
+ ));
+ return (DATAEXISTS);
+ }
+ fixttl(odp);
+ if (odp->d_ttl > dp->d_ttl)
+ dp->d_ttl = odp->d_ttl;
+ dprintf(3, (ddt,
+ "db_update: new ttl %d, +%d\n",
+ dp->d_ttl,
+ dp->d_ttl - tt.tv_sec));
+ }
+ 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) {
+ 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);
+ /* XXX: empty nodes bypass credibility checks above; should check
+ * response source address here if flags&NOTAUTH.
+ */
+ fixttl(newdp);
+ dprintf(3, (ddt, "db_update: adding%s %x\n",
+ (newdp->d_flags&DB_F_HINT) ? " hint":"", newdp));
+#ifdef INVQ
+ if (!(newdp->d_flags & DB_F_HINT))
+ addinv(np, newdp); /* modify inverse query tables */
+#endif
+
+#ifdef STATS
+ if (!newdp->d_zone && !(newdp->d_flags & DB_F_HINT))
+ newdp->d_ns = nameserFind(from_addr.sin_addr, NS_F_INSERT);
+#endif
+
+ /* Add to end of list, generally preserving order */
+ newdp->d_next = NULL;
+ if ((dp = np->n_data) == NULL) {
+#ifdef DATUMREFCNT
+ newdp->d_rcnt = 1;
+#endif
+ np->n_data = newdp;
+ return (OK);
+ }
+ 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);
+#ifdef DATUMREFCNT
+ newdp->d_rcnt = 1;
+#endif
+ dp->d_next = newdp;
+ return (OK);
+}
+
+static void
+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;
+}
+
+/*
+ * Compare type, class and data from databufs for equivalence.
+ * Must be case insensitive for some domain names.
+ * Return 0 if equivalent, nonzero otherwise.
+ */
+static int
+db_cmp(dp1, dp2)
+ register struct databuf *dp1, *dp2;
+{
+ register u_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 */
+#ifdef NCACHE
+ if (dp1->d_rcode && dp2->d_rcode)
+ return ((dp1->d_rcode == dp1->d_rcode)?0:1);
+ if (dp1->d_rcode || dp2->d_rcode)
+ return (1);
+#endif
+
+ switch (dp1->d_type) {
+
+ case T_A:
+ case T_UID:
+ case T_GID:
+ case T_WKS:
+ case T_NULL:
+ case T_NSAP:
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+#endif
+ 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((char *)dp1->d_data, (char *)dp2->d_data));
+
+ case T_HINFO:
+ case T_ISDN:
+ cp1 = dp1->d_data;
+ cp2 = dp2->d_data;
+ len = *cp1;
+ if (strncasecmp((char *)++cp1, (char *)++cp2, len))
+ return (1);
+ cp1 += len;
+ cp2 += len;
+ len = *cp1;
+ return (strncasecmp((char *)++cp1, (char *)++cp2, len));
+
+ case T_SOA:
+ case T_MINFO:
+ case T_RP:
+ if (strcasecmp((char *)dp1->d_data, (char *)dp2->d_data))
+ return (1);
+ cp1 = dp1->d_data + strlen((char *)dp1->d_data) + 1;
+ cp2 = dp2->d_data + strlen((char *)dp2->d_data) + 1;
+ if (dp1->d_type != T_SOA)
+ return (strcasecmp((char *)cp1, (char *)cp2));
+ if (strcasecmp((char *)cp1, (char *)cp2))
+ return (1);
+ cp1 += strlen((char *)cp1) + 1;
+ cp2 += strlen((char *)cp2) + 1;
+ return (bcmp(cp1, cp2, INT32SZ * 5));
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ cp1 = dp1->d_data;
+ cp2 = dp2->d_data;
+ if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* cmp prio */
+ return (1);
+ return (strcasecmp((char *)cp1, (char *)cp2));
+
+ case T_TXT:
+ case T_X25:
+ 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.sbin/named/dmalloc.c b/usr.sbin/named/dmalloc.c
new file mode 100644
index 0000000..4373024
--- /dev/null
+++ b/usr.sbin/named/dmalloc.c
@@ -0,0 +1,312 @@
+/* dmalloc - debugging layer on top of malloc
+ * vix 25mar92 [fixed bug in round-up calcs in alloc()]
+ * vix 24mar92 [added size calcs, improved printout]
+ * vix 22mar92 [original work]
+ *
+ * $Id: dmalloc.c,v 4.9.1.3 1994/07/02 16:28:11 vixie Exp $
+ */
+
+/*
+ * ++Copyright++ 1993
+ * -
+ * Copyright (c) 1993
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include "../conf/portability.h"
+#include "../conf/options.h"
+
+#ifdef DMALLOC
+
+#define TRUE 1
+#define FALSE 0
+typedef unsigned bool;
+
+#define MAX_MEMORY 65536 /* must fit in typeof(datum.size) */
+#define MAX_CALLERS 256 /* must be **2 */
+
+typedef struct caller {
+ struct caller *next;
+ struct filenam *file;
+ struct calltab *frees;
+ unsigned line;
+ unsigned calls;
+ unsigned blocks;
+ unsigned bytes;
+} caller;
+
+typedef struct filenam {
+ struct filenam *next;
+ char *name;
+} filenam;
+
+typedef struct calltab {
+ struct caller *callers[MAX_CALLERS];
+} calltab;
+
+typedef struct datum {
+ unsigned size; /* size of malloc'd item */
+ unsigned caller; /* offset into memory[] */
+ /* user data follows */
+} datum;
+
+static char memory[MAX_MEMORY];
+static char *nextmem = memory;
+static char *alloc(size) unsigned size; {
+ char *thismem = nextmem;
+ int oddness = (size % sizeof(char*));
+ if (oddness)
+ size += (sizeof(char*) - oddness);
+ nextmem += size;
+ if (nextmem >= &memory[MAX_MEMORY]) {
+ fprintf(stderr, "dmalloc.alloc: out of mem\n");
+ kill(0, SIGBUS);
+ }
+ return thismem;
+ }
+
+static filenam *Files;
+static calltab Callers;
+
+/*--------------------------------------------------- imports
+ */
+
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+
+char *malloc(), *calloc(), *realloc();
+
+#if defined(sun)
+int free();
+#else
+void free();
+#endif
+
+/*--------------------------------------------------- private
+ */
+
+#define STR_EQ(l,r) (((l)[0] == (r)[0]) && !strcmp(l, r))
+
+static filenam *
+findFile(file, addflag)
+ char *file;
+ bool addflag;
+{
+ filenam *f;
+
+ for (f = Files; f; f = f->next)
+ if (STR_EQ(file, f->name))
+ return f;
+ if (!addflag)
+ return NULL;
+ f = (filenam*) alloc(sizeof(filenam));
+ f->next = Files;
+ Files = f;
+ f->name = alloc(strlen(file) + 1);
+ strcpy(f->name, file);
+ return f;
+}
+
+static caller *
+findCaller(ctab, file, line, addflag)
+ calltab *ctab;
+ char *file;
+ unsigned line;
+ bool addflag;
+{
+ unsigned hash = line & (MAX_CALLERS - 1);
+ caller *c;
+
+ for (c = ctab->callers[hash]; c; c = c->next)
+ if ((c->line == line) && STR_EQ(c->file->name, file))
+ return c;
+ if (!addflag)
+ return NULL;
+ c = (caller*) alloc(sizeof(caller));
+ c->next = ctab->callers[hash];
+ c->file = findFile(file, TRUE);
+ c->line = line;
+ c->calls = 0;
+ c->frees = (calltab *) alloc(sizeof(calltab));
+ ctab->callers[hash] = c;
+ return c;
+}
+
+/*--------------------------------------------------- public
+ */
+
+char *
+dmalloc(file, line, size)
+ char *file;
+ unsigned line;
+ unsigned size;
+{
+ caller *c;
+ datum *d;
+
+ c = findCaller(&Callers, file, line, TRUE);
+ d = (datum *) malloc(sizeof(datum) + size);
+ d->size = size;
+ d->caller = ((char *)c) - memory;
+ c->calls++;
+ c->blocks++;
+ c->bytes += size;
+ return (char *) (d+1);
+}
+
+void
+dfree(file, line, ptr)
+ char *file;
+ unsigned line;
+ char *ptr;
+{
+ caller *c, *a;
+ datum *d;
+
+ d = (datum *) ptr; d--;
+ a = (caller *) (memory + d->caller);
+ a->bytes -= d->size;
+ a->blocks--;
+ c = findCaller(a->frees, file, line, TRUE);
+ c->calls++;
+ free((char*) d);
+}
+
+char *
+dcalloc(file, line, nelems, elsize)
+ char *file;
+ unsigned line;
+ unsigned nelems, elsize;
+{
+ unsigned size = (nelems * elsize);
+ char *ptr;
+
+ ptr = dmalloc(file, line, size);
+ bzero(ptr, size);
+ return ptr;
+}
+
+char *
+drealloc(file, line, ptr, size)
+ char *file;
+ unsigned line;
+ char *ptr;
+ unsigned size;
+{
+ caller *c, *a;
+ datum *d;
+
+ d = (datum *) ptr; d--;
+ /* fix up stats from allocation */
+ a = (caller *) (memory + d->caller);
+ a->bytes -= d->size;
+ a->blocks--;
+ /* we are a "freer" of this allocation */
+ c = findCaller(a->frees, file, line, TRUE);
+ c->calls++;
+ /* get new allocation and stat it */
+ c = findCaller(&Callers, file, line, TRUE);
+ d = (datum *) realloc((char *) d, sizeof(datum) + size);
+ d->size = size;
+ d->caller = ((char *)c) - memory;
+ c->calls++;
+ c->blocks++;
+ c->bytes += size;
+ return (char *) (d+1);
+}
+
+static void
+dmalloccallers(outf, prefix, ctab)
+ FILE *outf;
+ char *prefix;
+ calltab *ctab;
+{
+ /* this bizarre logic is to print all of a file's entries together */
+ filenam *f;
+
+ for (f = Files; f; f = f->next) {
+ int i;
+
+ for (i = MAX_CALLERS-1; i >= 0; i--) {
+ caller *c;
+
+ for (c = ctab->callers[i]; c; c = c->next) {
+ if (f != c->file)
+ continue;
+ fprintf(outf, "%s\"%s\":%u calls=%u",
+ prefix, c->file->name, c->line,
+ c->calls);
+ if (c->blocks || c->bytes)
+ fprintf(outf, " blocks=%u bytes=%u",
+ c->blocks, c->bytes);
+ fputc('\n', outf);
+ if (c->frees)
+ dmalloccallers(outf,
+ "\t\t", c->frees);
+ }
+ }
+ }
+}
+
+void
+dmallocstats(outf)
+ FILE *outf;
+{
+ fprintf(outf, "dallocstats [ private mem used=%u, avail=%u ]\n",
+ nextmem - memory, &memory[MAX_MEMORY] - nextmem);
+ dmalloccallers(outf, "\t", &Callers);
+}
+
+#endif /*DMALLOC*/
diff --git a/usr.sbin/named/dmalloc.h b/usr.sbin/named/dmalloc.h
new file mode 100644
index 0000000..54e68f9
--- /dev/null
+++ b/usr.sbin/named/dmalloc.h
@@ -0,0 +1,68 @@
+/* dmalloc - debugging layer on top of malloc
+ * vix 22mar92 [written]
+ *
+ * $Id: dmalloc.h,v 4.9.1.2 1993/09/08 00:01:17 vixie Exp $
+ */
+
+/*
+ * ++Copyright++
+ * -
+ * Copyright (c)
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#define malloc(s) dmalloc(__FILE__, __LINE__, s)
+#define free(p) dfree(__FILE__, __LINE__, p)
+#define calloc(n, s) dcalloc(__FILE__, __LINE__, n, s)
+#define realloc(p, s) drealloc(__FILE__, __LINE__, p, s)
+
+char *dmalloc(), *dcalloc(), *drealloc();
+void dfree(), dmallocstats();
diff --git a/usr.sbin/named/named.h b/usr.sbin/named/named.h
new file mode 100644
index 0000000..4e597d7
--- /dev/null
+++ b/usr.sbin/named/named.h
@@ -0,0 +1,19 @@
+/* named.h - include the local definitions in the right order
+ * vix 28aug93 [original]
+ *
+ * $Id: named.h,v 1.1 1993/09/08 04:57:40 vixie Exp $
+ */
+
+#include "../conf/portability.h"
+#include "../conf/options.h"
+
+#include "pathnames.h"
+
+#include "ns_defs.h"
+#include "db_defs.h"
+
+#include "ns_glob.h"
+#include "db_glob.h"
+
+#include "ns_func.h"
+#include "db_func.h"
diff --git a/usr.sbin/named/ns_defs.h b/usr.sbin/named/ns_defs.h
new file mode 100644
index 0000000..bb9f18f
--- /dev/null
+++ b/usr.sbin/named/ns_defs.h
@@ -0,0 +1,368 @@
+/*
+ * from ns.h 4.33 (Berkeley) 8/23/90
+ * $Id: ns_defs.h,v 1.12 1994/07/23 23:23:56 vixie Exp $
+ */
+
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+/*
+ * Global definitions for the name server.
+ */
+
+/*
+ * Effort has been expended here to make all structure members 32 bits or
+ * larger land on 32-bit boundaries; smaller structure members have been
+ * deliberately shuffled and smaller integer sizes chosen where possible
+ * to make sure this happens. This is all meant to avoid structure member
+ * padding which can cost a _lot_ of memory when you have hundreds of
+ * thousands of entries in your cache.
+ */
+
+/*
+ * 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 ([0..255]) */
+#define RETRYBASE 4 /* base time between retries */
+#define MAXCLASS 255 /* XXX - may belong elsewhere */
+#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 */
+#define MAXQSERIAL 4 /* max # of outstanding QSERIAL's */
+ /* (prevent "recursive" loops) */
+#define INIT_REFRESH 600 /* retry time for initial secondary */
+ /* contact (10 minutes) */
+#define NADDRECS 20 /* max addt'l rr's per resp */
+
+#define XFER_TIMER 120 /* named-xfer's connect timeout */
+#define MAX_XFER_TIME 60*60*2 /* max seconds for an xfer */
+#define XFER_TIME_FUDGE 10 /* MAX_XFER_TIME fudge */
+#define MAX_XFERS_RUNNING 10 /* default max value of xfers_running */
+#define MAX_XFERS_PERNS 2 /* max # of xfers per peer nameserver */
+
+#define ALPHA 0.7 /* How much to preserve 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 */
+
+ /* sequence-space arithmetic */
+#define SEQ_GT(a,b) ((int32_t)((a)-(b)) > 0)
+
+/* these fields are ordered to maintain word-alignment;
+ * be careful about changing them.
+ */
+struct zoneinfo {
+ 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_int32_t z_refresh; /* refresh interval */
+ u_int32_t z_retry; /* refresh retry interval */
+ u_int32_t z_expire; /* expiration time for cached info */
+ u_int32_t z_minimum; /* minimum TTL value */
+ u_int32_t z_serial; /* changes if zone modified */
+ char *z_source; /* source location of data */
+ time_t z_ftime; /* modification time of source file */
+ struct in_addr z_xaddr; /* override server for next xfer */
+ struct in_addr z_addr[NSMAX]; /* list of master servers for zone */
+ u_char z_addrcnt; /* number of entries in z_addr[] */
+ u_char z_type; /* type of zone; see below */
+ u_int16_t z_flags; /* state bits; see below */
+ pid_t z_xferpid; /* xfer child pid */
+ int z_class; /* class of zone */
+#ifdef SECURE_ZONES
+ struct netinfo *secure_nets; /* list of secure networks for zone */
+#endif
+};
+
+ /* zone types (z_type) */
+#define Z_NIL 0 /* zone slot not in use */
+#define Z_PRIMARY 1
+#define Z_SECONDARY 2
+#define Z_CACHE 3
+#define Z_STUB 4
+
+ /* zone state bits (16 bits) */
+#define Z_AUTH 0x0001 /* zone is authoritative */
+#define Z_NEED_XFER 0x0002 /* waiting to do xfer */
+#define Z_XFER_RUNNING 0x0004 /* asynch. xfer is running */
+#define Z_NEED_RELOAD 0x0008 /* waiting to do reload */
+#define Z_SYSLOGGED 0x0010 /* have logged timeout */
+#define Z_QSERIAL 0x0020 /* sysquery()'ing for serial number */
+#define Z_FOUND 0x0040 /* found in boot file when reloading */
+#define Z_INCLUDE 0x0080 /* set if include used in file */
+#define Z_DB_BAD 0x0100 /* errors when loading file */
+#define Z_TMP_FILE 0x0200 /* backup file for xfer is temporary */
+#ifdef ALLOW_UPDATES
+#define Z_DYNAMIC 0x0400 /* allow dynamic updates */
+#define Z_DYNADDONLY 0x0800 /* dynamic mode: add new data only */
+#define Z_CHANGED 0x1000 /* zone has changed */
+#endif /* ALLOW_UPDATES */
+
+ /* named_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 */
+
+#include <sys/time.h>
+
+/* XXX - "struct qserv" is deprecated in favor of "struct nameser" */
+struct qserv {
+ struct sockaddr_in
+ ns_addr; /* address of NS */
+ 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 */
+};
+
+/*
+ * Structure for recording info on forwarded or generated queries.
+ */
+struct qinfo {
+ u_int16_t q_id; /* id of query */
+ u_int16_t q_nsid; /* id of forwarded query */
+ struct sockaddr_in
+ q_from; /* requestor's address */
+ u_char *q_msg, /* the message */
+ *q_cmsg; /* the cname message */
+ int16_t q_msglen, /* len of message */
+ q_cmsglen; /* len of cname message */
+ int16_t q_dfd; /* UDP file descriptor */
+ struct fwdinfo *q_fwd; /* last forwarder used */
+ time_t q_time; /* time to retry */
+ time_t q_expire; /* time to expire */
+ struct qinfo *q_next; /* rexmit list (sorted by time) */
+ struct qinfo *q_link; /* storage list (random order) */
+ struct databuf *q_usedns[NSMAX]; /* databuf for NS that we've tried */
+ struct qserv q_addr[NSMAX]; /* addresses of NS's */
+#ifdef notyet
+ struct nameser *q_ns[NSMAX]; /* name servers */
+#endif
+ u_char q_naddr; /* number of addr's in q_addr */
+ u_char q_curaddr; /* last addr sent to */
+ u_char q_nusedns; /* number of elements in q_usedns[] */
+ u_int8_t q_flags; /* see below */
+ int16_t q_cname; /* # of cnames found */
+ int16_t q_nqueries; /* # of queries required */
+ struct qstream *q_stream; /* TCP stream, null if UDP */
+ struct zoneinfo *q_zquery; /* Zone query is about (Q_ZSERIAL) */
+#ifdef LAME_DELEGATION
+ char q_domain[MAXDNAME]; /* domain for servers we are querying */
+#endif /* LAME_DELEGATION */
+};
+
+ /* q_flags bits (8 bits) */
+#define Q_SYSTEM 0x01 /* is a system query */
+#define Q_PRIMING 0x02 /* generated during priming phase */
+#define Q_ZSERIAL 0x04 /* getting zone serial for xfer test */
+
+#define Q_NEXTADDR(qp,n) \
+ (((qp)->q_fwd == (struct fwdinfo *)0) ? \
+ &(qp)->q_addr[n].ns_addr : &(qp)->q_fwd->fwdaddr)
+
+#define RETRY_TIMEOUT 45
+#define QINFO_NULL ((struct qinfo *)0)
+
+/*
+ * 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 */
+ u_char *s_buf; /* buffer of received data */
+ u_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_int32_t s_time; /* time stamp of last transaction */
+ int s_refcnt; /* number of outstanding queries */
+ u_int16_t s_tempsize; /* temporary for size from net */
+};
+#define QSTREAM_NULL ((struct qstream *)0)
+
+struct qdatagram {
+ int dq_dfd; /* datagram file descriptor */
+ time_t dq_gen; /* generation number */
+ struct qdatagram
+ *dq_next; /* next datagram */
+ struct in_addr dq_addr; /* interface address */
+};
+#define QDATAGRAM_NULL ((struct qdatagram *)0)
+
+struct netinfo {
+ struct netinfo *next;
+ u_int32_t addr;
+ u_int32_t mask;
+ struct in_addr my_addr;
+};
+
+#define ALLOW_NETS 0x0001
+#define ALLOW_HOSTS 0x0002
+#define ALLOW_ALL (ALLOW_NETS | ALLOW_HOSTS)
+
+struct fwdinfo {
+ struct fwdinfo *next;
+ struct sockaddr_in
+ fwdaddr;
+};
+
+enum nameserStats { nssRcvdQ, /* sent us a query */
+ nssRcvdR, /* sent us an answer */
+ nssRcvdIQ, /* sent us an inverse query */
+ nssRcvdNXD, /* sent us a negative response */
+ nssRcvdFwdQ, /* sent us a query we had to fwd */
+ nssRcvdFwdR, /* sent us a response we had to fwd */
+ nssRcvdDupQ, /* sent us a retry */
+ nssRcvdDupR, /* sent us an extra answer */
+ nssRcvdFail, /* sent us a SERVFAIL */
+ nssRcvdFErr, /* sent us a FORMERR */
+ nssRcvdErr, /* sent us some other error */
+ nssRcvdTCP, /* sent us a query using TCP */
+ nssRcvdAXFR, /* sent us an AXFR */
+ nssRcvdLDel, /* sent us a lame delegation */
+ nssRcvdOpts, /* sent us some IP options */
+ nssSentSysQ, /* sent them a sysquery */
+ nssSentAns, /* sent them an answer */
+ nssSentFwdQ, /* fwdd a query to them */
+ nssSentFwdR, /* fwdd a response to them */
+ nssSentDupQ, /* sent them a retry */
+ nssSentFail, /* sent them a SERVFAIL */
+ nssSentFErr, /* sent them a FORMERR */
+ nssSendtoErr, /* error in sendto(2) */
+ nssLast };
+
+struct nameser {
+ struct in_addr addr; /* key */
+ u_long stats[nssLast]; /* statistics */
+#ifdef notyet
+ u_int32_t rtt; /* round trip time */
+ /* XXX - need to add more stuff from "struct qserv", and use our rtt */
+ u_int16_t flags; /* see below */
+#endif
+ u_int8_t xfers; /* #/xfers running right now */
+};
+
+
+#ifdef NCACHE
+#define NOERROR_NODATA 6 /* only used internally by the server, used for
+ * -ve $ing non-existence of records. 6 is not
+ * a code used as yet anyway. anant@isi.edu
+ */
+#define NTTL 600 /* ttl for negative data: 10 minutes? */
+#endif /*NCACHE*/
+
+#define VQEXPIRY 900 /* a VQ entry expires in 15*60 = 900 seconds */
+
+#ifdef VALIDATE
+
+#define INVALID 0
+#define VALID_NO_CACHE 1
+#define VALID_CACHE 2
+#define MAXNAMECACHE 100
+#define MAXVQ 100 /* Max number of elements in TO_Validate queue */
+
+struct _nameaddr {
+ struct in_addr ns_addr;
+ char *nsname;
+};
+typedef struct _nameaddr NAMEADDR;
+
+struct _to_validate {
+ int16_t class; /* Name Class */
+ int16_t type; /* RR type */
+ char *data; /* RR data */
+ char *dname; /* Name */
+ time_t time; /* time at which inserted in queue */
+ struct _to_validate
+ *next,
+ *prev;
+};
+typedef struct _to_validate TO_Validate;
+
+#endif /*VALIDATE*/
+
+
+#ifdef DEBUG
+# define dprintf(lev, args) ((debug >= lev) && fprintf args)
+#else
+# define dprintf(lev, args)
+#endif
+
+
+#ifdef INIT
+ error "INIT already defined, check system include files"
+#endif
+#ifdef DECL
+ error "DECL already defined, check system include files"
+#endif
+
+#ifdef MAIN_PROGRAM
+#define INIT(x) = x
+#define DECL
+#else
+#define INIT(x)
+#define DECL extern
+#endif
diff --git a/usr.sbin/named/ns_forw.c b/usr.sbin/named/ns_forw.c
new file mode 100644
index 0000000..5745964
--- /dev/null
+++ b/usr.sbin/named/ns_forw.c
@@ -0,0 +1,909 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_forw.c 4.32 (Berkeley) 3/3/91";
+static char rcsid[] = "$Id: ns_forw.c,v 4.9.1.17 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <syslog.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "named.h"
+
+/*
+ * 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 or if asked to do something
+ * dangerous, such as fwd to ourselves or fwd to the host that asked us.
+ *
+ * (no action is taken on errors and qpp is not filled in.)
+ */
+int
+ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp, dname, np)
+ struct databuf *nsp[];
+ u_char *msg;
+ int msglen;
+ struct sockaddr_in *fp;
+ struct qstream *qsp;
+ int dfd;
+ struct qinfo **qpp;
+ char *dname;
+ struct namebuf *np;
+{
+ register struct qinfo *qp;
+ struct sockaddr_in *nsa;
+ HEADER *hp;
+ u_int16_t id;
+ int n;
+
+ dprintf(3, (ddt, "ns_forw()\n"));
+
+ 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))) {
+ dprintf(3, (ddt,
+ "forw: dropped DUP id=%d\n", ntohs(id)));
+ nameserIncr(fp->sin_addr, nssRcvdDupQ);
+ return (FW_DUP);
+ }
+ }
+
+ qp = qnew();
+#ifdef LAME_DELEGATION
+ getname(np, qp->q_domain, sizeof qp->q_domain);
+#endif
+ qp->q_from = *fp; /* nslookup wants to know this */
+ if ((n = nslookup(nsp, qp, dname, "ns_forw")) < 0) {
+ dprintf(2, (ddt, "forw: nslookup reports danger\n"));
+ qfree(qp);
+ return (FW_SERVFAIL);
+ } else if (n == 0 && !(forward_only && fwdtab)) {
+ dprintf(2, (ddt, "forw: no nameservers found\n"));
+ 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;
+ qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2;
+ hp->id = qp->q_nsid = htons((u_int16_t)++nsid);
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ if ((qp->q_msg = (u_char *)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;
+ }
+
+#ifdef SLAVE_FORWARD
+ if (forward_only)
+ schedretry(qp, (time_t)slave_retry);
+ else
+#endif /* SLAVE_FORWARD */
+ schedretry(qp, qp->q_fwd ?(2*RETRYBASE) :retrytime(qp));
+
+ nsa = Q_NEXTADDR(qp, 0);
+ dprintf(1, (ddt,
+ "forw: forw -> [%s].%d ds=%d nsid=%d id=%d %dms retry %dsec\n",
+ inet_ntoa(nsa->sin_addr),
+ ntohs(nsa->sin_port), ds,
+ ntohs(qp->q_nsid), ntohs(qp->q_id),
+ (qp->q_addr[0].nsdata != NULL)
+ ? qp->q_addr[0].nsdata->d_nstime
+ : -1,
+ qp->q_time - tt.tv_sec));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(msg, ddt);
+#endif
+ if (sendto(ds, msg, msglen, 0, (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0) {
+ if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr))
+ syslog(LOG_NOTICE, "ns_forw: sendto([%s].%d): %m",
+ inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port));
+ nameserIncr(nsa->sin_addr, nssSendtoErr);
+ }
+ nameserIncr(fp->sin_addr, nssRcvdFwdQ);
+ nameserIncr(nsa->sin_addr, nssSentFwdQ);
+ if (qpp)
+ *qpp = qp;
+ hp->rd = 1;
+ return (0);
+}
+
+/* struct qdatagram *
+ * aIsUs(addr)
+ * scan the datagramq (our list of interface addresses) for "addr"
+ * returns:
+ * pointer to qdatagram entry or NULL if no match is found
+ * notes:
+ * INADDR_ANY ([0.0.0.0]) is on the datagramq, so it's considered "us"
+ * author:
+ * Paul Vixie (DECWRL) April 1991
+ */
+struct qdatagram *
+aIsUs(addr)
+ struct in_addr addr;
+{
+ struct qdatagram *dqp;
+
+ for (dqp = datagramq; dqp != QDATAGRAM_NULL; dqp = dqp->dq_next) {
+ if (addr.s_addr == dqp->dq_addr.s_addr) {
+ return dqp;
+ }
+ }
+ return NULL;
+}
+
+/* haveComplained(tag1, tag2)
+ * check to see if we have complained about (tag1,tag2) recently
+ * (note that these are declared as pointers but are never deref'd)
+ * returns:
+ * boolean: have we complained recently?
+ * side-effects:
+ * outdated complaint records removed from our static list
+ * author:
+ * Paul Vixie (DECWRL) April 1991
+ */
+int
+haveComplained(tag1, tag2)
+ char *tag1, *tag2;
+{
+ struct complaint {
+ char *tag1, *tag2;
+ time_t expire;
+ struct complaint *next;
+ };
+ static struct complaint *List = NULL;
+ struct complaint *cur, *next, *prev;
+ int r = 0;
+
+ for (cur = List, prev = NULL; cur; prev = cur, cur = next) {
+ next = cur->next;
+ if (tt.tv_sec > cur->expire) {
+ if (prev)
+ prev->next = next;
+ else
+ List = next;
+ free((char*) cur);
+ cur = prev;
+ } else if ((tag1 == cur->tag1) && (tag2 == cur->tag2)) {
+ r++;
+ }
+ }
+ if (!r) {
+ cur = (struct complaint *)malloc(sizeof(struct complaint));
+ cur->tag1 = tag1;
+ cur->tag2 = tag2;
+ cur->expire = tt.tv_sec + INIT_REFRESH; /* "10 minutes" */
+ cur->next = NULL;
+ if (prev)
+ prev->next = cur;
+ else
+ List = cur;
+ }
+ return r;
+}
+
+/* void
+ * nslookupComplain(sysloginfo, queryname, complaint, dname, a_rr)
+ * Issue a complaint about a dangerous situation found by nslookup().
+ * params:
+ * sysloginfo is a string identifying the complainant.
+ * queryname is the domain name associated with the problem.
+ * complaint is a string describing what is wrong.
+ * dname and a_rr are the problematic other name server.
+ */
+void
+nslookupComplain(sysloginfo, queryname, complaint, dname, a_rr)
+ char *sysloginfo, *queryname, *complaint, *dname;
+ register struct databuf *a_rr;
+{
+ dprintf(2, (ddt, "NS '%s' %s\n", dname, complaint));
+ if (sysloginfo && queryname && !haveComplained(queryname, complaint))
+ {
+ char buf[512];
+
+ /* syslog only takes 5 params */
+ sprintf(buf, "%s: query(%s) %s (%s:%s)",
+ sysloginfo, queryname,
+ complaint, dname, inet_ntoa(
+ *(struct in_addr*)a_rr->d_data
+ ));
+ syslog(LOG_INFO, buf);
+ }
+}
+
+/*
+ * nslookup(nsp, qp, syslogdname, sysloginfo)
+ * Lookup the address for each nameserver in `nsp' and add it to
+ * the list saved in the qinfo structure pointed to by `qp'.
+ * Omits information about nameservers that we shouldn't ask.
+ * Detects the following dangerous operations:
+ * One of the A records for one of the nameservers in nsp
+ * refers to the address of one of our own interfaces;
+ * One of the A records refers to the nameserver port on
+ * the host that asked us this question.
+ * returns: the number of addresses added, or -1 if a dangerous operation
+ * is detected.
+ * side effects:
+ * if a dangerous situation is detected and (syslogdname && sysloginfo),
+ * calls syslog.
+ */
+int
+nslookup(nsp, qp, syslogdname, sysloginfo)
+ struct databuf *nsp[];
+ register struct qinfo *qp;
+ char *syslogdname;
+ char *sysloginfo;
+{
+ register struct namebuf *np;
+ register struct databuf *dp, *nsdp;
+ register struct qserv *qs;
+ register int n;
+ register unsigned int i;
+ struct hashbuf *tmphtp;
+ char *dname, *fname;
+ int oldn, naddr, class, found_arr;
+ time_t curtime;
+
+ dprintf(3, (ddt, "nslookup(nsp=0x%x, qp=0x%x, \"%s\")\n",
+ nsp, qp, syslogdname));
+
+ naddr = n = qp->q_naddr;
+ curtime = (u_long) tt.tv_sec;
+ while ((nsdp = *nsp++) != NULL) {
+ class = nsdp->d_class;
+ dname = (char *)nsdp->d_data;
+ dprintf(3, (ddt, "nslookup: NS \"%s\" c=%d t=%d (0x%x)\n",
+ dname, class, nsdp->d_type, nsdp->d_flags));
+
+ /* don't put in servers we have tried */
+ for (i = 0; i < qp->q_nusedns; i++) {
+ if (qp->q_usedns[i] == nsdp) {
+ dprintf(2, (ddt,
+ "skipping used NS w/name %s\n",
+ nsdp->d_data));
+ goto skipserver;
+ }
+ }
+
+ tmphtp = ((nsdp->d_flags & DB_F_HINT) ?fcachetab :hashtab);
+ np = nlookup(dname, &tmphtp, &fname, 1);
+ if (np == NULL || fname != dname) {
+ dprintf(3, (ddt, "%s: not found %s %x\n",
+ dname, fname, np));
+ continue;
+ }
+ found_arr = 0;
+ oldn = n;
+
+ /* look for name server addresses */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ struct in_addr nsa;
+
+ if (dp->d_type == T_CNAME && dp->d_class == class)
+ goto skipserver;
+ if (dp->d_type != T_A || dp->d_class != class)
+ continue;
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ /*
+ * 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) )
+ {
+ dprintf(3, (ddt,
+ "nslookup: stale entry '%s'\n",
+ np->n_dname));
+ /* Cache invalidate the NS RR's */
+ if (dp->d_ttl < curtime)
+ delete_all(np, class, T_A);
+ n = oldn;
+ break;
+ }
+#ifdef VALIDATE
+ /* anant@isi.edu validation procedure, maintains a
+ * table of server names-addresses used recently
+ */
+ store_name_addr(dname, (struct in_addr *)dp->d_data,
+ syslogdname, sysloginfo);
+#endif /*VALIDATE*/
+
+ found_arr++;
+ nsa = *(struct in_addr *)dp->d_data;
+ /* don't put in duplicates */
+ qs = qp->q_addr;
+ for (i = 0; i < n; i++, qs++)
+ if (qs->ns_addr.sin_addr.s_addr == nsa.s_addr)
+ goto skipaddr;
+ qs->ns_addr.sin_family = AF_INET;
+ qs->ns_addr.sin_port = ns_port;
+ qs->ns_addr.sin_addr = nsa;
+ qs->ns = nsdp;
+ qs->nsdata = dp;
+ qs->nretry = 0;
+ /*
+ * if we are being asked to fwd a query whose
+ * nameserver list includes our own name/address(es),
+ * then we have detected a lame delegation and rather
+ * than melt down the network and hose down the other
+ * servers (who will hose us in return), we'll return
+ * -1 here which will cause SERVFAIL to be sent to
+ * the client's resolver which will hopefully then
+ * shut up.
+ *
+ * (originally done in nsContainsUs by vix@dec mar92;
+ * moved into nslookup by apb@und jan1993)
+ */
+ if (aIsUs(nsa)) {
+ static char *complaint = "contains our address";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp);
+ return (-1);
+ }
+ /*
+ * If we want to forward to a host that asked us
+ * this question then either we or they are sick
+ * (unless they asked from some port other than
+ * their nameserver port). (apb@und jan1993)
+ */
+ if (bcmp((char *)&qp->q_from, (char *)&qs->ns_addr,
+ sizeof(qp->q_from)) == 0)
+ {
+ static char *complaint = "forwarding loop";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp);
+ return (-1);
+ }
+ /*
+ * Don't forward queries to bogus servers. Note
+ * that this is unlike the previous tests, which
+ * are fatal to the query. Here we just skip the
+ * server, which is only fatal if it's the last
+ * server. Note also that we antialias here -- all
+ * A RR's of a server are considered the same server,
+ * and if any of them is bogus we skip the whole
+ * server. Those of you using multiple A RR's to
+ * load-balance your servers will (rightfully) lose
+ * here. But (unfortunately) only if they are bogus.
+ */
+ if (addr_on_netlist(nsa, boglist))
+ goto skipserver;
+
+ n++;
+ if (n >= NSMAX)
+ goto out;
+ skipaddr: ;
+ }
+ dprintf(8, (ddt, "nslookup: %d ns addrs\n", n));
+ if (found_arr == 0 && !(qp->q_flags & Q_SYSTEM))
+ (void) sysquery(dname, class, T_A, NULL, 0);
+skipserver: ;
+ }
+out:
+ dprintf(3, (ddt, "nslookup: %d ns addrs total\n", n));
+ qp->q_naddr = n;
+#ifdef DATUMREFCNT
+ /* must be run before the sort */
+ for (i = naddr ; i < n ; i++) {
+ qp->q_addr[i].nsdata->d_rcnt++;
+ qp->q_addr[i].ns->d_rcnt++;
+ }
+#endif
+ if (n > 1) {
+ qsort((char *)qp->q_addr, n, sizeof(struct qserv),
+ (int (*)__P((const void *, const void *)))qcomp);
+ }
+ return (n - naddr);
+}
+
+/*
+ * qcomp - compare two NS addresses, and return a negative, zero, or
+ * positive value depending on whether the first NS address is
+ * "better than", "equally good as", or "inferior to" the second
+ * NS address.
+ *
+ * How "goodness" is defined (for the purposes of this routine):
+ * - If the estimated round trip times differ by an amount deemed significant
+ * then the one with the smaller estimate is preferred; else
+ * - If we can determine which one is topologically closer then the
+ * closer one is preferred; else
+ * - The one with the smaller estimated round trip time is preferred
+ * (zero is returned if the two estimates are identical).
+ *
+ * How "topological closeness" is defined (for the purposes of this routine):
+ * Ideally, named could consult some magic map of the Internet and
+ * determine the length of the path to an arbitrary destination. Sadly,
+ * no such magic map exists. However, named does have a little bit of
+ * topological information in the form of the sortlist (which includes
+ * the directly connected subnet(s), the directly connected net(s), and
+ * any additional nets that the administrator has added using the "sortlist"
+ * directive in the bootfile. Thus, if only one of the addresses matches
+ * something in the sortlist then it is considered to be topologically
+ * closer. If both match, but match different entries in the sortlist,
+ * then the one that matches the entry closer to the beginning of the
+ * sorlist is considered to be topologically closer. In all other cases,
+ * topological closeness is ignored because it's either indeterminate or
+ * equal.
+ *
+ * How times are compared:
+ * Both times are rounded to the closest multiple of the NOISE constant
+ * defined below and then compared. If the rounded values are equal
+ * then the difference in the times is deemed insignificant. Rounding
+ * is used instead of merely taking the absolute value of the difference
+ * because doing the latter would make the ordering defined by this
+ * routine be incomplete in the mathematical sense (e.g. A > B and
+ * B > C would not imply A > C). The mathematics are important in
+ * practice to avoid core dumps in qsort().
+ *
+ * XXX: this doesn't solve the European root nameserver problem very well.
+ * XXX: we should detect and mark as inferior nameservers that give bogus
+ * answers
+ *
+ * (this was originally vixie's stuff but almquist fixed fatal bugs in it
+ * and wrote the above documentation)
+ */
+
+/*
+ * RTT delta deemed to be significant, in milliseconds. With the current
+ * definition of RTTROUND it must be a power of 2.
+ */
+#define NOISE 128 /* milliseconds; 0.128 seconds */
+
+#define sign(x) (((x) < 0) ? -1 : ((x) > 0) ? 1 : 0)
+#define RTTROUND(rtt) (((rtt) + (NOISE >> 1)) & ~(NOISE - 1))
+
+int
+qcomp(qs1, qs2)
+ struct qserv *qs1, *qs2;
+{
+ int pos1, pos2, pdiff;
+ u_long rtt1, rtt2;
+ long tdiff;
+
+ if ((!qs1->nsdata) || (!qs2->nsdata))
+ return 0;
+ rtt1 = qs1->nsdata->d_nstime;
+ rtt2 = qs2->nsdata->d_nstime;
+
+ dprintf(10, (ddt, "qcomp(%s, %s) %lu (%lu) - %lu (%lu) = %lu",
+ inet_ntoa(qs1->ns_addr.sin_addr),
+ inet_ntoa(qs2->ns_addr.sin_addr),
+ rtt1, RTTROUND(rtt1), rtt2, RTTROUND(rtt2),
+ rtt1 - rtt2));
+ if (RTTROUND(rtt1) == RTTROUND(rtt2)) {
+ pos1 = position_on_netlist(qs1->ns_addr.sin_addr, nettab);
+ pos2 = position_on_netlist(qs2->ns_addr.sin_addr, nettab);
+ pdiff = pos1 - pos2;
+ dprintf(10, (ddt, ", pos1=%d, pos2=%d\n", pos1, pos2));
+ if (pdiff)
+ return (pdiff);
+ } else {
+ dprintf(10, (ddt, "\n"));
+ }
+ tdiff = rtt1 - rtt2;
+ return (sign(tdiff));
+}
+#undef sign
+#undef RTTROUND
+
+/*
+ * Arrange that forwarded query (qp) is retried after t seconds.
+ * Query list will be sorted after z_time is updated.
+ */
+void
+schedretry(qp, t)
+ struct qinfo *qp;
+ time_t t;
+{
+ register struct qinfo *qp1, *qp2;
+
+#ifdef DEBUG
+ if (debug > 3) {
+ fprintf(ddt,"schedretry(0x%x, %ld sec)\n", qp, (long)t);
+ if (qp->q_time)
+ fprintf(ddt,
+ "WARNING: schedretry(%#x, %d) q_time already %d\n",
+ qp, t, 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.
+ */
+void
+unsched(qp)
+ struct qinfo *qp;
+{
+ register struct qinfo *np;
+
+ dprintf(3, (ddt, "unsched(%#x, %d )\n", qp, ntohs(qp->q_id)));
+ 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'.
+ */
+void
+retry(qp)
+ register struct qinfo *qp;
+{
+ register int n;
+ register HEADER *hp;
+ struct sockaddr_in *nsa;
+
+ dprintf(3, (ddt, "retry(x%x) id=%d\n", qp, ntohs(qp->q_id)));
+
+ if (qp->q_msg == NULL) { /* XXX - why? */
+ qremove(qp);
+ return;
+ }
+
+ if (qp->q_expire && (qp->q_expire < tt.tv_sec)) {
+ dprintf(1, (ddt,
+ "retry(x%x): expired @ %d (%d secs before now (%d))\n",
+ qp, qp->q_expire, tt.tv_sec - qp->q_expire,
+ tt.tv_sec));
+ if (qp->q_stream) /* return failure code on stream */
+ goto fail;
+ qremove(qp);
+ return;
+ }
+
+ /* 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 >= (int)qp->q_naddr)
+ n = 0;
+ if (qp->q_addr[n].nretry < MAXRETRY)
+ goto found;
+ } while (n != qp->q_curaddr);
+ }
+fail:
+ /*
+ * Give up. Can't reach destination.
+ */
+ hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg);
+ if (qp->q_flags & Q_PRIMING) {
+ /* 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 < (int)qp->q_naddr; n++)
+ qp->q_addr[n].nretry = 0;
+ return;
+ }
+ dprintf(5, (ddt, "give up\n"));
+ 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((u_char *)hp, n, qp)) {
+ dprintf(1, (ddt,"gave up retry(x%x) nsid=%d id=%d\n",
+ qp, ntohs(qp->q_nsid), ntohs(qp->q_id)));
+ }
+ nameserIncr(qp->q_from.sin_addr, nssSentFail);
+ 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);
+ nsa = Q_NEXTADDR(qp, n);
+ dprintf(1, (ddt,
+ "%s(addr=%d n=%d) -> [%s].%d ds=%d nsid=%d id=%d %dms\n",
+ (qp->q_fwd ? "reforw" : "resend"),
+ n, qp->q_addr[n].nretry,
+ inet_ntoa(nsa->sin_addr),
+ ntohs(nsa->sin_port), ds,
+ ntohs(qp->q_nsid), ntohs(qp->q_id),
+ (qp->q_addr[n].nsdata != 0)
+ ? qp->q_addr[n].nsdata->d_nstime
+ : (-1)));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(qp->q_msg, ddt);
+#endif
+ /* NOSTRICT */
+ if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0) {
+ dprintf(3, (ddt, "error resending msg errno=%d\n", errno));
+ }
+ hp->rd = 1; /* leave set to 1 for dup detection */
+ nameserIncr(nsa->sin_addr, nssSentDupQ);
+ unsched(qp);
+#ifdef SLAVE_FORWARD
+ if(forward_only)
+ schedretry(qp, (time_t)slave_retry);
+ else
+#endif /* SLAVE_FORWARD */
+ 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)
+ struct qinfo *qp;
+{
+ time_t t, u, v;
+ struct qserv *ns = &qp->q_addr[qp->q_curaddr];
+
+ if (ns->nsdata != NULL)
+ t = (time_t) MAX(RETRYBASE, 2 * ns->nsdata->d_nstime / 1000);
+ else
+ t = (time_t) RETRYBASE;
+ u = t << ns->nretry;
+ v = MIN(u, RETRY_TIMEOUT); /* max. retry timeout for now */
+ dprintf(3, (ddt, "retrytime: nstime%ldms t%ld nretry%ld u%ld : v%ld\n",
+ ns->nsdata ?(long)(ns->nsdata->d_nstime / 1000) :(long)-1,
+ (long)t, (long)ns->nretry, (long)u, (long)v));
+ return (v);
+}
+
+void
+qflush()
+{
+ while (qhead)
+ qremove(qhead);
+ qhead = QINFO_NULL;
+}
+
+void
+qremove(qp)
+ register struct qinfo *qp;
+{
+ dprintf(3, (ddt, "qremove(x%x)\n", qp));
+
+ if (qp->q_flags & Q_ZSERIAL)
+ qserial_answer(qp, 0);
+ unsched(qp);
+ qfree(qp);
+}
+
+#if defined(__STDC__) || defined(__GNUC__)
+struct qinfo *
+qfindid(u_int16_t id)
+#else
+struct qinfo *
+qfindid(id)
+ register u_int16_t id;
+#endif
+{
+ register struct qinfo *qp;
+
+ dprintf(3, (ddt, "qfindid(%d)\n", ntohs(id)));
+ for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
+ if (qp->q_nsid == id)
+ return(qp);
+ }
+ dprintf(5, (ddt, "qp not found\n"));
+ return (NULL);
+}
+
+struct qinfo *
+#ifdef DMALLOC
+qnew_tagged(file, line)
+ char *file;
+ int line;
+#else
+qnew()
+#endif
+{
+ register struct qinfo *qp;
+
+ if ((qp = (struct qinfo *)
+#ifdef DMALLOC
+ dcalloc(file, line,
+#else
+ calloc(
+#endif
+ 1, sizeof(struct qinfo))) == NULL) {
+ dprintf(5, (ddt, "qnew: calloc error\n"));
+ syslog(LOG_ERR, "forw: %m");
+ exit(12);
+ }
+ dprintf(5, (ddt, "qnew(x%x)\n", qp));
+ qp->q_link = qhead;
+ qhead = qp;
+ return (qp);
+}
+
+void
+qfree(qp)
+ struct qinfo *qp;
+{
+ register struct qinfo *np;
+ register struct databuf *dp;
+#ifdef DATUMREFCNT
+ int i;
+#endif
+
+#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);
+#ifdef DATUMREFCNT
+ for (i = 0 ; i < (int)qp->q_naddr ; i++) {
+ dp = qp->q_addr[i].ns;
+ if (dp)
+ if (--(dp->d_rcnt)) {
+ dprintf(3, (ddt, "qfree: ns %s rcnt %d\n",
+ dp->d_data,
+ dp->d_rcnt));
+ } else {
+ dprintf(3, (ddt, "qfree: ns %s rcnt %d delayed\n",
+ dp->d_data,
+ dp->d_rcnt));
+ free((char*)dp);
+ }
+ dp = qp->q_addr[i].nsdata;
+ if (dp)
+ if ((--(dp->d_rcnt))) {
+ dprintf(3, (ddt, "qfree: nsdata %08.8X rcnt %d\n",
+ *(int32_t *)(dp->d_data),
+ dp->d_rcnt));
+ } else {
+ dprintf(3, (ddt, "qfree: nsdata %08.8X rcnt %d delayed\n",
+ *(int32_t *)(dp->d_data),
+ dp->d_rcnt));
+ free((char*)dp);
+ }
+ }
+#endif
+ 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;
+ }
+ }
+ free((char *)qp);
+}
diff --git a/usr.sbin/named/ns_func.h b/usr.sbin/named/ns_func.h
new file mode 100644
index 0000000..eaff3bf
--- /dev/null
+++ b/usr.sbin/named/ns_func.h
@@ -0,0 +1,140 @@
+/* ns_func.h - declarations for ns_*.c's externally visible functions
+ *
+ * $Id: ns_func.h,v 1.12 1994/07/22 08:42:39 vixie Exp $
+ */
+
+/* ++from ns_resp.c++ */
+extern void ns_resp __P((u_char *, int)),
+ prime_cache __P((void)),
+ delete_all __P((struct namebuf *, int, int));
+extern struct qinfo *sysquery __P((char *, int, int,
+ struct in_addr *, int));
+extern int
+ doupdate __P((u_char *, int, u_char *, int,
+ struct databuf **, int, u_int)),
+ send_msg __P((u_char *, int, struct qinfo *)),
+ findns __P((struct namebuf **, int,
+ struct databuf **, int *, int)),
+ finddata __P((struct namebuf *, int, int, HEADER *,
+ char **, int *, int *)),
+ wanted __P((struct databuf *, int, int)),
+ add_data __P((struct namebuf *,
+ struct databuf **,
+ u_char *, int));
+/* --from ns_resp.c-- */
+
+/* ++from ns_req.c++ */
+extern void ns_req __P((u_char *, int, int,
+ struct qstream *,
+ struct sockaddr_in *,
+ int));
+extern int stale __P((struct databuf *)),
+ make_rr __P((char *, struct databuf *,
+ u_char *, int, int)),
+ doaddinfo __P((HEADER *, u_char *, int)),
+ doaddauth __P((HEADER *, u_char *, int,
+ struct namebuf *,
+ struct databuf *));
+/* --from ns_req.c-- */
+
+/* ++from ns_forw.c++ */
+extern time_t retrytime __P((struct qinfo *));
+extern int ns_forw __P((struct databuf *nsp[],
+ u_char *msg,
+ int msglen,
+ struct sockaddr_in *fp,
+ struct qstream *qsp,
+ int dfd,
+ struct qinfo **qpp,
+ char *dname,
+ struct namebuf *np)),
+ haveComplained __P((char *, char *)),
+ nslookup __P((struct databuf *nsp[],
+ struct qinfo *qp,
+ char *syslogdname,
+ char *sysloginfo)),
+ qcomp __P((struct qserv *, struct qserv *));
+extern struct qdatagram *aIsUs __P((struct in_addr));
+extern void nslookupComplain __P((char *, char *, char *, char *,
+ struct databuf *)),
+ schedretry __P((struct qinfo *, time_t)),
+ unsched __P((struct qinfo *)),
+ retry __P((struct qinfo *)),
+ qflush __P((void)),
+ qremove __P((struct qinfo *)),
+ qfree __P((struct qinfo *));
+extern struct qinfo *qfindid __P((u_int16_t)),
+#ifdef DMALLOC
+ *qnew_tagged __P((void));
+# define qnew() qnew_tagged(__FILE__, __LINE__)
+#else
+ *qnew();
+#endif
+/* --from ns_forw.c-- */
+
+/* ++from ns_main.c++ */
+extern u_int32_t net_mask __P((struct in_addr));
+extern void sqrm __P((struct qstream *)),
+ sqflush __P((struct qstream *allbut)),
+ dqflush __P((time_t gen)),
+ sq_done __P((struct qstream *)),
+ ns_setproctitle __P((char *, int)),
+ getnetconf __P((void));
+extern struct netinfo *findnetinfo __P((struct in_addr));
+/* --from ns_main.c-- */
+
+/* ++from ns_maint.c++ */
+extern void ns_maint __P((void)),
+ sched_maint __P((void)),
+#ifdef CLEANCACHE
+ remove_zone __P((struct hashbuf *, int, int)),
+#else
+ remove_zone __P((struct hashbuf *, int)),
+#endif
+ loadxfer __P((void)),
+ qserial_answer __P((struct qinfo *, u_int32_t));
+extern SIG_FN endxfer __P((void));
+#ifdef DEBUG
+extern void printzoneinfo __P((int));
+#endif
+/* --from ns_maint.c-- */
+
+/* ++from ns_sort.c++ */
+extern struct netinfo *local __P((struct sockaddr_in *));
+extern void sort_response __P((u_char *, int,
+ struct netinfo *,
+ u_char *));
+/* --from ns_sort.c-- */
+
+/* ++from ns_init.c++ */
+extern void ns_init __P((char *));
+/* --from ns_init.c-- */
+
+/* ++from ns_ncache.c++ */
+extern void cache_n_resp __P((u_char *, int));
+/* --from ns_ncache.c-- */
+
+/* ++from ns_stats.c++ */
+extern void ns_stats __P((void));
+extern void qtypeIncr __P((int qtype));
+extern struct nameser *nameserFind __P((struct in_addr addr, int flags));
+#define NS_F_INSERT 0x0001
+extern void nameserIncr __P((struct in_addr addr,
+ enum nameserStats which));
+/* --from ns_stats.c-- */
+
+/* ++from ns_validate.c++ */
+extern int
+#ifdef NCACHE
+ validate __P((char *, struct sockaddr_in *,
+ int, int, char *, int, int)),
+#else
+ validate __P((char *, struct sockaddr_in *,
+ int, int, char *, int)),
+#endif
+ dovalidate __P((u_char *, int, u_char *, int, int,
+ struct sockaddr_in *, int *)),
+ update_msg __P((u_char *, int *, int Vlist[], int));
+extern void store_name_addr __P((char *, struct in_addr *,
+ char *, char *));
+/* --from ns_validate.c-- */
diff --git a/usr.sbin/named/ns_glob.h b/usr.sbin/named/ns_glob.h
new file mode 100644
index 0000000..993d14d
--- /dev/null
+++ b/usr.sbin/named/ns_glob.h
@@ -0,0 +1,245 @@
+/*
+ * from ns.h 4.33 (Berkeley) 8/23/90
+ * $Id: ns_glob.h,v 1.7 1994/06/11 22:04:46 vixie Exp $
+ */
+
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+/*
+ * Global variables for the name server.
+ */
+
+#ifdef DEBUG
+DECL int debug INIT(0);
+DECL FILE *ddt INIT(NULL);
+#endif
+
+ /* list of open streams */
+DECL struct qstream *streamq INIT(QSTREAM_NULL);
+
+ /* list of datagram interfaces */
+DECL struct qdatagram *datagramq INIT(QDATAGRAM_NULL);
+
+ /* often set to the current time */
+DECL struct timeval tt;
+
+ /* head of allocated queries */
+DECL struct qinfo *qhead INIT(QINFO_NULL);
+
+ /* list of forwarding hosts */
+DECL struct fwdinfo *fwdtab INIT(NULL);
+
+ /* next forwarded query id */
+DECL int nsid INIT(0);
+
+ /* datagram socket */
+DECL int ds INIT(-1);
+
+ /* listening TCP socket */
+DECL int vs INIT(-1);
+
+ /* received SIGHUP, need to reload db */
+DECL int needreload INIT(0);
+
+ /* need to call ns_maint()*/
+DECL int needmaint INIT(0);
+
+ /* how often does ns_maint() need to be called, in seconds? */
+ /* (beware: this is also the upper bound on named_xfer real time) */
+DECL int maint_interval INIT(15*60);
+
+ /* need to reload secondary zone(s) */
+DECL int needzoneload INIT(0);
+
+ /* need to dump database */
+DECL int needToDoadump INIT(0);
+
+ /* need to checkpoint cache */
+DECL int needToChkpt INIT(0);
+
+ /* need to dump statistics */
+DECL int needStatsDump INIT(0);
+
+#ifdef ALLOW_UPDATES
+ /* need to exit (may need to doadump
+ * first, if database has changed since
+ * it was last dumped/booted). Gets
+ * set by shutdown signal handler
+ * (onintr)
+ */
+DECL int needToExit INIT(0);
+#endif /* ALLOW_UPDATES */
+
+#ifdef QRYLOG
+ /* is query logging turned on? */
+DECL int qrylog INIT(0);
+#endif /*QRYLOG*/
+
+ /* is this a root server that should therefore not recurse? */
+DECL int NoRecurse INIT(0);
+
+/*
+ * We keep a list of favored networks headed by nettab.
+ * There are three (possibly empty) parts to this list, in this order:
+ * 1. directly attached (sub)nets.
+ * 2. logical networks for directly attached subnetted networks.
+ * 3. networks from the sort list.
+ * The value (*elocal) points at the first entry in the second part of the
+ * list, if any, while (*enettab) points at the first entry in the sort list.
+ */
+DECL struct netinfo *nettab INIT(NULL);
+DECL struct netinfo **elocal INIT(&nettab);
+DECL struct netinfo **enettab INIT(&nettab);
+
+#ifdef XFRNETS
+ /* list of nets we're willing to zone transfer to */
+DECL struct netinfo *xfrnets INIT(NULL);
+#endif
+
+#ifdef BOGUSNS
+ /* list of bogus nameservers */
+DECL struct netinfo *boglist INIT(NULL);
+#endif
+
+ /* loopback net */
+DECL struct netinfo netloop;
+
+ /* port to which we send queries */
+DECL u_int16_t ns_port;
+
+ /* Source addr of last packet */
+DECL struct sockaddr_in from_addr;
+
+ /* Source addr size of last packet */
+DECL int from_len;
+
+ /* Used by ns_stats */
+DECL time_t boottime,
+ resettime;
+
+ /* next query to retry */
+DECL struct qinfo *retryqp INIT(NULL);
+
+ /* default boot file */
+#ifdef BOOTFILE
+DECL char *bootfile INIT(BOOTFILE);
+#else
+DECL char *bootfile INIT(_PATH_BOOT);
+#endif
+
+ /* default debug output file */
+#ifdef DEBUGFILE
+DECL char *debugfile INIT(DEBUGFILE);
+#else
+DECL char *debugfile INIT(_PATH_DEBUG);
+#endif
+
+#ifdef WANT_PIDFILE
+ /* file to store current named PID */
+#ifdef PIDFILE
+DECL char *PidFile INIT(PIDFILE);
+#else
+DECL char *PidFile INIT(_PATH_PIDFILE);
+#endif
+#endif /*WANT_PIDFILE*/
+
+ /* zone information */
+DECL struct zoneinfo *zones INIT(NULL);
+
+ /* number of zones in use */
+DECL int nzones INIT(0);
+
+ /* true on slave server */
+DECL int forward_only INIT(0);
+
+ /* set if we need a priming */
+DECL int needs_prime_cache INIT(0);
+
+ /* is cache being primed */
+DECL int priming INIT(0);
+
+ /* ptrs to dnames in msg for dn_comp */
+DECL u_char *dnptrs[40];
+
+ /* number of names in addinfo */
+DECL int addcount;
+
+ /* name of cache file */
+DECL char *cache_file;
+
+#ifdef LOCALDOM
+ /* our local domain (deprecated in favor of resolv.conf) */
+DECL char *localdomain;
+#endif
+
+#ifdef SLAVE_FORWARD
+ /* retry time when a slave */
+DECL int slave_retry INIT(4);
+#endif
+
+#ifdef STATSFILE
+DECL char *statsfile INIT(STATSFILE);
+#else
+DECL char *statsfile INIT(_PATH_STATS);
+#endif
+
+DECL char sendtoStr[] INIT("sendto");
+
+ /* defined in version.c, can't use DECL/INIT */
+extern char Version[];
+
+ /* max value of xfers_running */
+DECL int max_xfers_running INIT(MAX_XFERS_RUNNING);
diff --git a/usr.sbin/named/ns_init.c b/usr.sbin/named/ns_init.c
new file mode 100644
index 0000000..82c2071
--- /dev/null
+++ b/usr.sbin/named/ns_init.c
@@ -0,0 +1,808 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_init.c 4.38 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id:";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1990
+ * -
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <syslog.h>
+#include <signal.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "named.h"
+
+#undef nsaddr
+
+static void zoneinit __P((struct zoneinfo *)),
+ get_forwarders __P((FILE *)),
+ boot_read __P((char *)),
+#ifdef DEBUG
+ content_zone __P((int)),
+#endif
+ free_forwarders __P((void));
+
+static struct zoneinfo *find_zone __P((char *, int, int));
+
+/*
+ * Read boot file for configuration info.
+ */
+void
+ns_init(bootfile)
+ char *bootfile;
+{
+ register struct zoneinfo *zp;
+ static int loads = 0; /* number of times loaded */
+
+ dprintf(1, (ddt, "\nns_init(%s)\n", bootfile));
+ gettime(&tt);
+
+ 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_flags &= ~Z_FOUND;
+#ifdef LOCALDOM
+ if (localdomain) {
+ free(localdomain);
+ localdomain = NULL;
+ }
+#endif
+ free_forwarders();
+ free_netlist(enettab);
+#ifdef XFRNETS
+ free_netlist(&xfrnets);
+#endif
+#ifdef BOGUSNS
+ free_netlist(&boglist);
+#endif
+ forward_only = 0;
+ }
+
+ dprintf(3, (ddt, "\n content of zones before loading \n"));
+#ifdef DEBUG
+ if (debug >= 3) {
+ content_zone(nzones - 1);
+ }
+#endif
+ boot_read(bootfile);
+
+ /* erase all old zones that were not found */
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++) {
+ if (zp->z_type && (zp->z_flags & Z_FOUND) == 0) {
+#ifdef CLEANCACHE
+ remove_zone(hashtab, zp - zones, 1);
+#else
+ remove_zone(hashtab, zp - zones);
+#endif
+#ifdef SECURE_ZONES
+ free_netlist(&zp->secure_nets);
+#endif
+ syslog(LOG_NOTICE, "Zone \"%s\" was removed", zp->z_origin);
+ free(zp->z_origin);
+ free(zp->z_source);
+ bzero((char *) zp, sizeof(*zp));
+ }
+ }
+ dprintf(2, (ddt,"\n content of zones after loading\n"));
+
+#ifdef DEBUG
+ if (debug >= 2) {
+ content_zone(nzones-1);
+ }
+#endif
+
+ /*
+ * Schedule calls to ns_maint().
+ */
+ if (!needmaint)
+ sched_maint();
+ dprintf(1, (ddt, "exit ns_init()%s\n",
+ needmaint ? ", need maintenance immediately" : ""));
+ loads++;
+}
+
+/*
+ * Read the actual boot file.
+ * Set up to recurse.
+ */
+static void
+boot_read(bootfile)
+ char *bootfile;
+{
+ register struct zoneinfo *zp;
+ char buf[BUFSIZ], obuf[BUFSIZ], *source;
+ FILE *fp;
+ int type;
+ int class;
+#ifdef GEN_AXFR
+ char *class_p;
+#endif
+ struct stat f_time;
+ static int tmpnum = 0; /* unique number for tmp zone files */
+#ifdef ALLOW_UPDATES
+ char *cp, *flag;
+#endif
+ int slineno; /* Saved global line number. */
+ int i;
+
+ if ((fp = fopen(bootfile, "r")) == NULL) {
+ syslog(LOG_ERR, "%s: %m", bootfile);
+ exit(1);
+ }
+
+ slineno = lineno;
+ lineno = 0;
+
+ 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_netlist(fp, enettab, ALLOW_NETS, buf);
+ continue;
+ } else if (strcasecmp(buf, "max-fetch") == 0) {
+ max_xfers_running = getnum(fp, bootfile, 0);
+ continue;
+ } else if (strcasecmp(buf, "forwarders") == 0) {
+ get_forwarders(fp);
+ continue;
+ } else if (strcasecmp(buf, "slave") == 0) {
+ forward_only++;
+ endline(fp);
+ continue;
+#ifdef BOGUSNS
+ } else if (strcasecmp(buf, "bogusns") == 0) {
+ get_netlist(fp, &boglist, ALLOW_HOSTS, buf);
+ continue;
+#endif
+#ifdef XFRNETS
+ } else if ((strcasecmp(buf, "tcplist") == 0) ||
+ (strcasecmp(buf, "xfrnets") == 0)) {
+ get_netlist(fp, &xfrnets, ALLOW_NETS, buf);
+ continue;
+#endif
+#ifdef LOCALDOM
+ } else if (strcasecmp(buf, "domain") == 0) {
+ if (getword(buf, sizeof(buf), fp))
+ localdomain = savestr(buf);
+ endline(fp);
+ continue;
+#endif
+ } else if (strcasecmp(buf, "include") == 0) {
+ if (getword(buf, sizeof(buf), fp))
+ boot_read(buf);
+ endline(fp);
+ continue;
+ } else if (strncasecmp(buf, "cache", 5) == 0) {
+ type = Z_CACHE;
+ class = C_IN;
+#ifdef GEN_AXFR
+ if (class_p = strchr(buf, '/'))
+ class = get_class(class_p+1);
+#endif
+ } else if (strncasecmp(buf, "primary", 7) == 0) {
+ type = Z_PRIMARY;
+ class = C_IN;
+#ifdef GEN_AXFR
+ if (class_p = strchr(buf, '/'))
+ class = get_class(class_p+1);
+#endif
+ } else if (strncasecmp(buf, "secondary", 9) == 0) {
+ type = Z_SECONDARY;
+ class = C_IN;
+#ifdef GEN_AXFR
+ if (class_p = strchr(buf, '/'))
+ class = get_class(class_p+1);
+#endif
+#ifdef STUBS
+ } else if (strncasecmp(buf, "stub", 4) == 0) {
+ type = Z_STUB;
+ class = C_IN;
+#ifdef GEN_AXFR
+ if (class_p = strchr(buf, '/'))
+ class = get_class(class_p+1);
+#endif
+#endif
+ } else {
+ syslog(LOG_ERR, "%s: line %d: unknown field '%s'\n",
+ bootfile, lineno+1, 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;
+ }
+ i = strlen(obuf);
+ if ((obuf[i-1] == '.') && (i != 1))
+ syslog(LOG_ERR, "%s: line %d: zone \"%s\" has trailing dot\n",
+ bootfile, lineno, obuf);
+ while ((--i >= 0) && (obuf[i] == '.'))
+ obuf[i] = '\0';
+ dprintf(1, (ddt, "zone origin %s", obuf[0]?obuf:"."));
+ /*
+ * read source file or host address
+ */
+ if (!getword(buf, sizeof(buf), fp)) {
+ syslog(LOG_ERR, "%s: line %d: missing %s\n",
+ bootfile, lineno,
+#ifdef STUBS
+ (type == Z_SECONDARY || type == Z_STUB)
+#else
+ (type == Z_SECONDARY)
+#endif
+ ?"host address"
+ :"source file");
+ continue;
+ }
+
+ /* check for previous instance of this zone (reload) */
+ if (!(zp = find_zone(obuf, type, class))) {
+ if (type == Z_CACHE) {
+ zp = &zones[0];
+ zp->z_origin = "";
+ goto gotcache;
+ }
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++)
+ if (zp->z_type == Z_NIL)
+ goto gotzone;
+ /*
+ * this code assumes that nzones never decreases
+ */
+ if (nzones % 64 == 0) {
+ dprintf(1, (ddt,
+ "Reallocating zones structure\n"));
+ /*
+ * Realloc() not used since it might damage zones
+ * if an error occurs
+ */
+ zp = (struct zoneinfo *)
+ malloc((64 + nzones)
+ * sizeof(struct zoneinfo));
+ if (zp == (struct zoneinfo *)0) {
+ syslog(LOG_ERR,
+ "no memory for more zones");
+ dprintf(1, (ddt,
+ "Out of memory for new zones\n"
+ )
+ );
+ 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);
+ gotcache:
+ zp->z_type = type;
+ zp->z_class = class;
+ }
+ zp->z_addrcnt = 0;
+
+ switch (type) {
+ case Z_CACHE:
+ source = savestr(buf);
+ dprintf(1, (ddt, ", source = %s\n", source));
+ 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) &&
+ !(zp->z_flags & Z_INCLUDE) &&
+ stat(zp->z_source, &f_time) != -1 &&
+ zp->z_ftime == f_time.st_mtime) {
+ dprintf(1, (ddt, "cache is up to date\n"));
+ if (source != cache_file)
+ free(source);
+ break; /* zone is already up to date */
+ }
+
+ /* file has changed, or hasn't been loaded yet */
+ if (zp->z_source) {
+ free(zp->z_source);
+#ifdef CLEANCACHE
+ remove_zone(fcachetab, 0, 1);
+#else
+ remove_zone(fcachetab, 0);
+#endif
+ }
+ zp->z_source = source;
+ dprintf(1, (ddt, "reloading zone\n"));
+ (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 = strchr(flag, ',');
+ if (cp)
+ *cp++ = 0;
+ if (strcasecmp(flag, "dynamic") == 0)
+ zp->z_flags |= Z_DYNAMIC;
+ else if (strcasecmp(flag, "addonly") == 0)
+ zp->z_flags |= Z_DYNADDONLY;
+ else {
+ syslog(LOG_ERR,
+ "%s: line %d: bad flag '%s'\n",
+ bootfile, lineno, flag);
+ }
+ flag = cp;
+ }
+ }
+#else /*ALLOW_UPDATES*/
+ endline(fp);
+#endif
+
+ dprintf(1, (ddt, ", source = %s\n", source));
+ /*
+ * 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) &&
+ !(zp->z_flags & Z_INCLUDE) &&
+ stat(zp->z_source, &f_time) != -1 &&
+ zp->z_ftime == f_time.st_mtime) {
+ dprintf(1, (ddt, "zone is up to date\n"));
+ free(source);
+ break; /* zone is already up to date */
+ }
+ if (zp->z_source) {
+ free(zp->z_source);
+#ifdef CLEANCACHE
+ remove_zone(hashtab, zp - zones, 1);
+#else
+ remove_zone(hashtab, zp - zones);
+#endif
+ }
+ zp->z_source = source;
+ zp->z_flags &= ~Z_AUTH;
+ dprintf(1, (ddt, "reloading zone\n"));
+ if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0)
+ zp->z_flags |= Z_AUTH;
+#ifdef ALLOW_UPDATES
+ /* Guarantee calls to ns_maint() */
+ zp->z_refresh = maint_interval;
+#else
+ zp->z_refresh = 0; /* no maintenance needed */
+ zp->z_time = 0;
+#endif
+ break;
+
+ case Z_SECONDARY:
+#ifdef STUBS
+ case Z_STUB:
+#endif
+ source = NULL;
+ dprintf(1, (ddt, "\n\taddrs: "));
+ do {
+ if (!inet_aton(buf,
+ &zp->z_addr[zp->z_addrcnt])
+ ) {
+ source = savestr(buf);
+ endline(fp);
+ break;
+ }
+ dprintf(1, (ddt, "%s, ", buf));
+ if ((int)++zp->z_addrcnt > NSMAX - 1) {
+ zp->z_addrcnt = NSMAX - 1;
+ dprintf(1, (ddt,
+ "\nns.h NSMAX reached\n"));
+ }
+ } while (getword(buf, sizeof(buf), fp));
+ dprintf(1, (ddt, "addrcnt = %d\n", zp->z_addrcnt));
+ if (!source) {
+ /*
+ * We will always transfer this zone again
+ * after a reload.
+ */
+ sprintf(buf, "/%s/NsTmp%d.%d", _PATH_TMPDIR,
+ getpid(), tmpnum++);
+ source = savestr(buf);
+ zp->z_flags |= Z_TMP_FILE;
+ } else
+ zp->z_flags &= ~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) ||
+ (stat(zp->z_source, &f_time) == -1 ||
+ (zp->z_ftime != f_time.st_mtime)))) {
+ dprintf(1, (ddt, "backup file changed\n"));
+ free(zp->z_source);
+ zp->z_source = NULL;
+ zp->z_flags &= ~Z_AUTH;
+ zp->z_serial = 0; /* force xfer */
+#ifdef CLEANCACHE
+ remove_zone(hashtab, zp - zones, 1);
+#else
+ remove_zone(hashtab, zp - zones);
+#endif
+ }
+ if (zp->z_source)
+ free(source);
+ else
+ zp->z_source = source;
+ if (!(zp->z_flags & Z_AUTH))
+ zoneinit(zp);
+#ifdef FORCED_RELOAD
+ else {
+ /*
+ ** Force secondary to try transfer right away
+ ** after SIGHUP.
+ */
+ if (reloading) {
+ zp->z_time = tt.tv_sec;
+ needmaint = 1;
+ }
+ }
+#endif /* FORCED_RELOAD */
+ break;
+
+ }
+ zp->z_flags |= Z_FOUND;
+ dprintf(1, (ddt, "zone[%d] type %d: '%s'",
+ zp-zones, type,
+ *(zp->z_origin) == '\0' ? "." : zp->z_origin));
+ 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;
+ dprintf(1, (ddt, " z_time %d, z_refresh %d\n",
+ zp->z_time, zp->z_refresh));
+ }
+ (void) my_fclose(fp);
+ lineno = slineno;
+}
+
+static void
+zoneinit(zp)
+ register struct zoneinfo *zp;
+{
+ 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)
+ 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_flags |= Z_AUTH;
+ }
+}
+
+#ifdef ALLOW_UPDATES
+/*
+ * Look for the authoritative zone with the longest matching RHS of dname
+ * and return its zone # or zero if not found.
+ */
+int
+findzone(dname, class)
+ char *dname;
+ int class;
+{
+ char *dZoneName, *zoneName;
+ int dZoneNameLen, zoneNameLen;
+ int maxMatchLen = 0;
+ int maxMatchZoneNum = 0;
+ int zoneNum;
+
+ dprintf(4, (ddt, "findzone(dname=%s, class=%d)\n", dname, class));
+#ifdef DEBUG
+ if (debug >= 5) {
+ fprintf(ddt, "zone dump:\n");
+ for (zoneNum = 1; zoneNum < nzones; zoneNum++)
+ printzoneinfo(zoneNum);
+ }
+#endif
+
+ dZoneName = strchr(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;
+ dprintf(5, (ddt, "about to strncasecmp('%s', '%s', %d)\n",
+ dZoneName, zoneName, dZoneNameLen));
+ if (strncasecmp(dZoneName, zoneName, dZoneNameLen) == 0) {
+ dprintf(5, (ddt, "match\n"));
+ /*
+ * 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;
+ }
+ } else {
+ dprintf(5, (ddt, "no match\n"));
+ }
+ }
+ dprintf(4, (ddt, "findzone: returning %d\n", maxMatchZoneNum));
+ return (maxMatchZoneNum);
+}
+#endif /* ALLOW_UPDATES */
+
+static void
+get_forwarders(fp)
+ FILE *fp;
+{
+ char buf[BUFSIZ];
+ register struct fwdinfo *fip = NULL, *ftp = NULL;
+
+#ifdef SLAVE_FORWARD
+ int forward_count = 0;
+#endif
+
+ dprintf(1, (ddt, "forwarders "));
+
+ /* on mulitple forwarder lines, move to end of the list */
+#ifdef SLAVE_FORWARD
+ if (fwdtab != NULL){
+ forward_count++;
+ for (fip = fwdtab; fip->next != NULL; fip = fip->next)
+ forward_count++;
+ }
+#else
+ if (fwdtab != NULL) {
+ for (fip = fwdtab; fip->next != NULL; fip = fip->next) {
+ ;
+ }
+ }
+#endif /* SLAVE_FORWARD */
+
+ while (getword(buf, sizeof(buf), fp)) {
+ if (strlen(buf) == 0)
+ break;
+ dprintf(1, (ddt," %s",buf));
+ if (ftp == NULL)
+ ftp = (struct fwdinfo *)malloc(sizeof(struct fwdinfo));
+ if (inet_aton(buf, &ftp->fwdaddr.sin_addr)) {
+ ftp->fwdaddr.sin_port = ns_port;
+ ftp->fwdaddr.sin_family = AF_INET;
+ } else {
+ syslog(LOG_ERR, "'%s' (ignored, NOT dotted quad)",
+ buf);
+ dprintf(1, (ddt, " (ignored, NOT dotted quad)"));
+ continue;
+ }
+#ifdef FWD_LOOP
+ if (aIsUs(ftp->fwdaddr.sin_addr)) {
+ syslog(LOG_ERR,
+ "Forwarder '%s' ignored, my address",
+ buf);
+ dprintf(1, (ddt, " (ignored, my address)"));
+ continue;
+ }
+#endif /* FWD_LOOP */
+ ftp->next = NULL;
+ if (fwdtab == NULL)
+ fwdtab = ftp; /* First time only */
+ else
+ fip->next = ftp;
+ fip = ftp;
+ ftp = NULL;
+#ifdef SLAVE_FORWARD
+ forward_count++;
+#endif /* SLAVE_FORWARD */
+ }
+ if (ftp)
+ free((char *)ftp);
+
+#ifdef SLAVE_FORWARD
+ /*
+ ** Set the slave retry time to 60 seconds total divided
+ ** between each forwarder
+ */
+ if (forward_count != 0) {
+ slave_retry = (int) (60 / forward_count);
+ if(slave_retry <= 0)
+ slave_retry = 1;
+ }
+#endif
+
+ dprintf(1, (ddt, "\n"));
+#ifdef DEBUG
+ 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
+}
+
+static void
+free_forwarders()
+{
+ register struct fwdinfo *ftp, *fnext;
+
+ for (ftp = fwdtab; ftp != NULL; ftp = fnext) {
+ fnext = ftp->next;
+ free((char *)ftp);
+ }
+ fwdtab = NULL;
+}
+
+static struct zoneinfo *
+find_zone(name, type, class)
+ char *name;
+ int type, class;
+{
+ register struct zoneinfo *zp;
+
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++) {
+ if (zp->z_type == type && zp->z_class == class &&
+ strcasecmp(name, zp->z_origin) == 0) {
+ dprintf(2, (ddt, ", old zone (%d)", zp - zones));
+ return (zp);
+ }
+ }
+ dprintf(2, (ddt, ", new zone"));
+ return NULL;
+}
+
+#ifdef DEBUG
+/* prints out the content of zones */
+static void
+content_zone(end)
+ int end;
+{
+ int i;
+
+ for (i = 1; i <= end; i++) {
+ printzoneinfo(i);
+ }
+}
+#endif
diff --git a/usr.sbin/named/ns_main.c b/usr.sbin/named/ns_main.c
new file mode 100644
index 0000000..8b04a49
--- /dev/null
+++ b/usr.sbin/named/ns_main.c
@@ -0,0 +1,1581 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_main.c 4.55 (Berkeley) 7/1/91";
+static char rcsid[] = "$Id: ns_main.c,v 4.9.1.19 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1989, 1990
+ * -
+ * Copyright (c) 1986, 1989, 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#if !defined(lint) && !defined(SABER)
+char copyright[] =
+"@(#) Copyright (c) 1986, 1989, 1990 The Regents of the University of California.\n\
+ portions Copyright (c) 1993 Digital Equipment Corporation\n\
+ portions Copyright (c) 1993 Berkeley Network Software Consortium\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * Internet Name server (see rfc883 & others).
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#if !defined(SYSV) && defined(XXX)
+#include <sys/wait.h>
+#endif /* !SYSV */
+#include <sys/time.h>
+#define TIME_H_INCLUDED
+#include <sys/resource.h>
+#if defined(__osf__)
+#define _SOCKADDR_LEN /* XXX - should be in portability.h but that
+ * would need to be included before socket.h
+ */
+#endif
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <errno.h>
+#include <signal.h>
+#include <netdb.h>
+#include <resolv.h>
+#if defined(SVR4)
+# include <sys/sockio.h>
+#endif
+
+#define MAIN_PROGRAM
+#include "named.h"
+#undef MAIN_PROGRAM
+
+#undef nsaddr
+
+ /* UDP receive, TCP send buffer size */
+static const int rbufsize = 8 * 1024;
+
+static struct sockaddr_in nsaddr;
+static u_int16_t local_ns_port; /* our service port */
+static fd_set mask; /* open descriptors */
+static char **Argv = NULL;
+static char *LastArg = NULL; /* end of argv */
+
+static struct qstream *sqadd __P((void));
+static void sq_query __P((struct qstream *)),
+ opensocket __P((struct qdatagram *)),
+#ifdef DEBUG
+ printnetinfo __P((struct netinfo *)),
+#endif
+ setdebug __P((int));
+static int sq_here __P((struct qstream *));
+
+static SIG_FN onintr __P(()),
+ maint_alarm __P(()),
+ setdumpflg __P(()),
+ onhup __P(()),
+#if defined(QRYLOG) && defined(SIGWINCH)
+ setQrylogFlg __P(()),
+#endif
+ setIncrDbgFlg __P(()),
+ setNoDbgFlg __P(()),
+#ifdef SIGSYS
+ sigprof __P(()),
+#endif /* SIGSYS */
+ setchkptflg __P(()),
+ setstatsflg __P(());
+
+static void
+usage()
+{
+ fprintf(stderr,
+"Usage: named [-d #] [-q] [-r] [-p port[/localport]] [[-b] bootfile]\n");
+ exit(1);
+}
+
+/*ARGSUSED*/
+void
+main(argc, argv, envp)
+ int argc;
+ char *argv[], *envp[];
+{
+ register int n, udpcnt;
+ register char *arg;
+ register struct qstream *sp;
+ register struct qdatagram *dqp;
+ struct qstream *nextsp;
+ int nfds;
+ const int on = 1;
+ int len;
+ int rfd, size;
+ time_t lasttime, maxctime;
+ u_char buf[BUFSIZ];
+#ifndef SYSV
+ struct sigvec vec;
+#endif
+ fd_set tmpmask;
+ struct timeval t, *tp;
+ struct qstream *candidate = QSTREAM_NULL;
+ char **argp;
+#ifdef PID_FIX
+ char oldpid[10];
+#endif
+#ifdef WANT_PIDFILE
+ FILE *fp; /* file descriptor for pid file */
+#endif
+#ifdef IP_OPTIONS
+ u_char ip_opts[50]; /* arbitrary size */
+#endif
+
+ local_ns_port = ns_port = htons(NAMESERVER_PORT);
+
+ /*
+ ** Save start and extent of argv for ns_setproctitle().
+ */
+
+ Argv = argp = argv;
+ while (*argp)
+ argp++;
+ LastArg = argp[-1] + strlen(argp[-1]);
+
+ (void) umask(022);
+ /* XXX - should use getopt here */
+ while (--argc > 0) {
+ arg = *++argv;
+ if (*arg == '-') {
+ while (*++arg)
+ switch (*arg) {
+ case 'b':
+ if (--argc <= 0)
+ usage();
+ bootfile = savestr(*++argv);
+ break;
+
+ case 'd':
+ ++argv;
+
+ if (*argv != 0) {
+ if (**argv == '-') {
+ argv--;
+ break;
+ }
+#ifdef DEBUG
+ debug = atoi(*argv);
+#endif
+ --argc;
+ }
+#ifdef DEBUG
+ if (debug <= 0)
+ debug = 1;
+ setdebug(1);
+#endif
+ break;
+
+ case 'p':
+ /* use nonstandard port number.
+ * usage: -p remote/local
+ * remote is the port number to which
+ * we send queries. local is the port
+ * on which we listen for queries.
+ * local defaults to same as remote.
+ */
+ if (--argc <= 0)
+ usage();
+ ns_port = htons((u_int16_t)
+ atoi(*++argv));
+ {
+ char *p = strchr(*argv, '/');
+ if (p) {
+ local_ns_port =
+ htons((u_int16_t)
+ atoi(p+1));
+ } else {
+ local_ns_port = ns_port;
+ }
+ }
+ break;
+
+#ifdef QRYLOG
+ case 'q':
+ qrylog = 1;
+ break;
+#endif
+
+ case 'r':
+ NoRecurse = 1;
+ break;
+
+ default:
+ usage();
+ }
+ } else
+ bootfile = savestr(*argv);
+ }
+
+#ifdef DEBUG
+ if (!debug)
+#endif
+ for (n = getdtablesize() - 1; n > 2; n--)
+ (void) close(n); /* don't use my_close() here */
+#ifdef DEBUG
+ else {
+ fprintf(ddt, "Debug turned ON, Level %d\n",debug);
+ fprintf(ddt, "Version = %s\n", Version);
+ fprintf(ddt, "bootfile = %s\n", bootfile);
+ }
+#endif
+
+ n = 0;
+#if defined(DEBUG) && defined(LOG_PERROR)
+ if (debug)
+ n = LOG_PERROR;
+#endif
+#ifdef LOG_DAEMON
+ openlog("named", LOG_PID|LOG_CONS|LOG_NDELAY|n, LOGFAC);
+#else
+ openlog("named", LOG_PID);
+#endif
+
+#ifdef WANT_PIDFILE
+ /* tuck my process id away */
+#ifdef PID_FIX
+ fp = fopen(PidFile, "r+");
+ if (fp != NULL) {
+ (void) fgets(oldpid, sizeof(oldpid), fp);
+ (void) rewind(fp);
+ fprintf(fp, "%d\n", getpid());
+ (void) my_fclose(fp);
+ }
+#else /*PID_FIX*/
+ fp = fopen(PidFile, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", getpid());
+ (void) my_fclose(fp);
+ }
+#endif /*PID_FIX*/
+#endif /*WANT_PIDFILE*/
+
+ syslog(LOG_NOTICE, "starting. %s", Version);
+
+ _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
+
+ nsaddr.sin_family = AF_INET;
+ nsaddr.sin_addr.s_addr = INADDR_ANY;
+ nsaddr.sin_port = local_ns_port;
+
+ /*
+ ** Open stream port.
+ */
+ for (n = 0; ; n++) {
+ if ((vs = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket(SOCK_STREAM): %m");
+ exit(1);
+ }
+ if (setsockopt(vs, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
+ sizeof(on)) != 0)
+ {
+ syslog(LOG_ERR, "setsockopt(vs, reuseaddr): %m");
+ (void) my_close(vs);
+ continue;
+ }
+ if (bind(vs, (struct sockaddr *)&nsaddr, sizeof(nsaddr)) == 0)
+ break;
+
+ if (errno != EADDRINUSE || n > 4) {
+ if (errno == EADDRINUSE) {
+ syslog(LOG_ERR,
+ "There may be a name server already running");
+ syslog(LOG_ERR, "exiting");
+ } else {
+ syslog(LOG_ERR, "bind(vs, [%s].%d): %m",
+ inet_ntoa(nsaddr.sin_addr),
+ ntohs(nsaddr.sin_port));
+ }
+#if defined(WANT_PIDFILE) && defined(PID_FIX)
+ /* put old pid back */
+ if (atoi(oldpid) && (fp = fopen(PidFile, "w"))) {
+ fprintf(fp, "%s", oldpid);
+ (void) my_fclose(fp);
+ _exit(1);
+ }
+#endif /*WANT_PIDFILE && PID_FIX*/
+ exit(1);
+ } else { /* Retry opening the socket a few times */
+ my_close(vs);
+ sleep(1);
+ }
+ }
+ if (listen(vs, 5) != 0) {
+ syslog(LOG_ERR, "listen(vs, 5): %m");
+ exit(1);
+ }
+
+ /*
+ * named would be terminated if one of these is sent and no handler
+ */
+ (void) signal(SIGINT, setdumpflg);
+ (void) signal(SIGQUIT, setchkptflg);
+ (void) signal(SIGIOT, setstatsflg);
+#if defined(SIGUSR1) && defined(SIGUSR2)
+ (void) signal(SIGUSR1, setIncrDbgFlg);
+ (void) signal(SIGUSR2, setNoDbgFlg);
+#else /* SIGUSR1&&SIGUSR2 */
+ (void) signal(SIGEMT, setIncrDbgFlg);
+ (void) signal(SIGFPE, setNoDbgFlg);
+#endif /* SIGUSR1&&SIGUSR2 */
+
+#if defined(SIGWINCH) && defined(QRYLOG)
+ (void) signal(SIGWINCH, setQrylogFlg);
+#endif
+
+ /*
+ * Get list of local addresses and set up datagram sockets.
+ */
+ getnetconf();
+
+ /*
+ ** Initialize and load database.
+ */
+ gettime(&tt);
+ buildservicelist();
+ buildprotolist();
+ ns_init(bootfile);
+#ifdef DEBUG
+ if (debug) {
+ fprintf(ddt, "Network and sort list:\n");
+ printnetinfo(nettab);
+ }
+#endif
+
+ time(&boottime);
+ resettime = boottime;
+
+ (void) signal(SIGHUP, onhup);
+#if defined(SIGXFSZ)
+ (void) signal(SIGXFSZ, onhup); /* wierd DEC Hesiodism, harmless */
+#endif
+#if defined(SYSV)
+ (void) signal(SIGCLD, endxfer);
+ (void) signal(SIGALRM, maint_alarm);
+#else
+ bzero((char *)&vec, sizeof(vec));
+ vec.sv_handler = maint_alarm;
+ vec.sv_mask = sigmask(SIGCHLD);
+ (void) sigvec(SIGALRM, &vec, (struct sigvec *)NULL);
+
+ vec.sv_handler = endxfer;
+ vec.sv_mask = sigmask(SIGALRM);
+ (void) sigvec(SIGCHLD, &vec, (struct sigvec *)NULL);
+#endif /* SYSV */
+ (void) signal(SIGPIPE, SIG_IGN);
+#ifdef SIGSYS
+ (void) signal(SIGSYS, sigprof);
+#endif /* SIGSYS */
+
+#ifdef ALLOW_UPDATES
+ /* Catch SIGTERM so we can dump the database upon shutdown if it
+ has changed since it was last dumped/booted */
+ (void) signal(SIGTERM, onintr);
+#endif
+
+ dprintf(1, (ddt, "database initialized\n"));
+ t.tv_usec = 0;
+
+ /*
+ * Fork and go into background now that
+ * we've done any slow initialization
+ * and are ready to answer queries.
+ */
+#ifdef USE_SETSID
+ if (
+#ifdef DEBUG
+ !debug ||
+#endif
+ !isatty(0)) {
+ if (fork() > 0)
+ exit(0);
+ setsid();
+#ifdef DEBUG
+ if (!debug)
+#endif
+ {
+ n = open(_PATH_DEVNULL, O_RDONLY);
+ (void) dup2(n, 0);
+ (void) dup2(n, 1);
+ (void) dup2(n, 2);
+ if (n > 2)
+ (void) my_close(n);
+ }
+ }
+#else
+#ifdef DEBUG
+ if (!debug)
+#endif
+ {
+#ifdef HAVE_DAEMON
+ daemon(1, 0);
+#else
+ switch (fork()) {
+ case -1:
+ syslog(LOG_ERR, "fork: %m");
+ exit(1);
+ /*FALLTHROUGH*/
+ case 0:
+ /* child */
+ break;
+ default:
+ /* parent */
+ exit(0);
+ }
+ n = open(_PATH_DEVNULL, O_RDONLY);
+ (void) dup2(n, 0);
+ (void) dup2(n, 1);
+ (void) dup2(n, 2);
+ if (n > 2)
+ (void) my_close(n);
+#ifdef SYSV
+ setpgrp();
+#else
+ {
+ struct itimerval ival;
+
+ /*
+ * The open below may hang on pseudo ttys if the person
+ * who starts named logs out before this point.
+ *
+ * needmaint may get set inapropriately if the open
+ * hangs, but all that will happen is we will see that
+ * no maintenance is required.
+ */
+ bzero((char *)&ival, sizeof(ival));
+ ival.it_value.tv_sec = 120;
+ (void) setitimer(ITIMER_REAL, &ival,
+ (struct itimerval *)NULL);
+ n = open(_PATH_TTY, O_RDWR);
+ ival.it_value.tv_sec = 0;
+ (void) setitimer(ITIMER_REAL, &ival,
+ (struct itimerval *)NULL);
+ if (n > 0) {
+ (void) ioctl(n, TIOCNOTTY, (char *)NULL);
+ (void) my_close(n);
+ }
+ }
+#endif /* SYSV */
+#endif /* HAVE_DAEMON */
+ }
+#endif /* USE_SETSID */
+#ifdef WANT_PIDFILE
+ /* tuck my process id away again */
+ fp = fopen(PidFile, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", getpid());
+ (void) my_fclose(fp);
+ }
+#endif
+
+ syslog(LOG_NOTICE, "Ready to answer queries.\n");
+ prime_cache();
+ nfds = getdtablesize(); /* get the number of file descriptors */
+ if (nfds > FD_SETSIZE) {
+ nfds = FD_SETSIZE; /* Bulletproofing */
+ syslog(LOG_ERR, "Return from getdtablesize() > FD_SETSIZE");
+ }
+ FD_ZERO(&mask);
+ FD_SET(vs, &mask);
+ for (dqp = datagramq; dqp != QDATAGRAM_NULL; dqp = dqp->dq_next)
+ FD_SET(dqp->dq_dfd, &mask);
+ for (;;) {
+#ifdef DEBUG
+ if (ddt && debug == 0) {
+ fprintf(ddt,"Debug turned OFF\n");
+ (void) my_fclose(ddt);
+ ddt = 0;
+ }
+#endif
+#ifdef ALLOW_UPDATES
+ if (needToExit) {
+ struct zoneinfo *zp;
+ sigblock(~0); /*
+ * Block all blockable signals
+ * to ensure a consistant
+ * state during final dump
+ */
+ dprintf(1, (ddt, "Received shutdown signal\n"));
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ if (zp->z_flags & Z_CHANGED)
+ zonedump(zp);
+ }
+ exit(0);
+ }
+#endif /* ALLOW_UPDATES */
+ if (needreload) {
+ needreload = 0;
+ db_reload();
+ }
+ if (needStatsDump) {
+ needStatsDump = 0;
+ ns_stats();
+ }
+ if (needzoneload) {
+ needzoneload = 0;
+ loadxfer();
+ }
+ if (needmaint) {
+ needmaint = 0;
+ ns_maint();
+ }
+ if(needToChkpt) {
+ needToChkpt = 0;
+ doachkpt();
+ }
+ if(needToDoadump) {
+ needToDoadump = 0;
+ doadump();
+ }
+ /*
+ ** Wait until a query arrives
+ */
+ if (retryqp != NULL) {
+ gettime(&tt);
+ /*
+ ** The tv_sec field might be unsigned
+ ** and thus cannot be negative.
+ */
+ if ((int32_t) retryqp->q_time <= tt.tv_sec) {
+ retry(retryqp);
+ continue;
+ }
+ t.tv_sec = (int32_t) retryqp->q_time - tt.tv_sec;
+ tp = &t;
+ } else
+ tp = NULL;
+ tmpmask = mask;
+ n = select(nfds, &tmpmask, (fd_set *)NULL, (fd_set *)NULL, tp);
+ if (n < 0) {
+ if (errno != EINTR) {
+ syslog(LOG_ERR, "select: %m");
+ sleep(60);
+ }
+ }
+ if (n <= 0)
+ continue;
+
+ for (dqp = datagramq;
+ dqp != QDATAGRAM_NULL;
+ dqp = dqp->dq_next) {
+ if (FD_ISSET(dqp->dq_dfd, &tmpmask))
+ for (udpcnt = 0; udpcnt < 25; udpcnt++) { /*XXX*/
+ from_len = sizeof(from_addr);
+ if ((n = recvfrom(dqp->dq_dfd, buf, sizeof(buf), 0,
+ (struct sockaddr *)&from_addr, &from_len)) < 0)
+ {
+ if ((n < 0) && (errno == PORT_WOULDBLK))
+ break;
+ syslog(LOG_WARNING, "recvfrom: %m");
+ break;
+ }
+ if (n == 0)
+ break;
+ gettime(&tt);
+ dprintf(1, (ddt,
+ "\ndatagram from [%s].%d, fd %d, len %d; now %s",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port),
+ dqp->dq_dfd, n,
+ ctime(&tt.tv_sec)));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(buf, ddt);
+#endif
+ /*
+ * Consult database to get the answer.
+ */
+ gettime(&tt);
+ ns_req(buf, n, PACKETSZ, QSTREAM_NULL, &from_addr,
+ dqp->dq_dfd);
+ }
+ }
+ /*
+ ** Process stream connection.
+ **
+ ** Note that a "continue" in here takes us back to the select()
+ ** which, if our accept() failed, will bring us back here.
+ */
+ if (FD_ISSET(vs, &tmpmask)) {
+ from_len = sizeof(from_addr);
+ rfd = accept(vs,
+ (struct sockaddr *)&from_addr,
+ &from_len);
+ if (rfd < 0 && errno == EINTR)
+ continue;
+ if (rfd < 0 && errno == EMFILE && streamq) {
+ maxctime = 0;
+ candidate = NULL;
+ for (sp = streamq; sp; sp = nextsp) {
+ nextsp = sp->s_next;
+ if (sp->s_refcnt)
+ continue;
+ gettime(&tt);
+ lasttime = tt.tv_sec - sp->s_time;
+ if (lasttime >= VQEXPIRY)
+ sqrm(sp);
+ else if (lasttime > maxctime) {
+ candidate = sp;
+ maxctime = lasttime;
+ }
+ }
+ if (candidate)
+ sqrm(candidate);
+ continue;
+ }
+ if (rfd < 0) {
+ syslog(LOG_WARNING, "accept: %m");
+ continue;
+ }
+ if ((n = fcntl(rfd, F_GETFL, 0)) < 0) {
+ syslog(LOG_ERR, "fcntl(rfd, F_GETFL): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ if (fcntl(rfd, F_SETFL, n|PORT_NONBLOCK) != 0) {
+ syslog(LOG_ERR, "fcntl(rfd, NONBLOCK): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+#if defined(IP_OPTIONS)
+ len = sizeof ip_opts;
+ if (getsockopt(rfd, IPPROTO_IP, IP_OPTIONS,
+ (char *)ip_opts, &len) < 0) {
+ syslog(LOG_ERR,
+ "getsockopt(rfd, IP_OPTIONS): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ if (len != 0) {
+ nameserIncr(from_addr.sin_addr, nssRcvdOpts);
+ if (!haveComplained((char*)
+ from_addr.sin_addr.s_addr,
+ "rcvd ip options")) {
+ syslog(LOG_NOTICE,
+ "rcvd IP_OPTIONS from [%s].%d (ignored)",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port));
+ }
+ if (setsockopt(rfd, IPPROTO_IP, IP_OPTIONS,
+ NULL, 0) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt(!IP_OPTIONS): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ }
+#endif
+ if (setsockopt(rfd, SOL_SOCKET, SO_KEEPALIVE,
+ (char *)&on, sizeof(on)) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt(rfd, KEEPALIVE): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ if ((sp = sqadd()) == QSTREAM_NULL) {
+ (void) my_close(rfd);
+ continue;
+ }
+ sp->s_rfd = rfd; /* stream file descriptor */
+ sp->s_size = -1; /* amount of data to receive */
+ gettime(&tt);
+ sp->s_time = tt.tv_sec; /* last transaction time */
+ sp->s_from = from_addr; /* address to respond to */
+ sp->s_bufp = (u_char *)&sp->s_tempsize;
+ FD_SET(rfd, &mask);
+ FD_SET(rfd, &tmpmask);
+ dprintf(1, (ddt,
+ "\nTCP connection from [%s].%d (fd %d)\n",
+ inet_ntoa(sp->s_from.sin_addr),
+ ntohs(sp->s_from.sin_port), rfd));
+ }
+ if (streamq) {
+ dprintf(3, (ddt, "streamq = 0x%x\n",streamq));
+ }
+ for (sp = streamq; sp != QSTREAM_NULL; sp = nextsp) {
+ nextsp = sp->s_next;
+ if (!FD_ISSET(sp->s_rfd, &tmpmask))
+ continue;
+ dprintf(5, (ddt,
+ "sp x%x rfd %d size %d time %d next x%x\n",
+ sp, sp->s_rfd, sp->s_size,
+ sp->s_time, sp->s_next));
+ dprintf(5, (ddt,
+ "\tbufsize %d buf x%x bufp x%x\n",
+ sp->s_bufsize, sp->s_buf, sp->s_bufp));
+ if (sp->s_size < 0) {
+ size = INT16SZ
+ - (sp->s_bufp - (u_char *)&sp->s_tempsize);
+ while (size > 0 &&
+ (n = read(sp->s_rfd, sp->s_bufp, size)) > 0
+ ) {
+ sp->s_bufp += n;
+ size -= n;
+ }
+ if ((n < 0) && (errno == PORT_WOULDBLK))
+ continue;
+ if (n <= 0) {
+ sqrm(sp);
+ continue;
+ }
+ if ((sp->s_bufp - (u_char *)&sp->s_tempsize) ==
+ INT16SZ) {
+ sp->s_size = htons(sp->s_tempsize);
+ if (sp->s_bufsize == 0) {
+ if ( (sp->s_buf = (u_char *)
+ malloc(rbufsize))
+ == NULL) {
+ sp->s_buf = buf;
+ sp->s_size = sizeof(buf);
+ } else {
+ sp->s_bufsize = rbufsize;
+ }
+ }
+ if (sp->s_size > sp->s_bufsize &&
+ sp->s_bufsize != 0
+ ) {
+ sp->s_buf = (u_char *)
+ realloc((char *)sp->s_buf,
+ (unsigned)sp->s_size);
+ if (sp->s_buf == NULL) {
+ sp->s_buf = buf;
+ sp->s_bufsize = 0;
+ sp->s_size = sizeof(buf);
+ } else {
+ sp->s_bufsize = sp->s_size;
+ }
+ }
+ sp->s_bufp = sp->s_buf;
+ }
+ }
+ gettime(&tt);
+ sp->s_time = tt.tv_sec;
+ while (sp->s_size > 0 &&
+ (n = read(sp->s_rfd,
+ sp->s_bufp,
+ sp->s_size)
+ ) > 0
+ ) {
+ sp->s_bufp += n;
+ sp->s_size -= n;
+ }
+ /*
+ * we don't have enough memory for the query.
+ * if we have a query id, then we will send an
+ * error back to the user.
+ */
+ if (sp->s_bufsize == 0 &&
+ (sp->s_bufp - sp->s_buf > INT16SZ)) {
+ HEADER *hp;
+
+ hp = (HEADER *)sp->s_buf;
+ hp->qr = 1;
+ hp->ra = 1;
+ hp->ancount = 0;
+ hp->qdcount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ hp->rcode = SERVFAIL;
+ (void) writemsg(sp->s_rfd, sp->s_buf,
+ HFIXEDSZ);
+ continue;
+ }
+ if ((n == -1) && (errno == PORT_WOULDBLK))
+ continue;
+ if (n <= 0) {
+ sqrm(sp);
+ continue;
+ }
+ /*
+ * Consult database to get the answer.
+ */
+ if (sp->s_size == 0) {
+ nameserIncr(sp->s_from.sin_addr, nssRcvdTCP);
+ sq_query(sp);
+ ns_req(sp->s_buf,
+ sp->s_bufp - sp->s_buf,
+ sp->s_bufsize, sp,
+ &sp->s_from, -1);
+ /* ns_req() can call sqrm() - check for it */
+ if (sq_here(sp)) {
+ sp->s_bufp = (u_char *)&sp->s_tempsize;
+ sp->s_size = -1;
+ }
+ continue;
+ }
+ }
+ }
+ /* NOTREACHED */
+}
+
+void
+getnetconf()
+{
+ register struct netinfo *ntp;
+ struct netinfo *ontp;
+ struct ifconf ifc;
+ struct ifreq ifreq, *ifr;
+ struct qdatagram *dqp;
+ static int first = 1;
+ char buf[BUFSIZ], *cp, *cplim;
+ u_int32_t nm;
+ time_t my_generation = time(NULL);
+
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+ if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) {
+ syslog(LOG_ERR, "get interface configuration: %m - exiting");
+ exit(1);
+ }
+ ntp = NULL;
+#if defined(AF_LINK) && !defined(RISCOS_BSD)
+#define my_max(a, b) (a > b ? a : b)
+#define my_size(p) my_max((p).sa_len, sizeof(p))
+#else
+#define my_size(p) (sizeof (p))
+#endif
+ cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
+ for (cp = buf;
+ cp < cplim;
+ cp += sizeof (ifr->ifr_name) + my_size(ifr->ifr_addr)) {
+#undef my_size
+ ifr = (struct ifreq *)cp;
+ if (ifr->ifr_addr.sa_family != AF_INET ||
+ ((struct sockaddr_in *)
+ &ifr->ifr_addr)->sin_addr.s_addr == 0) {
+ continue;
+ }
+ ifreq = *ifr;
+ /*
+ * Don't test IFF_UP, packets may still be received at this
+ * address if any other interface is up.
+ */
+#if !defined(BSD) || (BSD < 199103)
+ if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "get interface addr: %m");
+ continue;
+ }
+#endif
+ dprintf(1, (ddt, "considering [%s]\n",
+ inet_ntoa(((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr)));
+ /* build datagram queue */
+ /*
+ * look for an already existing source interface address.
+ * This happens mostly when reinitializing. Also, if
+ * the machine has multiple point to point interfaces, then
+ * the local address may appear more than once.
+ */
+ if (dqp = aIsUs(((struct sockaddr_in *)&ifreq.ifr_addr)
+ ->sin_addr)) {
+ dprintf(1, (ddt,
+ "dup interface address %s on %s\n",
+ inet_ntoa(((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr),
+ ifreq.ifr_name));
+ dqp->dq_gen = my_generation;
+ continue;
+ }
+
+ /*
+ * Skip over address 0.0.0.0 since this will conflict
+ * with binding to wildcard address later. Interfaces
+ * which are not completely configured can have this addr.
+ */
+ if (((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr
+ == 0x00000000) { /* XXX */
+ dprintf(1, (ddt, "skipping address 0.0.0.0 on %s\n",
+ ifreq.ifr_name));
+ continue;
+ }
+ if ((dqp = (struct qdatagram *)
+ calloc(1, sizeof(struct qdatagram))
+ ) == NULL) {
+ syslog(LOG_ERR, "getnetconf: malloc: %m");
+ exit(12);
+ }
+ dqp->dq_next = datagramq;
+ datagramq = dqp;
+ dqp->dq_addr = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr;
+ dqp->dq_gen = my_generation;
+ opensocket(dqp);
+ dprintf(1, (ddt, "listening [%s]\n",
+ inet_ntoa(((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr)));
+
+ /*
+ * Add interface to list of directly-attached (sub)nets
+ * for use in sorting addresses.
+ */
+ if (ntp == NULL) {
+ ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
+ }
+ ntp->my_addr = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr;
+#ifdef SIOCGIFNETMASK
+ if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "get netmask: %m");
+ ntp->mask = net_mask(ntp->my_addr);
+ } else
+ ntp->mask = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr.s_addr;
+#else
+ /* 4.2 does not support subnets */
+ ntp->mask = net_mask(ntp->my_addr);
+#endif
+ if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "get interface flags: %m");
+ continue;
+ }
+#ifdef IFF_LOOPBACK
+ if (ifreq.ifr_flags & IFF_LOOPBACK)
+#else
+ /* test against 127.0.0.1 (yuck!!) */
+ if (ntp->my_addr.s_addr == inet_addr("127.0.0.1")) /* XXX */
+#endif
+ {
+ if (netloop.my_addr.s_addr == 0) {
+ netloop.my_addr = ntp->my_addr;
+ netloop.mask = 0xffffffff;
+ netloop.addr = ntp->my_addr.s_addr;
+ dprintf(1, (ddt, "loopback address: x%lx\n",
+ netloop.my_addr.s_addr));
+ }
+ continue;
+ } else if ((ifreq.ifr_flags & IFF_POINTOPOINT)) {
+ if (ioctl(vs, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "get dst addr: %m");
+ continue;
+ }
+ ntp->mask = 0xffffffff;
+ ntp->addr = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr.s_addr;
+ } else {
+ ntp->addr = ntp->mask & ntp->my_addr.s_addr;
+ }
+ /*
+ * Place on end of list of locally-attached (sub)nets,
+ * but before logical nets for subnetted nets.
+ */
+ ntp->next = *elocal;
+ *elocal = ntp;
+ if (elocal == enettab)
+ enettab = &ntp->next;
+ elocal = &ntp->next;
+ ntp = NULL;
+ }
+ if (ntp)
+ free((char *)ntp);
+
+ /*
+ * now go through the datagramq and delete anything that
+ * does not have the current generation number. this is
+ * how we catch interfaces that go away or change their
+ * addresses. note that 0.0.0.0 is the wildcard element
+ * and should never be deleted by this code.
+ *
+ * XXX - need to update enettab/elocal as well.
+ */
+ dqflush(my_generation);
+
+ /*
+ * Create separate qdatagram structure for socket
+ * wildcard address.
+ */
+ if (first) {
+ if (!(dqp = (struct qdatagram *)calloc(1, sizeof(*dqp)))) {
+ syslog(LOG_ERR, "getnetconf: malloc: %m");
+ exit(12);
+ }
+ dqp->dq_next = datagramq;
+ datagramq = dqp;
+ dqp->dq_addr.s_addr = INADDR_ANY;
+ opensocket(dqp);
+ ds = dqp->dq_dfd;
+ }
+
+ /*
+ * Compute logical networks to which we're connected
+ * based on attached subnets;
+ * used for sorting based on network configuration.
+ */
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ nm = net_mask(ntp->my_addr);
+ if (nm != ntp->mask) {
+ if (findnetinfo(ntp->my_addr))
+ continue;
+ ontp = (struct netinfo *)
+ malloc(sizeof(struct netinfo));
+ if (ontp == NULL) {
+ syslog(LOG_ERR, "getnetconf: malloc: %m");
+ exit(12);
+ }
+ ontp->my_addr = ntp->my_addr;
+ ontp->mask = nm;
+ ontp->addr = ontp->my_addr.s_addr & nm;
+ ontp->next = *enettab;
+ *enettab = ontp;
+ enettab = &ontp->next;
+ }
+ }
+ first = 0;
+}
+
+/*
+ * Find netinfo structure for logical network implied by address "addr",
+ * if it's on list of local/favored networks.
+ */
+struct netinfo *
+findnetinfo(addr)
+ struct in_addr addr;
+{
+ register struct netinfo *ntp;
+ u_int32_t net, mask;
+
+ mask = net_mask(addr);
+ net = addr.s_addr & mask;
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next)
+ if (ntp->addr == net && ntp->mask == mask)
+ return (ntp);
+ return ((struct netinfo *) NULL);
+}
+
+#ifdef DEBUG
+static void
+printnetinfo(ntp)
+ register struct netinfo *ntp;
+{
+ for ( ; ntp != NULL; ntp = ntp->next) {
+ fprintf(ddt,"addr x%lx mask x%lx", ntp->addr, ntp->mask);
+ fprintf(ddt," my_addr x%lx", ntp->my_addr.s_addr);
+ fprintf(ddt," %s\n", inet_ntoa(ntp->my_addr));
+ }
+}
+#endif
+
+static void
+opensocket(dqp)
+ register struct qdatagram *dqp;
+{
+ int n, m;
+ int on = 1;
+
+ /*
+ * Open datagram sockets bound to interface address.
+ */
+ if ((dqp->dq_dfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket(SOCK_DGRAM): %m - exiting");
+ exit(1);
+ }
+ dprintf(1, (ddt, "dqp->dq_addr %s d_dfd %d\n",
+ inet_ntoa(dqp->dq_addr), dqp->dq_dfd));
+ if (setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof(on)) != 0)
+ {
+ syslog(LOG_ERR, "setsockopt(dqp->dq_dfd, reuseaddr): %m");
+ /* XXX press on regardless, this is not too serious. */
+ }
+#ifdef SO_RCVBUF
+ m = sizeof(n);
+ if ((getsockopt(dqp->dq_dfd, SOL_SOCKET, SO_RCVBUF, &n, &m) >= 0)
+ && (m == sizeof(n))
+ && (n < rbufsize)) {
+ (void) setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_RCVBUF,
+ (char *)&rbufsize, sizeof(rbufsize));
+ }
+#endif /* SO_RCVBUF */
+ if ((n = fcntl(dqp->dq_dfd, F_GETFL, 0)) < 0) {
+ syslog(LOG_ERR, "fcntl(dfd, F_GETFL): %m");
+ /* XXX press on regardless, but this really is a problem. */
+ } else if (fcntl(dqp->dq_dfd, F_SETFL, n|PORT_NONBLOCK) != 0) {
+ syslog(LOG_ERR, "fcntl(dqp->dq_dfd, non-blocking): %m");
+ /* XXX press on regardless, but this really is a problem. */
+ }
+ /*
+ * NOTE: Some versions of SunOS have problems with the following
+ * call to bind. Bind still seems to function on these systems
+ * if you comment out the exit inside the if. This may cause
+ * Suns with multiple interfaces to reply strangely.
+ */
+ nsaddr.sin_addr = dqp->dq_addr;
+ if (bind(dqp->dq_dfd, (struct sockaddr *)&nsaddr, sizeof(nsaddr))) {
+ syslog(LOG_ERR, "bind(dfd=%d, [%s].%d): %m - exiting",
+ dqp->dq_dfd, inet_ntoa(nsaddr.sin_addr),
+ ntohs(nsaddr.sin_port));
+#if !defined(sun)
+ exit(1);
+#endif
+ }
+}
+
+/*
+** Set flag saying to reload database upon receiving SIGHUP.
+** Must make sure that someone isn't walking through a data
+** structure at the time.
+*/
+
+static SIG_FN
+onhup()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGHUP, onhup);
+#endif /* SYSV */
+ needreload = 1;
+ errno = save_errno;
+}
+
+/*
+** Set flag saying to call ns_maint()
+** Must make sure that someone isn't walking through a data
+** structure at the time.
+*/
+
+static SIG_FN
+maint_alarm()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGALRM, maint_alarm);
+#endif /* SYSV */
+ needmaint = 1;
+ errno = save_errno;
+}
+
+
+#ifdef ALLOW_UPDATES
+/*
+ * Signal handler to schedule shutdown. Just set flag, to ensure a consistent
+ * state during dump.
+ */
+static SIG_FN
+onintr()
+{
+ needToExit = 1;
+}
+#endif /* ALLOW_UPDATES */
+
+/*
+ * Signal handler to schedule a data base dump. Do this instead of dumping the
+ * data base immediately, to avoid seeing it in a possibly inconsistent state
+ * (due to updates), and to avoid long disk I/O delays at signal-handler
+ * level
+ */
+static SIG_FN
+setdumpflg()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGINT, setdumpflg);
+#endif /* SYSV */
+ needToDoadump = 1;
+ errno = save_errno;
+}
+
+/*
+** Turn on or off debuging by open or closeing the debug file
+*/
+
+static void
+setdebug(code)
+ int code;
+{
+#if defined(lint) && !defined(DEBUG)
+ code = code;
+#endif
+#ifdef DEBUG
+
+ if (code) {
+ int n;
+
+ ddt = freopen(debugfile, "w+", stderr);
+ if ( ddt == NULL) {
+ syslog(LOG_WARNING, "can't open debug file %s: %m",
+ debugfile);
+ debug = 0;
+ } else {
+#if defined(SYSV)
+ setvbuf(ddt, NULL, _IOLBF, BUFSIZ);
+#else
+ setlinebuf(ddt);
+#endif
+ if ((n = fcntl(fileno(ddt), F_GETFL, 0)) < 0) {
+ syslog(LOG_WARNING,
+ "fcntl(ddt, F_GETFL): %m");
+ } else {
+ (void) fcntl(fileno(ddt), F_SETFL, n|O_APPEND);
+ }
+ }
+ } else
+ debug = 0;
+ /* delay closing ddt, we might interrupt someone */
+#endif
+}
+
+/*
+** Catch a special signal and set debug level.
+**
+** If debuging is off then turn on debuging else increment the level.
+**
+** Handy for looking in on long running name servers.
+*/
+
+static SIG_FN
+setIncrDbgFlg()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGUSR1, setIncrDbgFlg);
+#endif /* SYSV */
+#ifdef DEBUG
+ if (debug == 0) {
+ debug++;
+ setdebug(1);
+ } else {
+ debug++;
+ }
+ if (debug)
+ fprintf(ddt, "Debug turned ON, Level %d\n", debug);
+#endif
+ errno = save_errno;
+}
+
+/*
+** Catch a special signal to turn off debugging
+*/
+
+static SIG_FN
+setNoDbgFlg()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGUSR2, setNoDbgFlg);
+#endif /* SYSV */
+ setdebug(0);
+ errno = save_errno;
+}
+
+#if defined(QRYLOG) && defined(SIGWINCH)
+/*
+** Set flag for query logging
+*/
+static SIG_FN
+setQrylogFlg()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGWINCH, setQrylogFlg);
+#endif /* SYSV */
+ qrylog = !qrylog;
+ syslog(LOG_NOTICE, "query log %s\n", qrylog ?"on" :"off");
+ errno = save_errno;
+}
+#endif /*QRYLOG && SIGWINCH*/
+
+/*
+** Set flag for statistics dump
+*/
+static SIG_FN
+setstatsflg()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGIOT, setstatsflg);
+#endif /* SYSV */
+ needStatsDump = 1;
+ errno = save_errno;
+}
+
+static SIG_FN
+setchkptflg()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGQUIT, setchkptflg);
+#endif /* SYSV */
+ needToChkpt = 1;
+ errno = save_errno;
+}
+
+/*
+** Catch a special signal SIGSYS
+**
+** this is setup to fork and exit to drop to /usr/tmp/gmon.out
+** and keep the server running
+*/
+
+#ifdef SIGSYS
+static SIG_FN
+sigprof()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGSYS, sigprof);
+#endif /* SYSV */
+ dprintf(1, (ddt, "sigprof()\n"));
+ if (fork() == 0)
+ {
+ (void) chdir(_PATH_TMPDIR);
+ exit(1);
+ }
+ errno = save_errno;
+}
+#endif /* SIGSYS */
+
+/*
+** Routines for managing stream queue
+*/
+
+static struct qstream *
+sqadd()
+{
+ register struct qstream *sqp;
+
+ if (!(sqp = (struct qstream *)calloc(1, sizeof(struct qstream)))) {
+ syslog(LOG_ERR, "sqadd: calloc: %m");
+ return (QSTREAM_NULL);
+ }
+ dprintf(3, (ddt, "sqadd(x%x)\n", sqp));
+
+ sqp->s_next = streamq;
+ streamq = sqp;
+ return (sqp);
+}
+
+/* sqrm(qp)
+ * remove stream queue structure `qp'.
+ * no current queries may refer to this stream when it is removed.
+ * side effects:
+ * memory is deallocated. sockets are closed. lists are relinked.
+ */
+void
+sqrm(qp)
+ register struct qstream *qp;
+{
+ register struct qstream *qsp;
+
+ dprintf(2, (ddt, "sqrm(%#x, %d ) rfcnt=%d\n",
+ qp, qp->s_rfd, qp->s_refcnt));
+
+ if (qp->s_bufsize != 0)
+ free(qp->s_buf);
+ FD_CLR(qp->s_rfd, &mask);
+ (void) my_close(qp->s_rfd);
+ if (qp == streamq) {
+ streamq = qp->s_next;
+ } else {
+ for (qsp = streamq;
+ qsp && (qsp->s_next != qp);
+ qsp = qsp->s_next)
+ ;
+ if (qsp) {
+ qsp->s_next = qp->s_next;
+ }
+ }
+ free((char *)qp);
+}
+
+/* void
+ * sqflush(allbut)
+ * call sqrm() on all open streams except `allbut'
+ * side effects:
+ * global list `streamq' modified
+ * idiocy:
+ * is N^2 due to the scan inside of sqrm()
+ */
+void
+sqflush(allbut)
+ register struct qstream *allbut;
+{
+ register struct qstream *sp, *spnext;
+
+ for (sp = streamq; sp != NULL; sp = spnext) {
+ spnext = sp->s_next;
+ if (sp != allbut)
+ sqrm(sp);
+ }
+}
+
+/* void
+ * dqflush(gen)
+ * close/deallocate all the udp sockets, unless `gen' != (time_t)0
+ * in which case all those not matching this generation will
+ * be deleted except the 0.0.0.0 element, and syslog() will
+ * be called whenever something is deleted.
+ * side effects:
+ * global list `datagramq' is modified
+ */
+void
+dqflush(gen)
+ register time_t gen;
+{
+ register struct qdatagram *dqp, *pqp, *nqp;
+
+ for (pqp = NULL, dqp = datagramq;
+ dqp != NULL;
+ pqp = dqp, dqp = nqp) {
+ nqp = dqp->dq_next;
+ if (gen != (time_t)0) {
+ if (dqp->dq_addr.s_addr == INADDR_ANY ||
+ dqp->dq_gen == gen)
+ continue;
+ syslog(LOG_CRIT, "interface [%s] missing; deleting",
+ inet_ntoa(dqp->dq_addr));
+ }
+ if (pqp != NULL)
+ pqp->dq_next = dqp->dq_next;
+ else
+ datagramq = dqp->dq_next;
+ free(dqp);
+ }
+}
+
+/* int
+ * sq_here(sp)
+ * determine whether stream 'sp' is still on the streamq
+ * return:
+ * boolean: is it here?
+ */
+static int
+sq_here(sp)
+ register struct qstream *sp;
+{
+ register struct qstream *t;
+
+ for (t = streamq; t != NULL; t = t->s_next)
+ if (t == sp)
+ return (1);
+ return (0);
+}
+
+/*
+ * Initiate query on stream;
+ * mark as referenced and stop selecting for input.
+ */
+static void
+sq_query(sp)
+ register struct qstream *sp;
+{
+ sp->s_refcnt++;
+ FD_CLR(sp->s_rfd, &mask);
+}
+
+/*
+ * Note that the current request on a stream has completed,
+ * and that we should continue looking for requests on the stream.
+ */
+void
+sq_done(sp)
+ register struct qstream *sp;
+{
+
+ sp->s_refcnt = 0;
+ sp->s_time = tt.tv_sec;
+ FD_SET(sp->s_rfd, &mask);
+}
+
+void
+ns_setproctitle(a, s)
+ char *a;
+ int s;
+{
+ int size;
+ register char *cp;
+ struct sockaddr_in sin;
+ char buf[80];
+
+ cp = Argv[0];
+ size = sizeof(sin);
+ if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
+ (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
+ else {
+ syslog(LOG_DEBUG, "getpeername: %m");
+ (void) sprintf(buf, "-%s", a);
+ }
+ (void) strncpy(cp, buf, LastArg - cp);
+ cp += strlen(cp);
+ while (cp < LastArg)
+ *cp++ = ' ';
+}
+
+u_int32_t
+net_mask(in)
+ struct in_addr in;
+{
+ register u_int32_t i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return (htonl(IN_CLASSA_NET));
+ else if (IN_CLASSB(i))
+ return (htonl(IN_CLASSB_NET));
+ else
+ return (htonl(IN_CLASSC_NET));
+}
+
+#if defined(BSD43_BSD43_NFS)
+/* junk needed for old Sun NFS licensees */
+#undef dn_skipname
+extern char *dn_skipname();
+char *(*hack_skipname)() = dn_skipname;
+#endif
diff --git a/usr.sbin/named/ns_maint.c b/usr.sbin/named/ns_maint.c
new file mode 100644
index 0000000..927fde3
--- /dev/null
+++ b/usr.sbin/named/ns_maint.c
@@ -0,0 +1,784 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_maint.c 4.39 (Berkeley) 3/2/91";
+static char rcsid[] = "$Id: ns_maint.c,v 4.9.1.15 1994/06/11 22:04:46 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988
+ * -
+ * Copyright (c) 1986, 1988
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "named.h"
+
+#ifdef USE_UTIME
+# include <utime.h>
+#endif
+
+static int xfers_running, /* # of xfers running */
+ xfers_deferred, /* # of needed xfers not run yet */
+ qserials_running,
+ alarm_pending, /* flag */
+ nxfers __P((struct zoneinfo *, int));
+
+static void startxfer __P((struct zoneinfo *)),
+ abortxfer __P((struct zoneinfo *)),
+ addxfer __P((struct zoneinfo *)),
+ qserial_query __P((struct zoneinfo *)),
+ tryxfer __P((void));
+
+#define qserial_qfull() (qserials_running == MAXQSERIAL)
+
+#ifdef CLEANCACHE
+static time_t cache_time;
+#endif
+/*
+ * 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.
+ */
+void
+ns_maint()
+{
+ register struct zoneinfo *zp;
+ int zonenum;
+
+ gettime(&tt);
+
+ dprintf(1, (ddt, "\nns_maint(); now %s", ctime(&tt.tv_sec)));
+
+ 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) {
+ switch (zp->z_type) {
+
+ case Z_CACHE:
+ doachkpt();
+ zp->z_time = tt.tv_sec + zp->z_refresh;
+ break;
+
+ case Z_SECONDARY:
+#ifdef STUBS
+ case Z_STUB:
+#endif
+ if (zp->z_flags &
+ (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL)) {
+ zp->z_time = tt.tv_sec + zp->z_refresh;
+ break;
+ }
+ if (zp->z_flags & Z_XFER_RUNNING) {
+ abortxfer(zp);
+ zp->z_time = tt.tv_sec + zp->z_retry;
+ break;
+ }
+ qserial_query(zp);
+ break;
+#ifdef ALLOW_UPDATES
+ case Z_PRIMARY:
+ /*
+ * Checkpoint the zone if it has changed
+ * since we last checkpointed
+ */
+ if (zp->z_flags & Z_CHANGED) {
+ zonedump(zp);
+ zp->z_time = tt.tv_sec + zp->z_refresh;
+ }
+ break;
+#endif /* ALLOW_UPDATES */
+ }
+ gettime(&tt);
+ }
+ }
+#ifdef CLEANCACHE
+ remove_zone(hashtab, 0, 0);
+#endif
+ if (!needmaint)
+ sched_maint();
+ dprintf(1, (ddt, "exit ns_maint()\n"));
+}
+
+/*
+ * Find when the next refresh needs to be and set
+ * interrupt time accordingly.
+ */
+void
+sched_maint()
+{
+ register struct zoneinfo *zp;
+ struct itimerval ival;
+#ifdef CLEANCACHE
+ time_t next_refresh = cache_time + 3600;
+#else
+ time_t next_refresh = 0;
+#endif
+ 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) {
+ dprintf(1, (ddt, "sched_maint: no schedule change\n"));
+ return;
+ }
+ /*
+ * tv_sec can be an unsigned long, so we can't let
+ * it go negative.
+ */
+ if (next_refresh < tt.tv_sec)
+ next_refresh = tt.tv_sec;
+ ival.it_value.tv_sec = next_refresh - tt.tv_sec;
+ if ((long) 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);
+ dprintf(1, (ddt, "sched_maint: Next interrupt in %d sec\n",
+ ival.it_value.tv_sec));
+}
+
+/*
+ * Mark a zone "up to date" after named-xfer tells us this or we
+ * discover it through the qserial_*() logic.
+ */
+static void
+markUpToDate(zp)
+ struct zoneinfo *zp;
+{
+ struct stat f_time;
+
+ zp->z_flags &= ~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_flags & Z_DB_BAD) == 0)
+ zp->z_flags |= Z_AUTH;
+ if (zp->z_source) {
+#if defined(USE_UTIME)
+ 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 /* USE_UTIME */
+ }
+ /* we use "stat" to set zp->z_ftime instead of just
+ setting it to tt.tv_sec in order to avoid any
+ possible rounding problems in utimes(). */
+ if (stat(zp->z_source, &f_time) != -1)
+ zp->z_ftime = f_time.st_mtime;
+ /* XXX log if stat fails? XXX */
+}
+
+/*
+ * Query for the serial number of a zone, so that
+ * we can check to see if we need to transfer it.
+ */
+static void
+qserial_query(zp)
+ struct zoneinfo *zp;
+{
+ struct qinfo *qp;
+
+ dprintf(1, (ddt, "qserial_query(%s)\n", zp->z_origin));
+
+ if (qserial_qfull())
+ return;
+
+ qp = sysquery(zp->z_origin, zp->z_class, T_SOA,
+ zp->z_addr, zp->z_addrcnt);
+ if (!qp) {
+ dprintf(1, (ddt, "qserial_query(%s) FAILED\n", zp->z_origin));
+ return; /* XXX - this is bad, we should do something */
+ }
+ qp->q_flags |= Q_ZSERIAL;
+ qp->q_zquery = zp;
+ zp->z_flags |= Z_QSERIAL;
+ zp->z_time = tt.tv_sec + zp->z_refresh;
+ qserials_running++;
+ dprintf(1, (ddt, "qserial_query(%s) QUEUED\n", zp->z_origin));
+}
+
+void
+qserial_answer(qp, serial)
+ struct qinfo *qp;
+ u_int32_t serial;
+{
+ struct zoneinfo *zp = qp->q_zquery;
+ int was_qfull = qserial_qfull();
+
+ dprintf(1, (ddt, "qserial_answer(%s, %lu)\n", zp->z_origin, serial));
+ zp->z_flags &= ~Z_QSERIAL;
+ qp->q_flags &= ~Q_ZSERIAL; /* keeps us from being called twice */
+ qserials_running--;
+ if (serial == 0) {
+ /* an error occurred, or the query timed out.
+ */
+#ifdef GETSER_LOGGING
+ syslog(GETSER_LOGGING, "Err/TO getting serial# for \"%s\"",
+ zp->z_origin);
+#endif /* GETSER_LOGGING */
+ addxfer(zp);
+ } else if (SEQ_GT(serial, zp->z_serial) || !zp->z_serial) {
+ dprintf(1, (ddt, "qserial_answer: zone is out of date\n"));
+ zp->z_xaddr = from_addr.sin_addr; /* don't use qp->q_from */
+ addxfer(zp);
+ } else if (SEQ_GT(zp->z_serial, serial)) {
+ if (!haveComplained((char*)zp, "went backward")) {
+ syslog(LOG_NOTICE,
+ "Zone \"%s\" (class %d) SOA serial# (%lu) rcvd from [%s] is < ours (%lu)\n",
+ zp->z_origin, zp->z_class, serial,
+ inet_ntoa(from_addr.sin_addr),
+ zp->z_serial);
+ }
+ } else {
+ dprintf(1, (ddt, "qserial_answer: zone serial is still OK\n"));
+ markUpToDate(zp);
+ }
+ done:
+ if (was_qfull)
+ needmaint = 1;
+}
+
+/*
+ * Start an asynchronous zone transfer for a zone.
+ * Depends on current time being in tt.
+ * The caller must call sched_maint after startxfer.
+ */
+static void
+startxfer(zp)
+ struct zoneinfo *zp;
+{
+ static char *argv[NSMAX + 20], argv_ns[NSMAX][MAXDNAME];
+ int argc = 0, argc_ns = 0, pid, omask;
+ unsigned int cnt;
+ char debug_str[10];
+ char serial_str[10];
+ char port_str[10];
+#ifdef GEN_AXFR
+ char class_str[10];
+#endif
+
+ dprintf(1, (ddt, "startxfer() %s\n", zp->z_origin));
+
+ 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, "%lu", zp->z_serial);
+ argv[argc++] = serial_str;
+#ifdef GEN_AXFR
+ argv[argc++] = "-C";
+ sprintf(class_str, "%d", zp->z_class);
+ argv[argc++] = class_str;
+#endif
+ if (zp->z_flags & Z_SYSLOGGED)
+ argv[argc++] = "-q";
+ argv[argc++] = "-P";
+ sprintf(port_str, "%d", ns_port);
+ argv[argc++] = port_str;
+#ifdef STUBS
+ if (zp->z_type == Z_STUB)
+ argv[argc++] = "-S";
+#endif
+#ifdef DEBUG
+ if (debug) {
+ argv[argc++] = "-d";
+ sprintf(debug_str, "%d", debug);
+ argv[argc++] = debug_str;
+ argv[argc++] = "-l";
+ argv[argc++] = _PATH_XFERDDT;
+ if (debug > 5) {
+ argv[argc++] = "-t";
+ argv[argc++] = _PATH_XFERTRACE;
+ }
+ }
+#endif
+
+ if (zp->z_xaddr.s_addr != 0) {
+ /* address was specified by the qserial logic, use it */
+ argv[argc++] = strcpy(argv_ns[argc_ns++],
+ inet_ntoa(zp->z_xaddr));
+ } else {
+ /*
+ * 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++) {
+ struct in_addr a;
+
+ a = zp->z_addr[cnt];
+ if (aIsUs(a)
+ && !haveComplained(zp->z_origin,
+ (char*)startxfer)) {
+ syslog(LOG_ERR,
+ "attempted to fetch zone %s from self (%s)",
+ zp->z_origin, inet_ntoa(a));
+ continue;
+ }
+ argv[argc++] = strcpy(argv_ns[argc_ns++],
+ inet_ntoa(a));
+ }
+ }
+
+ 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) {
+ syslog(LOG_ERR, "xfer vfork: %m");
+#ifndef SYSV
+ (void) sigsetmask(omask);
+#endif
+ zp->z_time = tt.tv_sec + 10;
+ return;
+ }
+
+ if (pid == 0) {
+ /* child */
+ execv(_PATH_XFER, argv);
+ syslog(LOG_ERR, "can't exec %s: %m", _PATH_XFER);
+ _exit(XFER_FAIL); /* avoid duplicate buffer flushes */
+ }
+ /* parent */
+ dprintf(1, (ddt, "started xfer child %d\n", pid));
+ zp->z_flags &= ~Z_NEED_XFER;
+ zp->z_flags |= Z_XFER_RUNNING;
+ zp->z_xferpid = pid;
+ xfers_running++;
+ zp->z_time = tt.tv_sec + MAX_XFER_TIME;
+#ifndef SYSV
+ (void) sigsetmask(omask);
+#endif
+}
+
+#ifdef DEBUG
+void
+printzoneinfo(zonenum)
+int zonenum;
+{
+ struct timeval tt;
+ struct zoneinfo *zp = &zones[zonenum];
+ char *ZoneType;
+
+ if (!debug)
+ return;
+
+ fprintf(ddt, "printzoneinfo(%d):\n", zonenum);
+
+ gettime(&tt);
+ switch (zp->z_type) {
+ case Z_PRIMARY:
+ ZoneType = "Primary";
+ break;
+ case Z_SECONDARY:
+ ZoneType = "Secondary";
+ break;
+#ifdef STUBS
+ case Z_STUB:
+ ZoneType = "Stub";
+ break;
+#endif
+ case Z_CACHE:
+ ZoneType = "Cache";
+ break;
+ default:
+ ZoneType = "Unknown";
+ break;
+ }
+ if (zp->z_origin != NULL && (zp->z_origin[0] == '\0'))
+ fprintf(ddt, "origin ='.'");
+ else
+ fprintf(ddt, "origin ='%s'", zp->z_origin);
+#ifdef GEN_AXFR
+ fprintf(ddt, ", class = %d", zp->z_class);
+#endif
+ fprintf(ddt, ", type = %s", ZoneType);
+ if (zp->z_source)
+ 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 = %lu\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, "; flags %x\n", zp->z_flags);
+}
+#endif /* DEBUG */
+
+/*
+ * remove_zone (htp, zone) --
+ * Delete all RR's in the zone "zone" under specified hash table.
+ */
+void
+#ifdef CLEANCACHE
+remove_zone(htp, zone, all)
+#else
+remove_zone(htp, zone)
+#endif
+ register struct hashbuf *htp;
+ register int zone;
+#ifdef CLEANCACHE
+ register int all;
+#endif
+{
+ register struct databuf *dp, *pdp;
+ register struct namebuf *np, *pnp, *npn;
+ struct namebuf **npp, **nppend;
+
+ nppend = htp->h_tab + htp->h_size;
+ for (npp = htp->h_tab; npp < nppend; npp++)
+ for (pnp = NULL, np = *npp; np != NULL; np = npn) {
+ for (pdp = NULL, dp = np->n_data; dp != NULL; ) {
+#ifdef CLEANCACHE
+ if (dp->d_zone == zone && (all || stale(dp)))
+#else
+ if (dp->d_zone == zone)
+#endif
+ dp = rm_datum(dp, np, pdp);
+ else {
+ pdp = dp;
+ dp = dp->d_next;
+ }
+ }
+
+ if (np->n_hash) {
+ /* call recursively to remove subdomains. */
+#ifdef CLEANCACHE
+ remove_zone(np->n_hash, zone, all);
+#else
+ remove_zone(np->n_hash, zone);
+#endif
+
+ /* if now empty, free it */
+ if (np->n_hash->h_cnt == 0) {
+ free((char*)np->n_hash);
+ np->n_hash = NULL;
+ }
+ }
+
+ if ((np->n_hash == NULL) && (np->n_data == NULL)) {
+ npn = rm_name(np, npp, pnp);
+ htp->h_cnt--;
+ } else {
+ npn = np->n_next;
+ pnp = np;
+ }
+ }
+}
+
+/*
+ * Handle XFER limit for a nameserver.
+ */
+static int
+nxfers(zp, delta)
+ struct zoneinfo *zp;
+ int delta;
+{
+ struct in_addr nsa;
+ struct nameser *nsp;
+ int ret;
+
+ if (zp->z_xaddr.s_addr)
+ nsa = zp->z_xaddr; /* qserial overrode address */
+ else if (!zp->z_addrcnt)
+ return (-1);
+ else
+ nsa = zp->z_addr[0]; /* first ns holds zone's xfer limit */
+
+ if (!(nsp = nameserFind(nsa, NS_F_INSERT)))
+ return (-1); /* probably ENOMEM */
+
+ ret = nsp->xfers;
+ if (delta < 0 && -delta > ret)
+ return (-1); /* taking more than we have */
+
+ nsp->xfers += delta;
+ return (ret);
+}
+
+/*
+ * Abort an xfer that has taken too long.
+ */
+static void
+abortxfer(zp)
+ struct zoneinfo *zp;
+{
+ kill(zp->z_xferpid, SIGKILL);
+ syslog(LOG_NOTICE, "zone transfer timeout for \"%s\"; pid %lu killed",
+ zp->z_origin, (u_long)zp->z_xferpid);
+ zp->z_time = tt.tv_sec + zp->z_retry;
+ (void) nxfers(zp, -1);
+ xfers_running--;
+}
+
+/*
+ * SIGCHLD signal handler: process exit of xfer's.
+ * (Note: also called when outgoing transfer completes.)
+ */
+SIG_FN
+endxfer()
+{
+ register struct zoneinfo *zp;
+ int exitstatus, pid, xfers, save_errno;
+#if defined(sequent)
+ union wait status;
+#else
+ int status;
+#endif /* sequent */
+
+ save_errno = errno;
+ xfers = 0;
+ gettime(&tt);
+#if defined(USE_WAITPID)
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+#else /* USE_WAITPID */
+ {
+ pid = wait(&status);
+#endif /* USE_WAITPID */
+ exitstatus = WIFEXITED(status) ?WEXITSTATUS(status) :0;
+
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ if (zp->z_xferpid != pid)
+ continue;
+ xfers++;
+ xfers_running--;
+ (void) nxfers(zp, -1);
+ zp->z_xferpid = 0;
+ zp->z_flags &= ~Z_XFER_RUNNING;
+ dprintf(1, (ddt,
+ "\nendxfer: child %d zone %s returned status=%d termsig=%d\n",
+ pid, zp->z_origin, exitstatus,
+ WIFSIGNALED(status) ?WTERMSIG(status) :-1
+ )
+ );
+ if (WIFSIGNALED(status)) {
+ if (WTERMSIG(status) != SIGKILL) {
+ syslog(LOG_NOTICE,
+ "named-xfer exited with signal %d\n",
+ WTERMSIG(status));
+ }
+ zp->z_time = tt.tv_sec + zp->z_retry;
+ } else {
+ switch (exitstatus) {
+ case XFER_UPTODATE:
+ markUpToDate(zp);
+ break;
+
+ case XFER_SUCCESS:
+ zp->z_flags |= Z_NEED_RELOAD;
+ zp->z_flags &= ~Z_SYSLOGGED;
+ needzoneload++;
+ break;
+
+ case XFER_TIMEOUT:
+ dprintf(1, (ddt,
+ "zoneref: Masters for secondary zone %s unreachable\n",
+ zp->z_origin));
+ if (!(zp->z_flags & Z_SYSLOGGED)) {
+ zp->z_flags |= Z_SYSLOGGED;
+ syslog(LOG_NOTICE,
+ "zoneref: Masters for secondary zone %s unreachable",
+ zp->z_origin);
+ }
+ zp->z_time = tt.tv_sec + zp->z_retry;
+ break;
+
+ default:
+ if (!(zp->z_flags & Z_SYSLOGGED)) {
+ zp->z_flags |= Z_SYSLOGGED;
+ syslog(LOG_NOTICE,
+ "named-xfer for %s exited %d",
+ zp->z_origin, exitstatus);
+ }
+ /* FALLTHROUGH */
+ case XFER_FAIL:
+ zp->z_flags |= Z_SYSLOGGED;
+ zp->z_time = tt.tv_sec + zp->z_retry;
+ break;
+ } /*switch*/
+ break;
+ } /*if/else*/
+ } /*for*/
+ } /*while*/
+ tryxfer();
+#if defined(SYSV)
+ (void)signal(SIGCLD, endxfer);
+#endif
+ errno = save_errno;
+}
+
+/*
+ * Try to start some xfers
+ */
+static void
+tryxfer() {
+ struct zoneinfo *zp;
+
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ int xfers;
+
+ if (!xfers_deferred || xfers_running >= max_xfers_running)
+ break;
+
+ if ((xfers = nxfers(zp, 0)) != -1 &&
+ xfers < MAX_XFERS_PERNS &&
+ (zp->z_flags & Z_NEED_XFER)) {
+ nxfers(zp, 1);
+ xfers_deferred--;
+ startxfer(zp);
+ }
+ }
+ if (!needmaint)
+ sched_maint();
+}
+
+/*
+ * Reload zones whose transfers have completed.
+ */
+void
+loadxfer()
+{
+ register struct zoneinfo *zp;
+
+ gettime(&tt);
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ if (zp->z_flags & Z_NEED_RELOAD) {
+ dprintf(1, (ddt, "loadxfer() \"%s\"\n",
+ zp->z_origin[0] ? zp->z_origin : "."));
+ zp->z_flags &= ~(Z_NEED_RELOAD|Z_AUTH);
+#ifdef CLEANCACHE
+ remove_zone(hashtab, zp - zones, 1);
+#else
+ remove_zone(hashtab, zp - zones);
+#endif
+ if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0)
+ zp->z_flags |= Z_AUTH;
+ if (zp->z_flags & Z_TMP_FILE)
+ (void) unlink(zp->z_source);
+ syslog(LOG_INFO,
+ "Zone \"%s\" (class %d) xfer'd and loaded (serial %lu)",
+ zp->z_origin, zp->z_class, zp->z_serial);
+ }
+ }
+ if (!needmaint)
+ sched_maint();
+}
+
+/*
+ * Add this zone to the set of those needing transfers.
+ */
+static void
+addxfer(zp)
+ struct zoneinfo *zp;
+{
+ if (!(zp->z_flags & Z_NEED_XFER)) {
+ zp->z_flags |= Z_NEED_XFER;
+ xfers_deferred++;
+ tryxfer();
+ }
+}
diff --git a/usr.sbin/named/ns_ncache.c b/usr.sbin/named/ns_ncache.c
new file mode 100644
index 0000000..5408342
--- /dev/null
+++ b/usr.sbin/named/ns_ncache.c
@@ -0,0 +1,152 @@
+/**************************************************************************
+ * ns_ncache.c
+ * author: anant kumar
+ * last modification: March 17, 1993
+ *
+ * implements negative caching
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <syslog.h>
+#include <errno.h>
+#include <stdio.h>
+#include <resolv.h>
+
+#include "named.h"
+
+#ifdef NCACHE
+
+void
+cache_n_resp(msg, msglen)
+ u_char *msg;
+ int msglen;
+{
+ register struct databuf *dp;
+ HEADER *hp;
+ u_char *cp;
+ char dname[MAXDNAME];
+ int n;
+ int type, class;
+ int Vcode;
+ int flags;
+
+ nameserIncr(from_addr.sin_addr, nssRcvdNXD);
+
+ hp = (HEADER *)msg;
+ cp = msg+HFIXEDSZ;
+
+ n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname);
+ if (n < 0) {
+ dprintf(1, (ddt, "Query expand name failed:cache_n_resp\n"));
+ hp->rcode = FORMERR;
+ return;
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ dprintf(1, (ddt,
+ "ncache: dname %s, type %d, class %d\n",
+ dname, type, class));
+
+#ifdef VALIDATE
+ Vcode = validate(dname, &from_addr, type, class, NULL, 0,
+ hp->rcode == NXDOMAIN ? NXDOMAIN : NOERROR_NODATA);
+ if (Vcode == INVALID || Vcode == VALID_NO_CACHE) {
+ /*Valid_no_cache should never occur but doesn't hurt to check*/
+ return;
+ }
+#endif
+#ifdef RETURNSOA
+ if (hp->rcode==NXDOMAIN) {
+ u_int32_t ttl;
+ u_int16_t atype;
+ u_char * tp = cp;
+ u_char * cp1;
+ u_char data[BUFSIZ+MAXDNAME];
+ int len = sizeof(data);
+
+ /* store ther SOA record */
+ if (!hp->nscount) {
+ dprintf(3, (ddt, "ncache: nscount == 0\n"));
+ return;
+ }
+ n = dn_skipname(tp, msg + msglen);
+ if (n < 0) {
+ dprintf(3, (ddt, "ncache: form error\n"));
+ return;
+ }
+ tp += n;
+ GETSHORT(atype,tp); /* type */
+ if (atype != T_SOA) {
+ dprintf(3, (ddt, "ncache: type (%d) != T_SOA\n",atype));
+ return;
+ }
+ tp += sizeof(u_int16_t); /* class */
+ GETLONG(ttl,tp); /* ttl */
+ tp += sizeof(u_int16_t); /* dlen */
+
+ if ((n = dn_expand(msg, msg + msglen, tp, data, len))
+ < 0 ) {
+ dprintf(3, (ddt, "ncache: form error 2\n"));
+ return;
+ } /* origin */
+ tp += n;
+ cp1 = data + (n = strlen(data) + 1);
+ len -= n;
+ if ((n = dn_expand(msg, msg + msglen, tp, cp1, len)) < 0 ) {
+ dprintf(3, (ddt, "ncache: form error 2\n"));
+ return;
+ } /* mail */
+ tp += n;
+ n = strlen(cp1) + 1;
+ cp1 += n;
+ len -= n;
+ bcopy(tp, cp1, n = 5 * sizeof(u_int32_t));
+ /* serial, refresh, retry, expire, min */
+ cp1 += n;
+ len -= n;
+ /* store the zone of the soa record */
+ if ((n = dn_expand(msg, msg + msglen, cp, cp1, len)) < 0 ) {
+ dprintf(3, (ddt, "ncache: form error 2\n"));
+ return;
+ }
+ n = strlen(cp1) + 1;
+ cp1 += n;
+
+ dp = savedata(class, T_SOA, MIN(ttl,NTTL)+tt.tv_sec, data,
+ cp1 - data);
+ } else {
+#endif
+ dp = savedata(class, type, NTTL+tt.tv_sec, NULL, 0);
+#ifdef RETURNSOA
+ }
+#endif
+ dp->d_zone = DB_Z_CACHE;
+ dp->d_cred = hp->aa ? DB_C_AUTH : DB_C_ANSWER;
+ dp->d_clev = 0;
+ if(hp->rcode == NXDOMAIN) {
+ dp->d_rcode = NXDOMAIN;
+ flags = DB_NODATA|DB_NOTAUTH|DB_NOHINTS;
+ } else {
+ dp->d_rcode = NOERROR_NODATA;
+ flags = DB_NOTAUTH|DB_NOHINTS;
+ }
+
+ if ((n = db_update(dname,dp,dp,flags,hashtab)) != OK) {
+ dprintf(1, (ddt,
+ "db_update failed return value:%d, cache_n_resp()\n",
+ n));
+ free((char *)dp);
+ return;
+ }
+ dprintf(4, (ddt,
+ "ncache succeeded: d:%s, t:%d, c:%d rcode:%d ttl:%d\n",
+ dname,type,class,dp->d_rcode, dp->d_ttl-tt.tv_sec));
+ return;
+}
+
+#endif /*NCACHE*/
diff --git a/usr.sbin/named/ns_req.c b/usr.sbin/named/ns_req.c
new file mode 100644
index 0000000..afc3fc5
--- /dev/null
+++ b/usr.sbin/named/ns_req.c
@@ -0,0 +1,1793 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_req.c 4.47 (Berkeley) 7/1/91";
+static char rcsid[] = "$Id: ns_req.c,v 4.9.1.22 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988, 1990
+ * -
+ * Copyright (c) 1986, 1988, 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <errno.h>
+#include <stdio.h>
+#include <resolv.h>
+
+#include "named.h"
+
+struct addinfo {
+ char *a_dname; /* domain name */
+ u_int a_class; /* class for address */
+};
+
+enum req_action { Finish, Refuse, Return };
+
+static enum req_action req_query __P((HEADER *hp, u_char **cpp, u_char *eom,
+ struct qstream *qsp,
+ int *buflenp, int *msglenp,
+ u_char *msg, int dfd,
+ struct sockaddr_in *from));
+
+#ifdef INVQ
+static enum req_action req_iquery __P((HEADER *hp, u_char **cpp, u_char *eom,
+ int *buflenp, u_char *msg,
+ struct sockaddr_in *from));
+#endif
+
+static void fwritemsg __P((FILE *, u_char *, int)),
+ doaxfr __P((struct namebuf *, FILE *,
+ struct namebuf *, int)),
+ startxfr __P((struct qstream *, struct namebuf *,
+ u_char *, int, int, const char *)),
+ printSOAdata __P((struct databuf));
+
+#ifdef ALLOW_UPDATES
+static int InitDynUpdate __P((register HEADER *hp,
+ char *msg,
+ int msglen,
+ u_char *startcp,
+ struct sockaddr_in *from,
+ struct qstream *qsp,
+ int dfd));
+#endif
+
+static struct addinfo addinfo[NADDRECS];
+static void addname __P((char *, u_int16_t));
+
+/*
+ * Process request using database; assemble and send response.
+ */
+void
+ns_req(msg, msglen, buflen, qsp, from, dfd)
+ u_char *msg;
+ int msglen, buflen;
+ struct qstream *qsp;
+ struct sockaddr_in *from;
+ int dfd;
+{
+ register HEADER *hp = (HEADER *) msg;
+ u_char *cp, *eom;
+ enum req_action action;
+
+#ifdef DEBUG
+ if (debug > 3) {
+ fprintf(ddt, "ns_req(from=[%s].%d)\n",
+ inet_ntoa(from->sin_addr), ntohs(from->sin_port));
+ fp_query(msg, ddt);
+ }
+#endif
+
+ /*
+ * XXX - this decision should be made by our caller, not by us.
+ */
+ if (hp->qr) {
+ ns_resp(msg, msglen);
+
+ /* Now is a safe time for housekeeping */
+ if (needs_prime_cache)
+ prime_cache();
+
+ return;
+ }
+
+ /* its a query and these bits have no business
+ * being set. will later simplify work if we can
+ * safely assume these are always 0 when a query
+ * comes in
+ */
+ hp->aa = hp->ra = 0;
+
+ hp->rcode = NOERROR;
+ cp = msg + HFIXEDSZ;
+ eom = msg + msglen;
+
+ dnptrs[0] = msg;
+ dnptrs[1] = NULL;
+
+ free_addinfo(); /* sets addcount to zero */
+ dnptrs[0] = NULL;
+
+ switch (hp->opcode) {
+ case QUERY:
+ action = req_query(hp, &cp, eom, qsp,
+ &buflen, &msglen,
+ msg, dfd, from);
+ break;
+
+#ifdef INVQ
+ case IQUERY:
+ action = req_iquery(hp, &cp, eom, &buflen, msg, from);
+ break;
+#endif
+
+#ifdef ALLOW_UPDATES
+#define FORWARDED 1000
+/*
+ * In a sense the following constant should be defined in <arpa/nameser.h>,
+ * since it is returned here in place of a response code if the update was
+ * forwarded, and the response codes are defined in nameser.h. On the other
+ * hand, though, this constant is only seen in this file. The assumption
+ * here is that none of the other return codes equals this one (a good
+ * assumption, since they only occupy 4 bits over-the-wire)
+ */
+ /* Call InitDynUpdate for all dynamic update requests */
+ case UPDATEM:
+ case UPDATEMA:
+ case UPDATED:
+ case UPDATEDA:
+ case UPDATEA:
+ n = InitDynUpdate(hp, msg, msglen, cp, from, qsp, dfd);
+ if (n == FORWARDED) {
+ /* Return directly because InitDynUpdate
+ * forwarded the query to the primary, so we
+ * will send response later
+ */
+ action = Return;
+ } else {
+ /* Either sucessful primary update or failure;
+ * return response code to client
+ */
+ action = Finish;
+ }
+#endif /* ALLOW_UPDATES */
+
+ case ZONEREF:
+ dprintf(1, (ddt, "Refresh Zone\n"));
+ /*FALLTHROUGH*/
+
+ default:
+ dprintf(1, (ddt, "ns_req: Opcode %d not implemented\n",
+ hp->opcode));
+ /* XXX - should syslog, limited by haveComplained */
+ hp->qdcount = 0;
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ hp->rcode = NOTIMP;
+ action = Finish;
+ }
+
+ /*
+ * vector via internal opcode. (yes, it was even uglier before.)
+ */
+ switch (action) {
+ case Return:
+ return;
+ case Refuse:
+ hp->rcode = REFUSED;
+ /*FALLTHROUGH*/
+ case Finish:
+ /* rest of the function handles this case */
+ break;
+ default:
+ syslog(LOG_CRIT, "bad action variable in ns_req() -- %d",
+ (int) action);
+ return; /* XXX - should really exit here */
+ }
+
+ /*
+ * apply final polish
+ */
+ hp->qr = 1; /* set Response flag */
+ if (NoRecurse)
+ hp->ra = 0; /* No recursion; maybe we're a root server */
+ else
+ hp->ra = 1; /* Recursion is Available */
+ hp->ancount = htons(hp->ancount);
+ if (addcount) {
+ int n = doaddinfo(hp, cp, buflen);
+ cp += n;
+ buflen -= n;
+ }
+
+ dprintf(1, (ddt, "ns_req: answer -> [%s].%d fd=%d id=%d %s\n",
+ inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port),
+ (qsp == QSTREAM_NULL) ?dfd :qsp->s_rfd,
+ ntohs(hp->id), local(from) == NULL ? "Remote" : "Local"));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(msg, ddt);
+#endif
+ if (qsp == QSTREAM_NULL) {
+ if (sendto(dfd, msg, cp - msg, 0,
+ (struct sockaddr *)from,
+ sizeof(*from)) < 0) {
+ if (!haveComplained((char*)from->sin_addr.s_addr,
+ sendtoStr))
+ syslog(LOG_NOTICE,
+ "ns_req: sendto([%s].%d): %m",
+ inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port));
+ nameserIncr(from->sin_addr, nssSendtoErr);
+ }
+ nameserIncr(from->sin_addr, nssSentAns);
+ } else {
+ (void) writemsg(qsp->s_rfd, msg, cp - msg);
+ sq_done(qsp);
+ }
+
+ if (needs_prime_cache) {
+ prime_cache(); /* Now is a safe time */
+ }
+}
+
+static enum req_action
+req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from)
+ HEADER *hp;
+ u_char **cpp;
+ u_char *eom;
+ struct qstream *qsp;
+ u_char *msg;
+ int *buflenp, *msglenp, dfd;
+ struct sockaddr_in *from;
+{
+ int n, class, type, count, foundname, founddata, omsglen, cname;
+ u_int16_t id;
+ u_char **dpp, *omsg, *answers;
+ char dnbuf[MAXDNAME], *dname, *fname;
+ struct hashbuf *htp;
+ struct databuf *nsp[NSMAX];
+ struct namebuf *np;
+ struct qinfo *qp;
+ struct netinfo *lp;
+
+ nameserIncr(from->sin_addr, nssRcvdQ);
+#ifdef DATUMREFCNT
+ nsp[0] = NULL;
+#endif
+
+ dpp = dnptrs;
+ *dpp++ = msg;
+ *dpp = NULL;
+
+ /* valid queries have one question and zero answers */
+ if ((ntohs(hp->qdcount) != 1)
+ || hp->ancount
+ || hp->nscount
+ || hp->arcount) {
+ dprintf(1, (ddt, "FORMERR Query header counts wrong\n"));
+ hp->qdcount = 0;
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+
+ /*
+ * Get domain name, class, and type.
+ */
+ if ((**cpp & INDIR_MASK) == 0) {
+ *dpp++ = *cpp; /* remember name for compression */
+ }
+ *dpp = NULL;
+ n = dn_expand(msg, eom, *cpp, dnbuf, sizeof dnbuf);
+ if (n < 0) {
+ dprintf(1, (ddt, "FORMERR Query expand name failed\n"));
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ *cpp += n;
+ GETSHORT(type, *cpp);
+ GETSHORT(class, *cpp);
+ if (*cpp > eom) {
+ dprintf(1, (ddt, "FORMERR Query message length short\n"));
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ if (*cpp < eom) {
+ dprintf(6, (ddt,"message length > received message\n"));
+ *msglenp = *cpp - msg;
+ }
+
+ qtypeIncr(type);
+
+ /*
+ * Process query.
+ */
+ if (type == T_AXFR) {
+ /* refuse request if not a TCP connection */
+ if (qsp == QSTREAM_NULL) {
+ syslog(LOG_INFO,
+ "rejected UDP AXFR from [%s].%u for \"%s\"",
+ inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port),
+ *dnbuf ? dnbuf : ".");
+ return (Refuse);
+ }
+ /* the position of this is subtle. */
+ nameserIncr(from->sin_addr, nssRcvdAXFR);
+#ifdef XFRNETS
+ if (xfrnets) {
+ /* if xfrnets was specified, peer address
+ * must be on it. should probably allow
+ * for negation some day.
+ */
+ if (!addr_on_netlist(from->sin_addr, xfrnets)) {
+ syslog(LOG_INFO,
+ "unapproved AXFR from [%s].%u for %s",
+ inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port),
+ *dnbuf ? dnbuf : ".");
+ return (Refuse);
+ }
+ }
+#endif /*XFRNETS*/
+ dnptrs[0] = NULL; /* don't compress names */
+ hp->rd = 0; /* recursion not possible */
+ syslog(LOG_INFO, "approved AXFR from [%s].%d for \"%s\"",
+ inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port),
+ *dnbuf ? dnbuf : ".");
+ }
+ *buflenp -= *msglenp;
+ count = 0;
+ foundname = 0;
+ founddata = 0;
+ dname = dnbuf;
+ cname = 0;
+
+#ifdef QRYLOG
+ if (qrylog) {
+ syslog(LOG_INFO, "XX /%s/%s/%s",
+ inet_ntoa(from->sin_addr),
+ (dname[0] == '\0') ?"." :dname,
+ p_type(type));
+ }
+#endif /*QRYLOG*/
+
+try_again:
+ dprintf(1, (ddt, "req: nlookup(%s) id %d type=%d\n",
+ dname, hp->id, type));
+ htp = hashtab; /* lookup relative to root */
+ if ((np = nlookup(dname, &htp, &fname, 0)) == NULL)
+ fname = "";
+ dprintf(1, (ddt, "req: %s '%s' as '%s' (cname=%d)\n",
+ np == NULL ? "missed" : "found",
+ dname, fname, cname));
+
+#ifdef LOCALDOM
+ /*
+ * if nlookup failed to find the name then
+ * see if there are any '.''s in the name
+ * if not then add local domain name to the
+ * name and try again.
+ */
+ if (!np && localdomain && !strchr(dname, '.')) {
+ (void) strcat(dname, ".");
+ (void) strcat(dname, localdomain);
+ dprintf(1, (ddt,"req: nlookup(%s) type=%d\n", dname, type));
+ htp = hashtab;
+ np = nlookup(dname, &htp, &fname, 0);
+ }
+#endif /*LOCALDOM*/
+
+#ifdef YPKLUDGE
+ /* Some braindamaged resolver software will not
+ recognize internet addresses in dot notation and
+ send out address queries for "names" such as
+ 128.93.8.1. This kludge will prevent those
+ from flooding higher level servers.
+ We simply claim to be authoritative and that
+ the domain doesn't exist.
+ Note that we could return the address but we
+ don't do that in order to encourage that broken
+ software is fixed.
+ */
+
+ if (!np && type == T_A && class == C_IN && dname) {
+ struct in_addr ina;
+
+ if (inet_aton(dname, &ina)) {
+ hp->rcode = NXDOMAIN;
+ hp->aa = 1;
+ dprintf(3, (ddt, "ypkludge: hit as '%s'\n", dname));
+ return (Finish);
+ }
+ }
+#endif /*YPKLUDGE*/
+
+ if ((!np) || (fname != dname))
+ goto fetchns;
+
+#ifdef SECURE_ZONES
+ if (np->n_data) {
+ struct zoneinfo *zp;
+
+ zp = &zones[np->n_data->d_zone];
+ if (zp->secure_nets
+ && !addr_on_netlist(from->sin_addr, zp->secure_nets)) {
+ dprintf(1, (ddt,
+ "REFUSED Unauthorized request from %s\n",
+ inet_ntoa(from->sin_addr)));
+ syslog(LOG_INFO, "Unauthorized request %s from %s",
+ dname, inet_ntoa(from->sin_addr));
+ return (Refuse);
+ }
+ }
+#endif
+ foundname++;
+ answers = *cpp;
+ count = *cpp - msg;
+
+#ifdef NCACHE
+ /* if this is a NXDOMAIN, will have only one databuf
+ * whose d_rcode field will be NXDOMAIN. So we can go home
+ * right here. -ve $ing: anant@isi.edu
+ */
+ if (np->n_data != NULL && !stale(np->n_data)) {
+ if (np->n_data->d_rcode == NXDOMAIN) {
+#ifdef RETURNSOA
+ n = finddata(np, class, T_SOA, hp, &dname,
+ buflenp, &count);
+ if (n != 0 ) {
+ if (hp->rcode == NOERROR_NODATA) {
+ /* this should not occur */
+ hp->rcode = NOERROR;
+ return (Finish);
+ }
+ *cpp += n;
+ *buflenp -= n;
+ *msglenp += n;
+ hp->rcode = NXDOMAIN;
+ hp->nscount = htons((u_int16_t)count);
+ hp->aa = 1;
+ return (Finish);
+ }
+ else
+ goto fetchns;
+#else
+ hp->rcode = NXDOMAIN;
+ hp->aa = 1;
+ return (Finish);
+#endif
+ }
+ }
+
+ /* if not NXDOMAIN, the NOERROR_NODATA record might be
+ * anywhere in the chain. have to go through the grind.
+ */
+#endif /*NCACHE*/
+
+ n = finddata(np, class, type, hp, &dname, buflenp, &count);
+ if (n == 0) {
+ /* NO data available. Refuse AXFR requests, or
+ * look for better servers for other requests.
+ */
+ if (type == T_AXFR) {
+ dprintf(1, (ddt, "T_AXFR refused: no data\n"));
+ return (Refuse);
+ } else {
+ goto fetchns;
+ }
+ }
+
+#ifdef NCACHE
+ if (hp->rcode == NOERROR_NODATA) {
+ hp->rcode = NOERROR;
+ founddata = 1;
+ return (Finish);
+ }
+#endif
+
+ *cpp += n;
+ *buflenp -= n;
+ *msglenp += n;
+ hp->ancount += count;
+ if (fname != dname && type != T_CNAME && type != T_ANY) {
+ if (cname++ >= MAXCNAMES) {
+ dprintf(3, (ddt,
+ "resp: leaving, MAXCNAMES exceeded\n"));
+ hp->rcode = SERVFAIL;
+ return (Finish);
+ }
+ goto try_again;
+ }
+ founddata = 1;
+ dprintf(3, (ddt,
+ "req: foundname=%d, count=%d, founddata=%d, cname=%d\n",
+ foundname, count, founddata, cname));
+
+ if ((lp = local(from)) != NULL)
+ sort_response(answers, count, lp, *cpp);
+ if (type == T_AXFR) {
+ hp->ancount = htons(hp->ancount);
+ startxfr(qsp, np, msg, *cpp - msg, class, dname);
+ sqrm(qsp);
+ return (Return);
+ }
+
+#ifdef notdef
+ /*
+ * If we found an authoritative answer,
+ * we're done.
+ */
+ if (hp->aa)
+ return (Finish);
+#endif
+
+fetchns:
+ /*
+ * Look for name servers to refer to and fill in the authority
+ * section or record the address for forwarding the query
+ * (recursion desired).
+ */
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ nsp[0] = NULL;
+ count = 0;
+ switch (findns(&np, class, nsp, &count, 0)) {
+ case NXDOMAIN:
+ if (!foundname) {
+ hp->rcode = NXDOMAIN;
+ }
+ dprintf(3, (ddt, "req: leaving (%s, rcode %d)\n",
+ dname, hp->rcode));
+ if (class != C_ANY) {
+ hp->aa = 1;
+ /* XXX: 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, *cpp, *buflenp, np, nsp[0]);
+ *cpp += n;
+ *buflenp -= n;
+#ifdef ADDAUTH
+ } else if (hp->ancount) {
+ /* don't add NS records for NOERROR NODATA
+ as some severs can get confused */
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ switch (findns(&np, class, nsp, &count, 1)) {
+ case NXDOMAIN:
+ case SERVFAIL:
+ break;
+ default:
+ if (np) {
+ n = add_data(np, nsp, *cpp,
+ *buflenp);
+ if (n < 0) {
+ hp->tc = 1;
+ n = (-n);
+ }
+ *cpp += n;
+ *buflenp -= n;
+ hp->nscount =
+ htons((u_int16_t)
+ count);
+ }
+ }
+#endif /*ADDAUTH*/
+ }
+ }
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+
+ case SERVFAIL:
+ if (!founddata && !(forward_only && fwdtab)) {
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+ }
+ }
+
+ /*
+ * If we successfully found the answer in the cache,
+ * or this is not a recursive query, or we are purposely
+ * never recursing, then add the nameserver references
+ * ("authority section") here and we're done.
+ */
+ if (founddata || (!hp->rd) || NoRecurse) {
+ n = add_data(np, nsp, *cpp, *buflenp);
+ if (n < 0) {
+ hp->tc = 1;
+ n = (-n);
+ }
+ *cpp += n;
+ *buflenp -= n;
+ hp->nscount = htons((u_int16_t)count);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+ }
+
+ /*
+ * At this point, we don't have the answer, but we do
+ * have some NS's to try. If the user would like us
+ * to recurse, create the initial query. If a cname
+ * is involved, we need to build a new query and save
+ * the old one in cmsg/cmsglen.
+ */
+ if (cname) {
+ omsg = (u_char *)malloc((unsigned) *msglenp);
+ if (omsg == (u_char *)NULL) {
+ dprintf(1, (ddt, "ns_req: malloc fail\n"));
+ syslog(LOG_ERR, "ns_req: Out Of Memory");
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+ }
+ id = hp->id;
+ hp->ancount = htons(hp->ancount);
+ omsglen = *msglenp;
+ bcopy(msg, omsg, omsglen);
+ *msglenp = res_mkquery(QUERY, dname, class, type,
+ NULL, 0, NULL, msg,
+ *msglenp + *buflenp);
+ }
+ n = ns_forw(nsp, msg, *msglenp, from, qsp, dfd, &qp, dname, np);
+ if (n != FW_OK && cname)
+ free(omsg);
+ switch (n) {
+ case FW_OK:
+ if (cname) {
+ qp->q_cname = cname;
+ qp->q_cmsg = omsg;
+ qp->q_cmsglen = omsglen;
+ qp->q_id = id;
+ }
+ break;
+ case FW_DUP:
+ break; /* Duplicate request dropped */
+ case FW_NOSERVER:
+ /*
+ ** Don't go into an infinite loop if
+ ** the admin gave root NS records in the cache
+ ** file without giving address records
+ ** for the root servers.
+ */
+ if (np) {
+ if (np->n_dname[0] == '\0') {
+ dprintf(1, (ddt,
+ "ns_req: no address for root NS\n"
+ ));
+ syslog(LOG_ERR,
+ "ns_req: no address for root server");
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+ }
+#ifdef VALIDATE
+ /*
+ * we need to kill all the NS records here as
+ * validate will fail as we are talking to the parent
+ * server
+ */
+ delete_all(np, class, T_NS);
+#endif
+ np = np->n_parent;
+ }
+ goto fetchns; /* Try again. */
+ case FW_SERVFAIL:
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+ }
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Return);
+}
+
+#ifdef INVQ
+static enum req_action
+req_iquery(hp, cpp, eom, buflenp, msg, from)
+ HEADER *hp;
+ u_char **cpp, *eom;
+ int *buflenp;
+ u_char *msg;
+ struct sockaddr_in *from;
+{
+ register struct invbuf *ip;
+ int dlen, alen, i, n, type, class, count;
+ char dnbuf[MAXDNAME], anbuf[PACKETSZ], *data, *fname;
+ struct namebuf *np;
+ struct qinfo *qp;
+ struct databuf *dp;
+
+ nameserIncr(from->sin_addr, nssRcvdIQ);
+
+ hp->ancount = htons(hp->ancount);
+ if ((hp->ancount != 1)
+ || hp->qdcount
+ || hp->nscount
+ || hp->arcount) {
+ dprintf(1, (ddt, "FORMERR IQuery header counts wrong\n"));
+ hp->qdcount = 0;
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+
+ /*
+ * Skip domain name, get class, and type.
+ */
+ if ((n = dn_skipname(*cpp, eom)) < 0) {
+ dprintf(1, (ddt, "FORMERR IQuery packet name problem\n"));
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ *cpp += n;
+ GETSHORT(type, *cpp);
+ GETSHORT(class, *cpp);
+ *cpp += INT32SZ; /* ttl */
+ GETSHORT(dlen, *cpp);
+ *cpp += dlen;
+ if (*cpp != eom) {
+ dprintf(1, (ddt, "FORMERR IQuery message length off\n"));
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+
+ /*
+ * not all inverse queries are handled.
+ */
+ switch (type) {
+ case T_A:
+ case T_UID:
+ case T_GID:
+ break;
+ default:
+ return (Refuse);
+ }
+ dprintf(1, (ddt, "req: IQuery class %d type %d\n", class, type));
+
+ fname = (char *)msg + HFIXEDSZ;
+ bcopy(fname, anbuf, alen = (char *)*cpp - fname);
+ data = anbuf + alen - dlen;
+ *cpp = (u_char *)fname;
+ *buflenp -= HFIXEDSZ;
+ count = 0;
+ for (ip = invtab[dhash((u_char *)data, dlen)];
+ ip != NULL;
+ ip = ip->i_next) {
+ for (i = 0; i < INVBLKSZ; i++) {
+ if ((np = ip->i_dname[i]) == NULL)
+ break;
+ dprintf(5, (ddt, "dname = %d\n", np->n_dname));
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!match(dp, class, type))
+ continue;
+ if (dp->d_size != dlen ||
+ bcmp(dp->d_data, data, dlen))
+ continue;
+ getname(np, dnbuf, sizeof(dnbuf));
+ dprintf(2, (ddt, "req: IQuery found %s\n",
+ dnbuf));
+ *buflenp -= QFIXEDSZ;
+ n = dn_comp(dnbuf, *cpp, *buflenp, NULL, NULL);
+ if (n < 0) {
+ hp->tc = 1;
+ return (Finish);
+ }
+ *cpp += n;
+ PUTSHORT((u_int16_t)dp->d_type, *cpp);
+ PUTSHORT((u_int16_t)dp->d_class, *cpp);
+ *buflenp -= n;
+ count++;
+ }
+ }
+ }
+ dprintf(1, (ddt, "req: IQuery %d records\n", count));
+ hp->qdcount = htons((u_int16_t)count);
+ if (alen > *buflenp) {
+ hp->tc = 1;
+ return (Finish);
+ }
+ bcopy(anbuf, *cpp, alen);
+ *cpp += alen;
+ return (Finish);
+}
+#endif
+
+static void
+fwritemsg(rfp, msg, msglen)
+ FILE *rfp;
+ u_char *msg;
+ int msglen;
+{
+ u_char len[INT16SZ];
+
+ __putshort(msglen, len);
+ if (fwrite((char *)len, INT16SZ, 1, rfp) != 1 ||
+ fwrite((char *)msg, msglen, 1, rfp) != 1) {
+ dprintf(1, (ddt, "fwrite failed %d\n", errno));
+ }
+}
+
+/*
+ * Test a datum for validity and return non-zero if it is out of date.
+ */
+int
+stale(dp)
+ register struct databuf *dp;
+{
+ register struct zoneinfo *zp = &zones[dp->d_zone];
+
+ switch (zp->z_type) {
+
+ case Z_PRIMARY:
+ return (0);
+
+ case Z_SECONDARY:
+#ifdef STUBS
+ case Z_STUB:
+#endif
+ /*
+ * Check to see whether a secondary zone
+ * has expired; if so clear authority flag
+ * for zone and return true. If lastupdate
+ * is in the future, assume zone is up-to-date.
+ */
+ if ((int32_t)(tt.tv_sec - zp->z_lastupdate)
+ > (int32_t)zp->z_expire) {
+ dprintf(1, (ddt,
+ "stale: secondary zone %s expired\n",
+ zp->z_origin));
+ if (!haveComplained(zp->z_origin, (char*)stale)) {
+ syslog(LOG_ERR,
+ "secondary zone \"%s\" expired",
+ zp->z_origin);
+ }
+ zp->z_flags &= ~Z_AUTH;
+ return (1);
+ }
+ return (0);
+
+ case Z_CACHE:
+ if (dp->d_flags & DB_F_HINT || dp->d_ttl >= tt.tv_sec)
+ return (0);
+ dprintf(3, (ddt, "stale: ttl %d %d (x%x)\n",
+ dp->d_ttl, dp->d_ttl - tt.tv_sec, dp->d_flags));
+ return (1);
+
+ default:
+ /* FALLTHROUGH */ ;
+
+ }
+ abort();
+ /* NOTREACHED */
+}
+
+/*
+ * Copy databuf into a resource record for replies.
+ * Return size of RR if OK, -1 if buffer is full.
+ */
+int
+make_rr(name, dp, buf, buflen, doadd)
+ char *name;
+ register struct databuf *dp;
+ u_char *buf;
+ int buflen, doadd;
+{
+ register u_char *cp;
+ u_char *cp1, *sp;
+ struct zoneinfo *zp;
+ register int32_t n;
+ register int32_t ttl;
+ u_char **edp = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+
+ dprintf(5, (ddt, "make_rr(%s, %x, %x, %d, %d) %d zone %d ttl %d\n",
+ name, dp, buf,
+ buflen, doadd, dp->d_size, dp->d_zone, dp->d_ttl));
+
+#ifdef NCACHE
+ if (dp->d_rcode
+#ifdef RETURNSOA
+ && dp->d_rcode != NXDOMAIN
+#endif
+ ) {
+ syslog(LOG_CRIT, "make_rr d_rcode %d", dp->d_rcode);
+#ifdef DEBUG
+ if (debug) abort();
+#endif
+ return (-1); /* XXX We should exit here */
+ }
+#endif
+ zp = &zones[dp->d_zone];
+ /* check for outdated RR before updating dnptrs by dn_comp() (???) */
+ if (zp->z_type == Z_CACHE) {
+ ttl = dp->d_ttl - (u_int32_t) tt.tv_sec;
+ if ((dp->d_flags & DB_F_HINT) || (ttl < 0)) {
+ dprintf(3, (ddt,
+ "make_rr: %d=>0, x%x\n",
+ ttl, dp->d_flags)); /* XXX */
+ ttl = 0;
+ }
+ } else {
+ if (dp->d_ttl)
+ ttl = dp->d_ttl;
+ else
+ ttl = zp->z_minimum; /* really default */
+#ifdef notdef /* don't decrease ttl based on time since verification */
+ if (zp->z_type == Z_SECONDARY) {
+ /*
+ * Set ttl to value received from primary,
+ * less time since we verified it (but never
+ * less than a small positive value).
+ */
+ ttl -= tt.tv_sec - zp->z_lastupdate;
+ if (ttl <= 0)
+ ttl = 120;
+ }
+#endif
+ }
+
+ buflen -= RRFIXEDSZ;
+#if defined(RETURNSOA) && defined(NCACHE)
+ if (dp->d_rcode == NXDOMAIN) {
+ name = (char *)dp->d_data;
+ name += strlen(name) +1;
+ name += strlen(name) +1;
+ name += 5 * INT32SZ;
+ }
+#endif
+ if ((n = dn_comp(name, buf, buflen, dnptrs, edp)) < 0)
+ return (-1);
+ cp = buf + n;
+ buflen -= n;
+ PUTSHORT((u_int16_t)dp->d_type, cp);
+ PUTSHORT((u_int16_t)dp->d_class, cp);
+ PUTLONG(ttl, cp);
+ sp = cp;
+ cp += INT16SZ;
+ switch (dp->d_type) {
+ case T_CNAME:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ n = dn_comp((char *)dp->d_data, cp, buflen, dnptrs, edp);
+ if (n < 0)
+ return (-1);
+ PUTSHORT((u_int16_t)n, sp);
+ cp += n;
+ break;
+
+ case T_MB:
+ case T_NS:
+ /* Store domain name in answer */
+ n = dn_comp((char *)dp->d_data, cp, buflen, dnptrs, edp);
+ if (n < 0)
+ return (-1);
+ PUTSHORT((u_int16_t)n, sp);
+ cp += n;
+ if (doadd)
+ addname((char*)dp->d_data, dp->d_class);
+ break;
+
+ case T_SOA:
+ case T_MINFO:
+ case T_RP:
+ cp1 = dp->d_data;
+ n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ buflen -= dp->d_type == T_SOA ? n + 5 * INT32SZ : n;
+ cp1 += strlen((char *)cp1) + 1;
+ n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ if (dp->d_type == T_SOA) {
+ cp1 += strlen((char *)cp1) + 1;
+ bcopy(cp1, cp, (n = 5 * INT32SZ));
+ cp += n;
+ }
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ PUTSHORT((u_int16_t)n, sp);
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ /* cp1 == our data/ cp == data of RR */
+ cp1 = dp->d_data;
+
+ /* copy preference */
+ bcopy(cp1, cp, INT16SZ);
+ cp += INT16SZ;
+ cp1 += INT16SZ;
+ buflen -= INT16SZ;
+
+ n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp);
+ if (n < 0)
+ return (-1);
+ cp += n;
+
+ /* save data length */
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ PUTSHORT((u_int16_t)n, sp);
+ if (doadd)
+ addname((char*)cp1, dp->d_class);
+ break;
+
+ default:
+ if (dp->d_size > buflen)
+ return (-1);
+ bcopy(dp->d_data, cp, dp->d_size);
+ PUTSHORT((u_int16_t)dp->d_size, sp);
+ cp += dp->d_size;
+ }
+ return (cp - buf);
+}
+
+#if defined(__STDC__) || defined(__GNUC__)
+static void
+addname(register char *name,
+ u_int16_t class)
+#else
+static void
+addname(name, class)
+ register char *name;
+ u_int16_t class;
+#endif
+{
+ register struct addinfo *ap;
+ register int n;
+
+ for (ap = addinfo, n = addcount; --n >= 0; ap++)
+ if (strcasecmp(ap->a_dname, name) == 0)
+ return;
+
+
+ /* add domain name to additional section */
+ if (addcount < NADDRECS) {
+ addcount++;
+ ap->a_dname = (char *)malloc(strlen(name)+1);
+ strcpy(ap->a_dname,name);
+ ap->a_class = class;
+ }
+}
+
+/*
+ * Lookup addresses for names in addinfo and put into the message's
+ * additional section.
+ */
+int
+doaddinfo(hp, msg, msglen)
+ HEADER *hp;
+ u_char *msg;
+ int msglen;
+{
+ register struct namebuf *np;
+ register struct databuf *dp;
+ register struct addinfo *ap;
+ register u_char *cp;
+ struct hashbuf *htp;
+ char *fname;
+ int n, count;
+
+ dprintf(3, (ddt, "doaddinfo() addcount = %d\n", addcount));
+
+ if (hp->tc) {
+ dprintf(4, (ddt, "doaddinfo(): tc already set, bailing\n"));
+ return (0);
+ }
+
+ count = 0;
+ cp = msg;
+ for (ap = addinfo; --addcount >= 0; ap++) {
+ int foundstale = 0,
+ foundany = 0,
+ save_count = count,
+ save_msglen = msglen;
+ u_char *save_cp = cp;
+
+ dprintf(3, (ddt, "do additional '%s'\n", ap->a_dname));
+ htp = hashtab; /* because "nlookup" stomps on arg. */
+ np = nlookup(ap->a_dname, &htp, &fname, 0);
+ if (np == NULL || fname != ap->a_dname)
+ goto next_rr;
+ dprintf(3, (ddt, "found it\n"));
+ /* look for the data */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if ( (!match(dp, (int)ap->a_class, T_A))
+ && (!match(dp, C_IN, T_A))
+ ) {
+ continue;
+ }
+ foundany++;
+ if (stale(dp)) {
+ foundstale++;
+ dprintf(1, (ddt,
+ "doaddinfo: stale entry '%s'%s\n",
+ np->n_dname,
+ (dp->d_flags&DB_F_HINT)
+ ? " hint"
+ : ""
+ ));
+ continue;
+ }
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ /*
+ * Should be smart and eliminate duplicate
+ * data here. XXX
+ */
+ if ((n = make_rr(ap->a_dname, dp, cp, msglen, 0)) < 0){
+ /* truncation in the additional-data section
+ * is not all that serious. we do not set TC,
+ * since the answer and authority sections are
+ * OK; however, since we're not setting TC we
+ * have to make sure that none of the RR's for
+ * this name go out (!TC implies that all
+ * {name,type} appearances are complete -- and
+ * since we only do A RR's here, the name is
+ * the key). vixie, 23apr93
+ */
+ cp = save_cp;
+ msglen = save_msglen;
+ count = save_count;
+ break;
+ }
+ dprintf(5, (ddt,
+ "addinfo: adding address data n = %d\n",
+ n));
+ cp += n;
+ msglen -= n;
+ count++;
+ }
+next_rr: if (foundstale) {
+ /* Cache invalidate the address RR's */
+ delete_all(np, (int)ap->a_class, T_A);
+ }
+ if (foundstale || !foundany) {
+ /* ask a real server for this info */
+ (void) sysquery(ap->a_dname, (int)ap->a_class, T_A,
+ NULL, 0);
+ }
+ free(ap->a_dname);
+ }
+ hp->arcount = htons((u_int16_t)count);
+ return (cp - msg);
+}
+
+int
+doaddauth(hp, cp, buflen, np, dp)
+ register HEADER *hp;
+ u_char *cp;
+ int buflen;
+ struct namebuf *np;
+ struct databuf *dp;
+{
+ char dnbuf[MAXDNAME];
+ int n;
+
+ getname(np, dnbuf, sizeof(dnbuf));
+ if (stale(dp)) {
+ dprintf(1, (ddt,
+ "doaddauth: can't add stale '%s' (%d)\n",
+ dnbuf, buflen));
+ return (0);
+ }
+ n = make_rr(dnbuf, dp, cp, buflen, 1);
+ if (n <= 0) {
+ dprintf(1, (ddt,
+ "doaddauth: can't add oversize '%s' (%d) (n=%d)\n",
+ dnbuf, buflen, n));
+ if (n < 0) {
+ hp->tc = 1;
+ }
+ return (0);
+ }
+ hp->nscount = htons((u_int16_t)1);
+ return (n);
+}
+
+/*
+ * Do a zone transfer (or a recursive part of a zone transfer).
+ * SOA record already sent.
+ *
+ * top always refers to the domain at the top of the zone being transferred.
+ * np refers to a domain inside the zone being transferred,
+ * which will be equal to top if this is the first call,
+ * or will be a subdomain below top if this is a recursive call,
+ * rfp is a stdio file to which output is sent.
+ */
+static void
+doaxfr(np, rfp, top, class)
+ register struct namebuf *np;
+ FILE *rfp;
+ struct namebuf *top;
+ int class; /* Class to transfer */
+{
+ register struct databuf *dp;
+ register int n;
+ struct hashbuf *htp;
+ struct databuf *gdp; /* glue databuf */
+ struct namebuf *gnp; /* glue namebuf */
+ struct namebuf *tnp; /* top namebuf */
+ struct databuf *tdp; /* top databuf */
+ struct namebuf **npp, **nppend;
+ u_char msg[PACKETSZ];
+ u_char *cp;
+ char *fname;
+ char dname[MAXDNAME];
+ HEADER *hp = (HEADER *) msg;
+ int fndns;
+
+ if (np == top)
+ dprintf(1, (ddt, "doaxfr()\n"));
+ fndns = 0;
+ hp->id = 0;
+ hp->opcode = QUERY;
+ hp->aa = hp->tc = hp->ra = hp->pr = hp->rd = 0;
+ hp->qr = 1;
+ hp->rcode = NOERROR;
+ hp->qdcount = 0;
+ hp->ancount = htons(1);
+ hp->nscount = 0;
+ hp->arcount = 0;
+ cp = (u_char *) (msg + HFIXEDSZ);
+ getname(np, dname, sizeof(dname));
+
+ /* first do the NS records (del@harris) */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+#ifdef GEN_AXFR
+ if (dp->d_class != class && class != C_ANY)
+ continue;
+#endif
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ if (dp->d_type == T_NS) {
+ fndns = 1;
+ n = make_rr(dname, dp, cp, sizeof(msg)-HFIXEDSZ, 0);
+ if (n < 0)
+ continue;
+ fwritemsg(rfp, msg, n + HFIXEDSZ);
+#ifdef NO_GLUE
+ if ((np != top) || (top->n_dname[0] == '\0')) {
+#endif /*NO_GLUE*/
+ /* Glue the sub domains together by sending
+ * the address records for the sub domain
+ * name servers along if necessary.
+ * Glue is necessary if the server is in any zone
+ * delegated from the current (top) zone. Such
+ * a delegated zone might or might not be that
+ * referred to by the NS record now being handled.
+ */
+ htp = hashtab;
+ cp = (u_char *) (msg + HFIXEDSZ);
+ gnp = nlookup((char *)dp->d_data, &htp, &fname, 0);
+ if (gnp == NULL || fname != (char *)dp->d_data)
+ continue;
+#ifdef NO_GLUE
+ for (tnp = gnp; tnp != NULL; tnp = tnp->n_parent)
+ if ( tnp == top )
+ break;
+ if ( (tnp == NULL) && (top->n_dname[0] != '\0') )
+ continue; /* name server is not below top domain */
+ for (tnp = gnp; tnp != top; tnp = tnp->n_parent) {
+ for (tdp = tnp->n_data;
+ tdp != NULL;
+ tdp = tdp->d_next) {
+#ifdef GEN_AXFR
+ if (tdp->d_class != class && class != C_ANY)
+ continue;
+#endif
+ if (tdp->d_type == T_NS)
+ break;
+ }
+ if (tdp != NULL)
+ break; /* found a zone cut */
+ }
+ if (tnp == top)
+ continue; /* name server is not in a delegated zone */
+ /* now we know glue records are needed. send them. */
+#endif /*NO_GLUE*/
+ for (gdp=gnp->n_data; gdp != NULL; gdp=gdp->d_next) {
+#ifdef GEN_AXFR
+ if (gdp->d_class != class && class != C_ANY)
+ continue;
+#endif
+ if (gdp->d_type != T_A || stale(gdp))
+ continue;
+#ifdef NCACHE
+ if (gdp->d_rcode)
+ continue;
+#endif
+ n = make_rr(fname, gdp, cp, sizeof(msg)-HFIXEDSZ, 0);
+ if (n < 0)
+ continue;
+ fwritemsg(rfp, msg, n + HFIXEDSZ);
+ }
+#ifdef NO_GLUE
+ }
+#endif /*NO_GLUE*/
+ }
+ }
+ /* no need to send anything else if a delegation appeared */
+ if ((np != top) && fndns)
+ return;
+
+ /* do the rest of the data records */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+#ifdef GEN_AXFR
+ if (dp->d_class != class && class != C_ANY)
+ continue;
+#endif
+ /*
+ * Skip the top SOA record (marks end of data);
+ * don't send SOA for subdomains, as we're not sending them;
+ * skip the NS records because we did them first.
+ */
+ if (dp->d_type == T_SOA || dp->d_type == T_NS)
+ continue;
+ if (dp->d_zone == 0 || stale(dp))
+ continue;
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ if ((n = make_rr(dname, dp, cp, sizeof(msg)-HFIXEDSZ, 0)) < 0)
+ continue;
+ fwritemsg(rfp, msg, n + HFIXEDSZ);
+ }
+
+ /* Finally do non-delegated subdomains. Delegated subdomains
+ * have already been handled.
+ */
+ /*
+ * We find the subdomains by looking in the hash table for this
+ * domain, but the root domain needs special treatment, because
+ * of the following wart in the database design:
+ *
+ * The top level hash table (pointed to by the global `hashtab'
+ * variable) contains pointers to the namebuf's for the root as
+ * well as for the top-level domains below the root, in contrast
+ * to the usual situation where a hash table contains entries
+ * for domains at the same level. The n_hash member of the
+ * namebuf for the root domain is NULL instead of pointing to a
+ * hashbuf for the top-level domains. The n_parent members of
+ * the namebufs for the top-level domains are NULL instead of
+ * pointing to the namebuf for the root.
+ *
+ * We work around the wart as follows:
+ *
+ * If we are not dealing with the root zone then we just set
+ * htp = np->n_hash, pointing to the hash table for the current
+ * domain, and we walk through the hash table as usual,
+ * processing the namebufs for all the subdomains.
+ *
+ * If we are dealing with the root zone, then we set
+ * htp = hashtab, pointing to the global hash table (because
+ * there is no hash table associated with the root domain's
+ * namebuf. While we walk this hash table, we take care not to
+ * recursively process the entry for the root namebuf.
+ *
+ * (apb@und nov1990)
+ */
+ htp = ((dname[0] == '\0') ? hashtab : np->n_hash);
+ if (htp == NULL) {
+ return; /* no subdomains */
+ }
+ npp = htp->h_tab;
+ nppend = npp + htp->h_size;
+ while (npp < nppend) {
+ for (np = *npp++; np != NULL; np = np->n_next) {
+ if (np->n_dname[0] != '\0') { /* don't redo root domain */
+ doaxfr(np, rfp, top, class);
+ }
+ }
+ }
+ if (np == top)
+ dprintf(1, (ddt, "exit doaxfr()\n"));
+}
+
+#ifdef ALLOW_UPDATES
+/*
+ * Called by UPDATE{A,D,DA,M,MA} to initiate a dynamic update. If this is the
+ * primary server for the zone being updated, we update the zone's serial
+ * number and then call doupdate directly. If this is a secondary, we just
+ * forward the update; this way, if the primary update fails (e.g., if the
+ * primary is unavailable), we don't update the secondary; if the primary
+ * update suceeds, ns_resp will get called with the response (when it comes
+ * in), and then update the secondary's copy.
+ */
+static int
+InitDynUpdate(hp, msg, msglen, startcp, from, qsp, dfd)
+ register HEADER *hp;
+ char *msg;
+ int msglen;
+ u_char *startcp;
+ struct sockaddr_in *from;
+ struct qstream *qsp;
+ int dfd;
+{
+ struct databuf *nsp[NSMAX];
+ struct zoneinfo *zp;
+ char dnbuf[MAXDNAME];
+ struct hashbuf *htp = hashtab; /* lookup relative to root */
+ struct namebuf *np;
+ struct databuf *olddp, *newdp, *dp;
+ struct databuf **nspp;
+ char *fname;
+ register u_char *cp = startcp;
+ u_int16_t class, type;
+ int n, size, zonenum;
+ char ZoneName[MAXDNAME], *znp;
+
+#ifdef DATUMREFCNT
+ nsp[0] = NULL;
+#endif
+ if ((n = dn_expand(msg, msg + msglen, cp, dnbuf, sizeof(dnbuf))) < 0) {
+ dprintf(1, (ddt,"FORMERR InitDynUpdate expand name failed\n"));
+ hp->rcode = FORMERR;
+ return (FORMERR);
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ if (type == T_SOA) { /* T_SOA updates not allowed */
+ hp->rcode = REFUSED;
+ dprintf(1, (ddt, "InitDynUpdate: REFUSED - SOA update\n"));
+ return (REFUSED);
+ }
+ GETSHORT(class, cp);
+ cp += INT32SZ;
+ GETSHORT(size, cp);
+/****XXX - need bounds checking here ****/
+ cp += size;
+
+ if ((zonenum = findzone(dnbuf, class)) == 0) { /* zone not found */
+ hp->rcode = NXDOMAIN;
+ return (NXDOMAIN);
+ }
+ zp = &zones[zonenum];
+
+ /* Disallow updates for which we aren't authoratative. Note: the
+ following test doesn't work right: If it's for a non-local zone,
+ we will think it's a primary but be unable to lookup the namebuf,
+ thus returning 'NXDOMAIN' */
+ if (zp->z_type != Z_PRIMARY && zp->z_type != Z_SECONDARY) {
+ hp->rcode = REFUSED;
+ dprintf(1, (ddt,
+ "InitDynUpdate: REFUSED - non-{primary,secondary} update\n"));
+ return (REFUSED);
+ }
+ if (!(zp->z_flags & Z_DYNAMIC)) {
+ hp->rcode = REFUSED;
+ dprintf(1, (ddt,
+ "InitDynUpdate: REFUSED - dynamic flag not set for zone\n"));
+ return (REFUSED);
+ }
+
+ /*
+ * Lookup the zone namebuf. Lookup "xyz" not "xyz.", since
+ * otherwise the lookup fails, because '.' may have a nil n_hash
+ * associated with it.
+ */
+ strcpy(ZoneName, zp->z_origin);
+ znp = &ZoneName[strlen(ZoneName) - 1];
+ if (*znp == '.')
+ *znp = NULL;
+ np = nlookup(ZoneName, &htp, &fname, 0);
+ if ((np == NULL) || (fname != ZoneName)) {
+ dprintf(1, (ddt, "InitDynUpdate: lookup failed on zone (%s)\n",
+ ZoneName));
+ syslog(LOG_ERR, "InitDynUpdate: lookup failed on zone (%s)\n",
+ ZoneName);
+ hp->rcode = NXDOMAIN;
+ return (NXDOMAIN);
+ }
+
+ /*
+ * If this is the primary copy increment the serial number. Don't
+ * increment the serial number if this is a secondary; this way, if 2
+ * different secondaries both update the primary, they will both have
+ * lower serial numbers than the primary has, and hence eventually
+ * refresh and get all updates and become consistent.
+ *
+ * Note that the serial number must be incremented in both the zone
+ * data structure and the zone's namebuf.
+ */
+ switch (zp->z_type) {
+ case Z_SECONDARY: /* forward update to primary */
+ nspp = nsp;
+ dp = np->n_data;
+ while (dp != NULL) {
+ if (match(dp, class, T_NS)) {
+ if (nspp < &nsp[NSMAX-1]) {
+ *nspp++ = dp;
+#ifdef DATUMREFCNT
+ dp->d_rcnt++;
+#endif
+ } else
+ break;
+ }
+ dp = dp->d_next;
+ }
+ *nspp = NULL; /* Delimiter */
+ if (ns_forw(nsp, msg, msglen, from, qsp, dfd, NULL, dnbuf, np)
+ <
+ 0) {
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (SERVFAIL);
+ }
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (FORWARDED);
+
+ case Z_PRIMARY:
+ zp->z_serial++;
+ /* Find the SOA record */
+ for (olddp = np->n_data; olddp != NULL; olddp = olddp->d_next)
+ if (match(olddp, class, T_SOA))
+ break;
+ if (olddp == NULL) {
+ dprintf(1, (ddt,
+ "InitDynUpdate: Couldn't find SOA record for '%s'\n",
+ ZoneName));
+ syslog(LOG_ERR,
+ "InitDynUpdate: Couldn't find SOA record for '%s'\n"
+,
+ ZoneName);
+ hp->rcode = NXDOMAIN;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (NXDOMAIN);
+ }
+ newdp = savedata(olddp->d_class, olddp->d_type, olddp->d_ttl,
+ olddp->d_data, olddp->d_size);
+ newdp->d_zone = olddp->d_zone;
+ newdp->d_cred = DB_C_AUTH; /* XXX - it may not be so */
+ newdp->d_clev = db_getclev(zp->z_origin);
+ cp = (u_char *)newdp->d_data;
+ cp += strlen(cp) + 1; /* skip origin string */
+ cp += strlen(cp) + 1; /* skip in-charge string */
+ putlong((u_int32_t)(zp->z_serial), cp);
+ dprintf(4, (ddt, "after stuffing data into newdp:\n"));
+#ifdef DEBUG
+ if (debug >= 4)
+ printSOAdata(newdp);
+#endif
+
+ if ((n = db_update(ZoneName, olddp, newdp, DB_DELETE,
+ hashtab)) != NOERROR) { /* XXX */
+ dprintf(1, (ddt,
+ "InitDynUpdate: SOA update failed\n"));
+ hp->rcode = NOCHANGE;
+ free((char*) dp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (NOCHANGE);
+ }
+
+ /* Now update the RR itself */
+ /* XXX - DB_C_AUTH may be wrong */
+ if (doupdate(msg, msglen, msg + HFIXEDSZ, zonenum,
+ (struct databuf *)0, DB_NODATA, DB_C_AUTH) < 0) {
+ dprintf(1, (ddt, "InitDynUpdate: doupdate failed\n"));
+ /* doupdate fills in rcode */
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (hp->rcode);
+ }
+ zp->z_flags |= Z_CHANGED;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (NOERROR);
+ }
+}
+
+#ifdef DEBUG
+/*
+ * Print the contents of the data in databuf pointed to by dp for an SOA record
+ */
+static void
+printSOAdata(dp)
+ struct databuf *dp;
+{
+ register u_char *cp;
+
+ if (!debug)
+ return; /* Otherwise fprintf to ddt will bomb */
+ cp = (u_char *)dp->d_data;
+ fprintf(ddt, "printSOAdata(%x): origin(%x)='%s'\n", dp, cp, cp);
+ cp += strlen(cp) + 1; /* skip origin string */
+ fprintf(ddt, "printSOAdata: in-charge(%x)='%s'\n", cp, cp);
+ cp += strlen(cp) + 1; /* skip in-charge string */
+ fprintf(ddt, "printSOAdata: serial(%x)=%d\n", cp, _getlong(cp));
+}
+#endif
+#endif
+
+static void
+startxfr(qsp, np, soa, soalen, class, dname)
+ struct qstream *qsp;
+ struct namebuf *np;
+ u_char *soa;
+ int soalen;
+ int class;
+ const char *dname;
+{
+ FILE *rfp;
+ int fdstat;
+ pid_t pid;
+
+ dprintf(5, (ddt, "startxfr()\n"));
+
+ /*
+ * child does the work while
+ * the parent continues
+ */
+ switch (pid = fork()) {
+ case -1:
+ syslog(LOG_ERR, "startxfr(%s -> [%s]) failing; fork: %m",
+ dname, inet_ntoa(qsp->s_from.sin_addr));
+ return;
+ case 0:
+ /* child */
+ break;
+ default:
+ /* parent */
+ syslog(LOG_DEBUG, "zone transfer of \"%s\" to [%s] (pid %lu)",
+ dname, inet_ntoa(qsp->s_from.sin_addr), pid);
+ return;
+ }
+
+ /*
+ * Child.
+ *
+ * XXX: this should be a vfork/exec since on non-copy-on-write
+ * systems with huge nameserver images, this is very expensive.
+ */
+ close(vs);
+ sqflush(/*allbut*/ qsp);
+ dqflush((time_t)0);
+
+#ifdef RENICE
+ nice(-40); nice(20); nice(0); /* back to "normal" */
+#endif
+ dprintf(5, (ddt, "startxfr: child pid %lu\n", (u_long)pid));
+
+ if (!(rfp = fdopen(qsp->s_rfd, "w"))) {
+ syslog(LOG_ERR, "fdopen: %m");
+ _exit(1);
+ }
+ ns_setproctitle("zone XFR to", qsp->s_rfd);
+ if (-1 == (fdstat = fcntl(qsp->s_rfd, F_GETFL, 0))) {
+ syslog(LOG_ERR, "fcntl(F_GETFL): %m");
+ _exit(1);
+ }
+ (void) fcntl(qsp->s_rfd, F_SETFL, fdstat & ~PORT_NONBLOCK);
+ fwritemsg(rfp, soa, soalen);
+ doaxfr(np, rfp, np, class);
+ fwritemsg(rfp, soa, soalen);
+ (void) fflush(rfp);
+ _exit(0);
+}
+
+free_addinfo() {
+ struct addinfo *ap;
+
+ for (ap = addinfo; --addcount >= 0; ap++) {
+ free(ap->a_dname);
+ }
+ addcount = 0;
+}
+
+#ifdef DATUMREFCNT
+free_nsp(nsp)
+struct databuf **nsp;
+{
+ while (*nsp) {
+ if (--((*nsp)->d_rcnt)) {
+ dprintf(3, (ddt, "free_nsp: %s rcnt %d\n",
+ (*nsp)->d_data, (*nsp)->d_rcnt));
+ } else {
+ dprintf(3, (ddt, "free_nsp: %s rcnt %d delayed\n",
+ (*nsp)->d_data, (*nsp)->d_rcnt));
+ free(*nsp); /* delayed free */
+ }
+ *nsp++ = NULL;
+ }
+}
+#endif
diff --git a/usr.sbin/named/ns_resp.c b/usr.sbin/named/ns_resp.c
new file mode 100644
index 0000000..f8086e3
--- /dev/null
+++ b/usr.sbin/named/ns_resp.c
@@ -0,0 +1,2190 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_resp.c 4.65 (Berkeley) 3/3/91";
+static char rcsid[] = "$Id: ns_resp.c,v 4.9.1.24 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988, 1990
+ * -
+ * Copyright (c) 1986, 1988, 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <syslog.h>
+#include <errno.h>
+#include <stdio.h>
+#include <resolv.h>
+
+#include "named.h"
+
+static void check_root __P((void)),
+ check_ns __P((void));
+
+static u_int8_t norootlogged[MAXCLASS]; /* XXX- should be a bitmap */
+
+static char skipnameFailedAnswer[] = "skipname failed in answer",
+ skipnameFailedQuery[] = "skipname failed in query",
+ outofDataQuery[] = "ran out of data in query",
+ outofDataAnswer[] = "ran out of data in answer",
+#ifdef LAME_DELEGATION
+ expandFailedQuery[] = "dn_expand failed in query",
+ expandFailedAuth[] = "dn_expand failed in authority",
+ outofDataAuth[] = "ran out of data in authority",
+#endif /* LAME_DELEGATION */
+ dlenOverrunAnswer[] = "dlen overrun in answer",
+ dlenUnderrunAnswer[] = "dlen underrun in answer",
+ outofDataFinal[] = "out of data in final pass",
+ outofDataAFinal[] = "out of data after final pass";
+
+void
+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;
+#ifdef VALIDATE
+ register u_char *tempcp;
+ struct sockaddr_in *server = &from_addr;
+ int *validatelist;
+ int lesscount;
+#endif
+ struct sockaddr_in *nsa;
+ struct databuf *nsp[NSMAX], **nspp;
+ int i, c, n, ancount, aucount, nscount, arcount;
+ int old_ancount;
+ 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;
+ char *formerrmsg = "brain damage";
+ u_char newmsg[BUFSIZ];
+ u_char **dpp, *tp;
+ time_t rtrip;
+ struct hashbuf *htp;
+ struct namebuf *np;
+ struct netinfo *lp;
+ struct fwdinfo *fwd;
+
+ nameserIncr(from_addr.sin_addr, nssRcvdR);
+#ifdef DATUMREFCNT
+ nsp[0] = NULL;
+#endif
+ hp = (HEADER *) msg;
+ if ((qp = qfindid(hp->id)) == NULL ) {
+ dprintf(1, (ddt, "DUP? dropped (id %d)\n", ntohs(hp->id)));
+ nameserIncr(from_addr.sin_addr, nssRcvdDupR);
+ return;
+ }
+
+ dprintf(2, (ddt, "Response (%s %s %s) nsid=%d id=%d\n",
+ (qp->q_flags & Q_SYSTEM) ?"SYSTEM" :"USER",
+ (qp->q_flags & Q_PRIMING) ?"PRIMING" :"NORMAL",
+ (qp->q_flags & Q_ZSERIAL) ?"ZSERIAL" :"-",
+ ntohs(qp->q_nsid), ntohs(qp->q_id)));
+
+ /*
+ * 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.
+ */
+ if ((hp->rcode != NOERROR && hp->rcode != NXDOMAIN)
+#ifndef NCACHE
+ || (hp->rcode == NXDOMAIN && !hp->aa) /* must accept this one if
+ * we allow negative caching
+ */
+#endif /*NCACHE*/
+ || hp->opcode != QUERY) {
+ dprintf(2, (ddt, "resp: error (ret %d, op %d), dropped\n",
+ hp->rcode, hp->opcode));
+ switch (hp->rcode) {
+ case SERVFAIL:
+ nameserIncr(from_addr.sin_addr, nssRcvdFail);
+ break;
+ case FORMERR:
+ nameserIncr(from_addr.sin_addr, nssRcvdFErr);
+ break;
+ default:
+ nameserIncr(from_addr.sin_addr, nssRcvdErr);
+ break;
+ }
+ return;
+ }
+#ifdef LAME_DELEGATION
+ /*
+ * Non-authoritative, no answer, no error
+ */
+ if (hp->rcode == NOERROR && !hp->aa && ntohs(hp->ancount) == 0 &&
+ ntohs(hp->nscount) > 0) {
+
+#ifdef LAME_LOGGING
+ char qname[MAXDNAME];
+#endif /* LAME_LOGGING */
+
+#ifdef DEBUG
+ if (debug > 0)
+ fp_query(msg, ddt);
+#endif
+
+ cp = msg + HFIXEDSZ;
+ dpp = dnptrs;
+ *dpp++ = msg;
+ if ((*cp & INDIR_MASK) == 0)
+ *dpp++ = cp;
+ *dpp = NULL;
+ if (hp->qdcount) {
+#ifdef LAME_LOGGING
+ n = dn_expand(msg, msg + msglen, cp, qname,
+ sizeof(qname));
+ if (n <= 0) {
+ formerrmsg = expandFailedQuery;
+ goto formerr;
+ }
+#else /* LAME_LOGGING */
+ n = dn_skipname(cp, msg + msglen);
+ if (n <= 0) {
+ formerrmsg = skipnameFailedQuery;
+ goto formerr;
+ }
+#endif /* LAME_LOGGING */
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ if (cp - msg > msglen) {
+ formerrmsg = outofDataQuery;
+ goto formerr;
+ }
+#ifdef LAME_LOGGING
+ } else {
+ strcpy(qname, "[No query name!]");
+#endif /* LAME_LOGGING */
+ }
+ n = dn_expand(msg, msg + msglen, cp, name, sizeof name);
+ if (n < 0) {
+ formerrmsg = expandFailedAuth;
+ goto formerr;
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ if (cp - msg > msglen) {
+ formerrmsg = outofDataAuth;
+ goto formerr;
+ }
+
+ /*
+ * If the answer delegates us either to the same level in
+ * the hierarchy or closer to the root, we consider this
+ * server lame.
+ */
+
+ if (type == T_NS && samedomain(qp->q_domain, name)) {
+ nameserIncr(from_addr.sin_addr, nssRcvdLDel);
+#ifdef LAME_LOGGING
+ if (!haveComplained((char*)dhash((u_char*)name,
+ strlen(name)),
+ (char*)dhash((u_char*)qp->q_domain,
+ strlen(qp->q_domain)
+ )
+ )
+ ) {
+ syslog(LAME_LOGGING,
+"Lame delegation to '%s' from [%s] (server for '%s'?) on query on name '%s'\n",
+ name, inet_ntoa(from_addr.sin_addr),
+ qp->q_domain, qname);
+ }
+#endif /* LAME_LOGGING */
+ return;
+ }
+ }
+#endif /* LAME_DELEGATION */
+
+
+#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
+ */
+ /* XXX - DB_C_AUTH may be wrong */
+ (void) doupdate(qp->q_msg, qp->q_msglen, qp->q_msg + HFIXEDSZ,
+ 0, (struct databuf *)0, 0, DB_C_AUTH);
+ dprintf(3, (ddt, "resp: leaving, UPDATE*\n"));
+ /* 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 (fwd->fwdaddr.sin_addr.s_addr ==
+ from_addr.sin_addr.s_addr) {
+ /* XXX - should put this in STATS somewhere */
+ break;
+ }
+ }
+ /* XXX: note bad ambiguity here. if one of our forwarders is also
+ * a delegated server for some domain, then we will not update
+ * the RTT information on any replies we get from those servers.
+ */
+ /*
+ * 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 (qs->ns_addr.sin_addr.s_addr ==
+ from_addr.sin_addr.s_addr)
+ break;
+ if (n >= qp->q_naddr) {
+ if (!haveComplained((char*)from_addr.sin_addr.s_addr,
+ "unexpected source")) {
+ syslog(LOG_NOTICE,
+ "Response from unexpected source [%s].%d",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port));
+ }
+ /*
+ * 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 ((qs->ns != NULL) && (stp->tv_sec == 0)) {
+ ns = qs->ns;
+ while (qs > qp->q_addr &&
+ (qs->stime.tv_sec == 0 || qs->ns != ns))
+ qs--;
+ *stp = qs->stime;
+ /* XXX - sometimes stp still ends up pointing to
+ * a zero timeval, in spite of the above attempt.
+ * Why? What should we do about it?
+ */
+ dprintf(1, (ddt,
+ "Response from unused address %s, assuming %s\n",
+ inet_ntoa(from_addr.sin_addr),
+ inet_ntoa(qs->ns_addr.sin_addr)));
+ /* XXX - catch aliases here */
+ }
+
+ /* compute query round trip time */
+ /* XXX - avoid integer overflow, which is quite likely if stp
+ * points to a zero timeval (see above).
+ * rtrip is of type time_t, which we assume is at least
+ * as big as an int.
+ */
+ if ((tt.tv_sec - stp->tv_sec) > (INT_MAX-999)/1000) {
+ rtrip = INT_MAX;
+ } else {
+ rtrip = ((tt.tv_sec - stp->tv_sec) * 1000 +
+ (tt.tv_usec - stp->tv_usec) / 1000);
+ }
+
+ dprintf(3, (ddt, "stime %d/%d now %d/%d rtt %d\n",
+ stp->tv_sec, stp->tv_usec,
+ tt.tv_sec, tt.tv_usec, rtrip));
+
+ /* 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 && (ns->d_type==T_A) && (ns->d_class==qs->ns->d_class)){
+ if (ns->d_nstime == 0)
+ ns->d_nstime = (u_int32_t)rtrip;
+ else
+ ns->d_nstime = (u_int32_t)
+ (ns->d_nstime * ALPHA
+ +
+ (1-ALPHA) * (u_int32_t)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 (ns && qs->ns && (qp->q_nusedns < NSMAX)) {
+ qp->q_usedns[qp->q_nusedns++] = qs->ns;
+ dprintf(2, (ddt, "NS #%d addr [%s] used, rtt %d\n",
+ n, inet_ntoa(qs->ns_addr.sin_addr),
+ ns->d_nstime));
+ }
+
+ /*
+ * 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) || (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 = (u_int32_t)(rtrip * BETA);
+ else
+ ns2->d_nstime = (u_int32_t)(
+ ns2->d_nstime * BETA + (1-ALPHA) * rtrip
+ );
+ if (ns2->d_nstime > 1000000)
+ ns2->d_nstime = 1000000;
+ } else
+ ns2->d_nstime = (u_int32_t)(ns2->d_nstime * GAMMA);
+ dprintf(2, (ddt, "NS #%d [%s] rtt now %d\n", n,
+ inet_ntoa(qs->ns_addr.sin_addr),
+ ns2->d_nstime));
+ }
+ }
+
+ /*************************************************************/
+
+ /*
+ * Skip query section
+ */
+ free_addinfo(); /* sets addcount to zero */
+ cp = msg + HFIXEDSZ;
+ dpp = dnptrs;
+ *dpp++ = msg;
+ if ((*cp & INDIR_MASK) == 0)
+ *dpp++ = cp;
+ *dpp = NULL;
+ type = class = 0;
+ if (hp->qdcount) {
+ n = dn_skipname(cp, msg + msglen);
+ if (n <= 0) {
+ formerrmsg = skipnameFailedQuery;
+ goto formerr;
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ if (cp - msg > msglen) {
+ formerrmsg = outofDataQuery;
+ 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;
+ dprintf(3, (ddt, "resp: ancount %d, aucount %d, arcount %d\n",
+ ancount, aucount, arcount));
+
+ /*
+ * 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) {
+ formerrmsg = outofDataAnswer;
+ goto formerr;
+ }
+ n = dn_skipname(tp, msg + msglen);
+ if (n <= 0) {
+ formerrmsg = skipnameFailedAnswer;
+ goto formerr;
+ }
+ tp += n; /* name */
+ GETSHORT(i, tp); /* type */
+ tp += INT16SZ; /* class */
+ tp += INT32SZ; /* ttl */
+ GETSHORT(count, tp); /* dlen */
+ if (tp - msg > msglen - count) {
+ formerrmsg = dlenOverrunAnswer;
+ goto formerr;
+ }
+ tp += count;
+ if (ancount && i == T_CNAME) {
+ cname++;
+ dprintf(1,
+ (ddt,
+ "CNAME - needs more processing\n"
+ )
+ );
+ 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;
+ }
+
+ if (qp->q_flags & Q_ZSERIAL) {
+ if ((hp->aa)
+ && (ancount != 0)
+ && (hp->rcode == NOERROR)
+ && (type == T_SOA)
+ && ((class == C_IN) || (class == C_HS))
+ ) { /* XXX - should check name, too */
+ int n;
+ u_int16_t dlen;
+ u_int32_t serial;
+ u_char *tp = cp;
+
+ if (0 >= (n = dn_skipname(tp, msg + msglen))) {
+ formerrmsg = skipnameFailedAnswer;
+ goto formerr;
+ }
+ tp += n /* name */
+ + INT16SZ /* type */
+ + INT16SZ /* class */
+ + INT32SZ; /* ttl */
+ GETSHORT(dlen, tp); /* dlen */
+
+ if (dlen < (5 * INT32SZ)) {
+ formerrmsg = dlenUnderrunAnswer;
+ goto formerr;
+ }
+
+ if (0 >= (n = dn_skipname(tp, msg + msglen))) {
+ formerrmsg = skipnameFailedAnswer;
+ goto formerr;
+ }
+ tp += n; /* mname */
+ if (0 >= (n = dn_skipname(tp, msg + msglen))) {
+ formerrmsg = skipnameFailedAnswer;
+ goto formerr;
+ }
+ tp += n; /* rname */
+ GETLONG(serial, tp);
+
+ qserial_answer(qp, serial);
+ }
+ qremove(qp);
+ return;
+ }
+
+ /*
+ * Add the info received in the response to the data base.
+ */
+ c = ancount + aucount + arcount;
+#ifdef NCACHE
+ /* -ve $ing non-existence of record, must handle non-authoritative
+ * NOERRORs with c == 0.
+ */
+ if (!hp->aa && hp->rcode == NOERROR && c == 0) {
+ goto return_msg;
+ } /*should ideally validate message before returning it*/
+#endif /*NCACHE*/
+#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_flags & Q_SYSTEM)) {
+ dprintf(4, (ddt, "resp: leaving, no CNAME\n"));
+
+ /* 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_flags & Q_SYSTEM)
+ dbflags = DB_NOTAUTH | DB_NODATA;
+ else
+ dbflags = DB_NOTAUTH | DB_NODATA | DB_NOHINTS;
+ count = c;
+ if (hp->tc) {
+ count -= arcount; /* truncation had to affect this */
+ if (!arcount) {
+ count -= aucount; /* guess it got this too */
+ }
+ if (!(arcount || aucount)) {
+ count -= ancount; /* things are pretty grim */
+ }
+ /* XXX - should retry this query with TCP */
+ }
+#ifdef VALIDATE
+ tempcp = cp;
+ validatelist = (int *)malloc(count * sizeof(int));
+ lesscount = 0; /*initialize*/
+ old_ancount = ancount;
+ for (i = 0; i < count; i++) {
+ int VCode;
+ if (tempcp >= msg + msglen) {
+ free((char *)validatelist);
+ formerrmsg = outofDataFinal;
+ goto formerr;
+ }
+ if ((n = dovalidate(msg, msglen, tempcp, 0,
+ dbflags, server, &VCode)) < 0) {
+ dprintf(1, (ddt,
+ "resp: leaving, dovalidate failed\n"));
+ free((char *)validatelist);
+
+ /* return code filled in by dovalidate */
+ goto return_msg;
+ }
+ validatelist[i] = VCode;
+ if (VCode == INVALID) lesscount++;
+ tempcp += n;
+ }
+
+ /* need to delete INVALID records from the message
+ * and change fields appropriately
+ */
+ n = update_msg(msg, &msglen, validatelist, count);
+ free((char *)validatelist);
+ if (n < 0)
+ goto formerr;
+ count -= lesscount;
+
+ if (old_ancount && !hp->ancount) {
+ /* We lost all the answers */
+ dprintf(1, (ddt, "validate count -> 0"));
+ return;
+ }
+ ancount = ntohs(hp->ancount);
+#endif
+
+ for (i = 0; i < count; i++) {
+ struct databuf *ns3;
+ u_char cred;
+
+ if (cp >= msg + msglen) {
+ formerrmsg = outofDataFinal;
+ goto formerr;
+ }
+ if (i < ancount) {
+ cred = hp->aa ? DB_C_AUTH : DB_C_ANSWER;
+ } else {
+ cred = DB_C_ADDITIONAL;
+ }
+ ns3 = 0;
+ n = doupdate(msg, msglen, cp, 0, &ns3, dbflags, cred);
+ if (n < 0) {
+ dprintf(1, (ddt, "resp: leaving, doupdate failed\n"));
+
+ /* 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;
+#ifdef DATUMREFCNT
+ ns3->d_rcnt++;
+ *nspp = NULL;
+#endif
+ }
+ cp += n;
+ }
+
+ if ((qp->q_flags & Q_SYSTEM) && ancount) {
+ if (qp->q_flags & Q_PRIMING)
+ check_root();
+ dprintf(3, (ddt, "resp: leaving, SYSQUERY ancount %d\n",
+ ancount));
+ qremove(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+ }
+
+ if (cp > msg + msglen) {
+ formerrmsg = outofDataAFinal;
+ 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)) {
+ dprintf(3, (ddt, "resp: got as much answer as there is\n"));
+ goto return_msg;
+ }
+
+ /*
+ * We might want to cache this negative answer.
+ */
+ if (!ancount &&
+ (!nscount || hp->rcode == NXDOMAIN) &&
+ (hp->aa || fwd || class == C_ANY)) {
+ /* we have an authoritative NO */
+ dprintf(3, (ddt, "resp: leaving auth NO\n"));
+ if (qp->q_cmsglen) {
+ msg = qp->q_cmsg;
+ msglen = qp->q_cmsglen;
+ hp = (HEADER *)msg;
+ }
+#ifdef NCACHE
+ /* answer was NO */
+ if (hp->aa &&
+ ((hp->rcode == NXDOMAIN) || (hp->rcode == NOERROR))) {
+ cache_n_resp(msg, msglen);
+ }
+#endif /*NCACHE*/
+ 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) {
+ dprintf(1, (ddt, "Cname second pass\n"));
+ 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 + HFIXEDSZ;
+ if (cname)
+ cp += dn_skipname(cp, newmsg + newmsglen) + QFIXEDSZ;
+ n = dn_expand(newmsg, newmsg + newmsglen, cp, dname, sizeof name);
+ if (n < 0) {
+ dprintf(1, (ddt, "dn_expand failed\n"));
+ goto servfail;
+ }
+ if (!cname)
+ cp += n + QFIXEDSZ;
+ buflen = sizeof(newmsg) - (cp - newmsg);
+
+try_again:
+ dprintf(1, (ddt, "resp: nlookup(%s) type=%d\n", dname, type));
+ fname = "";
+ htp = hashtab; /* lookup relative to root */
+ np = nlookup(dname, &htp, &fname, 0);
+ dprintf(1, (ddt, "resp: %s '%s' as '%s' (cname=%d)\n",
+ np == NULL ? "missed" : "found", dname, fname, cname));
+ 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;
+
+ dprintf(3, (ddt,
+ "resp: foundname=%d, count=%d, founddata=%d, cname=%d\n",
+ foundname, count, founddata, cname));
+
+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).
+ */
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ switch (findns(&np, class, nsp, &count, 0)) {
+ case NXDOMAIN: /* shouldn't happen */
+ dprintf(3, (ddt, "req: leaving (%s, rcode %d)\n",
+ dname, hp->rcode));
+ if (!foundname)
+ hp->rcode = NXDOMAIN;
+ if (class != C_ANY) {
+ hp->aa = 1;
+ /* XXX: 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_int16_t)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) {
+ dprintf(1,
+ (ddt,
+ "resp: MAXQUERIES exceeded (%s, class %d, type %d)\n",
+ dname, class, type
+ )
+ );
+ syslog(LOG_NOTICE,
+ "MAXQUERIES exceeded, possible data loop in resolving (%s)",
+ dname);
+ goto servfail;
+ }
+
+ /* Reset the query control structure */
+#ifdef DATUMREFCNT
+ for (i = 0 ; i < qp->q_naddr ; i++) {
+ if ((--(qp->q_addr[i].ns->d_rcnt))) {
+ dprintf(1 ,(ddt, "ns_resp: ns %s rcnt %d\n",
+ qp->q_addr[i].ns->d_data,
+ qp->q_addr[i].ns->d_rcnt));
+ } else {
+ dprintf(1 ,(ddt, "ns_resp: ns %s rcnt %d delayed\n",
+ qp->q_addr[i].ns->d_data,
+ qp->q_addr[i].ns->d_rcnt));
+ free((char*)qp->q_addr[i].ns);
+ }
+ if ((--(qp->q_addr[i].nsdata->d_rcnt))) {
+ dprintf(1 ,(ddt, "ns_resp: nsdata %08.8X rcnt %d\n",
+ *(int32_t *)(qp->q_addr[i].nsdata->d_data),
+ qp->q_addr[i].nsdata->d_rcnt));
+ } else {
+ dprintf(1 ,(ddt, "ns_resp: nsdata %08.8X rcnt %d delayed\n",
+ *(int32_t *)(qp->q_addr[i].nsdata->d_data),
+ qp->q_addr[i].nsdata->d_rcnt));
+ free((char*)qp->q_addr[i].nsdata);
+ }
+ }
+#endif
+ qp->q_naddr = 0;
+ qp->q_curaddr = 0;
+ qp->q_fwd = fwdtab;
+#ifdef LAME_DELEGATION
+ getname(np, qp->q_domain, sizeof(qp->q_domain));
+#endif /* LAME_DELEGATION */
+ if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) {
+ if (n < 0) {
+ dprintf(3, (ddt, "resp: nslookup reports danger\n"));
+ } else {
+ dprintf(3, (ddt, "resp: no addrs found for NS's\n"));
+ }
+ if (cname) /* a remote CNAME that does not have data */
+ goto return_newmsg;
+ 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) {
+ dprintf(3, (ddt,
+ "resp: leaving, MAXCNAMES exceeded\n"));
+ goto servfail;
+ }
+ dprintf(1, (ddt, "q_cname = %d\n",qp->q_cname));
+ dprintf(3, (ddt,
+ "resp: building recursive query; nslookup\n"));
+ if (qp->q_msg)
+ (void) free(qp->q_msg);
+ if ((qp->q_msg = (u_char *)malloc(BUFSIZ)) == NULL) {
+ dprintf(1, (ddt, "resp: malloc error\n"));
+ goto servfail;
+ }
+ qp->q_msglen = res_mkquery(QUERY, dname, class,
+ type, 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_int16_t)++nsid);
+ if (qp->q_fwd)
+ hp->rd = 1;
+ unsched(qp);
+ schedretry(qp, retrytime(qp));
+ nsa = Q_NEXTADDR(qp, 0);
+ dprintf(1, (ddt, "resp: forw -> [%s].%d ds=%d nsid=%d id=%d %dms\n",
+ inet_ntoa(nsa->sin_addr),
+ ntohs(nsa->sin_port), ds,
+ ntohs(qp->q_nsid), ntohs(qp->q_id),
+ (qp->q_addr[0].nsdata != NULL)
+ ? qp->q_addr[0].nsdata->d_nstime
+ : (-1)));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(msg, ddt);
+#endif
+ if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0) {
+ if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr))
+ syslog(LOG_NOTICE, "ns_resp: sendto([%s].%d): %m",
+ inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port));
+ nameserIncr(nsa->sin_addr, nssSendtoErr);
+ }
+ hp->rd = 0; /* leave set to 0 for dup detection */
+ nameserIncr(nsa->sin_addr, nssSentFwdR);
+ nameserIncr(qp->q_from.sin_addr, nssRcvdFwdR);
+ dprintf(3, (ddt, "resp: Query sent.\n"));
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+
+formerr:
+ dprintf(3, (ddt,
+ "FORMERR resp() from [%s].%d size err %d, msglen %d\n",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port),
+ cp - msg, msglen));
+ if (!haveComplained((char*)from_addr.sin_addr.s_addr,
+ (char*)dhash((u_char *)formerrmsg,
+ strlen(formerrmsg)
+ )
+ )
+ ) {
+ syslog(LOG_INFO, "Malformed response from [%s].%d (%s)\n",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port),
+ formerrmsg);
+ }
+ nameserIncr(from_addr.sin_addr, nssSentFErr);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+
+return_msg:
+ nameserIncr(from_addr.sin_addr, nssRcvdFwdR);
+ nameserIncr(qp->q_from.sin_addr, nssSentFwdR);
+ /* 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);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+
+return_newmsg:
+ nameserIncr(qp->q_from.sin_addr, nssSentAns);
+ if (addcount) {
+ n = doaddinfo(hp, cp, buflen);
+ cp += n;
+ buflen -= n;
+ }
+ hp->qr = 1;
+ hp->id = qp->q_id;
+ hp->rd = 1;
+ hp->ra = 1;
+ (void) send_msg(newmsg, cp - newmsg, qp);
+ qremove(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+
+servfail:
+ nameserIncr(qp->q_from.sin_addr, nssSentFail);
+ 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((u_char *)hp, (cname ? qp->q_cmsglen : qp->q_msglen),
+ qp);
+ qremove(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+}
+
+/*
+ * Decode the resource record 'rrp' and update the database.
+ * If savens is non-nil, record pointer for forwarding queries a second time.
+ */
+int
+doupdate(msg, msglen, rrp, zone, savens, flags, cred)
+ u_char *msg, *rrp;
+ struct databuf **savens;
+ int msglen, zone, flags;
+ u_int cred;
+{
+ register u_char *cp;
+ register int n;
+ int class, type, dlen, n1;
+ u_int32_t 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
+
+ dprintf(3, (ddt, "doupdate(zone %d, savens %x, flags %x)\n",
+ zone, savens, flags));
+
+ cp = rrp;
+ if ((n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname)) < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ GETSHORT(dlen, cp);
+ dprintf(3, (ddt, "doupdate: dname %s type %d class %d ttl %d\n",
+ dname, type, class, ttl));
+ /*
+ * Convert the resource record data into the internal
+ * database format.
+ */
+ switch (type) {
+ case T_A:
+ if (dlen != INT32SZ) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ /*FALLTHROUGH*/
+ case T_WKS:
+ case T_HINFO:
+ case T_UINFO:
+ case T_UID:
+ case T_GID:
+ case T_TXT:
+ case T_X25:
+ case T_ISDN:
+ case T_NSAP:
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+#endif
+ 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:
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = data;
+ n = strlen((char *)data) + 1;
+ break;
+
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)data, sizeof data);
+ if (n < 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 * INT32SZ;
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += strlen((char *)cp1) + 1;
+ if (type == T_SOA) {
+ bcopy(cp, cp1, n = 5 * INT32SZ);
+ cp += n;
+ cp1 += n;
+ }
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ /* grab preference */
+ bcopy(cp, data, INT16SZ);
+ cp1 = data + INT16SZ;
+ cp += INT16SZ;
+
+ /* get name */
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1,
+ sizeof data - INT16SZ);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+
+ /* compute end of data */
+ cp1 += strlen((char *)cp1) + 1;
+ /* compute size of data */
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ default:
+ dprintf(3, (ddt, "unknown type %d\n", type));
+ return ((cp - rrp) + dlen);
+ }
+ if (n > MAXDATA) {
+ dprintf(1, (ddt,
+ "update type %d: %d bytes is too much data\n",
+ type, n));
+ 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 */
+ dprintf(1, (ddt, "UDPATE: REFUSED - SOA delete\n"));
+ 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)) {
+ dprintf(1,
+ (ddt,
+ "FORMERR UPDATE message length off\n"
+ )
+ );
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ }
+ if ((zonenum = findzone(dname, class)) == 0) {
+ hp->rcode = NXDOMAIN;
+ return (-1);
+ }
+ if (zones[zonenum].z_flags & 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;
+ dp->d_cred = cred;
+ dp->d_clev = db_getclev(zones[zonenum].z_origin);
+ n = db_update(dname, dp, NULL, DB_MEXIST | DB_DELETE,
+ hashtab);
+ if (n != OK) {
+ dprintf(1, (ddt,
+ "UPDATE: db_update failed\n"));
+ free((char*) 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;
+ dp->d_cred = cred;
+ dp->d_clev = db_getclev(zones[zonenum].z_origin);
+ 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((char*) dp);
+ /* Ok for UPDATEMA not to have deleted any RRs */
+ if (!DeletedOne && hp->opcode == UPDATEDA) {
+ dprintf(1, (ddt,
+ "UPDATE: db_update failed\n"));
+ 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) {
+ dprintf(1, (ddt,
+ "FORMERR UPDATE expand name failed\n"));
+ 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) {
+ dprintf(1, (ddt, "UPDATE: too much data\n"));
+ hp->rcode = NOCHANGE;
+ return (-1);
+ }
+ if (cp != (u_char *)(msg + msglen)) {
+ dprintf(1, (ddt,
+ "FORMERR UPDATE message length off\n"));
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if ((zonenum = findzone(dname, class)) == 0) {
+ hp->rcode = NXDOMAIN;
+ return (-1);
+ }
+ if (zones[zonenum].z_flags & Z_DYNADDONLY) {
+ struct hashbuf *htp = hashtab;
+ char *fname;
+ if (nlookup(dname, &htp, &fname, 0) &&
+ !strcasecmp(dname, fname)) {
+ dprintf(1, (ddt,
+ "refusing add of existing name\n"
+ ));
+ hp->rcode = REFUSED;
+ return (-1);
+ }
+ }
+ dp = savedata(class, type, ttl, cp1, n);
+ dp->d_zone = zonenum;
+ dp->d_cred = cred;
+ dp->d_clev = db_getclev(zones[zonenum].z_origin);
+ if ((n = db_update(dname, NULL, dp, DB_NODATA,
+ hashtab)) != OK) {
+ dprintf(1, (ddt, "UPDATE: db_update failed\n"));
+ hp->rcode = NOCHANGE;
+ free((char*) dp);
+ return (-1);
+ }
+ else
+ return (cp - rrp);
+ }
+#endif /* ALLOW_UPDATES */
+
+ if (zone == 0)
+ ttl += tt.tv_sec;
+#if defined(TRACEROOT) || defined(BOGUSNS)
+ if ((type == T_NS) && (savens != NULL)) {
+ char qname[MAXDNAME], *temp;
+ register int bogus = 0;
+ int bogusns = 0;
+#ifdef BOGUSNS
+ if (addr_on_netlist(from_addr.sin_addr, boglist)) {
+ bogusns++;
+ bogus++;
+ }
+#endif
+ if (!bogus &&
+ ((temp = strrchr((char *)data, '.')) != NULL) &&
+ !strcasecmp(temp, ".arpa")
+ )
+ bogus++;
+ qname[0] = qname[1] = '\0';
+ if (dn_expand(msg, msg + msglen, msg + HFIXEDSZ,
+ qname, sizeof(qname)) < 0)
+ qname[0] = '?';
+ else if (qname[0] == '\0')
+ qname[0] = '.';
+ if (bogus && ((dname[0] == '\0') && (zone == 0))) {
+ if (!haveComplained((char*)from_addr.sin_addr.s_addr,
+ "bogus root NS"))
+ syslog(LOG_NOTICE,
+ "bogus root NS %s rcvd from [%s] on query for \"%s\"",
+ data, inet_ntoa(from_addr.sin_addr),
+ qname);
+ return (cp - rrp);
+ }
+#ifdef BOGUSNS
+ if (bogusns) {
+ if (!haveComplained((char*)from_addr.sin_addr.s_addr,
+ "bogus nonroot NS"))
+ syslog(LOG_NOTICE,
+ "bogus nonroot NS %s rcvd from [%s] on query for \"%s\"",
+ data, inet_ntoa(from_addr.sin_addr),
+ qname);
+ return (cp - rrp);
+ }
+#endif
+ }
+#endif /*TRACEROOT || BOGUSNS*/
+
+ dp = savedata(class, type, ttl, cp1, n);
+ dp->d_zone = zone;
+ dp->d_cred = cred;
+ dp->d_clev = 0; /* We trust what is on disk more, except root srvrs */
+ if ((n = db_update(dname, dp, dp, flags, hashtab)) != OK) {
+#ifdef DEBUG
+ if (debug && (n != DATAEXISTS))
+ fprintf(ddt,"update failed (%d)\n", n);
+ else if (debug >= 3)
+ fprintf(ddt,"update failed (DATAEXISTS)\n");
+#endif
+ free((char *)dp);
+ } else if (type == T_NS && savens != NULL)
+ *savens = dp;
+ return (cp - rrp);
+}
+
+int
+send_msg(msg, msglen, qp)
+ u_char *msg;
+ int msglen;
+ struct qinfo *qp;
+{
+ if (qp->q_flags & 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) {
+ struct qinfo *tqp;
+
+ 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) {
+ if (!haveComplained((char*)qp->q_from.sin_addr.s_addr,
+ sendtoStr))
+ syslog(LOG_NOTICE,
+ "send_msg: sendto([%s].%d): %m",
+ inet_ntoa(qp->q_from.sin_addr),
+ ntohs(qp->q_from.sin_port));
+ nameserIncr(qp->q_from.sin_addr, nssSendtoErr);
+ return (1);
+ }
+ } else {
+ (void) writemsg(qp->q_stream->s_rfd, (u_char*)msg, msglen);
+ sq_done(qp->q_stream);
+ }
+ return (0);
+}
+
+#ifdef notdef
+/* i don't quite understand this but the only ref to it is notdef'd --vix */
+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 + HFIXEDSZ, (u_char *)dname,
+ sizeof(dname)) < 0)
+ return;
+ dprintf(2, (ddt, "prime: %s\n", dname));
+ (void) sysquery(dname, class, type, NULL, 0);
+}
+#endif
+
+void
+prime_cache()
+{
+ register struct qinfo *qp;
+
+ dprintf(1, (ddt, "prime_cache: priming = %d\n", priming));
+ if (!priming && fcachetab->h_tab[0] != NULL && !forward_only) {
+ priming++;
+ if ((qp = sysquery("", C_IN, T_NS, NULL, 0)) == NULL)
+ priming = 0;
+ else
+ qp->q_flags |= (Q_SYSTEM | Q_PRIMING);
+ }
+ needs_prime_cache = 0;
+ return;
+}
+
+struct qinfo *
+sysquery(dname, class, type, nss, nsc)
+ char *dname;
+ int class, type;
+ struct in_addr *nss;
+ int nsc;
+{
+ register struct qinfo *qp, *oqp;
+ register HEADER *hp;
+ struct namebuf *np;
+ struct databuf *nsp[NSMAX];
+ struct hashbuf *htp;
+ struct sockaddr_in *nsa;
+ char *fname;
+ int count;
+
+#ifdef DATUMREFCNT
+ nsp[0] = NULL;
+#endif
+ dprintf(3, (ddt, "sysquery(%s, %d, %d, 0x%x, %d)\n",
+ dname, class, type, nss, nsc));
+ qp = qnew();
+
+ if (nss && nsc) {
+ np = NULL;
+ } else {
+ htp = hashtab;
+ if (priming && dname[0] == '\0') {
+ np = NULL;
+ } else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) {
+ dprintf(1, (ddt,
+ "sysquery: nlookup error on %s?\n",
+ dname));
+ qfree(qp);
+ return (0);
+ }
+
+ switch (findns(&np, class, nsp, &count, 0)) {
+ case NXDOMAIN:
+ case SERVFAIL:
+ dprintf(1, (ddt,
+ "sysquery: findns error on %s?\n", dname));
+ qfree(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (0);
+ }
+ }
+
+ /* build new qinfo struct */
+ qp->q_cmsg = qp->q_msg = NULL;
+ qp->q_dfd = ds;
+ if (nss && nsc)
+ qp->q_fwd = NULL;
+ else
+ qp->q_fwd = fwdtab;
+ qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2;
+ qp->q_flags |= Q_SYSTEM;
+#ifdef LAME_DELEGATION
+ getname(np, qp->q_domain, sizeof(qp->q_domain));
+#endif /* LAME_DELEGATION */
+
+ if ((qp->q_msg = (u_char *)malloc(BUFSIZ)) == NULL) {
+ qfree(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (0);
+ }
+ qp->q_msglen = res_mkquery(QUERY, dname, class,
+ type, NULL, 0, NULL,
+ qp->q_msg, BUFSIZ);
+ hp = (HEADER *) qp->q_msg;
+ hp->id = qp->q_nsid = htons((u_int16_t)++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
+ ) {
+ dprintf(3, (ddt, "sysquery: duplicate\n"));
+ qfree(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (0);
+ }
+ }
+
+ if (nss && nsc) {
+ int i;
+ struct qserv *qs;
+
+ for (i = 0, qs = qp->q_addr;
+ i < nsc;
+ i++, qs++) {
+ qs->ns_addr.sin_family = AF_INET;
+ qs->ns_addr.sin_addr = nss[i];
+ qs->ns_addr.sin_port = ns_port;
+ qs->ns = NULL;
+ qs->nsdata = NULL;
+ qs->stime = tt;
+ qs->nretry = 0;
+ }
+ qp->q_naddr = nsc;
+ } else {
+ if ((count = nslookup(nsp, qp, dname, "sysquery")) <= 0) {
+ if (count < 0) {
+ dprintf(1, (ddt,
+ "sysquery: nslookup reports danger\n"));
+ } else {
+ dprintf(1, (ddt,
+ "sysquery: no addrs found for NS's\n"));
+ }
+ qfree(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (0);
+ }
+ }
+
+ schedretry(qp, retrytime(qp));
+ if (qp->q_fwd == NULL)
+ qp->q_addr[0].stime = tt; /* XXX - why not every? */
+ nsa = Q_NEXTADDR(qp, 0);
+
+ dprintf(1, (ddt,
+ "sysquery: send -> [%s].%d dfd=%d nsid=%d id=%d retry=%ld\n",
+ inet_ntoa(nsa->sin_addr),
+ ntohs(nsa->sin_port), qp->q_dfd,
+ ntohs(qp->q_nsid), ntohs(qp->q_id),
+ qp->q_time));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(qp->q_msg, ddt);
+#endif
+ if (sendto(qp->q_dfd, qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0) {
+ if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr))
+ syslog(LOG_NOTICE, "sysquery: sendto([%s].%d): %m",
+ inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port));
+ nameserIncr(nsa->sin_addr, nssSendtoErr);
+ }
+ nameserIncr(nsa->sin_addr, nssSentSysQ);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (qp);
+}
+
+/*
+ * Check the list of root servers after receiving a response
+ * to a query for the root servers.
+ */
+static void
+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++;
+ dprintf(1, (ddt, "%d root servers\n", count));
+ 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) {
+ dprintf(1, (ddt, "deleting old root server '%s'\n",
+ dp->d_data));
+ 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
+ */
+static void
+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;
+
+ dprintf(2, (ddt, "check_ns()\n"));
+
+ curtime = (u_int32_t) 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 = (caddr_t) dp->d_data;
+ htp = hashtab;
+ tnp = nlookup(dname, &htp, &fname, 0);
+ if (tnp == NULL || fname != dname) {
+ dprintf(3, (ddt,
+ "check_ns: %s: not found %s %x\n",
+ dname, fname, tnp));
+ sysquery(dname, dp->d_class, T_A, NULL, 0);
+ 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)) {
+ dprintf(3, (ddt,
+ "check_ns: stale entry '%s'\n",
+ tnp->n_dname));
+ /* 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, NULL, 0);
+ }
+ }
+}
+
+/* int findns(npp, class, nsp, countp, flag)
+ * Find NS' or an SOA
+ * npp, class:
+ * dname whose least-superior NS is wanted
+ * nsp, countp:
+ * result array and count; array will also be NULL terminated
+ * flag:
+ * boolean: we're being called from ADDAUTH, bypass authority checks
+ * return value:
+ * NXDOMAIN: we are authoritative for this {dname,class}
+ * SERVFAIL: we are auth but zone isn't loaded; or, no root servers found
+ * OK: success (this is the only case where *countp and nsp[] are valid)
+ */
+int
+findns(npp, class, nsp, countp, flag)
+ register struct namebuf **npp;
+ int class;
+ struct databuf **nsp;
+ int *countp;
+ int flag;
+{
+ register struct namebuf *np = *npp;
+ register struct databuf *dp;
+ register struct databuf **nspp;
+ struct hashbuf *htp;
+
+#ifdef DATUMREFCNT
+ nsp[0] = NULL;
+#endif
+
+ if (priming && (np == NULL || np->n_dname[0] == '\0'))
+ htp = fcachetab;
+ else
+ htp = hashtab;
+
+try_again:
+ if (htp == fcachetab)
+ needs_prime_cache = 1;
+ while (np == NULL && htp != NULL) {
+ dprintf(3, (ddt, "findns: using %s\n",
+ htp == hashtab ? "cache" : "hints"));
+ 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) {
+ dprintf(5, (ddt, "findns: np 0x%x '%s'\n", np, np->n_dname));
+ /* Look first for SOA records. */
+#ifdef ADDAUTH
+ if (!flag)
+#endif
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (dp->d_zone != 0 && match(dp, class, T_SOA)) {
+ dprintf(3, (ddt, "findns: SOA found\n"));
+ if (zones[dp->d_zone].z_flags & Z_AUTH) {
+ *npp = np;
+ nsp[0] = dp;
+#ifdef DATUMREFCNT
+ nsp[1] = NULL;
+ dp->d_rcnt++;
+#endif
+ return (NXDOMAIN);
+ } else {
+ /* XXX: zone isn't loaded but we're
+ * primary or secondary for it.
+ * should we fwd this?
+ */
+ 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 (!match(dp, class, T_NS))
+ continue;
+ /*
+ * Don't use records that may become invalid to
+ * reference later when we do the rtt computation.
+ * Never delete our safety-belt information!
+ *
+ * XXX: this is horribly bogus.
+ */
+ if ((dp->d_zone == 0) &&
+ (dp->d_ttl < (tt.tv_sec+900)) &&
+ !(dp->d_flags & DB_F_HINT)) {
+ dprintf(1, (ddt, "findns: stale entry '%s'\n",
+ np->n_dname));
+ /* 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;
+#ifdef DATUMREFCNT
+ dp->d_rcnt++;
+#endif
+ }
+ }
+
+ *countp = nspp - nsp;
+ if (*countp > 0) {
+ dprintf(3, (ddt, "findns: %d NS's added for '%s'\n",
+ *countp, np->n_dname));
+ *nspp = NULL;
+ *npp = np;
+ return (OK); /* Success, got some NS's */
+ }
+try_parent:
+ np = np->n_parent;
+ }
+ if (htp)
+ goto try_again;
+ dprintf(1, (ddt, "findns: No root nameservers for class %s?\n",
+ p_class(class)));
+ if ((unsigned)class < MAXCLASS && norootlogged[class] == 0) {
+ norootlogged[class] = 1;
+ syslog(LOG_ERR, "No root nameservers for class %s\n",
+ p_class(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.
+ */
+int
+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;
+
+#ifdef ROUND_ROBIN
+ if (type != T_ANY && type != T_PTR) {
+ /* cycle order of RRs, for a load balancing effect... */
+
+ register struct databuf **dpp;
+
+ for (dpp = &np->n_data; dp = *dpp; dpp = &dp->d_next) {
+ if (dp->d_next && wanted(dp, class, type)) {
+ register struct databuf *lp;
+
+ *dpp = lp = dp->d_next;
+ dp->d_next = NULL;
+
+ for (dpp = &lp->d_next;
+ *dpp;
+ dpp = &lp->d_next)
+ lp = *dpp;
+ *dpp = dp;
+ break;
+ }
+ }
+ }
+#endif /*ROUND_ROBIN*/
+
+ buflen = *lenp;
+ cp = ((char *)hp) + *countp;
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!wanted(dp, class, type)) {
+#ifndef NCACHE /*if no negative caching then cname => nothing else*/
+ if (type == T_CNAME && class == dp->d_class) {
+ /* any data means no CNAME exists */
+ *countp = 0;
+ return 0;
+ }
+#endif /*NCACHE*/
+ 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.
+ */
+ dprintf(3, (ddt,
+ "finddata: stale entry '%s'\n",
+ np->n_dname));
+ if (dp->d_zone == 0)
+ foundstale++;
+ continue;
+ }
+ if (dp->d_cred == DB_C_ADDITIONAL) {
+ /* we want to expire additional data very
+ * quickly. current strategy is to cut 5%
+ * off each time it is accessed. this makes
+ * stale(dp) true faster when this datum is
+ * used often.
+ */
+ dp->d_ttl = tt.tv_sec
+ +
+ 0.95 * (int) (dp->d_ttl - tt.tv_sec);
+ }
+#ifdef NCACHE
+ /* -ve $ing stuff, anant@isi.edu
+ * if we have a -ve $ed record, change the rcode on the
+ * header to reflect that
+ */
+ if (dp->d_rcode == NOERROR_NODATA) {
+ if (count != 0) {
+ /*
+ * This should not happen, yet it does...
+ */
+ syslog(LOG_WARNING,
+ "NODATA & data for \"%s\" type %d class %d",
+ *dnamep, type, class);
+ continue;
+ }
+ if (type != T_ANY) {
+ hp->rcode = NOERROR_NODATA;
+ *countp = 0;
+ return 1; /* XXX - we have to report success */
+ }
+ /* don't satisfy T_ANY queries from -$ info */
+ continue;
+ }
+#ifndef RETURNSOA
+ if (dp->d_rcode == NXDOMAIN) {
+ if (count != 0) {
+ /*
+ * This should not happen, yet it might...
+ */
+ syslog(LOG_WARNING,
+ "NXDOMAIN & data for \"%s\" type %d class %d",
+ *dnamep, type, class);
+ continue;
+ }
+ if (type != T_ANY) {
+ hp->rcode = NXDOMAIN;
+ *countp = 0;
+ return 1; /* XXX - we have to report success */
+ }
+ /* don't satisfy T_ANY queries from -$ info */
+ continue;
+ }
+#endif
+#endif /*NCACHE*/
+
+ if ((n = make_rr(*dnamep, dp, (u_char *)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_flags & Z_AUTH) &&
+ class != C_ANY)
+ hp->aa = 1; /* XXX */
+#endif
+ if (dp->d_type == T_CNAME) {
+ if (type != T_ANY) { /* or T_NS? */
+ *dnamep = (caddr_t) dp->d_data;
+ if (dp->d_zone &&
+ (zones[dp->d_zone].z_flags & 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);
+ /* XXX this isn't right if 'type' is something special
+ * such as T_AXFR or T_MAILB, since the matching done
+ * by match() in delete_all() is different from that
+ * done by wanted() above.
+ */
+ }
+ dprintf(3, (ddt, "finddata: added %d class %d type %d RRs\n",
+ count, class, type));
+ *countp = count;
+ return (*lenp - buflen);
+}
+
+/*
+ * Do we want this data record based on the class and type?
+ */
+int
+wanted(dp, class, type)
+ struct databuf *dp;
+ int class, type;
+{
+
+ dprintf(3, (ddt, "wanted(%x, %d, %d) %d, %d\n", dp, class, type,
+ dp->d_class, dp->d_type));
+
+ if (dp->d_class != class && class != C_ANY)
+ return (0);
+ if (type == dp->d_type)
+ return (1);
+#ifdef NCACHE
+ /*-ve $ing stuff, for a T_ANY query, we do not want to return
+ * -ve $ed RRs.
+ */
+ if (type == T_ANY && dp->d_rcode == NOERROR_NODATA)
+ return (0);
+#endif
+
+ switch (dp->d_type) {
+ case T_ANY:
+ return (1);
+ case T_CNAME:
+#ifdef NCACHE
+ if (dp->d_rcode != NOERROR_NODATA)
+#endif
+ return (1);
+#ifdef NCACHE
+ else
+ break;
+#endif
+ }
+ 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:
+ /* T_AXFR needs an authoritative SOA */
+ if (dp->d_type == T_SOA && dp->d_zone != 0
+ && (zones[dp->d_zone].z_flags & Z_AUTH))
+ return (1);
+ break;
+ }
+ 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.
+ */
+int
+add_data(np, dpp, cp, buflen)
+ struct namebuf *np;
+ struct databuf **dpp;
+ register u_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 */
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ 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.
+ */
+void
+delete_all(np, class, type)
+ register struct namebuf *np;
+ int class, type;
+{
+ register struct databuf *dp, *pdp;
+
+ dprintf(3, (ddt, "delete_all: '%s' 0x%x class %d type %d\n",
+ np->n_dname, np, class, type));
+ 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.sbin/named/ns_sort.c b/usr.sbin/named/ns_sort.c
new file mode 100644
index 0000000..c35b58f
--- /dev/null
+++ b/usr.sbin/named/ns_sort.c
@@ -0,0 +1,169 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_sort.c 4.10 (Berkeley) 3/3/91";
+static char rcsid[] = "$Id: ns_sort.c,v 4.9.1.6 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1990
+ * -
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <resolv.h>
+
+#include "named.h"
+
+static int sort_rr __P((u_char *cp, int count, struct netinfo *ntp, u_char *eom));
+
+struct netinfo *
+local(from)
+ struct sockaddr_in *from;
+{
+ 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->addr == (from->sin_addr.s_addr & ntp->mask))
+ return (ntp);
+ }
+ return (NULL);
+}
+
+void
+sort_response(cp, ancount, lp, eom)
+ register u_char *cp;
+ register int ancount;
+ struct netinfo *lp;
+ u_char *eom;
+{
+ register struct netinfo *ntp;
+
+ dprintf(3, (ddt, "sort_response(%d)\n", ancount));
+ if (ancount > 1) {
+ if (sort_rr(cp, ancount, lp, eom))
+ return;
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if ((ntp->addr == lp->addr) && (ntp->mask == lp->mask))
+ continue;
+ if (sort_rr(cp, ancount, ntp, eom))
+ break;
+ }
+ }
+}
+
+static 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->addr;
+ fprintf(ddt, "sort_rr(x%x, %d, [%s])\n",
+ cp, count, inet_ntoa(inaddr));
+ }
+#endif
+ 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 += INT32SZ;
+ 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, INADDRSZ);
+ if (rr1 == NULL)
+ rr1 = cp;
+ if ((ntp->mask & inaddr.s_addr) == ntp->addr) {
+ dprintf(2, (ddt,"net [%s] best choice\n",
+ inet_ntoa(inaddr)));
+ if (rr1 != cp) {
+ bcopy(rr1, cp, INADDRSZ);
+ bcopy((char *)&inaddr, rr1, INADDRSZ);
+ }
+ return (1);
+ }
+ break;
+ }
+ break;
+ }
+ cp += dlen;
+ }
+ return (0);
+}
diff --git a/usr.sbin/named/ns_stats.c b/usr.sbin/named/ns_stats.c
new file mode 100644
index 0000000..d6d6225
--- /dev/null
+++ b/usr.sbin/named/ns_stats.c
@@ -0,0 +1,325 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_stats.c 4.10 (Berkeley) 6/27/90";
+static char rcsid[] = "$Id: ns_stats.c,v 4.9.1.7 1994/06/06 09:08:15 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+/**************************************************************************/
+/* simple monitoring of named behavior */
+/* dumps a bunch of values into a well-known file */
+/**************************************************************************/
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <errno.h>
+
+#include "named.h"
+#include "tree.h"
+
+static u_long typestats[T_ANY+1];
+static const 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", "RP", "AFSDB", "X25",
+ "ISDN", "RT", "NSAP", 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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,
+ /* 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"
+};
+
+static void nameserStats __P((FILE *));
+
+void
+ns_stats()
+{
+ time_t timenow;
+ register FILE *f;
+ register int i;
+
+ if (!(f = fopen(statsfile, "a"))) {
+ dprintf(1, (ddt, "can't open stat file, \"%s\"\n", statsfile));
+ syslog(LOG_ERR, "cannot open stat file, \"%s\"\n", statsfile);
+ return;
+ }
+
+ time(&timenow);
+ fprintf(f, "+++ Statistics Dump +++ (%ld) %s",
+ (long)timenow, ctime(&timenow));
+ fprintf(f, "%d\ttime since boot (secs)\n", timenow - boottime);
+ fprintf(f, "%d\ttime since reset (secs)\n", timenow - resettime);
+
+#ifdef DMALLOC
+ /* malloc statistics */
+ dmallocstats(f);
+#endif
+
+ /* 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);
+
+ /* name server statistics */
+ nameserStats(f);
+
+ fprintf(f, "--- Statistics Dump --- (%ld) %s",
+ (long)timenow, ctime(&timenow));
+ (void) my_fclose(f);
+}
+
+void
+qtypeIncr(qtype)
+ int qtype;
+{
+ if (qtype < T_A || qtype > T_ANY)
+ qtype = 0; /* bad type */
+ typestats[qtype]++;
+}
+
+static tree *nameserTree;
+static int nameserInit;
+
+#ifdef STATS
+static FILE *nameserStatsFile;
+static u_long globalStats[nssLast];
+static const char *statNames[nssLast] = {
+ "RQ", /* sent us a query */
+ "RR", /* sent us an answer */
+ "RIQ", /* sent us an inverse query */
+ "RNXD", /* sent us a negative response */
+ "RFwdQ", /* sent us a query we had to fwd */
+ "RFwdR", /* sent us a response we had to fwd */
+ "RDupQ", /* sent us a retry */
+ "RDupR", /* sent us an extra answer */
+ "RFail", /* sent us a SERVFAIL */
+ "RFErr", /* sent us a FORMERR */
+ "RErr", /* sent us some other error */
+ "RTCP", /* sent us a query using TCP */
+ "RAXFR", /* sent us an AXFR */
+ "RLame", /* sent us a lame delegation */
+ "ROpts", /* sent us some IP options */
+ "SSysQ", /* sent them a sysquery */
+ "SAns", /* sent them an answer */
+ "SFwdQ", /* fwdd a query to them */
+ "SFwdR", /* fwdd a response to them */
+ "SDupQ", /* sent them a retry */
+ "SFail", /* sent them a SERVFAIL */
+ "SFErr", /* sent them a FORMERR */
+ };
+#endif /*STATS*/
+
+static int
+nameserCompar(t1, t2)
+ const tree_t t1, t2;
+{
+ u_int32_t a1 = ntohl(((struct nameser *)t1)->addr.s_addr),
+ a2 = ntohl(((struct nameser *)t2)->addr.s_addr);
+
+ if (a1 < a2)
+ return (-1);
+ else if (a1 > a2)
+ return (1);
+ else
+ return (0);
+}
+
+struct nameser *
+nameserFind(addr, flags)
+ struct in_addr addr;
+ int flags;
+{
+ struct nameser dummy;
+ struct nameser *ns;
+
+ if (!nameserInit) {
+ tree_init(&nameserTree);
+ nameserInit++;
+ }
+
+ dummy.addr = addr;
+ ns = (struct nameser *)tree_srch(&nameserTree, nameserCompar,
+ (tree_t)&dummy);
+ if (!ns && (flags & NS_F_INSERT)) {
+ ns = (struct nameser *)malloc(sizeof(struct nameser));
+ if (!ns) {
+ nomem: if (!haveComplained("nameserFind complaint", ""))
+ syslog(LOG_NOTICE,
+ "nameserFind: malloc failed; %m");
+ return (NULL);
+ }
+ memset(ns, 0, sizeof(struct nameser));
+ ns->addr = addr;
+ if (!tree_add(&nameserTree, nameserCompar, (tree_t)ns, NULL)) {
+ int save = errno;
+ free(ns);
+ errno = save;
+ goto nomem;
+ }
+ }
+ return (ns);
+}
+
+
+void
+nameserIncr(addr, which)
+ struct in_addr addr;
+ enum nameserStats which;
+{
+#ifdef STATS
+ struct nameser *ns = nameserFind(addr, NS_F_INSERT);
+
+ if ((int)which < (int)nssLast) {
+ if (ns)
+ ns->stats[(int)which]++;
+ globalStats[(int)which]++;
+ } else {
+ syslog(LOG_DEBUG, "nameserIncr([%d], %d): bad 'which'",
+ inet_ntoa(addr), (int)which);
+ }
+#endif /*STATS*/
+}
+
+#ifdef STATS
+static void
+nameserStatsOut(f, stats)
+ FILE *f;
+ u_long stats[];
+{
+ int i;
+ char *pre = "\t";
+
+ for (i = 0; i < (int)nssLast; i++) {
+ fprintf(f, "%s%u", pre, stats[i]);
+ pre = ((i+1) % 5) ? " " : " ";
+ }
+ fputc('\n', f);
+}
+
+static void
+nameserStatsHdr(f)
+ FILE *f;
+{
+ int i;
+ char *pre = "\t";
+
+ fprintf(f, "(Legend)\n");
+ for (i = 0; i < (int)nssLast; i++) {
+ fprintf(f, "%s%s", pre,
+ statNames[i] ? statNames[i] : "");
+ pre = ((i+1) % 5) ? "\t" : "\n\t";
+ }
+ fputc('\n', f);
+}
+
+static int
+nameserStatsTravUAR(t)
+ tree_t t;
+{
+ struct nameser *ns = (struct nameser *)t;
+
+ fprintf(nameserStatsFile, "[%s]\n", /* : rtt %u */
+ inet_ntoa(ns->addr) /*, ns->rtt*/ );
+ nameserStatsOut(nameserStatsFile, ns->stats);
+ return (1);
+}
+#endif /*STATS*/
+
+static void
+nameserStats(f)
+ FILE *f;
+{
+#ifndef STATS
+ fprintf(f, "<<No nameserver statistics in this server>>\n");
+#else
+ nameserStatsFile = f;
+ fprintf(f, "++ Name Server Statistics ++\n");
+ nameserStatsHdr(f);
+ fprintf(f, "(Global)\n");
+ nameserStatsOut(f, globalStats);
+ tree_trav(&nameserTree, nameserStatsTravUAR);
+ fprintf(f, "-- Name Server Statistics --\n");
+ nameserStatsFile = NULL;
+#endif /*STATS*/
+}
diff --git a/usr.sbin/named/ns_validate.c b/usr.sbin/named/ns_validate.c
new file mode 100644
index 0000000..f1236c5
--- /dev/null
+++ b/usr.sbin/named/ns_validate.c
@@ -0,0 +1,1161 @@
+/**************************************************************************
+ * ns_validate.c (was security.c in original ISI contribution)
+ * author: anant kumar
+ * contributed: March 17, 1993
+ *
+ * implements validation procedure for RR's received from a server as a
+ * response to a query.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <syslog.h>
+#include <errno.h>
+#include <stdio.h>
+#include <resolv.h>
+
+#include "named.h"
+
+#ifdef VALIDATE
+
+static int isvalid __P((struct namebuf *, int, int, char *, int)),
+ check_addr_ns __P((struct databuf **,
+ struct sockaddr_in *,
+ char *)),
+ check_in_tables __P((struct databuf **,
+ struct sockaddr_in *,
+ char *));
+#if 0
+static void stick_in_queue __P((char *, int, int, char *));
+#endif
+
+static NAMEADDR nameaddrlist[MAXNAMECACHE];
+static int firstNA = 0,
+ lastNA = 0;
+
+static TO_Validate *validateQ, *currentVQ;
+static int VQcount;
+
+/*****************************************************************
+ * validate() is called from dovalidate(). it takes as parameters,
+ * the domain name sought, the class, type etc. of record, the server
+ * that gave us the answer and the data it gave us
+ *
+ * it returns VALID if it is able to validate the record, INVALID if it cannot.
+ * furtehr VALID is split into VALID_CACHE if we need to cache this record
+ * since the domainname is not something we are authoritative for and
+ * VALID_NO_CACHE if the name is something we are authoritative for.
+ *
+ * pseudocode for function validate is as follows:
+ * validate(domain, server, type, class, data, dlen, rcode) {
+ *
+ * if(dname or a higher level name not found in cache)
+ * return INVALID;
+ * if (NS records for "domain" found in cache){
+ *
+ * if(we are authoritative) /findns() returned NXDOMAIN;/
+ * if(we did not have an exact match on names)
+ * =>the name does not exist in our database
+ * => data is bad: return INVALID
+ * if(data agrees with what we have)
+ * return VALID_NO_CACHE;
+ * else return INVALID;
+ *
+ * if(we are not authoritative) /findns() returned OK;/
+ * if (address records for NS's found in cache){
+ * if("server" = one of the addresses){
+ * return VALID_CACHE;
+ * }else{
+ * stick in queue of "to_validate" data;
+ * return (INVALID);
+ * }
+ * else return INVALID;
+ *
+ * This performs the validation procedure described above. Checks
+ * for the longest component of the dname that has a NS record
+ * associated with it. At any stage, if no data is found, it implies
+ * that the name is bad (has an unknown domain identifier) thus, we
+ * return INVALID.
+ * If address of one of these servers matches the address of the server
+ * that returned us this data, we are happy!
+ *
+ * since findns will set needs_prime_cache if np = NULL is passed, we always
+ * reset it. will let ns_req do it when we are searching for ns records to
+ * query someone. hence in all the three cases of switch(findns())
+ * we have needs_prime_cache = 0;
+ *****************************************************************************/
+int
+validate(dname, server, type, class, data, dlen
+#ifdef NCACHE
+ ,rcode
+#endif
+ )
+ char *dname;
+ struct sockaddr_in *server;
+ int type;
+ int class;
+ char *data;
+ int dlen;
+#ifdef NCACHE
+ int rcode;
+#endif
+{
+ struct namebuf *np, *dnamep;
+ struct hashbuf *htp;
+ struct databuf *nsp[NSMAX];
+ int count;
+ char *fname;
+ int exactmatch = 0;
+ struct fwdinfo *fwd;
+
+#ifdef DATUMREFCNT
+ nsp[0] = NULL;
+#endif
+ dprintf(3, (ddt,
+ "validate(), d:%s, s:[%s], t:%d, c:%d\n",
+ dname, inet_ntoa(server->sin_addr), type, class));
+
+ /* everything from forwarders is the GOSPEL */
+ for (fwd = fwdtab; fwd != NULL; fwd = fwd->next) {
+ if (server->sin_addr.s_addr == fwd->fwdaddr.sin_addr.s_addr)
+ return(VALID_CACHE);
+ }
+
+ htp = hashtab;
+ if (priming && (dname[0] == '\0'))
+ np = NULL;
+ else
+ np = nlookup(dname, &htp, &fname, 0);
+
+ /* we were able to locate namebufs for this domain, or a parent domain,
+ * or ??? */
+
+ if (np == NULL) {
+ fname = (char *)malloc(1);
+ fname[0] = '\0';
+ }
+ dprintf(5, (ddt,
+ "validate:namebuf found np:0x%x, d:\"%s\", f:\"%s\"\n",
+ np, dname, fname));
+ /* save the namebuf if we were able to locate the exact dname */
+ if (!strcasecmp(dname, fname)) {
+ dnamep = np;
+ exactmatch = 1;
+ }
+ if (np == NULL && fname != NULL) {
+ free((char *)fname);
+ }
+ switch (findns(&np, class, nsp, &count, 0)) {
+ case NXDOMAIN:
+ /** we are authoritative for this domain, lookup name
+ * in our zone data, if it matches, return valid.
+ * in either case, do not cache
+ **/
+ dprintf(5, (ddt, "validate: auth data found\n"));
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ if (needs_prime_cache)
+ needs_prime_cache = 0;
+
+#ifdef NCACHE
+ if(rcode == NXDOMAIN) {
+ /* If we had an exactmatch on the name, we found the
+ * name in our authority database, so this couldn't
+ * have been a bad name. INVALID data, say so
+ */
+ if (exactmatch)
+ return INVALID;
+ else
+ /* we did not have an exactmatch, the data is
+ * good, we do not NCACHE stuff we are
+ * authoritative for, though.
+ */
+ return VALID_NO_CACHE;
+ }
+#endif
+ if (!strcasecmp(dname, np->n_dname)) {
+
+ /* if the name we seek is the same as that we have ns
+ * records for, compare the data we have to see if it
+ * matches. if it does, return valid_no_cache, if it
+ * doesn't, invalid.
+ */
+ if (isvalid(np, type, class, data, dlen))
+ return VALID_NO_CACHE;
+ else
+ return INVALID;
+ }
+
+ /* we found ns records in a higher level, if we were unable to
+ * locate the exact name earlier, it means we are
+ * authoritative for this domain but do not have records for
+ * this name. this name is obviously invalid
+ */
+ if (!exactmatch)
+ return INVALID;
+
+ /* we found the exact name earlier and we are obviously
+ * authoritative so check for data records and see if any
+ * match.
+ */
+ if (isvalid(dnamep, type, class, data, dlen))
+ return VALID_NO_CACHE;
+ else
+ return INVALID;
+
+ case SERVFAIL:/* could not find name server records*/
+ /* stick_in_queue(dname, type, class, data); */
+ if (needs_prime_cache)
+ needs_prime_cache = 0;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return INVALID;
+
+ case OK: /*proceed */
+ dprintf(5,
+ (ddt,
+ "validate:found ns records:calling check_addr_ns\n"));
+ if (needs_prime_cache)
+ needs_prime_cache = 0;
+ if (check_addr_ns(nsp, server, dname)) {
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return VALID_CACHE;
+ }
+ /* server is not one of those we know of */
+ /* stick_in_queue(dname, type, class, data); */
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return INVALID;
+ default:
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return INVALID;
+ } /*switch*/
+
+} /*validate*/
+
+/***********************************************************************
+ * validate rr returned by somebody against your own database, if you are
+ * authoritative for the information. if you have a record that matches,
+ * return 1, else return 0. validate() above will use this and determine
+ * if the record should be returned/discarded.
+ ***********************************************************************/
+static int
+isvalid(np, type, class, data, dlen)
+ struct namebuf *np;
+ int type, class;
+ char *data;
+ int dlen;
+{
+ register struct databuf *dp;
+
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!wanted(dp, class, type)) {
+ if ((type == T_CNAME) && (class == dp->d_class)) {
+ /* if a cname exists, any other will not */
+ return(0);
+ /* we come here only for zone info,
+ * so -ve $ed info can't be
+ */
+ }
+ continue;
+ }
+ /* type and class match, if i get here
+ * let's now compare the data section, per RR type
+ */
+
+ /* unless, of course, the data was negative, in which case
+ * we should return FAILURE since we should not have found
+ * data here.
+ */
+ if ((data == NULL) || (dlen == 0)) {
+ return 0;
+ }
+
+ /* XXX: why aren't we just calling db_cmp() ?
+ */
+
+ switch (type) {
+ char *td;
+ u_char *tdp;
+ int x;
+
+ case T_A:
+ case T_WKS:
+ case T_HINFO:
+ case T_UINFO:
+ case T_UID:
+ case T_GID:
+ case T_TXT:
+ case T_X25:
+ case T_ISDN:
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+#endif
+ x = memcmp(dp->d_data, data, dlen);
+ dprintf(3, (ddt, "type = %d, GOOD = %d\n",
+ type, x));
+ if (x == 0)
+ return (1);
+ else
+ break;
+
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_NS:
+ case T_PTR:
+ x = strncasecmp((char *)dp->d_data, data, dlen);
+ dprintf(3, (ddt, "type = %d, GOOD = %d\n",
+ type, x));
+ if (x == 0)
+ return (1);
+ else
+ break;
+
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ /* compare first string */
+ x = strncasecmp((char *)dp->d_data, data,
+ strlen(data) + 1);
+ if (x != 0)
+ break;
+
+ /* move to second string */
+ td = data + (strlen(data) + 1);
+ tdp = dp->d_data +
+ (strlen((char *)dp->d_data)+1);
+
+ /* compare second string */
+ x = strncasecmp(td, (char *)tdp,
+ strlen((char *)td+1));
+ if (x != 0)
+ break;
+
+ /* move beyond second string, to
+ * set of words in SOA.
+ * RP and MINFO stuff really
+ * ends here
+ */
+
+ td = td + strlen((char *)td) + 1;
+ tdp = tdp + strlen((char *)tdp) + 1;
+ if (type == T_SOA) {
+ x = memcmp(td, (char *)tdp,
+ 5*INT32SZ);
+ if (x != 0)
+ break;
+ }
+
+ /* everything was equal, wow!
+ * so return a success
+ */
+ return (1);
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ x = memcmp(dp->d_data, data,
+ INT16SZ);
+ if (x != 0)
+ break;
+ td = data + INT16SZ;
+ tdp = dp->d_data + INT16SZ;
+ x = strncasecmp(td, (char *)tdp,
+ strlen((char *)td) + 1);
+ if (x != 0)
+ break;
+ return (1);
+
+ default:
+ dprintf(3, (ddt, "unknown type %d\n", type));
+ return (0);
+ }
+ /* continue in loop if record did not match */
+ }
+ /* saw no record of interest in whole chain
+ * If the data we were trying to validate was negative, we succeeded!
+ * else we failed
+ */
+ if ((data == NULL) || (dlen == 0)) {
+ /* negative data, report success */
+ return 1;
+ }
+ /* positive data, no such RR, validation failed */
+ return (0);
+}
+
+/******************************************************************
+ * get a list of databufs that have ns addresses for the closest domain
+ * you know about, get their addresses and confirm that server indeed
+ * is one of them. if yes return 1 else 0.
+ * first checks the cache that we build in nslookup() earlier
+ * when we ns_forw(). if unableto find it there, it checks the entire
+ * hash table to do address translations.
+ *******************************************************************/
+static int
+check_addr_ns(nsp, server, dname)
+ struct databuf **nsp;
+ struct sockaddr_in *server;
+ char *dname;
+{
+ int i, found=0;
+ char sname[MAXDNAME];
+ struct in_addr *saddr = &(server->sin_addr);
+ struct databuf **nsdp;
+
+ dprintf(5, (ddt,
+ "check_addr_ns: s:[%s], db:0x%x, d:\"%s\"\n",
+ inet_ntoa(*saddr), nsp, dname));
+
+ for(i = lastNA; i != firstNA; i = (i+1) % MAXNAMECACHE) {
+ if (!bcmp((char *)saddr,
+ (char *)&(nameaddrlist[i].ns_addr),
+ INADDRSZ)) {
+ strcpy(sname, nameaddrlist[i].nsname);
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ dprintf(3, (ddt,
+ "check_addr_ns: found address:[%s]\n",
+ inet_ntoa(*saddr)));
+ for (nsdp = nsp; *nsdp != NULL;nsdp++) {
+ dprintf(5, (ddt,
+ "check_addr_ns:names are:%s, %s\n",
+ sname,(*nsdp)->d_data));
+ if (!strcasecmp(sname,(char *)((*nsdp)->d_data))) {
+ return (1);
+ }
+ }
+ }
+ /* could not find name in my cache of servers, must go through the
+ * whole grind
+ */
+
+ dprintf(2, (ddt, "check_addr_ns:calling check_in_tables()\n"));
+ return (check_in_tables(nsp, server, dname));
+}
+
+/*************************************************************************
+ * checks in hash tables for the address of servers whose name is in the
+ * data section of nsp records. borrows code from nslookup()/ns_forw.c
+ * largely.
+ *************************************************************************/
+static int
+check_in_tables(nsp, server, syslogdname)
+ struct databuf *nsp[];
+ struct sockaddr_in *server;
+ char *syslogdname;
+{
+ register struct namebuf *np;
+ register struct databuf *dp, *nsdp;
+ struct hashbuf *tmphtp;
+ char *dname, *fname;
+ int class;
+ int qcomp();
+
+ dprintf(3, (ddt, "check_in_tables(nsp=x%x,qp=x%x,'%s')\n",
+ nsp, server, syslogdname));
+
+ while ((nsdp = *nsp++) != NULL) {
+ class = nsdp->d_class;
+ dname = (char *)nsdp->d_data;
+ dprintf(3, (ddt, "check_in_tables: NS %s c%d t%d (x%x)\n",
+ dname, class, nsdp->d_type, nsdp->d_flags));
+ tmphtp = ((nsdp->d_flags & DB_F_HINT) ? fcachetab : hashtab);
+ np = nlookup(dname, &tmphtp, &fname, 1);
+ if (np == NULL || fname != dname) {
+ dprintf(3, (ddt, "%s: not found %s %x\n",
+ dname, fname, np));
+ continue;
+ }
+ /* look for name server addresses */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (stale(dp))
+ continue;
+ if (dp->d_type != T_A || dp->d_class != class)
+ continue;
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ if (!bcmp((char *)dp->d_data,
+ (char *)&(server->sin_addr),
+ INADDRSZ)) {
+ return (1);
+ }
+ }
+ }
+ return (0); /* haven't been able to locate the right address */
+}
+
+/************************************************************************
+ * is called in nslookup() and stores the name vs address of a name server
+ * --& check_in_tables above--
+ * we contact, in a list of a maximum MAXNAMECACHE entries. we later refer
+ * -- NAMEADDR nameaddrlist[MAXNAMECACHE]; --
+ * to this list when we are trying to resolve the name in check_addr_ns().
+ *************************************************************************/
+void
+store_name_addr(servername, serveraddr, syslogdname, sysloginfo)
+ char *servername;
+ struct in_addr *serveraddr;
+ char *syslogdname;
+ char *sysloginfo;
+{
+ int i;
+
+ dprintf(3, (ddt,
+ "store_name_addr:s:%s, a:[%s]\n",
+ servername, inet_ntoa(*serveraddr)));
+
+ /* if we already have the name address pair in cache, return */
+ for (i = lastNA; i != firstNA; i = (i+1) % MAXNAMECACHE) {
+ if (strcasecmp(servername, nameaddrlist[i].nsname) == 0) {
+ if (serveraddr->s_addr
+ ==
+ nameaddrlist[i].ns_addr.s_addr) {
+ dprintf(5, (ddt,
+ "store_name_addr:found n and a [%s] [%s] in our $\n",
+ inet_ntoa(nameaddrlist[i].ns_addr),
+ inet_ntoa(*serveraddr)));
+ return;
+ } /* if */
+ } else if (serveraddr->s_addr
+ ==
+ nameaddrlist[i].ns_addr.s_addr) {
+#ifdef BAD_IDEA
+ /*
+ * log this as it needs to be fixed.
+ * replace old name by new, next query likely to have
+ * NS record matching new
+ */
+ if (!haveComplained(
+ (char*)dhash((u_char*)nameaddrlist[i].nsname,
+ strlen(nameaddrlist[i].nsname)),
+ (char*)dhash((u_char*)servername,
+ strlen(servername))
+ )
+ ) {
+ syslog(LOG_INFO,
+ "%s: server name mismatch for [%s]: (%s != %s) (server for %s)",
+ sysloginfo,
+ inet_ntoa(*serveraddr),
+ nameaddrlist[i].nsname, servername,
+ syslogdname);
+ }
+#endif
+ free(nameaddrlist[i].nsname);
+ nameaddrlist[i].nsname =
+ (char *)malloc((unsigned)strlen(servername)+1);
+ strcpy(nameaddrlist[i].nsname, servername);
+ return;
+ }
+ }
+ /* we have to add this one to our cache */
+
+ nameaddrlist[firstNA].nsname =
+ (char *)malloc((unsigned)strlen(servername)+1);
+ strcpy(nameaddrlist[firstNA].nsname, servername);
+ bcopy((char *)serveraddr,
+ (char *)&(nameaddrlist[firstNA].ns_addr),
+ INADDRSZ);
+
+ dprintf(2, (ddt, "store_name_addr:added entry #:%d n:%s a:[%s]\n",
+ firstNA, nameaddrlist[firstNA].nsname,
+ inet_ntoa(nameaddrlist[firstNA].ns_addr)));
+
+ firstNA = (firstNA+1) % MAXNAMECACHE;
+ if (firstNA == lastNA) {
+ free(nameaddrlist[firstNA].nsname);
+ nameaddrlist[firstNA].nsname = 0;
+ lastNA = (lastNA+1) % MAXNAMECACHE;
+ }
+ return;
+}
+
+/*
+ * Decode the resource record 'rrp' and validate the RR.
+ * Borrows code almost entirely from doupdate(). is a rather
+ * non-invasive routine since it just goes thru the same motions
+ * as doupdate but just marks the array validatelist entry as
+ * the return code from validate(). This is later used in doupdate
+ * to cache/not cache the entry. also used in update_msg() to
+ * delete/keep the record from the outgoing message.
+ */
+int
+dovalidate(msg, msglen, rrp, zone, flags, server, VCode)
+ u_char *msg, *rrp;
+ int msglen, zone, flags;
+ struct sockaddr_in *server;
+ int *VCode;
+{
+ register u_char *cp;
+ register int n;
+ int class, type, dlen, n1;
+ u_int32_t ttl;
+ char dname[MAXDNAME];
+ u_char *cp1;
+ u_char data[BUFSIZ];
+ register HEADER *hp = (HEADER *) msg;
+
+ dprintf(2, (ddt, "dovalidate(zone %d, flags %x)\n",
+ zone, flags));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(msg, ddt);
+#endif
+
+ cp = rrp;
+ n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ GETSHORT(dlen, cp);
+ dprintf(2, (ddt, "dovalidate: dname %s type %d class %d ttl %d\n",
+ dname, type, class, ttl));
+ /*
+ * 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:
+ case T_X25:
+ case T_ISDN:
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+#endif
+ 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:
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = data;
+ n = strlen((char *)data) + 1;
+ break;
+
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)data, sizeof data);
+ if (n < 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 * INT32SZ;
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += strlen((char *)cp1) + 1;
+ if (type == T_SOA) {
+ bcopy((char *)cp, (char *)cp1, n = 5 * INT32SZ);
+ cp += n;
+ cp1 += n;
+ }
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ /* grab preference */
+ bcopy((char *)cp, data, INT16SZ);
+ cp1 = data + INT16SZ;
+ cp += INT16SZ;
+
+ /* get name */
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)cp1, sizeof(data) - INT16SZ);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return(-1);
+ }
+ cp += n;
+
+ /* compute end of data */
+ cp1 += strlen((char *)cp1) + 1;
+ /* compute size of data */
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ default:
+ dprintf(3, (ddt, "unknown type %d\n", type));
+ return ((cp - rrp) + dlen);
+ }
+ if (n > MAXDATA) {
+ dprintf(2, (ddt,
+ "update type %d: %d bytes is too much data\n",
+ type, n));
+ hp->rcode = NOCHANGE; /* XXX - FORMERR ??? */
+ return(-1);
+ }
+
+ *VCode = validate(dname, server, type, class,(char *)cp1, n
+#ifdef NCACHE
+ ,NOERROR
+#endif
+ );
+ if (*VCode == INVALID) {
+ dprintf(2, (ddt,
+ "validation failed d:%s, t:%d, c:%d\n",
+ dname, type, class));
+ } else {
+ dprintf(2, (ddt,
+ "validation succeeded d:%s, t:%d, c:%d\n",
+ dname, type, class));
+ }
+ return(cp -rrp);
+}
+
+#if 0
+/******************************************************************
+ * This manages a data structure that stores all RRs that we were
+ * unable to validate. Am not sure exactly what purpose this might
+ * serve but until such time as we are sure it will not help, let
+ * me do it anyway.
+ *****************************************************************/
+static void
+stick_in_queue(dname, type, class, data)
+ char *dname;
+ int type;
+ int class;
+ char *data;
+{
+ struct timeval tp;
+ struct _TIMEZONE tzp;
+ TO_Validate *tempVQ;
+ u_long leasttime;
+
+ if (validateQ == NULL) {
+ validateQ = (TO_Validate *)malloc(sizeof(TO_Validate));
+ validateQ->type = type;
+ validateQ->class = class;
+ validateQ->dname = malloc((unsigned)strlen(dname)+1);
+ strcpy(validateQ->dname, dname);
+ validateQ->data = malloc((unsigned)strlen(data)+1);
+ strcpy(validateQ->data, data);
+ gettimeofday(&tp, &tzp);
+ validateQ->time = tp.tv_sec;
+ VQcount = 1;
+ validateQ->next = validateQ->prev = NULL;
+ currentVQ = validateQ;
+ return;
+ }
+ if (VQcount < MAXVQ) {
+ tempVQ =(TO_Validate *)malloc(sizeof(TO_Validate));
+ tempVQ->type = type;
+ tempVQ->class = class;
+ tempVQ->dname = malloc((unsigned)strlen(dname)+1);
+ strcpy(tempVQ->dname, dname);
+ tempVQ->data = malloc((unsigned)strlen(data)+1);
+ strcpy(tempVQ->data, data);
+ gettimeofday(&tp,&tzp);
+ tempVQ->time = tp.tv_sec;
+ tempVQ->next = currentVQ->next;
+ tempVQ->prev = currentVQ;
+ if (currentVQ->next != NULL)
+ currentVQ->next->prev = tempVQ;
+ currentVQ->next = tempVQ;
+ currentVQ = tempVQ;
+ VQcount++;
+ return;
+ }
+ gettimeofday(&tp, &tzp);
+ leasttime = validateQ->time;
+ currentVQ = validateQ;
+ for (tempVQ = validateQ; tempVQ != NULL; tempVQ = tempVQ->next) {
+ if (tp.tv_sec >= tempVQ->time +VQEXPIRY) {
+ tempVQ->type = type;
+ tempVQ->class = class;
+ strcpy(tempVQ->dname, dname);
+ strcpy(tempVQ->data, data);
+ tempVQ->time = tp.tv_sec;
+ currentVQ = tempVQ;
+ return;
+ }
+ if (tempVQ->time < leasttime) {
+ leasttime = tempVQ->time;
+ currentVQ = tempVQ;
+ }
+ }
+ currentVQ->type = type;
+ currentVQ->class = class;
+ strcpy(currentVQ->dname, dname);
+ strcpy(currentVQ->data, data);
+ currentVQ->time = tp.tv_sec;
+ return;
+}
+#endif
+
+/* removes any INVALID RR's from the msg being returned, updates msglen to
+ * reflect the new message length.
+ */
+int
+update_msg(msg, msglen, Vlist, c)
+ u_char *msg;
+ int *msglen;
+ int Vlist[];
+ int c;
+{
+ register HEADER *hp;
+ register u_char *cp;
+ int i;
+ int n = 0;
+ u_char *tempcp, *newcp;
+ int *RRlen;
+ int qlen; /* the length of the query section*/
+ u_int16_t rdlength;
+ u_int16_t ancount, nscount;
+ u_int16_t new_ancount, new_nscount, new_arcount;
+ char dname[MAXDNAME], qname[MAXDNAME];
+ u_char data[MAXDNAME];
+ u_char **dpp;
+ u_char *dnptrs[40];
+ u_char **edp = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
+ u_char *eom = msg + *msglen;
+ int n_new;
+ int rembuflen, newlen;
+ u_char *newmsg;
+ u_int16_t type, class, dlen;
+ u_int32_t ttl;
+ int inv = 0;
+
+#ifdef DEBUG
+ if (debug) {
+ fprintf(ddt, "update_msg: msglen:%d, c:%d\n", *msglen, c);
+ if (debug >= 10)
+ fp_query(msg, ddt);
+ }
+#endif
+ /* just making sure we do not do all the work for nothing */
+ for (i=0; i<c; i++) {
+ if (Vlist[i] == INVALID) {
+ inv = 1;
+ break;
+ }
+ }
+ if (inv != 1) {
+ /* no invalid records, go about your job */
+ return (0);
+ }
+
+ dprintf(2, (ddt, "update_msg: NEEDS updating:\n"));
+
+ RRlen = (int *)malloc((unsigned)c*sizeof(int));
+ hp = (HEADER *)msg;
+ new_ancount = ancount = ntohs(hp->ancount);
+ new_nscount = nscount = ntohs(hp->nscount);
+ new_arcount = ntohs(hp->arcount);
+
+ cp = msg + HFIXEDSZ;
+ newlen = HFIXEDSZ;
+ /* skip the query section */
+ qlen = dn_expand(msg, eom, cp, qname, sizeof qname);
+ if (qlen <= 0) {
+ dprintf(2, (ddt, "dn_skipname() failed, bad record\n"));
+ goto badend;
+ }
+ cp +=qlen;
+ GETSHORT(type,cp);
+ GETSHORT(class,cp);
+ qlen += 2 * INT16SZ;
+ newlen += qlen;
+
+ for (i = 0; i < c; i++) {
+ if (Vlist[i] == INVALID) {
+ if (i < ancount)
+ new_ancount--;
+ else if (i < ancount+nscount)
+ new_nscount--;
+ else
+ new_arcount--;
+ }
+
+ RRlen[i] = dn_skipname(cp, msg + *msglen);
+ if (RRlen[i] <= 0) {
+ dprintf(2, (ddt,
+ "dn_skipname() failed, bad record\n"));
+ goto badend;
+ }
+ RRlen[i] += 2 * INT16SZ + INT32SZ;
+ /*type+class+TTL*/
+ cp += RRlen[i];
+ GETSHORT(rdlength, cp);
+ RRlen[i] += INT16SZ; /*rdlength*/
+ RRlen[i] += rdlength; /*rdata field*/
+ dprintf(3, (ddt, "RRlen[%d]=%d\n", i, RRlen[i]));
+ if (Vlist[i] != INVALID)
+ newlen += RRlen[i];
+ cp += rdlength; /*increment pointer to next RR*/
+ }
+ hp->ancount = htons(new_ancount);
+ hp->nscount = htons(new_nscount);
+ hp->arcount = htons(new_arcount);
+ /* get new buffer */
+ dprintf(3, (ddt,
+ "newlen:%d, if no RR is INVALID == msglen\n", newlen));
+ newmsg = (u_char *)calloc(1,newlen + MAXDNAME);
+ if(newmsg == NULL)
+ goto badend;
+ dpp = dnptrs;
+ *dpp++ = newmsg;
+ *dpp = NULL;
+ /* bcopy the header, with all the length fields correctly put in */
+ bcopy((char *)msg, (char*)newmsg, HFIXEDSZ); /*header copied */
+ newcp = newmsg +HFIXEDSZ; /*need a pointer in the new buffer */
+ rembuflen = newlen +MAXDNAME - HFIXEDSZ; /*buflen we can workin*/
+ newlen = HFIXEDSZ; /* this will now contain the length of msg */
+ n_new = dn_comp(qname, newcp, rembuflen, dnptrs, edp);
+ if (n_new < 0)
+ goto badend;
+ newcp += n_new;
+ PUTSHORT(type, newcp);
+ PUTSHORT(class, newcp); /*query section complete*/
+ newlen += (n_new+2*INT16SZ);
+ rembuflen -= (n_new+2*INT16SZ);
+ /* have to decode and copy every Valid RR from here */
+
+ cp = msg +HFIXEDSZ +qlen; /*skip header and query section*/
+ for (i = 0; i < c; i++) {
+ if (Vlist[i] == INVALID) {
+ /* go to next RR if this one is not INVALID */
+ cp += RRlen[i];
+ continue;
+ }
+ /* we have a valid record, must put it in the newmsg */
+ n = dn_expand(msg, eom, cp, dname, sizeof dname);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ goto badend;
+ }
+ n_new = dn_comp(dname, newcp, rembuflen, dnptrs, edp);
+ if (n_new < 0)
+ goto badend;
+ cp += n;
+ newcp += n_new;
+ dprintf(5, (ddt,
+ "cp:0x%x newcp:0x%x after getting name\n",
+ cp, newcp));
+ GETSHORT(type, cp);
+ PUTSHORT(type, newcp);
+ dprintf(5, (ddt,
+ "cp:0x%x newcp:0x%x after getting type\n",
+ cp, newcp));
+ GETSHORT(class, cp);
+ PUTSHORT(class, newcp);
+ dprintf(5, (ddt,
+ "cp:0x%x newcp:0x%x after getting class\n",
+ cp, newcp));
+ GETLONG(ttl, cp);
+ PUTLONG(ttl, newcp);
+ dprintf(5, (ddt,
+ "cp:0x%x newcp:0x%x after getting ttl\n",
+ cp, newcp));
+ /* this will probably be modified for newmsg,
+ * will put this in later, after compression
+ */
+ GETSHORT(dlen, cp);
+ newlen += (n_new+3*INT16SZ + INT32SZ);
+ rembuflen -= (n_new+3*INT16SZ+ INT32SZ);
+ tempcp = newcp;
+ newcp += INT16SZ; /*advance to rdata field*/
+ dprintf(5, (ddt, "tempcp:0x%x newcp:0x%x\n",
+ tempcp, newcp));
+ dprintf(3, (ddt,
+ "update_msg: dname %s type %d class %d ttl %d\n",
+ dname, type, class, ttl));
+ /* read off the data section */
+ switch (type) {
+ case T_A:
+ case T_WKS:
+ case T_HINFO:
+ case T_UINFO:
+ case T_UID:
+ case T_GID:
+ case T_TXT:
+ case T_X25:
+ case T_ISDN:
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+#endif
+ n = dlen;
+ PUTSHORT(n, tempcp); /*time to put in the dlen*/
+ bcopy(cp, newcp,n); /*done here*/
+ cp +=n;
+ newcp +=n;
+ newlen += n;
+ rembuflen -= n;
+ dprintf(3, (ddt, "\tcp:0x%x newcp:0x%x dlen:%d\n",
+ cp, newcp, dlen));
+ break;
+
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_NS:
+ case T_PTR:
+ /*read off name from data section */
+ n = dn_expand(msg, eom, cp,
+ (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ goto badend;
+ }
+ cp += n; /*advance pointer*/
+ /* fill in new packet */
+ n_new = dn_comp((char *)data, newcp, rembuflen,
+ dnptrs, edp);
+ if (n_new < 0)
+ goto badend;
+ PUTSHORT(n_new,tempcp); /*put in dlen field*/
+ newcp += n_new; /*advance new pointer*/
+ newlen += n_new;
+ rembuflen -= n_new;
+ break;
+
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ goto badend;
+ }
+ cp += n;
+ n_new = dn_comp((char *)data, newcp, rembuflen,
+ dnptrs, edp);
+ if (n_new < 0)
+ goto badend;
+ newcp += n_new;
+ newlen += n_new;
+ rembuflen -= n_new;
+ dlen = n_new;
+ n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ goto badend;
+ }
+ cp += n;
+ n_new = dn_comp((char *)data, newcp, rembuflen,
+ dnptrs, edp);
+ if (n_new < 0)
+ goto badend;
+ newcp += n_new;
+ newlen += n_new;
+ rembuflen -= n_new;
+ dlen += n_new;
+ if (type == T_SOA) {
+ bcopy(cp, newcp, n = 5*INT32SZ);
+ cp += n;
+ newcp += n;
+ newlen +=n;
+ rembuflen -= n;
+ dlen +=n;
+ }
+ PUTSHORT(dlen, tempcp);
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ /* grab preference */
+ bcopy(cp,newcp,INT16SZ);
+ cp += INT16SZ;
+ newcp += INT16SZ;
+
+ /* get name */
+ n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ goto badend;
+ }
+ cp += n;
+ n_new = dn_comp((char *)data, newcp, rembuflen,
+ dnptrs, edp);
+ if (n_new < 0)
+ goto badend;
+ PUTSHORT(n_new+INT16SZ, tempcp);
+ newcp += n_new;
+ newlen += n_new+INT16SZ;
+ rembuflen -= n_new+INT16SZ;
+ break;
+
+ default:
+ dprintf(3, (ddt, "unknown type %d\n", type));
+ goto badend;
+ }
+ dprintf(2, (ddt,
+ "newlen:%d, i:%d newcp:0x%x cp:0x%x\n\n",
+ newlen, i, newcp, cp));
+ }
+ bcopy(newmsg, msg, newlen);
+ n = *msglen - newlen;
+ if (n < 0) {
+ dprintf(2, (ddt,
+ "update_msg():newmsg longer than old: n:%d o:%d ???\n",
+ newlen, *msglen));
+ }
+ *msglen = newlen;
+ free((char *)newmsg);
+
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(msg, ddt);
+#endif
+ free((char *)RRlen);
+ return(n);
+badend:
+ dprintf(2, (ddt, "encountered problems: UPDATE_MSG\n"));
+ free((char *)RRlen);
+ return(-1);
+}
+
+#endif /*VALIDATE*/
diff --git a/usr.sbin/named/pathnames.h b/usr.sbin/named/pathnames.h
new file mode 100644
index 0000000..bcbe642
--- /dev/null
+++ b/usr.sbin/named/pathnames.h
@@ -0,0 +1,122 @@
+/*
+ * @(#)pathnames.h 5.4 (Berkeley) 6/1/90
+ * $Id: pathnames.h,v 4.9.1.5 1994/04/09 03:43:17 vixie Exp $
+ */
+
+/*
+ * ++Copyright++ 1989
+ * -
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#ifdef _PATH_XFER
+# define _PATH_XFER_PREDEFINED /* probably from Makefile */
+#endif
+
+#if defined (__sgi) && !defined(_SYSTYPE_SVR4) && !defined(__SYSTYPE_SVR4)
+#define _PATH_BOOT "/usr/etc/named.d/named.boot"
+#else
+#define _PATH_BOOT "/etc/named.boot"
+#endif
+
+#if defined(BSD) && BSD >= 198810
+
+#include <paths.h>
+#ifndef _PATH_XFER
+# define _PATH_XFER "/usr/libexec/named-xfer"
+#endif
+#define _PATH_DEBUG "/var/tmp/named.run"
+#define _PATH_DUMPFILE "/var/tmp/named_dump.db"
+#ifndef _PATH_PIDFILE
+# define _PATH_PIDFILE "/var/run/named.pid"
+#endif
+#define _PATH_STATS "/var/tmp/named.stats"
+#define _PATH_XFERTRACE "/var/tmp/xfer.trace"
+#define _PATH_XFERDDT "/var/tmp/xfer.ddt"
+#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"
+#ifndef _PATH_XFER
+# define _PATH_XFER "/etc/named-xfer"
+#endif
+#define _PATH_DEBUG "/usr/tmp/named.run"
+#define _PATH_DUMPFILE "/usr/tmp/named_dump.db"
+#ifndef _PATH_PIDFILE
+# define _PATH_PIDFILE "/etc/named.pid"
+#endif
+#define _PATH_STATS "/usr/tmp/named.stats"
+#define _PATH_XFERTRACE "/usr/tmp/xfer.trace"
+#define _PATH_XFERDDT "/usr/tmp/xfer.ddt"
+#define _PATH_TMPXFER "/usr/tmp/xfer.ddt.XXXXXX"
+#define _PATH_TMPDIR "/usr/tmp"
+#endif /* BSD */
+
+#ifndef _PATH_XFER_PREDEFINED
+# if defined(__sgi) || defined(NeXT) || defined(__ultrix)
+# undef _PATH_XFER
+# define _PATH_XFER "/usr/etc/named-xfer"
+# endif
+# if defined(__osf__)
+# undef _PATH_XFER
+# define _PATH_XFER "/usr/sbin/named-xfer"
+# endif
+# ifdef sun
+# undef _PATH_XFER
+# define _PATH_XFER "/usr/etc/in.named-xfer"
+# endif
+#else
+# undef _PATH_XFER_PREDEFINED
+#endif /*_PATH_XFER_PREDEFINED*/
diff --git a/usr.sbin/named/storage.c b/usr.sbin/named/storage.c
new file mode 100644
index 0000000..98a71b3
--- /dev/null
+++ b/usr.sbin/named/storage.c
@@ -0,0 +1,207 @@
+/*
+ * ++Copyright++ 1985, 1989
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/param.h>
+#include <syslog.h>
+#include "../conf/portability.h"
+#include "../conf/options.h"
+
+#ifdef DSTORAGE
+/*
+ * S T O R A G E . C
+ *
+ * Ray Tracing program, storage manager.
+ *
+ * Functions -
+ * rt_malloc Allocate storage, with visibility & checking
+ * rt_free Similarly, free storage
+ * rt_prmem When debugging, print memory map
+ * calloc, cfree Which call rt_malloc, rt_free
+ *
+ * Author -
+ * Michael John Muuss
+ *
+ * Source -
+ * SECAD/VLD Computing Consortium, Bldg 394
+ * The U. S. Army Ballistic Research Laboratory
+ * Aberdeen Proving Ground, Maryland 21005-5066
+ *
+ * Copyright Notice -
+ * This software is Copyright (C) 1987 by the United States Army.
+ * All rights reserved.
+ */
+#ifndef lint
+static char RCSid[] = "$Id: storage.c,v 4.9.1.2 1993/09/08 00:01:17 vixie Exp $";
+#endif
+
+#undef malloc
+#undef free
+
+#define MDB_SIZE 20000
+#define MDB_MAGIC 0x12348969
+struct memdebug {
+ char *mdb_addr;
+ char *mdb_str;
+ int mdb_len;
+} rt_mdb[MDB_SIZE];
+
+/*
+ * R T _ M A L L O C
+ */
+char *
+rt_malloc(cnt)
+unsigned int cnt;
+{
+ register char *ptr;
+
+ cnt = (cnt+2*sizeof(int)-1)&(~(sizeof(int)-1));
+ ptr = malloc(cnt);
+
+ if( ptr==(char *)0 ) {
+ syslog(LOG_ERR, "rt_malloc: malloc failure");
+ abort();
+ } else {
+ register struct memdebug *mp = rt_mdb;
+ for( ; mp < &rt_mdb[MDB_SIZE]; mp++ ) {
+ if( mp->mdb_len > 0 ) continue;
+ mp->mdb_addr = ptr;
+ mp->mdb_len = cnt;
+ mp->mdb_str = "???";
+ goto ok;
+ }
+ syslog(LOG_ERR, "rt_malloc: memdebug overflow\n");
+ }
+ok: ;
+ {
+ register int *ip = (int *)(ptr+cnt-sizeof(int));
+ *ip = MDB_MAGIC;
+ }
+ return(ptr);
+}
+
+/*
+ * R T _ F R E E
+ */
+void
+rt_free(ptr)
+char *ptr;
+{
+ register struct memdebug *mp = rt_mdb;
+ for( ; mp < &rt_mdb[MDB_SIZE]; mp++ ) {
+ if( mp->mdb_len <= 0 ) continue;
+ if( mp->mdb_addr != ptr ) continue;
+ {
+ register int *ip = (int *)(ptr+mp->mdb_len-sizeof(int));
+ if( *ip != MDB_MAGIC ) {
+ syslog(LOG_ERR, "ERROR rt_free(x%x, %s) corrupted! x%x!=x%x\n", ptr, "???", *ip, MDB_MAGIC);
+ abort();
+ }
+ }
+ mp->mdb_len = 0; /* successful free */
+ goto ok;
+ }
+ syslog(LOG_ERR, "ERROR rt_free(x%x, %s) bad pointer!\n", ptr, "???");
+ abort();
+ok: ;
+
+ *((int *)ptr) = -1; /* zappo! */
+ free(ptr);
+}
+
+/*
+ * R T _ P R M E M
+ *
+ * Print map of memory currently in use.
+ */
+void
+rt_prmem(str)
+char *str;
+{
+ register struct memdebug *mp = rt_mdb;
+ register int *ip;
+
+ printf("\nRT memory use\t\t%s\n", str);
+ for( ; mp < &rt_mdb[MDB_SIZE]; mp++ ) {
+ if( mp->mdb_len <= 0 ) continue;
+ ip = (int *)(mp->mdb_addr+mp->mdb_len-sizeof(int));
+ printf("%7x %5x %s %s\n",
+ mp->mdb_addr, mp->mdb_len, mp->mdb_str,
+ *ip!=MDB_MAGIC ? "-BAD-" : "" );
+ if( *ip != MDB_MAGIC )
+ printf("\t%x\t%x\n", *ip, MDB_MAGIC);
+ }
+}
+
+char *
+calloc(num, size)
+ register unsigned num, size;
+{
+ register char *p;
+
+ size *= num;
+ if (p = rt_malloc(size))
+ bzero(p, size);
+ return (p);
+}
+
+cfree(p, num, size)
+ char *p;
+ unsigned num;
+ unsigned size;
+{
+ rt_free(p);
+}
+
+#endif /*DSTORAGE*/
diff --git a/usr.sbin/named/tools/named.reload/named.reload.sh b/usr.sbin/named/tools/named.reload/named.reload.sh
new file mode 100644
index 0000000..a25de1b
--- /dev/null
+++ b/usr.sbin/named/tools/named.reload/named.reload.sh
@@ -0,0 +1,6 @@
+#!/bin/sh -
+#
+# from named.reload 5.2 (Berkeley) 6/27/89
+# $Id: named.reload.sh,v 4.9.1.2 1993/09/08 00:01:17 vixie Exp $
+#
+kill -HUP `cat %PIDDIR%/named.pid`
diff --git a/usr.sbin/named/tools/named.restart/named.restart.sh b/usr.sbin/named/tools/named.restart/named.restart.sh
new file mode 100644
index 0000000..8a61ccca
--- /dev/null
+++ b/usr.sbin/named/tools/named.restart/named.restart.sh
@@ -0,0 +1,12 @@
+#!/bin/sh -
+#
+# from named.restart 5.4 (Berkeley) 6/27/89
+# $Id: named.restart.sh,v 4.9.1.5 1994/04/09 03:43:17 vixie Exp $
+#
+
+PATH=%DESTSBIN%:/bin:/usr/bin
+
+pid=`cat %PIDDIR%/named.pid`
+kill $pid
+sleep 5
+exec %INDOT%named
diff --git a/usr.sbin/named/tools/nsquery/nsquery.c b/usr.sbin/named/tools/nsquery/nsquery.c
new file mode 100644
index 0000000..c7ff6eb
--- /dev/null
+++ b/usr.sbin/named/tools/nsquery/nsquery.c
@@ -0,0 +1,140 @@
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1986 Regents of the University of California.\n\
+ portions Copyright (c) 1993 Digital Equipment Corporation\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)nsquery.c 4.8 (Berkeley) 6/1/90";
+static char rcsid[] = "$Id: nsquery.c,v 4.9.1.4 1994/06/11 22:05:07 vixie Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <resolv.h>
+#include "../conf/portability.h"
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern struct __res_state _res;
+ register struct hostent *hp;
+ register char *s;
+
+ res_init();
+
+ if (argc >= 2 && strcmp(argv[1], "-d") == 0) {
+ _res.options |= RES_DEBUG;
+ argc--;
+ argv++;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "usage: nsquery [-d] host [server]\n");
+ exit(1);
+ }
+ if (argc == 3) {
+ hp = gethostbyname(argv[2]);
+ if (hp == NULL) {
+ fprintf(stderr, "nsquery:");
+ herror(argv[2]);
+ exit(1);
+ }
+ printf("\nServer:\n");
+ printanswer(hp);
+ _res.nsaddr.sin_addr = *(struct in_addr *)hp->h_addr;
+#ifdef nsaddr /* struct __res_state includes nscount and nsaddr_list[] */
+ _res.nscount = 1;
+#endif
+ }
+
+ hp = gethostbyname(argv[1]);
+ if (hp == NULL) {
+ fprintf(stderr, "nsquery: %s: ", argv[1]);
+ herror((char *)NULL);
+ exit(1);
+ }
+ printanswer(hp);
+ exit(0);
+}
+
+printanswer(hp)
+ register struct hostent *hp;
+{
+ register char **cp;
+
+ printf("Name: %s\n", hp->h_name);
+#if BSD >= 43 || defined(h_addr)
+ printf("Addresses:");
+ for (cp = hp->h_addr_list; cp && *cp; cp++)
+ printf(" %s", inet_ntoa(*(struct in_addr *)(*cp)));
+ printf("\n");
+#else
+ printf("Address: %s\n", inet_ntoa(*(struct in_addr *)hp->h_addr));
+#endif
+ printf("Aliases:");
+ for (cp = hp->h_aliases; cp && *cp && **cp; cp++)
+ printf(" %s", *cp);
+ printf("\n\n");
+}
diff --git a/usr.sbin/named/tools/nstest/nstest.c b/usr.sbin/named/tools/nstest/nstest.c
new file mode 100644
index 0000000..f20388d
--- /dev/null
+++ b/usr.sbin/named/tools/nstest/nstest.c
@@ -0,0 +1,424 @@
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1986 Regents of the University of California.\n\
+ portions Copyright (c) 1993 Digital Equipment Corporation\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)nstest.c 4.15 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: nstest.c,v 4.9.1.6 1994/06/01 21:10:11 vixie Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <resolv.h>
+#include "../conf/portability.h"
+
+char *progname;
+FILE *log;
+#define MAXDATA 256 /* really should get this from named/db.h */
+main(argc, argv)
+ char **argv;
+{
+ register char *cp;
+ register u_char *ucp;
+ struct hostent *hp;
+ u_short port = htons(NAMESERVER_PORT);
+ char buf[BUFSIZ];
+ u_char packet[PACKETSZ], answer[8*1024], OldRRData[MAXDATA];
+ struct rrec NewRR;
+ u_int32_t l;
+ int n, dump_packet;
+
+ NewRR.r_data = (char *) malloc(MAXDATA);
+ NewRR.r_data = (char *) malloc(MAXDATA);
+ progname = argv[0];
+ dump_packet = 0;
+ _res.options |= RES_DEBUG|RES_RECURSE;
+ (void) res_init();
+ while (argc > 1 && argv[1][0] == '-') {
+ argc--;
+ cp = *++argv;
+ while (*++cp)
+ switch (*cp) {
+ case 'p':
+ if (--argc <= 0)
+ usage();
+ port = htons(atoi(*++argv));
+ break;
+
+ case 'i':
+ _res.options |= RES_IGNTC;
+ break;
+
+ case 'v':
+ _res.options |= RES_USEVC|RES_STAYOPEN;
+ break;
+
+ case 'r':
+ _res.options &= ~RES_RECURSE;
+ break;
+
+ case 'd':
+ dump_packet++;
+ break;
+
+ default:
+ usage();
+ }
+ }
+ _res.nsaddr.sin_family = AF_INET;
+ _res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
+ _res.nsaddr.sin_port = port;
+ if (argc > 1) {
+ if (!inet_aton(argv[1],
+ (struct in_addr *)&_res.nsaddr.sin_addr))
+ usage();
+ }
+ if (argc > 2) {
+ log = fopen(argv[2],"w");
+ if (log == NULL) perror(argv[2]);
+ }
+ for (;;) {
+ printf("> ");
+ fflush(stdout);
+ if ((cp = fgets(buf, sizeof buf, stdin)) == NULL)
+ break;
+ switch (*cp++) {
+ case 'a':
+ n = res_mkquery(QUERY, cp, C_IN, T_A, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'A':
+ n = ntohl(inet_addr(cp));
+ putlong((u_int32_t)n, (u_char*)cp);
+ n = res_mkquery(IQUERY, "", C_IN, T_A, (u_char *)cp,
+ INT32SZ, NULL,
+ packet, sizeof(packet));
+ break;
+
+ case 'f':
+ n = res_mkquery(QUERY, cp, C_ANY, T_UINFO, NULL,
+ 0, NULL, packet, sizeof packet);
+ break;
+
+ case 'F':
+ n = res_mkquery(QUERY, cp, C_IN, T_AFSDB, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'g':
+ n = res_mkquery(QUERY, cp, C_ANY, T_GID, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'G':
+ *(int *)cp = htonl(atoi(cp));
+ n = res_mkquery(IQUERY, "", C_ANY, T_GID, (u_char *)cp,
+ sizeof(int), NULL, packet, sizeof packet);
+ break;
+
+ case 'c':
+ n = res_mkquery(QUERY, cp, C_IN, T_CNAME, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'h':
+ n = res_mkquery(QUERY, cp, C_IN, T_HINFO, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'm':
+ n = res_mkquery(QUERY, cp, C_IN, T_MX, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'M':
+ n = res_mkquery(QUERY, cp, C_IN, T_MAILB, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'n':
+ n = res_mkquery(QUERY, cp, C_IN, T_NS, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'p':
+ n = res_mkquery(QUERY, cp, C_IN, T_PTR, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 's':
+ n = res_mkquery(QUERY, cp, C_IN, T_SOA, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'T':
+ n = res_mkquery(QUERY, cp, C_IN, T_TXT, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'u':
+ n = res_mkquery(QUERY, cp, C_ANY, T_UID, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'U':
+ *(int *)cp = htonl(atoi(cp));
+ n = res_mkquery(IQUERY, "", C_ANY, T_UID, (u_char *)cp,
+ sizeof(int), NULL,
+ packet, sizeof packet);
+ break;
+
+ case 'x':
+ n = res_mkquery(QUERY, cp, C_IN, T_AXFR, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'w':
+ n = res_mkquery(QUERY, cp, C_IN, T_WKS, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'b':
+ n = res_mkquery(QUERY, cp, C_IN, T_MB, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'B':
+ n = res_mkquery(QUERY, cp, C_IN, T_MG, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'i':
+ n = res_mkquery(QUERY, cp, C_IN, T_MINFO, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'r':
+ n = res_mkquery(QUERY, cp, C_IN, T_MR, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case '*':
+ n = res_mkquery(QUERY, cp, C_IN, T_ANY, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+#ifdef ALLOW_UPDATES
+ case '^':
+ {
+ char IType[10], TempStr[50];
+ int Type, oldnbytes, nbytes, i;
+#ifdef ALLOW_T_UNSPEC
+ printf("Data type (a = T_A, u = T_UNSPEC): ");
+ gets(IType);
+ if (IType[0] == 'u') {
+ Type = T_UNSPEC;
+ printf("How many data bytes? ");
+ gets(TempStr); /* Throw away CR */
+ sscanf(TempStr, "%d", &nbytes);
+ for (i = 0; i < nbytes; i++) {
+ (NewRR.r_data)[i] = (char) i;
+ }
+ } else {
+#endif /* ALLOW_T_UNSPEC */
+ Type = T_A;
+ nbytes = INT32SZ;
+ printf(
+ "Inet addr for new dname (e.g., 192.4.3.2): "
+ );
+ gets(TempStr);
+ putlong(ntohl(inet_addr(TempStr)),
+ NewRR.r_data);
+#ifdef ALLOW_T_UNSPEC
+ }
+#endif
+ NewRR.r_class = C_IN;
+ NewRR.r_type = Type;
+ NewRR.r_size = nbytes;
+ NewRR.r_ttl = 99999999;
+ printf("Add, modify, or modify all (a/m/M)? ");
+ gets(TempStr);
+ if (TempStr[0] == 'a') {
+ n = res_mkquery(UPDATEA, cp, C_IN, Type,
+ OldRRData, nbytes,
+ &NewRR, packet,
+ sizeof packet);
+ } else {
+ if (TempStr[0] == 'm') {
+ printf("How many data bytes in old RR? ");
+ gets(TempStr); /* Throw away CR */
+ sscanf(TempStr, "%d", &oldnbytes);
+ for (i = 0; i < oldnbytes; i++) {
+ OldRRData[i] = (char) i;
+ }
+ n = res_mkquery(UPDATEM, cp,
+ C_IN, Type,
+ OldRRData, oldnbytes,
+ &NewRR, packet,
+ sizeof packet);
+ } else { /* Modify all */
+ n = res_mkquery(UPDATEMA, cp,
+ C_IN, Type, NULL, 0,
+ &NewRR, packet,
+ sizeof packet);
+
+ }
+ }
+ }
+ break;
+
+#ifdef ALLOW_T_UNSPEC
+ case 'D':
+ n = res_mkquery(UPDATEDA, cp, C_IN, T_UNSPEC,
+ (char *)0, 0, NULL,
+ packet, sizeof packet);
+ break;
+
+ case 'd':
+ {
+ char TempStr[100];
+ int nbytes, i;
+ printf("How many data bytes in oldrr data? ");
+ gets(TempStr); /* Throw away CR */
+ sscanf(TempStr, "%d", &nbytes);
+ for (i = 0; i < nbytes; i++) {
+ OldRRData[i] = (char) i;
+ }
+ n = res_mkquery(UPDATED, cp, C_IN, T_UNSPEC,
+ OldRRData, nbytes, NULL,
+ packet, sizeof packet);
+ }
+ break;
+#endif /* ALLOW_T_UNSPEC */
+#endif /* ALLOW_UPDATES */
+
+ default:
+ printf("a{host} - query T_A\n");
+ printf("A{addr} - iquery T_A\n");
+ printf("b{user} - query T_MB\n");
+ printf("B{user} - query T_MG\n");
+ printf("f{host} - query T_UINFO\n");
+ printf("g{host} - query T_GID\n");
+ printf("G{gid} - iquery T_GID\n");
+ printf("h{host} - query T_HINFO\n");
+ printf("i{host} - query T_MINFO\n");
+ printf("p{host} - query T_PTR\n");
+ printf("m{host} - query T_MX\n");
+ printf("M{host} - query T_MAILB\n");
+ printf("n{host} - query T_NS\n");
+ printf("r{host} - query T_MR\n");
+ printf("s{host} - query T_SOA\n");
+ printf("T{host} - query T_TXT\n");
+ printf("u{host} - query T_UID\n");
+ printf("U{uid} - iquery T_UID\n");
+ printf("x{host} - query T_AXFR\n");
+ printf("w{host} - query T_WKS\n");
+ printf("F{host} - query T_AFSDB\n");
+ printf("c{host} - query T_CNAME\n");
+ printf("*{host} - query T_ANY\n");
+#ifdef ALLOW_UPDATES
+ printf("^{host} - add/mod/moda (T_A/T_UNSPEC)\n");
+#ifdef ALLOW_T_UNSPEC
+ printf("D{host} - deletea T_UNSPEC\n");
+ printf("d{host} - delete T_UNSPEC\n");
+#endif /* ALLOW_T_UNSPEC */
+#endif /* ALLOW_UPDATES */
+ continue;
+ }
+ if (n < 0) {
+ printf("res_mkquery: buffer too small\n");
+ continue;
+ }
+ if (log) {
+ fprintf(log,"SEND QUERY\n");
+ fp_query(packet, log);
+ }
+ n = res_send(packet, n, answer, sizeof(answer));
+ if (n < 0) {
+ printf("res_send: send error\n");
+ if (log) fprintf(log, "res_send: send error\n");
+ }
+ else {
+ if (dump_packet) {
+ int f;
+ f = creat("ns_packet.dump", 0644);
+ write(f, answer, n);
+ (void) close(f);
+ }
+ if (log) {
+ fprintf(log, "GOT ANSWER\n");
+ fp_query(answer, log);
+ }
+ }
+ }
+}
+
+usage()
+{
+ fprintf(stderr, "Usage: %s [-v] [-i] [-r] [-d] [-p port] hostaddr\n",
+ progname);
+ exit(1);
+}
diff --git a/usr.sbin/named/tree.c b/usr.sbin/named/tree.c
new file mode 100644
index 0000000..58607ea
--- /dev/null
+++ b/usr.sbin/named/tree.c
@@ -0,0 +1,570 @@
+/* tree - balanced binary tree library
+ *
+ * vix 05apr94 [removed vixie.h dependencies; cleaned up formatting, names]
+ * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
+ * vix 23jun86 [added delete uar to add for replaced nodes]
+ * vix 20jun86 [added tree_delete per wirth a+ds (mod2 v.) p. 224]
+ * vix 06feb86 [added tree_mung()]
+ * vix 02feb86 [added tree balancing from wirth "a+ds=p" p. 220-221]
+ * vix 14dec85 [written]
+ */
+
+
+/* This program text was created by Paul Vixie using examples from the book:
+ * "Algorithms & Data Structures," Niklaus Wirth, Prentice-Hall, 1986, ISBN
+ * 0-13-022005-1. Any errors in the conversion from Modula-2 to C are Paul
+ * Vixie's.
+ *
+ * This code and associated documentation is hereby placed in the public
+ * domain, with the wish that my name and Prof. Wirth's not be removed
+ * from the source or documentation.
+ */
+
+
+#ifndef LINT
+static char RCSid[] = "$Id:";
+#endif
+
+
+/*#define DEBUG "tree"*/
+
+
+#include <stdio.h>
+#ifndef _PATH_XFER
+# include <stdlib.h>
+#else
+# include "../conf/portability.h"
+#endif
+#include "tree.h"
+
+
+#ifdef DEBUG
+static int debugDepth = 0;
+static char *debugFuncs[256];
+# define ENTER(proc) { \
+ debugFuncs[debugDepth] = proc; \
+ fprintf(stderr, "ENTER(%d:%s.%s)\n", \
+ debugDepth, DEBUG,
+ debugFuncs[debugDepth]); \
+ debugDepth++; \
+ }
+# define RET(value) { \
+ debugDepth--; \
+ fprintf(stderr, "RET(%d:%s.%s)\n", \
+ debugDepth, DEBUG, \
+ debugFuncs[debugDepth]); \
+ return (value); \
+ }
+# define RETV { \
+ debugDepth--; \
+ fprintf(stderr, "RETV(%d:%s.%s)\n", \
+ debugDepth, DEBUG, \
+ debugFuncs[debugDepth]); \
+ return; \
+ }
+# define MSG(msg) fprintf(stderr, "MSG(%s)\n", msg);
+#else
+# define ENTER(proc) ;
+# define RET(value) return (value);
+# define RETV return;
+# define MSG(msg) ;
+#endif
+
+
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif
+
+
+static tree * sprout __P( (tree **, tree_t, int *, int (*)(), void (*)()) );
+static int delete __P( (tree **, int (*)(), tree_t, void (*)(),
+ int *, int *) );
+static void del __P( (tree **, int *, tree **, void (*)(), int *) );
+static void bal_L __P( (tree **, int *) );
+static void bal_R __P( (tree **, int *) );
+
+
+void
+tree_init(ppr_tree)
+ tree **ppr_tree;
+{
+ ENTER("tree_init")
+ *ppr_tree = NULL;
+ RETV
+}
+
+
+tree_t
+tree_srch(ppr_tree, pfi_compare, p_user)
+ tree **ppr_tree;
+ int (*pfi_compare)();
+ tree_t p_user;
+{
+ register int i_comp;
+
+ ENTER("tree_srch")
+
+ if (*ppr_tree) {
+ i_comp = (*pfi_compare)(p_user, (**ppr_tree).data);
+
+ if (i_comp > 0)
+ RET(tree_srch(&(**ppr_tree).right,
+ pfi_compare,
+ p_user))
+
+ if (i_comp < 0)
+ RET(tree_srch(&(**ppr_tree).left,
+ pfi_compare,
+ p_user))
+
+ /* not higher, not lower... this must be the one.
+ */
+ RET((**ppr_tree).data)
+ }
+
+ /* grounded. NOT found.
+ */
+ RET(NULL)
+}
+
+
+tree_t
+tree_add(ppr_tree, pfi_compare, p_user, pfv_uar)
+ tree **ppr_tree;
+ int (*pfi_compare)();
+ tree_t p_user;
+ void (*pfv_uar)();
+{
+ int i_balance = FALSE;
+
+ ENTER("tree_add")
+ if (!sprout(ppr_tree, p_user, &i_balance, pfi_compare, pfv_uar))
+ RET(NULL)
+ RET(p_user)
+}
+
+
+int
+tree_delete(ppr_p, pfi_compare, p_user, pfv_uar)
+ tree **ppr_p;
+ int (*pfi_compare)();
+ tree_t p_user;
+ void (*pfv_uar)();
+{
+ int i_balance = FALSE,
+ i_uar_called = FALSE;
+
+ ENTER("tree_delete");
+ RET(delete(ppr_p, pfi_compare, p_user, pfv_uar,
+ &i_balance, &i_uar_called))
+}
+
+
+int
+tree_trav(ppr_tree, pfi_uar)
+ tree **ppr_tree;
+ int (*pfi_uar)();
+{
+ ENTER("tree_trav")
+
+ if (!*ppr_tree)
+ RET(TRUE)
+
+ if (!tree_trav(&(**ppr_tree).left, pfi_uar))
+ RET(FALSE)
+ if (!(*pfi_uar)((**ppr_tree).data))
+ RET(FALSE)
+ if (!tree_trav(&(**ppr_tree).right, pfi_uar))
+ RET(FALSE)
+ RET(TRUE)
+}
+
+
+void
+tree_mung(ppr_tree, pfv_uar)
+ tree **ppr_tree;
+ void (*pfv_uar)();
+{
+ ENTER("tree_mung")
+ if (*ppr_tree) {
+ tree_mung(&(**ppr_tree).left, pfv_uar);
+ tree_mung(&(**ppr_tree).right, pfv_uar);
+ if (pfv_uar)
+ (*pfv_uar)((**ppr_tree).data);
+ free(*ppr_tree);
+ *ppr_tree = NULL;
+ }
+ RETV
+}
+
+
+static tree *
+sprout(ppr, p_data, pi_balance, pfi_compare, pfv_delete)
+ tree **ppr;
+ tree_t p_data;
+ int *pi_balance;
+ int (*pfi_compare)();
+ void (*pfv_delete)();
+{
+ tree *p1, *p2, *sub;
+ int cmp;
+
+ ENTER("sprout")
+
+ /* are we grounded? if so, add the node "here" and set the rebalance
+ * flag, then exit.
+ */
+ if (!*ppr) {
+ MSG("grounded. adding new node, setting h=true")
+ *ppr = (tree *) malloc(sizeof(tree));
+ if (*ppr) {
+ (*ppr)->left = NULL;
+ (*ppr)->right = NULL;
+ (*ppr)->bal = 0;
+ (*ppr)->data = p_data;
+ *pi_balance = TRUE;
+ }
+ RET(*ppr);
+ }
+
+ /* compare the data using routine passed by caller.
+ */
+ cmp = (*pfi_compare)(p_data, (*ppr)->data);
+
+ /* if LESS, prepare to move to the left.
+ */
+ if (cmp < 0) {
+ MSG("LESS. sprouting left.")
+ sub = sprout(&(*ppr)->left, p_data, pi_balance,
+ pfi_compare, pfv_delete);
+ if (sub && *pi_balance) { /* left branch has grown */
+ MSG("LESS: left branch has grown")
+ switch ((*ppr)->bal) {
+ case 1: /* right branch WAS longer; bal is ok now */
+ MSG("LESS: case 1.. bal restored implicitly")
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ break;
+ case 0: /* balance WAS okay; now left branch longer */
+ MSG("LESS: case 0.. balnce bad but still ok")
+ (*ppr)->bal = -1;
+ break;
+ case -1: /* left branch was already too long. rebal */
+ MSG("LESS: case -1: rebalancing")
+ p1 = (*ppr)->left;
+ if (p1->bal == -1) { /* LL */
+ MSG("LESS: single LL")
+ (*ppr)->left = p1->right;
+ p1->right = *ppr;
+ (*ppr)->bal = 0;
+ *ppr = p1;
+ } else { /* double LR */
+ MSG("LESS: double LR")
+
+ p2 = p1->right;
+ p1->right = p2->left;
+ p2->left = p1;
+
+ (*ppr)->left = p2->right;
+ p2->right = *ppr;
+
+ if (p2->bal == -1)
+ (*ppr)->bal = 1;
+ else
+ (*ppr)->bal = 0;
+
+ if (p2->bal == 1)
+ p1->bal = -1;
+ else
+ p1->bal = 0;
+ *ppr = p2;
+ } /*else*/
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ } /*switch*/
+ } /*if*/
+ RET(sub)
+ } /*if*/
+
+ /* if MORE, prepare to move to the right.
+ */
+ if (cmp > 0) {
+ MSG("MORE: sprouting to the right")
+ sub = sprout(&(*ppr)->right, p_data, pi_balance,
+ pfi_compare, pfv_delete);
+ if (sub && *pi_balance) {
+ MSG("MORE: right branch has grown")
+
+ switch ((*ppr)->bal) {
+ case -1:
+ MSG("MORE: balance was off, fixed implicitly")
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ break;
+ case 0:
+ MSG("MORE: balance was okay, now off but ok")
+ (*ppr)->bal = 1;
+ break;
+ case 1:
+ MSG("MORE: balance was off, need to rebalance")
+ p1 = (*ppr)->right;
+ if (p1->bal == 1) { /* RR */
+ MSG("MORE: single RR")
+ (*ppr)->right = p1->left;
+ p1->left = *ppr;
+ (*ppr)->bal = 0;
+ *ppr = p1;
+ } else { /* double RL */
+ MSG("MORE: double RL")
+
+ p2 = p1->left;
+ p1->left = p2->right;
+ p2->right = p1;
+
+ (*ppr)->right = p2->left;
+ p2->left = *ppr;
+
+ if (p2->bal == 1)
+ (*ppr)->bal = -1;
+ else
+ (*ppr)->bal = 0;
+
+ if (p2->bal == -1)
+ p1->bal = 1;
+ else
+ p1->bal = 0;
+
+ *ppr = p2;
+ } /*else*/
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ } /*switch*/
+ } /*if*/
+ RET(sub)
+ } /*if*/
+
+ /* not less, not more: this is the same key! replace...
+ */
+ MSG("FOUND: Replacing data value")
+ *pi_balance = FALSE;
+ if (pfv_delete)
+ (*pfv_delete)((*ppr)->data);
+ (*ppr)->data = p_data;
+ RET(*ppr)
+}
+
+
+static int
+delete(ppr_p, pfi_compare, p_user, pfv_uar, pi_balance, pi_uar_called)
+ tree **ppr_p;
+ int (*pfi_compare)();
+ tree_t p_user;
+ void (*pfv_uar)();
+ int *pi_balance;
+ int *pi_uar_called;
+{
+ tree *pr_q;
+ int i_comp, i_ret;
+
+ ENTER("delete")
+
+ if (*ppr_p == NULL) {
+ MSG("key not in tree")
+ RET(FALSE)
+ }
+
+ i_comp = (*pfi_compare)((*ppr_p)->data, p_user);
+ if (i_comp > 0) {
+ MSG("too high - scan left")
+ i_ret = delete(&(*ppr_p)->left, pfi_compare, p_user, pfv_uar,
+ pi_balance, pi_uar_called);
+ if (*pi_balance)
+ bal_L(ppr_p, pi_balance);
+ } else if (i_comp < 0) {
+ MSG("too low - scan right")
+ i_ret = delete(&(*ppr_p)->right, pfi_compare, p_user, pfv_uar,
+ pi_balance, pi_uar_called);
+ if (*pi_balance)
+ bal_R(ppr_p, pi_balance);
+ } else {
+ MSG("equal")
+ pr_q = *ppr_p;
+ if (pr_q->right == NULL) {
+ MSG("right subtree null")
+ *ppr_p = pr_q->left;
+ *pi_balance = TRUE;
+ } else if (pr_q->left == NULL) {
+ MSG("right subtree non-null, left subtree null")
+ *ppr_p = pr_q->right;
+ *pi_balance = TRUE;
+ } else {
+ MSG("neither subtree null")
+ del(&pr_q->left, pi_balance, &pr_q,
+ pfv_uar, pi_uar_called);
+ if (*pi_balance)
+ bal_L(ppr_p, pi_balance);
+ }
+ if (!*pi_uar_called && pfv_uar)
+ (*pfv_uar)(pr_q->data);
+ free(pr_q); /* thanks to wuth@castrov.cuc.ab.ca */
+ i_ret = TRUE;
+ }
+ RET(i_ret)
+}
+
+
+static void
+del(ppr_r, pi_balance, ppr_q, pfv_uar, pi_uar_called)
+ tree **ppr_r;
+ int *pi_balance;
+ tree **ppr_q;
+ void (*pfv_uar)();
+ int *pi_uar_called;
+{
+ ENTER("del")
+
+ if ((*ppr_r)->right != NULL) {
+ del(&(*ppr_r)->right, pi_balance, ppr_q,
+ pfv_uar, pi_uar_called);
+ if (*pi_balance)
+ bal_R(ppr_r, pi_balance);
+ } else {
+ if (pfv_uar)
+ (*pfv_uar)((*ppr_q)->data);
+ *pi_uar_called = TRUE;
+ (*ppr_q)->data = (*ppr_r)->data;
+ *ppr_q = *ppr_r;
+ *ppr_r = (*ppr_r)->left;
+ *pi_balance = TRUE;
+ }
+
+ RETV
+}
+
+
+static void
+bal_L(ppr_p, pi_balance)
+ tree **ppr_p;
+ int *pi_balance;
+{
+ tree *p1, *p2;
+ int b1, b2;
+
+ ENTER("bal_L")
+ MSG("left branch has shrunk")
+
+ switch ((*ppr_p)->bal) {
+ case -1:
+ MSG("was imbalanced, fixed implicitly")
+ (*ppr_p)->bal = 0;
+ break;
+ case 0:
+ MSG("was okay, is now one off")
+ (*ppr_p)->bal = 1;
+ *pi_balance = FALSE;
+ break;
+ case 1:
+ MSG("was already off, this is too much")
+ p1 = (*ppr_p)->right;
+ b1 = p1->bal;
+ if (b1 >= 0) {
+ MSG("single RR")
+ (*ppr_p)->right = p1->left;
+ p1->left = *ppr_p;
+ if (b1 == 0) {
+ MSG("b1 == 0")
+ (*ppr_p)->bal = 1;
+ p1->bal = -1;
+ *pi_balance = FALSE;
+ } else {
+ MSG("b1 != 0")
+ (*ppr_p)->bal = 0;
+ p1->bal = 0;
+ }
+ *ppr_p = p1;
+ } else {
+ MSG("double RL")
+ p2 = p1->left;
+ b2 = p2->bal;
+ p1->left = p2->right;
+ p2->right = p1;
+ (*ppr_p)->right = p2->left;
+ p2->left = *ppr_p;
+ if (b2 == 1)
+ (*ppr_p)->bal = -1;
+ else
+ (*ppr_p)->bal = 0;
+ if (b2 == -1)
+ p1->bal = 1;
+ else
+ p1->bal = 0;
+ *ppr_p = p2;
+ p2->bal = 0;
+ }
+ }
+ RETV
+}
+
+
+static void
+bal_R(ppr_p, pi_balance)
+ tree **ppr_p;
+ int *pi_balance;
+{
+ tree *p1, *p2;
+ int b1, b2;
+
+ ENTER("bal_R")
+ MSG("right branch has shrunk")
+ switch ((*ppr_p)->bal) {
+ case 1:
+ MSG("was imbalanced, fixed implicitly")
+ (*ppr_p)->bal = 0;
+ break;
+ case 0:
+ MSG("was okay, is now one off")
+ (*ppr_p)->bal = -1;
+ *pi_balance = FALSE;
+ break;
+ case -1:
+ MSG("was already off, this is too much")
+ p1 = (*ppr_p)->left;
+ b1 = p1->bal;
+ if (b1 <= 0) {
+ MSG("single LL")
+ (*ppr_p)->left = p1->right;
+ p1->right = *ppr_p;
+ if (b1 == 0) {
+ MSG("b1 == 0")
+ (*ppr_p)->bal = -1;
+ p1->bal = 1;
+ *pi_balance = FALSE;
+ } else {
+ MSG("b1 != 0")
+ (*ppr_p)->bal = 0;
+ p1->bal = 0;
+ }
+ *ppr_p = p1;
+ } else {
+ MSG("double LR")
+ p2 = p1->right;
+ b2 = p2->bal;
+ p1->right = p2->left;
+ p2->left = p1;
+ (*ppr_p)->left = p2->right;
+ p2->right = *ppr_p;
+ if (b2 == -1)
+ (*ppr_p)->bal = 1;
+ else
+ (*ppr_p)->bal = 0;
+ if (b2 == 1)
+ p1->bal = -1;
+ else
+ p1->bal = 0;
+ *ppr_p = p2;
+ p2->bal = 0;
+ }
+ }
+ RETV
+}
diff --git a/usr.sbin/named/tree.h b/usr.sbin/named/tree.h
new file mode 100644
index 0000000..2cad7c1
--- /dev/null
+++ b/usr.sbin/named/tree.h
@@ -0,0 +1,48 @@
+/* tree.h - declare structures used by tree library
+ *
+ * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
+ * vix 27jun86 [broken out of tree.c]
+ *
+ * $Id: tree.h,v 1.1 1994/04/09 04:05:46 vixie Exp $
+ */
+
+
+#ifndef _TREE_H_INCLUDED
+#define _TREE_H_INCLUDED
+
+
+#ifndef __P
+# if defined(__STDC__) || defined(__GNUC__)
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+/*
+ * tree_t is our package-specific anonymous pointer.
+ */
+#if defined(__STDC__) || defined(__GNUC__)
+typedef void *tree_t;
+#else
+typedef char *tree_t;
+#endif
+
+
+typedef struct tree_s {
+ tree_t data;
+ struct tree_s *left, *right;
+ short bal;
+ }
+ tree;
+
+
+void tree_init __P((tree **));
+tree_t tree_srch __P((tree **, int (*)(), tree_t));
+tree_t tree_add __P((tree **, int (*)(), tree_t, void (*)()));
+int tree_delete __P((tree **, int (*)(), tree_t, void (*)()));
+int tree_trav __P((tree **, int (*)()));
+void tree_mung __P((tree **, void (*)()));
+
+
+#endif /* _TREE_H_INCLUDED */
diff --git a/usr.sbin/named/tree.man3 b/usr.sbin/named/tree.man3
new file mode 100644
index 0000000..5be48783
--- /dev/null
+++ b/usr.sbin/named/tree.man3
@@ -0,0 +1,154 @@
+.TH TREE 3 "5 April 1994"
+.\" from .TH TREE 3 "22 Jan 1993"
+.\" from .TH TREE 2 "23 June 1986"
+.UC 4
+.SH NAME
+tree_init, tree_mung, tree_srch, tree_add, tree_delete, tree_trav
+\- balanced binary tree routines
+.SH SYNOPSIS
+.nf
+.B void
+.B tree_init(tree)
+.B void **tree;
+.PP
+.B void *
+.B tree_srch(tree, compare, data)
+.B void **tree;
+.B int (*compare)();
+.B void *data;
+.PP
+.B void
+.B tree_add(tree, compare, data, del_uar)
+.B void **tree;
+.B int (*compare)();
+.B void *data;
+.B void (*del_uar)();
+.PP
+.B int
+.B tree_delete(tree, compare, data, del_uar)
+.B void **tree;
+.B int (*compare)();
+.B void *data;
+.B void (*del_uar)();
+.PP
+.B int
+.B tree_trav(tree, trav_uar)
+.B void **tree;
+.B int (*trav_uar)();
+.PP
+.B void
+.B tree_mung(tree, del_uar)
+.B void **tree;
+.B void (*del_uar)();
+.fi
+.SH DESCRIPTION
+These functions create and manipulate a balanced binary (AVL) tree. Each node
+of the tree contains the expected left & right subtree pointers, a short int
+balance indicator, and a pointer to the user data. On a 32 bit system, this
+means an overhead of 4+4+2+4 bytes per node (or, on a RISC or otherwise
+alignment constrained system with implied padding, 4+4+4+4 bytes per node).
+There is no key data type enforced by this package; a caller supplied
+compare routine is used to compare user data blocks.
+.PP
+Balanced binary trees are very fast on searches and replacements, but have a
+moderately high cost for additions and deletions. If your application does a
+lot more searches and replacements than it does additions and deletions, the
+balanced (AVL) binary tree is a good choice for a data structure.
+.PP
+.I Tree_init
+creates an empty tree and binds it to
+.I tree
+(which for this and all other routines in this package should be declared as
+a pointer to void or int, and passed by reference), which can then be used by
+other routines in this package. Note that more than one
+.I tree
+variable can exist at once; thus multiple trees can be manipulated
+simultaneously.
+.PP
+.I Tree_srch
+searches a tree for a specific node and returns either
+.I NULL
+if no node was found, or the value of the user data pointer if the node
+was found.
+.I compare
+is the address of a function to compare two user data blocks. This routine
+should work much the way
+.IR strcmp (3)
+does; in fact,
+.I strcmp
+could be used if the user data was a \s-2NUL\s+2 terminated string.
+.I data
+is the address of a user data block to be used by
+.I compare
+as the search criteria. The tree is searched for a node where
+.I compare
+returns 0.
+.PP
+.I Tree_add
+inserts or replaces a node in the specified tree. The tree specified by
+.I tree
+is searched as in
+.I tree_srch,
+and if a node is found to match
+.I data,
+then the
+.I del_uar
+function, if non\-\s-2NULL\s+2, is called with the address of the user data
+block for the node (this routine should deallocate any dynamic memory which
+is referenced exclusively by the node); the user data pointer for the node
+is then replaced by the value of
+.I data.
+If no node is found to match, a new node is added (which may or may not
+cause a transparent rebalance operation), with a user data pointer equal to
+.I data.
+A rebalance may or may not occur, depending on where the node is added
+and what the rest of the tree looks like.
+.I Tree_add
+will return the
+.I data
+pointer unless catastrophe occurs in which case it will return \s-2NULL\s+2.
+.PP
+.I Tree_delete
+deletes a node from
+.I tree.
+A rebalance may or may not occur, depending on where the node is removed from
+and what the rest of the tree looks like.
+.I Tree_delete
+returns TRUE if a node was deleted, FALSE otherwise.
+.PP
+.I Tree_trav
+traverses all of
+.I tree,
+calling
+.I trav_uar
+with the address of each user data block. If
+.I trav_uar
+returns FALSE at any time,
+.I tree_trav
+will immediately return FALSE to its caller. Otherwise all nodes will be
+reached and
+.I tree_trav
+will return TRUE.
+.PP
+.I Tree_mung
+deletes every node in
+.I tree,
+calling
+.I del_uar
+(if it is not \s-2NULL\s+2) with the user data address from each node (see
+.I tree_add
+and
+.I tree_delete
+above). The tree is left in the same state that
+.I tree_init
+leaves it in \- i.e., empty.
+.SH BUGS
+Should have a way for the caller to specify application specific
+.I malloc
+and
+.I free
+functions to be used internally when allocating meta data.
+.SH AUTHOR
+Paul Vixie, converted and augumented from Modula\-2 examples in
+.I Algorithms & Data Structures,
+Niklaus Wirth, Prentice\-Hall, ISBN 0\-13\-022005\-1.
diff --git a/usr.sbin/named/xfer/named-xfer.c b/usr.sbin/named/xfer/named-xfer.c
new file mode 100644
index 0000000..5d8a9cd
--- /dev/null
+++ b/usr.sbin/named/xfer/named-xfer.c
@@ -0,0 +1,1481 @@
+/*
+ * The original version of xfer by Kevin Dunlap.
+ * Completed and integrated with named by David Waitzman
+ * (dwaitzman@bbn.com) 3/14/88.
+ * Modified by M. Karels and O. Kure 10-88.
+ * Modified extensively since then by just about everybody.
+ */
+
+/*
+ * ++Copyright++ 1988, 1990
+ * -
+ * Copyright (c) 1988, 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#if !defined(lint) && !defined(SABER)
+char copyright[] =
+"@(#) Copyright (c) 1988, 1990 The Regents of the University of California.\n\
+ portions Copyright (c) 1993 Digital Equipment Corporation\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)named-xfer.c 4.18 (Berkeley) 3/7/91";
+static char rcsid[] = "$Id: named-xfer.c,v 4.9.1.23 1994/07/22 08:42:39 vixie Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <math.h>
+#include <signal.h>
+
+#define MAIN_PROGRAM
+#include "named.h"
+#undef MAIN_PROGRAM
+
+#ifndef LOG_PERROR
+# define LOG_PERROR 0
+#endif
+
+static struct zoneinfo zone; /* zone information */
+
+static char ddtfilename[] = _PATH_TMPXFER,
+ *ddtfile = ddtfilename,
+ *tmpname,
+ *domain; /* domain being xfered */
+
+static int quiet = 0,
+ read_interrupted = 0,
+ domain_len; /* strlen(domain) */
+
+static FILE *fp = NULL,
+ *dbfp = NULL;
+
+static void usage __P((const char *));
+static int getzone __P((struct zoneinfo *, u_int32_t, int)),
+ soa_zinfo __P((struct zoneinfo *, u_char *, u_char *)),
+ print_output __P((u_char *, int, u_char *)),
+ netread __P((int, char *, int, int));
+static SIG_FN read_alarm __P((void));
+static char *ProgName;
+
+extern char *optarg;
+extern int optind, getopt();
+
+void
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct zoneinfo *zp;
+ register struct hostent *hp;
+ char *dbfile = NULL, *tracefile = NULL, *tm = NULL;
+ int dbfd, ddtd, result, c, fd, closed = 0;
+ u_int32_t serial_no = 0;
+ u_int16_t port = htons(NAMESERVER_PORT);
+ struct stat statbuf;
+#ifdef STUBS
+ int stub_only = 0;
+#endif
+#ifdef GEN_AXFR
+ int class = C_IN;
+#endif
+
+ if (ProgName = strrchr(argv[0], '/'))
+ ProgName++;
+ else
+ ProgName = argv[0];
+
+ (void) umask(022);
+
+ /* this is a hack; closing everything in the parent is hard. */
+ for (fd = getdtablesize()-1; fd > STDERR_FILENO; fd--)
+ closed += (close(fd) == 0);
+
+#ifdef RENICE
+ nice (-40); /* this is the recommended procedure to */
+ nice (20); /* reset the priority of the current process */
+ nice (0); /* to "normal" (== 0) - see nice(3) */
+#endif
+
+#ifdef LOG_DAEMON
+ openlog(ProgName, LOG_PID|LOG_CONS|LOG_PERROR, LOGFAC);
+#else
+ openlog(ProgName, LOG_PID);
+#endif
+#ifdef STUBS
+ while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:qS")) != EOF)
+#else
+ while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:q")) != EOF)
+#endif
+ switch (c) {
+#ifdef GEN_AXFR
+ case 'C':
+ class = get_class(optarg);
+ break;
+#endif
+ case 'd':
+#ifdef DEBUG
+ debug = atoi(optarg);
+#endif
+ break;
+ case 'l':
+ ddtfile = (char *)malloc(strlen(optarg) +
+ sizeof(".XXXXXX") + 1);
+#ifdef SHORT_FNAMES
+ filenamecpy(ddtfile, optarg);
+#else
+ (void) strcpy(ddtfile, optarg);
+#endif /* SHORT_FNAMES */
+ (void) strcat(ddtfile, ".XXXXXX");
+ break;
+ case 's':
+ serial_no = strtoul(optarg, (char **)NULL, 10);
+ break;
+ case 't':
+ tracefile = optarg;
+ break;
+ case 'z': /* zone == domain */
+ domain = optarg;
+ domain_len = strlen(domain);
+ while ((domain_len > 0) &&
+ (domain[domain_len-1] == '.'))
+ domain[--domain_len] = '\0';
+ break;
+ case 'f':
+ dbfile = optarg;
+ tmpname = (char *)malloc((unsigned)strlen(optarg) +
+ sizeof(".XXXXXX") + 1);
+#ifdef SHORT_FNAMES
+ filenamecpy(tmpname, optarg);
+#else
+ (void) strcpy(tmpname, optarg);
+#endif /* SHORT_FNAMES */
+ break;
+ case 'p':
+ port = htons((u_int16_t)atoi(optarg));
+ break;
+ case 'P':
+ port = (u_int16_t)atoi(optarg);
+ break;
+#ifdef STUBS
+ case 'S':
+ stub_only = 1;
+ break;
+#endif
+ case 'q':
+ quiet++;
+ break;
+ case '?':
+ default:
+ usage("unrecognized argument");
+ /* NOTREACHED */
+ }
+
+ if (!domain || !dbfile || optind >= argc) {
+ if (!domain)
+ usage("no domain");
+ if (!dbfile)
+ usage("no dbfile");
+ if (optind >= argc)
+ usage("not enough arguments");
+ /* NOTREACHED */
+ }
+ if (stat(dbfile, &statbuf) != -1 &&
+ !S_ISREG(statbuf.st_mode) &&
+ !S_ISFIFO(statbuf.st_mode))
+ usage("dbfile must be a regular file or FIFO");
+ if (tracefile && (fp = fopen(tracefile, "w")) == NULL)
+ perror(tracefile);
+ (void) strcat(tmpname, ".XXXXXX");
+ /* tmpname is now something like "/etc/named/named.bu.db.XXXXXX" */
+ if ((dbfd = mkstemp(tmpname)) == -1) {
+ perror(tmpname);
+ if (!quiet)
+ syslog(LOG_ERR, "can't make tmpfile (%s): %m\n",
+ tmpname);
+ exit(XFER_FAIL);
+ }
+#if HAVE_FCHMOD
+ if (fchmod(dbfd, 0644) == -1)
+#else
+ if (chmod(tmpname, 0644) == -1)
+#endif
+ {
+ perror(tmpname);
+ if (!quiet)
+ syslog(LOG_ERR, "can't [f]chmod tmpfile (%s): %m\n",
+ tmpname);
+ exit(XFER_FAIL);
+ }
+ if ((dbfp = fdopen(dbfd, "r+")) == NULL) {
+ perror(tmpname);
+ if (!quiet)
+ syslog(LOG_ERR, "can't fdopen tmpfile (%s)", tmpname);
+ exit(XFER_FAIL);
+ }
+#ifdef DEBUG
+ if (debug) {
+ /* ddtfile is now something like "/usr/tmp/xfer.ddt.XXXXXX" */
+ if ((ddtd = mkstemp(ddtfile)) == -1) {
+ perror(ddtfile);
+ debug = 0;
+ }
+#if HAVE_FCHMOD
+ else if (fchmod(ddtd, 0644) == -1)
+#else
+ else if (chmod(ddtfile, 0644) == -1)
+#endif
+ {
+ perror(ddtfile);
+ debug = 0;
+ } else if ((ddt = fdopen(ddtd, "w")) == NULL) {
+ perror(ddtfile);
+ debug = 0;
+ } else {
+#if defined(SYSV)
+ setvbuf(ddt, NULL, _IOLBF, BUFSIZ);
+#else
+ setlinebuf(ddt);
+#endif
+ }
+ }
+#endif
+ /*
+ * Ignore many types of signals that named (assumed to be our parent)
+ * considers important- if not, the user controlling named with
+ * signals usually kills us.
+ */
+ (void) signal(SIGHUP, SIG_IGN);
+#ifdef SIGSYS
+ (void) signal(SIGSYS, SIG_IGN);
+#endif
+#ifdef DEBUG
+ if (debug == 0)
+#endif
+ {
+ (void) signal(SIGINT, SIG_IGN);
+ (void) signal(SIGQUIT, SIG_IGN);
+ }
+ (void) signal(SIGIOT, SIG_IGN);
+
+#if defined(SIGUSR1) && defined(SIGUSR2)
+ (void) signal(SIGUSR1, SIG_IGN);
+ (void) signal(SIGUSR2, SIG_IGN);
+#else /* SIGUSR1&&SIGUSR2 */
+ (void) signal(SIGEMT, SIG_IGN);
+ (void) signal(SIGFPE, SIG_IGN);
+#endif /* SIGUSR1&&SIGUSR2 */
+
+ dprintf(1, (ddt,
+ "domain `%s'; file `%s'; serial %lu; closed %d\n",
+ domain, dbfile, serial_no, closed));
+
+ buildservicelist();
+ buildprotolist();
+
+ /* init zone data */
+
+ zp = &zone;
+#ifdef STUBS
+ if (stub_only)
+ zp->z_type = Z_STUB;
+ else
+#endif
+ zp->z_type = Z_SECONDARY;
+#ifdef GEN_AXFR
+ zp->z_class = class;
+#endif
+ zp->z_origin = domain;
+ zp->z_source = dbfile;
+ zp->z_addrcnt = 0;
+ dprintf(1, (ddt, "zone found (%d): \"%s\", source = %s\n",
+ zp->z_type,
+ (zp->z_origin[0] == '\0')
+ ? "."
+ : zp->z_origin,
+ zp->z_source));
+
+ for (; optind != argc; optind++, zp->z_addrcnt++) {
+ tm = argv[optind];
+ if (!inet_aton(tm, &zp->z_addr[zp->z_addrcnt])) {
+ hp = gethostbyname(tm);
+ if (hp == NULL) {
+ syslog(LOG_NOTICE,
+ "uninterpretable server (%s) for %s\n",
+ tm, zp->z_origin);
+ zp->z_addrcnt--; /* hack */
+ continue;
+ }
+ bcopy(hp->h_addr,
+ (char *)&zp->z_addr[zp->z_addrcnt],
+ INADDRSZ);
+ dprintf(1, (ddt, "Arg: \"%s\"\n", tm));
+ }
+ if (zp->z_addr[zp->z_addrcnt].s_addr == 0) {
+ syslog(LOG_NOTICE,
+ "SOA query to localhost (%s) for %s",
+ tm, zp->z_origin);
+ zp->z_addrcnt--; /* hack */
+ continue;
+ }
+ if (zp->z_addrcnt >= NSMAX) {
+ zp->z_addrcnt = NSMAX;
+ dprintf(1, (ddt, "NSMAX reached\n"));
+ break;
+ }
+ }
+ dprintf(1, (ddt, "addrcnt = %d\n", zp->z_addrcnt));
+
+ _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
+ result = getzone(zp, serial_no, port);
+ (void) my_fclose(dbfp);
+ switch (result) {
+
+ case XFER_SUCCESS: /* ok exit */
+ if (rename(tmpname, dbfile) == -1) {
+ perror("rename");
+ if (!quiet)
+ syslog(LOG_ERR, "rename %s to %s: %m",
+ tmpname, dbfile);
+ exit(XFER_FAIL);
+ }
+ exit(XFER_SUCCESS);
+
+ case XFER_UPTODATE: /* the zone was already uptodate */
+ (void) unlink(tmpname);
+ exit(XFER_UPTODATE);
+
+ case XFER_TIMEOUT:
+#ifdef DEBUG
+ if (!debug)
+#endif
+ (void) unlink(tmpname);
+ exit(XFER_TIMEOUT); /* servers not reachable exit */
+
+ case XFER_FAIL:
+ default:
+#ifdef DEBUG
+ if (!debug)
+#endif
+ (void) unlink(tmpname);
+ exit(XFER_FAIL); /* yuck exit */
+ }
+ /*NOTREACHED*/
+}
+
+static char *UsageText[] = {
+ "\t-z zone_to_transfer\n",
+ "\t-f db_file\n",
+ "\t-s serial_no\n",
+ "\t[-d debug_level]\n",
+ "\t[-l debug_log_file]\n",
+ "\t[-t trace_file]\n",
+ "\t[-p port]\n",
+#ifdef STUBS
+ "\t[-S]\n",
+#endif
+#ifdef GEN_AXFR
+ "\t[-C class]\n",
+#endif
+ "\tservers...\n",
+ NULL
+};
+
+static void
+usage(msg)
+ const char *msg;
+{
+ char * const *line;
+
+ fprintf(stderr, "Usage error: %s\n", msg);
+ fprintf(stderr, "Usage: %s\n", ProgName);
+ for (line = UsageText; *line; line++)
+ fputs(*line, stderr);
+ exit(XFER_FAIL);
+}
+
+#define DEF_DNAME '\001' /* '\0' means the root domain */
+/* XXX: The following variables should probably all be "static" */
+int minimum_ttl = 0, got_soa = 0;
+int prev_comment = 0; /* was previous record a comment? */
+char zone_top[MAXDNAME]; /* the top of the zone */
+char prev_origin[MAXDNAME]; /* from most recent $ORIGIN line */
+char prev_dname[MAXDNAME] = { DEF_DNAME }; /* from previous record */
+char prev_ns_dname[MAXDNAME] = { DEF_DNAME }; /* from most recent NS record */
+
+static int
+getzone(zp, serial_no, port)
+ struct zoneinfo *zp;
+ u_int32_t serial_no;
+ int port;
+{
+ HEADER *hp;
+ u_int16_t len;
+ u_int32_t serial;
+ int s, n, l, cnt, nscnt, soacnt, error = 0;
+ u_char *cp, *nmp, *eom, *tmp ;
+ u_char *buf = NULL;
+ int bufsize;
+ char name[MAXDNAME], name2[MAXDNAME];
+ struct sockaddr_in sin;
+ struct zoneinfo zp_start, zp_finish;
+#ifdef POSIX_SIGNALS
+ struct sigaction sv, osv;
+#else
+ struct sigvec sv, osv;
+#endif
+ int ancount, aucount;
+ int Class;
+#ifdef DEBUG
+ if (debug) {
+ (void)fprintf(ddt,"getzone() %s ", zp->z_origin);
+ switch (zp->z_type) {
+ case Z_STUB:
+ fprintf(ddt,"stub\n");
+ break;
+ case Z_SECONDARY:
+ fprintf(ddt,"secondary\n");
+ break;
+ default:
+ fprintf(ddt,"unknown type\n");
+ }
+ }
+#endif
+#ifdef POSIX_SIGNALS
+ sv.sa_handler = read_alarm;
+ /* SA_ONSTACK isn't recommended for strict POSIX code */
+ /* is it absolutely necessary? */
+ /* sv.sa_flags = SA_ONSTACK; */
+ sigfillset(&sv.sa_mask);
+ (void) sigaction(SIGALRM, &sv, &osv);
+#else
+ sv.sv_handler = read_alarm;
+ sv.sv_onstack = 0;
+ sv.sv_mask = ~0;
+ (void) sigvec(SIGALRM, &sv, &osv);
+#endif
+
+ strcpy(zone_top, zp->z_origin);
+ if ((l = strlen(zone_top)) != 0 && zone_top[l - 1] == '.')
+ zone_top[l - 1] = '\0';
+ strcpy(prev_origin, zone_top);
+
+ for (cnt = 0; cnt < zp->z_addrcnt; cnt++) {
+#ifdef GEN_AXFR
+ Class = zp->z_class;
+#else
+ Class = C_IN;
+#endif
+ error = 0;
+ if (buf == NULL) {
+ if ((buf = (u_char *)malloc(2 * PACKETSZ)) == NULL) {
+ syslog(LOG_ERR, "malloc(%u) failed",
+ 2 * PACKETSZ);
+ error++;
+ break;
+ }
+ bufsize = 2 * PACKETSZ;
+ }
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = (u_int16_t)port;
+ sin.sin_addr = zp->z_addr[cnt];
+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ error++;
+ break;
+ }
+ dprintf(2, (ddt, "connecting to server #%d [%s].%d\n",
+ cnt+1, inet_ntoa(sin.sin_addr),
+ ntohs(sin.sin_port)));
+ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ syslog(LOG_ERR, "connect(%s) failed: %m",
+ inet_ntoa(sin.sin_addr));
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+tryagain:
+ n = res_mkquery(QUERY, zp->z_origin, Class,
+ T_SOA, NULL, 0, NULL, buf, bufsize);
+ if (n < 0) {
+ if (!quiet)
+ syslog(LOG_NOTICE,
+ "zone %s: res_mkquery T_SOA failed",
+ zp->z_origin);
+ (void) my_close(s);
+#ifdef POSIX_SIGNALS
+ (void) sigaction(SIGALRM, &osv, (struct sigaction *)0);
+#else
+ (void) sigvec(SIGALRM, &osv, (struct sigvec *)0);
+#endif
+ return (XFER_FAIL);
+ }
+ /*
+ * Send length & message for SOA query
+ */
+ if (writemsg(s, buf, n) < 0) {
+ syslog(LOG_ERR, "writemsg: %m");
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ /*
+ * Get out your butterfly net and catch the SOA
+ */
+ if (netread(s, (char *)buf, INT16SZ, XFER_TIMER) < 0) {
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ if ((len = _getshort(buf)) == 0) {
+ (void) my_close(s);
+ continue;
+ }
+ if (len > bufsize) {
+ if ((buf = (u_char *)realloc(buf, len)) == NULL) {
+ syslog(LOG_ERR,
+ "malloc(%u) failed for SOA from server [%s], zone %s\n",
+ len,
+ inet_ntoa(sin.sin_addr),
+ zp->z_origin);
+ (void) my_close(s);
+ continue;
+ }
+ bufsize = len;
+ }
+ if (netread(s, (char *)buf, len, XFER_TIMER) < 0) {
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+#ifdef DEBUG
+ if (debug >= 3) {
+ (void)fprintf(ddt,"len = %d\n", len);
+ fp_query(buf, ddt);
+ }
+#endif
+ hp = (HEADER *) buf;
+ ancount = ntohs(hp->ancount);
+ aucount = ntohs(hp->nscount);
+
+ /*
+ * close socket if:
+ * 1) rcode != NOERROR
+ * 2) not an authority response
+ * 3) both the number of answers and authority count < 1)
+ */
+ if (hp->rcode != NOERROR || !(hp->aa) ||
+ (ancount < 1 && aucount < 1)) {
+#ifndef GEN_AXFR
+ if (Class == C_IN) {
+ dprintf(1, (ddt, "SOA failed, trying C_HS\n"));
+ Class = C_HS;
+ goto tryagain;
+ }
+#endif
+ syslog(LOG_NOTICE,
+ "%s from [%s], zone %s: rcode %d, aa %d, ancount %d, aucount %d\n",
+ "bad response to SOA query",
+ inet_ntoa(sin.sin_addr), zp->z_origin,
+ hp->rcode, hp->aa, ancount, aucount);
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ zp_start = *zp;
+ if (len < HFIXEDSZ + QFIXEDSZ) {
+ badsoa:
+ syslog(LOG_NOTICE,
+ "malformed SOA from [%s], zone %s: too short\n",
+ inet_ntoa(sin.sin_addr), zp->z_origin);
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ tmp = buf + HFIXEDSZ;
+ eom = buf + len;
+ if ((n = dn_skipname(tmp, eom)) == -1)
+ goto badsoa;
+ tmp += n + QFIXEDSZ;
+ if ((n = dn_skipname(tmp, eom)) == -1)
+ goto badsoa;
+ tmp += n;
+ if (soa_zinfo(&zp_start, tmp, eom) == -1)
+ goto badsoa;
+ if (SEQ_GT(zp_start.z_serial, serial_no) || !serial_no) {
+ dprintf(1, (ddt, "need update, serial %d\n",
+ zp_start.z_serial));
+ hp = (HEADER *) buf;
+ soacnt = 0;
+ nscnt = 0;
+ gettime (&tt);
+ (void) fprintf (dbfp, "; zone '%s' last serial %lu\n",
+ domain, serial_no);
+ (void) fprintf (dbfp, "; from %s at %s",
+ inet_ntoa (sin.sin_addr),
+ ctime (&tt.tv_sec));
+ for (;;) {
+ if ((soacnt == 0) || (zp->z_type == Z_STUB)) {
+ int type;
+#ifdef STUBS
+ if (zp->z_type == Z_STUB) {
+ if (!soacnt)
+ type = T_SOA;
+ else if (!nscnt)
+ type = T_NS;
+ else
+ type = T_SOA;
+ } else
+#endif
+ type = T_AXFR;
+ n = res_mkquery(QUERY, zp->z_origin,
+ Class, type, NULL, 0,
+ NULL, buf, bufsize);
+ if (n < 0) {
+ if (!quiet) {
+#ifdef STUBS
+ if (zp->z_type == Z_STUB)
+ syslog(LOG_NOTICE,
+ (type == T_SOA)
+ ? "zone %s: res_mkquery T_SOA failed"
+ : "zone %s: res_mkquery T_NS failed",
+ zp->z_origin);
+ else
+#endif
+ syslog(LOG_NOTICE,
+ "zone %s: res_mkquery T_AXFR failed",
+ zp->z_origin);
+ }
+ (void) my_close(s);
+#ifdef POSIX_SIGNALS
+ sigaction(SIGALRM, &osv,
+ (struct sigaction *)0);
+#else
+ sigvec(SIGALRM, &osv,
+ (struct sigvec *)0);
+#endif
+ return (XFER_FAIL);
+ }
+ /*
+ * Send length & msg for zone transfer
+ */
+ if (writemsg(s, buf, n) < 0) {
+ syslog(LOG_ERR,"writemsg: %m");
+ error++;
+ (void) my_close(s);
+ break;
+ }
+ }
+ /*
+ * Receive length & response
+ */
+ if (netread(s, (char *)buf, INT16SZ,
+ (soacnt == 0) ?300 :XFER_TIMER)
+ < 0) {
+ error++;
+ break;
+ }
+ if ((len = _getshort(buf)) == 0)
+ break;
+ eom = buf + len;
+ if (netread(s, (char *)buf, len, XFER_TIMER)
+ < 0) {
+ error++;
+ break;
+ }
+#ifdef DEBUG
+ if (debug >= 3) {
+ (void)fprintf(ddt,"len = %d\n", len);
+ fp_query(buf, ddt);
+ }
+ if (fp)
+ fp_query(buf, fp);
+#endif
+ if (len < HFIXEDSZ) {
+ badrec:
+ error++;
+ syslog(LOG_NOTICE,
+ "record too short from [%s], zone %s\n",
+ inet_ntoa(sin.sin_addr),
+ zp->z_origin);
+ break;
+ }
+ cp = buf + HFIXEDSZ;
+ if (hp->qdcount) {
+ if ((n = dn_skipname(cp, eom)) == -1
+ || n + QFIXEDSZ >= eom - cp)
+ goto badrec;
+ cp += n + QFIXEDSZ;
+ }
+ nmp = cp;
+ if ((n = dn_skipname(cp, eom)) == -1)
+ goto badrec;
+ tmp = cp + n;
+#ifdef STUBS
+ if (zp->z_type == Z_STUB) {
+ ancount = ntohs(hp->ancount);
+ for (cnt = 0 ; cnt < ancount ; cnt++) {
+
+ n = print_output(buf, bufsize, cp);
+ cp += n;
+ }
+ if (hp->nscount) {
+ /* we should not get here */
+ ancount = ntohs(hp->nscount);
+ for (cnt = 0 ; cnt < ancount ; cnt++) {
+ n = print_output(buf, bufsize, cp);
+ cp += n;
+ }
+ }
+ ancount = ntohs(hp->arcount);
+ for (cnt = 0 ; cnt < ancount ; cnt ++) {
+ n = print_output(buf, bufsize, cp);
+ cp += n;
+ }
+ if (cp != eom) {
+ syslog(LOG_ERR,
+ "print_output: short answer (%d, %d), zone %s",
+ cp - buf, n, zp->z_origin);
+ error++;
+ break;
+ }
+
+ } else {
+#endif /*STUBS*/
+ n = print_output(buf, bufsize, cp);
+ if (cp + n != eom) {
+ syslog(LOG_ERR,
+ "print_output: short answer (%d, %d), zone %s",
+ cp - buf, n, zp->z_origin);
+ error++;
+ break;
+ }
+#ifdef STUBS
+ }
+#endif
+ GETSHORT(n, tmp);
+ if (n == T_SOA) {
+ if (soacnt == 0) {
+ soacnt++;
+ if (dn_expand(buf, buf + 512, nmp,
+ name, sizeof name) == -1)
+ goto badsoa;
+ if (eom - tmp
+ <= 2 * INT16SZ
+ + INT32SZ) {
+ goto badsoa;
+ }
+ tmp += 2 * INT16SZ
+ + INT32SZ;
+ if ((n = dn_skipname(tmp, eom)) == -1)
+ goto badsoa;
+ tmp += n;
+ if ((n = dn_skipname(tmp, eom)) == -1)
+ goto badsoa;
+ tmp += n;
+ if (eom - tmp <= INT32SZ)
+ goto badsoa;
+ GETLONG(serial, tmp);
+ dprintf(3, (ddt,
+ "first SOA for %s, serial %d\n",
+ name, serial));
+ continue;
+ }
+ if (dn_expand(buf, buf + 512, nmp,
+ name2, sizeof name2) == -1)
+ goto badsoa;
+ if (strcasecmp((char *)name,
+ (char *)name2) != 0) {
+ dprintf(2, (ddt,
+ "extraneous SOA for %s\n",
+ name2));
+ continue;
+ }
+ tmp -= INT16SZ;
+ if (soa_zinfo(&zp_finish, tmp, eom) == -1)
+ goto badsoa;
+ dprintf(2, (ddt,
+ "SOA, serial %d\n",
+ zp_finish.z_serial));
+ if (serial != zp_finish.z_serial) {
+ soacnt = 0;
+ got_soa = 0;
+ minimum_ttl = 0;
+ strcpy(prev_origin, zp->z_origin);
+ prev_dname[0] = DEF_DNAME;
+ dprintf(1, (ddt,
+ "serial changed, restart\n"
+ ));
+ /*
+ * Flush buffer, truncate file
+ * and seek to beginning to restart.
+ */
+ fflush(dbfp);
+ if (ftruncate(fileno(dbfp), 0) != 0) {
+ if (!quiet)
+ syslog(LOG_ERR,
+ "ftruncate %s: %m\n",
+ tmpname);
+ return (XFER_FAIL);
+ }
+ fseek(dbfp, 0L, 0);
+ } else
+ break;
+#ifdef STUBS
+ } else if (zp->z_type == Z_STUB && n == T_NS) {
+ nscnt++;
+ } else if (zp->z_type == Z_STUB) {
+ break;
+#endif
+ }
+ }
+ (void) my_close(s);
+ if (error == 0) {
+#ifdef POSIX_SIGNALS
+ (void) sigaction(SIGALRM, &osv,
+ (struct sigaction *)0);
+#else
+ (void) sigvec(SIGALRM, &osv, (struct sigvec *)0);
+#endif
+ return (XFER_SUCCESS);
+ }
+ dprintf(2, (ddt, "error receiving zone transfer\n"));
+ } else if (zp_start.z_serial == serial_no) {
+ (void) my_close(s);
+ dprintf(1, (ddt,
+ "zone up-to-date, serial %u\n",
+ zp_start.z_serial));
+ return (XFER_UPTODATE);
+ } else {
+ (void) my_close(s);
+ if (!quiet)
+ syslog(LOG_NOTICE,
+ "serial from [%s], zone %s: %u lower than current: %u\n",
+ inet_ntoa(sin.sin_addr), zp->z_origin,
+ zp_start.z_serial, serial_no);
+ return (XFER_FAIL);
+ }
+ }
+#ifdef POSIX_SIGNALS
+ (void) sigaction(SIGALRM, &osv, (struct sigaction *)0);
+#else
+ (void) sigvec(SIGALRM, &osv, (struct sigvec *)0);
+#endif
+ if (error)
+ return (XFER_TIMEOUT);
+ return (XFER_FAIL);
+}
+
+/*
+ * Set flag saying to read was interrupted
+ * used for a read timer
+ */
+static SIG_FN
+read_alarm()
+{
+ read_interrupted = 1;
+}
+
+static int
+netread(fd, buf, len, timeout)
+ int fd;
+ register char *buf;
+ register int len;
+ int timeout;
+{
+ static const char setitimerStr[] = "setitimer: %m";
+ struct itimerval ival, zeroival;
+ register int n;
+#if defined(sun)
+ int retries = 0;
+#endif
+
+ memset(&zeroival, 0, sizeof zeroival);
+ ival = zeroival;
+ ival.it_value.tv_sec = timeout;
+ while (len > 0) {
+ if (setitimer(ITIMER_REAL, &ival, NULL) < 0) {
+ syslog(LOG_ERR, setitimerStr);
+ return (-1);
+ }
+ errno = 0;
+ n = recv(fd, buf, len, 0);
+ if (n <= 0) {
+ if (errno == 0) {
+#if defined(sun)
+ if (++retries < 42) /* doug adams */
+ continue;
+#endif
+ syslog(LOG_ERR,
+ "recv(len=%d): n=%d && !errno",
+ len, n);
+ return (-1);
+ }
+ if (errno == EINTR && !read_interrupted) {
+ /* Some other signal returned; ignore it. */
+ continue;
+ }
+ syslog(LOG_ERR, "recv(len=%d): %m", len);
+ return (-1);
+ }
+ buf += n;
+ len -= n;
+ }
+ if (setitimer(ITIMER_REAL, &zeroival, NULL) < 0) {
+ syslog(LOG_ERR, setitimerStr);
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+soa_zinfo(zp, cp, eom)
+ register struct zoneinfo *zp;
+ register u_char *cp;
+ u_char *eom;
+{
+ register int n;
+
+ if (eom - cp < 3 * INT16SZ + INT32SZ)
+ return (-1);
+ cp += 3 * INT16SZ + INT32SZ;
+ if ((n = dn_skipname(cp, eom)) == -1)
+ return (-1);
+ cp += n;
+ if ((n = dn_skipname(cp, eom)) == -1)
+ return (-1);
+ cp += n;
+ if (eom - cp < 5 * INT32SZ)
+ return (-1);
+ GETLONG(zp->z_serial, cp);
+ GETLONG(zp->z_refresh, cp);
+ GETLONG(zp->z_retry, cp);
+ GETLONG(zp->z_expire, cp);
+ GETLONG(zp->z_minimum, cp);
+ return (0);
+}
+
+/*
+ * Parse the message, determine if it should be printed, and if so, print it
+ * in .db file form.
+ * Does minimal error checking on the message content.
+ */
+static int
+print_output(msg, msglen, rrp)
+ u_char *msg;
+ int msglen;
+ u_char *rrp;
+{
+ register u_char *cp;
+ register HEADER *hp = (HEADER *) msg;
+ u_int32_t addr, ttl;
+ int i, j, tab, result, class, type, dlen, n1, n;
+ char data[BUFSIZ];
+ u_char *cp1, *cp2, *temp_ptr;
+ char *cdata, *origin, *proto, dname[MAXDNAME];
+ char *ignore = "";
+#ifdef NO_GLUE
+ int lend, lenn;
+#endif /*NO_GLUE*/
+
+ cp = rrp;
+ n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ GETSHORT(dlen, cp);
+
+ origin = strchr(dname, '.');
+ if (origin == NULL)
+ origin = "";
+ else
+ origin++; /* move past the '.' */
+ dprintf(3, (ddt,
+ "print_output: dname %s type %d class %d ttl %d\n",
+ dname, type, class, ttl));
+ /*
+ * 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_TXT:
+ case T_X25:
+ case T_ISDN:
+ case T_UID:
+ case T_GID:
+ 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:
+ n = dn_expand(msg, msg + msglen, cp, data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = (u_char *)data;
+ n = strlen(data) + 1;
+ break;
+
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ n = dn_expand(msg, msg + msglen, cp, data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ n = strlen(data) + 1;
+ cp1 = (u_char *)data + n;
+ n1 = sizeof data - n;
+ if (type == T_SOA)
+ n1 -= 5 * INT32SZ;
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += strlen((char *) cp1) + 1;
+ if (type == T_SOA) {
+ temp_ptr = cp + 4 * INT32SZ;
+ GETLONG(minimum_ttl, temp_ptr);
+ n = 5 * INT32SZ;
+ bcopy((char *) cp, (char *) cp1, n);
+ cp += n;
+ cp1 += n;
+ }
+ n = cp1 - (u_char *)data;
+ cp1 = (u_char *)data;
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ /* grab preference */
+ bcopy((char *)cp, data, INT16SZ);
+ cp1 = (u_char *)data + INT16SZ;
+ cp += INT16SZ;
+
+ /* get name */
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)cp1, sizeof data - INT16SZ);
+ if (n < 0)
+ return (-1);
+ cp += n;
+
+ /* compute end of data */
+ cp1 += strlen((char *) cp1) + 1;
+ /* compute size of data */
+ n = cp1 - (u_char *)data;
+ cp1 = (u_char *)data;
+ break;
+
+ default:
+ dprintf(3, (ddt, "unknown type %d\n", type));
+ return ((cp - rrp) + dlen);
+ }
+ if (n > MAXDATA) {
+ dprintf(1, (ddt,
+ "update type %d: %d bytes is too much data\n",
+ type, n));
+ hp->rcode = NOCHANGE; /* XXX - FORMERR ??? */
+ return (-1);
+ }
+ cdata = (char *) cp1;
+ result = cp - rrp;
+
+ /*
+ * Only print one SOA per db file
+ */
+ if (type == T_SOA) {
+ if (got_soa)
+ return (result);
+ else
+ got_soa++;
+ }
+
+#ifdef NO_GLUE
+ /*
+ * If they are trying to tell us info about something that is
+ * not in the zone that we are transfering, then ignore it!
+ * They don't have the authority to tell us this info.
+ *
+ * We have to do a bit of checking here - the name that we are
+ * checking vs is fully qualified & may be in a subdomain of the
+ * zone in question. We also need to ignore any final dots.
+ *
+ * If a domain has both NS records and non-NS records, (for
+ * example, NS and MX records), then we should ignore the non-NS
+ * records (except that we should not ignore glue A records).
+ * XXX: It is difficult to do this properly, so we just compare
+ * the current dname with that in the most recent NS record.
+ * This defends against the most common error case,
+ * where the remote server sends MX records soon after the
+ * NS records for a particular domain. If sent earlier, we lose. XXX
+ */
+ if (!samedomain(dname, domain)) {
+ (void) fprintf(dbfp, "; Ignoring info about %s, not in zone %s.\n",
+ dname, domain);
+ ignore = "; ";
+ } else if (type != T_NS && type != T_A &&
+ strcasecmp(zone_top, dname) != 0 &&
+ strcasecmp(prev_ns_dname, dname) == 0)
+ {
+ (void) fprintf(dbfp, "; Ignoring extra info about %s, invalid after NS delegation.\n",
+ dname);
+ ignore = "; ";
+ }
+#endif /*NO_GLUE*/
+
+ /*
+ * If the current record is not being ignored, but the
+ * previous record was ignored, then we invalidate information
+ * that might have been altered by ignored records.
+ * (This means that we sometimes output unnecessary $ORIGIN
+ * lines, but that is harmless.)
+ *
+ * Also update prev_comment now.
+ */
+ if (prev_comment && ignore[0] == '\0') {
+ prev_dname[0] = DEF_DNAME;
+ prev_origin[0] = DEF_DNAME;
+ }
+ prev_comment = (ignore[0] != '\0');
+
+ /*
+ * set prev_ns_dname if necessary
+ */
+ if (type == T_NS) {
+ (void) strcpy(prev_ns_dname, dname);
+ }
+
+ /*
+ * If the origin has changed, print the new origin
+ */
+ if (strcasecmp(prev_origin, origin)) {
+ (void) strcpy(prev_origin, origin);
+ (void) fprintf(dbfp, "%s$ORIGIN %s.\n", ignore, origin);
+ }
+ tab = 0;
+
+ if (strcasecmp(prev_dname, dname)) {
+ /*
+ * set the prev_dname to be the current dname, then cut off all
+ * characters of dname after (and including) the first '.'
+ */
+ char *cutp = strchr(dname, '.');
+
+ (void) strcpy(prev_dname, dname);
+ if (cutp)
+ *cutp = '\0';
+
+ if (dname[0] == 0) {
+ if (origin[0] == 0)
+ (void) fprintf(dbfp, "%s.\t", ignore);
+ else
+ (void) fprintf(dbfp, "%s.%s.\t",
+ ignore, origin); /* ??? */
+ } else
+ (void) fprintf(dbfp, "%s%s\t", ignore, dname);
+ if (strlen(dname) < 8)
+ tab = 1;
+ } else {
+ (void) fprintf(dbfp, "%s\t", ignore);
+ tab = 1;
+ }
+
+ if (ttl != 0 && ttl != minimum_ttl)
+ (void) fprintf(dbfp, "%d\t", (int) ttl);
+ else if (tab)
+ (void) putc('\t', dbfp);
+
+ (void) fprintf(dbfp, "%s\t%s\t", p_class(class), p_type(type));
+ cp = (u_char *) cdata;
+
+ /*
+ * Print type specific data
+ */
+ switch (type) {
+
+ case T_A:
+ switch (class) {
+ case C_IN:
+ case C_HS:
+ GETLONG(n, cp);
+ n = htonl(n);
+ (void) fprintf(dbfp, "%s",
+ inet_ntoa(*(struct in_addr *) & n));
+ break;
+ }
+ (void) fprintf(dbfp, "\n");
+ break;
+
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ if (cp[0] == '\0')
+ (void) fprintf(dbfp, ".\n");
+ else
+ (void) fprintf(dbfp, "%s.\n", cp);
+ break;
+
+ case T_NS:
+ cp = (u_char *) cdata;
+ if (cp[0] == '\0')
+ (void) fprintf(dbfp, ".\t");
+ else
+ (void) fprintf(dbfp, "%s.", cp);
+ (void) fprintf(dbfp, "\n");
+ break;
+
+ case T_HINFO:
+ case T_ISDN:
+ cp2 = cp + n;
+ n = *cp++;
+ cp1 = cp + n;
+ if (cp1 > cp2)
+ cp1 = cp2;
+ (void) putc('"', dbfp);
+ while (cp < cp1) {
+ if (*cp == '\0') {
+ cp = cp1;
+ break;
+ }
+ if ((*cp == '\n') || (*cp == '"')) {
+ (void) putc('\\', dbfp);
+ }
+ (void) putc(*cp++, dbfp);
+ }
+ (void) fputs("\" \"", dbfp);
+ n = *cp++;
+ cp1 = cp + n;
+ if (cp1 > cp2)
+ cp1 = cp2;
+ while (cp < cp1) {
+ if (*cp == '\0') {
+ cp = cp1;
+ break;
+ }
+ if ((*cp == '\n') || (*cp == '"')) {
+ (void) putc('\\', dbfp);
+ }
+ (void) putc(*cp++, dbfp);
+ }
+ (void) fputs("\"\n", dbfp);
+ break;
+
+ case T_SOA:
+ (void) fprintf(dbfp, "%s.", cp);
+ cp += strlen((char *) cp) + 1;
+ (void) fprintf(dbfp, " %s. (\n", cp);
+ cp += strlen((char *) cp) + 1;
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, "%s\t\t%lu", ignore, n);
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, " %lu", n);
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, " %lu", n);
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, " %lu", n);
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, " %lu )\n", n);
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ GETSHORT(n, cp);
+ (void) fprintf(dbfp, "%lu", n);
+ (void) fprintf(dbfp, " %s.\n", cp);
+ break;
+
+ case T_TXT:
+ case T_X25:
+ cp1 = cp + n;
+ (void) putc('"', dbfp);
+ while (cp < cp1) {
+ if (i = *cp++) {
+ for (j = i ; j > 0 && cp < cp1 ; j--) {
+ if ((*cp == '\n') || (*cp == '"')) {
+ (void) putc('\\', dbfp);
+ }
+ (void) putc(*cp++, dbfp);
+ }
+ }
+ }
+ (void) fputs("\"\n", dbfp);
+ break;
+
+ case T_NSAP:
+ fprintf(dbfp, "%s\n", inet_nsap_ntoa(n, cp, NULL));
+ break;
+
+ case T_UINFO:
+ (void) fprintf(dbfp, "\"%s\"\n", cp);
+ break;
+
+ case T_UID:
+ case T_GID:
+ if (n == INT32SZ) {
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, "%lu\n", n);
+ }
+ break;
+
+ case T_WKS:
+ GETLONG(addr, cp);
+ addr = htonl(addr);
+ (void) fprintf(dbfp, "%s ",
+ inet_ntoa(*(struct in_addr *) & addr));
+ proto = protocolname(*cp);
+ cp += sizeof(char);
+ (void) fprintf(dbfp, "%s ", proto);
+ i = 0;
+ while (cp < (u_char *) cdata + n) {
+ j = *cp++;
+ do {
+ if (j & 0200)
+ (void) fprintf(dbfp, " %s",
+ servicename(i, proto));
+ j <<= 1;
+ } while (++i & 07);
+ }
+ (void) fprintf(dbfp, "\n");
+ break;
+
+ case T_MINFO:
+ case T_RP:
+ (void) fprintf(dbfp, "%s.", cp);
+ cp += strlen((char *) cp) + 1;
+ (void) fprintf(dbfp, " %s.\n", cp);
+ break;
+
+ default:
+ (void) fprintf(dbfp, "???\n");
+ }
+ if (ferror(dbfp)) {
+ syslog(LOG_ERR, "%s: %m", tmpname);
+ exit(XFER_FAIL);
+ }
+ return (result);
+}
+
+#ifdef SHORT_FNAMES
+/*
+** This routine handles creating temporary files with mkstemp
+** in the presence of a 14 char filename system. Pathconf()
+** does not work over NFS.
+*/
+filenamecpy(ddtfile, optarg)
+char *ddtfile, *optarg;
+{
+ int namelen, extra, len;
+ char *dirname, *filename;
+
+ /* determine the length of filename allowed */
+ if((dirname = strrchr(optarg, '/')) == NULL){
+ filename = optarg;
+ } else {
+ *dirname++ = '\0';
+ filename = dirname;
+ }
+ namelen = pathconf(dirname == NULL? "." : optarg, _PC_NAME_MAX);
+ if(namelen <= 0)
+ namelen = 255; /* length could not be determined */
+ if(dirname != NULL)
+ *--dirname = '/';
+
+ /* copy a shorter name if it will be longer than allowed */
+ extra = (strlen(filename)+strlen(".XXXXXX")) - namelen;
+ if(extra > 0){
+ len = strlen(optarg) - extra;
+ (void) strncpy(ddtfile, optarg, len);
+ ddtfile[len] = '\0';
+ } else
+ (void) strcpy(ddtfile, optarg);
+}
+#endif /* SHORT_FNAMES */
OpenPOWER on IntegriCloud