summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/named/Makefile29
-rw-r--r--usr.sbin/named/Makefile.dist2
-rw-r--r--usr.sbin/named/Makefile.inc14
-rw-r--r--usr.sbin/named/conf/options.h169
-rw-r--r--usr.sbin/named/conf/portability.h569
-rw-r--r--usr.sbin/named/dig/Makefile12
-rw-r--r--usr.sbin/named/dig/debug.obin0 -> 8305 bytes
-rw-r--r--usr.sbin/named/dig/digbin0 -> 44803 bytes
-rw-r--r--usr.sbin/named/dig/dig.c1212
-rw-r--r--usr.sbin/named/dig/dig.cat1396
-rw-r--r--usr.sbin/named/dig/dig.obin0 -> 16288 bytes
-rw-r--r--usr.sbin/named/dig/list.obin0 -> 11676 bytes
-rw-r--r--usr.sbin/named/dig/send.obin0 -> 3565 bytes
-rw-r--r--usr.sbin/named/dig/subr.obin0 -> 8863 bytes
-rw-r--r--usr.sbin/named/dnsquery/Makefile8
-rw-r--r--usr.sbin/named/dnsquery/dnsquery.c234
-rw-r--r--usr.sbin/named/host/Makefile10
-rw-r--r--usr.sbin/named/host/RELEASE_NOTES770
-rw-r--r--usr.sbin/named/host/conf.h63
-rw-r--r--usr.sbin/named/host/defs.h148
-rw-r--r--usr.sbin/named/host/exit.h25
-rw-r--r--usr.sbin/named/host/host.c7227
-rw-r--r--usr.sbin/named/host/mxlookup163
-rw-r--r--usr.sbin/named/host/nslookup280
-rw-r--r--usr.sbin/named/host/port.h136
-rw-r--r--usr.sbin/named/host/rrec.h245
-rw-r--r--usr.sbin/named/host/send.c760
-rw-r--r--usr.sbin/named/host/type.h91
-rw-r--r--usr.sbin/named/host/vers.c9
-rw-r--r--usr.sbin/named/man/dig.1366
-rw-r--r--usr.sbin/named/man/dnsquery.1166
-rw-r--r--usr.sbin/named/man/gethostbyname.3228
-rw-r--r--usr.sbin/named/man/getnetent.3135
-rw-r--r--usr.sbin/named/man/host.1781
-rw-r--r--usr.sbin/named/man/hostname.7110
-rw-r--r--usr.sbin/named/man/mailaddr.7137
-rw-r--r--usr.sbin/named/man/named-xfer.8148
-rw-r--r--usr.sbin/named/man/named.8422
-rw-r--r--usr.sbin/named/man/named.reload.871
-rw-r--r--usr.sbin/named/man/named.restart.875
-rw-r--r--usr.sbin/named/man/ndc.8129
-rw-r--r--usr.sbin/named/man/nslookup.8388
-rw-r--r--usr.sbin/named/man/resolver.3305
-rw-r--r--usr.sbin/named/man/resolver.5135
-rw-r--r--usr.sbin/named/named-xfer/Makefile14
-rw-r--r--usr.sbin/named/named-xfer/named-xfer.c1635
-rw-r--r--usr.sbin/named/named/Makefile18
-rw-r--r--usr.sbin/named/named/Version.c90
-rw-r--r--usr.sbin/named/named/db_defs.h182
-rw-r--r--usr.sbin/named/named/db_dump.c910
-rw-r--r--usr.sbin/named/named/db_func.h118
-rw-r--r--usr.sbin/named/named/db_glob.h95
-rw-r--r--usr.sbin/named/named/db_glue.c1226
-rw-r--r--usr.sbin/named/named/db_load.c1415
-rw-r--r--usr.sbin/named/named/db_lookup.c198
-rw-r--r--usr.sbin/named/named/db_reload.c127
-rw-r--r--usr.sbin/named/named/db_save.c209
-rw-r--r--usr.sbin/named/named/db_secure.c155
-rw-r--r--usr.sbin/named/named/db_update.c735
-rw-r--r--usr.sbin/named/named/dmalloc.c316
-rw-r--r--usr.sbin/named/named/dmalloc.h70
-rw-r--r--usr.sbin/named/named/named.h21
-rw-r--r--usr.sbin/named/named/ns_defs.h403
-rw-r--r--usr.sbin/named/named/ns_forw.c994
-rw-r--r--usr.sbin/named/named/ns_func.h163
-rw-r--r--usr.sbin/named/named/ns_glob.h272
-rw-r--r--usr.sbin/named/named/ns_init.c963
-rw-r--r--usr.sbin/named/named/ns_main.c1674
-rw-r--r--usr.sbin/named/named/ns_maint.c1103
-rw-r--r--usr.sbin/named/named/ns_ncache.c155
-rw-r--r--usr.sbin/named/named/ns_req.c2153
-rw-r--r--usr.sbin/named/named/ns_resp.c2595
-rw-r--r--usr.sbin/named/named/ns_sort.c173
-rw-r--r--usr.sbin/named/named/ns_stats.c400
-rw-r--r--usr.sbin/named/named/ns_validate.c1247
-rw-r--r--usr.sbin/named/named/pathnames.h124
-rw-r--r--usr.sbin/named/named/storage.c206
-rw-r--r--usr.sbin/named/named/tree.c572
-rw-r--r--usr.sbin/named/named/tree.h50
-rw-r--r--usr.sbin/named/named/version.c90
-rw-r--r--usr.sbin/named/ndc/Makefile25
-rw-r--r--usr.sbin/named/ndc/ndc.sh85
-rw-r--r--usr.sbin/named/nslookup/Makefile22
-rw-r--r--usr.sbin/named/nslookup/commands.l221
-rw-r--r--usr.sbin/named/nslookup/debug.c547
-rw-r--r--usr.sbin/named/nslookup/getinfo.c845
-rw-r--r--usr.sbin/named/nslookup/list.c1026
-rw-r--r--usr.sbin/named/nslookup/main.c1114
-rw-r--r--usr.sbin/named/nslookup/nslookup.help34
-rw-r--r--usr.sbin/named/nslookup/pathnames.h73
-rw-r--r--usr.sbin/named/nslookup/res.h174
-rw-r--r--usr.sbin/named/nslookup/send.c414
-rw-r--r--usr.sbin/named/nslookup/skip.c213
-rw-r--r--usr.sbin/named/nslookup/subr.c581
-rw-r--r--usr.sbin/named/reload/Makefile22
-rw-r--r--usr.sbin/named/reload/named.reload.sh8
-rw-r--r--usr.sbin/named/restart/Makefile22
-rw-r--r--usr.sbin/named/restart/named.restart.sh8
98 files changed, 42448 insertions, 25 deletions
diff --git a/usr.sbin/named/Makefile b/usr.sbin/named/Makefile
index 7f35099fcbc..307e4bd4833 100644
--- a/usr.sbin/named/Makefile
+++ b/usr.sbin/named/Makefile
@@ -1,27 +1,8 @@
-# from: @(#)Makefile 5.8 (Berkeley) 7/28/90
-# $Id: Makefile,v 1.1 1995/10/18 08:47:49 deraadt Exp $
+# $NetBSD: Makefile,v 1.7 1996/02/02 15:25:33 mrg Exp $
+# from $Id: Makefile,v 8.1 1994/12/15 06:23:43 vixie Exp
-### -DALLOW_T_UNSPEC -Dmalloc=rt_malloc -Dfree=rt_free
-### ALLOC=storage.o
-PROG= named
-MAN= named.8
-CFLAGS+=-DDEBUG -DSTATS
-SRCS= db_dump.c db_glue.c db_load.c db_lookup.c db_reload.c db_save.c \
- db_update.c ns_forw.c ns_init.c ns_main.c ns_maint.c ns_req.c \
- ns_resp.c ns_sort.c ns_stats.c
-OBJS+= version.o
-CLEANFILES+=version.c version.o
-SUBDIR= tools xfer
+SUBDIR= named named-xfer ndc reload restart dig nslookup host dnsquery
-version.c: ${.CURDIR}/Version.c
- (u=$${USER-root} d=`pwd |sed -e 's|/obj/|/src/|'` \
- h=`hostname` t=`date`; \
- sed -e "s|%WHEN%|$${t}|" \
- -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
- < ${.CURDIR}/Version.c > version.c)
+VER= 4.9.3-P1
-afterinstall:
- install -c -o ${BINOWN} -g ${BINGRP} -m 555 ${.CURDIR}/named.restart \
- ${.CURDIR}/named.reload ${DESTDIR}${BINDIR}
-
-.include <bsd.prog.mk>
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/named/Makefile.dist b/usr.sbin/named/Makefile.dist
index 7dd040a8920..e034c94b1ed 100644
--- a/usr.sbin/named/Makefile.dist
+++ b/usr.sbin/named/Makefile.dist
@@ -1,5 +1,5 @@
# from: @(#)Makefile.dist 5.5 (Berkeley) 8/23/90
-# $Id: Makefile.dist,v 1.1 1995/10/18 08:47:49 deraadt Exp $
+# $Id: Makefile.dist,v 1.2 1996/02/19 19:53:34 dm Exp $
STDDEF= -DDEBUG -DSTATS
### -DSIG_FN=void -DALLOW_T_UNSPEC -Dmalloc=rt_malloc -Dfree=rt_free
diff --git a/usr.sbin/named/Makefile.inc b/usr.sbin/named/Makefile.inc
new file mode 100644
index 00000000000..49eb866c57e
--- /dev/null
+++ b/usr.sbin/named/Makefile.inc
@@ -0,0 +1,14 @@
+# $NetBSD: Makefile.inc,v 1.1 1996/02/02 15:25:35 mrg Exp $
+# from: $Id: Makefile.inc,v 8.3 1995/12/31 23:28:00 vixie Exp
+
+BIND_DIR= ${.CURDIR}/..
+
+VER!= awk -F' *= *' '$$1 == "VER" { print $$2 ; exit }' \
+ ${BIND_DIR}/Makefile
+
+PIDDIR= /var/run
+PS= ps
+IOT= IOT
+
+CONFIG?= -DUSE_OPTIONS_H
+INCLUDE?= -I. -I${BIND_DIR} -I${BIND_DIR}/include
diff --git a/usr.sbin/named/conf/options.h b/usr.sbin/named/conf/options.h
new file mode 100644
index 00000000000..c032527d5cc
--- /dev/null
+++ b/usr.sbin/named/conf/options.h
@@ -0,0 +1,169 @@
+/* $NetBSD: options.h,v 1.1 1996/02/02 15:26:11 mrg Exp $ */
+
+/* options.h - specify the conditionally-compiled features
+ * vix 28mar92 [moved out of the Makefile because they were getting too big]
+ *
+ * $Id: options.h,v 8.7 1995/12/29 21:08:13 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--
+ */
+
+/* Key:
+ * ucb = U C Berkeley 4.8.3 release
+ * vix = Paul Vixie of Digital
+ * del = Don Lewis of Harris
+ * mcsun = Piet Beertema of EUNet
+ * asp = Andrew Partan of UUNet
+ * pma = Paul Albitz of Hewlett Packard
+ * bb = Bryan Beecher of UMich
+ * mpa = Mark Andrews of CSIRO - DMS
+ * rossc = Ross Cartlidge of The Univeritsy of Sydney
+ * mtr = Marshall Rose of TPC.INT
+ * bg = Benoit Grange of INRIA
+ * ckd = Christopher Davis of Kapor Enterprises
+ * gns = Greg Shapiro of WPI
+ */
+
+#define DEBUG /* enable -d flag and SIGUSR[12] support (ucb) */
+/*#define ALLOW_T_UNSPEC /* enable the "unspec" RR type for old athena (ucb) */
+/*#define INVQ /* enable inverse queries (nslookup) (ucb/vix) */
+/*#define DSTORAGE /* debug malloc overruns using storage.o (ucb/vix) */
+/*#define DMALLOC /* trace malloc orphans using dmalloc.o (vix) */
+#define XFRNETS /* enable "xfrnets" command in named.boot (vix) */
+#define PID_FIX /* be careful about overwriting named.pid file (del) */
+#define FWD_LOOP /* try to break out of forwarding loops (del) */
+#define NO_GLUE /* don't accept or send out-of-zone glue (del) */
+#define BOGUSNS /* detect bogus nameservers (mcsun) */
+#define QRYLOG /* enable SIGWINCH for query logging (bb) */
+/*#define YPKLUDGE /* deal effectively with broken "ypserv -i" (mcsun) */
+#define TRACEROOT /* trace bogus root servers and ignore them (pma,bb) */
+/*#define LOCALDOM /* permit "domain" directive in named.boot (ucb) */
+#define FORCED_RELOAD /* refresh secondary zones on SIGHUP (pma) */
+#define SLAVE_FORWARD /* use sensible timeouts on slave forwarders (pma) */
+#define WANT_PIDFILE /* if you want the named.pid file (ucb/arc) */
+#define DOTTED_SERIAL /* if you want to be able to specify dotted serial#s */
+/*#define SENSIBLE_DOTS /* if you want dotted serial#s to make numeric sense */
+#define NCACHE /* negative caching (anant@isi.edu) */
+/*#define VALIDATE /* validation procedure (anant@isi.edu) (BUGGY!) */
+/*#define SHORT_FNAMES /* file names used in named-xfer need to be short */
+#define RESOLVSORT /* allow sorting of addresses in gethostbyname (mpa) */
+#define STUBS /* allow transfers of NS only for a zone (mpa) */
+#ifndef LOGFAC
+#define LOGFAC LOG_DAEMON /* what syslog facility should named use? */
+#endif
+#define SECURE_ZONES /* if you want to inhibit world access to zones (gns)*/
+#define ROUND_ROBIN /* rotate databuf list after each access (mtr) */
+#define ADDAUTH /* return NS and glue w/ authorative answers (mpa) */
+#define RFC1535 /* use RFC 1535 default for "search" list (vix) */
+#define GEN_AXFR /* distinct zones within each class */
+#define DATUMREFCNT /* use reference counts on datums (mpa) */
+#define LAME_DELEGATION /* lame delegations (original-del,reworked-bb&del)*/
+#define LAME_LOGGING LOG_WARNING /* log lame delegations, set log level */
+#define GETSER_LOGGING LOG_INFO /* log errors/timeouts getting serial number */
+/*#define RETURNSOA /* good code that the world isn't ready for yet */
+#define CLEANCACHE /* useful and necessary in the face of NCACHE */
+#define PURGE_ZONE /* remove all traces of a zone when reloading (mpa) */
+/*#define STATS /* keep nameserver statistics; uses more memory */
+#define RENICE /* named-xfer should run at normal priority */
+/*#define XSTATS /* extended statistics, syslogged periodically (bg) */
+/*#define BIND_NOTIFY /* experimental - do not enable in customer products */
+#define LOC_RR /* support for (draft) LOC record parsing (ckd) */
+#define SORT_RESPONSE /* should we try to sort responses optimally? (vix) */
+
+/*--------------------------------------------*
+ * no user-servicable parts beyond this point *
+ *--------------------------------------------*/
+
+/* if DSTORAGE is defined, we need to disable DMALLOC and remap
+ * malloc and free to storage.o's exported names. storage.o also
+ * includes a calloc and a realloc, but once we drag in its malloc
+ * and free we'll get the others automatically and so will never
+ * pull in those routines from libc.a.
+ */
+#ifdef DSTORAGE
+# ifdef DMALLOC
+# undef DMALLOC
+# endif /*DMALLOC*/
+# define malloc rt_malloc
+# define free rt_free
+#endif /*DSTORAGE*/
+
+/* if DMALLOC is defined, grab the header file which will remap
+ * all the malloc-style names to those exported by dmalloc.o. note
+ * that DMALLOC also changes the function signatures of several
+ * functions in private named source modules, and that this file
+ * (options.h) must be included before any other private *.h files
+ * since those *.h files have some conditional remapping to do.
+ */
+#ifdef DMALLOC
+# include "dmalloc.h"
+#endif
+
+/* systems with killall(1M) don't need this
+ */
+#ifdef __sgi
+# ifdef WANT_PIDFILE
+# undef WANT_PIDFILE
+# endif
+#endif
+
+#ifdef LAME_LOGGING
+# define LAME_DELEGATION
+#endif
+
+#if defined(XSTATS) && !defined(STATS)
+# define STATS
+#endif
diff --git a/usr.sbin/named/conf/portability.h b/usr.sbin/named/conf/portability.h
new file mode 100644
index 00000000000..3cfc15ae4c9
--- /dev/null
+++ b/usr.sbin/named/conf/portability.h
@@ -0,0 +1,569 @@
+/* $NetBSD: portability.h,v 1.1 1996/02/02 15:26:12 mrg Exp $ */
+
+/* portability.h - include or define things that aren't present on all systems
+ * vixie@decwrl 26dec92 [new]
+ *
+ * $Id: portability.h,v 8.11 1995/12/22 10:20:19 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--
+ */
+
+/* XXX: this file has become a hopeless morass, and will be redone someday. */
+
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#ifndef TIME_H_INCLUDED
+# include <sys/time.h>
+# define TIME_H_INCLUDED
+#endif
+
+#ifdef ISC
+# ifndef _POSIX_SOURCE
+# define _POSIX_SOURCE
+# endif
+# define SYSV
+# define SVR3
+# define _SYSV3
+# define NEED_STRTOUL
+# define NEED_FTRUNCATE
+# define USE_POSIX
+# include <sys/bsdtypes.h>
+# include <sys/sioctl.h>
+# include <sys/stream.h>
+# include <net/errno.h>
+#endif
+
+#if defined(__convex__)
+# if !defined(_POSIX_SOURCE)
+# define _POSIX_SOURCE
+# endif
+# define USE_UTIME
+# define NEED_PUTENV
+#endif
+
+#if defined(_CRAY)
+# if !defined(_POSIX_SOURCE)
+# define _POSIX_SOURCE
+# endif
+# define writev(a,b,c) __writev(a,b,c)
+# define setitimer(a,b,c) __setitimer(a,b,c)
+#endif
+
+/* This is defined in the Makefile for ISC compiles. */
+#if defined(ISC)
+# define ftruncate(a,b) __ftruncate(a,b)
+# define USE_MEMCPY
+# define USE_UTIME
+# define HAVE_FCHMOD 0
+#endif
+
+/* SCO UNIX defines only this unique symbol, apparently. */
+#if defined(M_UNIX)
+/* XXX - why is this POSIX_SOURCE instead of _POSIX_SOURCE? */
+# undef POSIX_SOURCE
+# define POSIX_SIGNALS
+# define HAVE_FCHMOD 0
+# define writev(a,b,c) __writev(a,b,c)
+# define ftruncate(a,b) __ftruncate(a,b)
+#endif
+
+#ifdef NeXT
+# define NEED_PUTENV
+# define NEED_SETENV
+# define inet_addr(a) __inet_addr(a)
+#endif
+
+#if defined(__sgi)
+# define BSD 43
+# define vfork fork
+#endif
+
+#if defined(SUNOS4)
+# define BSD 43
+#endif
+
+#if defined(__osf__) && defined(__alpha)
+# undef BSD
+# define BSD 199103
+#endif
+
+#if defined(_AUX_SOURCE)
+# define vfork fork
+# define NEED_STRERROR
+# define NEED_STRTOUL
+# define SIG_FN void
+# define USE_MEMCPY
+#endif
+
+
+#if defined(SVR4) && !defined(SYSV)
+# define SYSV
+#endif
+
+#if defined(_POSIX_SOURCE) || defined(__sgi) || defined(__ultrix) || \
+ defined(__hpux) || (defined(BSD) && (BSD >= 199103)) || \
+ (defined(sun) && defined(SYSV))
+# define USE_POSIX
+#endif
+
+#if defined(__ultrix) && !defined(BSD)
+# define BSD 42
+#endif
+
+#if defined(host_mips) && defined(SYSTYPE_BSD43)
+# define RISCOS_BSD
+#endif
+
+#if defined(SYSV) || defined(__ultrix) || defined(__osf__) \
+ || (defined(BSD) && BSD >= 199306) || defined(linux)
+# define USE_UTIME
+# define HAVE_SETVBUF
+#endif
+
+#if defined(SYSV) && !defined(SVR4)
+# define vfork fork
+#endif
+
+#if defined(sun) || defined(SVR4)
+# define NETREAD_BROKEN
+#endif
+
+#if defined(BSD) && BSD >= 199006 && !defined(i386) && !defined(RISCOS_BSD)
+# define HAVE_DAEMON
+#endif
+
+#if !defined(BSD) || (BSD <= 199006)
+# if !defined(NeXT)
+# define NEED_INETADDR
+# endif
+# define NEED_INETATON
+#endif
+
+#if defined(__hpux)
+# if defined(__STDC__)
+# define select(a,b,c,d,e) select(a, (int *)b, (int *)c, (int *)d, e)
+# define ctime(x) ctime((const time_t *)x)
+# endif /*__STDC__*/
+# if !defined(SYSV)
+# define USE_UTIME
+# define setlinebuf(x) setvbuf(x, NULL, _IOLBF, BUFSIZ)
+# if !defined(SIGWINCH) /*pre 9.0*/
+# define SIGWINCH SIGWINDOW
+# endif
+# endif /*SYSV*/
+/* XXX: better autodetection of the need for "struct linger" would be nice */
+# if 0
+struct linger {
+ int l_onoff; /* option on/off */
+ int l_linger; /* linger time */
+};
+# endif
+#endif /*__hpux*/
+
+#if defined(_SEQUENT_)
+# include <netinet/in_systm.h>
+# define USE_UTIME
+# define USE_POSIX
+# define NEED_GETTIMEOFDAY
+# define _TIMEZONE timezoneBSD
+struct timezoneBSD {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+#endif
+
+#ifndef __P
+# if defined(__STDC__) || defined(__GNUC__)
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+#ifndef _TIMEZONE
+# define _TIMEZONE timezone
+#endif
+
+#if defined(USE_POSIX)
+# include <stdlib.h>
+# include <unistd.h>
+# include <limits.h>
+
+#else
+
+# define NEED_STRTOUL
+
+# define STDIN_FILENO 0
+# define STDOUT_FILENO 1
+# define STDERR_FILENO 2
+# ifndef NeXT
+extern char *getenv __P((char *));
+# else
+extern char *getenv __P((const char *));
+# endif
+extern int errno;
+
+# if !defined(DMALLOC) && !defined(NeXT)
+extern char *malloc(), *realloc(), *calloc();
+# if defined(sun)
+extern int free();
+# else
+extern void free();
+# endif
+# endif
+
+extern int getdtablesize __P((void));
+# ifdef SHORT_FNAMES
+extern long pathconf __P((const char *path, int name));
+# endif
+
+#endif /*USE_POSIX*/
+
+#ifndef UINT_MAX
+# ifdef __STDC__
+# define UINT_MAX 4294967295u /* max value of an "u_int" */
+# else
+# define UINT_MAX ((unsigned)4294967295) /* max value of an "u_int" */
+# endif
+# define ULONG_MAX UINT_MAX /* max decimal value of a "u_long" */
+#endif
+
+#ifndef INT_MAX
+# define INT_MAX 2147483647 /* max decimal value of an "int" */
+#endif
+
+#ifndef RAND_MAX
+# define RAND_MAX 0x7fffffff
+#endif
+
+#ifndef IN_LOOPBACKNET
+# define IN_LOOPBACKNET 127
+#endif
+
+#ifndef INADDR_NONE
+# define INADDR_NONE 0xffffffff
+#endif
+
+#if defined(apollo)
+ /* Defined in /usr/include/netinet/in.h but doesn't work */
+#undef IP_OPTIONS
+#endif
+
+#if !defined(__STDC__) && !defined(const)
+# define const /*constant*/
+#endif
+
+#if !defined(__convex__) && (!defined(BSD) || (BSD < 199103))
+int strcasecmp __P((const char *, const char *));
+#endif
+
+/* is USE_POSIX the right thing to use here? */
+#if (!defined(BSD) || (BSD <= 43)) && \
+ !defined(NeXT) && \
+ !defined(__convex__) && \
+ !defined(USE_POSIX)
+# if !defined(NCR)
+extern void syslog();
+# endif
+extern char *ctime __P((const time_t *clock));
+extern int close(), setitimer(), recv(), sendto(), sigsetmask(),
+ atoi(), getpid(), fork(), read(), ioctl(),
+ setsockopt(), socket(), bind();
+#endif
+
+#if !defined(bcopy) /* some machines have their own macros for this */
+# if defined(USE_POSIX) || \
+ (defined(__STDC__) && !defined(sun) && !defined(sequent) \
+ && !defined(M_UNIX))
+/* use ANSI C3.159-1989 (``ANSI C'') functions if possible;
+ * ideally we would change the code to use them and then
+ * define them in terms of bcopy et al if !defined(__STDC__)
+ * but that's more work.
+ */
+#if defined(USE_MEMCPY)
+# define bcopy(a,b,c) memcpy(b,a,c)
+#else
+# define bcopy(a,b,c) memmove(b,a,c)
+#endif
+# define bzero(a,b) memset(a,0,b)
+# define bcmp(a,b,c) memcmp(a,b,c)
+# else
+extern void bcopy();
+extern void bzero();
+extern int bcmp();
+# endif /* BSD */
+#endif /* bcopy */
+
+#if (!defined(BSD) || (BSD < 43) || defined(RISCOS_BSD)) \
+ && !defined(USE_POSIX) && !defined(apollo) && !defined(sequent) \
+ && !defined(M_UNIX)
+# define NEED_STRERROR
+#if !defined(ultrix) && !defined(NCR)
+# define NEED_PUTENV
+#endif
+#endif
+
+#if defined(SUNOS4)
+# define NEED_STRERROR
+# if defined(sun386)
+# define pid_t int
+# define NEED_STRCASECMP
+# endif
+#endif
+
+#if (!defined(BSD) || (BSD < 43))
+# define NEED_MKSTEMP
+# if !defined(__ultrix) && !defined(apollo)
+# define NEED_STRCASECMP
+# define NEED_MKTEMP
+# if !defined(SVR4)
+# define NEED_STRPBRK
+# endif
+# endif
+#endif
+
+#if defined(USE_POSIX)
+# define POSIX_SIGNALS
+#endif
+
+/*
+ * Attempt to configure for type of function returned by signal-catching
+ * functions (which signal and sigvec.sv_handler take a pointer to).
+ * This can guess for BSD; otherwise, define SIG_FN externally.
+ */
+#ifndef SIG_FN
+# ifdef BSD
+# if (BSD >= 199006) || defined(NeXT) || defined(__osf__) || defined(sun) \
+ || defined(__ultrix) || defined(apollo) || defined(POSIX_SIGNALS)
+# define SIG_FN void /* signal-catching functions return void */
+# else
+# define SIG_FN int /* signal-catching functions return int */
+# endif
+# else /*BSD*/
+# define SIG_FN void /* signal-catching functions return void */
+# endif /*BSD*/
+#endif
+
+#if !defined(SIGUSR1) && !defined(SIGUSR2)
+# define SIGUSR1 SIGEMT
+# define SIGUSR2 SIGFPE
+#endif
+#if !defined(SIGCHLD)
+# define SIGCHLD SIGCLD
+#endif
+
+#if !defined(ntohl) && !defined(htonl) && defined(BSD) && (BSD <= 43)
+/* if these aren't null macros in netinet/in.h, extern them here. */
+extern u_short htons(), ntohs();
+extern u_long htonl(), ntohl();
+#endif
+
+#if defined(USE_POSIX) && !defined(sun) && !defined(__sgi) \
+ && !defined(__convex__) && !defined(__ultrix) && !defined(_AUX_SOURCE)
+# define PORT_NONBLOCK O_NONBLOCK
+# define PORT_WOULDBLK EAGAIN
+#else
+# define PORT_NONBLOCK O_NDELAY
+# define PORT_WOULDBLK EWOULDBLOCK
+#endif
+
+#if defined(USE_POSIX)
+# define USE_SETSID
+#endif
+
+#if defined(USE_POSIX) || !defined(SYSV)
+#define USE_WAITPID
+#endif
+
+#if !defined(USE_POSIX)
+#define waitpid(x,y,z) (wait3(y,z,(struct rusage *)NULL))
+#endif
+
+#if defined(NeXT) || defined(_AIX) || defined(sun386)
+# undef WIFEXITED
+# undef WEXITSTATUS
+# undef WIFSIGNALED
+# undef WTERMSIG
+#endif /* NeXT */
+
+#if defined(sequent)
+#define WEXITSTATUS(x) ((x).w_retcode)
+#define WTERMSIG(x) ((x).w_termsig)
+#endif /* sequent */
+
+#if !defined(WIFEXITED)
+# define WIFEXITED(x) (!(x & 0177))
+#endif
+#if !defined(WEXITSTATUS)
+# define WEXITSTATUS(x) (x >> 8)
+#endif
+#if !defined(WIFSIGNALED)
+# define WIFSIGNALED(x) ((x & 0177) && ((x & 0377) != 0177))
+#endif
+#if !defined(WTERMSIG)
+# define WTERMSIG(x) (x & 0177)
+#endif
+
+#ifndef S_ISDIR
+# ifndef S_IFMT
+# define S_IFMT 0170000
+# endif
+# ifndef S_IFDIR
+# define S_IFDIR 0040000
+# endif
+# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
+#endif
+
+#ifndef S_ISREG
+# ifndef S_IFMT
+# define S_IFMT 0170000
+# endif
+# ifndef S_IFREG
+# define S_IFREG 0100000
+# endif
+# define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
+#endif
+
+#ifndef S_ISFIFO
+# ifndef S_IFMT
+# define S_IFMT 0170000
+# endif
+# ifndef S_IFIFO
+# define S_IFIFO 0010000
+# endif
+# define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO)
+#endif
+
+#if defined(NEED_STRTOUL) && \
+ (defined(__ultrix) || defined(__osf__) || defined(NeXT))
+# undef NEED_STRTOUL
+#endif
+
+#if defined(__ultrix) || defined(__osf__)
+# define MAYBE_HESIOD
+#endif
+
+#ifndef FD_SET
+#define NFDBITS 32
+#define FD_SETSIZE 32
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
+#endif
+
+#ifndef MIN
+# define MIN(x, y) ((x > y) ?y :x)
+#endif
+#ifndef MAX
+# define MAX(x, y) ((x > y) ?x :y)
+#endif
+
+#if !defined(PATH_MAX)
+# if defined(_POSIX_PATH_MAX)
+# define PATH_MAX _POSIX_PATH_MAX
+# else
+# if defined(MAXPATHLEN)
+# define PATH_MAX MAXPATHLEN
+# endif
+# endif
+#endif
+
+#if defined(BSD) || defined(__osf__) || defined(__convex__)
+# define HAVE_GETRUSAGE
+#endif
+
+/* May be set in the Makefile. */
+#if defined(HAVE_GETRUSAGE)
+# include <sys/resource.h>
+#endif
+
+/*
+ * Because Convex has true library function feof() which is
+ * patently wrong (it test bit _IOREAD) we need feof() as
+ * a macro.
+ */
+#if defined(__convex__) && !defined(feof)
+# define feof(p) ((p)->_flag&_IOEOF)
+#endif
+
+#if defined(M_UNIX) || defined(linux)
+# define SPURIOUS_ECONNREFUSED
+#endif
+
+/*
+ * Assume that a system has fchmod() unless something above says otherwise.
+ */
+#if !defined(HAVE_FCHMOD)
+# define HAVE_FCHMOD 1
+#endif
+
+/*
+ * Prototype the functions we'll be supplying.
+ */
+#ifdef NEED_PUTENV
+extern int putenv __P((char *));
+#endif
+
+#ifdef NEED_GETTIMEOFDAY
+extern int gettimeofday __P((struct timeval *, struct _TIMEZONE *));
+#endif
+
+#if defined(SVR4) && defined(sun)
+extern int gethostname __P((char *, size_t));
+#endif
diff --git a/usr.sbin/named/dig/Makefile b/usr.sbin/named/dig/Makefile
new file mode 100644
index 00000000000..4c8e492136d
--- /dev/null
+++ b/usr.sbin/named/dig/Makefile
@@ -0,0 +1,12 @@
+# $NetBSD: Makefile,v 1.1 1996/02/02 15:26:15 mrg Exp $
+# from: $Id: Makefile,v 8.1 1994/12/15 06:23:45 vixie Exp
+
+.PATH: ${.CURDIR}/../nslookup \
+ ${.CURDIR}/../man
+
+PROG= dig
+SRCS= dig.c list.c subr.c debug.c send.c
+CFLAGS+= -I${.CURDIR}/..
+
+.include <bsd.prog.mk>
+.include "../../Makefile.inc"
diff --git a/usr.sbin/named/dig/debug.o b/usr.sbin/named/dig/debug.o
new file mode 100644
index 00000000000..b7a9c922b3e
--- /dev/null
+++ b/usr.sbin/named/dig/debug.o
Binary files differ
diff --git a/usr.sbin/named/dig/dig b/usr.sbin/named/dig/dig
new file mode 100644
index 00000000000..5ee6a7d0c49
--- /dev/null
+++ b/usr.sbin/named/dig/dig
Binary files differ
diff --git a/usr.sbin/named/dig/dig.c b/usr.sbin/named/dig/dig.c
new file mode 100644
index 00000000000..25afd2a56fb
--- /dev/null
+++ b/usr.sbin/named/dig/dig.c
@@ -0,0 +1,1212 @@
+/* $NetBSD: dig.c,v 1.1 1996/02/02 15:26:18 mrg Exp $ */
+
+#ifndef lint
+static char rcsid[] = "$Id: dig.c,v 8.6 1995/12/29 21:08:13 vixie Exp ";
+#endif
+
+/*
+ * ++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--
+ */
+
+/*********************** Notes for the BIND 4.9 release (Paul Vixie, DEC)
+ * dig 2.0 was written by copying sections of libresolv.a and nslookup
+ * and modifying them to be more useful for a general lookup utility.
+ * as of BIND 4.9, the changes needed to support dig have mostly been
+ * incorporated into libresolv.a and nslookup; dig now links against
+ * some of nslookup's .o files rather than #including them or maintaining
+ * local copies of them. in some sense, dig belongs in the nslookup
+ * subdirectory rather than up here in "tools", but that's for arc@sgi.com
+ * (owner of nslookup) to decide.
+ *
+ * while merging dig back into the BIND release, i made a number of
+ * structural changes. for one thing, i put all of dig's private
+ * library routines into this file rather than maintaining them in
+ * separate, #included, files. i don't like to #include ".c" files.
+ * i removed all calls to "bcopy", replacing them with structure
+ * assignments. i removed all "extern"'s of standard functions,
+ * replacing them with #include's of standard header files. this
+ * version of dig is probably as portable as the rest of BIND.
+ *
+ * i had to remove the query-time and packet-count statistics since
+ * the current libresolv.a is a lot harder to modify to maintain these
+ * than the 4.8 one (used in the original dig) was. for consolation,
+ * i added a "usage" message with extensive help text.
+ *
+ * to save my (limited, albeit) sanity, i ran "indent" over the source.
+ * i also added the standard berkeley/DEC copyrights, since this file now
+ * contains a fair amount of non-USC code. note that the berkeley and
+ * DEC copyrights do not prohibit redistribution, with or without fee;
+ * we add them only to protect ourselves (you have to claim copyright
+ * in order to disclaim liability and warranty).
+ *
+ * Paul Vixie, Palo Alto, CA, April 1993
+ ****************************************************************************
+
+ /*******************************************************************
+ ** DiG -- Domain Information Groper **
+ ** **
+ ** dig.c - Version 2.1 (7/12/94) ("BIND takeover") **
+ ** **
+ ** Developed by: Steve Hotz & Paul Mockapetris **
+ ** USC Information Sciences Institute (USC-ISI) **
+ ** Marina del Rey, California **
+ ** 1989 **
+ ** **
+ ** dig.c - **
+ ** Version 2.0 (9/1/90) **
+ ** o renamed difftime() difftv() to avoid **
+ ** clash with ANSI C **
+ ** o fixed incorrect # args to strcmp,gettimeofday **
+ ** o incorrect length specified to strncmp **
+ ** o fixed broken -sticky -envsa -envset functions **
+ ** o print options/flags redefined & modified **
+ ** **
+ ** Version 2.0.beta (5/9/90) **
+ ** o output format - helpful to `doc` **
+ ** o minor cleanup **
+ ** o release to beta testers **
+ ** **
+ ** Version 1.1.beta (10/26/89) **
+ ** o hanging zone transer (when REFUSED) fixed **
+ ** o trailing dot added to domain names in RDATA **
+ ** o ISI internal **
+ ** **
+ ** Version 1.0.tmp (8/27/89) **
+ ** o Error in prnttime() fixed **
+ ** o no longer dumps core on large pkts **
+ ** o zone transfer (axfr) added **
+ ** o -x added for inverse queries **
+ ** (i.e. "dig -x 128.9.0.32") **
+ ** o give address of default server **
+ ** o accept broadcast to server @255.255.255.255 **
+ ** **
+ ** Version 1.0 (3/27/89) **
+ ** o original release **
+ ** **
+ ** DiG is Public Domain, and may be used for any purpose as **
+ ** long as this notice is not removed. **
+ **** ****
+ **** NOTE: Version 2.0.beta is not for public distribution ****
+ **** ****
+ *******************************************************************/
+
+
+#define VERSION 21
+#define VSTRING "2.1"
+
+#include <sys/types.h>
+#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 <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <netdb.h>
+#include <stdio.h>
+#include <resolv.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <setjmp.h>
+#include <fcntl.h>
+
+#include "nslookup/res.h"
+#include "../conf/portability.h"
+
+#define PRF_DEF 0x2ff9
+#define PRF_MIN 0xA930
+#define PRF_ZONE 0x24f9
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+int eecode = 0;
+
+FILE *qfp;
+int sockFD;
+
+#define SAVEENV "DiG.env"
+#define DIG_MAXARGS 30
+
+char *defsrv, *srvmsg;
+char defbuf[40] = "default -- ";
+char srvbuf[60];
+
+static void Usage();
+static int SetOption(), printZone(), printRR();
+static struct timeval difftv();
+static void prnttime();
+
+/* stuff for nslookup modules */
+FILE *filePtr;
+jmp_buf env;
+HostInfo *defaultPtr = NULL;
+HostInfo curHostInfo, defaultRec;
+int curHostValid = FALSE;
+int queryType, queryClass;
+extern int StringToClass(), StringToType(); /* subr.c */
+#if defined(BSD) && BSD >= 199006 && !defined(RISCOS_BSD)
+FILE *yyin = NULL;
+void yyrestart(f) { }
+#endif
+char *pager = NULL;
+/* end of nslookup stuff */
+
+ /*
+ ** Take arguments appearing in simple string (from file or command line)
+ ** place in char**.
+ */
+stackarg(y, l)
+ char *l;
+ char **y;
+{
+ int done=0;
+ while (!done) {
+ switch (*l) {
+ case '\t':
+ case ' ':
+ l++; break;
+ case '\0':
+ case '\n':
+ done++;
+ *y = NULL;
+ break;
+ default:
+ *y++=l;
+ while (!isspace(*l))
+ l++;
+ if (*l == '\n')
+ done++;
+ *l++ = '\0';
+ *y = NULL;
+ }
+ }
+}
+
+char myhostname[MAXHOSTNAMELEN];
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct hostent *hp;
+ short port = htons(NAMESERVER_PORT);
+ /* Wierd stuff for SPARC alignment, hurts nothing else. */
+ union {
+ HEADER header_;
+ u_char packet_[PACKETSZ];
+ } packet_;
+#define packet (packet_.packet_)
+ u_char answer[8*1024];
+ int n;
+ char doping[90];
+ char pingstr[50];
+ char *afile;
+ char *addrc, *addrend, *addrbegin;
+
+ struct timeval exectime, tv1, tv2, start_time, end_time, query_time;
+
+ char *srv;
+ int anyflag = 0;
+ int sticky = 0;
+ int tmp;
+ int qtypeSet;
+ int addrflag = 0;
+ int zone = 0;
+ int bytes_out, bytes_in;
+
+ char cmd[256];
+ char domain[MAXDNAME];
+ char msg[120], *msgptr;
+ char **vtmp;
+ char *args[DIG_MAXARGS];
+ char **ax;
+ char **ay;
+ int once = 1, dofile = 0; /* batch -vs- interactive control */
+ char fileq[100];
+ char *qptr;
+ int fp;
+ int wait=0, delay;
+ int envset=0, envsave=0;
+ struct __res_state res_x, res_t;
+ char *pp;
+ time_t t;
+
+ res_init();
+ _res.pfcode = PRF_DEF;
+ qtypeSet = 0;
+ bzero(domain, (sizeof domain));
+ gethostname(myhostname, (sizeof myhostname));
+ defsrv = strcat(defbuf, inet_ntoa(_res.nsaddr.sin_addr));
+ res_x = _res;
+
+ /*
+ ** If LOCALDEF in environment, should point to file
+ ** containing local favourite defaults. Also look for file
+ ** DiG.env (i.e. SAVEENV) in local directory.
+ */
+
+ if ((((afile = (char *) getenv("LOCALDEF")) != (char *) NULL) &&
+ ((fp = open(afile, O_RDONLY)) > 0)) ||
+ ((fp = open(SAVEENV, O_RDONLY)) > 0)) {
+ read(fp, (char *)&res_x, (sizeof res_x));
+ close(fp);
+ _res = res_x;
+ }
+ /*
+ ** check for batch-mode DiG; also pre-scan for 'help'
+ */
+ vtmp = argv;
+ ax = args;
+ while (*vtmp != NULL) {
+ if (strcmp(*vtmp, "-h") == 0 ||
+ strcmp(*vtmp, "-help") == 0 ||
+ strcmp(*vtmp, "-usage") == 0 ||
+ strcmp(*vtmp, "help") == 0) {
+ Usage();
+ exit(0);
+ }
+
+ if (strcmp(*vtmp, "-f") == 0) {
+ dofile++; once=0;
+ if ((qfp = fopen(*++vtmp, "r")) == NULL) {
+ fflush(stdout);
+ perror("file open");
+ fflush(stderr);
+ exit(10);
+ }
+ } else {
+ if (ax - args == DIG_MAXARGS) {
+ fprintf(stderr, "dig: too many arguments\n");
+ exit(10);
+ }
+ *ax++ = *vtmp;
+ }
+ vtmp++;
+ }
+
+ _res.id = 1;
+ gettimeofday(&tv1, NULL);
+
+ /*
+ ** Main section: once if cmd-line query
+ ** while !EOF if batch mode
+ */
+ *fileq = '\0';
+ while ((dofile && (fgets(fileq,100,qfp) != NULL)) ||
+ ((!dofile) && (once--)))
+ {
+ if ((*fileq=='\n') || (*fileq=='#') || (*fileq==';')) {
+ continue; /* ignore blank lines & comments */
+ }
+
+/*
+ * "sticky" requests that before current parsing args
+ * return to current "working" environment (X******)
+ */
+ if (sticky) {
+ printf(";; (using sticky settings)\n");
+ _res = res_x;
+ }
+
+/* concat cmd-line and file args */
+ ay = ax;
+ qptr = fileq;
+ stackarg(ay, qptr);
+
+ /* defaults */
+ queryType = T_NS;
+ queryClass = C_IN;
+ zone = 0;
+ *pingstr = 0;
+ srv = NULL;
+
+ sprintf(cmd,"\n; <<>> DiG %s <<>> ",VSTRING);
+ argv = args;
+ argc = ax - args;
+/*
+ * More cmd-line options than anyone should ever have to
+ * deal with ....
+ */
+ while (*(++argv) != NULL && **argv != '\0') {
+ strcat(cmd,*argv); strcat(cmd," ");
+ if (**argv == '@') {
+ srv = (*argv+1);
+ continue;
+ }
+ if (**argv == '%')
+ continue;
+ if (**argv == '+') {
+ SetOption(*argv+1);
+ continue;
+ }
+
+ if (strncmp(*argv,"-nost",5) == 0) {
+ sticky = 0;
+ continue;
+ } else if (strncmp(*argv,"-st",3) == 0) {
+ sticky++;
+ continue;
+ } else if (strncmp(*argv,"-envsa",6) == 0) {
+ envsave++;
+ continue;
+ } else if (strncmp(*argv,"-envse",6) == 0) {
+ envset++;
+ continue;
+ }
+
+ if (**argv == '-') {
+ switch (argv[0][1]) {
+ case 'T': wait = atoi(*++argv);
+ break;
+ case 'c':
+ if ((tmp = atoi(*++argv))
+ || *argv[0]=='0') {
+ queryClass = tmp;
+ } else if (tmp = StringToClass(*argv,
+ 0, NULL)
+ ) {
+ queryClass = tmp;
+ } else {
+ printf(
+ "; invalid class specified\n"
+ );
+ }
+ break;
+ case 't':
+ if ((tmp = atoi(*++argv))
+ || *argv[0]=='0') {
+ queryType = tmp;
+ qtypeSet++;
+ } else if (tmp = StringToType(*argv,
+ 0, NULL)
+ ) {
+ queryType = tmp;
+ qtypeSet++;
+ } else {
+ printf(
+ "; invalid type specified\n"
+ );
+ }
+ break;
+ case 'x':
+ if (!qtypeSet) {
+ queryType = T_ANY;
+ qtypeSet++;
+ }
+ if (!(addrc = *++argv)) {
+ printf(
+ "; no arg for -x?\n"
+ );
+ break;
+ }
+ addrend = addrc + strlen(addrc);
+ if (*addrend == '.')
+ *addrend = '\0';
+ *domain = '\0';
+ while (addrbegin = strrchr(addrc,'.')) {
+ strcat(domain, addrbegin+1);
+ strcat(domain, ".");
+ *addrbegin = '\0';
+ }
+ strcat(domain, addrc);
+ strcat(domain, ".in-addr.arpa.");
+ break;
+ case 'p': port = htons(atoi(*++argv)); break;
+ case 'P':
+ if (argv[0][2] != '\0')
+ strcpy(pingstr,&argv[0][2]);
+ else
+ strcpy(pingstr,"ping -s");
+ break;
+#if defined(__RES) && (__RES >= 19931104)
+ case 'n':
+ _res.ndots = atoi(&argv[0][2]);
+ break;
+#endif /*__RES*/
+ } /* switch - */
+ continue;
+ } /* if '-' */
+
+ if ((tmp = StringToType(*argv, -1, NULL)) != -1) {
+ if ((T_ANY == tmp) && anyflag++) {
+ queryClass = C_ANY;
+ continue;
+ }
+ if (T_AXFR == tmp) {
+ _res.pfcode = PRF_ZONE;
+ zone++;
+ } else {
+ queryType = tmp;
+ qtypeSet++;
+ }
+ } else if ((tmp = StringToClass(*argv, -1, NULL))
+ != -1) {
+ queryClass = tmp;
+ } else {
+ bzero(domain, (sizeof domain));
+ sprintf(domain,"%s",*argv);
+ }
+ } /* while argv remains */
+
+ if (_res.pfcode & 0x80000)
+ printf("; pfcode: %08x, options: %08x\n",
+ _res.pfcode, _res.options);
+
+/*
+ * Current env. (after this parse) is to become the
+ * new "working environmnet. Used in conj. with sticky.
+ */
+ if (envset) {
+ res_x = _res;
+ envset = 0;
+ }
+
+/*
+ * Current env. (after this parse) is to become the
+ * new default saved environmnet. Save in user specified
+ * file if exists else is SAVEENV (== "DiG.env").
+ */
+ if (envsave) {
+ afile = (char *) getenv("LOCALDEF");
+ if ((afile &&
+ ((fp = open(afile,
+ O_WRONLY|O_CREAT|O_TRUNC,
+ S_IREAD|S_IWRITE)) > 0))
+ ||
+ ((fp = open(SAVEENV,
+ O_WRONLY|O_CREAT|O_TRUNC,
+ S_IREAD|S_IWRITE)) > 0)) {
+ write(fp, (char *)&_res, (sizeof _res));
+ close(fp);
+ }
+ envsave = 0;
+ }
+
+ if (_res.pfcode & RES_PRF_CMD)
+ printf("%s\n", cmd);
+
+ addrflag = anyflag = 0;
+
+/*
+ * Find address of server to query. If not dot-notation, then
+ * try to resolve domain-name (if so, save and turn off print
+ * options, this domain-query is not the one we want. Restore
+ * user options when done.
+ * Things get a bit wierd since we need to use resolver to be
+ * able to "put the resolver to work".
+ */
+
+ srvbuf[0] = 0;
+ srvmsg = defsrv;
+ if (srv != NULL) {
+ struct in_addr addr;
+
+ if (inet_aton(srv, &addr)) {
+ _res.nscount = 1;
+ _res.nsaddr.sin_addr = addr;
+ srvmsg = strcat(srvbuf, srv);
+ } else {
+ res_t = _res;
+ _res.pfcode = 0;
+ _res.options = RES_DEFAULT;
+ res_init();
+ hp = gethostbyname(srv);
+ _res = res_t;
+ if (hp == NULL
+ || hp->h_addr_list == NULL
+ || *hp->h_addr_list == NULL) {
+ fflush(stdout);
+ fprintf(stderr,
+ "; Bad server: %s -- using default server and timer opts\n",
+ srv);
+ fflush(stderr);
+ srvmsg = defsrv;
+ srv = NULL;
+ } else {
+ u_int32_t **addr;
+
+ _res.nscount = 0;
+ for (addr = (u_int32_t**)hp->h_addr_list;
+ *addr && (_res.nscount < MAXNS);
+ addr++) {
+ _res.nsaddr_list[
+ _res.nscount++
+ ].sin_addr.s_addr = **addr;
+ }
+
+ srvmsg = strcat(srvbuf,srv);
+ strcat(srvbuf, " ");
+ strcat(srvmsg,
+ inet_ntoa(_res.nsaddr.sin_addr)
+ );
+ }
+ }
+ printf("; (%d server%s found)\n",
+ _res.nscount, (_res.nscount==1)?"":"s");
+ _res.id += _res.retry;
+ }
+
+ {
+ int i;
+
+ for (i = 0; i < _res.nscount; i++) {
+ _res.nsaddr_list[i].sin_family = AF_INET;
+ _res.nsaddr_list[i].sin_port = port;
+ }
+ _res.id += _res.retry;
+ }
+
+ if (zone) {
+ int i;
+
+ for (i = 0; i < _res.nscount; i++) {
+ int x = printZone(domain,
+ &_res.nsaddr_list[i]);
+ if (_res.pfcode & RES_PRF_STATS) {
+ struct timeval exectime;
+
+ gettimeofday(&exectime,NULL);
+ printf(";; FROM: %s to SERVER: %s\n",
+ myhostname,
+ inet_ntoa(_res.nsaddr_list[i]
+ .sin_addr));
+ t = exectime.tv_sec;
+ printf(";; WHEN: %s", ctime(&t));
+ }
+ if (!x)
+ break; /* success */
+ }
+ fflush(stdout);
+ continue;
+ }
+
+ if (*domain && !qtypeSet) {
+ queryType = T_A;
+ qtypeSet++;
+ }
+
+ bytes_out = n = res_mkquery(QUERY, domain,
+ queryClass, queryType,
+ NULL, 0, NULL,
+ packet, sizeof(packet));
+ if (n < 0) {
+ fflush(stderr);
+ printf(";; res_mkquery: buffer too small\n\n");
+ continue;
+ }
+ eecode = 0;
+ if (_res.pfcode & RES_PRF_HEAD1)
+ __fp_resstat(NULL, stdout);
+ (void) gettimeofday(&start_time, NULL);
+ if ((bytes_in = n = res_send(packet, n,
+ answer, sizeof(answer))) < 0) {
+ fflush(stdout);
+ n = 0 - n;
+ msg[0]=0;
+ strcat(msg,";; res_send to server ");
+ strcat(msg,srvmsg);
+ perror(msg);
+ fflush(stderr);
+
+ if (!dofile) {
+ if (eecode)
+ exit(eecode);
+ else
+ exit(9);
+ }
+ }
+ (void) gettimeofday(&end_time, NULL);
+
+ if (_res.pfcode & RES_PRF_STATS) {
+ query_time = difftv(start_time, end_time);
+ printf(";; Total query time: ");
+ prnttime(query_time);
+ putchar('\n');
+ gettimeofday(&exectime,NULL);
+ printf(";; FROM: %s to SERVER: %s\n",
+ myhostname, srvmsg);
+ t = exectime.tv_sec;
+ printf(";; WHEN: %s", ctime(&t));
+ printf(";; MSG SIZE sent: %d rcvd: %d\n",
+ bytes_out, bytes_in);
+ }
+
+ fflush(stdout);
+/*
+ * Argh ... not particularly elegant. Should put in *real* ping code.
+ * Would necessitate root priviledges for icmp port though!
+ */
+ if (*pingstr) {
+ sprintf(doping,"%s %s 56 3 | tail -3",pingstr,
+ (srv==NULL)?(defsrv+10):srv);
+ system(doping);
+ }
+ putchar('\n');
+
+/*
+ * Fairly crude method and low overhead method of keeping two
+ * batches started at different sites somewhat synchronized.
+ */
+ gettimeofday(&tv2, NULL);
+ delay = (int)(tv2.tv_sec - tv1.tv_sec);
+ if (delay < wait) {
+ sleep(wait - delay);
+ }
+ }
+ return(eecode);
+}
+
+
+static void
+Usage()
+{
+ fputs("\
+usage: dig [@server] [domain] [q-type] [q-class] {q-opt} {d-opt} [%comment]\n\
+where: server,\n\
+ domain are names in the Domain Name System\n\
+ q-class is one of (in,any,...) [default: in]\n\
+ q-type is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) [default: a]\n\
+", stderr);
+ fputs("\
+ q-opt is one of:\n\
+ -x dot-notation-address (shortcut to in-addr.arpa lookups)\n\
+ -f file (batch mode input file name)\n\
+ -T time (batch mode time delay, per query)\n\
+ -p port (nameserver is on this port) [53]\n\
+ -Pping-string (see man page)\n\
+ -t query-type (synonym for q-type)\n\
+ -c query-class (synonym for q-class)\n\
+ -envsav,-envset (see man page)\n\
+ -[no]stick (see man page)\n\
+", stderr);
+ fputs("\
+ d-opt is of the form ``+keyword=value'' where keyword is one of:\n\
+ [no]debug [no]d2 [no]recurse retry=# time=# [no]ko [no]vc\n\
+ [no]defname [no]search domain=NAME [no]ignore [no]primary\n\
+ [no]aaonly [no]sort [no]cmd [no]stats [no]Header [no]header\n\
+ [no]ttlid [no]cl [no]qr [no]reply [no]ques [no]answer\n\
+ [no]author [no]addit pfdef pfmin pfset=# pfand=# pfor=#\n\
+", stderr);
+ fputs("\
+notes: defname and search don't work; use fully-qualified names.\n\
+", stderr);
+}
+
+
+static int
+SetOption(string)
+ char *string;
+{
+ char option[NAME_LEN];
+ char type[NAME_LEN];
+ char *ptr;
+ int i;
+
+ i = sscanf(string, " %s", option);
+ if (i != 1) {
+ fprintf(stderr, ";*** Invalid option: %s\n", option);
+ return(ERROR);
+ }
+
+ if (strncmp(option, "aa", 2) == 0) { /* aaonly */
+ _res.options |= RES_AAONLY;
+ } else if (strncmp(option, "noaa", 4) == 0) {
+ _res.options &= ~RES_AAONLY;
+ } else if (strncmp(option, "deb", 3) == 0) { /* debug */
+ _res.options |= RES_DEBUG;
+ } else if (strncmp(option, "nodeb", 5) == 0) {
+ _res.options &= ~(RES_DEBUG | RES_DEBUG2);
+ } else if (strncmp(option, "ko", 2) == 0) { /* keepopen */
+ _res.options |= (RES_STAYOPEN | RES_USEVC);
+ } else if (strncmp(option, "noko", 4) == 0) {
+ _res.options &= ~RES_STAYOPEN;
+ } else if (strncmp(option, "d2", 2) == 0) { /* d2 (more debug) */
+ _res.options |= (RES_DEBUG | RES_DEBUG2);
+ } else if (strncmp(option, "nod2", 4) == 0) {
+ _res.options &= ~RES_DEBUG2;
+ } else if (strncmp(option, "def", 3) == 0) { /* defname */
+ _res.options |= RES_DEFNAMES;
+ } else if (strncmp(option, "nodef", 5) == 0) {
+ _res.options &= ~RES_DEFNAMES;
+ } else if (strncmp(option, "sea", 3) == 0) { /* search list */
+ _res.options |= RES_DNSRCH;
+ } else if (strncmp(option, "nosea", 5) == 0) {
+ _res.options &= ~RES_DNSRCH;
+ } else if (strncmp(option, "do", 2) == 0) { /* domain */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%s", _res.defdname);
+ }
+ } else if (strncmp(option, "ti", 2) == 0) { /* timeout */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%d", &_res.retrans);
+ }
+
+ } else if (strncmp(option, "ret", 3) == 0) { /* retry */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%d", &_res.retry);
+ }
+
+ } else if (strncmp(option, "i", 1) == 0) { /* ignore */
+ _res.options |= RES_IGNTC;
+ } else if (strncmp(option, "noi", 3) == 0) {
+ _res.options &= ~RES_IGNTC;
+ } else if (strncmp(option, "pr", 2) == 0) { /* primary */
+ _res.options |= RES_PRIMARY;
+ } else if (strncmp(option, "nop", 3) == 0) {
+ _res.options &= ~RES_PRIMARY;
+ } else if (strncmp(option, "rec", 3) == 0) { /* recurse */
+ _res.options |= RES_RECURSE;
+ } else if (strncmp(option, "norec", 5) == 0) {
+ _res.options &= ~RES_RECURSE;
+ } else if (strncmp(option, "v", 1) == 0) { /* vc */
+ _res.options |= RES_USEVC;
+ } else if (strncmp(option, "nov", 3) == 0) {
+ _res.options &= ~RES_USEVC;
+ } else if (strncmp(option, "pfset", 5) == 0) {
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ _res.pfcode = xstrtonum(++ptr);
+ }
+ } else if (strncmp(option, "pfand", 5) == 0) {
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ _res.pfcode = _res.pfcode & xstrtonum(++ptr);
+ }
+ } else if (strncmp(option, "pfor", 4) == 0) {
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ _res.pfcode |= xstrtonum(++ptr);
+ }
+ } else if (strncmp(option, "pfmin", 5) == 0) {
+ _res.pfcode = PRF_MIN;
+ } else if (strncmp(option, "pfdef", 5) == 0) {
+ _res.pfcode = PRF_DEF;
+ } else if (strncmp(option, "an", 2) == 0) { /* answer section */
+ _res.pfcode |= RES_PRF_ANS;
+ } else if (strncmp(option, "noan", 4) == 0) {
+ _res.pfcode &= ~RES_PRF_ANS;
+ } else if (strncmp(option, "qu", 2) == 0) { /* question section */
+ _res.pfcode |= RES_PRF_QUES;
+ } else if (strncmp(option, "noqu", 4) == 0) {
+ _res.pfcode &= ~RES_PRF_QUES;
+ } else if (strncmp(option, "au", 2) == 0) { /* authority section */
+ _res.pfcode |= RES_PRF_AUTH;
+ } else if (strncmp(option, "noau", 4) == 0) {
+ _res.pfcode &= ~RES_PRF_AUTH;
+ } else if (strncmp(option, "ad", 2) == 0) { /* addition section */
+ _res.pfcode |= RES_PRF_ADD;
+ } else if (strncmp(option, "noad", 4) == 0) {
+ _res.pfcode &= ~RES_PRF_ADD;
+ } else if (strncmp(option, "tt", 2) == 0) { /* TTL & ID */
+ _res.pfcode |= RES_PRF_TTLID;
+ } else if (strncmp(option, "nott", 4) == 0) {
+ _res.pfcode &= ~RES_PRF_TTLID;
+ } else if (strncmp(option, "he", 2) == 0) { /* head flags stats */
+ _res.pfcode |= RES_PRF_HEAD2;
+ } else if (strncmp(option, "nohe", 4) == 0) {
+ _res.pfcode &= ~RES_PRF_HEAD2;
+ } else if (strncmp(option, "H", 1) == 0) { /* header all */
+ _res.pfcode |= RES_PRF_HEADX;
+ } else if (strncmp(option, "noH", 3) == 0) {
+ _res.pfcode &= ~(RES_PRF_HEADX);
+ } else if (strncmp(option, "qr", 2) == 0) { /* query */
+ _res.pfcode |= RES_PRF_QUERY;
+ } else if (strncmp(option, "noqr", 4) == 0) {
+ _res.pfcode &= ~RES_PRF_QUERY;
+ } else if (strncmp(option, "rep", 3) == 0) { /* reply */
+ _res.pfcode |= RES_PRF_REPLY;
+ } else if (strncmp(option, "norep", 5) == 0) {
+ _res.pfcode &= ~RES_PRF_REPLY;
+ } else if (strncmp(option, "cm", 2) == 0) { /* command line */
+ _res.pfcode |= RES_PRF_CMD;
+ } else if (strncmp(option, "nocm", 4) == 0) {
+ _res.pfcode &= ~RES_PRF_CMD;
+ } else if (strncmp(option, "cl", 2) == 0) { /* class mnemonic */
+ _res.pfcode |= RES_PRF_CLASS;
+ } else if (strncmp(option, "nocl", 4) == 0) {
+ _res.pfcode &= ~RES_PRF_CLASS;
+ } else if (strncmp(option, "st", 2) == 0) { /* stats*/
+ _res.pfcode |= RES_PRF_STATS;
+ } else if (strncmp(option, "nost", 4) == 0) {
+ _res.pfcode &= ~RES_PRF_STATS;
+ } else {
+ fprintf(stderr, "; *** Invalid option: %s\n", option);
+ return(ERROR);
+ }
+ res_re_init();
+ return(SUCCESS);
+}
+
+
+
+/*
+ * Force a reinitialization when the domain is changed.
+ */
+res_re_init()
+{
+ static char localdomain[] = "LOCALDOMAIN";
+ char *buf;
+ long pfcode = _res.pfcode;
+#if defined(__RES) && (__RES >= 19931104)
+ long ndots = _res.ndots;
+#endif
+
+ /* this is ugly but putenv() is more portable than setenv() */
+ buf = malloc((sizeof localdomain) +strlen(_res.defdname) +10/*fuzz*/);
+ sprintf(buf, "%s=%s", localdomain, _res.defdname);
+ putenv(buf); /* keeps the argument, so we won't free it */
+ res_init();
+ _res.pfcode = pfcode;
+#if defined(__RES) && (__RES >= 19931104)
+ _res.ndots = ndots;
+#endif
+}
+
+
+/*
+ * convert char string (decimal, octal, or hex) to integer
+ */
+int
+xstrtonum(p)
+ char *p;
+{
+ int v = 0;
+ int i;
+ int b = 10;
+ int flag = 0;
+ while (*p != 0) {
+ if (!flag++)
+ if (*p == '0') {
+ b = 8; p++;
+ continue;
+ }
+ if (isupper(*p))
+ *p=tolower(*p);
+ if (*p == 'x') {
+ b = 16; p++;
+ continue;
+ }
+ if (isdigit(*p)) {
+ i = *p - '0';
+ } else if (isxdigit(*p)) {
+ i = *p - 'a' + 10;
+ } else {
+ fprintf(stderr,
+ "; *** Bad char in numeric string..ignored\n");
+ i = -1;
+ }
+ if (i >= b) {
+ fprintf(stderr,
+ "; *** Bad char in numeric string..ignored\n");
+ i = -1;
+ }
+ if (i >= 0)
+ v = v * b + i;
+ p++;
+ }
+ return(v);
+}
+
+/* this code was cloned from nslookup/list.c */
+
+extern char *_res_resultcodes[]; /* res_debug.c */
+
+typedef union {
+ HEADER qb1;
+ u_char qb2[PACKETSZ];
+} querybuf;
+
+static int
+printZone(zone, sin)
+ char *zone;
+ struct sockaddr_in *sin;
+{
+ querybuf buf;
+ HEADER *headerPtr;
+ int msglen;
+ int amtToRead;
+ int numRead;
+ int numAnswers = 0;
+ int result;
+ int soacnt = 0;
+ int sockFD;
+ u_short len;
+ u_char *cp, *nmp;
+ char dname[2][NAME_LEN];
+ char file[NAME_LEN];
+ static u_char *answer = NULL;
+ static int answerLen = 0;
+ enum {
+ NO_ERRORS,
+ ERR_READING_LEN,
+ ERR_READING_MSG,
+ ERR_PRINTING
+ } error = NO_ERRORS;
+
+ /*
+ * Create a query packet for the requested zone name.
+ */
+ msglen = res_mkquery(QUERY, zone, queryClass, T_AXFR, NULL,
+ 0, 0, buf.qb2, sizeof(buf));
+ if (msglen < 0) {
+ if (_res.options & RES_DEBUG) {
+ fprintf(stderr, ";; res_mkquery failed\n");
+ }
+ return (ERROR);
+ }
+
+ /*
+ * Set up a virtual circuit to the server.
+ */
+ if ((sockFD = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) {
+ int e = errno;
+ perror(";; socket");
+ return(e);
+ }
+ if (connect(sockFD, (struct sockaddr *)sin, sizeof(*sin)) < 0) {
+ int e = errno;
+ perror(";; connect");
+ (void) close(sockFD);
+ sockFD = -1;
+ return e;
+ }
+
+ /*
+ * Send length & message for zone transfer
+ */
+
+ __putshort(msglen, (u_char *)&len);
+
+ if (write(sockFD, (char *)&len, INT16SZ) != INT16SZ ||
+ write(sockFD, (char *)&buf, msglen) != msglen) {
+ int e = errno;
+ perror(";; write");
+ (void) close(sockFD);
+ sockFD = -1;
+ return(e);
+ }
+
+ dname[0][0] = '\0';
+ while (1) {
+ u_int16_t tmp;
+
+ /*
+ * Read the length of the response.
+ */
+
+ cp = (u_char *) &tmp;
+ amtToRead = INT16SZ;
+ while (amtToRead > 0 && (numRead=read(sockFD, cp, amtToRead)) > 0){
+ cp += numRead;
+ amtToRead -= numRead;
+ }
+ if (numRead <= 0) {
+ error = ERR_READING_LEN;
+ break;
+ }
+
+ if ((len = _getshort((u_char*)&tmp)) == 0) {
+ break; /* nothing left to read */
+ }
+
+ /*
+ * The server sent too much data to fit the existing buffer --
+ * allocate a new one.
+ */
+ if (len > (u_int)answerLen) {
+ if (answerLen != 0) {
+ free(answer);
+ }
+ answerLen = len;
+ answer = (u_char *)Malloc(answerLen);
+ }
+
+ /*
+ * Read the response.
+ */
+
+ amtToRead = len;
+ cp = answer;
+ while (amtToRead > 0 && (numRead=read(sockFD, cp, amtToRead)) > 0) {
+ cp += numRead;
+ amtToRead -= numRead;
+ }
+ if (numRead <= 0) {
+ error = ERR_READING_MSG;
+ break;
+ }
+
+ result = printRR(stdout, answer, cp);
+ if (result != 0) {
+ error = ERR_PRINTING;
+ break;
+ }
+
+ numAnswers++;
+ cp = answer + HFIXEDSZ;
+ if (ntohs(((HEADER *)answer)->qdcount) > 0)
+ cp += dn_skipname((u_char *)cp,
+ (u_char *)answer + len) + QFIXEDSZ;
+ nmp = cp;
+ cp += dn_skipname((u_char *)cp, (u_char *)answer + len);
+ if ((_getshort((u_char*)cp) == T_SOA)) {
+ (void) dn_expand(answer, answer + len, nmp,
+ dname[soacnt], sizeof dname[0]);
+ if (soacnt) {
+ if (strcmp(dname[0], dname[1]) == 0)
+ break;
+ } else
+ soacnt++;
+ }
+ }
+
+ fprintf(stdout, ";; Received %d record%s.\n",
+ numAnswers, (numAnswers != 1) ? "s" : "");
+
+ (void) close(sockFD);
+ sockFD = -1;
+
+ switch (error) {
+ case NO_ERRORS:
+ return (0);
+
+ case ERR_READING_LEN:
+ return(EMSGSIZE);
+
+ case ERR_PRINTING:
+ return(result);
+
+ case ERR_READING_MSG:
+ return(EMSGSIZE);
+
+ default:
+ return(EFAULT);
+ }
+}
+
+static int
+printRR(file, msg, eom)
+ FILE *file;
+ u_char *msg, *eom;
+{
+ register u_char *cp;
+ HEADER *headerPtr;
+ int type, class, dlen, nameLen;
+ u_int32_t ttl;
+ int n, pref;
+ struct in_addr inaddr;
+ char name[NAME_LEN];
+ char name2[NAME_LEN];
+ Boolean stripped;
+
+ /*
+ * Read the header fields.
+ */
+ headerPtr = (HEADER *)msg;
+ cp = msg + HFIXEDSZ;
+ if (headerPtr->rcode != NOERROR) {
+ return(headerPtr->rcode);
+ }
+
+ /*
+ * We are looking for info from answer resource records.
+ * If there aren't any, return with an error. We assume
+ * there aren't any question records.
+ */
+
+ if (ntohs(headerPtr->ancount) == 0) {
+ return(NO_INFO);
+ } else {
+ if (ntohs(headerPtr->qdcount) > 0) {
+ nameLen = dn_skipname(cp, eom);
+ if (nameLen < 0)
+ return (ERROR);
+ cp += nameLen + QFIXEDSZ;
+ }
+ cp = (u_char*) p_rr(cp, msg, stdout);
+ }
+ return(SUCCESS);
+}
+
+static
+struct timeval
+difftv(a, b)
+ struct timeval a, b;
+{
+ static struct timeval diff;
+
+ diff.tv_sec = b.tv_sec - a.tv_sec;
+ if ((diff.tv_usec = b.tv_usec - a.tv_usec) < 0) {
+ diff.tv_sec--;
+ diff.tv_usec += 1000000;
+ }
+ return(diff);
+}
+
+static
+void
+prnttime(t)
+ struct timeval t;
+{
+ printf("%u msec", t.tv_sec * 1000 + (t.tv_usec / 1000));
+}
diff --git a/usr.sbin/named/dig/dig.cat1 b/usr.sbin/named/dig/dig.cat1
new file mode 100644
index 00000000000..e9df225b97f
--- /dev/null
+++ b/usr.sbin/named/dig/dig.cat1
@@ -0,0 +1,396 @@
+
+
+
+DIG(1) DIG(1)
+
+
+NNAAMMEE
+ dig - send domain name query packets to name servers
+
+SSYYNNOOPPSSIISS
+ ddiigg [_@_s_e_r_v_e_r] _d_o_m_a_i_n [_<_q_u_e_r_y_-_t_y_p_e_>] [_<_q_u_e_r_y_-_c_l_a_s_s_>]
+ [_+_<_q_u_e_r_y_-_o_p_t_i_o_n_>] [_-_<_d_i_g_-_o_p_t_i_o_n_>] [_%_c_o_m_m_e_n_t]
+
+DDEESSCCRRIIPPTTIIOONN
+ _D_i_g (domain information groper) is a flexible command line
+ tool which can be used to gather information from the
+ Domain Name System servers. _D_i_g has two modes: simple
+ interactive mode which makes a single query, and batch
+ which executes a query for each in a list of several query
+ lines. All query options are accessible from the command
+ line.
+
+ The usual simple use of _d_i_g will take the form:
+
+ dig @server domain query-type query-class
+
+ where:
+
+ _s_e_r_v_e_r may be either a domain name or a dot-notation
+ Internet address. If this optional field is omit-
+ ted, _d_i_g will attempt to use the default name
+ server for your machine.
+
+ NNoottee:: If a domain name is specified, this will be
+ resolved using the domain name system resolver
+ (i.e., BIND). If your system does not support DNS,
+ you may _h_a_v_e to specify a dot-notation address.
+ Alternatively, if there is a server at your dis-
+ posal somewhere, all that is required is that
+ /etc/resolv.conf be present and indicate where the
+ default name servers reside, so that _s_e_r_v_e_r
+ itself can be resolved. See _r_e_s_o_l_v_e_r(5) for infor-
+ mation on /etc/resolv.conf. (WARNING: Changing
+ /etc/resolv.conf will affect the standard resolver
+ library and potentially several programs which use
+ it.) As an option, the user may set the environment
+ variable LOCALRES to name a file which is to be
+ used instead of /etc/resolv.conf (LOCALRES is spe-
+ cific to the _d_i_g resolver and not referenced by
+ the standard resolver). If the LOCALRES variable is
+ not set or the file is not readable then
+ /etc/resolv.conf will be used.
+
+ _d_o_m_a_i_n is the domain name for which you are requesting
+ information. See OPTIONS [-x] for convenient way
+ to specify inverse address query.
+
+ _q_u_e_r_y_-_t_y_p_e
+ is the type of information (DNS query type) that
+ you are requesting. If omitted, the default is "a"
+
+
+
+ August 30, 1990 1
+
+
+
+
+
+DIG(1) DIG(1)
+
+
+ (T_A = address). The following types are recog-
+ nized:
+
+ a T_A network address
+ any T_ANY all/any information about specified domain
+ mx T_MX mail exchanger for the domain
+ ns T_NS name servers
+ soa T_SOA zone of authority record
+ hinfo T_HINFO host information
+ axfr T_AXFR zone transfer
+ (must ask an authoritative server)
+ txt T_TXT arbitrary number of strings
+
+ (See RFC 1035 for the complete list.)
+
+ _q_u_e_r_y_-_c_l_a_s_s
+ is the network class requested in the query. If
+ omitted, the default is "in" (C_IN = Internet).
+ The following classes are recognized:
+
+ in C_IN Internet class domain
+ any C_ANY all/any class information
+
+ (See RFC 1035 for the complete list.)
+
+ NNoottee:: "Any" can be used to specify a class and/or a
+ type of query. _D_i_g will parse the first occurrence
+ of "any" to mean query-type = T_ANY. To specify
+ query-class = C_ANY you must either specify "any"
+ twice, or set query-class using "-c" option (see
+ below).
+
+OOTTHHEERR OOPPTTIIOONNSS
+ %ignored-comment
+ "%" is used to included an argument that is simply
+ not parsed. This may be useful if running _d_i_g in
+ batch mode. Instead of resolving every @server-
+ domain-name in a list of queries, you can avoid the
+ overhead of doing so, and still have the domain
+ name on the command line as a reference. Example:
+
+ dig @128.9.0.32 %venera.isi.edu mx
+ isi.edu
+
+
+ -<dig option>
+ "-" is used to specify an option which effects the
+ operation of _d_i_g. The following options are cur-
+ rently available (although not guaranteed to be
+ useful):
+
+ -x _d_o_t_-_n_o_t_a_t_i_o_n_-_a_d_d_r_e_s_s
+ Convenient form to specify inverse address
+ mapping. Instead of "dig 32.0.9.128.in-
+
+
+
+ August 30, 1990 2
+
+
+
+
+
+DIG(1) DIG(1)
+
+
+ addr.arpa" one can simply "dig -x
+ 128.9.0.32".
+
+ -f _f_i_l_e
+ File for _d_i_g batch mode. The file contains a
+ list of query specifications (_d_i_g command
+ lines) which are to be executed succes-
+ sively. Lines beginning with ';', '#', or
+ '\n' are ignored. Other options may still
+ appear on command line, and will be in
+ effect for each batch query.
+
+ -T _t_i_m_e
+ Time in seconds between start of successive
+ queries when running in batch mode. Can be
+ used to keep two or more batch _d_i_g commands
+ running roughly in sync. Default is zero.
+
+ -p _p_o_r_t
+ Port number. Query a name server listening
+ to a non-standard port number. Default is
+ 53.
+
+ -P[_p_i_n_g_-_s_t_r_i_n_g]
+ After query returns, execute a _p_i_n_g(8) com-
+ mand for response time comparison. This
+ rather unelegantly makes a call to the
+ shell. The last three lines of statistics is
+ printed for the command:
+
+ ping -s server_name 56 3
+
+ If the optional "ping string" is present, it
+ replaces "ping -s" in the shell command.
+
+ -t _q_u_e_r_y_-_t_y_p_e
+ Specify type of query. May specify either an
+ integer value to be included in the type
+ field or use the abbreviated mnemonic as
+ discussed above (i.e., mx = T_MX).
+
+ -c _q_u_e_r_y_-_c_l_a_s_s
+ Specify class of query. May specify either
+ an integer value to be included in the class
+ field or use the abbreviated mnemonic as
+ discussed above (i.e., in = C_IN).
+
+ -envsav
+ This flag specifies that the _d_i_g environment
+ (defaults, print options, etc.), after all
+ of the arguments are parsed, should be saved
+ to a file to become the default environment.
+ Useful if you do not like the standard set
+ of defaults and do not desire to include a
+
+
+
+ August 30, 1990 3
+
+
+
+
+
+DIG(1) DIG(1)
+
+
+ large number of options each time _d_i_g is
+ used. The environment consists of resolver
+ state variable flags, timeout, and retries
+ as well as the flags detailing _d_i_g output
+ (see below). If the shell environment vari-
+ able LOCALDEF is set to the name of a file,
+ this is where the default _d_i_g environment is
+ saved. If not, the file "DiG.env" is created
+ in the current working directory.
+
+ NNoottee:: LOCALDEF is specific to the _d_i_g
+ resolver, and will not affect operation of
+ the standard resolver library.
+
+ Each time _d_i_g is executed, it looks for
+ "./DiG.env" or the file specified by the
+ shell environment variable LOCALDEF. If such
+ file exists and is readable, then the envi-
+ ronment is restored from this file before
+ any arguments are parsed.
+
+ -envset
+ This flag only affects batch query runs.
+ When "-envset" is specified on a line in a
+ _d_i_g batch file, the _d_i_g environment after
+ the arguments are parsed, becomes the
+ default environment for the duration of the
+ batch file, or until the next line which
+ specifies "-envset".
+
+ -[no]stick
+ This flag only affects batch query runs. It
+ specifies that the _d_i_g environment (as read
+ initially or set by "-envset" switch) is to
+ be restored before each query (line) in a
+ _d_i_g batch file. The default "-nostick"
+ means that the _d_i_g environment does not
+ stick, hence options specified on a single
+ line in a _d_i_g batch file will remain in
+ effect for subsequent lines (i.e. they are
+ not restored to the "sticky" default).
+
+
+ +<query option>
+ "+" is used to specify an option to be changed in
+ the query packet or to change _d_i_g output specifics.
+ Many of these are the same parameters accepted by
+ _n_s_l_o_o_k_u_p(8). If an option requires a parameter,
+ the form is as follows:
+
+ +keyword[=value]
+
+ Most keywords can be abbreviated. Parsing of the
+ "+" options is very simplistic -- a value must
+
+
+
+ August 30, 1990 4
+
+
+
+
+
+DIG(1) DIG(1)
+
+
+ not be separated from its keyword by white space.
+ The following keywords are currently available:
+
+ Keyword Abbrev. Meaning [default]
+
+ [no]debug (deb) turn on/off debugging mode [deb]
+ [no]d2 turn on/off extra debugging mode [nod2]
+ [no]recurse (rec) use/don't use recursive lookup [rec]
+ retry=# (ret) set number of retries to # [4]
+ time=# (ti) set timeout length to # seconds [4]
+ [no]ko keep open option (implies vc) [noko]
+ [no]vc use/don't use virtual circuit [novc]
+ [no]defname (def) use/don't use default domain name [def]
+ [no]search (sea) use/don't use domain search list [sea]
+ domain=NAME (do) set default domain name to NAME
+ [no]ignore (i) ignore/don't ignore trunc. errors [noi]
+ [no]primary (pr) use/don't use primary server [nopr]
+ [no]aaonly (aa) authoritative query only flag [noaa]
+ [no]sort (sor) sort resource records [nosor]
+ [no]cmd echo parsed arguments [cmd]
+ [no]stats (st) print query statistics [st]
+ [no]Header (H) print basic header [H]
+ [no]header (he) print header flags [he]
+ [no]ttlid (tt) print TTLs [tt]
+ [no]cl print class info [nocl]
+ [no]qr print outgoing query [noqr]
+ [no]reply (rep) print reply [rep]
+ [no]ques (qu) print question section [qu]
+ [no]answer (an) print answer section [an]
+ [no]author (au) print authoritative section [au]
+ [no]addit (ad) print additional section [ad]
+ pfdef set to default print flags
+ pfmin set to minimal default print flags
+ pfset=# set print flags to #
+ (# can be hex/octal/decimal)
+ pfand=# bitwise and print flags with #
+ pfor=# bitwise or print flags with #
+
+ The retry and time options affect the retransmis-
+ sion strategy used by resolver library when sending
+ datagram queries. The algorithm is as follows:
+
+ for i = 0 to retry - 1
+ for j = 1 to num_servers
+ send_query
+ wait((time * (2**i)) / num_servers)
+ end
+ end
+
+ (Note: _d_i_g always uses a value of 1 for
+ num_servers.)
+
+DDEETTAAIILLSS
+ _D_i_g once required a slightly modified version of the BIND
+
+
+
+ August 30, 1990 5
+
+
+
+
+
+DIG(1) DIG(1)
+
+
+ _r_e_s_o_l_v_e_r(3) library. BIND's resolver has (as of BIND 4.9)
+ been augmented to work properly with _D_i_g. Essentially,
+ _D_i_g is a straight-forward (albeit not pretty) effort of
+ parsing arguments and setting appropriate parameters. _D_i_g
+ uses resolver routines res_init(), res_mkquery(),
+ res_send() as well as accessing _res structure.
+
+FFIILLEESS
+ /etc/resolv.conf initial domain name and name server
+ addresses
+
+EENNVVIIRROONNMMEENNTT
+ LOCALRES file to use in place of /etc/resolv.conf
+ LOCALDEF default environment file
+
+AAUUTTHHOORR
+ Steve Hotz hotz@isi.edu
+
+AACCKKNNOOWWLLEEDDGGMMEENNTTSS
+ _D_i_g uses functions from _n_s_l_o_o_k_u_p(8) authored by Andrew
+ Cherenson.
+
+BBUUGGSS
+ _D_i_g has a serious case of "creeping featurism" -- the
+ result of considering several potential uses during it's
+ development. It would probably benefit from a rigorous
+ diet. Similarly, the print flags and granularity of the
+ items they specify make evident their rather ad hoc gene-
+ sis.
+
+ _D_i_g does not consistently exit nicely (with appropriate
+ status) when a problem occurs somewhere in the resolver
+ (NOTE: most of the common exit cases are handled). This
+ is particularly annoying when running in batch mode. If
+ it exits abnormally (and is not caught), the entire batch
+ aborts; when such an event is trapped, _d_i_g simply contin-
+ ues with the next query.
+
+SSEEEE AALLSSOO
+ named(8), resolver(3), resolver(5), nslookup(8)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ August 30, 1990 6
+
+
diff --git a/usr.sbin/named/dig/dig.o b/usr.sbin/named/dig/dig.o
new file mode 100644
index 00000000000..d41ac47e8dc
--- /dev/null
+++ b/usr.sbin/named/dig/dig.o
Binary files differ
diff --git a/usr.sbin/named/dig/list.o b/usr.sbin/named/dig/list.o
new file mode 100644
index 00000000000..418801ff340
--- /dev/null
+++ b/usr.sbin/named/dig/list.o
Binary files differ
diff --git a/usr.sbin/named/dig/send.o b/usr.sbin/named/dig/send.o
new file mode 100644
index 00000000000..5ec66a308a5
--- /dev/null
+++ b/usr.sbin/named/dig/send.o
Binary files differ
diff --git a/usr.sbin/named/dig/subr.o b/usr.sbin/named/dig/subr.o
new file mode 100644
index 00000000000..32941f971da
--- /dev/null
+++ b/usr.sbin/named/dig/subr.o
Binary files differ
diff --git a/usr.sbin/named/dnsquery/Makefile b/usr.sbin/named/dnsquery/Makefile
new file mode 100644
index 00000000000..7ad58c12460
--- /dev/null
+++ b/usr.sbin/named/dnsquery/Makefile
@@ -0,0 +1,8 @@
+# $NetBSD: Makefile,v 1.1 1996/02/02 15:26:21 mrg Exp $
+
+.PATH: ${.CURDIR}/../man
+
+PROG= dnsquery
+
+.include <bsd.prog.mk>
+.include "../../Makefile.inc"
diff --git a/usr.sbin/named/dnsquery/dnsquery.c b/usr.sbin/named/dnsquery/dnsquery.c
new file mode 100644
index 00000000000..c6401467781
--- /dev/null
+++ b/usr.sbin/named/dnsquery/dnsquery.c
@@ -0,0 +1,234 @@
+/* $NetBSD: dnsquery.c,v 1.1 1996/02/02 15:26:24 mrg Exp $ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <errno.h>
+
+#include "../conf/portability.h"
+
+extern int errno;
+extern int h_errno;
+extern char *h_errlist[];
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char name[MAXDNAME];
+ u_char answer[8*1024];
+ register int c, i = 0;
+ unsigned long ul;
+ int nameservers = 0, class, type, len;
+ struct in_addr q_nsaddr[MAXNS];
+ struct hostent *q_nsname;
+ extern int optind, opterr;
+ extern char *optarg;
+ HEADER *hp;
+ int stream = 0, debug = 0;
+
+ /* set defaults */
+ len = MAXDNAME;
+ gethostname(name, len);
+ class = C_IN;
+ type = T_ANY;
+
+ /* if no args, exit */
+ if (argc == 1) {
+ fprintf(stderr, "Usage: %s [-h] host [-n ns] [-t type] [-c class] [-r retry] [-p period] [-s] [-v] [-d] [-a]\n", argv[0]);
+ exit(-1);
+ }
+
+ /* handle args */
+ while ((c = getopt(argc, argv, "c:dh:n:p:r:st:u:v")) != EOF) {
+ switch (c) {
+
+ case 'r' : _res.retry = atoi(optarg);
+ break;
+
+ case 'p' : _res.retrans = atoi(optarg);
+ break;
+
+ case 'h' : strcpy(name, optarg);
+ break;
+
+ case 'c' : if (!strcasecmp(optarg, "IN"))
+ class = C_IN;
+ else if (!strcasecmp(optarg, "HS"))
+ class = C_HS;
+ else if (!strcasecmp(optarg, "CHAOS"))
+ class = C_CHAOS;
+ else if (!strcasecmp(optarg, "ANY"))
+ class = C_ANY;
+ else {
+ class = T_ANY;
+ fprintf(stderr, "optarg=%s\n", optarg);
+ }
+ break;
+
+ case 't' : if (!strcasecmp(optarg, "A"))
+ type = T_A;
+ else if (!strcasecmp(optarg, "NS"))
+ type = T_NS;
+ else if (!strcasecmp(optarg, "MD"))
+ type = T_MD;
+ else if (!strcasecmp(optarg, "MF"))
+ type = T_MF;
+ else if (!strcasecmp(optarg, "CNAME"))
+ type = T_CNAME;
+ else if (!strcasecmp(optarg, "SOA"))
+ type = T_SOA;
+ else if (!strcasecmp(optarg, "MB"))
+ type = T_MB;
+ else if (!strcasecmp(optarg, "MG"))
+ type = T_MG;
+ else if (!strcasecmp(optarg, "MR"))
+ type = T_MR;
+ else if (!strcasecmp(optarg, "NULL"))
+ type = T_NULL;
+ else if (!strcasecmp(optarg, "WKS"))
+ type = T_WKS;
+ else if (!strcasecmp(optarg, "PTR"))
+ type = T_PTR;
+ else if (!strcasecmp(optarg, "HINFO"))
+ type = T_HINFO;
+ else if (!strcasecmp(optarg, "MINFO"))
+ type = T_MINFO;
+ else if (!strcasecmp(optarg, "MX"))
+ type = T_MX;
+ else if (!strcasecmp(optarg, "TXT"))
+ type = T_TXT;
+ else if (!strcasecmp(optarg, "RP"))
+ type = T_RP;
+ else if (!strcasecmp(optarg, "AFSDB"))
+ type = T_AFSDB;
+ else if (!strcasecmp(optarg, "ANY"))
+ type = T_ANY;
+ else if (!strcasecmp(optarg, "X25"))
+ type = T_X25;
+ else if (!strcasecmp(optarg, "ISDN"))
+ type = T_ISDN;
+ else if (!strcasecmp(optarg, "RT"))
+ type = T_RT;
+ else if (!strcasecmp(optarg, "NSAP"))
+ type = T_NSAP;
+ else if (!strcasecmp(optarg, "SIG"))
+ type = T_SIG;
+ else if (!strcasecmp(optarg, "KEY"))
+ type = T_KEY;
+ else if (!strcasecmp(optarg, "PX"))
+ type = T_PX;
+ else if (!strcasecmp(optarg, "GPOS"))
+ type = T_GPOS;
+ else if (!strcasecmp(optarg, "AAAA"))
+ type = T_AAAA;
+ else if (!strcasecmp(optarg, "LOC"))
+ type = T_LOC;
+ else {
+ fprintf(stderr, "Bad type (%s)\n", optarg);
+ exit(-1);
+ }
+ break;
+
+ case 'd' : debug++;
+ break;
+
+ case 's' :
+ case 'v' : stream++;
+ break;
+
+ case 'n' :
+ /*
+ * If we set some nameservers here without
+ * using gethostbyname() first, then they will
+ * get overwritten when we do the first query.
+ * So, we must init the resolver before any
+ * of this.
+ */
+ if (!(_res.options & RES_INIT))
+ if (res_init() == -1) {
+ fprintf(stderr,
+ "res_init() failed\n");
+ exit(-1);
+ }
+ if (nameservers >= MAXNS) break;
+ (void) inet_aton(optarg,
+ &q_nsaddr[nameservers]);
+ if (!inet_aton(optarg, &ul)) {
+ q_nsname = gethostbyname(optarg);
+ if (q_nsname == 0) {
+ fprintf(stderr,
+ "Bad nameserver (%s)\n",
+ optarg);
+ exit(-1);
+ }
+ bcopy((char *) q_nsname->h_addr,
+ (char *) &q_nsaddr[nameservers],
+ INADDRSZ);
+ }
+ else
+ q_nsaddr[nameservers].s_addr = ul;
+ nameservers++;
+ break;
+
+ default : fprintf(stderr,
+ "\tUsage: %s [-n ns] [-h host] [-t type] [-c class] [-r retry] [-p period] [-s] [-v] [-d] [-a]\n", argv[0]);
+ exit(-1);
+ }
+ }
+ if (optind < argc)
+ strcpy(name, argv[optind]);
+
+ len = sizeof(answer);
+
+ /*
+ * set these here so they aren't set for a possible call to
+ * gethostbyname above
+ */
+ if (debug)
+ _res.options |= RES_DEBUG;
+ if (stream)
+ _res.options |= RES_USEVC;
+
+ /* if the -n flag was used, add them to the resolver's list */
+ if (nameservers != 0) {
+ _res.nscount = nameservers;
+ for (i = nameservers - 1; i >= 0; i--) {
+ _res.nsaddr_list[i].sin_addr.s_addr = q_nsaddr[i].s_addr;
+ _res.nsaddr_list[i].sin_family = AF_INET;
+ _res.nsaddr_list[i].sin_port = htons(NAMESERVER_PORT);
+ }
+ }
+
+ /*
+ * if the -h arg is fully-qualified, use res_query() since
+ * using res_search() will lead to use of res_querydomain()
+ * which will strip the trailing dot
+ */
+ if (name[strlen(name) - 1] == '.') {
+ if (res_query(name, class, type, answer, len) < 0) {
+ hp = (HEADER *) answer;
+ if ((hp->rcode == 0) && (hp->ancount > 0))
+ __p_query(answer);
+ else
+ fprintf(stderr, "Query failed (h_errno = %d) : %s\n",
+ h_errno, h_errlist[h_errno]);
+ exit(-1);
+ }
+ }
+ else if (res_search(name, class, type, answer, len) < 0) {
+ hp = (HEADER *) answer;
+ if ((hp->rcode == 0) && (hp->ancount > 0))
+ __p_query(answer);
+ else
+ fprintf(stderr, "Query failed (h_errno = %d) : %s\n",
+ h_errno, h_errlist[h_errno]);
+ exit(-1);
+ }
+ __p_query(answer);
+ exit(0);
+}
diff --git a/usr.sbin/named/host/Makefile b/usr.sbin/named/host/Makefile
new file mode 100644
index 00000000000..abaddcbe6b5
--- /dev/null
+++ b/usr.sbin/named/host/Makefile
@@ -0,0 +1,10 @@
+# $NetBSD: Makefile,v 1.1 1996/02/02 15:26:27 mrg Exp $
+
+BINDIR=/usr/bin
+
+PROG = host
+SRCS = host.c send.c vers.c
+
+.PATH: ${.CURDIR}/../man
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/named/host/RELEASE_NOTES b/usr.sbin/named/host/RELEASE_NOTES
new file mode 100644
index 00000000000..095114f10ea
--- /dev/null
+++ b/usr.sbin/named/host/RELEASE_NOTES
@@ -0,0 +1,770 @@
+ @(#)RELEASE_NOTES e07@nikhef.nl (Eric Wassenaar) 951231
+
+yymmdd Description of changes per release
+TODO Things that still need to be done
+WISHLIST Wishes expressed by various people
+NOTES Important issues to keep in mind
+MISC Miscellaneous reminders
+
+# ----------------------------------------------------------------------
+# Description of changes per release
+# ----------------------------------------------------------------------
+
+951231
+ Cosmetic changes.
+ Print all relevant messages in debug mode to stdout,
+ and appropriately prefix them with ";; " to conform
+ with the BIND 4.9.3 conventions.
+ Miscellaneous changes.
+ Consider the all-ones broadcast address a fake address.
+
+951024
+ Avoid potential alignment conflicts.
+ Allocate socket addresses of type struct sockaddr_in
+ instead of type struct sockaddr. The first one has
+ stricter alignment restrictions, although they have
+ the same size.
+ Correct various misspellings.
+ Noted by Keith Bostic <bostic@bsdi.com>
+
+950925
+ Portability fix.
+ Refine type definitions for the arguments to various
+ resolver routines to be even more backward compatible,
+ and to avoid compilation or lint warning messages on
+ new platforms. It should run clean on BSD44 systems.
+ There are no functional changes in this release.
+
+950923
+ Add new -z option to list delegated zones in a zone.
+ This is a new variant of the zone listing specials.
+ A zone transfer is done, and only the names of the
+ encountered delegated zones are printed.
+ This option is undocumented, and subject to change.
+ Sort list of delegated zones alphabetically.
+ Before acting on delegated zones during zone listings,
+ sort them in alphabetical order for prettier output.
+ Portability fix.
+ The BIND 4.9.3 resolver routines require the passed
+ buffer arguments to be of type u_char instead of char.
+ This causes a prototype mismatch for HOST_RES_SEND.
+ Mentioned by Geert Jan de Groot <geertj@ripe.net>
+ Minor command option functionality change.
+ The -L flag, when given without any other list mode
+ option, now implies the -l option.
+ Miscellaneous code cleanup.
+ Pass the name of the actually contacted server during
+ zone listings in more elegant way.
+ Avoid (harmless) lint warnings on picky platforms.
+
+950822
+ Fix bug in recursive lookup handling.
+ During recursive lookups, e.g. when following CNAME
+ chains, querynames are always assumed to be already
+ fully qualified, and must be tried ``as is''.
+ The classical example of a CNAME that points to the
+ pseudo "localhost.", or an erroneously dot-terminated
+ single name, should not be subject to local aliasing
+ or search list processing. They were.
+ Reported by Alexander Dupuy <dupuy@smarts.com>
+
+950809
+ Portability fix.
+ Check for SVR4 as well as for SYSV in port.h, which is
+ necessary for compilation via the master BIND Makefile.
+ Suggested by <Piete.Brooks@cl.cam.ac.uk>
+ There are no functional changes in this release.
+
+950502
+ Maintain hash list for zone name lookups.
+ This should not be really necessary for most practical
+ purposes, but it makes processing of the .in-addr.arpa
+ zone and even the .COM zone at least feasible.
+ The latter still requires quite a lot of memory, and
+ some cpu time to filter out the glue records from its
+ 50000 A records and 110000 NS records.
+ The toplevel zone count as of today is:
+ COM 50000 delegated zones
+ IN-ADDR.ARPA 30000 delegated zones
+ ORG 5000 delegated zones
+ NET 3000 delegated zones
+ EDU 2000 delegated zones
+ Suppress various checks in quiet mode.
+ This avoids costly checks and achieves some speedup
+ in cases that nothing would have been printed anyway.
+ Supply alternative recv_sock() module.
+ The select() system call may fail on the solaris 2.4
+ platform without appropriate patches. An alarm can be
+ used instead, at the cost of extra system call overhead.
+
+950429
+ Fix bug in error reporting.
+ The name and address of the contacted server during
+ zone listings could be clobbered by intermediate
+ calls to res_send().
+
+950427
+ Fix glitch in host name lookup.
+ New entry would be inadvertently added to the hash
+ lish in case the MAXHOSTS limit was reached.
+ Miscellaneous changes.
+ Speedup comparison of zone names and host names by
+ looking up zone names in the host name hash list.
+
+950407
+ Maintain hash list for host name lookups.
+ A linear search through the per-zone host name table
+ becomes very costly for zones with several thousands
+ of hosts. Significant speedup is achieved.
+ Even for recursive listings of many small zones the
+ reduction of total processing time is noticeable.
+
+950318
+ Increase (static) maximum number of hosts.
+ This avoids imposing arbitrary limits in most cases.
+
+950302
+ Prevent zone transfer for certain zones.
+ Some zones are known to contain bogus information.
+ E.g. definition of A records for all possible addresses
+ in a class-B network will bias the hostcount.
+ Add new -N option to define an explicit list of zones
+ for which a zone transfer is deliberately skipped.
+ Requested by Peter Koch <pk@TechFak.Uni-Bielefeld.DE>
+ Miscellaneous code cleanup.
+ Split off various tasks from monolithic list_zone().
+ Invert the double matching loop in sort_servers().
+ Fix glitch when comparing matching domain labels.
+
+950115
+ Sort list of nameservers for a zone.
+ When the NS records for a zone are issued in BIND 4.9
+ round-robin fashion, this may yield an unfavorable
+ order for doing zone transfers. Apply some heuristic
+ to sort them according to preference, giving priority
+ to servers within your own domain or parent domains.
+ Add new option -P to define an explicit list of domains
+ of preferred servers, giving priority to matching ones.
+ Suggested by Marten Terpstra <marten@ripe.net>
+ Don't suppress certain rr data any more.
+ The preference value in the MX/RT/PX records and the
+ version number in the AFSDB record was suppressed in
+ non-verbose mode, unless the -T option was specified.
+ These values are now printed by default.
+ Requested by Geert Jan de Groot <geertj@ripe.net>
+
+941210
+ Adapt implementation of LOC RR.
+ The binary data format has already changed twice:
+ the four 4-bit fields are now four 8-bit fields,
+ and log2 encoding has changed to power-of-10 encoding.
+ Support for this will be incorporated in BIND 4.9.3.
+ Still undocumented in the host manual page.
+
+941206
+ Compatibility with BIND 4.9.3.
+ The NOCHANGE query response has now been conditionally
+ defined via #ifdef ALLOW_UPDATES. Older versions of
+ BIND may still return this (should have been FORMERR).
+ Improve error reporting.
+ Define a special h_errno status SERVER_FAILURE for the
+ case a SERVFAIL query response is returned. This is
+ used to report lame delegations during SOA checking
+ or zone transfers. Servers may return this code when
+ the zone data has expired altogether. This is not a
+ TRY_AGAIN situation if such server is authoritative.
+ Suggested by Peter Koch <pk@TechFak.Uni-Bielefeld.DE>
+ Rename special status NOT_AVAILABLE to QUERY_REFUSED.
+ Various minor changes.
+ Check for invalid characters in T_AAAA record names.
+ Print optional protocol and port from T_A record
+ after a comment sign. Not sure whether this has ever
+ been used.
+
+941129
+ Implement LOC RR as defined by preliminary draft-RFC.
+ Requires conversion routines for spherical position,
+ vertical position, and precision.
+ Tested on big-endian, little-endian, Alpha, Cray.
+ This is only a pre-release.
+ Undocumented until RFC gets public.
+
+941125
+ Recognize new RR types as reserved by RFC 1700.
+ Implement PX RR type as defined per RFC 1664.
+ Implement GPOS RR type as defined per RFC 1712.
+ Include few simple utility scripts.
+ These are just examples of wrappers to host.
+ nslookup -- emulate most functions of the real one.
+ mxlookup -- lookup records at each of its servers.
+
+941006
+ Lessen restrictions for certain tests.
+ The checks for invalid underscores and canonical host
+ names were suppressed during recursive zone listings
+ on all levels. They are now suppressed only when not
+ operating on the base level. This enables the checks
+ during the ``host -C -L 1'' command.
+ Extend functionality of -A option.
+ If the -A flag is specified along with any explicit
+ list mode option, it enables reversed address checking.
+ The address of each encountered A record is reverse
+ mapped, and it is checked whether it is registered and
+ maps back to the A record name. This flag can safely
+ be specified in the ``host -CA -L 1'' command.
+ Add new -W option to list wildcard records in a zone.
+ This is a new variant of the zone listing specials.
+ A zone transfer is done, and only wildcard records
+ are printed. The default resource record type is MX.
+ This option is undocumented, and subject to change.
+
+941004
+ Improve printout.
+ Include conversion of the various time values from the
+ SOA record in the comment part during ordinary printout.
+
+941002
+ Call alternative res_debug print routine if available.
+ In BIND 4.9.* an alternative module is present which
+ accepts (as it should) the size of the query buffer.
+ Rearrange include files.
+ Move configuration definitions to new conf.h.
+
+940917
+ Improve support for NSAP records, as per RFC 1637.
+ Print ordinary NSAP addresses with separating dots,
+ after the 1-byte AFI, then after every 2 bytes.
+ Add new option -n to generate reverse NSAP within the
+ nsap.int domain, similar to the -i option.
+ Print reverse NSAP in forward notation, unless forced
+ to print full zone file format.
+
+940911
+ Verify that some host names are canonical.
+ This is formally required, but also in practice highly
+ desirable. The target hosts in NS and MX records only
+ are verified, being the most crucial.
+ Currently the test is skipped during recursive zone
+ processing, to avoid excessive output of non-canonical
+ MX targets.
+ When figuring out the nameservers for a zone before
+ doing a zone transfer, a non-canonical nameserver name
+ is always reported.
+ Report illegal domain names.
+ This is now done by default for 'host' related domain
+ names. The A and MX record names and NS and MX target
+ names are checked only.
+ Only alphanumeric characters and hyphen '-' are valid.
+ Currently the reporting of names containing underscores
+ is suppressed during recursive zone listings, to avoid
+ excessive output of such illegal host names.
+ During SOA checking, an illegal primary or hostmaster
+ is always reported.
+ Document the -I option.
+ This option does no longer trigger the checking of
+ invalid characters in names.
+ To suppress illegal underscore messages, use "-I _".
+ To show them during recursive listings, use "-I ''".
+ Modify various messages.
+ Make some warning messages slightly shorter, and start
+ the message with the resource record or zone name.
+ Most of the SOA check messages have been affected.
+ Remove the answer buf offset in the incomplete HINFO
+ warning messages.
+ Improve error reporting.
+ Include the name of an explicit server in ns_error()
+ messages describing h_errno. This was already done
+ for the errno messages.
+ Include the server name also in ns_error() messages
+ after a failing zone transfer from that server.
+ Define a special h_errno status NOT_AVAILABLE for the
+ case a query was explicitly refused. Some servers are
+ configured to refuse zone transfers.
+ Major update of manual page.
+ Explain some more failure messages.
+ Explain most of the common warning and error messages.
+
+940819
+ Modify various messages.
+ Include the server name in messages reporting failures
+ and problems during zone transfers.
+ Implement ttl consistency checks.
+ Multiple records of same name/type/class should have the
+ same ttl value in zone listings. This is now checked.
+ A suitable hash function is needed to minimize overhead.
+ The approach is similar to the function used in sendmail.
+ This has been a long standing wish from
+ Peter Koch <pk@TechFak.Uni-Bielefeld.DE>
+ Various speedup fixes.
+ Avoid unnecessary indomain() calls during zone listings.
+
+940713
+ Modify various messages.
+ Replace some of the ``extraneous'' messages with a more
+ descriptive text. Include name and type of the query in
+ messages reporting format errors in the response.
+ Include zone name in error messages during SOA check.
+ Revise check for valid names.
+ If a domain name refers to a ``mailbox'', the part up to
+ the first unquoted dot is the ``local part'' to which
+ the RFC 822 syntax rules apply.
+
+940623
+ Revise res_send() strategy.
+ Mark bad server status for certain conditions which make
+ it unlikely that we will succeed during the next try.
+ Operating system failures are not in this category.
+ Nameserver unreachable status is now reported in a more
+ reliable fashion. A second try would sometimes timeout.
+ (May be useful for monitoring the upcoming summer 1994
+ reshuffling of EBONE/EuropaNET/NSFnet interconnections).
+ Facelift for socket I/O routines.
+ Systematically use _res_close() to close a connection.
+ Include the answer packet length in debug printout.
+ Extend resolver initialization.
+ Set initial query ID to some arbitrary number.
+ Various speedup fixes.
+ Avoid unnecessary strlen() calls during zone listings.
+ Check whether the resource record data must be printed
+ outside the print routine to avoid unnecessary overhead.
+ Use bcopy() instead of sprintf() in obvious cases.
+ Better output format control.
+ In non-verbose and non-debug mode, only pure resource
+ record output is written to stdout.
+ Add new -Z option to force resource record output to be
+ in full zone listing format, including trailing dot in
+ domain names, plus ttl value and class indicator.
+ Rearrange include files.
+ Define resource record structures in rrec.h.
+ Function declarations moved to defs.h.
+
+940615
+ Various portability changes.
+ Avoid use of sizeof() for all entities that have a fixed
+ field width, and use predefined constants instead. This
+ is necessary for systems without 16 or 32 bit integers.
+ Fix use of ipaddr_t and struct in_addr appropriately.
+ All this makes the utility portable to e.g. Cray.
+ Save and restore state during recursive lookup.
+ Error codes could be clobbered during MAILB tracing.
+ Miscellaneous minor code cleanup.
+
+940603
+ Fix implementation for -F option properly.
+ Exchanging the role of stdout and the logfile now works
+ on all platforms. Asked by Artur Romao <artur@dns.pt>
+
+940526
+ Combine explicit server and -p option.
+ If both are specified, the explicit server is contacted
+ to retrieve the desired servers for the given zone
+ during zone listing/checking modes. This is useful for
+ checking zones that have not been registered yet.
+ Requested by Geert Jan de Groot <geertj@ripe.net>
+ Rudimentary support for NSAP records.
+ This is still very experimental. It is unclear how an
+ NSAP address should be encoded in the resource record,
+ and how its hierarchical structure is decided.
+ Inspired by the 4.9 diffs from cisco.com.
+
+940317
+ Print SOA serial always as an unsigned value.
+ Warn about ``extraordinary'' serial if high bit is set.
+ Reset errno to avoid stale values.
+ Could happen when doing multiple gethostbyaddr() calls
+ in extended mode when the BIND res_send() is linked in.
+ Problem noted by <Piete.Brooks@cl.cam.ac.uk>
+ Solaris portability fix.
+ For solaris 2.x use res_gethostby{addr,name} modules
+ to force dns lookups. The __switch_gethostby{addr,name}
+ modules have disappeared in solaris 2.3.
+
+930926
+ Extend -I option with argument containing allowed chars.
+ This string specifies formally illegal, but silently
+ allowed characters when checking illegal domain names.
+ The -I option is still necessary to enable checking.
+ Still done only for resource record names in listings.
+ Note that some hesiod names contain the '/' character.
+ Indicated by Peter Koch <pk@TechFak.Uni-Bielefeld.DE>.
+ Additional SOA record checks.
+ Check hostmaster field for illegal chars, such as '@'
+ (needed as long as data field names are not checked).
+ Revised SOA record checks.
+ Check primary field against list of known nameservers.
+ Issue warning if not among the authoritative servers.
+ This may be intentional in special cases, however.
+ Required some code reshuffling.
+ Add new -M option to list mailable subdomains in a zone.
+ This is a new variant of the zone listing specials.
+ A zone transfer is done (without listing anything by
+ default) to determine the available delegated zones.
+ For each of these zones, the MX records are printed.
+ Experimental, undocumented. Insufficient too: you
+ really want to see also the domains for which only
+ an MX record exist.
+ Cleanup terminology in the code documentation.
+ Remove the word 'subdomain' and cleanup the confusion
+ between 'domain' versus 'zone'.
+ Update manual page.
+ Use terminology that is technically more correct.
+ Explain various things that were still missing.
+
+930919
+ Print actual name that was queried in error messages.
+ Formerly, only the (possibly abbreviated) queryname
+ as specified on the command line was printed.
+ Special care must be given if domain search is enabled,
+ especially in the enforced BIND compatibility mode.
+ Looks much better. Asked by <Piete.Brooks@cl.cam.ac.uk>
+ Some more SOA record tests.
+ Some records have the name of the zone specified in the
+ field that should contain the name of the primary server.
+ Miscellaneous minor changes.
+ Slightly modify the nameserver name printout during -C.
+ Set proper h_errno when answer buffer counts are corrupt.
+ Add new -V option to print version number.
+ Define version in separate vers.c
+ Use class mnemonics as defined in RFC 1035.
+ Print 'CH' instead of 'CHAOS'. Anyone using this ?
+ Recognize obsolete 'CS' or 'CSNET'. Pretty useless.
+ Just for ultimate completeness.
+ Check for invalid characters in domain names.
+ Only alphanumeric characters and hyphen '-' are valid.
+ Unfortunately, the use of underscore '_' is widespread,
+ so issuing a warning by default is unrealistic. Therefore:
+ Add new -I option to warn about illegal domain names.
+ Currently done only for resource record names during zone
+ listing. Could be extended to domain names in data fields.
+ Perhaps a warning by default in case illegal other than
+ underscore. Option is still undocumented as the semantics
+ are subject to change.
+
+930915
+ Add -R option to always first try search domains.
+ Normally querynames are assumed to be fully qualified
+ and are tried as such, unless it is a single name which
+ is always tried, and only once, in the default domain.
+ This option sets RES_DNSRCH and simulates the default
+ BIND behavior, with the exception that NO_DATA status
+ terminates the search immediately.
+ With the additional otherwise undocumented -B option the
+ BIND behavior is fully enforced and the search continues.
+ Added only for testing purposes, not for general use.
+ Few more BIND 4.9 compatibility changes.
+ Some resolver routines have gotten new argument types.
+ Adapt Makefile to BIND conventions.
+ The Makefile can be used completely stand-alone,
+ or can be invoked from the master BIND Makefile.
+ Affects names of various (inherited) make variables.
+ Change BIND_RES_SEND to HOST_RES_SEND with opposite
+ meaning. Default is HOST_RES_SEND in case stand-alone.
+
+930911
+ Extension of user interface.
+ Allow multiple arguments on command line or from stdin.
+ Requires new syntax for specifying explicit server.
+ New options -x and '-X server' indicate extended syntax.
+ Quite a lot reshuffling of code. Urgently requested by
+ <Piete.Brooks@cl.cam.ac.uk> and Paul Vixie <paul@vix.com>
+ Configurable default options.
+ Use an environment variable HOST_DEFAULTS to pre-define
+ default options and parameters. These are interpolated
+ in front of the command line arguments before scanning.
+ Syntax is the same as the command line syntax.
+ Fix bug when querying single name without dot.
+ Not only the default domain, but also the eventual other
+ search domains would be tried, although DNSRCH is off.
+ This is a long-standing bug. Very important fix.
+
+930908
+ Various declaration changes for portability.
+ Print TXT/HINFO/UINFO strings within double quotes.
+ It is done both in regular and zone listing output.
+ This is conforming the syntax for zone input files.
+ Add trailing dot to domain names in zone listing.
+ This is conforming the syntax for zone input files.
+ The trailing dot is not added in regular output.
+ Define exit codes in new exit.h header file.
+ This avoids the need to include /usr/ucbinclude when
+ running in non-BSD mode on solaris 2.x platforms.
+ Attempt to diagnose lame delegations.
+ Error messages about lame delegations are given during
+ zone listings and when checking SOA records (but only when
+ the contacted servers are supposed to be authoritative).
+ Also in case servers from NS records turn out not to exist.
+ This may need some refinement for special cases.
+ Perform some extra checks during zone listings.
+ Check for unexpected error status in packets. Only the
+ very first packet in response to a transfer query can
+ have an error status.
+ Issue warning if only a single nameserver found.
+ Not an error per se, but not much redundancy then.
+ Suggested by Peter Koch <pk@TechFak.Uni-Bielefeld.DE>.
+ Check for anomalous empty zone transfers.
+ Transfers consisting of only SOA records could occur if
+ we queried the victim of a lame delegation which happened
+ to have the SOA record present. Fake an error that will
+ result in a lame delegation message.
+ Mentioned by Peter Koch <pk@TechFak.Uni-Bielefeld.DE>.
+ Indicate list/check failure/success via exit code.
+ Failure status is returned in case any error has been
+ reported via errmsg or pr_error (not pr_warning).
+ For Ruediger Volk <rv@deins.informatik.uni-dortmund.de>
+ Add -o option to suppress rr output to stdout.
+ Can be used in combination with -f to separate rr output
+ from verbose comments and error output.
+ Perform some SOA timer consistency checks.
+ Check timer values for anomalies, such as (retry > refresh)
+ or (refresh + retry > expire).
+ Suggested by Peter Koch <pk@TechFak.Uni-Bielefeld.DE>.
+ Also compare all values instead of just serial.
+ More accurate reporting of zones processed.
+ Print total number of successful zone transfers versus the
+ number of attempted transfers. Print count of zones which
+ were successfully processed (transferred or -C checked)
+ versus the number of zones requested to be processed.
+ From this we can deduce the number of transfers that failed
+ and the number of times we couldn't find any nameservers.
+
+930901
+ Increase MAXNSNAME from 12 to 16.
+ This is conforming NSMAX in ns.h
+ Don't accumulate statistics if not necessary.
+ Skip the costly host count scan in case nothing would
+ be reported at all according to the command line options.
+ Add some extra checks during zone listings.
+ Check for invalid nonzero nscount and arcount.
+ Special handling for non-authoritative answers.
+ We had already NO_RREC for non-authoritative NO_DATA, but
+ non-authoritative HOST_NOT_FOUND would yield TRY_AGAIN.
+ Change this to NO_HOST to issue a separate error message.
+ This identifies some special cases, e.g. queries for a
+ non-existing name using class C_ANY when the nameserver
+ is authoritative only for one specific class.
+ Use TRY_AGAIN in both cases during zone listing errors.
+ Minor declaration changes for portability.
+ Add -F option to exchange role of stdout and logfile.
+ The '-F file' is the same as '-f file' but all stdout
+ output goes to the logfile, and stdout only gets the extra
+ resource record output (so that it can be used in pipes).
+ Implementation is inherently unportable. Supported only on
+ a few platforms where it happens to work.
+ Explain status messages in the manual page.
+ Include address and name of server in perror messages.
+ This gives a lot more information in case stderr and stdout
+ are differently redirected.
+
+930830
+ Make error checking in some routines uniform.
+ Miscellaneous declaration changes.
+ Filter resource record class appropriately.
+ In zone listings records of different class can show up,
+ e.g. HS records are mixed with IN records. Only records
+ of the requested class should be processed. This fixes
+ problems with recursive zone traversals and inaccurate
+ statistics. Pointed out by <Yves.Devillers@inria.fr>
+ and <Piet.Beertema@EU.net>. Important fix.
+ Include record class, if special, in some output.
+ Show the class if it is not the default IN class.
+ Include address of duplicate hosts in message.
+ This may help to locate the problem.
+ Properly concatenate long TXT strings that are split.
+ Long TXT strings (>255) are split as of BIND 4.8.3.
+ They were displayed incorrectly with TAB separators.
+ Problem noted by Peter Koch <pk@TechFak.Uni-Bielefeld.DE>.
+ Cleanup some DNS terminology in output messages.
+ Fix some confusion between '(sub)domain' and 'zone'. Only
+ done in the output of host, not yet in the documentation.
+ Pointed out by Peter Koch <pk@TechFak.Uni-Bielefeld.DE>.
+ Implement host address list as hashed list.
+ The linear list is replaced with a hashed list, using the
+ low-order address bits as the key. This may dramatically
+ speed up recursive zone listings. Very important fix.
+ Suggested by Peter Koch <pk@TechFak.Uni-Bielefeld.DE>.
+ Miscellaneous portability hooks.
+ Add new port.h header file.
+ Change u_long to u_int for resource record fields.
+ These are fixed 32-bit quantities.
+ Note that BIND 4.9 uses u_int32_t for these, but still uses
+ (inconsistently) u_short instead of u_int16_t.
+ Necessary for port to alpha and BIND 4.9.
+ Change u_long to ipaddr_t for 32-bit address fields.
+ For the time being, make this identical to u_long for non-
+ alpha machines with pre-BIND 4.9 to avoid lint warnings.
+ Note that BIND 4.9 uses u_int32_t for these.
+ Necessary for port to alpha and BIND 4.9.
+ Introduce new typedef for 'struct state'.
+ Necessary for BIND 4.9.
+ Make all arguments to vararg routines same type.
+ No more mixing of arbitrary pointers and ints. Only number
+ of arguments is variable. Requires few silly interfaces.
+ Necessary for port to alpha.
+ Add the RELEASE_NOTES file to explain changes.
+
+930209
+ Lookup server name with default resolver values.
+ Check SOA records without nameserver recursion.
+ Implement new RR types from RFC 1183 and 1348.
+
+921005
+ Anticipate ultrix specific resolv.h
+ Miscellaneous declaration changes.
+ Some reshuffling of code.
+
+920702
+ Recognize alternative program call names.
+ Distinguish between auth and non-auth NO_DATA.
+
+920624
+ Lookup server name before changing nameserver address.
+ Handle possible truncation in zone transfers.
+ Provide private simplified version of res_send().
+ Add -u option to force virtual circuit connections.
+ Move all socket I/O routines to separate send.c.
+
+920616
+ Allocate list of zonenames dynamically, not statically.
+ Move and slightly modify the test for fake hosts.
+ Suppress host count statistics during inverse listing.
+ Miscellaneous documentation updates.
+
+920315
+ Improve counting of hosts within domain.
+ Discard glue records not directly within domain.
+ Keep track of hosts with duplicate address.
+ Add -D option to list duplicate hosts.
+ Add -E option to list extrazone hosts.
+ Miscellaneous casting and typing cleanup.
+ Increase (static) number of possible subdomains.
+
+911201
+ Option -T also prints MX preference value.
+ Save name of longest hostname found (just for fun).
+ Undocumented option -g to select long names (fun).
+
+911010
+ Don't recurse on cnames if querytype is cname.
+
+910923
+ Count gateway hosts (with multiple addresses).
+ Add -G option to list gateway hosts.
+
+910905
+ Improve counting of hosts within domain.
+ Allow hosts not directly within domain.
+ Increase (static) maximum number of hosts.
+
+910415
+ Improve finding of subdomain names.
+ Allow subdomains not directly within domain.
+ Check for unauthoritative glue records.
+ Add -T option to print ttl when non-verbose.
+ Improve connect timeout handling.
+ Improve dotted quad parsing.
+ Minimum ttl is now called default ttl.
+
+910129
+ Maintain count of hosts during domain listings.
+ Check for hosts with same name as subdomain.
+ Add -H option for special host count mode.
+ Recognize obsolete T_MAILA.
+
+# ----------------------------------------------------------------------
+# TODO
+# ----------------------------------------------------------------------
+
+ Documentation changes.
+ References to BIND 4.9, not only 4.8.
+
+ Enhance reverse mapping.
+ The new BIND 4.9.* gethostbyaddr() can be configured
+ to return host aliases in case multiple PTR records
+ were encountered during the reverse lookup.
+ It is unclear what the official host name should be.
+ Should perhaps abandon the idea of official host name.
+
+# ----------------------------------------------------------------------
+# WISHLIST
+# ----------------------------------------------------------------------
+
+ Skip printing of second SOA in zone listing.
+ Asked by Peter Koch <pk@TechFak.Uni-Bielefeld.DE>.
+
+# ----------------------------------------------------------------------
+# NOTES
+# ----------------------------------------------------------------------
+
+ Include files and resolver library.
+ If you are linking this utility with an explicit resolver
+ library, make sure you will be compiling with the same
+ include files that were used to build the resolver library.
+ The BIND 4.9 include file <resolv.h> is incompatible with
+ the BIND 4.8 version. This utility can handle both versions,
+ but you cannot link with an 4.9 library after compilation
+ with the 4.8 include files, and vice versa.
+
+ Old resolver libraries.
+ The res_mkquery() routine in the SUN-supplied resolver
+ library on SunOS <= 4.1.3 adds the default domain to given
+ single names if REF_DEFNAMES is set. This is not correct and
+ leads to undesired results if you query about toplevel domains.
+ It may be a pre-BIND 4.8.2 problem.
+ The same behavior is reported in the default ultrix resolver.
+ This will not be fixed in host. The documentation states that
+ you need BIND 4.8.2 or higher.
+ Problem noted by Peter Koch <pk@TechFak.Uni-Bielefeld.DE>.
+
+ Vendor-specific resolver libraries.
+ Some vendors supply resolver libraries with configurable
+ lookup strategies for gethostbyname/gethostbyaddr, e.g. to
+ consult DNS, NIS, /etc/hosts, or other databases, in specific
+ order. Such libraries are to be avoided when linking host.
+ It is meant to query the DNS and DNS only.
+
+ SUN's resolver library on solaris 2.x
+ If you are on solaris 2.x and you don't have a proper BIND
+ resolver library to link with, but have to use the broken
+ default library, you can define NO_YP_LOOKUP in the Makefile
+ to prevent gethostbyname/gethostbyaddr querying the YP/NIS.
+ SUN will probably implement BIND 4.9.3 after its release.
+
+# ----------------------------------------------------------------------
+# MISC
+# ----------------------------------------------------------------------
+
+ Port to DEC/Alpha with OSF/1.
+ Requested by various people.
+ This requires basically two adaptations:
+ - sizeof(u_long) is 64 bits instead of 32 bits.
+ Affects ip address fields and some fixed fields in the
+ nameserver query/answer buffers.
+ - pointers in C subroutine arguments are 64 bit quantities.
+ Affects the varargs modules.
+ Suggestions by Dietrich Wiegandt <dietrich@dxcern.cern.ch>
+ and David Cherkus <cherkus@zk3.dec.com>.
+
+ Compatibility with BIND 4.9.
+ Don't use the u_long types any more.
+ The 'struct state' is now 'struct __res_state'.
+ New resolver library has various hooks for 'dig'.
+ New resolver library prints to stdout with leading ";" but
+ unfortunately not everywhere. It prints to stderr sometimes
+ also with ";" but does not so in the perror() messages.
+ (Things have been corrected in BIND 4.9.3).
+ BIND 4.9 prints FQDN with trailing dot.
+ BIND 4.9 prints TXT strings within double quotes.
+
+ New features of BIND 4.9.3.
+ Don't use sizeof() for u_int, u_short, struct in_addr, and
+ HEADER, but use predefined constants for entities that have
+ a fixed field width.
+ A new parameter _res.ndots has been defined.
+ The res_search() module may query the given name ``as_is''.
+ The res_search() module retries after SERVFAIL.
+ The res_send() module marks a bad server status for almost
+ every error condition.
+ Extra checks are carried out to ensure that a reply packet
+ really is the answer to a query: nameserver addresses and
+ query fields are compared.
+
diff --git a/usr.sbin/named/host/conf.h b/usr.sbin/named/host/conf.h
new file mode 100644
index 00000000000..d9812ccfb9d
--- /dev/null
+++ b/usr.sbin/named/host/conf.h
@@ -0,0 +1,63 @@
+/*
+** Various configuration definitions.
+**
+** @(#)conf.h e07@nikhef.nl (Eric Wassenaar) 951230
+*/
+
+/*
+ * A special version of res_send() is included, which returns additional
+ * errno statuses, and which corrects some flaws in the BIND 4.8 version.
+ */
+
+#if !defined(HOST_RES_SEND) && !defined(BIND_RES_SEND)
+#if defined(BIND_49)
+#define BIND_RES_SEND /* use the default BIND res_send() */
+#else
+#define HOST_RES_SEND /* use the special host res_send() */
+#endif
+#endif
+
+/*
+ * The root domain for the internet reversed mapping zones.
+ */
+
+#define ARPA_ROOT "in-addr.arpa"
+
+/*
+ * The root domain for the NSAP reversed mapping zones as per RFC 1637.
+ */
+
+#ifndef NSAP_ROOT
+#define NSAP_ROOT "nsap.int"
+#endif
+
+/*
+ * An encoded NSAP address is 7 to 20 octets as per RFC 1629.
+ */
+
+#define MAXNSAP 20 /* maximum size of encoded NSAP address */
+
+/*
+ * Miscellaneous constants.
+ */
+
+#define MAXADDRS 35 /* max address count from gethostnamadr.c */
+#define MAXNSNAME 16 /* maximum count of nameservers per zone */
+#define MAXIPADDR 10 /* maximum count of addresses per nameserver */
+#define MAXHOSTS 65536 /* maximum count of hostnames per zone */
+
+/*
+ * Version number of T_LOC resource record.
+ */
+
+#define T_LOC_VERSION 0 /* must be zero */
+
+/*
+ * Prefix for messages on stdout in debug mode.
+ */
+
+#if defined(BIND_49)
+#define DBPREFIX ";; "
+#else
+#define DBPREFIX ""
+#endif
diff --git a/usr.sbin/named/host/defs.h b/usr.sbin/named/host/defs.h
new file mode 100644
index 00000000000..8ff850b3940
--- /dev/null
+++ b/usr.sbin/named/host/defs.h
@@ -0,0 +1,148 @@
+/*
+** Declaration of functions.
+**
+** @(#)defs.h e07@nikhef.nl (Eric Wassenaar) 951015
+*/
+
+/*
+** Internal modules of the host utility
+** ------------------------------------
+*/
+
+ /* main.c */
+
+int main PROTO((int, char **));
+void set_defaults PROTO((char *, int, char **));
+int process_argv PROTO((int, char **));
+int process_file PROTO((FILE *));
+int process_name PROTO((char *));
+int execute_name PROTO((char *));
+bool execute PROTO((char *, ipaddr_t));
+bool host_query PROTO((char *, ipaddr_t));
+char *myhostname PROTO((void));
+void set_server PROTO((char *));
+void set_logfile PROTO((char *));
+void fatal PROTO((char *, ...));
+void errmsg PROTO((char *, ...));
+
+
+ /* info.c */
+
+bool get_hostinfo PROTO((char *, bool));
+bool get_domaininfo PROTO((char *, char *));
+int get_info PROTO((querybuf *, char *, int, int));
+bool print_info PROTO((querybuf *, int, char *, int, bool));
+void print_data PROTO((char *, ...));
+u_char *print_rrec PROTO((char *, u_char *, u_char *, u_char *, bool));
+u_char *skip_qrec PROTO((char *, u_char *, u_char *, u_char *));
+bool get_recursive PROTO((char *));
+
+
+ /* list.c */
+
+bool list_zone PROTO((char *));
+bool find_servers PROTO((char *));
+bool get_servers PROTO((char *));
+bool get_nsinfo PROTO((querybuf *, int, char *));
+void sort_servers PROTO((void));
+bool skip_transfer PROTO((char *));
+void do_check PROTO((char *));
+bool do_transfer PROTO((char *));
+bool transfer_zone PROTO((char *, int, struct in_addr, char *));
+bool get_zone PROTO((char *, int, struct in_addr, char *));
+bool get_mxrec PROTO((char *));
+char *get_primary PROTO((char *));
+bool check_zone PROTO((char *));
+bool get_soainfo PROTO((querybuf *, int, char *));
+void check_soa PROTO((querybuf *, char *));
+bool check_dupl PROTO((ipaddr_t));
+bool check_ttl PROTO((char *, int, int, int));
+void clear_ttltab PROTO((void));
+int host_index PROTO((char *, bool));
+void clear_hosttab PROTO((void));
+int zone_index PROTO((char *, bool));
+void clear_zonetab PROTO((void));
+int check_canon PROTO((char *));
+
+
+ /* addr.c */
+
+bool check_addr PROTO((char *));
+bool check_name PROTO((ipaddr_t));
+
+
+ /* util.c */
+
+int parse_type PROTO((char *));
+int parse_class PROTO((char *));
+char *in_addr_arpa PROTO((char *));
+char *nsap_int PROTO((char *));
+void print_host PROTO((char *, struct hostent *));
+void show_res PROTO((void));
+void print_statistics PROTO((char *, int, int));
+void clear_statistics PROTO((void));
+void show_types PROTO((char *, int, int));
+void ns_error PROTO((char *, int, int, char *));
+char *decode_error PROTO((int));
+void print_status PROTO((querybuf *));
+void pr_error PROTO((char *, ...));
+void pr_warning PROTO((char *, ...));
+bool want_type PROTO((int, int));
+bool want_class PROTO((int, int));
+bool indomain PROTO((char *, char *, bool));
+bool samedomain PROTO((char *, char *, bool));
+bool gluerecord PROTO((char *, char *, char **, int));
+int matchlabels PROTO((char *, char *));
+char *pr_domain PROTO((char *, bool));
+char *pr_dotname PROTO((char *));
+char *pr_nsap PROTO((char *));
+char *pr_type PROTO((int));
+char *pr_class PROTO((int));
+int expand_name PROTO((char *, int, u_char *, u_char *, u_char *, char *));
+int check_size PROTO((char *, int, u_char *, u_char *, u_char *, int));
+bool valid_name PROTO((char *, bool, bool, bool));
+int canonical PROTO((char *));
+char *mapreverse PROTO((char *, struct in_addr));
+int compare_name PROTO((char **, char **));
+
+
+ /* misc.c */
+
+ptr_t *xalloc PROTO((ptr_t *, siz_t));
+char *itoa PROTO((int));
+char *utoa PROTO((int));
+char *stoa PROTO((u_char *, int));
+char *nsap_ntoa PROTO((u_char *, int));
+char *pr_time PROTO((int, bool));
+char *pr_spherical PROTO((int, char *, char *));
+char *pr_vertical PROTO((int, char *, char *));
+char *pr_precision PROTO((int));
+
+
+ /* send.c */
+
+#ifdef HOST_RES_SEND
+int res_send PROTO((CONST qbuf_t *, int, qbuf_t *, int));
+#endif /*HOST_RES_SEND*/
+int _res_connect PROTO((int, struct sockaddr_in *, int));
+int _res_write PROTO((int, struct sockaddr_in *, char *, char *, int));
+int _res_read PROTO((int, struct sockaddr_in *, char *, char *, int));
+void _res_perror PROTO((struct sockaddr_in *, char *, char *));
+
+/*
+** External library functions
+** --------------------------
+*/
+
+ /* extern */
+
+ipaddr_t inet_addr PROTO((CONST char *));
+char *inet_ntoa PROTO((struct in_addr));
+char *hostalias PROTO((CONST char *));
+char *index PROTO((const char *, char));
+char *rindex PROTO((const char *, char));
+char *strcpy PROTO((char *, const char *));
+char *getenv PROTO((const char *));
+ptr_t *malloc PROTO((siz_t));
+ptr_t *realloc PROTO((ptr_t *, siz_t));
+void exit PROTO((int));
diff --git a/usr.sbin/named/host/exit.h b/usr.sbin/named/host/exit.h
new file mode 100644
index 00000000000..3e630b1e977
--- /dev/null
+++ b/usr.sbin/named/host/exit.h
@@ -0,0 +1,25 @@
+/*
+** Various exit codes.
+**
+** They come from <sysexits.h>
+** Defined here to avoid including /usr/ucbinclude on solaris 2.x
+**
+** @(#)exit.h e07@nikhef.nl (Eric Wassenaar) 930903
+*/
+
+#define EX_OK 0 /* successful termination */
+#define EX_USAGE 64 /* command line usage error */
+#define EX_DATAERR 65 /* data format error */
+#define EX_NOINPUT 66 /* cannot open input */
+#define EX_NOUSER 67 /* addressee unknown */
+#define EX_NOHOST 68 /* host name unknown */
+#define EX_UNAVAILABLE 69 /* service unavailable */
+#define EX_SOFTWARE 70 /* internal software error */
+#define EX_OSERR 71 /* system error (e.g., can't fork) */
+#define EX_OSFILE 72 /* critical OS file missing */
+#define EX_CANTCREAT 73 /* can't create (user) output file */
+#define EX_IOERR 74 /* input/output error */
+#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
+#define EX_PROTOCOL 76 /* remote error in protocol */
+#define EX_NOPERM 77 /* permission denied */
+#define EX_CONFIG 78 /* local configuration error */
diff --git a/usr.sbin/named/host/host.c b/usr.sbin/named/host/host.c
new file mode 100644
index 00000000000..e928c464c1c
--- /dev/null
+++ b/usr.sbin/named/host/host.c
@@ -0,0 +1,7227 @@
+/*
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement: ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Originally, this program came from Rutgers University, however it
+ * is based on nslookup and other pieces of named tools, so it needs
+ * that copyright notice.
+ */
+
+/*
+ * Rewritten by Eric Wassenaar, Nikhef-H, <e07@nikhef.nl>
+ *
+ * The officially maintained source of this program is available
+ * via anonymous ftp from machine 'ftp.nikhef.nl' [192.16.199.1]
+ * in the directory '/pub/network' as 'host.tar.Z'
+ *
+ * You are kindly requested to report bugs and make suggestions
+ * for improvements to the author at the given email address,
+ * and to not re-distribute your own modifications to others.
+ */
+
+#ifndef lint
+static char Version[] = "@(#)host.c e07@nikhef.nl (Eric Wassenaar) 951231";
+#endif
+
+#if defined(apollo) && defined(lint)
+#define __attribute(x)
+#endif
+
+#define justfun /* this is only for fun */
+#undef obsolete /* old code left as a reminder */
+#undef notyet /* new code for possible future use */
+
+/*
+ * New features
+ *
+ * - Major overhaul of the entire code.
+ * - Very rigid error checking, with more verbose error messages.
+ * - Zone listing section completely rewritten.
+ * - It is now possible to do recursive listings into delegated zones.
+ * - Maintain resource record statistics during zone listings.
+ * - Maintain count of hosts during zone listings.
+ * - Check for various extraneous conditions during zone listings.
+ * - Check for illegal domain names containing invalid characters.
+ * - Verify that certain domain names represent canonical host names.
+ * - Perform ttl consistency checking during zone listings.
+ * - Exploit multiple server addresses if available.
+ * - Option to exploit only primary server for zone transfers.
+ * - Option to exclude info from names that do not reside in a zone.
+ * - Implement timeout handling during connect and read.
+ * - Write resource record output to optional log file.
+ * - Special MB tracing by recursively expanding MR and MG records.
+ * - Special mode to check SOA records at each nameserver for a zone.
+ * - Special mode to check reverse mappings of host addresses.
+ * - Extended syntax allows multiple arguments on command line or stdin.
+ * - Configurable default options in HOST_DEFAULTS environment variable.
+ * - Implement new resource record types from RFC 1183 and 1348.
+ * - Basic experimental NSAP support as defined in RFC 1637.
+ * - Implement new resource record types from RFC 1664 and 1712.
+ * - Code is extensively documented.
+ */
+
+/*
+ * Publication history
+ *
+ * This information has been moved to the RELEASE_NOTES file.
+ */
+
+/*
+ * Compilation options
+ *
+ * This program usually compiles without special compilation options,
+ * but for some platforms you may have to define special settings.
+ * See the Makefile and the header file port.h for details.
+ */
+
+/*
+ * Miscellaneous notes
+ *
+ * This program should be linked explicitly with the BIND resolver library
+ * in case the default gethostbyname() or gethostbyaddr() routines use a
+ * non-standard strategy for retrieving information. These functions in the
+ * resolver library call on the nameserver, and fall back on the hosts file
+ * only if no nameserver is running (ECONNREFUSED).
+ *
+ * You may also want to link this program with the BIND resolver library if
+ * your default library has not been compiled with DEBUG printout enabled.
+ *
+ * The version of the resolver should be BIND 4.8.2 or later. The crucial
+ * include files are <netdb.h>, (resolv.h>, <arpa/nameser.h>. These files
+ * are assumed to be present in the /usr/include directory.
+ *
+ * The resolver code depends on the definition of the BSD pre-processor
+ * variable. This variable is usually defined in the file <sys/param.h>.
+ *
+ * The definition of this variable determines the method how to handle
+ * datagram connections. This may not work properly on all platforms.
+ *
+ * The hostent struct defined in <netdb.h> is assumed to handle multiple
+ * addresses in h_addr_list[]. Usually this is true if BSD >= 43.
+ *
+ * Your nameserver may not handle queries about top-level zones properly
+ * if the "domain" directive is present in the named.boot file. It will
+ * append the default domain to single names for which no data is cached.
+ *
+ * The treatment of TXT records has changed from 4.8.2 to 4.8.3. Formerly,
+ * the data consisted simply of the text string. Now, the text string is
+ * preceded by the character count with a maximum of 255, and multiple
+ * strings are embedded if the total character count exceeds 255.
+ * We handle only the new situation in this program, assuming that nobody
+ * uses TXT records before 4.8.3 (unfortunately this is not always true:
+ * current vendor supplied software may sometimes be even pre-BIND 4.8.2).
+ *
+ * Note that in 4.8.3 PACKETSZ from nameser.h is still at 512, which is
+ * the maximum possible packet size for datagrams, whereas MAXDATA from
+ * db.h has increased from 256 to 2048. The resolver defines MAXPACKET
+ * as 1024. The nameserver reads queries in a buffer of size BUFSIZ.
+ *
+ * The gethostbyname() routine in 4.8.3 interprets dotted quads (if not
+ * terminated with a dot) and simulates a gethostbyaddr(), but we will
+ * not rely on it, and handle dotted quads ourselves.
+ *
+ * On some systems a bug in the _doprnt() routine exists which prevents
+ * printf("%.*s", n, string) to be printed correctly if n == 0.
+ *
+ * This program has not been optimized for speed. Especially the memory
+ * management is simple and straightforward.
+ */
+
+/*
+ * Terminology used
+ *
+ * Gateway hosts.
+ * These are hosts that have more than one address registered under
+ * the same name. Obviously we cannot recognize a gateway host if it
+ * has different names associated with its different addresses.
+ *
+ * Duplicate hosts.
+ * These are non-gateway hosts of which the address was found earlier
+ * but with a different name, possibly in a totally different zone.
+ * Such hosts should not be counted again in the overall host count.
+ * This situation notably occurs in e.g. the "ac.uk" domain which has
+ * many names registered in both the long and the abbreviated form,
+ * such as 'host.department.university.ac.uk' and 'host.dept.un.ac.uk'.
+ * This is probably not an error per se. It is an error if some domain
+ * has registered a foreign address under a name within its own domain.
+ * To recognize duplicate hosts when traversing many zones, we have to
+ * maintain a global list of host addresses. To simplify things, only
+ * single-address hosts are handled as such.
+ *
+ * Extrazone hosts.
+ * These are hosts which belong to a zone but which are not residing
+ * directly within the zone under consideration and which are not
+ * glue records for a delegated zone of the given zone. E.g. if we are
+ * processing the zone 'bar' and find 'host.foo.bar' but 'foo.bar' is not
+ * an NS registered delegated zone of 'bar' then it is considered to be
+ * an extrazone host. This is not necessarily an error, but it could be.
+ *
+ * Lame delegations.
+ * If we query the SOA record of a zone at a supposedly authoritative
+ * nameserver for that zone (listed in the NS records for the zone),
+ * the SOA record should be present and the answer authoritative.
+ * If not, we flag a lame delegation of the zone to that nameserver.
+ * This may need refinement in some special cases.
+ * A lame delegation is also flagged if we discover that a nameserver
+ * mentioned in an NS record does not exist when looking up its address.
+ *
+ * Primary nameserver.
+ * This utility assumes that the first domain name in the RHS of the
+ * SOA record for a zone contains the name of the primary nameserver
+ * (or one of the primary nameservers) for that zone. Unfortunately,
+ * this field has not been unambiguously defined. Nevertheless, many
+ * hostmasters interpret the definitions given in RFC 1033 and 1035
+ * as such, and therefore host will continue doing so. Interpretation
+ * as the machine that holds the zone data disk file is pretty useless.
+ */
+
+/*
+ * Usage: host [options] name [server]
+ * Usage: host [options] -x [name ...]
+ * Usage: host [options] -X server [name ...]
+ *
+ * Regular command line options:
+ * ----------------------------
+ *
+ * -t type specify query type; default is T_A for normal mode
+ * -a specify query type T_ANY
+ * -v print verbose messages (-vv is very verbose)
+ * -d print debugging output (-dd prints even more)
+ *
+ * Special mode options.
+ * --------------------
+ *
+ * -l special mode to generate zone listing for a zone
+ * -L level do recursive zone listing/checking this level deep
+ * -p use primary nameserver of zone for zone transfers
+ * -P server give priority to preferred servers for zone transfers
+ * -N zone do not perform zone transfer for these explicit zones
+ * -S print zone resource record statistics
+ * -H special mode to count hosts residing in a zone
+ * -G same as -H but lists gateway hosts in addition
+ * -E same as -H but lists extrazone hosts in addition
+ * -D same as -H but lists duplicate hosts in addition
+ * -C special mode to check SOA records for a zone
+ * -A special mode to check reverse mappings of host addresses
+ *
+ * Miscellaneous options.
+ * ---------------------
+ *
+ * -f filename log resource record output also in given file
+ * -F filename same as -f, but exchange role of stdout and log file
+ * -I chars chars are not considered illegal in domain names
+ * -i generate reverse in-addr.arpa query for dotted quad
+ * -n generate reverse nsap.int query for dotted nsap address
+ * -q be quiet about some non-fatal errors
+ * -T print ttl value during non-verbose output
+ * -Z print selected RR output in full zone file format
+ *
+ * Seldom used options.
+ * -------------------
+ *
+ * -c class specify query class; default is C_IN
+ * -e exclude info from names that do not reside in the zone
+ * -m specify query type T_MAILB and trace MB records
+ * -o suppress resource record output to stdout
+ * -r do not use recursion when querying nameserver
+ * -R repeatedly add search domains to qualify queryname
+ * -s secs specify timeout value in seconds; default is 2 * 5
+ * -u use virtual circuit instead of datagram for queries
+ * -w wait until nameserver becomes available
+ *
+ * Undocumented options. (Experimental, subject to change)
+ * --------------------
+ *
+ * -g length only select names that are at least this long
+ * -B enforce full BIND behavior during DNSRCH
+ * -M special mode to list mailable delegated zones of zone
+ * -W special mode to list wildcard records in a zone
+ * -z special mode to list delegated zones in a zone
+ */
+
+static char Usage[] =
+"\
+Usage: host [-v] [-a] [-t querytype] [options] name [server]\n\
+Listing: host [-v] [-a] [-t querytype] [options] -l zone [server]\n\
+Hostcount: host [-v] [options] -H [-D] [-E] [-G] zone\n\
+Check soa: host [-v] [options] -C zone\n\
+Addrcheck: host [-v] [options] -A host\n\
+Listing options: [-L level] [-S] [-A] [-p] [-P prefserver] [-N skipzone]\n\
+Common options: [-d] [-f|-F filename] [-I chars] [-i|-n] [-q] [-T] [-Z]\n\
+Other options: [-c class] [-e] [-m] [-o] [-r] [-R] [-s secs] [-u] [-w]\n\
+Extended usage: [-x [name ...]] [-X server [name ...]]\
+";
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+
+#include <sys/types.h> /* not always automatically included */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#undef NOERROR /* in <sys/streams.h> on solaris 2.x */
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "port.h" /* various portability definitions */
+#include "conf.h" /* various configuration definitions */
+#include "type.h" /* types should be in <arpa/nameser.h> */
+#include "exit.h" /* exit codes come from <sysexits.h> */
+
+typedef int bool; /* boolean type */
+#define TRUE 1
+#define FALSE 0
+
+#ifndef NO_DATA
+#define NO_DATA NO_ADDRESS /* used here only in case authoritative */
+#endif
+
+#define NO_RREC (NO_DATA + 1) /* used for non-authoritative NO_DATA */
+#define NO_HOST (NO_DATA + 2) /* used for non-authoritative HOST_NOT_FOUND */
+
+#define QUERY_REFUSED (NO_DATA + 3) /* query was refused by server */
+#define SERVER_FAILURE (NO_DATA + 4) /* instead of TRY_AGAIN upon SERVFAIL */
+#define HOST_NOT_CANON (NO_DATA + 5) /* host name is not canonical */
+
+#define T_NONE 0 /* yet unspecified resource record type */
+#define T_FIRST T_A /* first possible type in resource record */
+#define T_LAST (T_AXFR - 1) /* last possible type in resource record */
+
+#ifndef NOCHANGE
+#define NOCHANGE 0xf /* compatibility with older BIND versions */
+#endif
+
+#define NOT_DOTTED_QUAD ((ipaddr_t)-1)
+#define BROADCAST_ADDR ((ipaddr_t)0xffffffff)
+#define LOCALHOST_ADDR ((ipaddr_t)0x7f000001)
+
+#if PACKETSZ > 1024
+#define MAXPACKET PACKETSZ
+#else
+#define MAXPACKET 1024
+#endif
+
+typedef union {
+ HEADER header;
+ u_char packet[MAXPACKET];
+} querybuf;
+
+#ifndef HFIXEDSZ
+#define HFIXEDSZ 12 /* actually sizeof(HEADER) */
+#endif
+
+#define MAXDLEN (MAXPACKET - HFIXEDSZ) /* upper bound for dlen */
+
+#include "rrec.h" /* resource record structures */
+
+#define input /* read-only input parameter */
+#define output /* modified output parameter */
+
+#define STDIN 0
+#define STDOUT 1
+#define STDERR 2
+
+#ifdef lint
+#define EXTERN
+#else
+#define EXTERN extern
+#endif
+
+EXTERN int errno;
+EXTERN int h_errno; /* defined in gethostnamadr.c */
+EXTERN res_state_t _res; /* defined in res_init.c */
+extern char *dbprefix; /* prefix for debug messages (send.c) */
+extern char *version; /* program version number (vers.c) */
+
+char **optargv = NULL; /* argument list including default options */
+int optargc = 0; /* number of arguments in new argument list */
+
+int errorcount = 0; /* global error count */
+
+int record_stats[T_ANY+1]; /* count of resource records per type */
+
+char cnamebuf[MAXDNAME+1];
+char *cname = NULL; /* name to which CNAME is aliased */
+
+char mnamebuf[MAXDNAME+1];
+char *mname = NULL; /* name to which MR or MG is aliased */
+
+char soanamebuf[MAXDNAME+1];
+char *soaname = NULL; /* domain name of SOA record */
+
+char subnamebuf[MAXDNAME+1];
+char *subname = NULL; /* domain name of NS record */
+
+char adrnamebuf[MAXDNAME+1];
+char *adrname = NULL; /* domain name of A record */
+
+ipaddr_t address; /* internet address of A record */
+
+char *listhost = NULL; /* actual host queried during zone listing */
+
+char serverbuf[MAXDNAME+1];
+char *server = NULL; /* name of explicit server to query */
+
+char realnamebuf[2*MAXDNAME+2];
+char *realname = NULL; /* the actual name that was queried */
+
+FILE *logfile = NULL; /* default is stdout only */
+bool logexchange = FALSE; /* exchange role of log file and stdout */
+
+char *illegal = NULL; /* give warning about illegal domain names */
+char *skipzone = NULL; /* zone(s) for which to skip zone transfer */
+char *prefserver = NULL; /* preferred server(s) for zone listing */
+
+char *queryname = NULL; /* the name about which to query */
+int querytype = T_NONE; /* the type of the query */
+int queryclass = C_IN; /* the class of the query */
+ipaddr_t queryaddr; /* set if name to query is dotted quad */
+
+int debug = 0; /* print resolver debugging output */
+int verbose = 0; /* verbose mode for extra output */
+
+#ifdef justfun
+int namelen = 0; /* select records exceeding this length */
+#endif
+
+int recursive = 0; /* recursive listmode maximum level */
+int recursion_level = 0; /* current recursion level */
+int skip_level = 0; /* level beyond which to skip checks */
+
+bool quiet = FALSE; /* suppress non-fatal warning messages */
+bool reverse = FALSE; /* generate reverse in-addr.arpa queries */
+bool revnsap = FALSE; /* generate reverse nsap.int queries */
+bool primary = FALSE; /* use primary server for zone transfers */
+bool suppress = FALSE; /* suppress resource record output */
+bool dotprint = FALSE; /* print trailing dot in non-listing mode */
+bool ttlprint = FALSE; /* print ttl value in non-verbose mode */
+bool waitmode = FALSE; /* wait until server becomes available */
+bool mailmode = FALSE; /* trace MG and MR into MB records */
+bool addrmode = FALSE; /* check reverse mappings of addresses */
+bool listmode = FALSE; /* generate zone listing of a zone */
+bool hostmode = FALSE; /* count real hosts residing within zone */
+bool duplmode = FALSE; /* list duplicate hosts within zone */
+bool extrmode = FALSE; /* list extrazone hosts within zone */
+bool gatemode = FALSE; /* list gateway hosts within zone */
+bool checkmode = FALSE; /* check SOA records at each nameserver */
+bool mxdomains = FALSE; /* list MX records for each delegated zone */
+bool wildcards = FALSE; /* list only wildcard records in a zone */
+bool listzones = FALSE; /* list only delegated zones in a zone */
+bool exclusive = FALSE; /* exclude records that are not in zone */
+bool recurskip = FALSE; /* skip certain checks during recursion */
+bool statistics = FALSE; /* print resource record statistics */
+bool bindcompat = FALSE; /* enforce full BIND DNSRCH compatibility */
+bool classprint = FALSE; /* print class value in non-verbose mode */
+
+#include "defs.h" /* declaration of functions */
+
+#define lower(c) (((c) >= 'A' && (c) <= 'Z') ? (c) + 'a' - 'A' : (c))
+#define hexdigit(n) (((n) < 10) ? '0' + (n) : 'A' + (n) - 10);
+
+#define is_xdigit(c) (isascii(c) && isxdigit(c))
+#define is_space(c) (isascii(c) && isspace(c))
+#define is_alnum(c) (isascii(c) && isalnum(c))
+#define is_upper(c) (isascii(c) && isupper(c))
+
+#define bitset(a,b) (((a) & (b)) != 0)
+#define sameword(a,b) (strcasecmp(a,b) == 0)
+#define samepart(a,b) (strncasecmp(a,b,strlen(b)) == 0)
+#define samehead(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
+
+#define fakename(a) (samehead(a,"localhost.") || samehead(a,"loopback."))
+#define nulladdr(a) (((a) == 0) || ((a) == BROADCAST_ADDR))
+#define fakeaddr(a) (nulladdr(a) || ((a) == htonl(LOCALHOST_ADDR)))
+#define incopy(a) *((struct in_addr *)a)
+
+#define newlist(a,n,t) (t *)xalloc((ptr_t *)a, (siz_t)((n)*sizeof(t)))
+#define newstring(s) (char *)xalloc((ptr_t *)NULL, (siz_t)(strlen(s)+1))
+#define newstr(s) strcpy(newstring(s), s)
+#define xfree(a) (void) free((ptr_t *)a)
+
+#define strlength(s) (int)strlen(s)
+#define in_string(s,c) (index(s,c) != NULL)
+
+#define plural(n) (((n) == 1) ? "" : "s")
+#define plurale(n) (((n) == 1) ? "" : "es")
+
+#ifdef DEBUG
+#define assert(condition)\
+{\
+ if (!(condition))\
+ {\
+ (void) fprintf(stderr, "assertion botch: ");\
+ (void) fprintf(stderr, "%s(%d): ", __FILE__, __LINE__);\
+ (void) fprintf(stderr, "%s\n", "condition");\
+ exit(EX_SOFTWARE);\
+ }\
+}
+#else
+#define assert(condition)
+#endif
+
+ /*
+** MAIN -- Start of program host
+** -----------------------------
+**
+** Exits:
+** EX_OK Operation successfully completed
+** EX_UNAVAILABLE Could not obtain requested information
+** EX_CANTCREAT Could not create specified log file
+** EX_NOINPUT No input arguments were found
+** EX_NOHOST Could not lookup explicit server
+** EX_OSERR Could not obtain resources
+** EX_USAGE Improper parameter/option specified
+** EX_SOFTWARE Assertion botch in DEBUG mode
+*/
+
+int
+main(argc, argv)
+input int argc;
+input char *argv[];
+{
+ register char *option;
+ res_state_t new_res; /* new resolver database */
+ int result; /* result status of action taken */
+ char *program; /* name that host was called with */
+ char *servername = NULL; /* name of explicit server */
+ char *logfilename = NULL; /* name of log file */
+ bool extended = FALSE; /* accept extended argument syntax */
+
+ assert(sizeof(int) >= 4); /* probably paranoid */
+#ifdef obsolete
+ assert(sizeof(u_short) == 2); /* perhaps less paranoid */
+ assert(sizeof(ipaddr_t) == 4); /* but this is critical */
+#endif
+
+/*
+ * Synchronize stdout and stderr in case output is redirected.
+ */
+ linebufmode(stdout);
+
+/*
+ * Initialize resolver, set new defaults. See show_res() for details.
+ * The old defaults are (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
+ */
+ (void) res_init();
+
+ _res.options |= RES_DEFNAMES; /* qualify single names */
+ _res.options &= ~RES_DNSRCH; /* dotted names are qualified */
+
+ _res.options |= RES_RECURSE; /* request nameserver recursion */
+ _res.options &= ~RES_DEBUG; /* turn off debug printout */
+ _res.options &= ~RES_USEVC; /* do not use virtual circuit */
+
+ _res.retry = 2; /* number of retries, default = 4 */
+ _res.retrans = 5; /* timeout in seconds, default = 5 or 6 */
+
+ /* initialize packet id */
+ _res.id = getpid() & 0x7fff;
+
+ /* save new defaults */
+ new_res = _res;
+
+/*
+ * Check whether host was called with a different name.
+ * Interpolate default options and parameters.
+ */
+ if (argc < 1 || argv[0] == NULL)
+ fatal(Usage);
+
+ option = getenv("HOST_DEFAULTS");
+ if (option != NULL)
+ {
+ set_defaults(option, argc, argv);
+ argc = optargc; argv = optargv;
+ }
+
+ program = rindex(argv[0], '/');
+ if (program++ == NULL)
+ program = argv[0];
+
+ /* check for resource record names */
+ querytype = parse_type(program);
+ if (querytype < 0)
+ querytype = T_NONE;
+
+ /* check for zone listing abbreviation */
+ if (sameword(program, "zone"))
+ listmode = TRUE;
+
+/*
+ * Scan command line options and flags.
+ */
+ while (argc > 1 && argv[1] != NULL && argv[1][0] == '-')
+ {
+ for (option = &argv[1][1]; *option != '\0'; option++)
+ {
+ switch (*option)
+ {
+ case 'w' :
+ waitmode = TRUE;
+ new_res.retry = 2;
+ new_res.retrans = 5;
+ break;
+
+ case 's' :
+ if (argv[2] == NULL || argv[2][0] == '-')
+ fatal("Missing timeout value");
+ new_res.retry = 2;
+ new_res.retrans = atoi(argv[2]);
+ if (new_res.retrans <= 0)
+ fatal("Invalid timeout value %s", argv[2]);
+ argv++; argc--;
+ break;
+
+ case 'r' :
+ new_res.options &= ~RES_RECURSE;
+ break;
+
+ case 'B' :
+ bindcompat = TRUE;
+ /*FALLTHROUGH*/
+
+ case 'R' :
+ new_res.options |= RES_DNSRCH;
+ break;
+
+ case 'u' :
+ new_res.options |= RES_USEVC;
+ break;
+
+ case 'd' :
+ new_res.options |= RES_DEBUG;
+ debug++; /* increment debugging level */
+ break;
+
+ case 'v' :
+ verbose++; /* increment verbosity level */
+ break;
+
+ case 'q' :
+ quiet = TRUE;
+ break;
+
+ case 'i' :
+ reverse = TRUE;
+ break;
+
+ case 'n' :
+ revnsap = TRUE;
+ break;
+
+ case 'p' :
+ primary = TRUE;
+ break;
+
+ case 'o' :
+ suppress = TRUE;
+ break;
+
+ case 'e' :
+ exclusive = TRUE;
+ break;
+
+ case 'S' :
+ statistics = TRUE;
+ break;
+
+ case 'T' :
+ ttlprint = TRUE;
+ break;
+
+ case 'Z' :
+ dotprint = TRUE;
+ ttlprint = TRUE;
+ classprint = TRUE;
+ break;
+
+ case 'A' :
+ addrmode = TRUE;
+ break;
+
+ case 'D' :
+ case 'E' :
+ case 'G' :
+ case 'H' :
+ if (*option == 'D')
+ duplmode = TRUE;
+ if (*option == 'E')
+ extrmode = TRUE;
+ if (*option == 'G')
+ gatemode = TRUE;
+ hostmode = TRUE;
+ listmode = TRUE;
+ if (querytype == T_NONE)
+ querytype = -1; /* suppress zone data output */
+ break;
+
+ case 'C' :
+ checkmode = TRUE;
+ listmode = TRUE;
+ if (querytype == T_NONE)
+ querytype = -1; /* suppress zone data output */
+ break;
+
+ case 'z' :
+ listzones = TRUE;
+ listmode = TRUE;
+ if (querytype == T_NONE)
+ querytype = -1; /* suppress zone data output */
+ break;
+
+ case 'M' :
+ mxdomains = TRUE;
+ listmode = TRUE;
+ if (querytype == T_NONE)
+ querytype = -1; /* suppress zone data output */
+ break;
+
+ case 'W' :
+ wildcards = TRUE;
+ listmode = TRUE;
+ if (querytype == T_NONE)
+ querytype = T_MX;
+ break;
+
+ case 'L' :
+ if (argv[2] == NULL || argv[2][0] == '-')
+ fatal("Missing recursion level");
+ recursive = atoi(argv[2]);
+ if (recursive <= 0)
+ fatal("Invalid recursion level %s", argv[2]);
+ argv++; argc--;
+ /*FALLTHROUGH*/
+
+ case 'l' :
+ listmode = TRUE;
+ break;
+
+ case 'c' :
+ if (argv[2] == NULL || argv[2][0] == '-')
+ fatal("Missing query class");
+ queryclass = parse_class(argv[2]);
+ if (queryclass < 0)
+ fatal("Invalid query class %s", argv[2]);
+ argv++; argc--;
+ break;
+
+ case 't' :
+ if (argv[2] == NULL || argv[2][0] == '-')
+ fatal("Missing query type");
+ querytype = parse_type(argv[2]);
+ if (querytype < 0)
+ fatal("Invalid query type %s", argv[2]);
+ argv++; argc--;
+ break;
+
+ case 'a' :
+ querytype = T_ANY; /* filter anything available */
+ break;
+
+ case 'm' :
+ mailmode = TRUE;
+ querytype = T_MAILB; /* filter MINFO/MG/MR/MB data */
+ break;
+
+ case 'I' :
+ if (argv[2] == NULL || argv[2][0] == '-')
+ fatal("Missing allowed chars");
+ illegal = argv[2];
+ argv++; argc--;
+ break;
+
+ case 'P' :
+ if (argv[2] == NULL || argv[2][0] == '-')
+ fatal("Missing preferred server");
+ prefserver = argv[2];
+ argv++; argc--;
+ break;
+
+ case 'N' :
+ if (argv[2] == NULL || argv[2][0] == '-')
+ fatal("Missing zone to be skipped");
+ skipzone = argv[2];
+ argv++; argc--;
+ break;
+
+ case 'F' :
+ logexchange = TRUE;
+ /*FALLTHROUGH*/
+
+ case 'f' :
+ if (argv[2] == NULL || argv[2][0] == '-')
+ fatal("Missing log file name");
+ logfilename = argv[2];
+ argv++; argc--;
+ break;
+
+ case 'X' :
+ if (argv[2] == NULL || argv[2][0] == '-')
+ fatal("Missing server name");
+ servername = argv[2];
+ argv++; argc--;
+ /*FALLTHROUGH*/
+
+ case 'x' :
+ extended = TRUE;
+ break;
+#ifdef justfun
+ case 'g' :
+ if (argv[2] == NULL || argv[2][0] == '-')
+ fatal("Missing minimum length");
+ namelen = atoi(argv[2]);
+ if (namelen <= 0)
+ fatal("Invalid minimum length %s", argv[2]);
+ argv++; argc--;
+ break;
+#endif
+ case 'V' :
+ printf("Version %s\n", version);
+ exit(EX_OK);
+
+ default:
+ fatal(Usage);
+ }
+ }
+
+ argv++; argc--;
+ }
+
+/*
+ * Check the remaining arguments.
+ */
+ /* old syntax must have at least one argument */
+ if (!extended && (argc < 2 || argv[1] == NULL || argc > 3))
+ fatal(Usage);
+
+ /* old syntax has explicit server as second argument */
+ if (!extended && (argc > 2 && argv[2] != NULL))
+ servername = argv[2];
+
+/*
+ * Open log file if requested.
+ */
+ if (logfilename != NULL)
+ set_logfile(logfilename);
+
+/*
+ * Set default preferred server for zone listings, if not specified.
+ */
+ if (listmode && (prefserver == NULL))
+ prefserver = myhostname();
+
+/*
+ * Check for possible alternative server. Use new resolver defaults.
+ */
+ if (servername != NULL)
+ set_server(servername);
+
+/*
+ * Do final resolver initialization.
+ * Show resolver parameters and special environment options.
+ */
+ /* set new resolver values changed by command options */
+ _res.retry = new_res.retry;
+ _res.retrans = new_res.retrans;
+ _res.options = new_res.options;
+
+ /* show the new resolver database */
+ if (debug > 1 || verbose > 1)
+ show_res();
+
+ /* show customized default domain */
+ option = getenv("LOCALDOMAIN");
+ if (option != NULL && verbose > 1)
+ printf("Explicit local domain %s\n\n", option);
+
+/*
+ * Process command line argument(s) depending on syntax.
+ */
+ if (!extended) /* only one argument */
+ result = process_name(argv[1]);
+
+ else if (argc < 2) /* no arguments */
+ result = process_file(stdin);
+
+ else /* multiple command line arguments */
+ result = process_argv(argc, argv);
+
+/*
+ * Report result status of action taken.
+ */
+ exit(result);
+ /*NOTREACHED*/
+}
+
+ /*
+** SET_DEFAULTS -- Interpolate default options and parameters in argv
+** ------------------------------------------------------------------
+**
+** The HOST_DEFAULTS environment variable gives customized options.
+**
+** Returns:
+** None.
+**
+** Outputs:
+** Creates ``optargv'' vector with ``optargc'' arguments.
+*/
+
+void
+set_defaults(option, argc, argv)
+input char *option; /* option string */
+input int argc; /* original command line arg count */
+input char *argv[]; /* original command line arguments */
+{
+ register char *p, *q;
+ register int i;
+
+/*
+ * Allocate new argument vector.
+ */
+ optargv = newlist(NULL, 2, char *);
+ optargv[0] = argv[0];
+ optargc = 1;
+
+/*
+ * Construct argument list from option string.
+ */
+ for (q = "", p = newstr(option); *p != '\0'; p = q)
+ {
+ while (is_space(*p))
+ p++;
+
+ if (*p == '\0')
+ break;
+
+ for (q = p; *q != '\0' && !is_space(*q); q++)
+ continue;
+
+ if (*q != '\0')
+ *q++ = '\0';
+
+ optargv = newlist(optargv, optargc+2, char *);
+ optargv[optargc] = p;
+ optargc++;
+ }
+
+/*
+ * Append command line arguments.
+ */
+ for (i = 1; i < argc && argv[i] != NULL; i++)
+ {
+ optargv = newlist(optargv, optargc+2, char *);
+ optargv[optargc] = argv[i];
+ optargc++;
+ }
+
+ /* and terminate */
+ optargv[optargc] = NULL;
+}
+
+ /*
+** PROCESS_ARGV -- Process command line arguments
+** ----------------------------------------------
+**
+** Returns:
+** EX_OK if information was obtained successfully.
+** Appropriate exit code otherwise.
+*/
+
+int
+process_argv(argc, argv)
+input int argc;
+input char *argv[];
+{
+ register int i;
+ int result; /* result status of action taken */
+ int excode = EX_NOINPUT; /* overall result status */
+
+ for (i = 1; i < argc && argv[i] != NULL; i++)
+ {
+ /* process a single argument */
+ result = process_name(argv[i]);
+
+ /* maintain overall result */
+ if (result != EX_OK || excode == EX_NOINPUT)
+ excode = result;
+ }
+
+ /* return overall result */
+ return(excode);
+}
+
+ /*
+** PROCESS_FILE -- Process arguments from input file
+** -------------------------------------------------
+**
+** Returns:
+** EX_OK if information was obtained successfully.
+** Appropriate exit code otherwise.
+*/
+
+int
+process_file(fp)
+input FILE *fp; /* input file with query names */
+{
+ register char *p, *q;
+ char buf[BUFSIZ];
+ int result; /* result status of action taken */
+ int excode = EX_NOINPUT; /* overall result status */
+
+ while (fgets(buf, sizeof(buf), fp) != NULL)
+ {
+ p = index(buf, '\n');
+ if (p != NULL)
+ *p = '\0';
+
+ /* extract names separated by whitespace */
+ for (q = "", p = buf; *p != '\0'; p = q)
+ {
+ while (is_space(*p))
+ p++;
+
+ /* ignore comment lines */
+ if (*p == '\0' || *p == '#' || *p == ';')
+ break;
+
+ for (q = p; *q != '\0' && !is_space(*q); q++)
+ continue;
+
+ if (*q != '\0')
+ *q++ = '\0';
+
+ /* process a single argument */
+ result = process_name(p);
+
+ /* maintain overall result */
+ if (result != EX_OK || excode == EX_NOINPUT)
+ excode = result;
+ }
+ }
+
+ /* return overall result */
+ return(excode);
+}
+
+ /*
+** PROCESS_NAME -- Process a single command line argument
+** ------------------------------------------------------
+**
+** Returns:
+** EX_OK if information was obtained successfully.
+** Appropriate exit code otherwise.
+**
+** Wrapper for execute_name() to hide administrative tasks.
+*/
+
+int
+process_name(name)
+input char *name; /* command line argument */
+{
+ int result; /* result status of action taken */
+ static int save_querytype;
+ static bool save_reverse;
+ static bool firstname = TRUE;
+
+ /* separate subsequent pieces of output */
+ if (!firstname && (verbose || debug || checkmode))
+ printf("\n");
+
+/*
+ * Some global variables are redefined further on. Save their initial
+ * values in the first pass, and restore them during subsequent passes.
+ */
+ if (firstname)
+ {
+ save_querytype = querytype;
+ save_reverse = reverse;
+ firstname = FALSE;
+ }
+ else
+ {
+ querytype = save_querytype;
+ reverse = save_reverse;
+ }
+
+/*
+ * Do the real work.
+ */
+ result = execute_name(name);
+ return(result);
+}
+
+ /*
+** EXECUTE_NAME -- Process a single command line argument
+** ------------------------------------------------------
+**
+** Returns:
+** EX_OK if information was obtained successfully.
+** Appropriate exit code otherwise.
+**
+** Outputs:
+** Defines ``queryname'' and ``queryaddr'' appropriately.
+**
+** Side effects:
+** May redefine ``querytype'' and ``reverse'' if necessary.
+*/
+
+int
+execute_name(name)
+input char *name; /* command line argument */
+{
+ bool result; /* result status of action taken */
+
+ /* check for nonsense input name */
+ if (strlength(name) > MAXDNAME)
+ {
+ errmsg("Query name %s too long", name);
+ return(EX_USAGE);
+ }
+
+/*
+ * Analyze the name and type to be queried about.
+ * The name can be an ordinary domain name, or an internet address
+ * in dotted quad notation. If the -n option is given, the name is
+ * supposed to be a dotted nsap address.
+ */
+ queryname = name;
+ if (queryname[0] == '\0')
+ queryname = ".";
+
+ if (sameword(queryname, "."))
+ queryaddr = NOT_DOTTED_QUAD;
+ else
+ queryaddr = inet_addr(queryname);
+
+/*
+ * Generate reverse in-addr.arpa query if so requested.
+ * The input name must be a dotted quad, and be convertible.
+ */
+ if (reverse)
+ {
+ if (queryaddr == NOT_DOTTED_QUAD)
+ name = queryname, queryname = NULL;
+ else
+ queryname = in_addr_arpa(queryname);
+
+ if (queryname == NULL)
+ {
+ errmsg("Invalid dotted quad %s", name);
+ return(EX_USAGE);
+ }
+
+ queryaddr = NOT_DOTTED_QUAD;
+ }
+
+/*
+ * Generate reverse nsap.int query if so requested.
+ * The input name must be a dotted nsap, and be convertible.
+ */
+ if (revnsap)
+ {
+ if (reverse)
+ name = queryname, queryname = NULL;
+ else
+ queryname = nsap_int(queryname);
+
+ if (queryname == NULL)
+ {
+ errmsg("Invalid nsap address %s", name);
+ return(EX_USAGE);
+ }
+
+ queryaddr = NOT_DOTTED_QUAD;
+ reverse = TRUE;
+ }
+
+/*
+ * In regular mode, the querytype is used to formulate the nameserver
+ * query, and any response is filtered out when processing the answer.
+ * In listmode, the querytype is used to filter out the proper records.
+ */
+ /* set querytype for regular mode if unspecified */
+ if ((querytype == T_NONE) && !listmode)
+ {
+ if ((queryaddr != NOT_DOTTED_QUAD) || reverse)
+ querytype = T_PTR;
+ else
+ querytype = T_A;
+ }
+
+/*
+ * Check for incompatible options.
+ */
+ /* cannot have dotted quad in listmode */
+ if (listmode && (queryaddr != NOT_DOTTED_QUAD))
+ {
+ errmsg("Invalid query name %s", queryname);
+ return(EX_USAGE);
+ }
+
+ /* must have regular name or dotted quad in addrmode */
+ if (!listmode && addrmode && reverse)
+ {
+ errmsg("Invalid query name %s", queryname);
+ return(EX_USAGE);
+ }
+
+ /* show what we are going to query about */
+ if (verbose)
+ show_types(queryname, querytype, queryclass);
+
+/*
+ * All set. Perform requested function.
+ */
+ result = execute(queryname, queryaddr);
+ return(result ? EX_OK : EX_UNAVAILABLE);
+}
+
+ /*
+** EXECUTE -- Perform the requested function
+** -----------------------------------------
+**
+** Returns:
+** TRUE if information was obtained successfully.
+** FALSE otherwise.
+**
+** The whole environment has been set up and checked.
+*/
+
+bool
+execute(name, addr)
+input char *name; /* name to query about */
+input ipaddr_t addr; /* explicit address of query */
+{
+ bool result; /* result status of action taken */
+
+/*
+ * Special mode to list contents of specified zone.
+ */
+ if (listmode)
+ {
+ result = list_zone(name);
+ return(result);
+ }
+
+/*
+ * Special mode to check reverse mappings of host addresses.
+ */
+ if (addrmode)
+ {
+ if (addr == NOT_DOTTED_QUAD)
+ result = check_addr(name);
+ else
+ result = check_name(addr);
+ return(result);
+ }
+
+/*
+ * Regular mode to query about specified host.
+ */
+ result = host_query(name, addr);
+ return(result);
+}
+
+ /*
+** HOST_QUERY -- Regular mode to query about specified host
+** --------------------------------------------------------
+**
+** Returns:
+** TRUE if information was obtained successfully.
+** FALSE otherwise.
+*/
+
+bool
+host_query(name, addr)
+input char *name; /* name to query about */
+input ipaddr_t addr; /* explicit address of query */
+{
+ struct hostent *hp;
+ struct in_addr inaddr;
+ char newnamebuf[MAXDNAME+1];
+ char *newname = NULL; /* name to which CNAME is aliased */
+ int ncnames = 0; /* count of CNAMEs in chain */
+ bool result; /* result status of action taken */
+
+ inaddr.s_addr = addr;
+
+ result = FALSE;
+ h_errno = TRY_AGAIN;
+
+ /* retry until positive result or permanent failure */
+ while (result == FALSE && h_errno == TRY_AGAIN)
+ {
+ /* reset before each query to avoid stale data */
+ errno = 0;
+ realname = NULL;
+
+ if (addr == NOT_DOTTED_QUAD)
+ {
+ /* reset CNAME indicator */
+ cname = NULL;
+
+ /* lookup the name in question */
+ if (newname == NULL)
+ result = get_hostinfo(name, FALSE);
+ else
+ result = get_hostinfo(newname, TRUE);
+
+ /* recurse on CNAMEs, but not too deep */
+ if (cname && (querytype != T_CNAME))
+ {
+ newname = strcpy(newnamebuf, cname);
+
+ if (++ncnames > 5)
+ {
+ errmsg("Possible CNAME loop");
+ return(FALSE);
+ }
+
+ result = FALSE;
+ h_errno = TRY_AGAIN;
+ continue;
+ }
+ }
+ else
+ {
+ hp = gethostbyaddr((char *)&inaddr, INADDRSZ, AF_INET);
+ if (hp != NULL)
+ {
+ print_host("Name", hp);
+ result = TRUE;
+ }
+ }
+
+ /* only retry if so requested */
+ if (!waitmode)
+ break;
+ }
+
+ /* use actual name if available */
+ if (realname != NULL)
+ name = realname;
+
+ /* explain the reason of a failure */
+ if (result == FALSE)
+ ns_error(name, querytype, queryclass, server);
+
+ return(result);
+}
+
+ /*
+** MYHOSTNAME -- Determine our own fully qualified host name
+** ---------------------------------------------------------
+**
+** Returns:
+** Pointer to own host name.
+** Aborts if host name could not be determined.
+*/
+
+char *
+myhostname()
+{
+ struct hostent *hp;
+ static char mynamebuf[MAXDNAME+1];
+ static char *myname = NULL;
+
+ if (myname == NULL)
+ {
+ if (gethostname(mynamebuf, MAXDNAME) < 0)
+ {
+ perror("gethostname");
+ exit(EX_OSERR);
+ }
+ mynamebuf[MAXDNAME] = '\0';
+
+ hp = gethostbyname(mynamebuf);
+ if (hp == NULL)
+ {
+ ns_error(mynamebuf, T_A, C_IN, server);
+ errmsg("Error in looking up own name");
+ exit(EX_NOHOST);
+ }
+
+ /* cache the result */
+ myname = strcpy(mynamebuf, hp->h_name);
+ }
+
+ return(myname);
+}
+
+ /*
+** SET_SERVER -- Override default nameserver with explicit server
+** --------------------------------------------------------------
+**
+** Returns:
+** None.
+** Aborts the program if an unknown host was given.
+**
+** Side effects:
+** The global variable ``server'' is set to indicate
+** that an explicit server is being used.
+**
+** The default nameserver addresses in the resolver database
+** which are initialized by res_init() from /etc/resolv.conf
+** are replaced with the (possibly multiple) addresses of an
+** explicitly named server host. If a dotted quad is given,
+** only that single address will be used.
+**
+** The answers from such server must be interpreted with some
+** care if we don't know beforehand whether it can be trusted.
+*/
+
+void
+set_server(name)
+input char *name; /* name of server to be queried */
+{
+ register int i;
+ struct hostent *hp;
+ struct in_addr inaddr;
+ ipaddr_t addr; /* explicit address of server */
+
+ /* check for nonsense input name */
+ if (strlength(name) > MAXDNAME)
+ {
+ errmsg("Server name %s too long", name);
+ exit(EX_USAGE);
+ }
+
+/*
+ * Overrule the default nameserver addresses.
+ */
+ addr = inet_addr(name);
+ inaddr.s_addr = addr;
+
+ if (addr == NOT_DOTTED_QUAD)
+ {
+ /* lookup all of its addresses; this must not fail */
+ hp = gethostbyname(name);
+ if (hp == NULL)
+ {
+ ns_error(name, T_A, C_IN, server);
+ errmsg("Error in looking up server name");
+ exit(EX_NOHOST);
+ }
+
+ for (i = 0; i < MAXNS && hp->h_addr_list[i]; i++)
+ {
+ nslist(i).sin_family = AF_INET;
+ nslist(i).sin_port = htons(NAMESERVER_PORT);
+ nslist(i).sin_addr = incopy(hp->h_addr_list[i]);
+ }
+ _res.nscount = i;
+ }
+ else
+ {
+ /* lookup the name, but use only the given address */
+ hp = gethostbyaddr((char *)&inaddr, INADDRSZ, AF_INET);
+
+ nslist(0).sin_family = AF_INET;
+ nslist(0).sin_port = htons(NAMESERVER_PORT);
+ nslist(0).sin_addr = inaddr;
+ _res.nscount = 1;
+ }
+
+/*
+ * Indicate the use of an explicit server.
+ */
+ if (hp != NULL)
+ {
+ server = strcpy(serverbuf, hp->h_name);
+ if (verbose)
+ print_host("Server", hp);
+ }
+ else
+ {
+ server = strcpy(serverbuf, inet_ntoa(inaddr));
+ if (verbose)
+ printf("Server: %s\n\n", server);
+ }
+}
+
+ /*
+** SET_LOGFILE -- Initialize optional log file
+** -------------------------------------------
+**
+** Returns:
+** None.
+** Aborts the program if the file could not be created.
+**
+** Side effects:
+** The global variable ``logfile'' is set to indicate
+** that resource record output is to be written to it.
+**
+** Swap ordinary stdout and log file output if so requested.
+*/
+
+void
+set_logfile(filename)
+input char *filename; /* name of log file */
+{
+ if (logexchange)
+ {
+ logfile = fdopen(dup(STDOUT), "w");
+ if (logfile == NULL)
+ {
+ perror("fdopen");
+ exit(EX_OSERR);
+ }
+
+ if (freopen(filename, "w", stdout) == NULL)
+ {
+ perror(filename);
+ exit(EX_CANTCREAT);
+ }
+ }
+ else
+ {
+ logfile = fopen(filename, "w");
+ if (logfile == NULL)
+ {
+ perror(filename);
+ exit(EX_CANTCREAT);
+ }
+ }
+}
+
+ /*
+** FATAL -- Abort program when illegal option encountered
+** ------------------------------------------------------
+**
+** Returns:
+** Aborts after issuing error message.
+*/
+
+void /*VARARGS1*/
+fatal(fmt, a, b, c, d)
+input char *fmt; /* format of message */
+input char *a, *b, *c, *d; /* optional arguments */
+{
+ (void) fprintf(stderr, fmt, a, b, c, d);
+ (void) fprintf(stderr, "\n");
+ exit(EX_USAGE);
+}
+
+
+/*
+** ERRMSG -- Issue error message to error output
+** ---------------------------------------------
+**
+** Returns:
+** None.
+**
+** Side effects:
+** Increments the global error count.
+*/
+
+void /*VARARGS1*/
+errmsg(fmt, a, b, c, d)
+input char *fmt; /* format of message */
+input char *a, *b, *c, *d; /* optional arguments */
+{
+ (void) fprintf(stderr, fmt, a, b, c, d);
+ (void) fprintf(stderr, "\n");
+
+ /* flag an error */
+ errorcount++;
+}
+
+ /*
+** GET_HOSTINFO -- Principal routine to query about given name
+** -----------------------------------------------------------
+**
+** Returns:
+** TRUE if requested info was obtained successfully.
+** FALSE otherwise.
+**
+** This is the equivalent of the resolver module res_search().
+**
+** In this program RES_DEFNAMES is always on, and RES_DNSRCH
+** is off by default. This means that single names without dot
+** are always, and only, tried within the own default domain,
+** and compound names are assumed to be already fully qualified.
+**
+** The default BIND behavior can be simulated by turning on
+** RES_DNSRCH with -R. The given name, whether or not compound,
+** is then first tried within the possible search domains.
+**
+** Note. In the latter case, the search terminates in case the
+** specified name exists but does not have the desired type.
+** The BIND behavior is to continue the search. This can be
+** simulated with the undocumented option -B.
+*/
+
+bool
+get_hostinfo(name, qualified)
+input char *name; /* name to query about */
+input bool qualified; /* assume fully qualified if set */
+{
+ register char **domain;
+ register char *cp;
+ int dot; /* number of dots in query name */
+ bool result; /* result status of action taken */
+ char oldnamebuf[2*MAXDNAME+2];
+ char *oldname; /* saved actual name when NO_DATA */
+ int nodata = 0; /* NO_DATA status during DNSRCH */
+ int nquery = 0; /* number of extra search queries */
+
+/*
+ * Single dot means root zone.
+ */
+ if (sameword(name, "."))
+ qualified = TRUE;
+
+/*
+ * Names known to be fully qualified are just tried ``as is''.
+ */
+ if (qualified)
+ {
+ result = get_domaininfo(name, (char *)NULL);
+ return(result);
+ }
+
+/*
+ * Count number of dots. Move to the end of the name.
+ */
+ for (dot = 0, cp = name; *cp != '\0'; cp++)
+ if (*cp == '.')
+ dot++;
+
+/*
+ * Check for aliases of single name.
+ * Note that the alias is supposed to be fully qualified.
+ */
+ if (dot == 0 && (cp = hostalias(name)) != NULL)
+ {
+ if (verbose)
+ printf("Aliased to \"%s\"\n", cp);
+
+ result = get_domaininfo(cp, (char *)NULL);
+ return(result);
+ }
+
+/*
+ * Trailing dot means absolute (fully qualified) address.
+ */
+ if (dot != 0 && cp[-1] == '.')
+ {
+ cp[-1] = '\0';
+ result = get_domaininfo(name, (char *)NULL);
+ cp[-1] = '.';
+ return(result);
+ }
+
+/*
+ * Append own default domain and other search domains if appropriate.
+ */
+ if ((dot == 0 && bitset(RES_DEFNAMES, _res.options)) ||
+ (dot != 0 && bitset(RES_DNSRCH, _res.options)))
+ {
+ for (domain = _res.dnsrch; *domain; domain++)
+ {
+ result = get_domaininfo(name, *domain);
+ if (result)
+ return(result);
+
+ /* keep count of extra search queries */
+ nquery++;
+
+ /* in case nameserver not present */
+ if (errno == ECONNREFUSED)
+ return(FALSE);
+
+ /* if no further search desired (single name) */
+ if (!bitset(RES_DNSRCH, _res.options))
+ break;
+
+ /* if name exists but has not requested type */
+ if (h_errno == NO_DATA || h_errno == NO_RREC)
+ {
+ if (bindcompat)
+ {
+ /* remember status and search up */
+ oldname = strcpy(oldnamebuf, realname);
+ nodata = h_errno;
+ continue;
+ }
+
+ return(FALSE);
+ }
+
+ /* retry only if name does not exist at all */
+ if (h_errno != HOST_NOT_FOUND && h_errno != NO_HOST)
+ break;
+ }
+ }
+
+/*
+ * Single name lookup failed.
+ */
+ if (dot == 0)
+ {
+ /* unclear what actual name should be */
+ if (nquery != 1)
+ realname = NULL;
+
+ /* restore nodata status from search */
+ if (bindcompat && nodata)
+ {
+ realname = strcpy(realnamebuf, oldname);
+ h_errno = nodata;
+ }
+
+ /* set status in case we never queried */
+ if (!bitset(RES_DEFNAMES, _res.options))
+ h_errno = HOST_NOT_FOUND;
+
+ return(FALSE);
+ }
+
+/*
+ * Rest means fully qualified.
+ */
+ result = get_domaininfo(name, (char *)NULL);
+
+ /* restore nodata status from search */
+ if (!result && bindcompat && nodata)
+ {
+ realname = strcpy(realnamebuf, oldname);
+ h_errno = nodata;
+ }
+
+ return(result);
+}
+
+ /*
+** GET_DOMAININFO -- Fetch and print desired info about name in domain
+** -------------------------------------------------------------------
+**
+** Returns:
+** TRUE if requested info was obtained successfully.
+** FALSE otherwise.
+**
+** Side effects:
+** Sets global variable ``realname'' to actual name queried.
+**
+** This is the equivalent of the resolver module res_querydomain().
+**
+** Things get a little complicated in case RES_DNSRCH is on.
+** If we get an answer but the data is corrupted, an error will be
+** returned and NO_RECOVERY will be set. This will terminate the
+** extra search loop, but a compound name will still be tried as-is.
+** The same holds if the query times out or we have a server failure,
+** in which case an error will be returned and TRY_AGAIN will be set.
+** For now we take this for granted. Normally RES_DNSRCH is disabled.
+** In this default case we do only one query and we have no problem.
+*/
+
+bool
+get_domaininfo(name, domain)
+input char *name; /* name to query about */
+input char *domain; /* domain to which name is relative */
+{
+ char namebuf[2*MAXDNAME+2]; /* buffer to store full domain name */
+ querybuf answer;
+ register int n;
+ bool result; /* result status of action taken */
+
+/*
+ * Show what we are about to query.
+ */
+ if (verbose)
+ {
+ if (domain == NULL || domain[0] == '\0')
+ printf("Trying %s", name);
+ else
+ printf("Trying %s within %s", name, domain);
+
+ if (server && (verbose > 1))
+ printf(" at server %s", server);
+
+ printf(" ...\n");
+ }
+
+/*
+ * Construct the actual domain name.
+ * A null domain means the given name is already fully qualified.
+ * If the composite name is too long, res_mkquery() will fail.
+ */
+ if (domain == NULL || domain[0] == '\0')
+ (void) sprintf(namebuf, "%.*s", MAXDNAME, name);
+ else
+ (void) sprintf(namebuf, "%.*s.%.*s",
+ MAXDNAME, name, MAXDNAME, domain);
+ name = namebuf;
+
+/*
+ * Fetch the desired info.
+ */
+ n = get_info(&answer, name, querytype, queryclass);
+ result = (n < 0) ? FALSE : TRUE;
+
+/*
+ * Print the relevant data.
+ * If we got a positive answer, the data may still be corrupted.
+ */
+ if (result)
+ result = print_info(&answer, n, name, querytype, FALSE);
+
+/*
+ * Remember the actual name that was queried.
+ * Must be at the end to avoid clobbering during recursive calls.
+ */
+ realname = strcpy(realnamebuf, name);
+
+ return(result);
+}
+
+ /*
+** GET_INFO -- Basic routine to issue a nameserver query
+** -----------------------------------------------------
+**
+** Returns:
+** Length of nameserver answer buffer, if obtained.
+** -1 if an error occurred (h_errno is set appropriately).
+**
+** This is the equivalent of the resolver module res_query().
+*/
+
+int
+get_info(answerbuf, name, type, class)
+output querybuf *answerbuf; /* location of buffer to store answer */
+input char *name; /* full name to query about */
+input int type; /* specific resource record type */
+input int class; /* specific resource record class */
+{
+ querybuf query;
+ HEADER *bp;
+ int ancount;
+ register int n;
+
+/*
+ * Construct query, and send it to the nameserver.
+ * res_send() will fail if no nameserver responded. In the BIND version the
+ * possible values for errno are ECONNREFUSED and ETIMEDOUT. If we did get
+ * an answer, errno should be reset, since res_send() may have left an errno
+ * in case it has used datagrams. Our private version of res_send() will leave
+ * also other error statuses, and will clear errno if an answer was obtained.
+ */
+ errno = 0; /* reset before querying nameserver */
+
+ n = res_mkquery(QUERY, name, class, type, (qbuf_t *)NULL, 0,
+ (rrec_t *)NULL, (qbuf_t *)&query, sizeof(querybuf));
+ if (n < 0)
+ {
+ if (debug)
+ printf("%sres_mkquery failed\n", dbprefix);
+ h_errno = NO_RECOVERY;
+ return(-1);
+ }
+
+ n = res_send((qbuf_t *)&query, n, (qbuf_t *)answerbuf, sizeof(querybuf));
+ if (n < 0)
+ {
+ if (debug)
+ printf("%sres_send failed\n", dbprefix);
+ h_errno = TRY_AGAIN;
+ return(-1);
+ }
+
+ errno = 0; /* reset after we got an answer */
+
+ if (n < HFIXEDSZ)
+ {
+ pr_error("answer length %s too short after %s query for %s",
+ itoa(n), pr_type(type), name);
+ h_errno = NO_RECOVERY;
+ return(-1);
+ }
+
+/*
+ * Analyze the status of the answer from the nameserver.
+ */
+ if (debug || verbose)
+ print_status(answerbuf);
+
+ bp = (HEADER *)answerbuf;
+ ancount = ntohs(bp->ancount);
+
+ if (bp->rcode != NOERROR || ancount == 0)
+ {
+ switch (bp->rcode)
+ {
+ case NXDOMAIN:
+ /* distinguish between authoritative or not */
+ h_errno = bp->aa ? HOST_NOT_FOUND : NO_HOST;
+ break;
+
+ case NOERROR:
+ /* distinguish between authoritative or not */
+ h_errno = bp->aa ? NO_DATA : NO_RREC;
+ break;
+
+ case SERVFAIL:
+ h_errno = SERVER_FAILURE; /* instead of TRY_AGAIN */
+ break;
+
+ case REFUSED:
+ h_errno = QUERY_REFUSED; /* instead of NO_RECOVERY */
+ break;
+
+ default:
+ h_errno = NO_RECOVERY; /* FORMERR NOTIMP NOCHANGE */
+ break;
+ }
+ return(-1);
+ }
+
+ h_errno = 0;
+ return(n);
+}
+
+ /*
+** PRINT_INFO -- Check resource records in answer and print relevant data
+** ----------------------------------------------------------------------
+**
+** Returns:
+** TRUE if answer buffer was processed successfully.
+** FALSE otherwise.
+**
+** Side effects:
+** Will recurse on MAILB records if appropriate.
+** See also side effects of the print_rrec() routine.
+*/
+
+bool
+print_info(answerbuf, answerlen, name, type, listing)
+input querybuf *answerbuf; /* location of answer buffer */
+input int answerlen; /* length of answer buffer */
+input char *name; /* full name we are querying about */
+input int type; /* record type we are querying about */
+input bool listing; /* set if this is a zone listing */
+{
+ HEADER *bp;
+ int qdcount, ancount, nscount, arcount;
+ u_char *msg, *eom;
+ register u_char *cp;
+
+ bp = (HEADER *)answerbuf;
+ qdcount = ntohs(bp->qdcount);
+ ancount = ntohs(bp->ancount);
+ nscount = ntohs(bp->nscount);
+ arcount = ntohs(bp->arcount);
+
+ msg = (u_char *)answerbuf;
+ eom = (u_char *)answerbuf + answerlen;
+ cp = (u_char *)answerbuf + HFIXEDSZ;
+
+/*
+ * Skip the query section in the response (present only in normal queries).
+ */
+ if (qdcount)
+ {
+ while (qdcount > 0 && cp < eom)
+ {
+ /* cp += dn_skipname(cp, eom) + QFIXEDSZ; */
+ cp = skip_qrec(name, cp, msg, eom);
+ if (cp == NULL)
+ return(FALSE);
+ qdcount--;
+ }
+
+ if (qdcount)
+ {
+ pr_error("invalid qdcount after %s query for %s",
+ pr_type(type), name);
+ h_errno = NO_RECOVERY;
+ return(FALSE);
+ }
+ }
+
+/*
+ * Process the actual answer section in the response.
+ * During zone transfers, this is the only section available.
+ */
+ if (ancount)
+ {
+ if (!listing && verbose && !bp->aa)
+ printf("The following answer is not authoritative:\n");
+
+ while (ancount > 0 && cp < eom)
+ {
+ cp = print_rrec(name, cp, msg, eom, listing);
+ if (cp == NULL)
+ return(FALSE);
+ ancount--;
+
+ /*
+ * When we ask for address and there is a CNAME, it returns
+ * both the CNAME and the address. Since we trace down the
+ * CNAME chain ourselves, we don't really want to print the
+ * address at this point.
+ */
+ if (!listmode && !verbose && cname)
+ return(TRUE);
+
+ /*
+ * Recursively expand MR or MG records into MB records.
+ */
+ if (!listmode && mailmode && mname)
+ {
+ char newnamebuf[MAXDNAME+1];
+ char *newname;
+
+ newname = strcpy(newnamebuf, mname);
+ mname = NULL;
+
+ (void) get_recursive(newname);
+ }
+ }
+
+ if (ancount)
+ {
+ pr_error("invalid ancount after %s query for %s",
+ pr_type(type), name);
+ h_errno = NO_RECOVERY;
+ return(FALSE);
+ }
+ }
+
+/*
+ * The nameserver and additional info section are normally not processed.
+ * Both sections shouldn't exist in zone transfers.
+ */
+ if (!verbose || exclusive)
+ return(TRUE);
+
+ if (nscount)
+ {
+ printf("Authoritative nameservers:\n");
+
+ while (nscount > 0 && cp < eom)
+ {
+ cp = print_rrec(name, cp, msg, eom, FALSE);
+ if (cp == NULL)
+ return(FALSE);
+ nscount--;
+ }
+
+ if (nscount)
+ {
+ pr_error("invalid nscount after %s query for %s",
+ pr_type(type), name);
+ h_errno = NO_RECOVERY;
+ return(FALSE);
+ }
+ }
+
+ if (arcount)
+ {
+ printf("Additional information:\n");
+
+ while (arcount > 0 && cp < eom)
+ {
+ cp = print_rrec(name, cp, msg, eom, FALSE);
+ if (cp == NULL)
+ return(FALSE);
+ arcount--;
+ }
+
+ if (arcount)
+ {
+ pr_error("invalid arcount after %s query for %s",
+ pr_type(type), name);
+ h_errno = NO_RECOVERY;
+ return(FALSE);
+ }
+ }
+
+ return(TRUE);
+}
+
+ /*
+** PRINT_DATA -- Output resource record data if this record is wanted
+** ------------------------------------------------------------------
+**
+** Returns:
+** None.
+**
+** Inputs:
+** The global variable ``doprint'' is set by print_rrec()
+** if we need to print the data.
+*/
+
+static bool doprint; /* indicates whether or not to print */
+
+void /*VARARGS1*/
+print_data(fmt, a, b, c, d)
+input char *fmt; /* format of message */
+input char *a, *b, *c, *d; /* optional arguments */
+{
+ /* if (doprint) */
+ {
+ if (!suppress)
+ printf(fmt, a, b, c, d);
+
+ if (logfile != NULL)
+ (void) fprintf(logfile, fmt, a, b, c, d);
+ }
+}
+
+#define doprintf(x)\
+{\
+ if (doprint)\
+ {\
+ print_data x ;\
+ }\
+}
+
+ /*
+** PRINT_RREC -- Decode single resource record and output relevant data
+** --------------------------------------------------------------------
+**
+** Returns:
+** Pointer to position in answer buffer after current record.
+** NULL if there was a format error in the current record.
+**
+** Outputs:
+** The global variable ``doprint'' is set appropriately
+** for use by print_data().
+**
+** Side effects:
+** Updates resource record statistics in record_stats[].
+** Sets ``soaname'' if this is an SOA record.
+** Sets ``subname'' if this is an NS record.
+** Sets ``adrname'' if this is an A record.
+** Sets ``address'' if this is an A record.
+** Sets ``cname'' if this is a valid CNAME record.
+** Sets ``mname'' if this is a valid MAILB record.
+** These variables must have been cleared before calling
+** print_info() and may be checked afterwards.
+*/
+
+/* print domain names after certain conversions */
+#define pr_name(x) pr_domain(x, listing)
+
+/* check the LHS record name of these records for invalid characters */
+#define test_valid(t) ((t == T_A && !reverse) || t == T_MX || t == T_AAAA)
+
+/* check the RHS domain name of these records for canonical host names */
+#define test_canon(t) (t == T_NS || t == T_MX)
+
+u_char *
+print_rrec(name, cp, msg, eom, listing)
+input char *name; /* full name we are querying about */
+register u_char *cp; /* current position in answer buf */
+input u_char *msg, *eom; /* begin and end of answer buf */
+input bool listing; /* set if this is a zone listing */
+{
+ char rname[MAXDNAME+1]; /* record name in LHS */
+ char dname[MAXDNAME+1]; /* domain name in RHS */
+ int type, class, ttl, dlen; /* fixed values in every record */
+ u_char *eor; /* predicted position of next record */
+ bool classmatch; /* set if we want to see this class */
+ char *host = listhost; /* contacted host for zone listings */
+ register int n, c;
+ struct in_addr inaddr;
+ struct protoent *protocol;
+ struct servent *service;
+
+/*
+ * Pickup the standard values present in each resource record.
+ */
+ n = expand_name(name, T_NONE, cp, msg, eom, rname);
+ if (n < 0)
+ return(NULL);
+ cp += n;
+
+ n = 3*INT16SZ + INT32SZ;
+ if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
+ return(NULL);
+
+ type = _getshort(cp);
+ cp += INT16SZ;
+
+ class = _getshort(cp);
+ cp += INT16SZ;
+
+ ttl = _getlong(cp);
+ cp += INT32SZ;
+
+ dlen = _getshort(cp);
+ cp += INT16SZ;
+
+ eor = cp + dlen;
+
+/*
+ * Decide whether or not to print this resource record.
+ */
+ if (listing)
+ {
+ classmatch = want_class(class, queryclass);
+ doprint = classmatch && want_type(type, querytype);
+ }
+ else
+ {
+ classmatch = want_class(class, C_ANY);
+ doprint = classmatch && want_type(type, T_ANY);
+ }
+
+#ifdef obsolete
+ if (doprint && exclusive && !samedomain(rname, name, TRUE))
+ doprint = FALSE;
+#endif
+ if (doprint && exclusive && !indomain(rname, name, TRUE))
+ doprint = FALSE;
+
+ if (doprint && exclusive && fakename(rname))
+ doprint = FALSE;
+
+ if (doprint && wildcards && !in_string(rname, '*'))
+ doprint = FALSE;
+#ifdef justfun
+ if (namelen && (strlength(rname) < namelen))
+ doprint = FALSE;
+#endif
+
+/*
+ * Print name and common values, if appropriate.
+ */
+ doprintf(("%-20s", pr_name(rname)))
+
+ if (verbose || ttlprint)
+ doprintf(("\t%s", itoa(ttl)))
+
+ if (verbose || classprint || (class != queryclass))
+ doprintf(("\t%s", pr_class(class)))
+
+ doprintf(("\t%s", pr_type(type)))
+
+/*
+ * Update resource record statistics for zone listing.
+ */
+ if (listing && classmatch)
+ {
+ if (type >= T_FIRST && type <= T_LAST)
+ record_stats[type]++;
+ }
+
+/*
+ * Save the domain name of an SOA or NS or A record for zone listing.
+ */
+ if (listing && classmatch)
+ {
+ if (type == T_A)
+ adrname = strcpy(adrnamebuf, rname);
+
+ else if (type == T_NS)
+ subname = strcpy(subnamebuf, rname);
+
+ else if (type == T_SOA)
+ soaname = strcpy(soanamebuf, rname);
+ }
+
+/*
+ * Print type specific data, if appropriate.
+ */
+ switch (type)
+ {
+ case T_A:
+ if (class == C_IN || class == C_HS)
+ {
+ if (dlen == INADDRSZ)
+ {
+ bcopy((char *)cp, (char *)&inaddr, INADDRSZ);
+ address = inaddr.s_addr;
+ doprintf(("\t%s", inet_ntoa(inaddr)))
+ cp += INADDRSZ;
+ break;
+ }
+
+ if (dlen == INADDRSZ + 1 + INT16SZ)
+ {
+ bcopy((char *)cp, (char *)&inaddr, INADDRSZ);
+ address = inaddr.s_addr;
+ doprintf(("\t%s", inet_ntoa(inaddr)))
+ cp += INADDRSZ;
+
+ n = *cp++;
+ doprintf((" ; proto = %s", itoa(n)))
+
+ n = _getshort(cp);
+ doprintf((", port = %s", itoa(n)))
+ cp += INT16SZ;
+ break;
+ }
+
+ address = 0;
+ break;
+ }
+
+ address = 0;
+ cp += dlen;
+ break;
+
+ case T_MX:
+ if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
+ break;
+ n = _getshort(cp);
+ doprintf(("\t%s", itoa(n)))
+ cp += INT16SZ;
+
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf((" %s", pr_name(dname)))
+ cp += n;
+ break;
+
+ case T_NS:
+ case T_PTR:
+ case T_CNAME:
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf(("\t%s", pr_name(dname)))
+ cp += n;
+ break;
+
+ case T_HINFO:
+ if (check_size(rname, type, cp, msg, eor, 1) < 0)
+ break;
+ n = *cp++;
+ doprintf(("\t\"%s\"", stoa(cp, n)))
+ cp += n;
+
+ if (check_size(rname, type, cp, msg, eor, 1) < 0)
+ break;
+ n = *cp++;
+ doprintf(("\t\"%s\"", stoa(cp, n)))
+ cp += n;
+ break;
+
+ case T_SOA:
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf(("\t%s", pr_name(dname)))
+ cp += n;
+
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf((" %s", pr_name(dname)))
+ cp += n;
+
+ n = 5*INT32SZ;
+ if (check_size(rname, type, cp, msg, eor, n) < 0)
+ break;
+ doprintf((" ("))
+
+ n = _getlong(cp);
+ doprintf(("\n\t\t\t%s", utoa(n)))
+ doprintf(("\t;serial (version)"))
+ cp += INT32SZ;
+
+ n = _getlong(cp);
+ doprintf(("\n\t\t\t%s", itoa(n)))
+ doprintf(("\t;refresh period (%s)", pr_time(n, FALSE)))
+ cp += INT32SZ;
+
+ n = _getlong(cp);
+ doprintf(("\n\t\t\t%s", itoa(n)))
+ doprintf(("\t;retry interval (%s)", pr_time(n, FALSE)))
+ cp += INT32SZ;
+
+ n = _getlong(cp);
+ doprintf(("\n\t\t\t%s", itoa(n)))
+ doprintf(("\t;expire time (%s)", pr_time(n, FALSE)))
+ cp += INT32SZ;
+
+ n = _getlong(cp);
+ doprintf(("\n\t\t\t%s", itoa(n)))
+ doprintf(("\t;default ttl (%s)", pr_time(n, FALSE)))
+ cp += INT32SZ;
+
+ doprintf(("\n\t\t\t)"))
+ break;
+
+ case T_WKS:
+ if (check_size(rname, type, cp, msg, eor, INADDRSZ) < 0)
+ break;
+ bcopy((char *)cp, (char *)&inaddr, INADDRSZ);
+ doprintf(("\t%s", inet_ntoa(inaddr)))
+ cp += INADDRSZ;
+
+ if (check_size(rname, type, cp, msg, eor, 1) < 0)
+ break;
+ n = *cp++;
+ protocol = getprotobynumber(n);
+ if (protocol != NULL)
+ doprintf((" %s", protocol->p_name))
+ else
+ doprintf((" %s", itoa(n)))
+
+ doprintf((" ("))
+ n = 0;
+ while (cp < eor)
+ {
+ c = *cp++;
+ do
+ {
+ if (c & 0200)
+ {
+ int port;
+
+ port = htons(n);
+ if (protocol != NULL)
+ service = getservbyport(port, protocol->p_name);
+ else
+ service = NULL;
+
+ if (service != NULL)
+ doprintf((" %s", service->s_name))
+ else
+ doprintf((" %s", itoa(n)))
+ }
+ c <<= 1;
+ } while (++n & 07);
+ }
+ doprintf((" )"))
+ break;
+
+#ifdef obsolete
+ case T_TXT:
+ if (dlen > 0)
+ {
+ doprintf(("\t\"%s\"", stoa(cp, dlen)))
+ cp += dlen;
+ }
+ break;
+#endif
+
+ case T_TXT:
+ if (check_size(rname, type, cp, msg, eor, 1) < 0)
+ break;
+ n = *cp++;
+ doprintf(("\t\"%s", stoa(cp, n)))
+ cp += n;
+
+ while (cp < eor)
+ {
+ if (check_size(rname, type, cp, msg, eor, 1) < 0)
+ break;
+ n = *cp++;
+ doprintf(("%s", stoa(cp, n)))
+ cp += n;
+ }
+ doprintf(("\""))
+ break;
+
+ case T_MINFO:
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf(("\t%s", pr_name(dname)))
+ cp += n;
+
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf((" %s", pr_name(dname)))
+ cp += n;
+ break;
+
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_MD:
+ case T_MF:
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf(("\t%s", pr_name(dname)))
+ cp += n;
+ break;
+
+ case T_UID:
+ case T_GID:
+ if (dlen == INT32SZ)
+ {
+ n = _getlong(cp);
+ doprintf(("\t%s", itoa(n)))
+ cp += INT32SZ;
+ }
+ break;
+
+ case T_UINFO:
+ doprintf(("\t\"%s\"", stoa(cp, dlen)))
+ cp += dlen;
+ break;
+
+ case T_RP:
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf(("\t%s", pr_name(dname)))
+ cp += n;
+
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf((" %s", pr_name(dname)))
+ cp += n;
+ break;
+
+ case T_RT:
+ if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
+ break;
+ n = _getshort(cp);
+ doprintf(("\t%s", itoa(n)))
+ cp += INT16SZ;
+
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf((" %s", pr_name(dname)))
+ cp += n;
+ break;
+
+ case T_AFSDB:
+ if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
+ break;
+ n = _getshort(cp);
+ doprintf(("\t%s", itoa(n)))
+ cp += INT16SZ;
+
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf((" %s", pr_name(dname)))
+ cp += n;
+ break;
+
+ case T_X25:
+ if (check_size(rname, type, cp, msg, eor, 1) < 0)
+ break;
+ n = *cp++;
+ doprintf(("\t%s", stoa(cp, n)))
+ cp += n;
+ break;
+
+ case T_ISDN:
+ if (check_size(rname, type, cp, msg, eor, 1) < 0)
+ break;
+ n = *cp++;
+ doprintf(("\t%s", stoa(cp, n)))
+ cp += n;
+
+ if (cp < eor)
+ {
+ if (check_size(rname, type, cp, msg, eor, 1) < 0)
+ break;
+ n = *cp++;
+ doprintf((" %s", stoa(cp, n)))
+ cp += n;
+ }
+ break;
+
+ case T_NSAP:
+ doprintf(("\t0x%s", nsap_ntoa(cp, dlen)))
+ cp += dlen;
+ break;
+
+ case T_NSAPPTR:
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf(("\t%s", pr_name(dname)))
+ cp += n;
+ break;
+
+ case T_PX:
+ if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
+ break;
+ n = _getshort(cp);
+ doprintf(("\t%s", itoa(n)))
+ cp += INT16SZ;
+
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf((" %s", pr_name(dname)))
+ cp += n;
+
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ break;
+ doprintf((" %s", pr_name(dname)))
+ cp += n;
+ break;
+
+ case T_GPOS:
+ if (check_size(rname, type, cp, msg, eor, 1) < 0)
+ break;
+ n = *cp++;
+ doprintf(("\t%s", stoa(cp, n)))
+ cp += n;
+
+ if (check_size(rname, type, cp, msg, eor, 1) < 0)
+ break;
+ n = *cp++;
+ doprintf(("\t%s", stoa(cp, n)))
+ cp += n;
+
+ if (check_size(rname, type, cp, msg, eor, 1) < 0)
+ break;
+ n = *cp++;
+ doprintf(("\t%s", stoa(cp, n)))
+ cp += n;
+ break;
+
+ case T_LOC:
+ if ((n = *cp) != T_LOC_VERSION)
+ {
+ pr_error("invalid version %s in %s record for %s",
+ itoa(n), pr_type(type), rname);
+ cp += dlen;
+ break;
+ }
+
+ n = INT32SZ + 3*INT32SZ;
+ if (check_size(rname, type, cp, msg, eor, n) < 0)
+ break;
+ c = _getlong(cp);
+ cp += INT32SZ;
+
+ n = _getlong(cp);
+ doprintf(("\t%s ", pr_spherical(n, "N", "S")))
+ cp += INT32SZ;
+
+ n = _getlong(cp);
+ doprintf((" %s ", pr_spherical(n, "E", "W")))
+ cp += INT32SZ;
+
+ n = _getlong(cp);
+ doprintf((" %sm ", pr_vertical(n, "", "-")))
+ cp += INT32SZ;
+
+ doprintf((" %sm", pr_precision((c >> 16) & 0xff)))
+ doprintf((" %sm", pr_precision((c >> 8) & 0xff)))
+ doprintf((" %sm", pr_precision((c >> 0) & 0xff)))
+ break;
+
+ case T_UNSPEC:
+ case T_NULL:
+ cp += dlen;
+ break;
+
+ case T_SIG:
+ case T_KEY:
+ case T_AAAA:
+ doprintf(("\t(not yet implemented)"))
+ cp += dlen;
+ break;
+
+ default:
+ doprintf(("\t???"))
+ cp += dlen;
+ break;
+ }
+
+/*
+ * Terminate resource record printout.
+ */
+ doprintf(("\n"))
+
+/*
+ * Check whether we have reached the exact end of this resource record.
+ * If not, we cannot be sure that the record has been decoded correctly,
+ * and therefore the subsequent tests will be skipped.
+ */
+ if (cp != eor)
+ {
+ pr_error("size error in %s record for %s, off by %s",
+ pr_type(type), rname, itoa(cp - eor));
+
+ /* we believe value of dlen; should perhaps return(NULL) */
+ return(eor);
+ }
+
+/*
+ * Save the CNAME alias for cname chain tracing.
+ * Save the MR or MG alias for MB chain tracing.
+ * These features can be enabled only in normal mode.
+ */
+ if (!listmode && classmatch)
+ {
+ if (type == T_CNAME)
+ cname = strcpy(cnamebuf, dname);
+
+ else if (type == T_MR || type == T_MG)
+ mname = strcpy(mnamebuf, dname);
+ }
+
+/*
+ * Suppress the subsequent checks in quiet mode.
+ * This can safely be done as there are no side effects.
+ * It may speedup things, and nothing would be printed anyway.
+ */
+ if (quiet)
+ return(cp);
+
+/*
+ * In zone listings, resource records with the same name/type/class
+ * must have the same ttl value. Maintain and check list of record info.
+ * This is done on a per-zone basis.
+ */
+ if (listing && !check_ttl(rname, type, class, ttl))
+ {
+ pr_warning("%s %s records have different ttl within %s from %s",
+ rname, pr_type(type), name, host);
+ }
+
+/*
+ * Check validity of 'host' related domain names in certain resource records.
+ * These include LHS record names and RHS domain names of selected records.
+ * Currently underscores are not reported during deep recursive listings.
+ */
+ if (test_valid(type) && !valid_name(rname, TRUE, FALSE, recurskip))
+ {
+ pr_warning("%s %s record has illegal name",
+ rname, pr_type(type));
+ }
+
+ if (test_canon(type) && !valid_name(dname, FALSE, FALSE, recurskip))
+ {
+ pr_warning("%s %s host %s has illegal name",
+ rname, pr_type(type), dname);
+ }
+
+/*
+ * The RHS of various resource records should refer to a canonical host name,
+ * i.e. it should exist and have an A record and not be a CNAME.
+ * Currently this test is suppressed during deep recursive zone listings.
+ */
+ if (!recurskip && test_canon(type) && (n = check_canon(dname)) != 0)
+ {
+ /* only report definitive target host failures */
+ if (n == HOST_NOT_FOUND)
+ pr_warning("%s %s host %s does not exist",
+ rname, pr_type(type), dname);
+ else if (n == NO_DATA)
+ pr_warning("%s %s host %s has no A record",
+ rname, pr_type(type), dname);
+ else if (n == HOST_NOT_CANON)
+ pr_warning("%s %s host %s is not canonical",
+ rname, pr_type(type), dname);
+
+ /* authoritative failure to find nameserver target host */
+ if (type == T_NS && (n == NO_DATA || n == HOST_NOT_FOUND))
+ {
+ if (server == NULL)
+ errmsg("%s has lame delegation to %s",
+ rname, dname);
+ }
+ }
+
+/*
+ * On request, reverse map the address of an A record, and verify that
+ * it is registered and maps back to the name of the A record.
+ * Currently this option has effect here only during zone listings.
+ */
+ if (addrmode && (type == T_A && !reverse) && !fakeaddr(address))
+ {
+ host = mapreverse(rname, inaddr);
+ if (host == NULL)
+ pr_warning("%s address %s is not registered",
+ rname, inet_ntoa(inaddr));
+ else if (host != rname)
+ pr_warning("%s address %s maps to %s",
+ rname, inet_ntoa(inaddr), host);
+ }
+
+/*
+ * This record was processed successfully.
+ */
+ return(cp);
+}
+
+ /*
+** SKIP_QREC -- Skip the query record in the nameserver answer buffer
+** ------------------------------------------------------------------
+**
+** Returns:
+** Pointer to position in answer buffer after current record.
+** NULL if there was a format error in the current record.
+*/
+
+u_char *
+skip_qrec(name, cp, msg, eom)
+input char *name; /* full name we are querying about */
+register u_char *cp; /* current position in answer buf */
+input u_char *msg, *eom; /* begin and end of answer buf */
+{
+ char rname[MAXDNAME+1]; /* record name in LHS */
+ int type, class; /* fixed values in query record */
+ register int n;
+
+ n = expand_name(name, T_NONE, cp, msg, eom, rname);
+ if (n < 0)
+ return(NULL);
+ cp += n;
+
+ n = 2*INT16SZ;
+ if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
+ return(NULL);
+
+ type = _getshort(cp);
+ cp += INT16SZ;
+
+ class = _getshort(cp);
+ cp += INT16SZ;
+
+#ifdef lint
+ if (verbose)
+ printf("%-20s\t%s\t%s\n",
+ rname, pr_class(class), pr_type(type));
+#endif
+ return(cp);
+}
+
+ /*
+** GET_RECURSIVE -- Wrapper for get_hostinfo() during recursion
+** ------------------------------------------------------------
+**
+** Returns:
+** TRUE if requested info was obtained successfully.
+** FALSE otherwise.
+*/
+
+bool
+get_recursive(name)
+input char *name; /* name to query about */
+{
+ static int level = 0; /* recursion level */
+ bool result; /* result status of action taken */
+ int save_errno;
+ int save_herrno;
+
+ if (level > 5)
+ {
+ errmsg("Recursion too deep");
+ return(FALSE);
+ }
+
+ save_errno = errno;
+ save_herrno = h_errno;
+
+ level++;
+ result = get_hostinfo(name, TRUE);
+ level--;
+
+ errno = save_errno;
+ h_errno = save_herrno;
+
+ return(result);
+}
+
+
+/*
+ * Nameserver information.
+ * Stores names and addresses of all servers that are to be queried
+ * for a zone transfer of the desired zone. Normally these are the
+ * authoritative primary and/or secondary nameservers for the zone.
+ */
+
+char nsname[MAXNSNAME][MAXDNAME+1]; /* nameserver host name */
+struct in_addr ipaddr[MAXNSNAME][MAXIPADDR]; /* nameserver addresses */
+int naddrs[MAXNSNAME]; /* count of addresses */
+int nservers = 0; /* count of nameservers */
+
+#ifdef notyet
+typedef struct srvr_data {
+ char nsname[MAXDNAME+1]; /* nameserver host name */
+ struct in_addr ipaddr[MAXIPADDR]; /* nameserver addresses */
+ int naddrs; /* count of addresses */
+} srvr_data_t;
+
+srvr_data_t nsinfo[MAXNSNAME]; /* nameserver info */
+#endif
+
+bool authserver; /* server is supposed to be authoritative */
+bool lameserver; /* server could not provide SOA service */
+
+/*
+ * Host information.
+ * Stores names and (single) addresses encountered during the zone listing
+ * of all A records that belong to the zone. Non-authoritative glue records
+ * that do not belong to the zone are not stored. Glue records that belong
+ * to a delegated zone will be filtered out later during the host count scan.
+ * The host names are allocated dynamically.
+#ifdef notyet
+ * The host data should have been allocated dynamically to avoid static
+ * limits, but this is less important since it is not saved across calls.
+ * In case the static limit is reached, increase MAXHOSTS and recompile.
+#endif
+ */
+
+char *hostname[MAXHOSTS]; /* host name of host in zone */
+ipaddr_t hostaddr[MAXHOSTS]; /* first host address */
+bool multaddr[MAXHOSTS]; /* set if this is a multiple address host */
+int hostcount = 0; /* count of hosts in zone */
+
+#ifdef notyet
+typedef struct host_data {
+ char *hostname; /* host name of host in zone */
+ ipaddr_t hostaddr; /* first host address */
+ bool multaddr; /* set if this is a multiple address host */
+} host_data_t;
+
+host_data_t hostlist[MAXHOSTS]; /* info on hosts in zone */
+#endif
+
+/*
+ * Delegated zone information.
+ * Stores the names of the delegated zones encountered during the zone
+ * listing. The names and the list itself are allocated dynamically.
+ */
+
+char **zonename = NULL; /* names of delegated zones within zone */
+int zonecount = 0; /* count of delegated zones within zone */
+
+/*
+ * Address information.
+ * Stores the (single) addresses of hosts found in all zones traversed.
+ * Used to search for duplicate hosts (same address but different name).
+ * The list of addresses is allocated dynamically, and remains allocated.
+ * This has now been implemented as a hashed list, using the low-order
+ * address bits as the hash key.
+ */
+
+#ifdef obsolete
+ipaddr_t *addrlist = NULL; /* global list of addresses */
+int addrcount = 0; /* count of global addresses */
+#endif
+
+/*
+ * SOA record information.
+ */
+
+soa_data_t soa; /* buffer to store soa data */
+
+/*
+ * Nameserver preference.
+ * As per BIND 4.9.* resource records may be returned after round-robin
+ * reshuffling each time they are retrieved. For NS records, this may
+ * lead to an unfavorable order for doing zone transfers.
+ * We apply some heuristic to sort the NS records according to their
+ * preference with respect to a given list of preferred server domains.
+ */
+
+int nsrank[MAXNSNAME]; /* nameserver ranking after sorting */
+int nspref[MAXNSNAME]; /* nameserver preference value */
+
+ /*
+** LIST_ZONE -- Basic routine to do complete zone listing and checking
+** -------------------------------------------------------------------
+**
+** Returns:
+** TRUE if the requested info was processed successfully.
+** FALSE otherwise.
+*/
+
+int total_calls = 0; /* number of calls for zone processing */
+int total_check = 0; /* number of zones successfully processed */
+int total_tries = 0; /* number of zone transfer attempts */
+int total_zones = 0; /* number of successful zone transfers */
+int total_hosts = 0; /* number of hosts in all traversed zones */
+int total_dupls = 0; /* number of duplicates in all zones */
+
+#ifdef justfun
+char longname[MAXDNAME+1]; /* longest host name found */
+int longsize = 0; /* size of longest host name */
+#endif
+
+bool
+list_zone(name)
+input char *name; /* name of zone to process */
+{
+ register int n;
+ register int i;
+ int nzones; /* count of delegated zones */
+ int nhosts; /* count of real host names */
+ int ndupls; /* count of duplicate hosts */
+ int nextrs; /* count of extrazone hosts */
+ int ngates; /* count of gateway hosts */
+
+ total_calls += 1; /* update zone processing calls */
+
+/*
+ * Normalize to not have trailing dot, unless it is the root zone.
+ */
+ n = strlength(name);
+ if (n > 1 && name[n-1] == '.')
+ name[n-1] = '\0';
+
+/*
+ * Indicate whether we are processing an in-addr.arpa reverse zone.
+ * In this case we will suppress accumulating host count statistics.
+ */
+ reverse = indomain(name, ARPA_ROOT, FALSE);
+
+/*
+ * Suppress various checks if working beyond the recursion skip level.
+ * This affects processing in print_rrec(). It may need refinement.
+ */
+ recurskip = (recursion_level > skip_level) ? TRUE : FALSE;
+
+/*
+ * Find the nameservers for the given zone.
+ */
+ (void) find_servers(name);
+
+ if (nservers < 1)
+ {
+ errmsg("No nameservers for %s found", name);
+ return(FALSE);
+ }
+
+/*
+ * Make sure we have an address for at least one nameserver.
+ */
+ for (n = 0; n < nservers; n++)
+ if (naddrs[n] > 0)
+ break;
+
+ if (n >= nservers)
+ {
+ errmsg("No addresses of nameservers for %s found", name);
+ return(FALSE);
+ }
+
+/*
+ * Without an explicit server on the command line, the servers we
+ * have looked up are supposed to be authoritative for the zone.
+ */
+ authserver = server ? FALSE : TRUE;
+
+/*
+ * Check SOA records at each of the nameservers if so requested.
+ */
+ if (checkmode)
+ {
+ do_check(name);
+
+ total_check += 1; /* update zones processed */
+
+ /* all done if maximum recursion level reached */
+ if (!recursive || (recursion_level >= recursive))
+ return((errorcount == 0) ? TRUE : FALSE);
+ }
+
+/*
+ * The zone transfer for certain zones can be skipped.
+ * Currently this must be indicated on the command line.
+ */
+ if (skip_transfer(name))
+ {
+ if (verbose || statistics || checkmode || hostmode)
+ printf("Skipping zone transfer for %s\n", name);
+ return(FALSE);
+ }
+
+/*
+ * Ask zone transfer to the nameservers, until one responds.
+ */
+ total_tries += 1; /* update zone transfer attempts */
+
+ if (!do_transfer(name))
+ return(FALSE);
+
+ total_zones += 1; /* update successful zone transfers */
+
+/*
+ * Print resource record statistics if so requested.
+ */
+ if (statistics)
+ print_statistics(name, querytype, queryclass);
+
+/*
+ * Accumulate host count statistics for this zone.
+ * Do this only in modes in which such output would be printed.
+ */
+ nzones = zonecount;
+
+ nhosts = 0, ndupls = 0, nextrs = 0, ngates = 0;
+
+ i = (verbose || statistics || hostmode) ? 0 : hostcount;
+
+ for (n = i; n < hostcount; n++)
+ {
+ /* skip fake hosts using a very rudimentary test */
+ if (fakename(hostname[n]) || fakeaddr(hostaddr[n]))
+ continue;
+#ifdef justfun
+ /* save longest host name encountered so far */
+ if (verbose && ((i = strlength(hostname[n])) > longsize))
+ {
+ longsize = i;
+ (void) strcpy(longname, hostname[n]);
+ }
+#endif
+ /* skip apparent glue records */
+ if (gluerecord(hostname[n], name, zonename, nzones))
+ {
+ if (verbose > 1)
+ printf("%s is glue record\n", hostname[n]);
+ continue;
+ }
+
+ /* otherwise count as host */
+ nhosts++;
+
+ /*
+ * Mark hosts not residing directly in the zone as extrazone host.
+ */
+ if (!samedomain(hostname[n], name, TRUE))
+ {
+ nextrs++;
+ if (extrmode || (verbose > 1))
+ printf("%s is extrazone host\n", hostname[n]);
+ }
+
+ /*
+ * Mark hosts with more than one address as gateway host.
+ * These are not checked for duplicate addresses.
+ */
+ if (multaddr[n])
+ {
+ ngates++;
+ if (gatemode || (verbose > 1))
+ printf("%s is gateway host\n", hostname[n]);
+ }
+
+ /*
+ * Compare single address hosts against global list of addresses.
+ * Multiple address hosts are too complicated to handle this way.
+ */
+ else if (check_dupl(hostaddr[n]))
+ {
+ struct in_addr inaddr;
+ inaddr.s_addr = hostaddr[n];
+
+ ndupls++;
+ if (duplmode || (verbose > 1))
+ printf("%s is duplicate host with address %s\n",
+ hostname[n], inet_ntoa(inaddr));
+ }
+ }
+
+/*
+ * Print statistics for this zone.
+ */
+ if (verbose || statistics || hostmode)
+ {
+ printf("Found %d host%s within %s\n",
+ nhosts, plural(nhosts), name);
+
+ if ((ndupls > 0) || duplmode || (verbose > 1))
+ printf("Found %d duplicate host%s within %s\n",
+ ndupls, plural(ndupls), name);
+
+ if ((nextrs > 0) || extrmode || (verbose > 1))
+ printf("Found %d extrazone host%s within %s\n",
+ nextrs, plural(nextrs), name);
+
+ if ((ngates > 0) || gatemode || (verbose > 1))
+ printf("Found %d gateway host%s within %s\n",
+ ngates, plural(ngates), name);
+ }
+
+ total_hosts += nhosts; /* update total number of hosts */
+ total_dupls += ndupls; /* update total number of duplicates */
+
+ if (!checkmode)
+ total_check += 1; /* update zones processed */
+
+ if (verbose || statistics)
+ printf("Found %d delegated zone%s within %s\n",
+ nzones, plural(nzones), name);
+
+/*
+ * Sort the encountered delegated zones alphabetically.
+ * Note that this precludes further use of the zone_index() function.
+ */
+ if ((nzones > 1) && (recursive || listzones || mxdomains))
+ qsort((char *)zonename, nzones, sizeof(char *), compare_name);
+
+/*
+ * The names of the hosts were allocated dynamically.
+ */
+ for (n = 0; n < hostcount; n++)
+ xfree(hostname[n]);
+
+/*
+ * Check for mailable delegated zones within this zone.
+ * This is based on ordinary MX lookup, and not on the MX info
+ * which may be present in the zone listing, to reduce zone transfers.
+ */
+ if (mxdomains)
+ {
+ if (recursion_level == 0)
+ {
+ if (verbose)
+ printf("\n");
+
+ if (!get_mxrec(name))
+ ns_error(name, T_MX, queryclass, server);
+ }
+
+ for (n = 0; n < nzones; n++)
+ {
+ if (verbose)
+ printf("\n");
+
+ if (!get_mxrec(zonename[n]))
+ ns_error(zonename[n], T_MX, queryclass, server);
+ }
+ }
+
+/*
+ * Do recursion on delegated zones if requested and any were found.
+ * Temporarily save zonename list, and force allocation of new list.
+ */
+ if (recursive && (recursion_level < recursive))
+ {
+ for (n = 0; n < nzones; n++)
+ {
+ char **newzone; /* local copy of list */
+
+ newzone = zonename;
+ zonename = NULL; /* allocate new list */
+
+ if (verbose || statistics || checkmode || hostmode)
+ printf("\n");
+
+ if (listzones)
+ {
+ for (i = 0; i <= recursion_level; i++)
+ printf("%s", (i == 0) ? "\t" : " ");
+ printf("%s\n", newzone[n]);
+ }
+
+ if (verbose)
+ printf("Entering zone %s\n", newzone[n]);
+
+ recursion_level++;
+ (void) list_zone(newzone[n]);
+ recursion_level--;
+
+ zonename = newzone; /* restore */
+ }
+ }
+ else if (listzones)
+ {
+ for (n = 0; n < nzones; n++)
+ {
+ for (i = 0; i <= recursion_level; i++)
+ printf("%s", (i == 0) ? "\t" : " ");
+ printf("%s\n", zonename[n]);
+ }
+ }
+
+/*
+ * The names of the delegated zones were allocated dynamically.
+ * The list of delegated zone names was also allocated dynamically.
+ */
+ for (n = 0; n < nzones; n++)
+ xfree(zonename[n]);
+
+ if (zonename != NULL)
+ xfree(zonename);
+
+ zonename = NULL;
+
+/*
+ * Print final overall statistics.
+ */
+ if (recursive && (recursion_level == 0))
+ {
+ if (verbose || statistics || checkmode || hostmode)
+ printf("\n");
+
+ if (verbose || statistics || hostmode)
+ printf("Encountered %d host%s in %d zone%s within %s\n",
+ total_hosts, plural(total_hosts),
+ total_zones, plural(total_zones),
+ name);
+
+ if (verbose || statistics || hostmode)
+ printf("Encountered %d duplicate host%s in %d zone%s within %s\n",
+ total_dupls, plural(total_dupls),
+ total_zones, plural(total_zones),
+ name);
+
+ if (verbose || statistics || checkmode)
+ printf("Transferred %d zone%s out of %d attempt%s\n",
+ total_zones, plural(total_zones),
+ total_tries, plural(total_tries));
+
+ if (verbose || statistics || checkmode)
+ printf("Processed %d zone%s out of %d request%s\n",
+ total_check, plural(total_check),
+ total_calls, plural(total_calls));
+#ifdef justfun
+ if (verbose && (longsize > 0))
+ printf("Longest hostname %s\t%d\n",
+ longname, longsize);
+#endif
+ }
+
+ /* indicate whether any errors were encountered */
+ return((errorcount == 0) ? TRUE : FALSE);
+}
+
+ /*
+** FIND_SERVERS -- Fetch names and addresses of authoritative servers
+** ------------------------------------------------------------------
+**
+** Returns:
+** TRUE if servers could be determined successfully.
+** FALSE otherwise.
+**
+** Inputs:
+** The global variable ``server'', if set, contains the
+** name of the explicit server to be contacted.
+** The global variable ``primary'', if set, indicates
+** that we must use the primary nameserver for the zone.
+** If both are set simultaneously, the explicit server
+** is contacted to retrieve the desired servers.
+**
+** Outputs:
+** The count of nameservers is stored in ``nservers''.
+** Names are stored in the nsname[] database.
+** Addresses are stored in the ipaddr[] database.
+** Address counts are stored in the naddrs[] database.
+*/
+
+bool
+find_servers(name)
+input char *name; /* name of zone to find servers for */
+{
+ struct hostent *hp;
+ register int n;
+ register int i;
+
+/*
+ * Use the explicit server if given on the command line.
+ * Its addresses are stored in the resolver state struct.
+ * This server may not be authoritative for the given zone.
+ */
+ if (server && !primary)
+ {
+ (void) strcpy(nsname[0], server);
+ for (i = 0; i < MAXIPADDR && i < _res.nscount; i++)
+ ipaddr[0][i] = nslist(i).sin_addr;
+ naddrs[0] = i;
+
+ nservers = 1;
+ return(TRUE);
+ }
+
+/*
+ * Fetch primary nameserver info if so requested.
+ * Get its name from the SOA record for the zone, and do a regular
+ * host lookup to fetch its addresses. We are assuming here that the
+ * SOA record is a proper one. This is not necessarily true.
+ * Obviously this server should be authoritative.
+ */
+ if (primary && !server)
+ {
+ char *primaryname;
+
+ primaryname = get_primary(name);
+ if (primaryname == NULL)
+ {
+ ns_error(name, T_SOA, queryclass, server);
+ nservers = 0;
+ return(FALSE);
+ }
+
+ hp = gethostbyname(primaryname);
+ if (hp == NULL)
+ {
+ ns_error(primaryname, T_A, C_IN, server);
+ nservers = 0;
+ return(FALSE);
+ }
+
+ (void) strcpy(nsname[0], hp->h_name);
+ for (i = 0; i < MAXIPADDR && hp->h_addr_list[i]; i++)
+ ipaddr[0][i] = incopy(hp->h_addr_list[i]);
+ naddrs[0] = i;
+
+ if (verbose)
+ printf("Found %d address%-2s for %s\n",
+ naddrs[0], plurale(naddrs[0]), nsname[0]);
+
+ nservers = 1;
+ return(TRUE);
+ }
+
+/*
+ * Otherwise we have to find the nameservers for the zone.
+ * These are supposed to be authoritative, but sometimes we
+ * encounter lame delegations, perhaps due to misconfiguration.
+ * Retrieve the NS records for this zone.
+ */
+ if (!get_servers(name))
+ {
+ ns_error(name, T_NS, queryclass, server);
+ nservers = 0;
+ return(FALSE);
+ }
+
+/*
+ * Usually we'll get addresses for all the servers in the additional
+ * info section. But in case we don't, look up their addresses.
+ * Addresses could be missing because there is no room in the answer.
+ * No address is present if the name of a server is not canonical.
+ * If we get no addresses by extra query, and this is authoritative,
+ * we flag a lame delegation to that server.
+ */
+ for (n = 0; n < nservers; n++)
+ {
+ if (naddrs[n] == 0)
+ {
+ hp = gethostbyname(nsname[n]);
+ if (hp != NULL)
+ {
+ for (i = 0; i < MAXIPADDR && hp->h_addr_list[i]; i++)
+ ipaddr[n][i] = incopy(hp->h_addr_list[i]);
+ naddrs[n] = i;
+ }
+
+ if (verbose)
+ printf("Found %d address%-2s for %s by extra query\n",
+ naddrs[n], plurale(naddrs[n]), nsname[n]);
+
+ if (hp == NULL)
+ {
+ /* server name lookup failed */
+ ns_error(nsname[n], T_A, C_IN, server);
+
+ /* authoritative denial: probably misconfiguration */
+ if (h_errno == NO_DATA || h_errno == HOST_NOT_FOUND)
+ {
+ errmsg("%s has lame delegation to %s",
+ name, nsname[n]);
+ }
+ }
+
+ if ((hp != NULL) && !sameword(hp->h_name, nsname[n]))
+ pr_warning("%s nameserver %s is not canonical (%s)",
+ name, nsname[n], hp->h_name);
+ }
+ else
+ {
+ if (verbose)
+ printf("Found %d address%-2s for %s\n",
+ naddrs[n], plurale(naddrs[n]), nsname[n]);
+ }
+ }
+
+/*
+ * Issue warning if only one server has been discovered.
+ * This is not an error per se, but not much redundancy in that case.
+ */
+ if (nservers == 1)
+ pr_warning("%s has only one nameserver %s",
+ name, nsname[0]);
+
+ return((nservers > 0) ? TRUE : FALSE);
+}
+
+ /*
+** GET_SERVERS -- Fetch names and addresses of authoritative servers
+** -----------------------------------------------------------------
+**
+** Returns:
+** TRUE if servers could be determined successfully.
+** FALSE otherwise.
+**
+** Side effects:
+** The count of nameservers is stored in ``nservers''.
+** Names are stored in the nsname[] database.
+** Addresses are stored in the ipaddr[] database.
+** Address counts are stored in the naddrs[] database.
+*/
+
+bool
+get_servers(name)
+input char *name; /* name of zone to find servers for */
+{
+ querybuf answer;
+ register int n;
+ bool result; /* result status of action taken */
+
+ if (verbose)
+ printf("Finding nameservers for %s ...\n", name);
+
+ n = get_info(&answer, name, T_NS, queryclass);
+ if (n < 0)
+ return(FALSE);
+
+ if (verbose > 1)
+ (void) print_info(&answer, n, name, T_NS, FALSE);
+
+ result = get_nsinfo(&answer, n, name);
+ return(result);
+}
+
+ /*
+** GET_NSINFO -- Extract nameserver data from nameserver answer buffer
+** -------------------------------------------------------------------
+**
+** Returns:
+** TRUE if servers could be determined successfully.
+** FALSE otherwise.
+**
+** Outputs:
+** The count of nameservers is stored in ``nservers''.
+** Names are stored in the nsname[] database.
+** Addresses are stored in the ipaddr[] database.
+** Address counts are stored in the naddrs[] database.
+*/
+
+bool
+get_nsinfo(answerbuf, answerlen, name)
+input querybuf *answerbuf; /* location of answer buffer */
+input int answerlen; /* length of answer buffer */
+input char *name; /* name of zone to find servers for */
+{
+ HEADER *bp;
+ int qdcount, ancount, nscount, arcount, rrcount;
+ u_char *msg, *eom;
+ register u_char *cp;
+ register int i;
+
+ nservers = 0; /* count of nameservers */
+
+ bp = (HEADER *)answerbuf;
+ qdcount = ntohs(bp->qdcount);
+ ancount = ntohs(bp->ancount);
+ nscount = ntohs(bp->nscount);
+ arcount = ntohs(bp->arcount);
+
+ msg = (u_char *)answerbuf;
+ eom = (u_char *)answerbuf + answerlen;
+ cp = (u_char *)answerbuf + HFIXEDSZ;
+
+ while (qdcount > 0 && cp < eom)
+ {
+ cp = skip_qrec(name, cp, msg, eom);
+ if (cp == NULL)
+ return(FALSE);
+ qdcount--;
+ }
+
+ if (qdcount)
+ {
+ pr_error("invalid qdcount after %s query for %s",
+ pr_type(T_NS), name);
+ h_errno = NO_RECOVERY;
+ return(FALSE);
+ }
+
+/*
+ * If the answer is authoritative, the names are found in the
+ * answer section, and the nameserver section is empty.
+ * If not, there may be duplicate names in both sections.
+ * Addresses are found in the additional info section both cases.
+ */
+ rrcount = ancount + nscount + arcount;
+ while (rrcount > 0 && cp < eom)
+ {
+ char rname[MAXDNAME+1];
+ char dname[MAXDNAME+1];
+ int type, class, ttl, dlen;
+ u_char *eor;
+ register int n;
+ struct in_addr inaddr;
+
+ n = expand_name(name, T_NONE, cp, msg, eom, rname);
+ if (n < 0)
+ return(FALSE);
+ cp += n;
+
+ n = 3*INT16SZ + INT32SZ;
+ if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
+ return(FALSE);
+
+ type = _getshort(cp);
+ cp += INT16SZ;
+
+ class = _getshort(cp);
+ cp += INT16SZ;
+
+ ttl = _getlong(cp);
+ cp += INT32SZ;
+
+ dlen = _getshort(cp);
+ cp += INT16SZ;
+
+ eor = cp + dlen;
+#ifdef lint
+ if (verbose)
+ printf("%-20s\t%d\t%s\t%s\n",
+ rname, ttl, pr_class(class), pr_type(type));
+#endif
+ if ((type == T_NS) && sameword(rname, name))
+ {
+ n = expand_name(rname, type, cp, msg, eom, dname);
+ if (n < 0)
+ return(FALSE);
+ cp += n;
+
+ for (i = 0; i < nservers; i++)
+ if (sameword(nsname[i], dname))
+ break; /* duplicate */
+
+ if (i >= nservers && nservers < MAXNSNAME)
+ {
+ (void) strcpy(nsname[nservers], dname);
+ naddrs[nservers] = 0;
+ nservers++;
+ }
+ }
+ else if ((type == T_A) && dlen == INADDRSZ)
+ {
+ for (i = 0; i < nservers; i++)
+ if (sameword(nsname[i], rname))
+ break; /* found */
+
+ if (i < nservers && naddrs[i] < MAXIPADDR)
+ {
+ bcopy((char *)cp, (char *)&inaddr, INADDRSZ);
+ ipaddr[i][naddrs[i]] = inaddr;
+ naddrs[i]++;
+ }
+
+ cp += dlen;
+ }
+ else
+ cp += dlen;
+
+ if (cp != eor)
+ {
+ pr_error("size error in %s record for %s, off by %s",
+ pr_type(type), rname, itoa(cp - eor));
+ return(FALSE);
+ }
+
+ rrcount--;
+ }
+
+ if (rrcount)
+ {
+ pr_error("invalid rrcount after %s query for %s",
+ pr_type(T_NS), name);
+ h_errno = NO_RECOVERY;
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+ /*
+** SORT_SERVERS -- Sort set of nameservers according to preference
+** ---------------------------------------------------------------
+**
+** Returns:
+** None.
+**
+** Inputs:
+** Set of nameservers as determined by find_servers().
+** The global variable ``prefserver'', if set, contains
+** a list of preferred server domains to compare against.
+**
+** Outputs:
+** Stores the preferred nameserver order in nsrank[].
+*/
+
+void
+sort_servers()
+{
+ register int i, j;
+ register int n, pref;
+ register char *p, *q;
+
+/*
+ * Initialize the default ranking.
+ */
+ for (n = 0; n < nservers; n++)
+ {
+ nsrank[n] = n;
+ nspref[n] = 0;
+ }
+
+/*
+ * Determine the nameserver preference.
+ * Compare against a list of comma-separated preferred server domains.
+ * Use the maximum value of all comparisons.
+ */
+ for (q = NULL, p = prefserver; p != NULL; p = q)
+ {
+ q = index(p, ',');
+ if (q != NULL)
+ *q = '\0';
+
+ for (n = 0; n < nservers; n++)
+ {
+ pref = matchlabels(nsname[n], p);
+ if (pref > nspref[n])
+ nspref[n] = pref;
+ }
+
+ if (q != NULL)
+ *q++ = ',';
+ }
+
+/*
+ * Sort the set according to preference.
+ * Keep the rest as much as possible in original order.
+ */
+ for (i = 0; i < nservers; i++)
+ {
+ for (j = i + 1; j < nservers; j++)
+ {
+ if (nspref[j] > nspref[i])
+ {
+ pref = nspref[j];
+ /* nspref[j] = nspref[i]; */
+ for (n = j; n > i; n--)
+ nspref[n] = nspref[n-1];
+ nspref[i] = pref;
+
+ pref = nsrank[j];
+ /* nsrank[j] = nsrank[i]; */
+ for (n = j; n > i; n--)
+ nsrank[n] = nsrank[n-1];
+ nsrank[i] = pref;
+ }
+ }
+ }
+}
+
+ /*
+** SKIP_TRANSFER -- Check whether a zone transfer should be skipped
+** ----------------------------------------------------------------
+**
+** Returns:
+** TRUE if a transfer for this zone should be skipped.
+** FALSE if the zone transfer should proceed.
+**
+** Inputs:
+** The global variable ``skipzone'', if set, contains
+** a list of zone names to be skipped.
+**
+** Certain zones are known to contain bogus information, and
+** can be requested to be excluded from further processing.
+** The zone transfer for such zones and its delegated zones
+** will be skipped.
+*/
+
+bool
+skip_transfer(name)
+input char *name; /* name of zone to process */
+{
+ register char *p, *q;
+ bool skip = FALSE;
+
+ for (q = NULL, p = skipzone; p != NULL; p = q)
+ {
+ q = index(p, ',');
+ if (q != NULL)
+ *q = '\0';
+
+ if (sameword(name, p))
+ skip = TRUE;
+
+ if (q != NULL)
+ *q++ = ',';
+ }
+
+ return(skip);
+}
+
+ /*
+** DO_CHECK -- Check SOA records at each of the nameservers
+** --------------------------------------------------------
+**
+** Returns:
+** None.
+**
+** Inputs:
+** The count of nameservers is stored in ``nservers''.
+** Names are stored in the nsname[] database.
+** Addresses are stored in the ipaddr[] database.
+** Address counts are stored in the naddrs[] database.
+**
+** The SOA record of the zone is checked at each nameserver.
+** Nameserver recursion is turned off to make sure that the
+** answer is authoritative.
+*/
+
+void
+do_check(name)
+input char *name; /* name of zone to process */
+{
+ res_state_t save_res; /* saved copy of resolver database */
+ char *save_server; /* saved copy of server name */
+ register int n;
+ register int i;
+
+ /* save resolver database */
+ save_res = _res;
+ save_server = server;
+
+ /* turn off nameserver recursion */
+ _res.options &= ~RES_RECURSE;
+
+ for (n = 0; n < nservers; n++)
+ {
+ if (naddrs[n] < 1)
+ continue; /* shortcut */
+
+ server = nsname[n];
+ for (i = 0; i < MAXNS && i < naddrs[n]; i++)
+ {
+ nslist(i).sin_family = AF_INET;
+ nslist(i).sin_port = htons(NAMESERVER_PORT);
+ nslist(i).sin_addr = ipaddr[n][i];
+ }
+ _res.nscount = i;
+
+ /* retrieve and check SOA */
+ if (check_zone(name))
+ continue;
+
+ /* SOA query failed */
+ ns_error(name, T_SOA, queryclass, server);
+
+ /* explicit server failure: possibly data expired */
+ lameserver = (h_errno == SERVER_FAILURE) ? TRUE : FALSE;
+
+ /* non-authoritative denial: assume lame delegation */
+ if (h_errno == NO_RREC || h_errno == NO_HOST)
+ lameserver = TRUE;
+
+ /* authoritative denial: probably misconfiguration */
+ if (h_errno == NO_DATA || h_errno == HOST_NOT_FOUND)
+ lameserver = TRUE;
+
+ /* flag an error if server should not have failed */
+ if (lameserver && authserver)
+ errmsg("%s has lame delegation to %s",
+ name, server);
+ }
+
+ /* restore resolver database */
+ _res = save_res;
+ server = save_server;
+}
+
+ /*
+** DO_TRANSFER -- Perform a zone transfer from any of its nameservers
+** ------------------------------------------------------------------
+**
+** Returns:
+** TRUE if the zone data have been retrieved successfully.
+** FALSE if none of the servers responded.
+**
+** Inputs:
+** The count of nameservers is stored in ``nservers''.
+** Names are stored in the nsname[] database.
+** Addresses are stored in the ipaddr[] database.
+** Address counts are stored in the naddrs[] database.
+**
+** Ask zone transfer to the nameservers, until one responds.
+** The list of nameservers is sorted according to preference.
+** An authoritative server should always respond positively.
+** If it responds with an error, we may have a lame delegation.
+** Always retry with the next server to avoid missing entire zones.
+*/
+
+bool
+do_transfer(name)
+input char *name; /* name of zone to do zone xfer for */
+{
+ register int n, ns;
+ register int i;
+
+ for (sort_servers(), ns = 0; ns < nservers; ns++)
+ {
+ for (n = nsrank[ns], i = 0; i < naddrs[n]; i++)
+ {
+ if (verbose)
+ printf("Trying server %s (%s) ...\n",
+ inet_ntoa(ipaddr[n][i]), nsname[n]);
+
+ if (transfer_zone(name, queryclass, ipaddr[n][i], nsname[n]))
+ goto done; /* double break */
+
+ /* zone transfer failed */
+ if ((h_errno != TRY_AGAIN) || verbose)
+ ns_error(name, T_AXFR, queryclass, nsname[n]);
+
+ /* zone transfer request was explicitly refused */
+ if (h_errno == QUERY_REFUSED)
+ break;
+
+ /* explicit server failure: possibly data expired */
+ lameserver = (h_errno == SERVER_FAILURE) ? TRUE : FALSE;
+
+ /* non-authoritative denial: assume lame delegation */
+ if (h_errno == NO_RREC || h_errno == NO_HOST)
+ lameserver = TRUE;
+
+ /* authoritative denial: probably misconfiguration */
+ if (h_errno == NO_DATA || h_errno == HOST_NOT_FOUND)
+ lameserver = TRUE;
+
+ /* flag an error if server should not have failed */
+ if (lameserver && authserver)
+ errmsg("%s has lame delegation to %s",
+ name, nsname[n]);
+
+ /* try next server if this one is sick */
+ if (lameserver)
+ break;
+
+ /* terminate on irrecoverable errors */
+ if (h_errno != TRY_AGAIN)
+ return(FALSE);
+
+ /* in case nameserver not present */
+ if (errno == ECONNREFUSED)
+ break;
+ }
+ }
+done:
+ if (ns >= nservers)
+ {
+ if ((h_errno == TRY_AGAIN) && !verbose)
+ ns_error(name, T_AXFR, queryclass, (char *)NULL);
+ errmsg("No nameservers for %s responded", name);
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+ /*
+** TRANSFER_ZONE -- Wrapper for get_zone() to hide administrative tasks
+** --------------------------------------------------------------------
+**
+** Returns:
+** See get_zone() for details.
+**
+** Side effects:
+** See get_zone() for details.
+**
+** This routine may be called repeatedly with different server
+** addresses, until one of the servers responds. Various items
+** must be reset on every try to continue with a clean slate.
+*/
+
+bool
+transfer_zone(name, class, inaddr, host)
+input char *name; /* name of zone to do zone xfer for */
+input int class; /* specific resource record class */
+input struct in_addr inaddr; /* address of server to be queried */
+input char *host; /* name of server to be queried */
+{
+ register int n;
+
+/*
+ * Reset the resource record statistics before each try.
+ */
+ clear_statistics();
+
+/*
+ * Reset the hash tables of saved resource record information.
+ * These tables are used only during the zone transfer itself.
+ */
+ clear_ttltab();
+ clear_hosttab();
+ clear_zonetab();
+
+/*
+ * Perform the actual zone transfer.
+ */
+ if (get_zone(name, class, inaddr, host))
+ return(TRUE);
+
+/*
+ * Failure to get the zone. Free any memory that may have been allocated.
+ * On success it is the responsibility of the caller to free the memory.
+ * The information gathered is used by list_zone() after the zone transfer.
+ */
+ for (n = 0; n < hostcount; n++)
+ xfree(hostname[n]);
+
+ for (n = 0; n < zonecount; n++)
+ xfree(zonename[n]);
+
+ if (zonename != NULL)
+ xfree(zonename);
+
+ zonename = NULL;
+
+ return(FALSE);
+}
+
+ /*
+** GET_ZONE -- Perform a zone transfer from server at specific address
+** -------------------------------------------------------------------
+**
+** Returns:
+** TRUE if the zone data have been retrieved successfully.
+** FALSE if an error occurred (h_errno is set appropriately).
+** Set TRY_AGAIN wherever possible to try the next server.
+**
+** Side effects:
+** Stores list of delegated zones found in zonename[],
+** and the count of delegated zones in ``zonecount''.
+** Stores list of host names found in hostname[],
+** and the count of host names in ``hostcount''.
+** Updates resource record statistics in record_stats[].
+** This array must have been cleared before.
+*/
+
+bool
+get_zone(name, class, inaddr, host)
+input char *name; /* name of zone to do zone xfer for */
+input int class; /* specific resource record class */
+input struct in_addr inaddr; /* address of server to be queried */
+input char *host; /* name of server to be queried */
+{
+ querybuf query;
+ querybuf answer;
+ HEADER *bp;
+ int ancount;
+ int sock;
+ struct sockaddr_in sin;
+ register int n;
+ register int i;
+ int nrecords = 0; /* number of records processed */
+ int soacount = 0; /* count of SOA records */
+
+ zonecount = 0; /* count of delegated zones */
+ hostcount = 0; /* count of host names */
+
+/*
+ * Construct query, and connect to the given server.
+ */
+ errno = 0; /* reset before querying nameserver */
+
+ n = res_mkquery(QUERY, name, class, T_AXFR, (qbuf_t *)NULL, 0,
+ (rrec_t *)NULL, (qbuf_t *)&query, sizeof(querybuf));
+ if (n < 0)
+ {
+ if (debug)
+ printf("%sres_mkquery failed\n", dbprefix);
+ h_errno = NO_RECOVERY;
+ return(FALSE);
+ }
+
+ if (debug)
+ {
+ printf("%sget_zone()\n", dbprefix);
+ pr_query((qbuf_t *)&query, n, stdout);
+ }
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(NAMESERVER_PORT);
+ sin.sin_addr = inaddr;
+
+ /* add name and address to error messages */
+ /* _res_setaddr(&sin, host); */
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ _res_perror(&sin, host, "socket");
+ h_errno = TRY_AGAIN;
+ return(FALSE);
+ }
+
+ if (_res_connect(sock, &sin, sizeof(sin)) < 0)
+ {
+ if (debug || verbose)
+ _res_perror(&sin, host, "connect");
+ (void) close(sock);
+ h_errno = TRY_AGAIN;
+ return(FALSE);
+ }
+
+ if (verbose)
+ printf("Asking zone transfer for %s ...\n", name);
+
+/*
+ * Send the query buffer.
+ */
+ if (_res_write(sock, &sin, host, (char *)&query, n) < 0)
+ {
+ (void) close(sock);
+ h_errno = TRY_AGAIN;
+ return(FALSE);
+ }
+
+/*
+ * Process all incoming records, each record in a separate packet.
+ */
+ while ((n = _res_read(sock, &sin, host, (char *)&answer, sizeof(querybuf))) != 0)
+ {
+ if (n < 0)
+ {
+ (void) close(sock);
+ h_errno = TRY_AGAIN;
+ return(FALSE);
+ }
+
+ errno = 0; /* reset after we got an answer */
+
+ if (n < HFIXEDSZ)
+ {
+ pr_error("answer length %s too short during %s for %s from %s",
+ itoa(n), pr_type(T_AXFR), name, host);
+ (void) close(sock);
+ h_errno = TRY_AGAIN;
+ return(FALSE);
+ }
+
+ if (debug > 1)
+ {
+ printf("%sgot answer, %d bytes:\n", dbprefix, n);
+ pr_query((qbuf_t *)&answer, n, stdout);
+ }
+
+ /*
+ * Analyze the contents of the answer and check for errors.
+ * An error can be expected only in the very first packet.
+ * The query section should be empty except in the first packet.
+ * Note the special error status codes for specific failures.
+ */
+ bp = (HEADER *)&answer;
+ ancount = ntohs(bp->ancount);
+
+ if (bp->rcode != NOERROR || ancount == 0)
+ {
+ if (debug || verbose)
+ print_status(&answer);
+
+ switch (bp->rcode)
+ {
+ case NXDOMAIN:
+ /* distinguish between authoritative or not */
+ h_errno = bp->aa ? HOST_NOT_FOUND : NO_HOST;
+ break;
+
+ case NOERROR:
+ /* distinguish between authoritative or not */
+ h_errno = bp->aa ? NO_DATA : NO_RREC;
+ break;
+
+ case REFUSED:
+ /* special status if zone transfer refused */
+ h_errno = QUERY_REFUSED;
+ break;
+
+ case SERVFAIL:
+ /* special status upon explicit failure */
+ h_errno = SERVER_FAILURE;
+ break;
+
+ default:
+ /* all other errors will cause a retry */
+ h_errno = TRY_AGAIN;
+ break;
+ }
+
+ if (nrecords != 0)
+ pr_error("unexpected error during %s for %s from %s",
+ pr_type(T_AXFR), name, host);
+
+ (void) close(sock);
+ return(FALSE);
+ }
+
+ h_errno = 0;
+
+ /*
+ * The nameserver and additional info section should be empty,
+ * and there should be a single answer in the answer section.
+ */
+ if (ancount != 1)
+ pr_error("multiple answers during %s for %s from %s",
+ pr_type(T_AXFR), name, host);
+
+ i = ntohs(bp->nscount);
+ if (i != 0)
+ pr_error("nonzero nscount during %s for %s from %s",
+ pr_type(T_AXFR), name, host);
+
+ i = ntohs(bp->arcount);
+ if (i != 0)
+ pr_error("nonzero arcount during %s for %s from %s",
+ pr_type(T_AXFR), name, host);
+
+ /*
+ * Valid packet received. Print contents if appropriate.
+ */
+ nrecords++;
+
+ soaname = NULL, subname = NULL, adrname = NULL;
+ listhost = host;
+ (void) print_info(&answer, n, name, T_AXFR, TRUE);
+
+ /*
+ * Terminate upon the second SOA record for this zone.
+ */
+ if (soaname && sameword(soaname, name) && soacount++)
+ break;
+
+ /* the nameserver balks on this one */
+ if (soaname && !sameword(soaname, name))
+ pr_warning("extraneous SOA record for %s within %s from %s",
+ soaname, name, host);
+
+ /*
+ * Save encountered delegated zone name for recursive listing.
+ */
+ if (subname && indomain(subname, name, FALSE))
+ {
+ i = zone_index(subname, TRUE);
+#ifdef obsolete
+ for (i = 0; i < zonecount; i++)
+ if (sameword(zonename[i], subname))
+ break; /* duplicate */
+#endif
+ if (i >= zonecount)
+ {
+ zonename = newlist(zonename, zonecount+1, char *);
+ zonename[zonecount] = newstr(subname);
+ zonecount++;
+ }
+ }
+ /* warn about strange delegated zones */
+ else if (subname && !indomain(subname, name, TRUE))
+ pr_warning("extraneous NS record for %s within %s from %s",
+ subname, name, host);
+
+ /*
+ * Save encountered name of A record for host name count.
+ */
+ if (adrname && indomain(adrname, name, FALSE) && !reverse)
+ {
+ i = host_index(adrname, (hostcount < MAXHOSTS));
+#ifdef obsolete
+ for (i = 0; i < hostcount; i++)
+ if (sameword(hostname[i], adrname))
+ break; /* duplicate */
+#endif
+ if (i < hostcount && address != hostaddr[i])
+ multaddr[i] = TRUE;
+
+ if (i >= hostcount && hostcount < MAXHOSTS)
+ {
+ hostname[hostcount] = newstr(adrname);
+ hostaddr[hostcount] = address;
+ multaddr[hostcount] = FALSE;
+ hostcount++;
+
+ if (hostcount == MAXHOSTS)
+ pr_error("maximum %s hosts reached within %s from %s",
+ itoa(hostcount), name, host);
+ }
+ }
+ /* check for unauthoritative glue records */
+ else if (adrname && !indomain(adrname, name, TRUE))
+ pr_warning("extraneous glue record for %s within %s from %s",
+ adrname, name, host);
+ }
+
+/*
+ * End of zone transfer at second SOA record or zero length read.
+ */
+ (void) close(sock);
+
+/*
+ * Check for the anomaly that the whole transfer consisted of the
+ * SOA records only. Could occur if we queried the victim of a lame
+ * delegation which happened to have the SOA record present.
+ */
+ if (nrecords <= soacount)
+ {
+ pr_error("empty zone transfer for %s from %s",
+ name, host);
+ h_errno = NO_RREC;
+ return(FALSE);
+ }
+
+/*
+ * Do an extra check for delegated zones that also have an A record.
+ * Those may have been defined in the child zone, and crept in the
+ * parent zone, or may have been defined as glue records.
+ * This is not necessarily an error, but the host count may be wrong.
+ * Note that an A record for the current zone has been ignored above.
+ */
+ for (n = 0; n < zonecount; n++)
+ {
+ i = host_index(zonename[n], FALSE);
+#ifdef obsolete
+ for (i = 0; i < hostcount; i++)
+ if (sameword(hostname[i], zonename[n]))
+ break; /* found */
+#endif
+ if (i < hostcount)
+ pr_warning("%s has both NS and A records within %s from %s",
+ zonename[n], name, host);
+ }
+
+/*
+ * The zone transfer has been successful.
+ */
+ if (verbose)
+ printf("Transfer complete, %d records received for %s\n",
+ nrecords, name);
+
+ return(TRUE);
+}
+
+ /*
+** GET_MXREC -- Fetch MX records of a domain
+** -----------------------------------------
+**
+** Returns:
+** TRUE if MX records were found.
+** FALSE otherwise.
+*/
+
+bool
+get_mxrec(name)
+input char *name; /* domain name to get mx for */
+{
+ querybuf answer;
+ register int n;
+
+ if (verbose)
+ printf("Finding MX records for %s ...\n", name);
+
+ n = get_info(&answer, name, T_MX, queryclass);
+ if (n < 0)
+ return(FALSE);
+
+ (void) print_info(&answer, n, name, T_MX, FALSE);
+
+ return(TRUE);
+}
+
+ /*
+** GET_PRIMARY -- Fetch name of primary nameserver for a zone
+** ----------------------------------------------------------
+**
+** Returns:
+** Pointer to the name of the primary server, if found.
+** NULL if the server could not be determined.
+*/
+
+char *
+get_primary(name)
+input char *name; /* name of zone to get soa for */
+{
+ querybuf answer;
+ register int n;
+
+ if (verbose)
+ printf("Finding primary nameserver for %s ...\n", name);
+
+ n = get_info(&answer, name, T_SOA, queryclass);
+ if (n < 0)
+ return(NULL);
+
+ if (verbose > 1)
+ (void) print_info(&answer, n, name, T_SOA, FALSE);
+
+ soaname = NULL;
+ (void) get_soainfo(&answer, n, name);
+ if (soaname == NULL)
+ return(NULL);
+
+ return(soa.primary);
+}
+
+ /*
+** CHECK_ZONE -- Fetch and analyze SOA record of a zone
+** ----------------------------------------------------
+**
+** Returns:
+** TRUE if the SOA record was found at the given server.
+** FALSE otherwise.
+**
+** Inputs:
+** The global variable ``server'' must contain the name
+** of the server that was queried.
+*/
+
+bool
+check_zone(name)
+input char *name; /* name of zone to get soa for */
+{
+ querybuf answer;
+ register int n;
+
+ if (verbose)
+ printf("Checking SOA for %s at server %s ...\n", name, server);
+ else if (authserver)
+ printf("%-20s\tNS\t%s\n", name, server);
+ else
+ printf("%s\t(%s)\n", name, server);
+
+ n = get_info(&answer, name, T_SOA, queryclass);
+ if (n < 0)
+ return(FALSE);
+
+ if (verbose > 1)
+ (void) print_info(&answer, n, name, T_SOA, FALSE);
+
+ soaname = NULL;
+ (void) get_soainfo(&answer, n, name);
+ if (soaname == NULL)
+ return(FALSE);
+
+ check_soa(&answer, name);
+
+ return(TRUE);
+}
+
+ /*
+** GET_SOAINFO -- Extract SOA data from nameserver answer buffer
+** -------------------------------------------------------------
+**
+** Returns:
+** TRUE if the SOA record was found successfully.
+** FALSE otherwise.
+**
+** Outputs:
+** The global struct ``soa'' is filled with the soa data.
+**
+** Side effects:
+** Sets ``soaname'' if this is a valid SOA record.
+** This variable must have been cleared before calling
+** get_soainfo() and may be checked afterwards.
+*/
+
+bool
+get_soainfo(answerbuf, answerlen, name)
+input querybuf *answerbuf; /* location of answer buffer */
+input int answerlen; /* length of answer buffer */
+input char *name; /* name of zone to get soa for */
+{
+ HEADER *bp;
+ int qdcount, ancount;
+ u_char *msg, *eom;
+ register u_char *cp;
+
+ bp = (HEADER *)answerbuf;
+ qdcount = ntohs(bp->qdcount);
+ ancount = ntohs(bp->ancount);
+
+ msg = (u_char *)answerbuf;
+ eom = (u_char *)answerbuf + answerlen;
+ cp = (u_char *)answerbuf + HFIXEDSZ;
+
+ while (qdcount > 0 && cp < eom)
+ {
+ cp = skip_qrec(name, cp, msg, eom);
+ if (cp == NULL)
+ return(FALSE);
+ qdcount--;
+ }
+
+ if (qdcount)
+ {
+ pr_error("invalid qdcount after %s query for %s",
+ pr_type(T_SOA), name);
+ h_errno = NO_RECOVERY;
+ return(FALSE);
+ }
+
+/*
+ * Check answer section only.
+ * The nameserver section may contain the nameservers for the zone,
+ * and the additional section their addresses, but not guaranteed.
+ * Those sections are usually empty for authoritative answers.
+ */
+ while (ancount > 0 && cp < eom)
+ {
+ char rname[MAXDNAME+1];
+ int type, class, ttl, dlen;
+ u_char *eor;
+ register int n;
+
+ n = expand_name(name, T_NONE, cp, msg, eom, rname);
+ if (n < 0)
+ return(FALSE);
+ cp += n;
+
+ n = 3*INT16SZ + INT32SZ;
+ if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
+ return(FALSE);
+
+ type = _getshort(cp);
+ cp += INT16SZ;
+
+ class = _getshort(cp);
+ cp += INT16SZ;
+
+ ttl = _getlong(cp);
+ cp += INT32SZ;
+
+ dlen = _getshort(cp);
+ cp += INT16SZ;
+
+ eor = cp + dlen;
+#ifdef lint
+ if (verbose)
+ printf("%-20s\t%d\t%s\t%s\n",
+ rname, ttl, pr_class(class), pr_type(type));
+#endif
+ switch (type)
+ {
+ case T_SOA:
+ n = expand_name(rname, type, cp, msg, eom, soa.primary);
+ if (n < 0)
+ return(FALSE);
+ cp += n;
+
+ n = expand_name(rname, type, cp, msg, eom, soa.hostmaster);
+ if (n < 0)
+ return(FALSE);
+ cp += n;
+
+ n = 5*INT32SZ;
+ if (check_size(rname, type, cp, msg, eor, n) < 0)
+ return(FALSE);
+ soa.serial = _getlong(cp);
+ cp += INT32SZ;
+ soa.refresh = _getlong(cp);
+ cp += INT32SZ;
+ soa.retry = _getlong(cp);
+ cp += INT32SZ;
+ soa.expire = _getlong(cp);
+ cp += INT32SZ;
+ soa.defttl = _getlong(cp);
+ cp += INT32SZ;
+
+ /* valid complete soa record found */
+ soaname = strcpy(soanamebuf, rname);
+ break;
+
+ default:
+ cp += dlen;
+ break;
+ }
+
+ if (cp != eor)
+ {
+ pr_error("size error in %s record for %s, off by %s",
+ pr_type(type), rname, itoa(cp - eor));
+ return(FALSE);
+ }
+
+ ancount--;
+ }
+
+ if (ancount)
+ {
+ pr_error("invalid ancount after %s query for %s",
+ pr_type(T_SOA), name);
+ h_errno = NO_RECOVERY;
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+ /*
+** CHECK_SOA -- Analyze retrieved SOA records of a zone
+** ----------------------------------------------------
+**
+** Returns:
+** None.
+**
+** Inputs:
+** The global variable ``server'' must contain the
+** name of the server that was queried.
+** The global struct ``soa'' must contain the soa data.
+*/
+
+void
+check_soa(answerbuf, name)
+input querybuf *answerbuf; /* location of answer buffer */
+input char *name; /* name of zone to check soa for */
+{
+ static char oldnamebuf[MAXDNAME+1];
+ static char *oldname = NULL; /* previous name of zone */
+ static char *oldserver = NULL; /* previous name of server */
+ static soa_data_t oldsoa; /* previous soa data */
+ register int n;
+ HEADER *bp;
+
+/*
+ * Print the various SOA fields in abbreviated form.
+ * Values are actually unsigned, but we print them as signed integers,
+ * apart from the serial which really becomes that big sometimes.
+ * In the latter case we print a warning below.
+ */
+ printf("%s\t%s\t(%u %d %d %d %d)\n",
+ soa.primary, soa.hostmaster, (unsigned)soa.serial,
+ soa.refresh, soa.retry, soa.expire, soa.defttl);
+
+/*
+ * We are supposed to have queried an authoritative nameserver, and since
+ * nameserver recursion has been turned off, answer must be authoritative.
+ */
+ bp = (HEADER *)answerbuf;
+ if (!bp->aa)
+ {
+ if (authserver)
+ pr_error("%s SOA record at %s is not authoritative",
+ name, server);
+ else
+ pr_warning("%s SOA record at %s is not authoritative",
+ name, server);
+
+ if (authserver)
+ errmsg("%s has lame delegation to %s",
+ name, server);
+ }
+
+/*
+ * Check whether we are switching to a new zone.
+ * The old name must have been saved in static storage.
+ */
+ if ((oldname != NULL) && !sameword(name, oldname))
+ oldname = NULL;
+
+/*
+ * Make few timer consistency checks only for the first one in a series.
+ * Compare the primary field against the list of authoritative servers.
+ * Explicitly check the hostmaster field for illegal characters ('@').
+ * Yell if the serial has the high bit set (not always intentional).
+ */
+ if (oldname == NULL)
+ {
+ for (n = 0; n < nservers; n++)
+ if (sameword(soa.primary, nsname[n]))
+ break; /* found */
+
+ if ((n >= nservers) && authserver)
+ pr_warning("%s SOA primary %s is not advertised via NS",
+ name, soa.primary);
+
+ if (!valid_name(soa.primary, FALSE, FALSE, FALSE))
+ pr_warning("%s SOA primary %s has illegal name",
+ name, soa.primary);
+
+ if (!valid_name(soa.hostmaster, FALSE, TRUE, FALSE))
+ pr_warning("%s SOA hostmaster %s has illegal mailbox",
+ name, soa.hostmaster);
+
+ if (bitset(0x80000000, soa.serial))
+ pr_warning("%s SOA serial has high bit set",
+ name);
+
+ if (soa.retry > soa.refresh)
+ pr_warning("%s SOA retry exceeds refresh",
+ name);
+
+ if (soa.refresh + soa.retry > soa.expire)
+ pr_warning("%s SOA refresh+retry exceeds expire",
+ name);
+ }
+
+/*
+ * Compare various fields with those of the previous query, if any.
+ * Different serial numbers may be present if secondaries have not yet
+ * refreshed the data from the primary. Issue only a warning in that case.
+ */
+ if (oldname != NULL)
+ {
+ if (!sameword(soa.primary, oldsoa.primary))
+ pr_error("%s and %s have different primary for %s",
+ server, oldserver, name);
+
+ if (!sameword(soa.hostmaster, oldsoa.hostmaster))
+ pr_error("%s and %s have different hostmaster for %s",
+ server, oldserver, name);
+
+ if (soa.serial != oldsoa.serial)
+ pr_warning("%s and %s have different serial for %s",
+ server, oldserver, name);
+
+ if (soa.refresh != oldsoa.refresh)
+ pr_error("%s and %s have different refresh for %s",
+ server, oldserver, name);
+
+ if (soa.retry != oldsoa.retry)
+ pr_error("%s and %s have different retry for %s",
+ server, oldserver, name);
+
+ if (soa.expire != oldsoa.expire)
+ pr_error("%s and %s have different expire for %s",
+ server, oldserver, name);
+
+ if (soa.defttl != oldsoa.defttl)
+ pr_error("%s and %s have different defttl for %s",
+ server, oldserver, name);
+ }
+
+/*
+ * Save the current information.
+ */
+ oldname = strcpy(oldnamebuf, name);
+ oldserver = server;
+ oldsoa = soa;
+}
+
+ /*
+** CHECK_DUPL -- Check global address list for duplicates
+** ------------------------------------------------------
+**
+** Returns:
+** TRUE if the given host address already exists.
+** FALSE otherwise.
+**
+** Side effects:
+** Adds the host address to the list if not present.
+**
+** The information in this table is global, and is not cleared.
+*/
+
+#define AHASHSIZE 0x2000
+#define AHASHMASK 0x1fff
+
+typedef struct addr_tab {
+ ipaddr_t *addrlist; /* global list of addresses */
+ int addrcount; /* count of global addresses */
+} addr_tab_t;
+
+addr_tab_t addrtab[AHASHSIZE]; /* hash list of global addresses */
+
+bool
+check_dupl(addr)
+input ipaddr_t addr; /* address of host to check */
+{
+ register int i;
+ register addr_tab_t *s;
+
+ s = &addrtab[ntohl(addr) & AHASHMASK];
+
+ for (i = 0; i < s->addrcount; i++)
+ if (s->addrlist[i] == addr)
+ return(TRUE); /* duplicate */
+
+ s->addrlist = newlist(s->addrlist, s->addrcount+1, ipaddr_t);
+ s->addrlist[s->addrcount] = addr;
+ s->addrcount++;
+ return(FALSE);
+}
+
+ /*
+** CHECK_TTL -- Check list of records for different ttl values
+** -----------------------------------------------------------
+**
+** Returns:
+** TRUE if the ttl value matches the first record
+** already listed with the same name/type/class.
+** FALSE only when the first discrepancy is found.
+**
+** Side effects:
+** Adds the record data to the list if not present.
+*/
+
+#define THASHSIZE 2003
+
+typedef struct ttl_tab {
+ struct ttl_tab *next; /* next entry in chain */
+ char *name; /* name of resource record */
+ int type; /* resource record type */
+ int class; /* resource record class */
+ int ttl; /* time_to_live value */
+ int count; /* count of different ttl values */
+} ttl_tab_t;
+
+ttl_tab_t *ttltab[THASHSIZE]; /* hash list of record info */
+
+bool
+check_ttl(name, type, class, ttl)
+input char *name; /* resource record name */
+input int type, class, ttl; /* resource record fixed values */
+{
+ register ttl_tab_t *s;
+ register ttl_tab_t **ps;
+ register unsigned int hfunc;
+ register char *p;
+ register char c;
+
+/*
+ * Compute the hash function for this resource record.
+ * Look it up in the appropriate hash chain.
+ */
+ for (hfunc = type, p = name; (c = *p) != '\0'; p++)
+ {
+ hfunc = ((hfunc << 1) ^ (lower(c) & 0377)) % THASHSIZE;
+ }
+
+ for (ps = &ttltab[hfunc]; (s = *ps) != NULL; ps = &s->next)
+ {
+ if (s->type != type || s->class != class)
+ continue;
+ if (sameword(s->name, name))
+ break;
+ }
+
+/*
+ * Allocate new entry if not found.
+ */
+ if (s == NULL)
+ {
+ /* ps = &ttltab[hfunc]; */
+ s = newlist(NULL, 1, ttl_tab_t);
+
+ /* initialize new entry */
+ s->name = newstr(name);
+ s->type = type;
+ s->class = class;
+ s->ttl = ttl;
+ s->count = 0;
+
+ /* link it in */
+ s->next = *ps;
+ *ps = s;
+ }
+
+/*
+ * Check whether the ttl value matches the first recorded one.
+ * If not, signal only the first discrepancy encountered, so
+ * only one warning message will be printed.
+ */
+ if (s->ttl == ttl)
+ return(TRUE);
+
+ s->count += 1;
+ return((s->count == 1) ? FALSE : TRUE);
+}
+
+ /*
+** CLEAR_TTLTAB -- Clear resource record list for ttl checking
+** -----------------------------------------------------------
+**
+** Returns:
+** None.
+**
+** An entry on the hash list, and the host name in each
+** entry, have been allocated in dynamic memory.
+**
+** The information in this table is on a per-zone basis.
+** It must be cleared before any subsequent zone transfers.
+*/
+
+void
+clear_ttltab()
+{
+ register int i;
+ register ttl_tab_t *s, *t;
+
+ for (i = 0; i < THASHSIZE; i++)
+ {
+ if (ttltab[i] != NULL)
+ {
+ /* free chain of entries */
+ for (t = NULL, s = ttltab[i]; s != NULL; s = t)
+ {
+ t = s->next;
+ xfree(s->name);
+ xfree(s);
+ }
+
+ /* reset hash chain */
+ ttltab[i] = NULL;
+ }
+ }
+}
+
+ /*
+** HOST_INDEX -- Check list of host names for name being present
+** -------------------------------------------------------------
+**
+** Returns:
+** Index into hostname[] table, if found.
+** Current ``hostcount'' value, if not found.
+**
+** Side effects:
+** May add an entry to the hash list if not present.
+**
+** A linear search through the master table becomes very
+** costly for zones with more than a few thousand hosts.
+** Maintain a hash list with indexes into the master table.
+** Caller should update the master table after this call.
+*/
+
+#define HHASHSIZE 2003
+
+typedef struct host_tab {
+ struct host_tab *next; /* next entry in chain */
+ int slot; /* slot in host name table */
+} host_tab_t;
+
+host_tab_t *hosttab[HHASHSIZE]; /* hash list of host name info */
+
+int
+host_index(name, enter)
+input char *name; /* the host name to check */
+input bool enter; /* add to table if not found */
+{
+ register host_tab_t *s;
+ register host_tab_t **ps;
+ register unsigned int hfunc;
+ register char *p;
+ register char c;
+
+/*
+ * Compute the hash function for this host name.
+ * Look it up in the appropriate hash chain.
+ */
+ for (hfunc = 0, p = name; (c = *p) != '\0'; p++)
+ {
+ hfunc = ((hfunc << 1) ^ (lower(c) & 0377)) % HHASHSIZE;
+ }
+
+ for (ps = &hosttab[hfunc]; (s = *ps) != NULL; ps = &s->next)
+ {
+ if (s->slot >= hostcount)
+ continue;
+ if (sameword(hostname[s->slot], name))
+ break;
+ }
+
+/*
+ * Allocate new entry if not found.
+ */
+ if ((s == NULL) && enter)
+ {
+ /* ps = &hosttab[hfunc]; */
+ s = newlist(NULL, 1, host_tab_t);
+
+ /* initialize new entry */
+ s->slot = hostcount;
+
+ /* link it in */
+ s->next = *ps;
+ *ps = s;
+ }
+
+ return((s != NULL) ? s->slot : hostcount);
+}
+
+ /*
+** CLEAR_HOSTTAB -- Clear hash list for host name checking
+** -------------------------------------------------------
+**
+** Returns:
+** None.
+**
+** A hash list entry has been allocated in dynamic memory.
+**
+** The information in this table is on a per-zone basis.
+** It must be cleared before any subsequent zone transfers.
+*/
+
+void
+clear_hosttab()
+{
+ register int i;
+ register host_tab_t *s, *t;
+
+ for (i = 0; i < HHASHSIZE; i++)
+ {
+ if (hosttab[i] != NULL)
+ {
+ /* free chain of entries */
+ for (t = NULL, s = hosttab[i]; s != NULL; s = t)
+ {
+ t = s->next;
+ xfree(s);
+ }
+
+ /* reset hash chain */
+ hosttab[i] = NULL;
+ }
+ }
+}
+
+ /*
+** ZONE_INDEX -- Check list of zone names for name being present
+** -------------------------------------------------------------
+**
+** Returns:
+** Index into zonename[] table, if found.
+** Current ``zonecount'' value, if not found.
+**
+** Side effects:
+** May add an entry to the hash list if not present.
+**
+** A linear search through the master table becomes very
+** costly for more than a few thousand delegated zones.
+** Maintain a hash list with indexes into the master table.
+** Caller should update the master table after this call.
+*/
+
+#define ZHASHSIZE 2003
+
+typedef struct zone_tab {
+ struct zone_tab *next; /* next entry in chain */
+ int slot; /* slot in zone name table */
+} zone_tab_t;
+
+zone_tab_t *zonetab[ZHASHSIZE]; /* hash list of zone name info */
+
+int
+zone_index(name, enter)
+input char *name; /* the zone name to check */
+input bool enter; /* add to table if not found */
+{
+ register zone_tab_t *s;
+ register zone_tab_t **ps;
+ register unsigned int hfunc;
+ register char *p;
+ register char c;
+
+/*
+ * Compute the hash function for this zone name.
+ * Look it up in the appropriate hash chain.
+ */
+ for (hfunc = 0, p = name; (c = *p) != '\0'; p++)
+ {
+ hfunc = ((hfunc << 1) ^ (lower(c) & 0377)) % ZHASHSIZE;
+ }
+
+ for (ps = &zonetab[hfunc]; (s = *ps) != NULL; ps = &s->next)
+ {
+ if (s->slot >= zonecount)
+ continue;
+ if (sameword(zonename[s->slot], name))
+ break;
+ }
+
+/*
+ * Allocate new entry if not found.
+ */
+ if ((s == NULL) && enter)
+ {
+ /* ps = &zonetab[hfunc]; */
+ s = newlist(NULL, 1, zone_tab_t);
+
+ /* initialize new entry */
+ s->slot = zonecount;
+
+ /* link it in */
+ s->next = *ps;
+ *ps = s;
+ }
+
+ return((s != NULL) ? s->slot : zonecount);
+}
+
+ /*
+** CLEAR_ZONETAB -- Clear hash list for zone name checking
+** -------------------------------------------------------
+**
+** Returns:
+** None.
+**
+** A hash list entry has been allocated in dynamic memory.
+**
+** The information in this table is on a per-zone basis.
+** It must be cleared before any subsequent zone transfers.
+*/
+
+void
+clear_zonetab()
+{
+ register int i;
+ register zone_tab_t *s, *t;
+
+ for (i = 0; i < ZHASHSIZE; i++)
+ {
+ if (zonetab[i] != NULL)
+ {
+ /* free chain of entries */
+ for (t = NULL, s = zonetab[i]; s != NULL; s = t)
+ {
+ t = s->next;
+ xfree(s);
+ }
+
+ /* reset hash chain */
+ zonetab[i] = NULL;
+ }
+ }
+}
+
+ /*
+** CHECK_CANON -- Check list of domain names for name being canonical
+** ------------------------------------------------------------------
+**
+** Returns:
+** Nonzero if the name is definitely not canonical.
+** 0 if it is canonical, or if it remains undecided.
+**
+** Side effects:
+** Adds the domain name to the list if not present.
+**
+** The information in this table is global, and is not cleared
+** (which may be necessary if the checking algorithm changes).
+*/
+
+#define CHASHSIZE 2003
+
+typedef struct canon_tab {
+ struct canon_tab *next; /* next entry in chain */
+ char *name; /* domain name */
+ int status; /* nonzero if not canonical */
+} canon_tab_t;
+
+canon_tab_t *canontab[CHASHSIZE]; /* hash list of domain name info */
+
+int
+check_canon(name)
+input char *name; /* the domain name to check */
+{
+ register canon_tab_t *s;
+ register canon_tab_t **ps;
+ register unsigned int hfunc;
+ register char *p;
+ register char c;
+
+/*
+ * Compute the hash function for this domain name.
+ * Look it up in the appropriate hash chain.
+ */
+ for (hfunc = 0, p = name; (c = *p) != '\0'; p++)
+ {
+ hfunc = ((hfunc << 1) ^ (lower(c) & 0377)) % CHASHSIZE;
+ }
+
+ for (ps = &canontab[hfunc]; (s = *ps) != NULL; ps = &s->next)
+ {
+ if (sameword(s->name, name))
+ break;
+ }
+
+/*
+ * Allocate new entry if not found.
+ * Only then is the actual check carried out.
+ */
+ if (s == NULL)
+ {
+ /* ps = &canontab[hfunc]; */
+ s = newlist(NULL, 1, canon_tab_t);
+
+ /* initialize new entry */
+ s->name = newstr(name);
+ s->status = canonical(name);
+
+ /* link it in */
+ s->next = *ps;
+ *ps = s;
+ }
+
+ return(s->status);
+}
+
+ /*
+** CHECK_ADDR -- Check whether reverse address mappings revert to host
+** -------------------------------------------------------------------
+**
+** Returns:
+** TRUE if all addresses of host map back to host.
+** FALSE otherwise.
+*/
+
+bool
+check_addr(name)
+input char *name; /* host name to check addresses for */
+{
+ struct hostent *hp;
+ register int i;
+ struct in_addr inaddr[MAXADDRS];
+ int naddr;
+ char hnamebuf[MAXDNAME+1];
+ char *hname;
+ char inamebuf[MAXDNAME+1];
+ char *iname;
+ int matched;
+
+/*
+ * Look up the specified host to fetch its addresses.
+ */
+ hp = gethostbyname(name);
+ if (hp == NULL)
+ {
+ ns_error(name, T_A, C_IN, server);
+ return(FALSE);
+ }
+
+ hname = strcpy(hnamebuf, hp->h_name);
+
+ for (i = 0; i < MAXADDRS && hp->h_addr_list[i]; i++)
+ inaddr[i] = incopy(hp->h_addr_list[i]);
+ naddr = i;
+
+ if (verbose)
+ printf("Found %d address%s for %s\n",
+ naddr, plurale(naddr), hname);
+
+/*
+ * Map back the addresses found, and check whether they revert to host.
+ */
+ for (matched = 0, i = 0; i < naddr; i++)
+ {
+ iname = strcpy(inamebuf, inet_ntoa(inaddr[i]));
+
+ if (verbose)
+ printf("Checking %s address %s\n", hname, iname);
+
+ hp = gethostbyaddr((char *)&inaddr[i], INADDRSZ, AF_INET);
+ if (hp == NULL)
+ ns_error(iname, T_PTR, C_IN, server);
+ else if (!sameword(hp->h_name, hname))
+ pr_warning("%s address %s maps to %s",
+ hname, iname, hp->h_name);
+ else
+ matched++;
+ }
+
+ return((matched == naddr) ? TRUE : FALSE);
+}
+
+ /*
+** CHECK_NAME -- Check whether address belongs to host addresses
+** -------------------------------------------------------------
+**
+** Returns:
+** TRUE if given address was found among host addresses.
+** FALSE otherwise.
+*/
+
+bool
+check_name(addr)
+input ipaddr_t addr; /* address of host to check */
+{
+ struct hostent *hp;
+ register int i;
+ struct in_addr inaddr;
+ char hnamebuf[MAXDNAME+1];
+ char *hname;
+ char inamebuf[MAXDNAME+1];
+ char *iname;
+ int matched;
+
+/*
+ * Check whether the address is registered by fetching its host name.
+ */
+ inaddr.s_addr = addr;
+ iname = strcpy(inamebuf, inet_ntoa(inaddr));
+
+ hp = gethostbyaddr((char *)&inaddr, INADDRSZ, AF_INET);
+ if (hp == NULL)
+ {
+ ns_error(iname, T_PTR, C_IN, server);
+ return(FALSE);
+ }
+
+ hname = strcpy(hnamebuf, hp->h_name);
+
+ if (verbose)
+ printf("Address %s maps to %s\n", iname, hname);
+
+/*
+ * Lookup the host name found to fetch its addresses.
+ * Verify whether the mapped host name is canonical.
+ */
+ hp = gethostbyname(hname);
+ if (hp == NULL)
+ {
+ ns_error(hname, T_A, C_IN, server);
+ return(FALSE);
+ }
+
+ if (!sameword(hp->h_name, hname))
+ pr_warning("%s host %s is not canonical (%s)",
+ iname, hname, hp->h_name);
+
+/*
+ * Check whether the given address is listed among the known addresses.
+ */
+ for (matched = 0, i = 0; hp->h_addr_list[i]; i++)
+ {
+ inaddr = incopy(hp->h_addr_list[i]);
+
+ if (verbose)
+ printf("Checking %s address %s\n",
+ hname, inet_ntoa(inaddr));
+
+ if (inaddr.s_addr == addr)
+ matched++;
+ }
+
+ if (!matched)
+ pr_error("address %s does not belong to %s",
+ iname, hname);
+
+ return(matched ? TRUE : FALSE);
+}
+
+ /*
+** PARSE_TYPE -- Decode rr type from input string
+** ----------------------------------------------
+**
+** Returns:
+** Value of resource record type.
+** -1 if specified record name is invalid.
+**
+** Note. T_MD, T_MF, T_MAILA are obsolete, but recognized.
+** T_AXFR is not allowed to be specified as query type.
+*/
+
+int
+parse_type(str)
+input char *str; /* input string with record type */
+{
+ register int type;
+
+ if (sameword(str, "A")) return(T_A);
+ if (sameword(str, "NS")) return(T_NS);
+ if (sameword(str, "MD")) return(T_MD); /* obsolete */
+ if (sameword(str, "MF")) return(T_MF); /* obsolete */
+ if (sameword(str, "CNAME")) return(T_CNAME);
+ if (sameword(str, "SOA")) return(T_SOA);
+ if (sameword(str, "MB")) return(T_MB);
+ if (sameword(str, "MG")) return(T_MG);
+ if (sameword(str, "MR")) return(T_MR);
+ if (sameword(str, "NULL")) return(T_NULL);
+ if (sameword(str, "WKS")) return(T_WKS);
+ if (sameword(str, "PTR")) return(T_PTR);
+ if (sameword(str, "HINFO")) return(T_HINFO);
+ if (sameword(str, "MINFO")) return(T_MINFO);
+ if (sameword(str, "MX")) return(T_MX);
+ if (sameword(str, "TXT")) return(T_TXT);
+
+ if (sameword(str, "RP")) return(T_RP);
+ if (sameword(str, "AFSDB")) return(T_AFSDB);
+ if (sameword(str, "X25")) return(T_X25);
+ if (sameword(str, "ISDN")) return(T_ISDN);
+ if (sameword(str, "RT")) return(T_RT);
+ if (sameword(str, "NSAP")) return(T_NSAP);
+ if (sameword(str, "NSAP-PTR")) return(T_NSAPPTR);
+ if (sameword(str, "SIG")) return(T_SIG);
+ if (sameword(str, "KEY")) return(T_KEY);
+ if (sameword(str, "PX")) return(T_PX);
+ if (sameword(str, "GPOS")) return(T_GPOS);
+ if (sameword(str, "AAAA")) return(T_AAAA);
+ if (sameword(str, "LOC")) return(T_LOC);
+
+ if (sameword(str, "UINFO")) return(T_UINFO);
+ if (sameword(str, "UID")) return(T_UID);
+ if (sameword(str, "GID")) return(T_GID);
+ if (sameword(str, "UNSPEC")) return(T_UNSPEC);
+
+ if (sameword(str, "AXFR")) return(-1); /* illegal */
+ if (sameword(str, "MAILB")) return(T_MAILB);
+ if (sameword(str, "MAILA")) return(T_MAILA); /* obsolete */
+ if (sameword(str, "ANY")) return(T_ANY);
+ if (sameword(str, "*")) return(T_ANY);
+
+ type = atoi(str);
+ if (type >= T_FIRST && type <= T_LAST)
+ return(type);
+
+ return(-1);
+}
+
+ /*
+** PARSE_CLASS -- Decode rr class from input string
+** ------------------------------------------------
+**
+** Returns:
+** Value of resource class.
+** -1 if specified class name is invalid.
+**
+** Note. C_CSNET is obsolete, but recognized.
+*/
+
+int
+parse_class(str)
+input char *str; /* input string with resource class */
+{
+ register int class;
+
+ if (sameword(str, "IN")) return(C_IN);
+ if (sameword(str, "INTERNET")) return(C_IN);
+ if (sameword(str, "CS")) return(C_CSNET); /* obsolete */
+ if (sameword(str, "CSNET")) return(C_CSNET); /* obsolete */
+ if (sameword(str, "CH")) return(C_CHAOS);
+ if (sameword(str, "CHAOS")) return(C_CHAOS);
+ if (sameword(str, "HS")) return(C_HS);
+ if (sameword(str, "HESIOD")) return(C_HS);
+
+ if (sameword(str, "ANY")) return(C_ANY);
+ if (sameword(str, "*")) return(C_ANY);
+
+ class = atoi(str);
+ if (class > 0)
+ return(class);
+
+ return(-1);
+}
+
+ /*
+** IN_ADDR_ARPA -- Convert dotted quad string to reverse in-addr.arpa
+** ------------------------------------------------------------------
+**
+** Returns:
+** Pointer to appropriate reverse in-addr.arpa name
+** with trailing dot to force absolute domain name.
+** NULL in case of invalid dotted quad input string.
+*/
+
+char *
+in_addr_arpa(dottedquad)
+input char *dottedquad; /* input string with dotted quad */
+{
+ static char addrbuf[4*4 + sizeof(ARPA_ROOT) + 2];
+ unsigned int a[4];
+ register int n;
+
+ n = sscanf(dottedquad, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]);
+ switch (n)
+ {
+ case 4:
+ (void) sprintf(addrbuf, "%u.%u.%u.%u.%s.",
+ a[3]&0xff, a[2]&0xff, a[1]&0xff, a[0]&0xff, ARPA_ROOT);
+ break;
+
+ case 3:
+ (void) sprintf(addrbuf, "%u.%u.%u.%s.",
+ a[2]&0xff, a[1]&0xff, a[0]&0xff, ARPA_ROOT);
+ break;
+
+ case 2:
+ (void) sprintf(addrbuf, "%u.%u.%s.",
+ a[1]&0xff, a[0]&0xff, ARPA_ROOT);
+ break;
+
+ case 1:
+ (void) sprintf(addrbuf, "%u.%s.",
+ a[0]&0xff, ARPA_ROOT);
+ break;
+
+ default:
+ return(NULL);
+ }
+
+ while (--n >= 0)
+ if (a[n] > 255)
+ return(NULL);
+
+ return(addrbuf);
+}
+
+ /*
+** NSAP_INT -- Convert dotted nsap address string to reverse nsap.int
+** ------------------------------------------------------------------
+**
+** Returns:
+** Pointer to appropriate reverse nsap.int name
+** with trailing dot to force absolute domain name.
+** NULL in case of invalid nsap address input string.
+*/
+
+char *
+nsap_int(name)
+input char *name; /* input string with dotted nsap */
+{
+ static char addrbuf[4*MAXNSAP + sizeof(NSAP_ROOT) + 2];
+ register int n;
+ register int i;
+
+ /* skip optional leading hex indicator */
+ if (samehead(name, "0x"))
+ name += 2;
+
+ for (n = 0, i = strlength(name)-1; i >= 0; --i)
+ {
+ /* skip optional interspersed separators */
+ if (name[i] == '.' || name[i] == '+' || name[i] == '/')
+ continue;
+
+ /* must consist of hex digits only */
+ if (!is_xdigit(name[i]))
+ return(NULL);
+
+ /* but not too many */
+ if (n >= 4*MAXNSAP)
+ return(NULL);
+
+ addrbuf[n++] = name[i];
+ addrbuf[n++] = '.';
+ }
+
+ /* must have an even number of hex digits */
+ if (n == 0 || (n % 4) != 0)
+ return(NULL);
+
+ (void) sprintf(&addrbuf[n], "%s.", NSAP_ROOT);
+ return(addrbuf);
+}
+
+ /*
+** PRINT_HOST -- Print host name and address of hostent struct
+** -----------------------------------------------------------
+**
+** Returns:
+** None.
+*/
+
+void
+print_host(heading, hp)
+input char *heading; /* header string */
+input struct hostent *hp; /* location of hostent struct */
+{
+ register char **ap;
+
+ printf("%s: %s", heading, hp->h_name);
+
+ for (ap = hp->h_addr_list; ap && *ap; ap++)
+ {
+ if (ap == hp->h_addr_list)
+ printf("\nAddress:");
+
+ printf(" %s", inet_ntoa(incopy(*ap)));
+ }
+
+ for (ap = hp->h_aliases; ap && *ap && **ap; ap++)
+ {
+ if (ap == hp->h_aliases)
+ printf("\nAliases:");
+
+ printf(" %s", *ap);
+ }
+
+ printf("\n\n");
+}
+
+ /*
+** SHOW_RES -- Show resolver database information
+** ----------------------------------------------
+**
+** Returns:
+** None.
+**
+** Inputs:
+** The resolver database _res is localized in the resolver.
+*/
+
+void
+show_res()
+{
+ register int i;
+ register char **domain;
+
+/*
+ * The default domain is defined by the "domain" entry in /etc/resolv.conf
+ * if not overridden by the environment variable "LOCALDOMAIN".
+ * If still not defined, gethostname() may yield a fully qualified host name.
+ */
+ printf("Default domain:");
+ if (_res.defdname[0] != '\0')
+ printf(" %s", _res.defdname);
+ printf("\n");
+
+/*
+ * The search domains are extracted from the default domain components,
+ * but may be overridden by "search" directives in /etc/resolv.conf
+ * since 4.8.3.
+ */
+ printf("Search domains:");
+ for (domain = _res.dnsrch; *domain; domain++)
+ printf(" %s", *domain);
+ printf("\n");
+
+/*
+ * The routine res_send() will do _res.retry tries to contact each of the
+ * _res.nscount nameserver addresses before giving up when using datagrams.
+ * The first try will timeout after _res.retrans seconds. Each following
+ * try will timeout after ((_res.retrans << try) / _res.nscount) seconds.
+ * Note. When we contact an explicit server the addresses will be replaced
+ * by the multiple addresses of the same server.
+ * When doing a zone transfer _res.retrans is used for the connect timeout.
+ */
+ printf("Timeout per retry: %d secs\n", _res.retrans);
+ printf("Number of retries: %d\n", _res.retry);
+
+ printf("Number of addresses: %d\n", _res.nscount);
+ for (i = 0; i < _res.nscount; i++)
+ printf("%s\n", inet_ntoa(nslist(i).sin_addr));
+
+/*
+ * The resolver options are initialized by res_init() to contain the
+ * defaults settings (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
+ * The various options have the following meaning:
+ *
+ * RES_INIT set after res_init() has been called
+ * RES_DEBUG let the resolver modules print debugging info
+ * RES_AAONLY want authoritative answers only (not implemented)
+ * RES_USEVC use tcp virtual circuit instead of udp datagrams
+ * RES_PRIMARY use primary nameserver only (not implemented)
+ * RES_IGNTC ignore datagram truncation; don't switch to tcp
+ * RES_RECURSE forward query if answer not locally available
+ * RES_DEFNAMES add default domain to queryname without dot
+ * RES_STAYOPEN keep tcp socket open for subsequent queries
+ * RES_DNSRCH append search domains even to queryname with dot
+ */
+ printf("Options set:");
+ if (bitset(RES_INIT, _res.options)) printf(" INIT");
+ if (bitset(RES_DEBUG, _res.options)) printf(" DEBUG");
+ if (bitset(RES_AAONLY, _res.options)) printf(" AAONLY");
+ if (bitset(RES_USEVC, _res.options)) printf(" USEVC");
+ if (bitset(RES_PRIMARY, _res.options)) printf(" PRIMARY");
+ if (bitset(RES_IGNTC, _res.options)) printf(" IGNTC");
+ if (bitset(RES_RECURSE, _res.options)) printf(" RECURSE");
+ if (bitset(RES_DEFNAMES, _res.options)) printf(" DEFNAMES");
+ if (bitset(RES_STAYOPEN, _res.options)) printf(" STAYOPEN");
+ if (bitset(RES_DNSRCH, _res.options)) printf(" DNSRCH");
+ printf("\n");
+
+ printf("Options clr:");
+ if (!bitset(RES_INIT, _res.options)) printf(" INIT");
+ if (!bitset(RES_DEBUG, _res.options)) printf(" DEBUG");
+ if (!bitset(RES_AAONLY, _res.options)) printf(" AAONLY");
+ if (!bitset(RES_USEVC, _res.options)) printf(" USEVC");
+ if (!bitset(RES_PRIMARY, _res.options)) printf(" PRIMARY");
+ if (!bitset(RES_IGNTC, _res.options)) printf(" IGNTC");
+ if (!bitset(RES_RECURSE, _res.options)) printf(" RECURSE");
+ if (!bitset(RES_DEFNAMES, _res.options)) printf(" DEFNAMES");
+ if (!bitset(RES_STAYOPEN, _res.options)) printf(" STAYOPEN");
+ if (!bitset(RES_DNSRCH, _res.options)) printf(" DNSRCH");
+ printf("\n");
+
+/*
+ * The new BIND 4.9.3 has additional features which are not (yet) used.
+ */
+ printf("\n");
+}
+
+ /*
+** PRINT_STATISTICS -- Print resource record statistics
+** ----------------------------------------------------
+**
+** Returns:
+** None.
+**
+** Inputs:
+** The record_stats[] counts have been updated by print_rrec().
+*/
+
+void
+print_statistics(name, filter, class)
+input char *name; /* name of zone we are listing */
+input int filter; /* type of records we want to see */
+input int class; /* class of records we want to see */
+{
+ register int type;
+ int nrecords;
+
+ for (type = T_FIRST; type <= T_LAST; type++)
+ {
+ nrecords = record_stats[type];
+ if (nrecords > 0 || ((filter != T_ANY) && want_type(type, filter)))
+ {
+ printf("Found %4d %-5s record%-1s", nrecords,
+ pr_type(type), plural(nrecords));
+
+ if (class != C_IN)
+ printf(" in class %s", pr_class(class));
+
+ printf(" within %s\n", name);
+ }
+ }
+}
+
+
+/*
+** CLEAR_STATISTICS -- Clear resource record statistics
+** ----------------------------------------------------
+**
+** Returns:
+** None.
+*/
+
+void
+clear_statistics()
+{
+ bzero((char *)record_stats, sizeof(record_stats));
+}
+
+ /*
+** SHOW_TYPES -- Show resource record types wanted
+** -----------------------------------------------
+**
+** Returns:
+** None.
+*/
+
+void
+show_types(name, filter, class)
+input char *name; /* name we want to query about */
+input int filter; /* type of records we want to see */
+input int class; /* class of records we want to see */
+{
+ register int type;
+
+ if (filter >= T_NONE)
+ {
+ printf("Query about %s for record types", name);
+
+ if (filter == T_ANY)
+ printf(" %s", pr_type(T_ANY));
+ else
+ for (type = T_FIRST; type <= T_LAST; type++)
+ if (want_type(type, filter))
+ printf(" %s", pr_type(type));
+
+ if (class != C_IN)
+ printf(" in class %s", pr_class(class));
+
+ printf("\n");
+ }
+}
+
+ /*
+** NS_ERROR -- Print error message from errno and h_errno
+** ------------------------------------------------------
+**
+** Returns:
+** None.
+**
+** If BIND res_send() fails, it will leave errno in either of the first
+** two following states when using datagrams. Note that this depends on
+** the proper handling of connected datagram sockets, which is usually
+** true if BSD >= 43 (see res_send.c for details; it may need a patch).
+** Note. If the 4.8 version succeeds, it may leave errno as EAFNOSUPPORT
+** if it has disconnected a previously connected datagram socket, since
+** the dummy address used to disconnect does not have a proper family set.
+** Always clear errno after getting a reply, or patch res_send().
+** Our private version of res_send() will leave also other error statuses.
+*/
+
+void
+ns_error(name, type, class, host)
+input char *name; /* full name we queried about */
+input int type; /* record type we queried about */
+input int class; /* record class we queried about */
+input char *host; /* set if explicit server was used */
+{
+ static char *auth = "Authoritative answer";
+
+/*
+ * Print the message associated with the network related errno values.
+ */
+ switch (errno)
+ {
+ case ECONNREFUSED:
+ /*
+ * The contacted host does not have a nameserver running.
+ * The standard res_send() also returns this if none of
+ * the intended hosts could be reached via datagrams.
+ */
+ if (host != NULL)
+ errmsg("Nameserver %s not running", host);
+ else
+ errmsg("Nameserver not running");
+ break;
+
+ case ETIMEDOUT:
+ /*
+ * The contacted server did not give any reply at all
+ * within the specified time frame.
+ */
+ if (host != NULL)
+ errmsg("Nameserver %s not responding", host);
+ else
+ errmsg("Nameserver not responding");
+ break;
+
+ case ENETDOWN:
+ case ENETUNREACH:
+ case EHOSTDOWN:
+ case EHOSTUNREACH:
+ /*
+ * The host to be contacted or its network can not be reached.
+ * Our private res_send() also returns this using datagrams.
+ */
+ if (host != NULL)
+ errmsg("Nameserver %s not reachable", host);
+ else
+ errmsg("Nameserver not reachable");
+ break;
+ }
+
+/*
+ * Print the message associated with the particular nameserver error.
+ */
+ switch (h_errno)
+ {
+ case HOST_NOT_FOUND:
+ /*
+ * The specified name does definitely not exist at all.
+ * In this case the answer is always authoritative.
+ * Nameserver status: NXDOMAIN
+ */
+ if (class != C_IN)
+ errmsg("%s does not exist in class %s (%s)",
+ name, pr_class(class), auth);
+ else if (host != NULL)
+ errmsg("%s does not exist at %s (%s)",
+ name, host, auth);
+ else
+ errmsg("%s does not exist (%s)",
+ name, auth);
+ break;
+
+ case NO_HOST:
+ /*
+ * The specified name does not exist, but the answer
+ * was not authoritative, so it is still undecided.
+ * Nameserver status: NXDOMAIN
+ */
+ if (class != C_IN)
+ errmsg("%s does not exist in class %s, try again",
+ name, pr_class(class));
+ else if (host != NULL)
+ errmsg("%s does not exist at %s, try again",
+ name, host);
+ else
+ errmsg("%s does not exist, try again",
+ name);
+ break;
+
+ case NO_DATA:
+ /*
+ * The name is valid, but the specified type does not exist.
+ * This status is here returned only in case authoritative.
+ * Nameserver status: NOERROR
+ */
+ if (class != C_IN)
+ errmsg("%s has no %s record in class %s (%s)",
+ name, pr_type(type), pr_class(class), auth);
+ else if (host != NULL)
+ errmsg("%s has no %s record at %s (%s)",
+ name, pr_type(type), host, auth);
+ else
+ errmsg("%s has no %s record (%s)",
+ name, pr_type(type), auth);
+ break;
+
+ case NO_RREC:
+ /*
+ * The specified type does not exist, but we don't know whether
+ * the name is valid or not. The answer was not authoritative.
+ * Perhaps recursion was off, and no data was cached locally.
+ * Nameserver status: NOERROR
+ */
+ if (class != C_IN)
+ errmsg("%s %s record in class %s currently not present",
+ name, pr_type(type), pr_class(class));
+ else if (host != NULL)
+ errmsg("%s %s record currently not present at %s",
+ name, pr_type(type), host);
+ else
+ errmsg("%s %s record currently not present",
+ name, pr_type(type));
+ break;
+
+ case TRY_AGAIN:
+ /*
+ * Some intermediate failure, e.g. connect timeout,
+ * or some local operating system transient errors.
+ * General failure to reach any appropriate servers.
+ * The status SERVFAIL now yields a separate error code.
+ * Nameserver status: (SERVFAIL)
+ */
+ if (class != C_IN)
+ errmsg("%s %s record in class %s not found, try again",
+ name, pr_type(type), pr_class(class));
+ else if (host != NULL)
+ errmsg("%s %s record not found at %s, try again",
+ name, pr_type(type), host);
+ else
+ errmsg("%s %s record not found, try again",
+ name, pr_type(type));
+ break;
+
+ case SERVER_FAILURE:
+ /*
+ * Explicit server failure status. This will be returned upon
+ * some internal server errors, forwarding failures, or when
+ * the server is not authoritative for a specific class.
+ * Also if the zone data has expired at a secondary server.
+ * Nameserver status: SERVFAIL
+ */
+ if (class != C_IN)
+ errmsg("%s %s record in class %s not found, server failure",
+ name, pr_type(type), pr_class(class));
+ else if (host != NULL)
+ errmsg("%s %s record not found at %s, server failure",
+ name, pr_type(type), host);
+ else
+ errmsg("%s %s record not found, server failure",
+ name, pr_type(type));
+ break;
+
+ case NO_RECOVERY:
+ /*
+ * Some irrecoverable format error, or server refusal.
+ * The status REFUSED now yields a separate error code.
+ * Nameserver status: (REFUSED) FORMERR NOTIMP NOCHANGE
+ */
+ if (class != C_IN)
+ errmsg("%s %s record in class %s not found, no recovery",
+ name, pr_type(type), pr_class(class));
+ else if (host != NULL)
+ errmsg("%s %s record not found at %s, no recovery",
+ name, pr_type(type), host);
+ else
+ errmsg("%s %s record not found, no recovery",
+ name, pr_type(type));
+ break;
+
+ case QUERY_REFUSED:
+ /*
+ * The server explicitly refused to answer the query.
+ * Servers can be configured to disallow zone transfers.
+ * Nameserver status: REFUSED
+ */
+ if (class != C_IN)
+ errmsg("%s %s record in class %s query refused",
+ name, pr_type(type), pr_class(class));
+ else if (host != NULL)
+ errmsg("%s %s record query refused by %s",
+ name, pr_type(type), host);
+ else
+ errmsg("%s %s record query refused",
+ name, pr_type(type));
+ break;
+
+ default:
+ /*
+ * Unknown cause for server failure.
+ */
+ if (class != C_IN)
+ errmsg("%s %s record in class %s not found",
+ name, pr_type(type), pr_class(class));
+ else if (host != NULL)
+ errmsg("%s %s record not found at %s",
+ name, pr_type(type), host);
+ else
+ errmsg("%s %s record not found",
+ name, pr_type(type));
+ break;
+ }
+}
+
+ /*
+** DECODE_ERROR -- Convert nameserver error code to error message
+** --------------------------------------------------------------
+**
+** Returns:
+** Pointer to appropriate error message.
+*/
+
+char *
+decode_error(rcode)
+input int rcode; /* error code from bp->rcode */
+{
+ switch (rcode)
+ {
+ case NOERROR: return("no error");
+ case FORMERR: return("format error");
+ case SERVFAIL: return("server failure");
+ case NXDOMAIN: return("non-existent domain");
+ case NOTIMP: return("not implemented");
+ case REFUSED: return("query refused");
+ case NOCHANGE: return("no change");
+ }
+
+ return("unknown error");
+}
+
+ /*
+** PRINT_STATUS -- Print result status after nameserver query
+** ----------------------------------------------------------
+**
+** Returns:
+** None.
+**
+** Conditions:
+** The size of the answer buffer must have been
+** checked before to be of sufficient length,
+** i.e. to contain at least the buffer header.
+*/
+
+void
+print_status(answerbuf)
+input querybuf *answerbuf; /* location of answer buffer */
+{
+ HEADER *bp;
+ int ancount;
+ bool failed;
+
+ bp = (HEADER *)answerbuf;
+ ancount = ntohs(bp->ancount);
+ failed = (bp->rcode != NOERROR || ancount == 0);
+
+ printf("%sQuery %s, %d answer%s%s, %sstatus: %s\n",
+ verbose ? "" : dbprefix,
+ failed ? "failed" : "done",
+ ancount, plural(ancount),
+ bp->tc ? " (truncated)" : "",
+ bp->aa ? "authoritative " : "",
+ decode_error((int)bp->rcode));
+}
+
+ /*
+** PR_ERROR -- Print error message about encountered inconsistencies
+** -----------------------------------------------------------------
+**
+** We are supposed to have an error condition which is fatal
+** for normal continuation, and the message is always printed.
+**
+** Returns:
+** None.
+**
+** Side effects:
+** Increments the global error count.
+*/
+
+void /*VARARGS1*/
+pr_error(fmt, a, b, c, d)
+input char *fmt; /* format of message */
+input char *a, *b, *c, *d; /* optional arguments */
+{
+ (void) fprintf(stderr, " *** ");
+ (void) fprintf(stderr, fmt, a, b, c, d);
+ (void) fprintf(stderr, "\n");
+
+ /* flag an error */
+ errorcount++;
+}
+
+
+/*
+** PR_WARNING -- Print warning message about encountered inconsistencies
+** ---------------------------------------------------------------------
+**
+** We are supposed to have an error condition which is non-fatal
+** for normal continuation, and the message is suppressed in case
+** quiet mode has been selected.
+**
+** Returns:
+** None.
+*/
+
+void /*VARARGS1*/
+pr_warning(fmt, a, b, c, d)
+input char *fmt; /* format of message */
+input char *a, *b, *c, *d; /* optional arguments */
+{
+ if (!quiet)
+ {
+ (void) fprintf(stderr, " !!! ");
+ (void) fprintf(stderr, fmt, a, b, c, d);
+ (void) fprintf(stderr, "\n");
+ }
+}
+
+ /*
+** WANT_TYPE -- Indicate whether the rr type matches the desired filter
+** --------------------------------------------------------------------
+**
+** Returns:
+** TRUE if the resource record type matches the filter.
+** FALSE otherwise.
+**
+** In regular mode, the querytype is used to formulate the query,
+** and the filter is set to T_ANY to filter out any response.
+** In listmode, we get everything, so the filter is set to the
+** querytype to filter out the proper responses.
+** Note that T_NONE is the default querytype in listmode.
+*/
+
+bool
+want_type(type, filter)
+input int type; /* resource record type */
+input int filter; /* type of records we want to see */
+{
+ if (type == filter)
+ return(TRUE);
+
+ if (filter == T_ANY)
+ return(TRUE);
+
+ if (filter == T_NONE &&
+ (type == T_A || type == T_NS || type == T_PTR))
+ return(TRUE);
+
+ if (filter == T_MAILB &&
+ (type == T_MB || type == T_MR || type == T_MG || type == T_MINFO))
+ return(TRUE);
+
+ if (filter == T_MAILA &&
+ (type == T_MD || type == T_MF))
+ return(TRUE);
+
+ return(FALSE);
+}
+
+ /*
+** WANT_CLASS -- Indicate whether the rr class matches the desired filter
+** ----------------------------------------------------------------------
+**
+** Returns:
+** TRUE if the resource record class matches the filter.
+** FALSE otherwise.
+**
+** In regular mode, the queryclass is used to formulate the query,
+** and the filter is set to C_ANY to filter out any response.
+** In listmode, we get everything, so the filter is set to the
+** queryclass to filter out the proper responses.
+** Note that C_IN is the default queryclass in listmode.
+*/
+
+bool
+want_class(class, filter)
+input int class; /* resource record class */
+input int filter; /* class of records we want to see */
+{
+ if (class == filter)
+ return(TRUE);
+
+ if (filter == C_ANY)
+ return(TRUE);
+
+ return(FALSE);
+}
+
+ /*
+** INDOMAIN -- Check whether a name belongs to a zone
+** --------------------------------------------------
+**
+** Returns:
+** TRUE if the given name lies anywhere in the zone, or
+** if the given name is the same as the zone and may be so.
+** FALSE otherwise.
+*/
+
+bool
+indomain(name, domain, equal)
+input char *name; /* the name under consideration */
+input char *domain; /* the name of the zone */
+input bool equal; /* set if name may be same as zone */
+{
+ register char *dot;
+
+ if (sameword(name, domain))
+ return(equal);
+
+ if (sameword(domain, "."))
+ return(TRUE);
+
+ dot = index(name, '.');
+ while (dot != NULL)
+ {
+ if (sameword(dot+1, domain))
+ return(TRUE);
+
+ dot = index(dot+1, '.');
+ }
+
+ return(FALSE);
+}
+
+ /*
+** SAMEDOMAIN -- Check whether a name belongs to a zone
+** ----------------------------------------------------
+**
+** Returns:
+** TRUE if the given name lies directly in the zone, or
+** if the given name is the same as the zone and may be so.
+** FALSE otherwise.
+*/
+
+bool
+samedomain(name, domain, equal)
+input char *name; /* the name under consideration */
+input char *domain; /* the name of the zone */
+input bool equal; /* set if name may be same as zone */
+{
+ register char *dot;
+
+ if (sameword(name, domain))
+ return(equal);
+
+ dot = index(name, '.');
+ if (dot == NULL)
+ return(sameword(domain, "."));
+
+ if (sameword(dot+1, domain))
+ return(TRUE);
+
+ return(FALSE);
+}
+
+ /*
+** GLUERECORD -- Check whether a name is a glue record
+** ---------------------------------------------------
+**
+** Returns:
+** TRUE is this is a glue record.
+** FALSE otherwise.
+**
+** The name is supposed to be the name of an address record.
+** If it lies directly in the given zone, it is considered
+** an ordinary host within that zone, and not a glue record.
+** If it does not belong to the given zone at all, is it
+** here considered to be a glue record.
+** If it lies in the given zone, but not directly, it is
+** considered a glue record if it belongs to any of the known
+** delegated zones of the given zone.
+** In the root zone itself are no hosts, only glue records.
+*/
+
+bool
+gluerecord(name, domain, zone, nzones)
+input char *name; /* the name under consideration */
+input char *domain; /* name of zone being processed */
+input char *zone[]; /* list of known delegated zones */
+input int nzones; /* number of known delegated zones */
+{
+ register int n;
+
+ if (sameword(domain, "."))
+ return(TRUE);
+
+ if (samedomain(name, domain, TRUE))
+ return(FALSE);
+
+ if (!indomain(name, domain, TRUE))
+ return(TRUE);
+
+ for (n = 0; n < nzones; n++)
+ if (indomain(name, zone[n], TRUE))
+ return(TRUE);
+
+ return(FALSE);
+}
+
+ /*
+** MATCHLABELS -- Determine number of matching domain name labels
+** --------------------------------------------------------------
+**
+** Returns:
+** Number of shared trailing components in both names.
+*/
+
+int
+matchlabels(name, domain)
+input char *name; /* domain name to check */
+input char *domain; /* domain name to compare against */
+{
+ register int i, j;
+ int matched = 0;
+
+ i = strlength(name);
+ j = strlength(domain);
+
+ while (--i >= 0 && --j >= 0)
+ {
+ if (lower(name[i]) != lower(domain[j]))
+ break;
+ if (domain[j] == '.')
+ matched++;
+ else if (j == 0 && (i == 0 || name[i-1] == '.'))
+ matched++;
+ }
+
+ return(matched);
+}
+
+ /*
+** PR_DOMAIN -- Convert domain name according to printing options
+** --------------------------------------------------------------
+**
+** Returns:
+** Pointer to new domain name, if conversion was done.
+** Pointer to original name, if no conversion necessary.
+*/
+
+char *
+pr_domain(name, listing)
+input char *name; /* domain name to be printed */
+input bool listing; /* set if this is a zone listing */
+{
+ char *newname; /* converted domain name */
+
+/*
+ * Print reverse nsap.int name in forward notation, unless prohibited.
+ */
+ if (revnsap && !dotprint)
+ {
+ newname = pr_nsap(name);
+ if (newname != name)
+ return(newname);
+ }
+
+/*
+ * Print domain names with trailing dot if necessary.
+ */
+ if (listing || dotprint)
+ {
+ newname = pr_dotname(name);
+ if (newname != name)
+ return(newname);
+ }
+
+/*
+ * No conversion was required, use original name.
+ */
+ return(name);
+}
+
+ /*
+** PR_DOTNAME -- Return domain name with trailing dot
+** --------------------------------------------------
+**
+** Returns:
+** Pointer to new domain name, if dot was added.
+** Pointer to original name, if dot was already present.
+*/
+
+char *
+pr_dotname(name)
+input char *name; /* domain name to append to */
+{
+ static char buf[MAXDNAME+2]; /* buffer to store new domain name */
+ register int n;
+
+ n = strlength(name);
+ if (n > 0 && name[n-1] == '.')
+ return(name);
+
+ if (n > MAXDNAME)
+ n = MAXDNAME;
+
+#ifdef obsolete
+ (void) sprintf(buf, "%.*s.", MAXDNAME, name);
+#endif
+ bcopy(name, buf, n);
+ buf[n] = '.';
+ buf[n+1] = '\0';
+ return(buf);
+}
+
+ /*
+** PR_NSAP -- Convert reverse nsap.int to dotted forward notation
+** --------------------------------------------------------------
+**
+** Returns:
+** Pointer to new dotted nsap, if converted.
+** Pointer to original name otherwise.
+*/
+
+char *
+pr_nsap(name)
+input char *name; /* potential reverse nsap.int name */
+{
+ static char buf[3*MAXNSAP+1];
+ register char *p;
+ register int n;
+ register int i;
+
+ /* must begin with single hex digits separated by dots */
+ for (i = 0; is_xdigit(name[i]) && name[i+1] == '.'; i += 2)
+ continue;
+
+ /* must have an even number of hex digits */
+ if (i == 0 || (i % 4) != 0)
+ return(name);
+
+ /* but not too many */
+ if (i > 4*MAXNSAP)
+ return(name);
+
+ /* must end in the appropriate root domain */
+ if (!sameword(&name[i], NSAP_ROOT))
+ return(name);
+
+ for (p = buf, n = 0; i >= 4; i -= 4, n++)
+ {
+ *p++ = name[i-2];
+ *p++ = name[i-4];
+
+ /* add dots for readability */
+ if ((n % 2) == 0 && (i - 4) > 0)
+ *p++ = '.';
+ }
+ *p = '\0';
+
+ return(buf);
+}
+
+ /*
+** PR_TYPE -- Return name of resource record type
+** ----------------------------------------------
+**
+** Returns:
+** Pointer to name of resource record type.
+**
+** Note. All possible (even obsolete) types are recognized.
+*/
+
+char *
+pr_type(type)
+input int type; /* resource record type */
+{
+ static char buf[30];
+
+ switch (type)
+ {
+ case T_A: return("A"); /* internet address */
+ case T_NS: return("NS"); /* authoritative server */
+ case T_MD: return("MD"); /* mail destination */
+ case T_MF: return("MF"); /* mail forwarder */
+ case T_CNAME: return("CNAME"); /* canonical name */
+ case T_SOA: return("SOA"); /* start of auth zone */
+ case T_MB: return("MB"); /* mailbox domain name */
+ case T_MG: return("MG"); /* mail group member */
+ case T_MR: return("MR"); /* mail rename name */
+ case T_NULL: return("NULL"); /* null resource record */
+ case T_WKS: return("WKS"); /* well known service */
+ case T_PTR: return("PTR"); /* domain name pointer */
+ case T_HINFO: return("HINFO"); /* host information */
+ case T_MINFO: return("MINFO"); /* mailbox information */
+ case T_MX: return("MX"); /* mail routing info */
+ case T_TXT: return("TXT"); /* descriptive text */
+
+ case T_RP: return("RP"); /* responsible person */
+ case T_AFSDB: return("AFSDB"); /* afs database location */
+ case T_X25: return("X25"); /* x25 address */
+ case T_ISDN: return("ISDN"); /* isdn address */
+ case T_RT: return("RT"); /* route through host */
+ case T_NSAP: return("NSAP"); /* nsap address */
+ case T_NSAPPTR: return("NSAP-PTR"); /* nsap pointer */
+ case T_SIG: return("SIG"); /* security signature */
+ case T_KEY: return("KEY"); /* security key */
+ case T_PX: return("PX"); /* rfc822 - x400 mapping */
+ case T_GPOS: return("GPOS"); /* geographical position */
+ case T_AAAA: return("AAAA"); /* ip v6 address */
+ case T_LOC: return("LOC"); /* geographical location */
+
+ case T_UINFO: return("UINFO"); /* user information */
+ case T_UID: return("UID"); /* user ident */
+ case T_GID: return("GID"); /* group ident */
+ case T_UNSPEC: return("UNSPEC"); /* unspecified binary data */
+
+ case T_AXFR: return("AXFR"); /* zone transfer */
+ case T_MAILB: return("MAILB"); /* matches MB/MR/MG/MINFO */
+ case T_MAILA: return("MAILA"); /* matches MD/MF */
+ case T_ANY: return("ANY"); /* matches any type */
+
+ case T_NONE: return("resource"); /* not yet determined */
+ }
+
+ (void) sprintf(buf, "%d", type);
+ return(buf);
+}
+
+ /*
+** PR_CLASS -- Return name of resource record class
+** ------------------------------------------------
+**
+** Returns:
+** Pointer to name of resource record class.
+*/
+
+char *
+pr_class(class)
+input int class; /* resource record class */
+{
+ static char buf[30];
+
+ switch (class)
+ {
+ case C_IN: return("IN"); /* internet */
+ case C_CSNET: return("CS"); /* csnet */
+ case C_CHAOS: return("CH"); /* chaosnet */
+ case C_HS: return("HS"); /* hesiod */
+ case C_ANY: return("ANY"); /* any class */
+ }
+
+ (void) sprintf(buf, "%d", class);
+ return(buf);
+}
+
+ /*
+** EXPAND_NAME -- Expand compressed domain name in a recource record
+** -----------------------------------------------------------------
+**
+** Returns:
+** Number of bytes advanced in answer buffer.
+** -1 if there was a format error.
+**
+** It is assumed that the specified buffer is of sufficient size.
+*/
+
+int
+expand_name(name, type, cp, msg, eom, namebuf)
+input char *name; /* name of resource record */
+input int type; /* type of resource record */
+input u_char *cp; /* current position in answer buf */
+input u_char *msg, *eom; /* begin and end of answer buf */
+output char *namebuf; /* location of buf to expand name in */
+{
+ register int n;
+
+ n = dn_expand(msg, eom, cp, (nbuf_t *)namebuf, MAXDNAME);
+ if (n < 0)
+ {
+ pr_error("expand error in %s record for %s, offset %s",
+ pr_type(type), name, itoa(cp - msg));
+ h_errno = NO_RECOVERY;
+ return(-1);
+ }
+
+ /* change root to single dot */
+ if (namebuf[0] == '\0')
+ {
+ namebuf[0] = '.';
+ namebuf[1] = '\0';
+ }
+
+ return(n);
+}
+
+ /*
+** CHECK_SIZE -- Check whether resource record is of sufficient length
+** -------------------------------------------------------------------
+**
+** Returns:
+** Requested size if current record is long enough.
+** -1 if current record does not have this many bytes.
+**
+** Note that HINFO records are very often incomplete since only
+** one of the two data fields has been filled in and the second
+** field is missing. So we generate only a warning message.
+*/
+
+int
+check_size(name, type, cp, msg, eor, size)
+input char *name; /* name of resource record */
+input int type; /* type of resource record */
+input u_char *cp; /* current position in answer buf */
+input u_char *msg; /* begin of answer buf */
+input u_char *eor; /* predicted position of next record */
+input int size; /* required record size remaining */
+{
+ if (cp + size > eor)
+ {
+ if (type != T_HINFO)
+ pr_error("incomplete %s record for %s, offset %s",
+ pr_type(type), name, itoa(cp - msg));
+ else
+ pr_warning("incomplete %s record for %s",
+ pr_type(type), name);
+ h_errno = NO_RECOVERY;
+ return(-1);
+ }
+
+ return(size);
+}
+
+ /*
+** VALID_NAME -- Check whether domain name contains invalid characters
+** -------------------------------------------------------------------
+**
+** Returns:
+** TRUE if the name is valid.
+** FALSE otherwise.
+**
+** The total size of a compound name should not exceed MAXDNAME.
+** We assume that this is true. Its individual components between
+** dots should not be longer than 64. This is not checked here.
+**
+** Only alphanumeric characters and dash '-' may be used (dash
+** only in the middle). We only check the individual characters.
+** Strictly speaking, this restriction is only for ``host names''.
+** The underscore is illegal, at least not recommended, but is
+** so abundant that is requires special processing.
+**
+** If the domain name represents a mailbox specification, the
+** first label up to the first (unquoted) dot is the local part
+** of a mail address, which should adhere to the RFC 822 specs.
+** This first dot takes the place of the RFC 822 '@' sign.
+**
+** The label '*' can in principle be used anywhere to indicate
+** wildcarding. It is valid only in the LHS resource record name,
+** in definitions in zone files only as the first component.
+** Used primarily in wildcard MX record definitions.
+*/
+
+char *specials = ".()<>@,;:\\\"[]"; /* RFC 822 specials */
+
+bool
+valid_name(name, wildcard, localpart, underscore)
+input char *name; /* domain name to check */
+input bool wildcard; /* set if wildcard is allowed */
+input bool localpart; /* set if this is a mailbox spec */
+input bool underscore; /* set if underscores are allowed */
+{
+ bool backslash = FALSE;
+ bool quoting = FALSE;
+ register char *p;
+ register char c;
+
+ for (p = name; (c = *p) != '\0'; p++)
+ {
+ /* special check for local part in mailbox */
+ if (localpart)
+ {
+ if (backslash)
+ backslash = FALSE; /* escape this char */
+ else if (c == '\\')
+ backslash = TRUE; /* escape next char */
+ else if (c == '"')
+ quoting = !quoting; /* start/stop quoting */
+ else if (quoting)
+ continue; /* allow quoted chars */
+ else if (c == '.')
+ localpart = FALSE; /* instead of '@' */
+ else if (c == '@')
+ return(FALSE); /* should be '.' */
+ else if (in_string(specials, c))
+ return(FALSE); /* must be escaped */
+ else if (is_space(c))
+ return(FALSE); /* must be escaped */
+ continue;
+ }
+
+ /* basic character set */
+ if (is_alnum(c) || (c == '-'))
+ continue;
+
+ /* start of a new component */
+ if (c == '.')
+ continue;
+
+ /* allow '*' for use in wildcard names */
+ if ((c == '*') && wildcard)
+ continue;
+
+ /* ignore underscore in certain circumstances */
+ if ((c == '_') && underscore && !illegal)
+ continue;
+
+ /* silently allowed widespread exceptions */
+ if (illegal && in_string(illegal, c))
+ continue;
+
+ return(FALSE);
+ }
+
+ /* must be beyond the local part in a mailbox */
+ if (localpart)
+ return(FALSE);
+
+ return(TRUE);
+}
+
+ /*
+** CANONICAL -- Check whether domain name is a canonical host name
+** ---------------------------------------------------------------
+**
+** Returns:
+** Nonzero if the name is definitely not canonical.
+** 0 if it is canonical, or if it remains undecided.
+*/
+
+int
+canonical(name)
+input char *name; /* the domain name to check */
+{
+ struct hostent *hp;
+ int status;
+ int save_errno;
+ int save_herrno;
+
+/*
+ * Preserve state when querying, to avoid clobbering current values.
+ */
+ save_errno = errno;
+ save_herrno = h_errno;
+
+ hp = gethostbyname(name);
+ status = h_errno;
+
+ errno = save_errno;
+ h_errno = save_herrno;
+
+/*
+ * Indicate negative result only after definitive lookup failures.
+ */
+ if (hp == NULL)
+ {
+ /* authoritative denial -- not existing or no A record */
+ if (status == NO_DATA || status == HOST_NOT_FOUND)
+ return(status);
+
+ /* nameserver failure -- still undecided, assume ok */
+ return(0);
+ }
+
+/*
+ * The given name exists and there is an associated A record.
+ * The name of this A record should be the name we queried about.
+ * If this is not the case we probably supplied a CNAME.
+ */
+ status = sameword(hp->h_name, name) ? 0 : HOST_NOT_CANON;
+ return(status);
+}
+
+ /*
+** MAPREVERSE -- Check whether address maps back to given domain
+** -------------------------------------------------------------
+**
+** Returns:
+** NULL if address could definitively not be mapped.
+** Given name if the address maps back properly, or
+** in case of transient nameserver failures.
+** Reverse name if it differs from the given name.
+*/
+
+char *
+mapreverse(name, inaddr)
+input char *name; /* domain name of A record */
+input struct in_addr inaddr; /* address of A record to check */
+{
+ struct hostent *hp;
+ int status;
+ int save_errno;
+ int save_herrno;
+
+/*
+ * Preserve state when querying, to avoid clobbering current values.
+ */
+ save_errno = errno;
+ save_herrno = h_errno;
+
+ hp = gethostbyaddr((char *)&inaddr, INADDRSZ, AF_INET);
+ status = h_errno;
+
+ errno = save_errno;
+ h_errno = save_herrno;
+
+/*
+ * Indicate negative result only after definitive lookup failures.
+ */
+ if (hp == NULL)
+ {
+ /* authoritative denial -- not existing or no PTR record */
+ if (status == NO_DATA || status == HOST_NOT_FOUND)
+ return(NULL);
+
+ /* nameserver failure -- still undecided, assume ok */
+ return(name);
+ }
+
+/*
+ * Indicate whether the reverse mapping yields the given name.
+ */
+ return(sameword(hp->h_name, name) ? name : hp->h_name);
+}
+
+ /*
+** COMPARE_NAME -- Compare two names wrt alphabetical order
+** --------------------------------------------------------
+**
+** Returns:
+** Value of case-insensitive comparison.
+*/
+
+int
+compare_name(a, b)
+input char **a; /* first name */
+input char **b; /* second name */
+{
+ return(strcasecmp(*a, *b));
+}
+
+ /*
+** XALLOC -- Allocate or reallocate additional memory
+** --------------------------------------------------
+**
+** Returns:
+** Pointer to (re)allocated buffer space.
+** Aborts if the requested memory could not be obtained.
+*/
+
+ptr_t *
+xalloc(buf, size)
+register ptr_t *buf; /* current start of buffer space */
+input siz_t size; /* number of bytes to allocate */
+{
+ if (buf == NULL)
+ buf = malloc(size);
+ else
+ buf = realloc(buf, size);
+
+ if (buf == NULL)
+ {
+ errmsg("Out of memory");
+ exit(EX_OSERR);
+ }
+
+ return(buf);
+}
+
+ /*
+** ITOA -- Convert integer value to ascii string
+** ---------------------------------------------
+**
+** Returns:
+** Pointer to string.
+*/
+
+char *
+itoa(n)
+input int n; /* value to convert */
+{
+ static char buf[30];
+
+ (void) sprintf(buf, "%d", n);
+ return(buf);
+}
+
+
+/*
+** UTOA -- Convert unsigned integer value to ascii string
+** ------------------------------------------------------
+**
+** Returns:
+** Pointer to string.
+*/
+
+char *
+utoa(n)
+input int n; /* value to convert */
+{
+ static char buf[30];
+
+ (void) sprintf(buf, "%u", (unsigned)n);
+ return(buf);
+}
+
+ /*
+** STOA -- Extract partial ascii string
+** ------------------------------------
+**
+** Returns:
+** Pointer to string.
+*/
+
+char *
+stoa(cp, size)
+input u_char *cp; /* current position in answer buf */
+input int size; /* number of bytes to extract */
+{
+ static char buf[MAXDLEN+1];
+
+ if (size > MAXDLEN)
+ size = MAXDLEN;
+
+#ifdef obsolete
+ if (size > 0)
+ (void) sprintf(buf, "%.*s", size, (char *)cp);
+ else
+ (void) sprintf(buf, "%s", "");
+#endif
+ bcopy((char *)cp, buf, size);
+ buf[size] = '\0';
+ return(buf);
+}
+
+ /*
+** NSAP_NTOA -- Convert binary nsap address to ascii
+** -------------------------------------------------
+**
+** Returns:
+** Pointer to string.
+**
+** As per RFC 1637 an nsap address is encoded in binary form
+** in the resource record. It was unclear from RFC 1348 how
+** the encoding should be. RFC 1629 defines an upper bound
+** of 20 bytes to the size of a binary nsap address.
+*/
+
+char *
+nsap_ntoa(cp, size)
+input u_char *cp; /* current position in answer buf */
+input int size; /* number of bytes to extract */
+{
+ static char buf[3*MAXNSAP+1];
+ register char *p;
+ register int n;
+ register int i;
+
+ if (size > MAXNSAP)
+ size = MAXNSAP;
+
+ for (p = buf, i = 0; i < size; i++, cp++)
+ {
+ n = ((int)(*cp) >> 4) & 0x0f;
+ *p++ = hexdigit(n);
+ n = ((int)(*cp) >> 0) & 0x0f;
+ *p++ = hexdigit(n);
+
+ /* add dots for readability */
+ if ((i % 2) == 0 && (i + 1) < size)
+ *p++ = '.';
+ }
+ *p = '\0';
+
+ return(buf);
+}
+
+ /*
+** PR_TIME -- Produce printable version of a time interval
+** -------------------------------------------------------
+**
+** Returns:
+** Pointer to a string version of interval.
+**
+** The value is a time interval expressed in seconds.
+*/
+
+char *
+pr_time(value, brief)
+input int value; /* the interval to be converted */
+input bool brief; /* use brief format if set */
+{
+ static char buf[256];
+ register char *p = buf;
+ int week, days, hour, mins, secs;
+
+ /* special cases */
+ if (value < 0)
+ return("negative");
+ if ((value == 0) && !brief)
+ return("zero seconds");
+
+/*
+ * Decode the components.
+ */
+ secs = value % 60; value /= 60;
+ mins = value % 60; value /= 60;
+ hour = value % 24; value /= 24;
+ days = value;
+
+ if (!brief)
+ {
+ days = value % 7; value /= 7;
+ week = value;
+ }
+
+/*
+ * Now turn it into a sexy form.
+ */
+ if (brief)
+ {
+ if (days > 0)
+ {
+ (void) sprintf(p, "%d+", days);
+ p += strlength(p);
+ }
+
+ (void) sprintf(p, "%02d:%02d:%02d", hour, mins, secs);
+ return(buf);
+ }
+
+ if (week > 0)
+ {
+ (void) sprintf(p, ", %d week%s", week, plural(week));
+ p += strlength(p);
+ }
+
+ if (days > 0)
+ {
+ (void) sprintf(p, ", %d day%s", days, plural(days));
+ p += strlength(p);
+ }
+
+ if (hour > 0)
+ {
+ (void) sprintf(p, ", %d hour%s", hour, plural(hour));
+ p += strlength(p);
+ }
+
+ if (mins > 0)
+ {
+ (void) sprintf(p, ", %d minute%s", mins, plural(mins));
+ p += strlength(p);
+ }
+
+ if (secs > 0)
+ {
+ (void) sprintf(p, ", %d second%s", secs, plural(secs));
+ /* p += strlength(p); */
+ }
+
+ return(buf + 2);
+}
+
+ /*
+** PR_SPHERICAL -- Produce printable version of a spherical location
+** -----------------------------------------------------------------
+**
+** Returns:
+** Pointer to a string version of location.
+**
+** The value is a spherical location (latitude or longitude)
+** expressed in thousandths of a second of arc.
+** The value 2^31 represents zero (equator or prime meridian).
+*/
+
+char *
+pr_spherical(value, pos, neg)
+input int value; /* the location to be converted */
+input char *pos; /* suffix if value positive */
+input char *neg; /* suffix if value negative */
+{
+ static char buf[256];
+ register char *p = buf;
+ char *direction;
+ int degrees, minutes, seconds, fracsec;
+
+/*
+ * Normalize.
+ */
+ value -= (1 << 31);
+
+ direction = pos;
+ if (value < 0)
+ {
+ direction = neg;
+ value = -value;
+ }
+
+/*
+ * Decode the components.
+ */
+ fracsec = value % 1000; value /= 1000;
+ seconds = value % 60; value /= 60;
+ minutes = value % 60; value /= 60;
+ degrees = value;
+
+/*
+ * Construct output string.
+ */
+ (void) sprintf(p, "%d", degrees);
+ p += strlength(p);
+
+ if (minutes > 0 || seconds > 0 || fracsec > 0)
+ {
+ (void) sprintf(p, " %02d", minutes);
+ p += strlength(p);
+ }
+
+ if (seconds > 0 || fracsec > 0)
+ {
+ (void) sprintf(p, " %02d", seconds);
+ p += strlength(p);
+ }
+
+ if (fracsec > 0)
+ {
+ (void) sprintf(p, ".%03d", fracsec);
+ p += strlength(p);
+ }
+
+ (void) sprintf(p, " %s", direction);
+
+#ifdef obsolete
+ (void) sprintf(buf, "%d %02d %02d.%03d %s",
+ degrees, minutes, seconds, fracsec, direction);
+#endif
+ return(buf);
+}
+
+ /*
+** PR_VERTICAL -- Produce printable version of a vertical location
+** ---------------------------------------------------------------
+**
+** Returns:
+** Pointer to a string version of location.
+**
+** The value is an altitude expressed in centimeters, starting
+** from a base 100000 meters below the GPS reference spheroid.
+** This allows for the actual range [-10000000 .. 4293967296].
+*/
+
+char *
+pr_vertical(value, pos, neg)
+input int value; /* the location to be converted */
+input char *pos; /* prefix if value positive */
+input char *neg; /* prefix if value negative */
+{
+ static char buf[256];
+ register char *p = buf;
+ char *direction;
+ int meters, centimeters;
+ unsigned int altitude;
+ unsigned int reference;
+
+/*
+ * Normalize.
+ */
+ altitude = value;
+ reference = 100000*100;
+
+ if (altitude < reference)
+ {
+ direction = neg;
+ altitude = reference - altitude;
+ }
+ else
+ {
+ direction = pos;
+ altitude = altitude - reference;
+ }
+
+/*
+ * Decode the components.
+ */
+ centimeters = altitude % 100; altitude /= 100;
+ meters = altitude;
+
+/*
+ * Construct output string.
+ */
+ (void) sprintf(p, "%s%d", direction, meters);
+ p += strlength(p);
+
+ if (centimeters > 0)
+ (void) sprintf(p, ".%02d", centimeters);
+
+#ifdef obsolete
+ (void) sprintf(buf, "%s%d.%02d", direction, meters, centimeters);
+#endif
+ return(buf);
+}
+
+ /*
+** PR_PRECISION -- Produce printable version of a location precision
+** -----------------------------------------------------------------
+**
+** Returns:
+** Pointer to a string version of precision.
+**
+** The value is a precision expressed in centimeters, encoded
+** as 4-bit mantissa and 4-bit power of 10 (each ranging 0-9).
+*/
+
+unsigned int poweroften[10] =
+{1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
+
+char *
+pr_precision(value)
+input int value; /* the precision to be converted */
+{
+ static char buf[256];
+ register char *p = buf;
+ int meters, centimeters;
+ unsigned int precision;
+ register int mantissa;
+ register int exponent;
+
+/*
+ * Normalize.
+ */
+ mantissa = ((value >> 4) & 0x0f) % 10;
+ exponent = ((value >> 0) & 0x0f) % 10;
+ precision = mantissa * poweroften[exponent];
+
+/*
+ * Decode the components.
+ */
+ centimeters = precision % 100; precision /= 100;
+ meters = precision;
+
+/*
+ * Construct output string.
+ */
+ (void) sprintf(p, "%d", meters);
+ p += strlength(p);
+
+ if (centimeters > 0)
+ (void) sprintf(p, ".%02d", centimeters);
+
+#ifdef obsolete
+ (void) sprintf(buf, "%d.%02d", meters, centimeters);
+#endif
+ return(buf);
+}
diff --git a/usr.sbin/named/host/mxlookup b/usr.sbin/named/host/mxlookup
new file mode 100644
index 00000000000..bbb5863d1ee
--- /dev/null
+++ b/usr.sbin/named/host/mxlookup
@@ -0,0 +1,163 @@
+#!/bin/sh -
+#
+# @(#)mxlookup e07@nikhef.nl (Eric Wassenaar) 950108
+#
+# Author: E.Wassenaar, Nikhef-H
+# Version: 09-OCT-1994
+# Revision: 08-JAN-1995, Make sure servers come from NS records
+#
+# This utility looks up the MX and A records for a given domain name
+# at each of the authoritative servers for the zone it belongs to.
+# The printout shows whether or not the servers have the same notion.
+# Too often mail is bounced with a "No address or MX record" message
+# whereas the mail address is perfectly valid. Usually this happens
+# when one of the servers turns out to be misconfigured and the data
+# was retrieved unfortunately from just that server.
+#
+# With the -t option you can verify resource records of another type
+# at each of the servers. The -v option shows the SOA record and the
+# NS records of the zone to which the given domain name belongs.
+# The -r option disables nameserver recursion at the contacted servers.
+
+exec=echo
+exec=
+
+# ----------------------------------------------------------------------
+# Setup environment.
+# ----------------------------------------------------------------------
+
+# This is where the ``host'' executable lives.
+BINDIR=/usr/local/bin
+
+PATH=${BINDIR}:/bin:/usr/bin:/usr/ucb ; export PATH
+
+cmd=`basename $0`
+
+options="[-v] [-r] [-t type]"
+usage="Usage: $cmd $options name"
+
+# ----------------------------------------------------------------------
+# Exit codes from <sysexits.h>
+# ----------------------------------------------------------------------
+
+EX_OK=0
+EX_USAGE=64
+EX_UNAVAILABLE=69
+
+# ----------------------------------------------------------------------
+# Process options.
+# ----------------------------------------------------------------------
+
+type=""
+recurse=
+verbose=
+
+skip=
+for i
+do
+ if [ $skip ]
+ then
+ skip=
+ continue
+ fi
+
+ case "$i" in
+ -t)
+ case "$2" in
+ ""|-*) echo "$usage" 1>&2 ; exit $EX_USAGE
+ esac
+
+ type="$2"
+ skip=true
+ shift
+ ;;
+ -r)
+ recurse="-r"
+ ;;
+ -d)
+ exec=echo
+ ;;
+ -v)
+ verbose=true
+ ;;
+ -*)
+ echo "$cmd: Unknown option $i" 1>&2 ; exit $EX_USAGE
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+done
+
+# ----------------------------------------------------------------------
+# Process arguments.
+# ----------------------------------------------------------------------
+
+name="$1"
+
+if [ "X$name" = "X" ]
+then
+ echo "$usage" 1>&2 ; exit $EX_USAGE
+fi
+
+# Remove trailing dots.
+name=`echo $name | sed 's/\.*$//'`
+
+# ----------------------------------------------------------------------
+# Main loop.
+# ----------------------------------------------------------------------
+
+domain="$name"
+
+while [ "X$domain" != "X" ]
+do
+ # Make sure there is at least one dot.
+ parentdomain=`echo $domain | sed 's/^[^.]*\.//'`
+
+ if [ "X$parentdomain" = "X$domain" ]
+ then
+ domain=""
+ continue
+ fi
+
+ # Find the servers for this domain.
+ servers=`host -t NS "$domain" | awk '$2 == "NS" {print $3}'`
+
+ if [ "X$servers" = "X" ]
+ then
+ # Move to parent domain and retry.
+ domain="$parentdomain"
+ continue
+ fi
+
+ if [ "X$domain" != "X$name" ]
+ then
+ echo
+ fi
+
+ if [ $verbose ]
+ then
+ echo "--- $domain ---"
+ $exec host -T -t SOA "$domain"
+ $exec host -T -t NS "$domain"
+ echo
+ fi
+
+ for server in $servers
+ do
+ echo "--- $server ---"
+ if [ "X$type" = "X" ]
+ then
+ $exec host $recurse -T -t MX "$name" "$server"
+ $exec host $recurse -T -t A "$name" "$server"
+ else
+ $exec host $recurse -T -t "$type" "$name" "$server"
+ fi
+ echo
+ done
+
+ exit $EX_OK
+done
+
+exit $EX_UNAVAILABLE
diff --git a/usr.sbin/named/host/nslookup b/usr.sbin/named/host/nslookup
new file mode 100644
index 00000000000..71601f7057c
--- /dev/null
+++ b/usr.sbin/named/host/nslookup
@@ -0,0 +1,280 @@
+#!/bin/sh -
+#
+# @(#)nslookup e07@nikhef.nl (Eric Wassenaar) 940919
+#
+# Author: E.Wassenaar, Nikhef-H
+# Version: 19-SEP-1994
+# Revision:
+#
+# This utility emulates nslookup as a wrapper to host.
+# It performs most, but not all, functions.
+
+exec=echo
+exec=
+
+# ----------------------------------------------------------------------
+# Setup environment.
+# ----------------------------------------------------------------------
+
+# This is where the ``host'' executable lives.
+BINDIR=/usr/local/bin
+
+PATH=${BINDIR}:/bin:/usr/bin:/usr/ucb ; export PATH
+
+cmd=`basename $0`
+
+options="[-l]"
+usage="Usage: $cmd $options [server]"
+
+# ----------------------------------------------------------------------
+# Exit codes from <sysexits.h>
+# ----------------------------------------------------------------------
+
+EX_OK=0
+EX_USAGE=64
+EX_UNAVAILABLE=69
+
+# ----------------------------------------------------------------------
+# Setup defaults.
+# ----------------------------------------------------------------------
+
+name=""
+zone=""
+
+type=""
+class=""
+
+server=""
+
+debug=""
+verbose=""
+norecurse=""
+vc=""
+
+# ----------------------------------------------------------------------
+# Process arguments.
+# ----------------------------------------------------------------------
+
+for i
+do
+ if [ "X$server" != "X" ]
+ then
+ echo "$usage" 1>&2 ; exit $EX_USAGE
+ fi
+
+ case "$i" in
+ -d) exec=echo ;;
+ -l) server=`hostname` ;;
+ -*) echo "$cmd: Unknown option $i" 1>&2 ; exit $EX_USAGE ;;
+ *) server="$i" ;;
+ esac
+done
+
+# ----------------------------------------------------------------------
+# Choose between BSD or SYSV echo command.
+# ----------------------------------------------------------------------
+
+n=`echo -n`
+if [ "$n" = "-n" ]
+then
+ c='\c' ; n=''
+else
+ n='-n' ; c=''
+fi
+
+# ----------------------------------------------------------------------
+# Main loop.
+# ----------------------------------------------------------------------
+
+trap continue 2
+
+while echo $n "> $c" ; read line
+do
+ case "$line" in
+ "") continue ;;
+ *\**) continue ;;
+ *\!*) continue ;;
+ *\?*) line="help" ;;
+ esac
+
+ set - $line
+ command="$1"
+ case "$command" in
+
+ help)
+ cat <<!
+ exit | quit - exit from the program
+ help | ? - print this help message
+ set | set all - show all current settings
+ set [no]debug - increase debug output level
+ set [no]verbose - increase verbose output level
+ set [no]recurse - request recursive nameserver queries
+ set [no]vc - use virtual circuit for queries
+ set type=TYPE - query about the given resource record TYPE
+ set class=CLASS - query about the given resource record CLASS
+ server SERVER - contact the explicit server with name SERVER
+ server - show the name of the current explicit SERVER
+ NAME - query for NAME using all current settings
+ NAME SERVER - query for NAME at the given SERVER
+ ls ZONE - generate listing of the given name ZONE
+ ls - generate listing of the last given ZONE
+ ls ZONE [>]FILE - copy resource record output also to FILE
+!
+ ;;
+
+ exit|quit)
+ break
+ ;;
+
+ set)
+ option="$2"
+ case "$option" in
+
+ ""|all)
+ echo "name=$name"
+ echo "zone=$zone"
+ echo "server=$server"
+ echo "set type=$type"
+ echo "set class=$class"
+ echo "set debug=$debug"
+ echo "set verbose=$verbose"
+ echo "set norecurse=$norecurse"
+ echo "set vc=$vc"
+ ;;
+
+ debug|debu|deb|de|d)
+ debug="-d $debug"
+ ;;
+
+ nodebug|nodebu|nodeb|node|nod)
+ debug=""
+ ;;
+
+ d2)
+ debug="-d -d"
+ verbose="-v -v"
+ ;;
+
+ nod2)
+ debug=""
+ verbose=""
+ ;;
+
+ verbose|verbos|verbo|verb|ver|ve|v)
+ verbose="-v $verbose"
+ ;;
+
+ noverbose|noverbos|noverbo|noverb|nover|nove|nov)
+ verbose=""
+ ;;
+
+ recurse|recurs|recur|recu|rec|re|r)
+ norecurse=""
+ ;;
+
+ norecurse|norecurs|norecur|norecu|norec|nore|nor)
+ norecurse="-r"
+ ;;
+
+ vc)
+ vc="-u"
+ ;;
+
+ novc)
+ vc=""
+ ;;
+
+ querytype=*|querytyp=*|queryty=*|queryt=*|\
+ query=*|quer=*|que=*|qu=*|q=*|\
+ type=*|typ=*|ty=*|t=*)
+ type=`echo $option | sed 's/.*=//'`
+ if [ "X$type" != "X" ]
+ then
+ type="-t $type"
+ fi
+ ;;
+
+ querytype|querytyp|queryty|queryt|\
+ query|quer|que|qu|q|\
+ type|typ|ty|t)
+ type=""
+ ;;
+
+ class=*|clas=*|cla=*|cl=*|c=*)
+ class=`echo $option | sed 's/.*=//'`
+ if [ "X$class" != "X" ]
+ then
+ class="-c $class"
+ fi
+ ;;
+
+ class*|clas*|cla*|cl*|c*)
+ class=""
+ ;;
+
+ *)
+ echo "Unknown option $option"
+ ;;
+
+ esac
+ ;;
+
+ server)
+ nserver="$2"
+ if [ "X$nserver" = "X" ]
+ then
+ if [ "X$server" = "X" ]
+ then
+ echo "No server defined"
+ else
+ echo "server=$server"
+ fi
+ else
+ server="$nserver"
+ fi
+ ;;
+
+ ls)
+ nzone="$2"
+ if [ "X$nzone" = "X" ]
+ then
+ if [ "X$zone" = "X" ]
+ then
+ echo "No zone defined"
+ continue
+ fi
+ else
+ zone="$nzone"
+ fi
+
+ file=`echo "$3$4" | sed 's/>*//'`
+ if [ "X$file" != "X" ]
+ then
+ file="-f $file"
+ fi
+
+ options="$debug $verbose $norecurse $vc $file"
+ $exec host $options $type $class -l $zone $nserver
+ ;;
+
+ [a-zA-Z0-9]*)
+ name="$1"
+
+ nserver="$2"
+ if [ "X$nserver" = "X" ]
+ then
+ nserver="$server"
+ fi
+
+ options="$debug $verbose $norecurse $vc"
+ $exec host $options $type $class $name $nserver
+ ;;
+
+ *)
+ echo "Unknown command $command"
+ ;;
+
+ esac
+done
+
+exit $EX_OK
diff --git a/usr.sbin/named/host/port.h b/usr.sbin/named/host/port.h
new file mode 100644
index 00000000000..3e0ec14f6fe
--- /dev/null
+++ b/usr.sbin/named/host/port.h
@@ -0,0 +1,136 @@
+/*
+** Various portability definitions.
+**
+** @(#)port.h e07@nikhef.nl (Eric Wassenaar) 950925
+*/
+
+#if defined(SYSV) || defined(SVR4)
+#define SYSV_MEMSET
+#define SYSV_STRCHR
+#define SYSV_SETVBUF
+#endif
+
+#if defined(__hpux) || defined(hpux)
+#define SYSV_SETVBUF
+#endif
+
+#if defined(RES_PRF_STATS)
+#define BIND_49
+#else
+#define BIND_48
+#endif
+
+#if defined(BIND_49)
+#if defined(__BIND)
+#define BIND_493
+#endif
+#endif
+
+/*
+** Define constants for fixed sizes.
+*/
+
+#ifndef INT16SZ
+#define INT16SZ 2 /* for systems without 16-bit ints */
+#endif
+
+#ifndef INT32SZ
+#define INT32SZ 4 /* for systems without 32-bit ints */
+#endif
+
+#ifndef INADDRSZ
+#define INADDRSZ 4 /* for sizeof(struct inaddr) != 4 */
+#endif
+
+/*
+** The following should depend on existing definitions.
+*/
+
+#if defined(BIND_49)
+typedef struct __res_state res_state_t;
+#else
+typedef struct state res_state_t;
+#endif
+
+#if defined(BIND_48)
+typedef struct rrec rrec_t;
+#else
+#if defined(BIND_493)
+typedef u_char rrec_t;
+#else
+typedef char rrec_t;
+#endif
+#endif
+
+#if defined(BIND_493)
+typedef u_char qbuf_t;
+#else
+typedef char qbuf_t;
+#endif
+
+#if defined(BIND_493)
+typedef char nbuf_t;
+#else
+typedef u_char nbuf_t;
+#endif
+
+#if defined(__alpha) || defined(BIND_49)
+typedef u_int ipaddr_t;
+#else
+typedef u_long ipaddr_t;
+#endif
+
+#if defined(apollo) || defined(_BSD_SIGNALS)
+typedef int sigtype_t;
+#else
+typedef void sigtype_t;
+#endif
+
+/* too primitive */
+typedef char ptr_t; /* generic pointer type */
+typedef u_int siz_t; /* general size type */
+
+#ifdef SYSV_MEMSET
+#define bzero(a,n) (void) memset(a,'\0',n)
+#define bcopy(a,b,n) (void) memcpy(b,a,n)
+#endif
+
+#ifdef SYSV_STRCHR
+#define index strchr
+#define rindex strrchr
+#endif
+
+#ifdef SYSV_SETVBUF
+#define linebufmode(a) (void) setvbuf(a, (char *)NULL, _IOLBF, BUFSIZ);
+#else
+#define linebufmode(a) (void) setlinebuf(a);
+#endif
+
+#ifdef ULTRIX_RESOLV
+#define nslist(i) _res.ns_list[i].addr
+#else
+#define nslist(i) _res.nsaddr_list[i]
+#endif
+
+#ifdef fp_nquery
+#define pr_query(a,n,f) fp_nquery(a,n,f)
+#else
+#define pr_query(a,n,f) fp_query(a,f)
+#endif
+
+#if defined(sun) && defined(NO_YP_LOOKUP)
+#define gethostbyname (struct hostent *)res_gethostbyname
+#define gethostbyaddr (struct hostent *)res_gethostbyaddr
+#endif
+
+/*
+** No prototypes yet.
+*/
+
+#define PROTO(TYPES) ()
+
+#if defined(__STDC__) && defined(BIND_49)
+#define CONST const
+#else
+#define CONST
+#endif
diff --git a/usr.sbin/named/host/rrec.h b/usr.sbin/named/host/rrec.h
new file mode 100644
index 00000000000..305f8af3ebd
--- /dev/null
+++ b/usr.sbin/named/host/rrec.h
@@ -0,0 +1,245 @@
+/*
+** Resource record structures.
+**
+** These define the various resource record fields after decoding
+** from the internal representation in the nameserver answer buffer.
+**
+** @(#)rrec.h e07@nikhef.nl (Eric Wassenaar) 941205
+*/
+
+#define MAXSTRING 255 /* maximum size of single encoded string */
+#define MAXSTRLEN MAXDLEN /* maximum size of total encoded string */
+
+typedef struct rr_data {
+ u_char databuf[MAXDLEN]; /* generic data buffer */
+} rr_data_t;
+
+/*
+** Record-specific data fields.
+*/
+ /* traditional records */
+
+typedef struct a_data {
+ ipaddr_t address; /* internet address of host */
+} a_data_t;
+
+typedef struct ns_data {
+ char nameserver[MAXDNAME+1]; /* name of domain nameserver */
+} ns_data_t;
+
+typedef struct md_data {
+ char destination[MAXDNAME+1]; /* name of mail destination */
+} md_data_t;
+
+typedef struct mf_data {
+ char forwarder[MAXDNAME+1]; /* name of mail forwarder */
+} mf_data_t;
+
+typedef struct cname_data {
+ char canonical[MAXDNAME+1]; /* canonical domain name */
+} cname_data_t;
+
+typedef struct soa_data {
+ char primary[MAXDNAME+1]; /* name of primary nameserver */
+ char hostmaster[MAXDNAME+1]; /* name of hostmaster mailbox */
+ int serial; /* serial (version) number */
+ int refresh; /* refresh time in seconds */
+ int retry; /* refresh retry time in seconds */
+ int expire; /* expiration time in seconds */
+ int defttl; /* default time_to_live */
+} soa_data_t;
+
+typedef struct mb_data {
+ char mailhost[MAXDNAME+1]; /* name of mailbox host */
+} mb_data_t;
+
+typedef struct mg_data {
+ char memberbox[MAXDNAME+1]; /* mailbox of mail group member */
+} mg_data_t;
+
+typedef struct mr_data {
+ char aliasbox[MAXDNAME+1]; /* mailbox of mail alias */
+} mr_data_t;
+
+typedef struct null_data {
+ u_char nullbuf[MAXDLEN]; /* generic data buffer */
+} null_data_t;
+
+typedef struct wks_data {
+ ipaddr_t servaddress; /* internet address of host */
+ int protocol; /* protocol number */
+ u_char services[32]; /* ports 0-255 */
+} wks_data_t;
+
+typedef struct ptr_data {
+ char domain[MAXDNAME+1]; /* domain name of pointer */
+} ptr_data_t;
+
+typedef struct hinfo_data {
+ char cputype[MAXSTRING+1]; /* machine description */
+ char ostype[MAXSTRING+1]; /* operating system type */
+} hinfo_data_t;
+
+typedef struct minfo_data {
+ char ownerbox[MAXDNAME+1]; /* name of owner mailbox */
+ char errorbox[MAXDNAME+1]; /* name of error mailbox */
+} minfo_data_t;
+
+typedef struct mx_data {
+ int preference; /* preference value */
+ char mxhost[MAXDNAME+1]; /* name of mx host */
+} mx_data_t;
+
+typedef struct txt_data {
+ char text[MAXSTRLEN+1]; /* concatenated substrings */
+} txt_data_t;
+
+ /* later additions */
+
+typedef struct rp_data {
+ char mailbox[MAXDNAME+1]; /* name of person mailbox */
+ char txtinfo[MAXDNAME+1]; /* name of description txt record */
+} rp_data_t;
+
+typedef struct afsdb_data {
+ int afstype; /* type of afs server */
+ char afshost[MAXDNAME+1]; /* name of afs server */
+} afsdb_data_t;
+
+typedef struct x25_data {
+ char psdnaddress[MAXSTRING+1]; /* x25 psdn address */
+} x25_data_t;
+
+typedef struct isdn_data {
+ char isdnaddress[MAXSTRING+1]; /* isdn address */
+ char isdnsubaddr[MAXSTRING+1]; /* isdn subaddress */
+} isdn_data_t;
+
+typedef struct rt_data {
+ int routepref; /* preference value */
+ char routehost[MAXDNAME+1]; /* name of route-through host */
+} rt_data_t;
+
+typedef struct nsap_data {
+ u_char nsapaddr[MAXNSAP]; /* binary nsap address */
+} nsap_data_t;
+
+typedef struct nsapptr_data {
+ char nsapdomain[MAXDNAME+1]; /* domain name of nsap pointer */
+} nsapptr_data_t;
+
+typedef struct px_data {
+ int mappref; /* preference value */
+ char map822[MAXDNAME+1]; /* rfc822 domain name */
+ char mapx400[MAXDNAME+1]; /* x400 domain name */
+} px_data_t;
+
+typedef struct gpos_data {
+ char longpos[MAXSTRING+1]; /* geographical longitude */
+ char latpos[MAXSTRING+1]; /* geographical latitude */
+ char altpos[MAXSTRING+1]; /* geographical altitude */
+} gpos_data_t;
+
+typedef struct loc_data {
+ int locversion; /* version number */
+ int objectsize; /* size of object */
+ int hprecision; /* horizontal precision */
+ int vprecision; /* vertical precision */
+ int longitude; /* geographical longitude */
+ int latitude; /* geographical latitude */
+ int altitude; /* geographical altitude */
+} loc_data_t;
+
+ /* nonstandard records */
+
+typedef struct uinfo_data {
+ char userinfo[MAXSTRLEN+1]; /* user description */
+} uinfo_data_t;
+
+typedef struct uid_data {
+ int userid; /* user uid */
+} uid_data_t;
+
+typedef struct gid_data {
+ int groupid; /* user gid */
+} gid_data_t;
+
+typedef struct unspec_data {
+ u_char unspecbuf[MAXDLEN]; /* generic data buffer */
+} unspec_data_t;
+
+/*
+** Generic resource record description.
+*/
+
+typedef struct rrecord {
+ char name[MAXDNAME+1]; /* resource record name */
+ int type; /* resource record type */
+ int class; /* resource record class */
+ int ttl; /* time_to_live value */
+ union {
+ rr_data_t data_rr;
+ a_data_t data_a;
+ ns_data_t data_ns;
+ md_data_t data_md;
+ mf_data_t data_mf;
+ cname_data_t data_cname;
+ soa_data_t data_soa;
+ mb_data_t data_mb;
+ mg_data_t data_mg;
+ mr_data_t data_mr;
+ null_data_t data_null;
+ wks_data_t data_wks;
+ ptr_data_t data_ptr;
+ hinfo_data_t data_hinfo;
+ minfo_data_t data_minfo;
+ mx_data_t data_mx;
+ txt_data_t data_txt;
+ rp_data_t data_rp;
+ afsdb_data_t data_afsdb;
+ x25_data_t data_x25;
+ isdn_data_t data_isdn;
+ rt_data_t data_rt;
+ nsap_data_t data_nsap;
+ nsapptr_data_t data_nsapptr;
+ px_data_t data_px;
+ gpos_data_t data_gpos;
+ loc_data_t data_loc;
+ uinfo_data_t data_uinfo;
+ uid_data_t data_uid;
+ gid_data_t data_gid;
+ unspec_data_t data_unspec;
+ } data;
+} rrecord_t;
+
+#define t_rr data.data_rr
+#define t_a data.data_a
+#define t_ns data.data_ns
+#define t_md data.data_md
+#define t_mf data.data_mf
+#define t_cname data.data_cname
+#define t_soa data.data_soa
+#define t_mb data.data_mb
+#define t_mg data.data_mg
+#define t_mr data.data_mr
+#define t_null data.data_null
+#define t_wks data.data_wks
+#define t_ptr data.data_ptr
+#define t_hinfo data.data_hinfo
+#define t_minfo data.data_minfo
+#define t_mx data.data_mx
+#define t_txt data.data_txt
+#define t_rp data.data_rp
+#define t_afsdb data.data_afsdb
+#define t_x25 data.data_x25
+#define t_isdn data.data_isdn
+#define t_rt data.data_rt
+#define t_nsap data.data_nsap
+#define t_nsapptr data.data_nsapptr
+#define t_px data.data_px
+#define t_gpos data.data_gpos
+#define t_loc data.data_loc
+#define t_uinfo data.data_uinfo
+#define t_uid data.data_uid
+#define t_gid data.data_gid
+#define t_unspec data.data_unspec
diff --git a/usr.sbin/named/host/send.c b/usr.sbin/named/host/send.c
new file mode 100644
index 00000000000..f8a76825dec
--- /dev/null
+++ b/usr.sbin/named/host/send.c
@@ -0,0 +1,760 @@
+/*
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement: ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char Version[] = "@(#)send.c e07@nikhef.nl (Eric Wassenaar) 951231";
+#endif
+
+#if defined(apollo) && defined(lint)
+#define __attribute(x)
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#include <sys/types.h> /* not always automatically included */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#undef NOERROR /* in <sys/streams.h> on solaris 2.x */
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "port.h" /* various portability definitions */
+#include "conf.h" /* various configuration definitions */
+
+#define input /* read-only input parameter */
+#define output /* modified output parameter */
+
+#define bitset(a,b) (((a) & (b)) != 0)
+#define setalarm(n) (void) alarm((unsigned int)n)
+
+extern int errno;
+extern res_state_t _res; /* defined in res_init.c */
+
+char *dbprefix = DBPREFIX; /* prefix for debug messages to stdout */
+
+static int timeout; /* connection read timeout */
+static struct sockaddr_in from; /* address of inbound packet */
+static struct sockaddr *from_sa = (struct sockaddr *)&from;
+
+/* extern */
+char *inet_ntoa PROTO((struct in_addr));
+
+/* send.c */
+#ifdef HOST_RES_SEND
+int res_send PROTO((CONST qbuf_t *, int, qbuf_t *, int));
+void _res_close PROTO((void));
+static int send_stream PROTO((struct sockaddr_in *, qbuf_t *, int, qbuf_t *, int));
+static int send_dgram PROTO((struct sockaddr_in *, qbuf_t *, int, qbuf_t *, int));
+#endif /*HOST_RES_SEND*/
+static sigtype_t timer PROTO((int));
+int _res_connect PROTO((int, struct sockaddr_in *, int));
+int _res_write PROTO((int, struct sockaddr_in *, char *, char *, int));
+int _res_read PROTO((int, struct sockaddr_in *, char *, char *, int));
+static int recv_sock PROTO((int, char *, int));
+void _res_perror PROTO((struct sockaddr_in *, char *, char *));
+
+#ifdef HOST_RES_SEND
+
+ /*
+** RES_SEND -- Send nameserver query and retrieve answer
+** -----------------------------------------------------
+**
+** Returns:
+** Length of nameserver answer buffer, if obtained.
+** -1 if an error occurred (errno set appropriately).
+**
+** This is a simplified version of the BIND 4.8.3 res_send().
+** - Always use connected datagrams to get proper error messages.
+** - Do not only return ETIMEDOUT or ECONNREFUSED in datagram mode,
+** but also host or network unreachable status if appropriate.
+** - Never leave a connection open after we got an answer.
+** - No special ECONNRESET handling when using virtual circuits.
+**
+** Note that this private version of res_send() is not only called
+** directly by 'host' but also indirectly by gethostbyname() or by
+** gethostbyaddr() via their resolver interface routines.
+*/
+
+int
+res_send(query, querylen, answer, anslen)
+input CONST qbuf_t *query; /* location of formatted query buffer */
+input int querylen; /* length of query buffer */
+output qbuf_t *answer; /* location of buffer to store answer */
+input int anslen; /* maximum size of answer buffer */
+{
+ HEADER *bp = (HEADER *)answer;
+ struct sockaddr_in *addr; /* the server address to connect to */
+ int v_circuit; /* virtual circuit or datagram switch */
+ int servfail[MAXNS]; /* saved failure codes per nameserver */
+ register int try, ns;
+ register int n;
+
+ /* make sure resolver has been initialized */
+ if (!bitset(RES_INIT, _res.options) && res_init() == -1)
+ return(-1);
+
+ if (bitset(RES_DEBUG, _res.options))
+ {
+ printf("%sres_send()\n", dbprefix);
+ pr_query(query, querylen, stdout);
+ }
+
+ /* use virtual circuit if requested or if necessary */
+ v_circuit = bitset(RES_USEVC, _res.options) || (querylen > PACKETSZ);
+
+ /* reset server failure codes */
+ for (n = 0; n < MAXNS; n++)
+ servfail[n] = 0;
+
+/*
+ * Do _res.retry attempts for each of the _res.nscount addresses.
+ * Upon failure, the current server will be marked bad if we got
+ * an error condition which makes it unlikely that we will succeed
+ * the next time we try this server.
+ * Internal operating system failures, such as temporary lack of
+ * resources, do not fall in that category.
+ */
+ for (try = 0; try < _res.retry; try++)
+ {
+ for (ns = 0; ns < _res.nscount; ns++)
+ {
+ /* skip retry if server failed permanently */
+ if (servfail[ns])
+ continue;
+
+ /* fetch server address */
+ addr = &nslist(ns);
+retry:
+ if (bitset(RES_DEBUG, _res.options))
+ printf("%sQuerying server (# %d) %s address = %s\n", dbprefix,
+ ns+1, v_circuit ? "tcp" : "udp", inet_ntoa(addr->sin_addr));
+
+ if (v_circuit)
+ {
+ /* at most one attempt per server */
+ try = _res.retry;
+
+ /* connect via virtual circuit */
+ n = send_stream(addr, query, querylen, answer, anslen);
+ }
+ else
+ {
+ /* set datagram read timeout for recv_sock() */
+ timeout = (_res.retrans << try);
+ if (try > 0)
+ timeout /= _res.nscount;
+ if (timeout <= 0)
+ timeout = 1;
+
+ /* connect via datagram */
+ n = send_dgram(addr, query, querylen, answer, anslen);
+
+ /* check truncation; use v_circuit with same server */
+ if (n > 0 && bp->tc)
+ {
+ if (bitset(RES_DEBUG, _res.options))
+ printf("%struncated answer\n", dbprefix);
+
+ if (!bitset(RES_IGNTC, _res.options))
+ {
+ v_circuit = 1;
+ goto retry;
+ }
+ }
+ }
+
+ if (n <= 0)
+ {
+ switch (errno)
+ {
+ case ECONNREFUSED:
+ case ENETDOWN:
+ case ENETUNREACH:
+ case EHOSTDOWN:
+ case EHOSTUNREACH:
+ servfail[ns] = errno;
+ break;
+ }
+
+ /* try next server */
+ continue;
+ }
+
+ if (bitset(RES_DEBUG, _res.options))
+ {
+ printf("%sgot answer, %d bytes:\n", dbprefix, n);
+ pr_query(answer, n, stdout);
+ }
+
+ /* we have an answer; clear possible error condition */
+ errno = 0;
+ return(n);
+ }
+ }
+
+ /* no answer obtained; return error condition */
+ return(-1);
+}
+
+ /*
+** _RES_CLOSE -- Close an open stream or dgram connection
+** ------------------------------------------------------
+**
+** Returns:
+** None.
+*/
+
+static int srvsock = -1; /* socket descriptor */
+
+void
+_res_close()
+{
+ int save_errno = errno; /* preserve state */
+
+ /* close the connection if open */
+ if (srvsock >= 0)
+ {
+ (void) close(srvsock);
+ srvsock = -1;
+ }
+
+ /* restore state */
+ errno = save_errno;
+}
+
+ /*
+** SEND_STREAM -- Query nameserver via virtual circuit
+** ---------------------------------------------------
+**
+** Returns:
+** Length of nameserver answer buffer, if obtained.
+** -1 if an error occurred.
+**
+** Note that connect() is the call that is allowed to fail
+** under normal circumstances. All other failures generate
+** an unconditional error message.
+** Note that truncation is handled within _res_read().
+*/
+
+static int
+send_stream(addr, query, querylen, answer, anslen)
+input struct sockaddr_in *addr; /* the server address to connect to */
+input qbuf_t *query; /* location of formatted query buffer */
+input int querylen; /* length of query buffer */
+output qbuf_t *answer; /* location of buffer to store answer */
+input int anslen; /* maximum size of answer buffer */
+{
+ char *host = NULL; /* name of server is unknown */
+ register int n;
+
+/*
+ * Setup a virtual circuit connection.
+ */
+ srvsock = socket(AF_INET, SOCK_STREAM, 0);
+ if (srvsock < 0)
+ {
+ _res_perror(addr, host, "socket");
+ return(-1);
+ }
+
+ if (_res_connect(srvsock, addr, sizeof(*addr)) < 0)
+ {
+ if (bitset(RES_DEBUG, _res.options))
+ _res_perror(addr, host, "connect");
+ _res_close();
+ return(-1);
+ }
+
+ if (bitset(RES_DEBUG, _res.options))
+ printf("%sconnected to %s\n", dbprefix, inet_ntoa(addr->sin_addr));
+
+/*
+ * Send the query buffer.
+ */
+ if (_res_write(srvsock, addr, host, (char *)query, querylen) < 0)
+ {
+ _res_close();
+ return(-1);
+ }
+
+/*
+ * Read the answer buffer.
+ */
+ n = _res_read(srvsock, addr, host, (char *)answer, anslen);
+ if (n <= 0)
+ {
+ _res_close();
+ return(-1);
+ }
+
+/*
+ * Never leave the socket open.
+ */
+ _res_close();
+ return(n);
+}
+
+ /*
+** SEND_DGRAM -- Query nameserver via datagram
+** -------------------------------------------
+**
+** Returns:
+** Length of nameserver answer buffer, if obtained.
+** -1 if an error occurred.
+**
+** Inputs:
+** The global variable ``timeout'' should have been
+** set with the desired timeout value in seconds.
+**
+** Sending to a nameserver datagram port with no nameserver running
+** will cause an ICMP port unreachable message to be returned. If the
+** socket is connected, we get an ECONNREFUSED error on the next socket
+** operation, and select returns if the error message is received.
+** Also, we get ENETUNREACH or EHOSTUNREACH errors if appropriate.
+** We thus get a proper error status before timing out.
+** This method usually works only if BSD >= 43.
+**
+** Note that send() and recvfrom() are now the calls that are allowed
+** to fail under normal circumstances. All other failures generate
+** an unconditional error message.
+*/
+
+static int
+send_dgram(addr, query, querylen, answer, anslen)
+input struct sockaddr_in *addr; /* the server address to connect to */
+input qbuf_t *query; /* location of formatted query buffer */
+input int querylen; /* length of query buffer */
+output qbuf_t *answer; /* location of buffer to store answer */
+input int anslen; /* maximum size of answer buffer */
+{
+ char *host = NULL; /* name of server is unknown */
+ HEADER *qp = (HEADER *)query;
+ HEADER *bp = (HEADER *)answer;
+ register int n;
+
+/*
+ * Setup a connected datagram socket.
+ */
+ srvsock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (srvsock < 0)
+ {
+ _res_perror(addr, host, "socket");
+ return(-1);
+ }
+
+ if (connect(srvsock, (struct sockaddr *)addr, sizeof(*addr)) < 0)
+ {
+ _res_perror(addr, host, "connect");
+ _res_close();
+ return(-1);
+ }
+
+/*
+ * Send the query buffer.
+ */
+ if (send(srvsock, (char *)query, querylen, 0) != querylen)
+ {
+ if (bitset(RES_DEBUG, _res.options))
+ _res_perror(addr, host, "send");
+ _res_close();
+ return(-1);
+ }
+
+/*
+ * Wait for the arrival of a reply, timeout, or error message.
+ */
+wait:
+ n = recv_sock(srvsock, (char *)answer, anslen);
+ if (n <= 0)
+ {
+ if (bitset(RES_DEBUG, _res.options))
+ _res_perror(addr, host, "recvfrom");
+ _res_close();
+ return(-1);
+ }
+
+/*
+ * Make sure it is the proper response by checking the packet id.
+ */
+ if (qp->id != bp->id)
+ {
+ if (bitset(RES_DEBUG, _res.options))
+ {
+ printf("%sold answer:\n", dbprefix);
+ pr_query(answer, n, stdout);
+ }
+ goto wait;
+ }
+
+/*
+ * Never leave the socket open.
+ */
+ _res_close();
+ return(n);
+}
+
+#endif /*HOST_RES_SEND*/
+
+ /*
+** _RES_CONNECT -- Connect to a stream (virtual circuit) socket
+** ------------------------------------------------------------
+**
+** Returns:
+** 0 if successfully connected.
+** -1 in case of failure or timeout.
+**
+** Note that we use _res.retrans to override the default
+** connect timeout value.
+*/
+
+static jmp_buf timer_buf;
+
+static sigtype_t
+/*ARGSUSED*/
+timer(sig)
+int sig;
+{
+ longjmp(timer_buf, 1);
+ /*NOTREACHED*/
+}
+
+
+int
+_res_connect(sock, addr, addrlen)
+input int sock;
+input struct sockaddr_in *addr; /* the server address to connect to */
+input int addrlen;
+{
+ if (setjmp(timer_buf) != 0)
+ {
+ errno = ETIMEDOUT;
+ setalarm(0);
+ return(-1);
+ }
+
+ (void) signal(SIGALRM, timer);
+ setalarm(_res.retrans);
+
+ if (connect(sock, (struct sockaddr *)addr, addrlen) < 0)
+ {
+ if (errno == EINTR)
+ errno = ETIMEDOUT;
+ setalarm(0);
+ return(-1);
+ }
+
+ setalarm(0);
+ return(0);
+}
+
+ /*
+** _RES_WRITE -- Write the query buffer via a stream socket
+** --------------------------------------------------------
+**
+** Returns:
+** Length of buffer if successfully transmitted.
+** -1 in case of failure (error message is issued).
+**
+** The query is sent in two steps: first a single word with
+** the length of the buffer, followed by the buffer itself.
+*/
+
+int
+_res_write(sock, addr, host, buf, bufsize)
+input int sock;
+input struct sockaddr_in *addr; /* the server address to connect to */
+input char *host; /* name of server to connect to */
+input char *buf; /* location of formatted query buffer */
+input int bufsize; /* length of query buffer */
+{
+ u_short len;
+
+/*
+ * Write the length of the query buffer.
+ */
+ /* len = htons(bufsize); */
+ putshort((u_short)bufsize, (u_char *)&len);
+
+ if (write(sock, (char *)&len, INT16SZ) != INT16SZ)
+ {
+ _res_perror(addr, host, "write query length");
+ return(-1);
+ }
+
+/*
+ * Write the query buffer itself.
+ */
+ if (write(sock, buf, bufsize) != bufsize)
+ {
+ _res_perror(addr, host, "write query");
+ return(-1);
+ }
+
+ return(bufsize);
+}
+
+ /*
+** _RES_READ -- Read the answer buffer via a stream socket
+** -------------------------------------------------------
+**
+** Returns:
+** Length of buffer if successfully received.
+** -1 in case of failure (error message is issued).
+**
+** The answer is read in two steps: first a single word which
+** gives the length of the buffer, followed by the buffer itself.
+** If the answer is too long to fit into the supplied buffer,
+** only the portion that fits will be stored, the residu will be
+** flushed, and the truncation flag will be set.
+*/
+
+int
+_res_read(sock, addr, host, buf, bufsize)
+input int sock;
+input struct sockaddr_in *addr; /* the server address to connect to */
+input char *host; /* name of server to connect to */
+output char *buf; /* location of buffer to store answer */
+input int bufsize; /* maximum size of answer buffer */
+{
+ u_short len;
+ char *buffer;
+ int buflen;
+ int reslen;
+ register int n;
+
+ /* set stream timeout for recv_sock() */
+ timeout = 60;
+
+/*
+ * Read the length of answer buffer.
+ */
+ buffer = (char *)&len;
+ buflen = INT16SZ;
+
+ while (buflen > 0 && (n = recv_sock(sock, buffer, buflen)) > 0)
+ {
+ buffer += n;
+ buflen -= n;
+ }
+
+ if (buflen != 0)
+ {
+ _res_perror(addr, host, "read answer length");
+ return(-1);
+ }
+
+/*
+ * Terminate if length is zero.
+ */
+ /* len = ntohs(len); */
+ len = _getshort((u_char *)&len);
+ if (len == 0)
+ return(0);
+
+/*
+ * Check for truncation.
+ */
+ reslen = 0;
+ if ((int)len > bufsize)
+ {
+ reslen = len - bufsize;
+ len = bufsize;
+ }
+
+/*
+ * Read the answer buffer itself.
+ */
+ buffer = buf;
+ buflen = len;
+
+ while (buflen > 0 && (n = recv_sock(sock, buffer, buflen)) > 0)
+ {
+ buffer += n;
+ buflen -= n;
+ }
+
+ if (buflen != 0)
+ {
+ _res_perror(addr, host, "read answer");
+ return(-1);
+ }
+
+/*
+ * Discard the residu to keep connection in sync.
+ */
+ if (reslen > 0)
+ {
+ HEADER *bp = (HEADER *)buf;
+ char resbuf[PACKETSZ];
+
+ buffer = resbuf;
+ buflen = reslen < sizeof(resbuf) ? reslen : sizeof(resbuf);
+
+ while (reslen > 0 && (n = recv_sock(sock, buffer, buflen)) > 0)
+ {
+ reslen -= n;
+ buflen = reslen < sizeof(resbuf) ? reslen : sizeof(resbuf);
+ }
+
+ if (reslen != 0)
+ {
+ _res_perror(addr, host, "read residu");
+ return(-1);
+ }
+
+ if (bitset(RES_DEBUG, _res.options))
+ printf("%sresponse truncated\n", dbprefix);
+
+ /* set truncation flag */
+ bp->tc = 1;
+ }
+
+ return(len);
+}
+
+ /*
+** RECV_SOCK -- Read from stream or datagram socket with timeout
+** -------------------------------------------------------------
+**
+** Returns:
+** Length of buffer if successfully received.
+** -1 in case of failure or timeout.
+**
+** Inputs:
+** The global variable ``timeout'' should have been
+** set with the desired timeout value in seconds.
+**
+** Outputs:
+** Sets global ``from'' to the address from which we
+** received the packet.
+*/
+
+static int
+recv_sock(sock, buffer, buflen)
+input int sock;
+output char *buffer; /* current buffer address */
+input int buflen; /* remaining buffer size */
+{
+ fd_set fds;
+ struct timeval wait;
+ int fromlen;
+ register int n;
+
+ wait.tv_sec = timeout;
+ wait.tv_usec = 0;
+
+ /* FD_ZERO(&fds); */
+ bzero((char *)&fds, sizeof(fds));
+ FD_SET(sock, &fds);
+
+ /* wait for the arrival of data, or timeout */
+ n = select(FD_SETSIZE, &fds, (fd_set *)NULL, (fd_set *)NULL, &wait);
+ if (n <= 0)
+ {
+ if (n == 0)
+ errno = ETIMEDOUT;
+ return(-1);
+ }
+
+ /* fake an error if nothing was actually read */
+ fromlen = sizeof(from);
+ n = recvfrom(sock, buffer, buflen, 0, from_sa, &fromlen);
+ if (n == 0)
+ errno = ECONNRESET;
+ return(n);
+}
+
+ /*
+ * Alternative version for systems with broken networking code.
+ *
+ * The select() system call may fail on the solaris 2.4 platform
+ * without appropriate patches. However, these patches are reported
+ * to break client NFS.
+ *
+ * This version uses an alarm() instead of select(). This introduces
+ * additional system call overhead.
+ */
+
+#ifdef BROKEN_SELECT
+
+static int
+recv_sock(sock, buffer, buflen)
+input int sock;
+output char *buffer; /* current buffer address */
+input int buflen; /* remaining buffer size */
+{
+ int fromlen;
+ register int n;
+
+ if (setjmp(timer_buf) != 0)
+ {
+ errno = ETIMEDOUT;
+ setalarm(0);
+ return(-1);
+ }
+
+ (void) signal(SIGALRM, timer);
+ setalarm(timeout);
+
+ /* fake an error if nothing was actually read */
+ fromlen = sizeof(from);
+ n = recvfrom(sock, buffer, buflen, 0, from_sa, &fromlen);
+ if (n == 0)
+ errno = ECONNRESET;
+ setalarm(0);
+ return(n);
+}
+
+#endif /*BROKEN_SELECT*/
+
+ /*
+** _RES_PERROR -- Issue perror message including host info
+** -------------------------------------------------------
+**
+** Returns:
+** None.
+*/
+
+void
+_res_perror(addr, host, message)
+input struct sockaddr_in *addr; /* the server address to connect to */
+input char *host; /* name of server to connect to */
+input char *message; /* perror message string */
+{
+ int save_errno = errno; /* preserve state */
+
+ /* prepend server address and name */
+ if (addr != NULL)
+ (void) fprintf(stderr, "%s ", inet_ntoa(addr->sin_addr));
+ if (host != NULL)
+ (void) fprintf(stderr, "(%s) ", host);
+
+ /* issue actual message */
+ errno = save_errno;
+ perror(message);
+
+ /* restore state */
+ errno = save_errno;
+}
diff --git a/usr.sbin/named/host/type.h b/usr.sbin/named/host/type.h
new file mode 100644
index 00000000000..8f1712ec34c
--- /dev/null
+++ b/usr.sbin/named/host/type.h
@@ -0,0 +1,91 @@
+/*
+** Various new resource record type and class values.
+**
+** They belong in <arpa/nameser.h>
+**
+** @(#)type.h e07@nikhef.nl (Eric Wassenaar) 941205
+*/
+
+/* never used in practice */
+
+#ifndef C_CSNET
+#define C_CSNET 2
+#endif
+
+/* missing in some old versions */
+
+#ifndef C_HS
+#define C_HS 4
+#endif
+
+/* missing in some old versions */
+
+#ifndef T_TXT
+#define T_TXT 16
+#endif
+
+/* defined per RFC 1183 */
+
+#ifndef T_RP
+#define T_RP 17
+#endif
+
+#ifndef T_AFSDB
+#define T_AFSDB 18
+#endif
+
+#ifndef T_X25
+#define T_X25 19
+#endif
+
+#ifndef T_ISDN
+#define T_ISDN 20
+#endif
+
+#ifndef T_RT
+#define T_RT 21
+#endif
+
+/* defined per RFC 1348, revised per RFC 1637 */
+
+#ifndef T_NSAP
+#define T_NSAP 22
+#endif
+
+#ifndef T_NSAPPTR
+#define T_NSAPPTR 23
+#endif
+
+/* reserved per RFC 1700 */
+
+#ifndef T_SIG
+#define T_SIG 24
+#endif
+
+#ifndef T_KEY
+#define T_KEY 25
+#endif
+
+/* defined per RFC 1664 */
+
+#ifndef T_PX
+#define T_PX 26
+#endif
+
+/* defined per RFC 1712, already withdrawn */
+
+#ifndef T_GPOS
+#define T_GPOS 27
+#endif
+
+/* reserved per RFC 1700 */
+
+#ifndef T_AAAA
+#define T_AAAA 28
+#endif
+
+/* defined per RFC XXXX */
+
+#ifndef T_LOC
+#define T_LOC 29
+#endif
diff --git a/usr.sbin/named/host/vers.c b/usr.sbin/named/host/vers.c
new file mode 100644
index 00000000000..ec39cc4ab09
--- /dev/null
+++ b/usr.sbin/named/host/vers.c
@@ -0,0 +1,9 @@
+#ifndef lint
+static char Version[] = "@(#)vers.c e07@nikhef.nl (Eric Wassenaar) 951231";
+#endif
+
+char *version = "951231";
+
+#if defined(apollo)
+int h_errno = 0;
+#endif
diff --git a/usr.sbin/named/man/dig.1 b/usr.sbin/named/man/dig.1
new file mode 100644
index 00000000000..37be48ae94b
--- /dev/null
+++ b/usr.sbin/named/man/dig.1
@@ -0,0 +1,366 @@
+.\" $NetBSD: dig.1,v 1.1 1996/02/02 15:27:16 mrg Exp $
+.\"
+.\" $Id: dig.1,v 8.1 1994/12/15 06:24:10 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--
+.\"
+.\" Distributed with 'dig' version 2.0 from University of Southern
+.\" California Information Sciences Institute (USC-ISI).
+.\"
+.\" dig.1 2.0 (USC-ISI) 8/30/90
+.\"
+.\" Man page reformatted for this release by Andrew Cherenson
+.\" (arc@sgi.com)
+.\"
+.TH DIG 1 "August 30, 1990"
+.SH NAME
+dig \- send domain name query packets to name servers
+.SH SYNOPSIS
+.B dig
+.RI [ @\fIserver\fP ]
+.I domain
+.RI [ "<query-type>" ]
+.RI [ "<query-class>" ]
+.RI [ "+<query-option>" ]
+.RI [ "\-<dig-option>" ]
+.RI [ "%comment" ]
+.SH DESCRIPTION
+\fIDig\fP (domain information groper) is a flexible command line tool
+which can be used to gather information from the Domain
+Name System servers. \fIDig\fP has two modes: simple interactive mode
+which makes a single query, and batch which executes a query for
+each in a list of several query lines. All query options are
+accessible from the command line.
+.PP
+The usual simple use of \fIdig\fP will take the form:
+.sp 1
+ dig @server domain query-type query-class
+.sp 1
+where:
+.IP \fIserver\fP
+may be either a domain name or a dot-notation
+Internet address. If this optional field is omitted, \fIdig\fP
+will attempt to use the default name server for your machine.
+.sp 1
+\fBNote:\fP If a domain name is specified, this will be resolved
+using the domain name system resolver (i.e., BIND). If your
+system does not support DNS, you may \fIhave\fP to specify a
+dot-notation address. Alternatively, if there is a server
+at your disposal somewhere, all that is required is that
+/etc/resolv.conf be present and indicate where the default
+name servers reside, so that \fIserver\fP itself can be
+resolved. See
+.IR resolver (5)
+for information on /etc/resolv.conf.
+(WARNING: Changing /etc/resolv.conf will affect
+the standard resolver library and potentially several
+programs which use it.) As an option, the user may set the
+environment variable LOCALRES to name a file which is to
+be used instead of /etc/resolv.conf (LOCALRES is specific
+to the \fIdig\fP resolver and not referenced by the standard
+resolver). If the LOCALRES variable is not set or the file
+is not readable then /etc/resolv.conf will be used.
+.IP \fIdomain\fP
+is the domain name for which you are requesting information.
+See OPTIONS [-x] for convenient way to specify inverse address
+query.
+.IP \fIquery-type\fP
+is the type of information (DNS query type) that
+you are requesting. If omitted, the default is "a" (T_A = address).
+The following types are recognized:
+.sp 1
+.ta \w'hinfoXX'u +\w'T_HINFOXX'u
+.nf
+a T_A network address
+any T_ANY all/any information about specified domain
+mx T_MX mail exchanger for the domain
+ns T_NS name servers
+soa T_SOA zone of authority record
+hinfo T_HINFO host information
+axfr T_AXFR zone transfer
+ (must ask an authoritative server)
+txt T_TXT arbitrary number of strings
+.fi
+.sp 1
+(See RFC 1035 for the complete list.)
+.IP \fIquery-class\fP
+is the network class requested in the query. If
+omitted, the default is "in" (C_IN = Internet).
+The following classes are recognized:
+.sp 1
+.ta \w'hinfoXX'u +\w'T_HINFOXX'u
+.nf
+in C_IN Internet class domain
+any C_ANY all/any class information
+.fi
+.sp 1
+(See RFC 1035 for the complete list.)
+.sp 1
+\fBNote:\fP
+"Any" can be used to specify a class and/or a type of
+query. \fIDig\fP will parse the first occurrence of "any"
+to mean query-type = T_ANY. To specify query-class =
+C_ANY you must either specify "any" twice, or set
+query-class using "\-c" option (see below).
+.SH OTHER OPTIONS
+.IP "%ignored-comment"
+"%" is used to included an argument that is simply not
+parsed. This may be useful if running \fIdig\fP in batch
+mode. Instead of resolving every @server-domain-name in
+a list of queries, you can avoid the overhead of doing
+so, and still have the domain name on the command line
+as a reference. Example:
+.sp 1
+ dig @128.9.0.32 %venera.isi.edu mx isi.edu
+.sp 1
+.IP "\-<dig option>"
+"\-" is used to specify an option which effects the
+operation of \fIdig\fP. The following options are currently
+available (although not guaranteed to be useful):
+.RS
+.IP "\-x \fIdot-notation-address\fP"
+Convenient form to specify inverse address mapping.
+Instead of "dig 32.0.9.128.in-addr.arpa" one can
+simply "dig -x 128.9.0.32".
+.IP "\-f \fIfile\fP"
+File for \fIdig\fP batch mode. The file contains a list
+of query specifications (\fIdig\fP command lines) which
+are to be executed successively. Lines beginning
+with ';', '#', or '\\n' are ignored. Other options
+may still appear on command line, and will be in
+effect for each batch query.
+.IP "\-T \fItime\fP"
+Time in seconds between start of successive
+queries when running in batch mode. Can be used
+to keep two or more batch \fIdig\fP commands running
+roughly in sync. Default is zero.
+.IP "\-p \fIport\fP"
+Port number. Query a name server listening to a
+non-standard port number. Default is 53.
+.IP "\-P[\fIping-string\fP]"
+After query returns, execute a
+.IR ping (8)
+command
+for response time comparison. This rather
+unelegantly makes a call to the shell. The last
+three lines of statistics is printed for the
+command:
+.sp 1
+ ping \-s server_name 56 3
+.sp 1
+If the optional "ping string" is present, it
+replaces "ping \-s" in the shell command.
+.IP "\-t \fIquery-type\fP"
+Specify type of query. May specify either an
+integer value to be included in the type field
+or use the abbreviated mnemonic as discussed
+above (i.e., mx = T_MX).
+.IP "\-c \fIquery-class\fP"
+Specify class of query. May specify either an
+integer value to be included in the class field
+or use the abbreviated mnemonic as discussed
+above (i.e., in = C_IN).
+.IP "\-envsav"
+This flag specifies that the \fIdig\fP environment
+(defaults, print options, etc.), after
+all of the arguments are parsed, should be saved
+to a file to become the default environment.
+Useful if you do not like the standard set of
+defaults and do not desire to include a
+large number of options each time \fIdig\fP is used.
+The environment consists of resolver state
+variable flags, timeout, and retries as well as
+the flags detailing \fIdig\fP output (see below).
+If the shell environment variable LOCALDEF is set
+to the name of a file, this is where the default
+\fIdig\fP environment is saved. If not, the file
+"DiG.env" is created in the current working directory.
+.sp 1
+\fBNote:\fP LOCALDEF is specific to the \fIdig\fP resolver,
+and will not affect operation of the standard
+resolver library.
+.sp 1
+Each time \fIdig\fP is executed, it looks for "./DiG.env"
+or the file specified by the shell environment variable
+LOCALDEF. If such file exists and is readable, then the
+environment is restored from this file
+before any arguments are parsed.
+.IP "\-envset"
+This flag only affects
+batch query runs. When "\-envset" is
+specified on a line in a \fIdig\fP batch file,
+the \fIdig\fP environment after the arguments are parsed,
+becomes the default environment for the duration of
+the batch file, or until the next line which specifies
+"\-envset".
+.IP "\-[no]stick"
+This flag only affects batch query runs.
+It specifies that the \fIdig\fP environment (as read initially
+or set by "\-envset" switch) is to be restored before each query
+(line) in a \fIdig\fP batch file.
+The default "\-nostick" means that the \fIdig\fP environment
+does not stick, hence options specified on a single line
+in a \fIdig\fP batch file will remain in effect for
+subsequent lines (i.e. they are not restored to the
+"sticky" default).
+
+.RE
+.IP "+<query option>"
+"+" is used to specify an option to be changed in the
+query packet or to change \fIdig\fP output specifics. Many
+of these are the same parameters accepted by
+.IR nslookup (8).
+If an option requires a parameter, the form is as
+follows:
+.sp 1
+ +keyword[=value]
+.sp 1
+Most keywords can be abbreviated. Parsing of the "+"
+options is very simplistic \(em a value must not be
+separated from its keyword by white space. The following
+keywords are currently available:
+.sp 1
+.nf
+.ta \w'domain=NAMEXX'u +\w'(deb)XXX'u
+Keyword Abbrev. Meaning [default]
+
+[no]debug (deb) turn on/off debugging mode [deb]
+[no]d2 turn on/off extra debugging mode [nod2]
+[no]recurse (rec) use/don't use recursive lookup [rec]
+retry=# (ret) set number of retries to # [4]
+time=# (ti) set timeout length to # seconds [4]
+[no]ko keep open option (implies vc) [noko]
+[no]vc use/don't use virtual circuit [novc]
+[no]defname (def) use/don't use default domain name [def]
+[no]search (sea) use/don't use domain search list [sea]
+domain=NAME (do) set default domain name to NAME
+[no]ignore (i) ignore/don't ignore trunc. errors [noi]
+[no]primary (pr) use/don't use primary server [nopr]
+[no]aaonly (aa) authoritative query only flag [noaa]
+[no]sort (sor) sort resource records [nosor]
+[no]cmd echo parsed arguments [cmd]
+[no]stats (st) print query statistics [st]
+[no]Header (H) print basic header [H]
+[no]header (he) print header flags [he]
+[no]ttlid (tt) print TTLs [tt]
+[no]cl print class info [nocl]
+[no]qr print outgoing query [noqr]
+[no]reply (rep) print reply [rep]
+[no]ques (qu) print question section [qu]
+[no]answer (an) print answer section [an]
+[no]author (au) print authoritative section [au]
+[no]addit (ad) print additional section [ad]
+pfdef set to default print flags
+pfmin set to minimal default print flags
+pfset=# set print flags to #
+ (# can be hex/octal/decimal)
+pfand=# bitwise and print flags with #
+pfor=# bitwise or print flags with #
+.fi
+.sp 1
+The retry and time options affect the retransmission strategy used by resolver
+library when sending datagram queries. The algorithm is as follows:
+.sp 1
+.in +5n
+.nf
+for i = 0 to retry \- 1
+ for j = 1 to num_servers
+ send_query
+ wait((time * (2**i)) / num_servers)
+ end
+end
+.fi
+.in -5n
+.sp 1
+(Note: \fIdig\fP always uses a value of 1 for num_servers.)
+.SH DETAILS
+\fIDig\fP once required a slightly modified version of the BIND
+.IR resolver (3)
+library. BIND's resolver has (as of BIND 4.9) been augmented to work
+properly with \fIDig\fP. Essentially, \fIDig\fP is a straight-forward
+(albeit not pretty) effort of parsing arguments and setting appropriate
+parameters. \fIDig\fP uses resolver routines res_init(), res_mkquery(),
+res_send() as well as accessing _res structure.
+.SH FILES
+.ta \w'/etc/resolv.confXX'u
+/etc/resolv.conf initial domain name and name server
+\./DiG.env default save file for default options
+.br
+ addresses
+.SH ENVIRONMENT
+LOCALRES file to use in place of /etc/resolv.conf
+.br
+LOCALDEF default environment file
+.SH AUTHOR
+Steve Hotz
+hotz@isi.edu
+.SH ACKNOWLEDGMENTS
+\fIDig\fP uses functions from
+.IR nslookup (8)
+authored by Andrew Cherenson.
+.SH BUGS
+\fIDig\fP has a serious case of "creeping featurism" -- the result of
+considering several potential uses during it's development. It would
+probably benefit from a rigorous diet. Similarly, the print flags
+and granularity of the items they specify make evident their
+rather ad hoc genesis.
+.PP
+\fIDig\fP does not consistently exit nicely (with appropriate status)
+when a problem occurs somewhere in the resolver (NOTE: most of the common
+exit cases are handled). This is particularly annoying when running in
+batch mode. If it exits abnormally (and is not caught), the entire
+batch aborts; when such an event is trapped, \fIdig\fP simply
+continues with the next query.
+.SH SEE ALSO
+named(8), resolver(3), resolver(5), nslookup(8)
diff --git a/usr.sbin/named/man/dnsquery.1 b/usr.sbin/named/man/dnsquery.1
new file mode 100644
index 00000000000..f0208454e7d
--- /dev/null
+++ b/usr.sbin/named/man/dnsquery.1
@@ -0,0 +1,166 @@
+.\" $NetBSD: dnsquery.1,v 1.1 1996/02/02 15:27:20 mrg Exp $
+.\"
+.TH DNSQUERY 1 "10 March 1990"
+.UC 6
+.SH NAME
+dnsquery \- query domain name servers using resolver
+.SH SYNOPSIS
+.B dnsquery
+[-n
+.I nameserver]
+[-t
+.I type]
+[-c
+.I class]
+[-r
+.I retry]
+[-p
+.I retry period]
+[-d] [-s] [-v] host
+.SH DESCRIPTION
+The
+.IR dnsquery
+program is a general interface to nameservers via
+BIND resolver library calls. The program supports
+queries to the nameserver with an opcode of QUERY.
+This program is intended to be a replacement or
+supplement to programs like nstest, nsquery and
+nslookup. All arguments except for
+.IR host
+and
+.IR ns
+are treated without case-sensitivity.
+.SH OPTIONS
+.TP 1i
+.B \-n
+The nameserver to be used in the query. Nameservers can appear as either
+Internet addresses of the form w.x.y.z or can appear as domain names.
+(default: as specified in /etc/resolv.conf)
+.TP 1i
+.B \-t
+The type of resource record of interest. Types include:
+.RS 1.5i
+.TP 1i
+A
+address
+.PD 0
+.TP 1i
+NS
+nameserver
+.TP 1i
+CNAME
+canonical name
+.TP 1i
+PTR
+domain name pointer
+.TP 1i
+SOA
+start of authority
+.TP 1i
+WKS
+well-known service
+.TP 1i
+HINFO
+host information
+.TP 1i
+MINFO
+mailbox information
+.TP 1i
+MX
+mail exchange
+.TP 1i
+RP
+responsible person
+.TP 1i
+MG
+mail group member
+.TP 1i
+AFSDB
+DCE or AFS server
+.TP 1i
+ANY
+wildcard
+.RE
+.PD
+.IP
+Note that any case may be used. (default: ANY)
+.TP 1i
+.B \-c
+The class of resource records of interest.
+Classes include:
+.RS 2i
+.TP 1i
+IN
+Internet
+.PD 0
+.TP 1i
+HS
+Hesiod
+.TP 1i
+CHAOS
+Chaos
+.TP 1i
+ANY
+wildcard
+.RE
+.PD
+.IP
+Note that any case may be used. (default: IN)
+.TP 1i
+.B \-r
+The number of times to retry if the nameserver is
+not responding. (default: 4)
+.TP 1i
+.B \-p
+Period to wait before timing out. (default: RES_TIMEOUT)
+.IR options
+field. (default: any answer)
+.TP 1i
+.B \-d
+Turn on debugging. This sets the RES_DEBUG bit of the resolver's
+.IR options
+field. (default: no debugging)
+.TP 1i
+.B \-s
+Use a
+.IR stream
+rather than a packet. This uses a TCP stream connection with
+the nameserver rather than a UDP datagram. This sets the
+RES_USEVC bit of the resolver's
+.IR options
+field. (default: UDP)
+.TP 1i
+.B \-v
+Synonym for the 's' flag.
+.TP 1i
+.B host
+The name of the host (or domain) of interest.
+.SH FILES
+/etc/resolv.conf to get the default ns and search lists
+.br
+<arpa/nameser.h> list of usable RR types and classes
+.br
+<resolv.h> list of resolver flags
+.SH "SEE ALSO"
+nslookup(8), nstest(1), nsquery(1),
+named(8), resolver(5)
+.SH DIAGNOSTICS
+If the resolver fails to answer the query and debugging has not been
+turned on,
+.IR dnsquery
+will simply print a message like:
+.TP 1i
+Query failed (rc = 1) : Unknown host
+.LP
+The value of the return code is supplied by h_errno.
+.SH BUGS
+Queries of a class other than IN can have interesting results
+since ordinarily a nameserver only has a list of root nameservers
+for class IN resource records.
+.PP
+Query uses a call to inet_addr() to determine if the argument
+for the '-n' option is a valid Internet address. Unfortunately,
+inet_addr() seems to cause a segmentation fault with some (bad)
+addresses (e.g. 1.2.3.4.5).
+.SH AUTHOR
+Bryan Beecher
diff --git a/usr.sbin/named/man/gethostbyname.3 b/usr.sbin/named/man/gethostbyname.3
new file mode 100644
index 00000000000..0f8137bab22
--- /dev/null
+++ b/usr.sbin/named/man/gethostbyname.3
@@ -0,0 +1,228 @@
+.\" $NetBSD: gethostbyname.3,v 1.1 1996/02/02 15:27:23 mrg Exp $
+.\"
+.\" Copyright (c) 1983, 1987 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted provided
+.\" that: (1) source distributions retain this entire copyright notice and
+.\" comment, and (2) distributions including binaries display the following
+.\" acknowledgement: ``This product includes software developed by the
+.\" University of California, Berkeley and its contributors'' in the
+.\" documentation or other materials provided with the distribution and in
+.\" all advertising materials mentioning features or use of this software.
+.\" 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" @(#)gethostbyname.3 6.12 (Berkeley) 6/23/90
+.\"
+.TH GETHOSTBYNAME 3 "June 23, 1990"
+.UC 5
+.SH NAME
+gethostbyname, gethostbyaddr, gethostent, sethostent, endhostent, herror \- get network host entry
+.SH SYNOPSIS
+.B "#include <netdb.h>
+.PP
+.B "extern int h_errno;
+.PP
+.B "struct hostent *gethostbyname(name)
+.br
+.B "char *name;
+.PP
+.B "struct hostent *gethostbyname2(name, af)
+.br
+.B "char *name; int af;
+.PP
+.B "struct hostent *gethostbyaddr(addr, len, type)
+.br
+.B "char *addr; int len, type;
+.PP
+.B "struct hostent *gethostent()
+.PP
+.B "sethostent(stayopen)
+.br
+.B "int stayopen;
+.PP
+.B "endhostent()
+.PP
+.B "herror(string)
+.br
+.B "char *string;
+.PP
+.SH DESCRIPTION
+.IR Gethostbyname ,
+.IR gethostbyname2 ,
+and
+.I gethostbyaddr
+each return a pointer to an object with the
+following structure describing an internet host
+referenced by name or by address, respectively.
+This structure contains either the information obtained from the name server,
+.IR named (8),
+or broken-out fields from a line in
+.IR /etc/hosts .
+If the local name server is not running these routines do a lookup in
+.IR /etc/hosts .
+.RS
+.PP
+.nf
+struct hostent {
+ char *h_name; /* official name of host */
+ char **h_aliases; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+ char **h_addr_list; /* list of addresses from name server */
+};
+#define h_addr h_addr_list[0] /* address, for backward compatibility */
+.ft R
+.ad
+.fi
+.RE
+.PP
+The members of this structure are:
+.TP \w'h_addr_list'u+2n
+h_name
+Official name of the host.
+.TP \w'h_addr_list'u+2n
+h_aliases
+A zero terminated array of alternate names for the host.
+.TP \w'h_addr_list'u+2n
+h_addrtype
+The type of address being returned; usually AF_INET.
+.TP \w'h_addr_list'u+2n
+h_length
+The length, in bytes, of the address.
+.TP \w'h_addr_list'u+2n
+h_addr_list
+A zero terminated array of network addresses for the host.
+Host addresses are returned in network byte order.
+.TP \w'h_addr_list'u+2n
+h_addr
+The first address in h_addr_list; this is for backward compatibility.
+.PP
+When using the nameserver,
+.I gethostbyname
+will search for the named host in the current domain and its parents
+unless the name ends in a dot.
+If the name contains no dot, and if the environment variable ``HOSTALAIASES''
+contains the name of an alias file, the alias file will first be searched
+for an alias matching the input name.
+See
+.IR hostname (7)
+for the domain search procedure and the alias file format.
+.PP
+.I Gethostbyname2
+is an evolution of
+.I gethostbyname
+intended to allow lookups in address families other than AF_INET, for example
+AF_INET6. Currently the
+.I af
+argument must be specified as
+.I AF_INET
+else the function will return \s-2NULL\s+2 after having set
+.I h_errno
+to \s-2NETDB_INTERNAL\s+2.
+.PP
+.I Sethostent
+may be used to request the use of a connected TCP socket for queries.
+If the
+.I stayopen
+flag is non-zero,
+this sets the option to send all queries to the name server using TCP
+and to retain the connection after each call to
+.I gethostbyname
+or
+.IR gethostbyaddr .
+Otherwise, queries are performed using UDP datagrams.
+.PP
+.I Endhostent
+closes the TCP connection.
+.SH DIAGNOSTICS
+.PP
+Error return status from
+.I gethostbyname
+and
+.I gethostbyaddr
+is indicated by return of a null pointer.
+The external integer
+.IR h_errno
+may then be checked to see whether this is a temporary failure
+or an invalid or unknown host.
+The routine
+.I herror
+can be used to print an error message describing the failure.
+If its argument
+.I string
+is non-NULL, it is printed, followed by a colon and a space.
+The error message is printed with a trailing newline.
+.PP
+.IR h_errno
+can have the following values:
+.RS
+.IP NETDB_INTERNAL \w'HOST_NOT_FOUND'u+2n
+This indicates an internal error in the library, unrelated to the network
+or name service.
+.I errno
+will be valid in this case; see
+.IR perror (3).
+.IP HOST_NOT_FOUND \w'HOST_NOT_FOUND'u+2n
+No such host is known.
+.IP TRY_AGAIN \w'HOST_NOT_FOUND'u+2n
+This is usually a temporary error
+and means that the local server did not receive
+a response from an authoritative server.
+A retry at some later time may succeed.
+.IP NO_RECOVERY \w'HOST_NOT_FOUND'u+2n
+Some unexpected server failure was encountered.
+This is a non-recoverable error.
+.IP NO_DATA \w'HOST_NOT_FOUND'u+2n
+The requested name is valid but does not have an IP address;
+this is not a temporary error.
+This means that the name is known to the name server but there is no address
+associated with this name.
+Another type of request to the name server using this domain name
+will result in an answer;
+for example, a mail-forwarder may be registered for this domain.
+.RE
+.SH FILES
+/etc/hosts
+.SH "SEE ALSO"
+resolver(3), hosts(5), hostname(7), named(8)
+.SH CAVEAT
+.PP
+.I Gethostent
+is defined, and
+.I sethostent
+and
+.I endhostent
+are redefined,
+when
+.IR libc
+is built to use only the routines to lookup in
+.IR /etc/hosts
+and not the name server.
+.PP
+.I Gethostent
+reads the next line of
+.IR /etc/hosts ,
+opening the file if necessary.
+.PP
+.I Sethostent
+is redefined to open and rewind the file. If the
+.I stayopen
+argument is non-zero,
+the hosts data base will not be closed after each call to
+.I gethostbyname
+or
+.IR gethostbyaddr .
+.I Endhostent
+is redefined to close the file.
+.SH BUGS
+All information
+is contained in a static area
+so it must be copied if it is
+to be saved. Only the Internet
+address format is currently understood.
diff --git a/usr.sbin/named/man/getnetent.3 b/usr.sbin/named/man/getnetent.3
new file mode 100644
index 00000000000..efd80822fa5
--- /dev/null
+++ b/usr.sbin/named/man/getnetent.3
@@ -0,0 +1,135 @@
+.\" $NetBSD: getnetent.3,v 1.1 1996/02/02 15:27:26 mrg Exp $
+.\"
+.\" $Id: getnetent.3,v 8.1 1994/12/15 06:24:10 vixie Exp
+.TH getnetent 3
+.SH NAME
+getnetent, getnetbyaddr, getnetbyname, setnetent, endnetent \- get networks
+entry
+.SH SYNTAX
+.nf
+.B #include <netdb.h>
+.PP
+.B struct netent *getnetent()
+.PP
+.B struct netent *getnetbyname(\fIname\fP)
+.B char *\fIname\fP;
+.PP
+.B struct netent *getnetbyaddr(\fInet\fP, \fItype\fP)
+.B long \fInet\fP; int \fItype\fP;
+.PP
+.B void setnetent(\fIstayopen\fP)
+.B int \fIstayopen\fP;
+.PP
+.B void endnetent()
+.fi
+.SH DESCRIPTION
+The
+.IR getnetent ,
+.IR getnetbyname ,
+and
+.I getnetbyaddr
+subroutines
+each return a pointer to an object with the
+following structure
+containing the broken-out
+fields of a line in the
+.I networks
+database.
+.RS
+.PP
+.nf
+struct netent {
+ char *n_name; /* official name of net */
+ char **n_aliases; /* alias list */
+ int n_addrtype; /* net number type */
+ long n_net; /* net number */
+};
+.ft R
+.ad
+.fi
+.RE
+.PP
+The members of this structure are:
+.TP \w'n_addrtype'u+2n
+n_name
+The official name of the network.
+.TP \w'n_addrtype'u+2n
+n_aliases
+A zero terminated list of alternate names for the network.
+.TP \w'n_addrtype'u+2n
+n_addrtype
+The type of the network number returned: AF_INET.
+.TP \w'n_addrtype'u+2n
+n_net
+The network number. Network numbers are returned in machine byte
+order.
+.PP
+If the
+.I stayopen
+flag on a
+.I setnetent
+subroutine is NULL, the
+.I networks
+database is opened. Otherwise the
+.I setnetent
+has the effect of rewinding the
+.I networks
+database.
+The
+.I endnetent
+may be called to
+close the
+.I networks
+database when processing is complete.
+.PP
+The
+.I getnetent
+subroutine simply reads the next
+line while
+.I getnetbyname
+and
+.I getnetbyaddr
+search until a matching
+.I name
+or
+.I net
+number is found
+(or until EOF is encountered). The \fItype\fP must be AF_INET.
+The
+.I getnetent
+subroutine keeps a pointer in the database, allowing
+successive calls to be used
+to search the entire file.
+.PP
+A call to
+.I setnetent
+must be made before a
+.I while
+loop using
+.I getnetent
+in order to perform initialization and an
+.I endnetent
+must be used after the loop. Both
+.I getnetbyname
+and
+.I getnetbyaddr
+make calls to
+.I setnetent
+and
+.I endnetent .
+.SH FILES
+.I /etc/networks
+.SH DIAGNOSTICS
+Null pointer (0) returned on EOF or error.
+.SH SEE ALSO
+.nf
+networks(5)
+RFC 1101
+.SH HISTORY
+The getnetent(), getnetbyaddr(), getnetbyname(), setnetent(), and
+endnetent() functions appeared in 4.2BSD.
+.SH BUGS
+The data space used by these functions is static; if future use requires the
+data, it should be copied before any subsequent calls to these functions
+overwrite it. Only Internet network numbers are currently understood.
+Expecting network numbers to fit in no more than 32 bits is probably naive.
diff --git a/usr.sbin/named/man/host.1 b/usr.sbin/named/man/host.1
new file mode 100644
index 00000000000..656ea50a355
--- /dev/null
+++ b/usr.sbin/named/man/host.1
@@ -0,0 +1,781 @@
+.\"
+.\" @(#)host.1 e07@nikhef.nl (Eric Wassenaar) 951024
+.\"
+.TH host 1 "951024"
+.SH NAME
+host \- query nameserver about domain names and zones
+.SH SYNOPSIS
+.na
+.nf
+\fBhost\fP [\fB\-v\fP] [\fB\-a\fP] [\fB\-t\fP \fIquerytype\fP] [\fIoptions\fP] \fIname\fP [\fIserver\fP]
+.br
+\fBhost\fP [\fB\-v\fP] [\fB\-a\fP] [\fB\-t\fP \fIquerytype\fP] [\fIoptions\fP] \fB\-l\fP \fIzone\fP [\fIserver\fP]
+.br
+\fBhost\fP [\fB\-v\fP] [\fIoptions\fP] \fB\-H\fP [\fB\-D\fP] [\fB\-E\fP] [\fB\-G\fP] \fIzone\fP
+.br
+\fBhost\fP [\fB\-v\fP] [\fIoptions\fP] \fB\-C\fP \fIzone\fP
+.br
+\fBhost\fP [\fB\-v\fP] [\fIoptions\fP] \fB\-A\fP \fIhost\fP
+.sp
+\fBhost\fP [\fIoptions\fP] \fB\-x\fP [\fIname\fP ...]
+.br
+\fBhost\fP [\fIoptions\fP] \fB\-X\fP \fIserver\fP [\fIname\fP ...]
+.SH DESCRIPTION
+.I host
+looks for information about Internet hosts and domain names.
+It gets this information from a set of interconnected servers
+that are spread across the world. The information is stored
+in the form of "resource records" belonging to hierarchically
+organized "zones".
+.PP
+By default, the program simply converts between host names and Internet
+addresses. However, with the \fB\-t\fP, \fB\-a\fP and \fB\-v\fP
+options, it can be used to find all of the information about
+domain names that is maintained by the domain nameserver system.
+The information printed consists of various fields of the
+associated resource records that were retrieved.
+.PP
+The arguments can be either host names (domain names) or numeric
+Internet addresses.
+.PP
+A numeric Internet address consists of four decimal numbers
+separated by dots, e.g. \fB192.16.199.1\fP, representing the
+four bytes of the 32-bit address.
+.br
+The default action is to look up the associated host name.
+.PP
+A host name or domain name consists of component names (labels)
+separated by dots, e.g. \fBnikhefh.nikhef.nl\fP
+.br
+The default action is to look up all of its Internet addresses.
+.PP
+For single names without a trailing dot, the local domain is
+automatically tacked on the end.
+Thus a user in domain "nikhef.nl" can say "host nikhapo",
+and it will actually look up "nikhapo.nikhef.nl".
+In all other cases, the name is tried unchanged.
+Single names with trailing dot are considered top-level domain
+specifications, e.g. "nl."
+.PP
+Note that the usual lookup convention for any name that does not end
+with a trailing dot is to try first with the local domain appended,
+and possibly other search domains.
+This convention is not used by this program.
+.PP
+The actual suffix to tack on the end is usually the local domain
+as specified in the \fB/etc/resolv.conf\fP file, but this can be
+overridden.
+See below for a description of how to customize the host name lookup.
+.SH ARGUMENTS
+The first argument is normally the host name (domain name) for which
+you want to look up the requested information.
+If the first argument is an Internet address, a query is done on the
+special "reverse mapping" domain to look up its associated host name.
+.PP
+If the \fB\-l\fP option is given, the first argument is a domain zone
+name for which a complete listing is given. The program enters a
+special zone listing mode which has several variants (see below).
+.PP
+The second argument is optional. It allows you to specify a particular
+server to query. If you don't specify this argument, default servers
+are used, as defined by the \fB/etc/resolv.conf\fP file.
+.SH EXTENDED SYNTAX
+If the \fB\-x\fP option is given, it extends the syntax in the sense
+that multiple arguments are allowed on the command line. An optional
+explicit server must now be specified using the \fB\-X\fP option as it
+cannot be given as an ordinary argument any more. The \fB\-X\fP
+option implies \fB\-x\fP.
+.sp
+The extended syntax allows no arguments at all, in which case the
+arguments will be read from standard input. This can be a pipe,
+redirection from a file, or an interactive terminal. Note that
+these arguments are the names to be queried, and not command options.
+Everything that appears after a '#' or ';' on an input line will be
+skipped. Multiple arguments per line are allowed.
+.SH OPTIONS
+There are a number of options that can be used before the specified
+arguments. Some of these options are meaningful only to the people
+who maintain the domain database zones.
+The first options are the regularly used ones.
+.TP 4
+.B \-v
+causes printout to be in a "verbose" format.
+All resource record fields are printed.
+Without this option, the ttl and class fields are not shown.
+Also the contents of the "additional information" and "authoritative
+nameservers" sections in the answer from the nameserver are printed,
+if present. Normally these sections are not shown.
+In addition, the verbose option prints extra information about the
+various actions that are taken by the program.
+Note that \fB\-vv\fP is "very verbose". This generates a lot of output.
+.TP
+.BI \-t " querytype"
+allows you to specify a particular type of resource record information
+to be looked up. Supported types are listed below.
+The wildcard may be written as either \fBANY\fP or \fB*\fP.
+Types may be given in upper or lower case.
+The default is type \fBA\fP for regular lookups,
+and \fBA\fP, \fBNS\fP, and \fBPTR\fP for zone listings.
+.TP
+.B \-a
+is equivalent to \fB\-t ANY\fP.
+Note that this gives you "anything available" (currently cached) and
+not "all defined data" if a non-authoritative server is queried.
+.SH SPECIAL MODES
+The following options put the program in a special mode.
+.TP 4
+.BI \-l " zone"
+generates the listing of an entire zone.
+.sp
+E.g. the command
+.br
+ \fBhost \-l nikhef.nl\fP
+.br
+will give a listing of all hosts in the "nikhef.nl" zone.
+The \fB\-t\fP option is used to filter what information is
+extracted, as you would expect. The default is address
+information from A records, supplemented with data from PTR
+and NS records.
+.sp
+The command
+.br
+ \fBhost \-Z \-a \-l nikhef.nl\fP
+.br
+will give a complete download of the zone data for "nikhef.nl",
+in the official master file format.
+.TP 4
+.B \-H
+can be specified instead of the \fB\-l\fP option. It will print
+the count of the unique hostnames (names with an A record)
+encountered within the zone.
+It will not count pseudo names like "localhost", nor addresses
+associated with the zone name itself. Neither are counted the
+"glue records" that are necessary to define nameservers for
+the zone and its delegated zones.
+.sp
+By default, this option will not print any resource records.
+.sp
+Combined with the \fB\-S\fP option, it will give a complete
+statistics survey of the zone.
+.sp
+The host count may be affected by duplicate hosts (see below).
+To compute the most realistic value, subtract the duplicate
+host count from the total host count.
+.TP
+.B \-G
+implies \fB\-H\fP, but lists the names of gateway hosts.
+These are the hosts that have more than one address.
+Gateway hosts are not checked for duplicate addresses.
+.TP
+.B \-E
+implies \fB\-H\fP, but lists the names of extrazone hosts.
+An extrazone host in zone "foo.bar" is of the form
+"host.xxx.foo.bar" where "xxx.foo.bar" is not defined as
+a delegated zone with an NS record.
+This may be intentional, but also may be an error.
+.TP
+.B \-D
+implies \fB\-H\fP, but lists the names of duplicate hosts.
+These are hosts with only one address, which is known to
+have been defined also for another host with a different name,
+possibly even in a different zone.
+This may be intentional, but also may be an error.
+.TP
+.B \-C
+can be specified instead of the \fB\-l\fP option. It causes the SOA
+records for the specified zone to be compared as found at each of
+the authoritative nameservers for the zone (as listed in the NS records).
+Nameserver recursion is turned off, and it will be checked whether
+the answers are really authoritative. If a server cannot provide an
+authoritative SOA record, a lame delegation of the zone to that server
+is reported.
+Discrepancies between the records are reported. Various sanity checks
+are performed.
+.TP
+.B \-A
+enters a special address check mode.
+.sp
+If the first argument is a host name, its addresses will be retrieved,
+and for each of the addresses it will be checked whether they map back
+to the given host.
+.sp
+If the first argument is a dotted quad Internet address, its name will
+be retrieved, and it will be checked whether the given address is listed
+among the known addresses belonging to that host.
+.sp
+If the \fB\-A\fP flag is specified along with any zone listing option,
+a reverse lookup of the address in each encountered A record is performed,
+and it is checked whether it is registered and maps back to the name of
+the A record.
+.SH SPECIAL OPTIONS
+The following options apply only to the special zone listing modes.
+.TP 4
+.BI \-L " level"
+Recursively generate zone listings up to this level deep.
+Level 1 traverses the parent zone and all of its delegated zones.
+Each additional level descends into another layer of delegated zones.
+.TP
+.B \-S
+prints statistics about the various types of resource records found
+during zone listings, the number of various host classifications,
+the number of delegated zones, and some total statistics after
+recursive listings.
+.TP
+.B \-p
+causes only the primary nameserver of a zone to be contacted for zone
+transfers during zone listings. Normally, zone transfers are obtained
+from any one of the authoritative servers that responds.
+The primary nameserver is obtained from the SOA record of the zone.
+If a specific server is given on the command line, this option will
+query that server for the desired nameservers of the zone. This can be
+used for testing purposes in case the zone has not been registered yet.
+.TP
+.BI \-P " prefserver"
+gives priority for zone transfers to preferred servers residing in
+domains given by the comma-separated list \fIprefserver\fP. The more
+domain component labels match, the higher the priority.
+If this option is not present, priority is given to servers within
+your own domain or parent domains.
+The order in which NS records are issued may be unfavorable if they
+are subject to BIND 4.9 round-robin reshuffling.
+.TP
+.BI \-N " skipzone"
+prohibits zone transfers for the zones given by the comma-separated
+list \fIskipzone\fP. This may be used during recursive zone listings
+when certain zones are known to contain bogus information which
+should be excluded from further processing.
+.SH COMMON OPTIONS
+The following options can be used in both normal mode and domain
+listing mode.
+.TP 4
+.B \-d
+turns on debugging. Nameserver transactions are shown in detail.
+Note that \fB\-dd\fP prints even more debugging output.
+.TP
+.BI \-f " filename"
+writes the resource record output to the given logfile as well as
+to standard output.
+.TP
+.BI \-F " filename"
+same as \fB\-f\fP, but exchange the role of stdout and logfile.
+All stdout output (including verbose and debug printout) goes to
+the logfile, and stdout gets only the extra resource record output
+(so that it can be used in pipes).
+.TP
+.BI \-I " chars"
+suppresses warning messages about illegal domain names containing
+invalid characters, by specifying such characters in the string
+\fIchars\fP. The underscore is a good candidate.
+.TP
+.B \-i
+constructs a query for the "reverse mapping" \fBin-addr.arpa\fP
+domain in case a numeric (dotted quad) address was specified.
+Useful primarily for zone listing mode, since for numeric regular
+lookups such query is done anyway (but with \-i you see the actual
+PTR resource record outcome).
+.TP
+.B \-n
+constructs a query for the "reverse mapping" \fBnsap.int\fP
+domain in case an nsap address was specified.
+This can be used to look up the names associated with nsap addresses,
+or to list reverse nsap zones.
+An nsap address consists of an even number of hexadecimal digits,
+with a maximum of 40, optionally separated by interspersed dots.
+An optional prefix "0x" is skipped.
+If this option is used, all reverse nsap.int names are by default
+printed in forward notation, only to improve readability.
+The \fB\-Z\fP option forces the output to be in the official zone
+file format.
+.TP
+.B \-q
+be quiet and suppress various warning messages (the ones preceded
+by " !!! ").
+Serious error messages (preceded by " *** ") are never suppressed.
+.TP
+.B \-T
+prints the time-to-live values during non-verbose output.
+By default the ttl is shown only in verbose mode.
+.TP
+.B \-Z
+prints the selected resource record output in full zone file format,
+including trailing dot in domain names, plus ttl value and class name.
+.SH OTHER OPTIONS
+The following options are used only in special circumstances.
+.TP 4
+.BI \-c " class"
+allows you to specify a particular resource record class.
+Supported are
+\fBIN\fP, \fBINTERNET\fP, \fBCS\fP, \fBCSNET\fP, \fBCH\fP, \fBCHAOS\fP,
+\fBHS\fP, \fBHESIOD\fP, and the wildcard \fBANY\fP or \fB*\fP.
+The default class is \fBIN\fP.
+.TP
+.B \-e
+excludes information about names that are not residing within
+the given zone during zone listings, such as some glue records.
+For regular queries, it suppresses the printing of the "additional
+information" and "authoritative nameserver" sections in the answer
+from the nameserver.
+.TP
+.B \-m
+is equivalent to \fB\-t MAILB\fP, which filters
+any of types \fBMB\fP, \fBMR\fP, \fBMG\fP, or \fBMINFO\fP.
+In addition, \fBMR\fP and \fBMG\fP records will be recursively
+expanded into \fBMB\fP records.
+.TP
+.B \-o
+suppresses the resource record output to stdout. Can be used in
+combination with the \fB\-f\fP option to separate the resource
+record output from verbose and debug comments and error messages.
+.TP
+.B \-r
+causes nameserver recursion to be turned off in the request.
+This means that the contacted nameserver will return only data
+it has currently cached in its own database.
+It will not ask other servers to retrieve the information.
+Note that nameserver recursion is always turned off when checking
+SOA records using the \fB\-C\fP option. Authoritative servers
+should have all relevant information available.
+.TP
+.B \-R
+Normally querynames are assumed to be fully qualified and are
+tried as such, unless it is a single name, which is always tried
+(and only once) in the default domain.
+This option simulates the default BIND behavior by qualifying
+any specified name by repeatedly adding search domains, with
+the exception that the search terminates immediately if the name
+exists but does not have the desired querytype.
+The default search domains are constructed from the default domain
+by repeatedly peeling off the first component, until a final domain
+with only one dot remains.
+.TP
+.BI \-s " seconds"
+specifies a new nameserver timeout value. The program will wait
+for a nameserver reply in two attempts of this number of seconds.
+Normally it does 2 attempts of 5 seconds per nameserver address tried.
+The actual timeout algorithm is slightly more complicated, extending
+the timeout value dynamically depending on the number of tries and
+the number of nameserver addresses.
+.TP
+.B \-u
+forces the use of virtual circuits (TCP) instead of datagrams (UDP) when
+issuing nameserver queries. This is slower, but potentially more reliable.
+Note that a virtual circuit is automatically chosen in case a query
+exceeds the maximum datagram packet size. Also if a datagram answer
+turns out to be truncated, the query is retried using virtual circuit.
+A zone transfer is always done via a virtual circuit.
+.TP
+.B \-w
+causes the program to retry forever if the response to a regular query
+times out. Normally it will time out after some 10 seconds per
+nameserver address tried.
+.TP
+.B \-V
+prints just the version number of the \fBhost\fP program, and exits.
+.SH DEFAULT OPTIONS
+Default options and parameters can be preset in an environment
+variable \fBHOST_DEFAULTS\fP using the same syntax as on the command
+line. They will be evaluated before the command line arguments.
+.SH QUERYTYPES
+The following querytypes (resource record types) are supported.
+Indicated within parentheses are the various kinds of data fields.
+.TP 10
+.B A
+Host address (dotted quad)
+.TP
+.B NS
+Authoritative nameserver (domain name)
+.TP
+.B MD
+Mail destination (domain name)
+.TP
+.B MF
+Mail forwarder (domain name)
+.TP
+.B CNAME
+Canonical name for an alias (domain name)
+.TP
+.B SOA
+Marks the start of a zone of authority
+(domain name of primary, domain name of hostmaster,
+serial, refresh, retry, expiration, default ttl)
+.TP
+.B MB
+Mailbox domain name (domain name)
+.TP
+.B MG
+Mail group member (domain name)
+.TP
+.B MR
+Mail rename domain name (domain name)
+.TP
+.B NULL
+Null resource record (no format or data)
+.TP
+.B WKS
+Well-known service description (dotted quad, protocol name, list of services)
+.TP
+.B PTR
+Domain name pointer (domain name)
+.TP
+.B HINFO
+Host information (CPU type string, OS type string)
+.TP
+.B MINFO
+Mailbox or mail list information (request domain name, error domain name)
+.TP
+.B MX
+Mail exchanger (preference value, domain name)
+.TP
+.B TXT
+Descriptive text (string)
+.TP
+.B UINFO
+User information (string)
+.TP
+.B UID
+User identification (number)
+.TP
+.B GID
+Group identification (number)
+.TP
+.B UNSPEC
+Unspecified binary data (data)
+.TP
+.B ANY
+Matches information of any type available.
+.TP
+.B MAILB
+Matches any of types \fBMB\fP, \fBMR\fP, \fBMG\fP, or \fBMINFO\fP.
+.TP
+.B MAILA
+Matches any of types \fBMD\fP, or \fBMF\fP.
+.PP
+The following types have been defined in RFC 1183, but
+are not yet in general use. They are recognized by this program.
+.TP 10
+.B RP
+Responsible person (domain name for MB, domain name for TXT)
+.TP
+.B AFSDB
+AFS database location (type, domain name)
+.TP
+.B X25
+X25 address (address string)
+.TP
+.B ISDN
+ISDN address (address string, optional subaddress string)
+.TP
+.B RT
+Route through host (preference value, domain name)
+.PP
+The following types have been defined in RFC 1348, but
+are not yet in general use. They are recognized by this program.
+RFC 1348 has already been obsoleted by RFC 1637, which defines
+a new experimental usage of NSAP records. This program has now
+hooks to manipulate them.
+.TP 10
+.B NSAP
+NSAP address (encoded address)
+.TP
+.B NSAP-PTR
+NSAP pointer (domain name)
+.PP
+The following are new types as per RFC 1664 and RFC 1712.
+Note that the GPOS type has been withdrawn already, and will be
+superseded by the LOC type.
+.TP 10
+.B PX
+X400 to RFC822 mapping (preference value, rfc822 domain, x400 domain)
+.TP
+.B GPOS
+Geographical position (longitude string, latitude string, altitude string)
+.PP
+The following types have already been reserved in RFC 1700, but are
+not yet implemented.
+.TP 10
+.B SIG
+Security signature
+.TP
+.B KEY
+Security key
+.TP
+.B AAAA
+IP v6 address
+.TP
+.B LOC
+Geographical location
+.SH FAILURE MESSAGES
+The following messages are printed to show the reason
+of failure for a particular query. The name of an explicit
+server, if specified, may be included. If a special class
+was requested, it is also shown.
+.TP 4
+Nameserver [\fIserver\fP] not running
+The contacted server host does not have a nameserver running.
+.TP
+Nameserver [\fIserver\fP] not responding
+The nameserver at the contacted server host did not give a reply
+within the specified time frame.
+.TP
+Nameserver [\fIserver\fP] not reachable
+The network route to the intended server host is blocked.
+.TP
+\fIname\fP does not exist [at \fIserver\fP] (Authoritative answer)
+The queryname does definitely not exist at all.
+.TP
+\fIname\fP does not exist [at \fIserver\fP], try again
+The queryname does not exist, but the answer was not authoritative,
+so it is still undecided.
+.TP
+\fIname\fP has no \fItype\fP record [at \fIserver\fP] (Authoritative answer)
+The queryname is valid, but the specified type does not exist.
+This status is here returned only in case authoritative.
+.TP
+\fIname\fP \fItype\fP record currently not present [at \fIserver\fP]
+The specified type does not exist, but we don't know whether
+the queryname is valid or not. The answer was not authoritative.
+Perhaps recursion was off, and no data was cached locally.
+.TP
+\fIname\fP \fItype\fP record not found [at \fIserver\fP], try again
+Some intermediate failure, e.g. timeout reaching a nameserver.
+.TP
+\fIname\fP \fItype\fP record not found [at \fIserver\fP], server failure
+Some explicit nameserver failure to process the query, due to internal
+or forwarding errors. This may also be returned if the zone data has
+expired at a secondary server, of when the server is not authoritative
+for some class.
+.TP
+\fIname\fP \fItype\fP record not found [at \fIserver\fP], no recovery
+Some irrecoverable format error, or server refusal.
+.TP
+\fIname\fP \fItype\fP record query refused [by \fIserver\fP]
+The contacted nameserver explicitly refused to answer the query.
+Some nameservers are configured to refuse zone transfer requests
+that come from arbitrary clients.
+.TP
+\fIname\fP \fItype\fP record not found [at \fIserver\fP]
+The exact reason for failure could not be determined.
+(This should not happen).
+.TP
+\fIzone\fP has lame delegation to \fIserver\fP
+If we query a supposedly authoritative nameserver for the SOA record
+of a zone, the information should be available and the answer should
+be authoritative. If not, a lame delegation is flagged. This is also
+done if the server turns out not to exist at all. Ditto if we ask for
+a zone transfer and the server cannot provide it.
+.TP
+No nameservers for \fIzone\fP found
+It was not possible to retrieve the name of any nameserver
+for the desired zone, in order to do a zone transfer.
+.TP
+No addresses of nameservers for \fIzone\fP found
+We got some nameserver names, but it was not possible to retrieve
+addresses for any of them.
+.TP
+No nameservers for \fIzone\fP responded
+When trying all nameservers in succession to do a zone transfer,
+none of them were able or willing to provide it.
+.SH WARNING AND ERROR MESSAGES
+Miscellaneous warning messages may be generated.
+They are preceded by " !!! " and indicate some non-fatal condition,
+usually during the interpretation of the retrieved data.
+These messages can be suppressed with the \-q command line option.
+.sp
+Error messages are preceded by " *** " and indicate a serious problem,
+such as format errors in the answers to queries, but also major
+violations of the specifications.
+Those messages cannot be suppressed.
+.TP 4
+\fIzone\fP has only one nameserver \fIserver\fP
+When retrieving the nameservers for a zone, it appears that only one
+single nameserver exists. This is against the recommendations.
+.TP
+\fIzone\fP nameserver \fIserver\fP is not canonical (\fIrealserver\fP)
+When retrieving the nameservers for a zone, the name of the specified
+server appears not to be canonical. This may cause serious operational
+problems. The canonical name is given between parentheses.
+.TP
+empty zone transfer for \fIzone\fP from \fIserver\fP
+The zone transfer from the specified server contained no data, perhaps
+only the SOA record. This could happen if we query the victim of a
+lame delegation which happens to have the SOA record in its cache.
+.TP
+extraneous NS record for \fIname\fP within \fIzone\fP from \fIserver\fP
+During a zone transfer, an NS record appears for a name which is not
+a delegated subzone of the current zone.
+.TP
+extraneous SOA record for \fIname\fP within \fIzone\fP from \fIserver\fP
+During a zone transfer, an SOA record appears for a name which is
+not the name of the current zone.
+.TP
+extraneous glue record for \fIname\fP within \fIzone\fP from \fIserver\fP
+During a zone transfer, a glue record is included for a name which
+is not part of the zone or its delegated subzones. This is done in some
+older versions of BIND. It is undesirable since unauthoritative, or even
+incorrect, information may be propagated.
+.TP
+incomplete \fItype\fP record for \fIname\fP
+When decoding the resource record data from the answer to a query,
+not all required data fields were present. This is frequently the case
+for HINFO records of which only one of the two data field is encoded.
+.TP
+\fIname\fP has both NS and A records within \fIzone\fP from \fIserver\fP
+An A record has been defined for the delegated zone \fIname\fP. This is
+signalled only during the transfer of the parent \fIzone\fP. It is not
+an error, but the overall hostcount may be wrong, since the A record
+is counted as a host in the parent zone. This A record is not included
+in the hostcount of the delegated zone.
+.TP
+\fIname\fP \fItype\fP records have different ttl within \fIzone\fP from \fIserver\fP
+Resource records of the same name/type/class should have the same ttl value
+in zone listings. This is sometimes not the case, due to the independent
+definition of glue records or other information in the parent zone, which
+is not kept in sync with the definition in the delegated zone.
+.TP
+\fIname\fP \fItype\fP record has illegal name
+The name of an A or MX record contains invalid characters.
+Only alphanumeric characters and hyphen '-' are valid in
+components (labels) between dots.
+.TP
+\fIname\fP \fItype\fP host \fIserver\fP has illegal name
+The name of an NS or MX target host contains invalid characters.
+Only alphanumeric characters and hyphen '-' are valid in
+components (labels) between dots.
+.TP
+\fIname\fP \fItype\fP host \fIserver\fP does not exist
+The NS or MX target host \fIserver\fP does not exist at all.
+In case of NS, a lame delegation of \fIname\fP to \fIserver\fP
+is flagged.
+.TP
+\fIname\fP \fItype\fP host \fIserver\fP has no A record
+The NS or MX target host \fIserver\fP has no address.
+In case of NS, a lame delegation of \fIname\fP to \fIserver\fP
+is flagged.
+.TP
+\fIname\fP \fItype\fP host \fIserver\fP is not canonical
+The NS or MX target host \fIserver\fP is not a canonical name.
+This may cause serious operational problems during domain data
+retrieval, or electronic mail delivery.
+.TP
+\fIname\fP address \fIA.B.C.D\fP is not registered
+The reverse lookup of the address of an A record failed in an
+authoritative fashion. It was not present in the corresponding
+in-addr.arpa zone.
+.TP
+\fIname\fP address \fIA.B.C.D\fP maps to \fIrealname\fP
+The reverse lookup of the address of an A record succeeded,
+but it did not map back to the name of the A record.
+There may be A records with different names for the same address.
+In the reverse in-addr.arpa zone there is usually only one PTR to
+the ``official'' host name.
+.TP
+\fIzone\fP SOA record at \fIserver\fP is not authoritative
+When checking the SOA for a zone at one of its supposedly
+authoritative nameservers, the SOA information turns out
+to be not authoritative. This could be determined by making
+a query without nameserver recursion turned on.
+.TP
+\fIzone\fP SOA primary \fIserver\fP is not advertised via NS
+The primary nameserver is not among the list of nameservers
+retrieved via NS records for the zone.
+This is not an error per se, since only publicly accessible
+nameservers may be advertised, and others may be behind a
+firewall.
+.TP
+\fIzone\fP SOA primary \fIserver\fP has illegal name
+The name of the primary nameserver contains invalid characters.
+.TP
+\fIzone\fP SOA hostmaster \fImailbox\fP has illegal mailbox
+The name of the hostmaster mailbox contains invalid characters.
+A common mistake is to use an RFC822 email address with a ``@'',
+whereas the at-sign should have been replaced with a dot.
+.TP
+\fIzone\fP SOA serial has high bit set
+Although the serial number is an unsigned 32-bit value, overflow
+into the high bit can inadvertently occur by making inappropriate
+use of the dotted decimal notation in the zone file. This may lead
+to synchronization failures between primary and secondary servers.
+.TP
+\fIzone\fP SOA retry exceeds refresh
+A failing refresh would be retried after it is time for the
+next refresh.
+.TP
+\fIzone\fP SOA refresh+retry exceeds expire
+The retry after a failing refresh would be done after the data
+has already expired.
+.TP
+\fIserver1\fP and \fIserver2\fP have different primary for \fIzone\fP
+If the SOA record is different, the zone data is probably different
+as well. What you get depends on which server you happen to query.
+.TP
+\fIserver1\fP and \fIserver2\fP have different hostmaster for \fIzone\fP
+If the SOA record is different, the zone data is probably different
+as well. What you get depends on which server you happen to query.
+.TP
+\fIserver1\fP and \fIserver2\fP have different serial for \fIzone\fP
+This is usually not an error, but happens during the period after the
+primary server has updated its zone data, but before a secondary
+performed a refresh. Nevertheless there could be an error if a mistake
+has been made in properly adapting the serial number.
+.TP
+\fIserver1\fP and \fIserver2\fP have different refresh for \fIzone\fP
+If the SOA record is different, the zone data is probably different
+as well. What you get depends on which server you happen to query.
+.TP
+\fIserver1\fP and \fIserver2\fP have different retry for \fIzone\fP
+If the SOA record is different, the zone data is probably different
+as well. What you get depends on which server you happen to query.
+.TP
+\fIserver1\fP and \fIserver2\fP have different expire for \fIzone\fP
+If the SOA record is different, the zone data is probably different
+as well. What you get depends on which server you happen to query.
+.TP
+\fIserver1\fP and \fIserver2\fP have different defttl for \fIzone\fP
+If the SOA record is different, the zone data is probably different
+as well. What you get depends on which server you happen to query.
+.SH EXIT STATUS
+The program returns a zero exit status if the requested information
+could be retrieved successfully, or in case zone listings or SOA
+checks were performed without any serious error.
+Otherwise it returns a non-zero exit status.
+.SH CUSTOMIZING HOST NAME LOOKUP
+In general, if the name supplied by the user does not have any dots
+in it, a default domain is appended to the end. This domain is usually
+defined in the \fB/etc/resolv.conf\fP file. If not, it is derived by
+taking the local hostname and taking everything after its first dot.
+.PP
+The user can override this, and specify a different default domain,
+by defining it in the environment variable \fILOCALDOMAIN\fP.
+.PP
+In addition, the user can supply his own single-word abbreviations
+for host names. They should be in a file consisting of one line per
+abbreviation. Each line contains an abbreviation, white space, and
+then the fully qualified host name. The name of this file must be
+specified in the environment variable \fIHOSTALIASES\fP.
+.SH SPECIAL CONSIDERATIONS
+The complete set of resource record information for a domain name
+is available from an authoritative nameserver only. Therefore,
+if you query another server with the "-a" option, only a subset
+of the data may be presented, since this option asks for any data
+that the latter server currently knows about, not all data that
+may possibly exist. Note that the "-v" option shows whether an
+answer is authoritative or not.
+.PP
+When listing a zone with the "-l" option, information will be fetched
+from authoritative nameservers for that zone. This is implemented by
+doing a complete zone transfer and then filtering out the information
+that you have asked for.
+Note that direct contact with such nameservers must be possible for
+this option to work.
+This option should be used with caution. Servers may be configured
+to refuse zone transfers if they are flooded with requests.
+.SH RELATED DOCUMENTATION
+rfc920, rfc952, rfc974, rfc1032, rfc1033, rfc1034, rfc1035,
+rfc1101, rfc1183, rfc1348, rfc1535, rfc1536, rfc1537, rfc1637,
+rfc1664, rfc1712
+.SH AUTHOR
+This program is originally from Rutgers University.
+.br
+Rewritten by Eric Wassenaar, Nikhef-H, <e07@nikhef.nl>
+.SH "SEE ALSO"
+named(8), resolv.conf(5), resolver(3)
diff --git a/usr.sbin/named/man/hostname.7 b/usr.sbin/named/man/hostname.7
new file mode 100644
index 00000000000..f19d84b4de8
--- /dev/null
+++ b/usr.sbin/named/man/hostname.7
@@ -0,0 +1,110 @@
+.\" $NetBSD: hostname.7,v 1.1 1996/02/02 15:27:32 mrg Exp $
+.\"
+.\" Copyright (c) 1987 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley. The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" @(#)hostname.7 6.4 (Berkeley) 1/16/90
+.\"
+.TH HOSTNAME 7 "February 16, 1994"
+.UC 5
+.SH NAME
+hostname \- host name resolution description
+.SH DESCRIPTION
+Hostnames are domains. A domain is a hierarchical, dot-separated list
+of subdomains. For example, the machine \fImonet\fP, in the \fIBerkeley\fP
+subdomain of the \fIEDU\fP subdomain of the Internet Domain Name System
+would be represented as
+.br
+ \fImonet\fP.\fIBerkeley\fP.\fIEDU\fP
+.br
+(with no trailing dot).
+.PP
+Hostnames are often used with network client and server programs,
+which must generally translate the name to an address for use.
+(This task is usually performed by the library routine
+.IR gethostbyname (3).)
+The default method for resolving hostnames by the Internet name resolver is
+to follow \s-1RFC\s+1 1535's security recommendations. Actions can be taken
+by the administrator to override these recommendations and to have the
+resolver behave the same as earlier, non-\s-1RFC\s+1 1535 resolvers.
+.PP
+The default method (using \s-1RFC\s+1 1535 guidelines) follows:
+.PP
+If the name consists of a single component, i.e. contains no dot, and if the
+environment variable ``\s-1HOSTALIASES\s+1'' is set to the name of a file,
+that file is searched for a string matching the input hostname. The file
+should consist of lines made up of two strings separated by white-space, the
+first of which is the hostname alias, and the second of which is the complete
+hostname to be substituted for that alias. If a case-insensitive match is
+found between the hostname to be resolved and the first field of a line in
+the file, the substituted name is looked up with no further processing.
+.PP
+If there is at least one dot in the name, then the name is first tried as
+is. The number of dots to cause this action is configurable by setting the
+threshold using the ``\fIndots\fP'' option in
+.I /etc/resolv.conf
+(default: \fI1\fP). If the name ends with a dot, the trailing dot is
+removed, and the remaining name is looked up (regardless of the setting of
+the 'ndots' option) and no further processing is done.
+.PP
+If the input name does not end with a trailing dot, it is looked up by
+searching through a list of domains until a match is found. If neither the
+search option in the
+.I /etc/resolv.conf
+file or the ``\s-1LOCALDOMAIN\s+1'' environment variable is used, then the
+search list of domains contains only the full domain specified by the domain
+option (in
+.IR /etc/resolv.conf )
+or the domain used in the local hostname (see
+.IR hostname (1)
+and
+.IR resolver (5)).
+For example, if the ``\fIdomain\fP'' option is set to \fICS.Berkeley.EDU\fP,
+then only CS.Berkeley.EDU will be in the search list and will be the only
+domain appended to the partial hostname, for example, ``\fIlithium\fP'',
+making \fIlithium.CS.Berkeley.EDU\fP the only name to be tried using the
+search list.
+.PP
+If the search option is used in
+.I /etc/resolv.conf
+or the environment variable, ``\s-1LOCALDOMAIN\s+1'' is set by the user, then
+the search list will include what is set by these methods. For
+example, if the ``\fIsearch\fP'' option contained
+.br
+ \fICS.Berkeley.EDU CChem.Berkeley.EDU Berkeley.EDU\fP
+.br
+then the partial hostname (e.g., ``\fIlithium\fP'') will be tried with each
+domainname appended (in the same order specified). The resulting hostnames
+that would be tried are:
+.nf
+ \fIlithium.CS.Berkeley.EDU\fP
+ \fIlithium.CChem.Berkeley.EDU\fP
+ \fIlithium.Berkeley.EDU\fP
+.fi
+.PP
+The environment variable ``\s-1LOCALDOMAIN\s+1'' overrides the
+``\fIsearch\fP'' and ``\fIdomain\fP'' options, and if both search and domain
+options are present in the resolver configuration file, then only the last
+one listed is used (see
+.IR resolver (5)).
+.PP
+If the name was not previously tried ``as is'' (i.e., it fell below the
+``\fIndots\fP'' threshold or did not contain a dot), then the name as
+originally provided is attempted.
+.SH SEE ALSO
+.IR gethostbyname (3),
+.IR resolver (5),
+.IR mailaddr (7),
+.IR named (8)
diff --git a/usr.sbin/named/man/mailaddr.7 b/usr.sbin/named/man/mailaddr.7
new file mode 100644
index 00000000000..517e31fcfe4
--- /dev/null
+++ b/usr.sbin/named/man/mailaddr.7
@@ -0,0 +1,137 @@
+.\" $NetBSD: mailaddr.7,v 1.1 1996/02/02 15:27:34 mrg Exp $
+.\"
+.\" Copyright (c) 1983, 1987 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley. The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" @(#)mailaddr.7 6.5 (Berkeley) 2/14/89
+.\"
+.TH MAILADDR 7 "February 14, 1989"
+.UC 5
+.SH NAME
+mailaddr \- mail addressing description
+.SH DESCRIPTION
+Mail addresses are based on the ARPANET protocol listed at the end of this
+manual page. These addresses are in the general format
+.PP
+ user@domain
+.PP
+where a domain is a hierarchical dot separated list of subdomains. For
+example, the address
+.PP
+ eric@monet.berkeley.edu
+.PP
+is normally interpreted from right to left: the message should go to the
+ARPA name tables (which do not correspond exactly to the physical ARPANET),
+then to the Berkeley gateway, after which it should go to the local host
+monet. When the message reaches monet it is delivered to the user ``eric''.
+.PP
+Unlike some other forms of addressing, this does not imply any routing.
+Thus, although this address is specified as an ARPA address, it might
+travel by an alternate route if that were more convenient or efficient.
+For example, at Berkeley, the associated message would probably go directly
+to monet over the Ethernet rather than going via the Berkeley ARPANET
+gateway.
+.SS Abbreviation.
+.PP
+Under certain circumstances it may not be necessary to type the entire
+domain name. In general, anything following the first dot may be omitted
+if it is the same as the domain from which you are sending the message.
+For example, a user on ``calder.berkeley.edu'' could send to ``eric@monet''
+without adding the ``berkeley.edu'' since it is the same on both sending
+and receiving hosts.
+.PP
+Certain other abbreviations may be permitted as special cases. For
+example, at Berkeley, ARPANET hosts may be referenced without adding
+the ``berkeley.edu'' as long as their names do not conflict with a local
+host name.
+.SS Compatibility.
+.PP
+Certain old address formats are converted to the new format to provide
+compatibility with the previous mail system. In particular,
+.PP
+ user@host.ARPA
+.PP
+is allowed and
+.PP
+ host:user
+.PP
+is converted to
+.PP
+ user@host
+.PP
+to be consistent with the \fIrcp\fP(1) command.
+.PP
+Also, the syntax
+.PP
+ host!user
+.PP
+is converted to:
+.PP
+ user@host.UUCP
+.PP
+This is normally converted back to the ``host!user'' form before being sent
+on for compatibility with older UUCP hosts.
+.PP
+The current implementation is not able to route messages automatically through
+the UUCP network. Until that time you must explicitly tell the mail system
+which hosts to send your message through to get to your final destination.
+.SS Case Distinctions.
+.PP
+Domain names (i.e., anything after the ``@'' sign) may be given in any mixture
+of upper and lower case with the exception of UUCP hostnames. Most hosts
+accept any combination of case in user names, with the notable exception of
+MULTICS sites.
+.SS Route-addrs.
+.PP
+Under some circumstances it may be necessary to route a message through
+several hosts to get it to the final destination. Normally this routing
+is done automatically, but sometimes it is desirable to route the message
+manually. Addresses which show these relays are termed ``route-addrs.''
+These use the syntax:
+.PP
+ <@hosta,@hostb:user@hostc>
+.PP
+This specifies that the message should be sent to hosta, from there to hostb,
+and finally to hostc. This path is forced even if there is a more efficient
+path to hostc.
+.PP
+Route-addrs occur frequently on return addresses, since these are generally
+augmented by the software at each host. It is generally possible to ignore
+all but the ``user@domain'' part of the address to determine the actual
+sender.
+.SS Postmaster.
+.PP
+Every site is required to have a user or user alias designated ``postmaster''
+to which problems with the mail system may be addressed.
+.SS Other Networks.
+.PP
+Some other networks can be reached by giving the name of the network as the
+last component of the domain. \fIThis is not a standard feature\fP and may
+not be supported at all sites. For example, messages to CSNET or BITNET sites
+can often be sent to ``user@host.CSNET'' or ``user@host.BITNET'' respectively.
+.SH BUGS
+The RFC822 group syntax (``group:user1,user2,user3;'') is not supported
+except in the special case of ``group:;'' because of a conflict with old
+berknet-style addresses.
+.PP
+Route-Address syntax is grotty.
+.PP
+UUCP- and ARPANET-style addresses do not coexist politely.
+.SH SEE ALSO
+mail(1), sendmail(8);
+Crocker, D. H.,
+.ul
+Standard for the Format of Arpa Internet Text Messages,
+RFC822.
diff --git a/usr.sbin/named/man/named-xfer.8 b/usr.sbin/named/man/named-xfer.8
new file mode 100644
index 00000000000..7f94bcff120
--- /dev/null
+++ b/usr.sbin/named/man/named-xfer.8
@@ -0,0 +1,148 @@
+.\" $NetBSD: named-xfer.8,v 1.1 1996/02/02 15:27:37 mrg Exp $
+.\"
+.\" ++Copyright++ 1985
+.\" -
+.\" Copyright (c) 1985
+.\" 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--
+.\"
+.\" from named.8 6.6 (Berkeley) 2/14/89
+.\"
+.TH NAMED-XFER 8 "June 26, 1993"
+.UC 4
+.SH NAME
+named-xfer \- ancillary agent for inbound zone transfers
+.SH SYNOPSIS
+.B named-xfer
+.B \-z
+.I zone_to_transfer
+.B \-f
+.I db_file
+.B \-s
+.I serial_no
+[
+.B \-d
+.I debuglevel
+] [
+.B \-l
+.I debug_log_file
+] [
+.B \-t
+.I trace_file
+] [
+.B \-p
+.I port#
+] [
+.B \-S
+]
+.I nameserver
+...
+.SH DESCRIPTION
+.I Named-xfer
+is an ancillary program executed by
+.IR named (8)
+to perform an inbound zone transfer. It is rarely executed directly, and
+only by system administrators who are trying to debug a zone transfer problem.
+See RFC's 1033, 1034, and 1035 for more information on the Internet
+name-domain system.
+.PP
+Options are:
+.TP
+.B \-z
+specifies the name of the zone to be transferred.
+.TP
+.B \-f
+specifies the name of the file into which the zone should be dumped
+when it is received from the primary server.
+.TP
+.B \-s
+specifies the serial number of our current copy of this zone. If the
+\s-1SOA RR\s+1 we get from the primary server does not have a serial
+number higher than this, the transfer will be aborted.
+.TP
+.B \-d
+Print debugging information.
+A number after the ``d'' determines the level of
+messages printed.
+.TP
+.B \-l
+Specifies a log file for debugging messages. The default is system-
+dependent but is usually in
+.I /var/tmp
+or
+.IR /usr/tmp .
+Note that this only applies if
+.I \-d
+is also specified.
+.TP
+.B \-t
+Specifies a trace file which will contain a protocol trace of the zone
+transfer. This is probably only of interest to people debugging the name
+server itself.
+.TP
+.B \-p
+Use a different port number. The default is the standard port number
+as returned by getservbyname(3) for service ``domain''.
+.TP
+.B \-S
+Perform a restricted transfer of only the SOA, NS records and glue A records
+for the zone. The SOA record will not be loaded by named but will be used to
+determine when to verify the NS records. See the ``stubs'' directive in
+.IR named (8)
+for more information.
+.PP
+Additional arguments are taken as name server addresses in so-called
+``dotted-quad'' syntax only; no host name are allowed here. At least
+one address must be specified. Any additional addresses will be tried
+in order if the first one fails to transfer to us successfully.
+.SH "SEE ALSO"
+named(8), resolver(3), resolver(5), hostname(7),
+RFC 882, RFC 883, RFC 973, RFC 974, RFC 1033, RFC 1034, RFC 1035, RFC 1123,
+\fIName Server Operations Guide for \s-1BIND\s+1\fR
diff --git a/usr.sbin/named/man/named.8 b/usr.sbin/named/man/named.8
new file mode 100644
index 00000000000..297b8b8819e
--- /dev/null
+++ b/usr.sbin/named/man/named.8
@@ -0,0 +1,422 @@
+.\" $NetBSD: named.8,v 1.1 1996/02/02 15:27:39 mrg Exp $
+.\"
+.\" ++Copyright++ 1985
+.\" -
+.\" Copyright (c) 1985
+.\" 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--
+.\"
+.\" @(#)named.8 6.6 (Berkeley) 2/14/89
+.\"
+.TH NAMED 8 "June 20, 1995"
+.UC 4
+.SH NAME
+named \- Internet domain name server
+.SH SYNOPSIS
+.B named
+[
+.B \-d
+.I debuglevel
+] [
+.B \-p
+.IR port# [\fB/\fP\fIlocalport#\fP]
+] [{\-b}
+.I bootfile
+] [
+.B \-q
+] [
+.B \-r
+]
+.SH DESCRIPTION
+.I Named
+is the Internet domain name server.
+See RFC's 1033, 1034, and 1035 for more information on the Internet
+name-domain system. Without any arguments,
+.I named
+will read the default boot file
+.IR /etc/named.boot ,
+read any initial data and listen for queries.
+.PP
+Options are:
+.TP
+.B \-d
+Print debugging information.
+A number after the ``d'' determines the level of
+messages printed.
+.TP
+.B \-p
+Use nonstandard port numbers. The default is the standard port number
+as returned by getservbyname(3) for service ``domain''.
+The argument can specify two port numbers separated by a slash (``\fB/\fP'')
+in which case the first port is that used when contacting remote servers,
+and the second one is the service port bound by the local instance of
+.IR named .
+This is used mostly for debugging purposes.
+.TP
+.B \-b
+Use an alternate boot file. This is optional and allows you to
+specify a file with a leading dash.
+.TP
+.B \-q
+Trace all incoming queries if \fInamed\fP has been compiled with
+\fIQRYLOG\fP defined. \fINOTE:\fP this option is deprecated in favour
+of the boot file directive ``options query-log''.
+.TP
+.B \-r
+Turns recursion off in the server. Answers can come only from local
+(primary or secondary) zones. This can be used on root servers.
+\fINOTE:\fP this option is deprecated in favour
+of the boot file directive ``options no-recursion''.
+.PP
+Any additional argument is taken as the name of the boot file.
+If multiple boot files are specified, only the last is used.
+.PP
+The boot file contains information about where the name server is to get
+its initial data.
+Lines in the boot file cannot be continued on subsequent lines.
+The following is a small example:
+.in +2m
+.nf
+
+;
+; boot file for name server
+;
+directory /usr/local/adm/named
+
+.ta \w'forwarders\ 'u +\w'6.32.128.IN-ADDR.ARPA\ 'u +\w'128.32.137.8 128.32.137.3\ 'u
+; type domain source host/file backup file
+
+cache . root.cache
+primary Berkeley.EDU berkeley.edu.zone
+primary 32.128.IN-ADDR.ARPA ucbhosts.rev
+secondary CC.Berkeley.EDU 128.32.137.8 128.32.137.3 cc.zone.bak
+secondary 6.32.128.IN-ADDR.ARPA 128.32.137.8 128.32.137.3 cc.rev.bak
+primary 0.0.127.IN-ADDR.ARPA localhost.rev
+forwarders 10.0.0.78 10.2.0.78
+limit transfers-in 10
+limit datasize 64M
+options forward-only query-log fake-iquery
+
+.DT
+.fi
+.in
+The ``directory'' line causes the server to change its working directory to
+the directory specified. This can be important for the correct processing
+of \s-1$INCLUDE\s+1 files in primary zone files.
+.LP
+The ``cache'' line specifies that data in ``root.cache'' is to be placed in
+the backup cache. Its main use is to specify data such as locations of root
+domain servers. This cache is not used during normal operation, but is used
+as ``hints'' to find the current root servers. The file ``root.cache'' is
+in the same format as ``berkeley.edu.zone''. There can be more than one
+``cache'' file specified. The ``root.cache'' file should be retrieved
+periodically from \s-1FTP.RS.INTERNIC.NET\s+1 since it contains a list of
+root servers, and this list changes periodically.
+.LP
+The first example ``primary'' line states that the file
+``berkeley.edu.zone'' contains authoritative data for the ``Berkeley.EDU''
+zone. The file ``berkeley.edu.zone'' contains data in the master file
+format described in RFC 883. All domain names are relative to the origin, in
+this case, ``Berkeley.EDU'' (see below for a more detailed description).
+The second ``primary'' line states that the file ``ucbhosts.rev'' contains
+authoritative data for the domain ``32.128.IN-ADDR.ARPA,'' which is used to
+translate addresses in network 128.32 to hostnames. Each master file should
+begin with an SOA record for the zone (see below).
+.LP
+The first example ``secondary'' line specifies that all authoritative data
+under ``CC.Berkeley.EDU'' is to be transferred from the name server at
+128.32.137.8. If the transfer fails it will try 128.32.137.3 and continue
+trying the addresses, up to 10, listed on this line. The secondary copy is
+also authoritative for the specified domain. The first non-dotted-quad
+address on this line will be taken as a filename in which to backup the
+transferred zone. The name server will load the zone from this backup file
+if it exists when it boots, providing a complete copy even if the master
+servers are unreachable. Whenever a new copy of the domain is received by
+automatic zone transfer from one of the master servers, this file will be
+updated. If no file name is given, a temporary file will be used, and will
+be deleted after each successful zone transfer. This is not recommended
+since it is a needless waste of bandwidth. The second example ``secondary''
+line states that the address-to-hostname mapping for the subnet 128.32.136
+should be obtained from the same list of master servers as the previous zone.
+.LP
+The ``forwarders'' line specifies the addresses of sitewide servers that
+will accept recursive queries from other servers. If the boot file
+specifies one or more forwarders, then the server will send all queries for
+data not in the cache to the forwarders first. Each forwarder will be asked
+in turn until an answer is returned or the list is exhausted. If no answer
+is forthcoming from a forwarder, the server will continue as it would have
+without the forwarders line unless it is in ``forward-only'' mode. The
+forwarding facility is useful to cause a large sitewide cache to be
+generated on a master, and to reduce traffic over links to outside servers.
+It can also be used to allow servers to run that do not have direct access
+to the Internet, but wish to look up exterior names anyway.
+.LP
+The ``slave'' line (deprecated) is allowed for backward compatibility. Its
+meaning is identical to ``options forward-only''.
+.LP
+The ``sortlist'' line can be used to indicate networks that are to be
+preferred over other networks. Queries for host addresses from hosts on the
+same network as the server will receive responses with local network
+addresses listed first, then addresses on the sort list, then other
+addresses.
+.LP
+The ``xfrnets'' directive (not shown) can be used to implement primitive
+access control. If this directive is given, then your name server will
+only answer zone transfer requests from hosts which are on networks listed
+in your ``xfrnets'' directives. This directive may also be given as
+``tcplist'' for compatibility with older, interim servers.
+.LP
+The ``include'' directive (not shown) can be used to process the contents
+of some other file as though they appeared in place of the ``include''
+directive. This is useful if you have a lot of zones or if you have
+logical groupings of zones which are maintained by different people.
+The ``include'' directive takes one argument, that being the name of the
+file whose contents are to be included. No quotes are necessary around
+the file name.
+.LP
+The ``bogusns'' directive (not shown) tells \s-1BIND\s+1 that no queries
+are to be sent to the specified name server addresses (which are specified
+as dotted quads, not as domain names). This is useful when you know that
+some popular server has bad data in a zone or cache, and you want to avoid
+contamination while the problem is being fixed.
+.LP
+The ``limit'' directive can be used to change \s-1BIND\s+1's internal limits,
+some of which (\fBdatasize\fP, for example) are implemented by the system and
+others (like \fBtransfers-in\fP) by \s-1BIND\s+1 itself. The number following
+the limit name can be scaled by postfixing a ``k,'' ``m,'' or ``g'' for
+kilobytes, megabytes, and gigabytes respectively.
+\fBdatasize\fP's argument sets the process data size enforced by the kernel.
+\fINote:\fP not all systems provide a call to implement this -- on such
+systems, the use of the \fBdatasize\fP parameter of ``limit'' will result in
+a warning message.
+\fBtransfers-in\fP's argument is the number of \fInamed-xfer\fP subprocesses
+which \s-1BIND\s+1 will spawn at any one time.
+\fBtransfers-per-ns\fP's argument is the maximum number of zone transfers to
+be simultaneously initiated to any given remote name server.
+.LP
+The ``options'' directive introduces a boolean specifier that changes the
+behaviour of \s-1BIND\s+1. More than one option can be specified in a single
+directive. The currently defined options are as follows:
+\fBno-recursion\fP, which will cause \s-1BIND\s+1 to answer with a referral
+rather than actual data whenever it receives a query for a name it is not
+authoritative for -- don't set this on a server that is listed in any host's
+\fIresolv.conf\fP file;
+\fBno-fetch-glue\fP, which keeps \s-1BIND\s+1 from fetching missing glue when
+constructing the ``additional data'' section of a response; this can be used
+in conjunction with \fBno-recursion\fP to prevent \s-1BIND\s+1's cache from
+ever growing in size or becoming corrupted;
+\fBquery-log\fP, which causes all queries to be logged via
+syslog(8) -- this is a lot of data, don't turn it on lightly;
+\fBforward-only\fP, which causes the server to query only its forwarders --
+this option is normally used on machine that wishes to run a server but for
+physical or administrative reasons cannot be given access to the Internet;
+and \fBfake-iquery\fP, which tells \s-1BIND\s+1 to send back a useless and
+bogus reply to ``inverse queries'' rather than responding with an error --
+this is helpful if you have a lot of microcomputers or SunOS hosts or both.
+.LP
+The ``max-fetch'' directive (not shown) is allowed for backward compatibility;
+its meaning is identical to ``limit transfers-in''.
+.PP
+The master file consists of control information and a list of resource
+records for objects in the zone of the forms:
+.RS
+.nf
+
+$INCLUDE <filename> <opt_domain>
+$ORIGIN <domain>
+<domain> <opt_ttl> <opt_class> <type> <resource_record_data>
+
+.fi
+.RE
+where
+.I domain
+is "." for root, "@" for the current origin, or a standard domain
+name. If
+.I domain
+is a standard domain name that does not end with ``.'', the current origin
+is appended to the domain. Domain names ending with ``.'' are
+unmodified.
+The
+.I opt_domain
+field is used to define an origin for the data in an included file.
+It is equivalent to placing a $ORIGIN statement before the first
+line of the included file. The field is optional.
+Neither the
+.I opt_domain
+field nor $ORIGIN statements in the included file modify the current origin
+for this file.
+The
+.I opt_ttl
+field is an optional integer number for the time-to-live field.
+It defaults to zero, meaning the minimum value specified in the SOA
+record for the zone.
+The
+.I opt_class
+field is the object address type; currently only one type is supported,
+.BR IN ,
+for objects connected to the DARPA Internet.
+The
+.I type
+field contains one of the following tokens; the data expected in the
+.I resource_record_data
+field is in parentheses.
+.TP "\w'MINFO 'u"
+A
+a host address (dotted quad)
+.IP NS
+an authoritative name server (domain)
+.IP MX
+a mail exchanger (domain), preceded by a preference value (0..32767),
+with lower numeric values representing higher logical preferences.
+.IP CNAME
+the canonical name for an alias (domain)
+.IP SOA
+marks the start of a zone of authority (domain of originating host,
+domain address of maintainer, a serial number and the following
+parameters in seconds: refresh, retry, expire and minimum TTL (see RFC 883)).
+.IP NULL
+a null resource record (no format or data)
+.IP RP
+a Responsible Person for some domain name (mailbox, TXT-referral)
+.IP PTR
+a domain name pointer (domain)
+.IP HINFO
+host information (cpu_type OS_type)
+.PP
+Resource records normally end at the end of a line,
+but may be continued across lines between opening and closing parentheses.
+Comments are introduced by semicolons and continue to the end of the line.
+.PP
+Note that there are other resource record types, not shown here. You should
+consult the \s-1BIND\s+1 Operations Guide (``\s-1BOG\s+1'') for the complete
+list. Some resource record types may have been standardized in newer RFC's
+but not yet implemented in this version of \s-1BIND\s+1.
+.PP
+Each master zone file should begin with an SOA record for the zone.
+An example SOA record is as follows:
+.LP
+.nf
+@ IN SOA ucbvax.Berkeley.EDU. rwh.ucbvax.Berkeley.EDU. (
+ 1989020501 ; serial
+ 10800 ; refresh
+ 3600 ; retry
+ 3600000 ; expire
+ 86400 ) ; minimum
+.fi
+.LP
+The SOA specifies a serial number, which should be changed each time the
+master file is changed. Note that the serial number can be given as a
+dotted number, but this is a \fIvery\fP unwise thing to do since the
+translation to normal integers is via concatenation rather than
+multiplication and addition. You can spell out the year, month, day of
+month, and 0..99 version number and still fit inside the unsigned 32-bit
+size of this field. It's true that we will have to rethink this strategy in
+the year 4294 (Greg.) but we're not worried about it. Secondary servers
+check the serial number at intervals specified by the refresh time in
+seconds; if the serial number changes, a zone transfer will be done to load
+the new data. If a master server cannot be contacted when a refresh is due,
+the retry time specifies the interval at which refreshes should be attempted.
+If a master server cannot be contacted within the interval given by the
+expire time, all data from the zone is discarded by secondary servers. The
+minimum value is the time-to-live (``\s-1TTL\s+1'') used by records in the
+file with no explicit time-to-live value.
+.SH NOTES
+The boot file directives ``domain'' and ``suffixes'' have been
+obsoleted by a more useful resolver-based implementation of
+suffixing for partially qualified domain names. The prior mechanisms
+could fail under a number of situations, especially when then local
+nameserver did not have complete information.
+.sp
+The following signals have the specified effect when sent to the
+server process using the
+.IR kill (1)
+command.
+.IP SIGHUP
+Causes server to read named.boot and reload the database. If the server
+is built with the FORCED_RELOAD compile-time option, then SIGHUP will
+also cause the server to check the serial number on all secondary zones.
+Normally the serial numbers are only checked at the SOA-specified intervals.
+.IP SIGINT
+Dumps the current data base and cache to /var/tmp/named_dump.db
+.IP SIGIOT
+Dumps statistics data into /var/tmp/named.stats if the server is
+compiled with -DSTATS. Statistics data is appended to the file. Some
+systems use SIGABRT rather than SIGIOT for this.
+.IP SIGSYS
+Dumps the profiling data in /var/tmp if the server is compiled
+with profiling (server forks, chdirs and exits).
+.IP SIGTERM
+Dumps the primary and secondary database files.
+Used to save modified data on shutdown if the
+server is compiled with dynamic updating enabled.
+.IP SIGUSR1
+Turns on debugging; each SIGUSR1 increments debug level.
+(SIGEMT on older systems without SIGUSR1)
+.IP SIGUSR2
+Turns off debugging completely.
+(SIGFPE on older systems without SIGUSR2)
+.IP SIGWINCH
+Toggles logging of all incoming queries via syslog(8)
+(requires server to have been built with the QRYLOG option).
+.SH FILES
+.nf
+.ta \w'/var/tmp/named_dump.db 'u
+/etc/named.boot name server configuration boot file
+/etc/named.pid the process id (on older systems)
+/var/run/named.pid the process id (on newer systems)
+/var/tmp/named_dump.db dump of the name server database
+/var/tmp/named.run debug output
+/var/tmp/named.stats nameserver statistics data
+.fi
+.SH "SEE ALSO"
+kill(1), gethostbyname(3), signal(2),
+resolver(3), resolver(5), hostname(7),
+RFC 882, RFC 883, RFC 973, RFC 974, RFC 1033, RFC 1034, RFC 1035, RFC 1123,
+\fIName Server Operations Guide for \s-1BIND\s+1\fR
diff --git a/usr.sbin/named/man/named.reload.8 b/usr.sbin/named/man/named.reload.8
new file mode 100644
index 00000000000..9e3a66cdcea
--- /dev/null
+++ b/usr.sbin/named/man/named.reload.8
@@ -0,0 +1,71 @@
+.\" $NetBSD: named.reload.8,v 1.1 1996/02/02 15:27:42 mrg Exp $
+.\"
+.\" ++Copyright++ 1987, 1993
+.\" -
+.\" Copyright (c) 1987, 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--
+.\"
+.\" from hostname.7 6.4 (Berkeley) 1/16/90
+.\"
+.TH NAMED.RELOAD 8 "June 26, 1993"
+.UC 5
+.SH NAME
+named.reload \- cause the name server to synchronize its database
+.SH DESCRIPTION
+This command sends a \s-1SIGHUP\s+1 to the running name server. This
+signal is documented in
+.IR named (8).
+.SH BUGS
+Does not check to see if the name server is actually running, and could
+use a stale PID cache file which may result in the death of an unrelated
+process.
+.SH SEE ALSO
+named(8), named.restart(8)
diff --git a/usr.sbin/named/man/named.restart.8 b/usr.sbin/named/man/named.restart.8
new file mode 100644
index 00000000000..3bcc4b3ee6c
--- /dev/null
+++ b/usr.sbin/named/man/named.restart.8
@@ -0,0 +1,75 @@
+.\" $NetBSD: named.restart.8,v 1.1 1996/02/02 15:27:45 mrg Exp $
+.\"
+.\" ++Copyright++ 1987, 1993
+.\" -
+.\" Copyright (c) 1987, 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--
+.\"
+.\" from hostname.7 6.4 (Berkeley) 1/16/90
+.\"
+.TH NAMED.RESTART 8 "June 26, 1993"
+.UC 5
+.SH NAME
+named.restart \- stop and restart the name server
+.SH DESCRIPTION
+This command sends a \s-1SIGKILL\s+1 to the running name server and then
+starts a new one.
+.SH BUGS
+Does not check to see if the name server is actually running, and could
+use a stale PID cache file which may result in the death of an unrelated
+process.
+.PP
+Does not wait after killing the old server before starting a new one; since
+the server could take some time to die and the new one will experience a
+fatal error if the old one isn't gone by the time it starts, you can be left
+in a situation where you have no name server at all.
+.SH SEE ALSO
+named(8), named.reload(8)
diff --git a/usr.sbin/named/man/ndc.8 b/usr.sbin/named/man/ndc.8
new file mode 100644
index 00000000000..f8799e169a5
--- /dev/null
+++ b/usr.sbin/named/man/ndc.8
@@ -0,0 +1,129 @@
+.\" $NetBSD: ndc.8,v 1.1 1996/02/02 15:27:48 mrg Exp $
+.\"
+.\" Copyright (c) 1994
+.\" 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.
+.\"
+.TH NDC 8 "November 27, 1994"
+.UC 5
+.SH NAME
+ndc \- name daemon control interface
+.SH SYNOPSIS
+.B ndc
+.I directive
+[ ... ]
+.SH DESCRIPTION
+This command allows the name server administrator to send various signals
+to the name server, or to restart it. Zero or more directives may be given,
+from the following list:
+.TP
+.B status
+Displays the current status of
+.B named
+as shown by
+.BR ps (1).
+.TP
+.B dumpdb
+Causes
+.B named
+to dump its database and cache to
+.B /var/tmp/named_dump.db
+(uses the INT signal.)
+.TP
+.B reload
+Causes
+.B named
+to check the serial numbers of all primary and secondary zones
+and to reload those that have changed (uses the HUP signal.)
+.TP
+.B stats
+Causes
+.B named
+to dump its statistics to
+.B /var/tmp/named.stats
+(uses the IOT or ABRT signal.)
+.TP
+.B trace
+Causes
+.B named
+to increment its ``tracing level'' by one. Whenever the tracing level
+is nonzero, trace information will be written to
+.BR /var/tmp/named.run .
+Higher tracing levels result in more detailed information.
+(Uses the USR1 signal.)
+.TP
+.B notrace
+Causes
+.B named
+to set its ``tracing level'' to zero, closing
+.B /var/tmp/named.run
+if it is open (uses the USR2 signal.)
+.TP
+.B querylog
+Causes
+.B named
+to toggle the ``query logging'' feature, which while on will result in a
+.BR syslog (3)
+of each incoming query (uses the WINCH signal.) Note that query logging
+consumes quite a lot of log file space. This directive may also be given as
+.BR qrylog .
+.TP
+.B start
+Causes
+.B named
+to be started, as long as it isn't already running.
+.TP
+.B stop
+Causes
+.B named
+to be stopped, if it is running.
+.TP
+.B restart
+Causes
+.B named
+to be killed and restarted.
+.SH BUGS
+Arguments to
+.B named
+are not preserved by
+.BR restart ,
+or known by
+.BR start .
+Some mechanism for controlling the parameters and environment should exist.
+.PP
+Implemented as a
+.BR sh (1)
+script.
+.SH AUTHOR
+Paul Vixie (Internet Software Consortium)
+.SH SEE ALSO
+named(8),
+named.reload(8),
+named.restart(8)
diff --git a/usr.sbin/named/man/nslookup.8 b/usr.sbin/named/man/nslookup.8
new file mode 100644
index 00000000000..ca8189d53ca
--- /dev/null
+++ b/usr.sbin/named/man/nslookup.8
@@ -0,0 +1,388 @@
+.\" $NetBSD: nslookup.8,v 1.1 1996/02/02 15:27:51 mrg Exp $
+.\"
+.\" ++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--
+.\"
+.\" @(#)nslookup.8 5.3 (Berkeley) 6/24/90
+.\"
+.TH NSLOOKUP 8 "June 24, 1990"
+.UC 6
+.SH NAME
+nslookup \- query Internet name servers interactively
+.SH SYNOPSIS
+.B nslookup
+[
+.I \-option ...
+]
+[
+.I host-to-find
+| \- [
+.I server
+]]
+.SH DESCRIPTION
+.I Nslookup
+is a program to query Internet domain name servers.
+Nslookup has two modes: interactive and non-interactive.
+Interactive mode allows the user to query name servers for
+information about various hosts and domains or to print a list of hosts
+in a domain.
+Non-interactive mode is used to print just the name and requested information
+for a host or domain.
+.sp 1
+.SH ARGUMENTS
+Interactive mode is entered in the following cases:
+.IP a) 4
+when no arguments are given (the default name server will be used),
+.IP b) 4
+when the first argument is a hyphen (\-) and the second argument
+is the host name or Internet address of a name server.
+.LP
+Non-interactive mode is used when the name or Internet address
+of the host to be looked up
+is given as the first argument. The optional second argument specifies
+the host name or address of a name server.
+.LP
+The options listed under the ``set'' command below can be specified in
+the .nslookuprc file in the user's home directory if they are listed
+one per line. Options can also be specified
+on the command line if they precede the arguments and are prefixed with
+a hyphen. For example, to change the default query type to host information,
+and the initial timeout to 10 seconds, type:
+.sp .5v
+ nslookup \-query=hinfo \-timeout=10
+.sp .5v
+.SH "INTERACTIVE COMMANDS"
+Commands may be interrupted at any time by typing a control-C.
+To exit, type a control-D (EOF) or type exit.
+The command line length must be less than 256 characters.
+To treat a built-in command as a host name,
+precede it with an escape character (\e).
+\fBN.B.\fP an unrecognized command will be interpreted as a host name.
+.sp .5v
+.IP "\fIhost\fP [\fIserver\fP]"
+Look up information for \fIhost\fP using the current default server
+or using \fIserver\fP if specified.
+If \fIhost\fP is an Internet address and the query type is A or PTR, the
+name of the host is returned.
+If \fIhost\fP is a name and does not have a trailing period, the default
+domain name is appended to the name. (This behavior depends on the state of the
+\fBset\fP options \fBdomain\fP, \fBsrchlist\fP,
+\fBdefname\fP, and \fBsearch\fP).
+To look up a host not in the current domain, append a period to
+the name.
+.sp 1
+.IP "\fBserver\fP \fIdomain\fP"
+.ns
+.IP "\fBlserver\fP \fIdomain\fP"
+Change the default server to \fIdomain\fP.
+\fBLserver\fP uses the initial server to look up
+information about \fIdomain\fP while \fBserver\fP
+uses the current default server.
+If an authoritative answer can't be found, the names of servers
+that might have the answer are returned.
+.sp 1
+.IP \fBroot\fP
+Changes the default server to the server for the root of the domain name space.
+Currently, the host ns.internic.net is used.
+(This command is a synonym for \fBlserver ns.internic.net.\fP)
+The name of the root server can be changed with the \fBset root\fP command.
+.sp 1
+.IP "\fBfinger\fP [\fIname\fP] [\fB>\fP \fIfilename\fP]"
+.ns
+.IP "\fBfinger\fP [\fIname\fP] [\fB>>\fP \fIfilename\fP]"
+Connects with the finger server on the current host.
+The current host is defined when a previous lookup for a host
+was successful and returned address information (see the
+\fBset querytype=A\fP command).
+\fIName\fP is optional.
+\fB>\fP and \fB>>\fP can be used to redirect output in the
+usual manner.
+.sp 1
+.IP "\fBls\fR [\fIoption\fR] \fIdomain\fR [\fB>\fR \fIfilename\fR]"
+.ns
+.IP "\fBls\fR [\fIoption\fR] \fIdomain\fR [\fB>>\fR \fIfilename\fR]"
+List the information available for \fIdomain\fP, optionally creating
+or appending to \fIfilename\fP.
+The default output contains host names and their Internet addresses.
+.I Option
+can be one of the following:
+.RS
+.IP "\fB\-t \fIquerytype\fP" 4
+lists all records of the specified type (see \fIquerytype\fP below).
+.IP \fB\-a\fP 4
+lists aliases of hosts in the domain.
+synonym for \fB\-t\ \ CNAME\fP.
+.IP \fB\-d\fP 4
+lists all records for the domain.
+synonym for \fB\-t\ \ ANY\fP.
+.IP \fB\-h\fP 4
+lists CPU and operating system information for the domain.
+synonym for \fB\-t\ \ HINFO\fP.
+.IP \fB\-s\fP 4
+lists well-known services of hosts in the domain.
+synonym for \fB\-t\ \ WKS\fP.
+.P
+When output is directed to a file, hash marks are printed for every
+50 records received from the server.
+.RE
+.sp 1
+.IP "\fBview\fP \fIfilename\fP"
+Sorts and lists the output of previous \fBls\fP command(s) with
+\fImore\fP(1).
+.sp 1
+.ne 4
+.IP "\fBhelp\fP"
+.ns
+.IP "\fB?\fP"
+Prints a brief summary of commands.
+.sp 1
+.IP "\fBexit\fP"
+Exits the program.
+.sp 1
+.IP "\fBset\fP \fIkeyword\fP[=\fIvalue\fP]"
+This command is used to change state information that affects the lookups.
+Valid keywords are:
+.RS
+.IP "\fBall\fP"
+Prints the current values of the frequently-used options to \fBset\fP.
+Information about the current default server and host is also printed.
+.IP "\fBclass=\fIvalue\fR"
+Change the query class to one of:
+.RS
+.IP IN 10
+the Internet class.
+.IP CHAOS 10
+the Chaos class.
+.IP HESIOD 10
+the MIT Athena Hesiod class.
+.IP ANY 10
+wildcard (any of the above).
+.P
+The class specifies the protocol group of the information.
+.br
+(Default = IN, abbreviation = cl)
+.RE
+.IP "\fB[no]debug\fP"
+Turn debugging mode on. A lot more information is printed about the
+packet sent to the server and the resulting answer.
+.br
+(Default = nodebug, abbreviation = [no]deb)
+.IP "\fB[no]d2\fP"
+Turn exhaustive debugging mode on.
+Essentially all fields of every packet are printed.
+.br
+(Default = nod2)
+.IP "\fBdomain=\fIname\fR"
+Change the default domain name to \fIname\fP.
+The default domain name is appended to a lookup request depending on the
+state of the \fBdefname\fP and \fBsearch\fP options.
+The domain search list contains the parents of the default domain if it has
+at least two components in its name.
+For example, if the default domain
+is CC.Berkeley.EDU, the search list is CC.Berkeley.EDU and Berkeley.EDU.
+Use the \fBset srchlist\fP command to specify a different list.
+Use the \fBset all\fP command to display the list.
+.br
+(Default = value from hostname, /etc/resolv.conf or LOCALDOMAIN,
+abbreviation = do)
+.IP "\fBsrchlist=\fIname1/name2/...\fR"
+Change the default domain name to \fIname1\fP and the domain search list
+to \fIname1\fP, \fIname2\fP, etc. A maximum of 6 names separated by slashes (/)
+can be specified.
+For example,
+.sp .5v
+ set\ srchlist=lcs.MIT.EDU/ai.MIT.EDU/MIT.EDU
+.sp .5v
+sets the domain to lcs.MIT.EDU and the search list to the three names.
+This command overrides the
+default domain name and search list of the \fBset domain\fP command.
+Use the \fBset all\fP command to display the list.
+.br
+(Default = value based on hostname, /etc/resolv.conf or LOCALDOMAIN,
+abbreviation = srchl)
+.IP "\fB[no]defname\fP"
+If set, append the default domain name to a single-component lookup request
+(i.e., one that does not contain a period).
+.br
+(Default = defname, abbreviation = [no]def)
+.IP "\fB[no]search\fP"
+If the lookup request contains at least one period but doesn't end
+with a trailing period,
+append the domain names in the domain search list
+to the request until an answer is received.
+.br
+(Default = search, abbreviation = [no]sea)
+.IP "\fBport=\fIvalue\fR"
+Change the default TCP/UDP name server port to \fIvalue\fP.
+.br
+(Default = 53, abbreviation = po)
+.IP "\fBquerytype=\fIvalue\fR"
+.ns
+.IP "\fBtype=\fIvalue\fR"
+.ns
+Change the type of information query to one of:
+.RS
+.IP A 10
+the host's Internet address.
+.IP CNAME 10
+the canonical name for an alias.
+.IP HINFO 10
+the host CPU and operating system type.
+.IP MINFO 10
+the mailbox or mail list information.
+.IP MX 10
+the mail exchanger.
+.IP NS 10
+the name server for the named zone.
+.IP PTR 10
+the host name if the query is an Internet address,
+otherwise the pointer to other information.
+.IP SOA 10
+the domain's ``start-of-authority'' information.
+.IP TXT 10
+the text information.
+.IP UINFO 10
+the user information.
+.IP WKS 10
+the supported well-known services.
+.P
+Other types (ANY, AXFR, MB, MD, MF, NULL) are described in the
+RFC-1035 document.
+.br
+(Default = A, abbreviations = q, ty)
+.RE
+.IP "\fB[no]recurse\fP"
+Tell the name server to query other servers if it does not have the
+information.
+.br
+(Default = recurse, abbreviation = [no]rec)
+.IP \fBretry=\fInumber\fR
+Set the number of retries to \fInumber\fP.
+When a reply to a request is not received within a certain
+amount of time (changed with \fBset timeout\fP),
+the timeout period is doubled and the request is resent.
+The retry value controls how many times a request is resent before giving up.
+.br
+(Default = 4, abbreviation = ret)
+.IP \fBroot=\fIhost\fR
+Change the name of the root server to \fIhost\fP. This
+affects the \fBroot\fP command.
+.br
+(Default = ns.internic.net., abbreviation = ro)
+.IP \fBtimeout=\fInumber\fR
+Change the initial timeout interval
+for waiting for a reply
+to \fInumber\fP seconds.
+Each retry doubles the timeout period.
+.br
+(Default = 5 seconds, abbreviation = ti)
+.IP "\fB[no]vc\fP"
+Always use a virtual circuit when sending requests to the server.
+.br
+(Default = novc, abbreviation = [no]v)
+.IP "\fB[no]ignoretc\fP"
+Ignore packet truncation errors.
+.br
+(Default = noignoretc, abbreviation = [no]ig)
+.RE
+.SH DIAGNOSTICS
+If the lookup request was not successful, an error message is printed.
+Possible errors are:
+.IP "Timed out" 5
+The server did not respond to a request after a certain amount of
+time (changed with \fBset timeout=\fIvalue\fR)
+and a certain number of retries (changed with \fBset retry=\fIvalue\fR).
+.IP "No response from server" 5
+No name server is running on the server machine.
+.IP "No records" 5
+The server does not have resource records of the current query type for the
+host, although the host name is valid.
+The query type is specified with the \fBset querytype\fP command.
+.IP "Non-existent domain" 5
+The host or domain name does not exist.
+.IP "Connection refused" 5
+.ns
+.IP "Network is unreachable" 5
+The connection to the name or finger server could not be made
+at the current time.
+This error commonly occurs with \fBls\fP and \fBfinger\fP requests.
+.IP "Server failure" 5
+The name server found an internal inconsistency in its database
+and could not return a valid answer.
+.IP "Refused" 5
+The name server refused to service the request.
+.IP "Format error" 5
+The name server found that the request packet was not in the proper format.
+It may indicate an error in \fInslookup\fP.
+.sp 1
+.SH FILES
+.ta \w'/usr/share/misc/nslookup.helpXXX'u
+/etc/resolv.conf initial domain name and
+ name server addresses.
+.br
+$HOME/.nslookuprc user's initial options.
+.br
+/usr/share/misc/nslookup.help summary of commands.
+.SH ENVIRONMENT
+.ta \w'HOSTALIASESXXXX'u
+HOSTALIASES file containing host aliases.
+.br
+LOCALDOMAIN overrides default domain.
+.SH SEE ALSO
+resolver(3), resolver(5), named(8),
+.br
+RFC-1034 ``Domain Names \- Concepts and Facilities''
+.br
+RFC-1035 ``Domain Names \- Implementation and Specification''
+.SH AUTHOR
+Andrew Cherenson
diff --git a/usr.sbin/named/man/resolver.3 b/usr.sbin/named/man/resolver.3
new file mode 100644
index 00000000000..6372823e11f
--- /dev/null
+++ b/usr.sbin/named/man/resolver.3
@@ -0,0 +1,305 @@
+.\" $NetBSD: resolver.3,v 1.1 1996/02/02 15:27:53 mrg Exp $
+.\"
+.\" Copyright (c) 1985, 1995 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted provided
+.\" that: (1) source distributions retain this entire copyright notice and
+.\" comment, and (2) distributions including binaries display the following
+.\" acknowledgement: ``This product includes software developed by the
+.\" University of California, Berkeley and its contributors'' in the
+.\" documentation or other materials provided with the distribution and in
+.\" all advertising materials mentioning features or use of this software.
+.\" 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" @(#)resolver.3 6.5 (Berkeley) 6/23/90
+.\" $Id: resolver.3,v 8.3 1995/12/22 10:20:28 vixie Exp
+.\"
+.TH RESOLVER 3 "December 11, 1995
+.UC 4
+.SH NAME
+res_query, res_search, res_mkquery, res_send, res_init, dn_comp, dn_expand \- resolver routines
+.SH SYNOPSIS
+.B #include <sys/types.h>
+.br
+.B #include <netinet/in.h>
+.br
+.B #include <arpa/nameser.h>
+.br
+.B #include <resolv.h>
+.PP
+.B "res_query(dname, class, type, answer, anslen)"
+.br
+.B const char *dname;
+.br
+.B int class, type;
+.br
+.B u_char *answer;
+.br
+.B int anslen;
+.PP
+.B "res_search(dname, class, type, answer, anslen)"
+.br
+.B const char *dname;
+.br
+.B int class, type;
+.br
+.B u_char *answer;
+.br
+.B int anslen;
+.PP
+.B "res_mkquery(op, dname, class, type, data, datalen, newrr, buf, buflen)"
+.br
+.B int op;
+.br
+.B const char *dname;
+.br
+.B int class, type;
+.br
+.B const char *data;
+.br
+.B int datalen;
+.br
+.B struct rrec *newrr;
+.br
+.B u_char *buf;
+.br
+.B int buflen;
+.PP
+.B res_send(msg, msglen, answer, anslen)
+.br
+.B const u_char *msg;
+.br
+.B int msglen;
+.br
+.B u_char *answer;
+.br
+.B int anslen;
+.PP
+.B res_init()
+.PP
+.B dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
+.br
+.B const char *exp_dn;
+.br
+.B u_char *comp_dn;
+.br
+.B int length;
+.br
+.B u_char **dnptrs, **lastdnptr;
+.PP
+.B dn_expand(msg, eomorig, comp_dn, exp_dn, length)
+.br
+.B const u_char *msg, *eomorig, *comp_dn;
+.br
+.B char *exp_dn;
+.br
+.B int length;
+.SH DESCRIPTION
+These routines are used for making, sending and interpreting
+query and reply messages with Internet domain name servers.
+.PP
+Global configuration and state information that is used by the
+resolver routines is kept in the structure
+.IR _res .
+Most of the values have reasonable defaults and can be ignored.
+Options
+stored in
+.I _res.options
+are defined in
+.I resolv.h
+and are as follows.
+Options are stored as a simple bit mask containing the bitwise ``or''
+of the options enabled.
+.IP RES_INIT
+True if the initial name server address and default domain name are
+initialized (i.e.,
+.I res_init
+has been called).
+.IP RES_DEBUG
+Print debugging messages.
+.IP RES_AAONLY
+Accept authoritative answers only.
+With this option,
+.I res_send
+should continue until it finds an authoritative answer or finds an error.
+Currently this is not implemented.
+.IP RES_USEVC
+Use TCP connections for queries instead of UDP datagrams.
+.IP RES_STAYOPEN
+Used with RES_USEVC to keep the TCP connection open between
+queries.
+This is useful only in programs that regularly do many queries.
+UDP should be the normal mode used.
+.IP RES_IGNTC
+Unused currently (ignore truncation errors, i.e., don't retry with TCP).
+.IP RES_RECURSE
+Set the recursion-desired bit in queries.
+This is the default.
+(\c
+.I res_send
+does not do iterative queries and expects the name server
+to handle recursion.)
+.IP RES_DEFNAMES
+If set,
+.I res_search
+will append the default domain name to single-component names
+(those that do not contain a dot).
+This option is enabled by default.
+.IP RES_DNSRCH
+If this option is set,
+.I res_search
+will search for host names in the current domain and in parent domains; see
+.IR hostname (7).
+This is used by the standard host lookup routine
+.IR gethostbyname (3).
+This option is enabled by default.
+.IP RES_NOALIASES
+This option turns off the user level aliasing feature controlled by
+the HOSTALIASES environment variable. Network daemons should set this option.
+.PP
+The
+.I res_init
+routine
+reads the configuration file (if any; see
+.IR resolver (5))
+to get the default domain name,
+search list and
+the Internet address of the local name server(s).
+If no server is configured, the host running
+the resolver is tried.
+The current domain name is defined by the hostname
+if not specified in the configuration file;
+it can be overridden by the environment variable LOCALDOMAIN.
+This environment variable may contain several blank-separated
+tokens if you wish to override the
+.I "search list"
+on a per-process basis. This is similar to the
+.I search
+command in the configuration file.
+Another environment variable (``RES_OPTIONS'') can be set to
+override certain internal resolver options which are otherwise
+set by changing fields in the
+.I _res
+structure or are inherited from the configuration file's
+.I options
+command. The syntax of the ``RES_OPTIONS'' environment variable
+is explained in
+.IR resolver (5).
+Initialization normally occurs on the first call
+to one of the other resolver routines.
+.PP
+The
+.I res_query
+function provides an interface to the server query mechanism.
+It constructs a query, sends it to the local server,
+awaits a response, and makes preliminary checks on the reply.
+The query requests information of the specified
+.I type
+and
+.I class
+for the specified fully-qualified domain name
+.I dname .
+The reply message is left in the
+.I answer
+buffer with length
+.I anslen
+supplied by the caller.
+.PP
+The
+.I res_search
+routine makes a query and awaits a response like
+.IR res_query ,
+but in addition, it implements the default and search rules
+controlled by the RES_DEFNAMES and RES_DNSRCH options.
+It returns the first successful reply.
+.PP
+The remaining routines are lower-level routines used by
+.IR res_query .
+The
+.I res_mkquery
+function
+constructs a standard query message and places it in
+.IR buf .
+It returns the size of the query, or \-1 if the query is
+larger than
+.IR buflen .
+The query type
+.I op
+is usually QUERY, but can be any of the query types defined in
+.IR <arpa/nameser.h> .
+The domain name for the query is given by
+.IR dname .
+.I Newrr
+is currently unused but is intended for making update messages.
+.PP
+The
+.I res_send
+routine
+sends a pre-formatted query and returns an answer.
+It will call
+.I res_init
+if RES_INIT is not set, send the query to the local name server, and
+handle timeouts and retries.
+The length of the reply message is returned, or
+\-1 if there were errors.
+.PP
+The
+.I dn_comp
+function
+compresses the domain name
+.I exp_dn
+and stores it in
+.IR comp_dn .
+The size of the compressed name is returned or \-1 if there were errors.
+The size of the array pointed to by
+.I comp_dn
+is given by
+.IR length .
+The compression uses
+an array of pointers
+.I dnptrs
+to previously-compressed names in the current message.
+The first pointer points to
+to the beginning of the message and the list ends with NULL.
+The limit to the array is specified by
+.IR lastdnptr .
+A side effect of
+.I dn_comp
+is to update the list of pointers for
+labels inserted into the message
+as the name is compressed.
+If
+.I dnptr
+is NULL, names are not compressed.
+If
+.I lastdnptr
+is NULL, the list of labels is not updated.
+.PP
+The
+.I dn_expand
+entry
+expands the compressed domain name
+.I comp_dn
+to a full domain name
+The compressed name is contained in a query or reply message;
+.I msg
+is a pointer to the beginning of the message.
+The uncompressed name is placed in the buffer indicated by
+.I exp_dn
+which is of size
+.IR length .
+The size of compressed name is returned or \-1 if there was an error.
+.SH FILES
+/etc/resolv.conf see resolver(5)
+.SH "SEE ALSO"
+gethostbyname(3), named(8), resolver(5), hostname(7),
+.br
+RFC1032, RFC1033, RFC1034, RFC1035, RFC974,
+.br
+SMM:11 Name Server Operations Guide for BIND
diff --git a/usr.sbin/named/man/resolver.5 b/usr.sbin/named/man/resolver.5
new file mode 100644
index 00000000000..20b54f57378
--- /dev/null
+++ b/usr.sbin/named/man/resolver.5
@@ -0,0 +1,135 @@
+.\" $NetBSD: resolver.5,v 1.1 1996/02/02 15:27:55 mrg Exp $
+.\"
+.\" Copyright (c) 1986 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley. The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" @(#)resolver.5 5.9 (Berkeley) 12/14/89
+.\" $Id: resolver.5,v 8.3 1995/12/06 20:34:35 vixie Exp
+.\"
+.TH RESOLVER 5 ""November 11, 1993""
+.UC 4
+.SH NAME
+resolver \- resolver configuration file
+.SH SYNOPSIS
+/etc/resolv.conf
+.SH DESCRIPTION
+.LP
+The
+.I resolver
+is a set of routines in the C library (\c
+.IR resolv (3))
+that provide access to the Internet Domain Name System.
+The resolver configuration file contains information that is read
+by the resolver routines the first time they are invoked by a process.
+The file is designed to be human readable and contains a list of
+keywords with values that provide various types of resolver information.
+.LP
+On a normally configured system this file should not be necessary.
+The only name server to be queried will be on the local machine,
+the domain name is determined from the host name,
+and the domain search path is constructed from the domain name.
+.LP
+The different configuration options are:
+.TP
+\fBnameserver\fP
+Internet address (in dot notation) of a name server
+that the resolver should query.
+Up to MAXNS (currently 3) name servers may be listed,
+one per keyword.
+If there are multiple servers,
+the resolver library queries them in the order listed.
+If no \fBnameserver\fP entries are present,
+the default is to use the name server on the local machine.
+(The algorithm used is to try a name server, and if the query times out,
+try the next, until out of name servers,
+then repeat trying all the name servers
+until a maximum number of retries are made).
+.TP
+\fBdomain\fP
+Local domain name.
+Most queries for names within this domain can use short names
+relative to the local domain.
+If no \fBdomain\fP entry is present, the domain is determined
+from the local host name returned by
+\fIgethostname\fP\|(2);
+the domain part is taken to be everything after the first `.'.
+Finally, if the host name does not contain a domain part, the root
+domain is assumed.
+.TP
+\fBsearch\fP
+Search list for host-name lookup.
+The search list is normally determined from the local domain name;
+by default, it contains only the local domain name.
+This may be changed by listing the desired domain search path
+following the \fIsearch\fP keyword with spaces or tabs separating
+the names.
+Most resolver queries will be attempted using each component
+of the search path in turn until a match is found.
+Note that this process may be slow and will generate a lot of network
+traffic if the servers for the listed domains are not local,
+and that queries will time out if no server is available
+for one of the domains.
+.IP
+The search list is currently limited to six domains
+with a total of 256 characters.
+.TP
+\fBsortlist\fP
+Sortlist allows addresses returned by gethostbyname to be sorted.
+A sortlist is specified by IP address netmask pairs. The netmask is
+optional and defaults to the natural netmask of the net. The IP address
+and optional network pairs are separated by slashes. Up to 10 pairs may
+be specified.
+.IP
+e.g. sortlist 130.155.160.0/255.255.240.0 130.155.0.0
+.TP
+\fBoptions\fP
+Options allows certain internal resolver variables to be modified.
+The syntax is
+.IP
+\fBoptions\fP \fIoption\fP \fI...\fP
+.IP
+where \fIoption\fP is one of the following:
+.IP
+\fBdebug\fP \(em sets RES_DEBUG in _res.options.
+.IP
+\fBndots:\fP\fIn\fP \(em sets a threshold for the number of dots which
+must appear in a name given to \fBres_query\fP (see \fIresolver\fP(3))
+before an \fIinitial absolute query\fP will be made. The default for
+\fIn\fP is ``1'', meaning that if there are any dots in a name, the name
+will be tried first as an absolute name before any \fIsearch list\fP
+elements are appended to it.
+.LP
+The \fIdomain\fP and \fIsearch\fP keywords are mutually exclusive.
+If more than one instance of these keywords is present,
+the last instance wins.
+.LP
+The \fIsearch\fP keyword of a system's \fIresolv.conf\fP file can be
+overridden on a per-process basis by setting the environment variable
+``\s-1LOCALDOMAIN\s+1'' to a space-separated list of search domains.
+.LP
+The \fIoptions\fP keyword of a system's \fIresolv.conf\fP file can be
+amended on a per-process basis by setting the environment variable
+``\s-1RES_OPTIONS\s+1'' to a space-separated list of resolver options
+as explained above under \fBoptions\fP.
+.LP
+The keyword and value must appear on a single line, and the keyword
+(e.g. \fBnameserver\fP) must start the line. The value follows
+the keyword, separated by white space.
+.SH FILES
+.I /etc/resolv.conf
+.SH SEE ALSO
+gethostbyname(3), resolver(3), hostname(7), named(8)
+.br
+Name Server Operations Guide for BIND
diff --git a/usr.sbin/named/named-xfer/Makefile b/usr.sbin/named/named-xfer/Makefile
new file mode 100644
index 00000000000..61d4d118564
--- /dev/null
+++ b/usr.sbin/named/named-xfer/Makefile
@@ -0,0 +1,14 @@
+# $NetBSD: Makefile,v 1.2 1996/02/04 12:02:12 mrg Exp $
+# from: $Id: Makefile,v 8.2 1995/12/31 23:28:01 vixie Exp
+
+.PATH: ${.CURDIR}/../named \
+ ${.CURDIR}/../man
+
+PROG= named-xfer
+SRCS= named-xfer.c db_glue.c storage.c dmalloc.c version.c
+CFLAGS+= -I${.CURDIR}/../named
+MAN= named-xfer.8
+BINDIR= /usr/libexec
+
+.include <bsd.prog.mk>
+.include "../../Makefile.inc"
diff --git a/usr.sbin/named/named-xfer/named-xfer.c b/usr.sbin/named/named-xfer/named-xfer.c
new file mode 100644
index 00000000000..8df110816e7
--- /dev/null
+++ b/usr.sbin/named/named-xfer/named-xfer.c
@@ -0,0 +1,1635 @@
+/* $NetBSD: named-xfer.c,v 1.1 1996/02/02 15:29:42 mrg Exp $ */
+
+/*
+ * 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 8.10 1995/12/06 20:34:38 vixie Exp ";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#if defined(__osf__)
+# include <sys/mbuf.h>
+# include <net/route.h>
+#endif
+#if defined(_AIX)
+# include <sys/time.h>
+# define TIME_H_INCLUDED
+#endif
+#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>
+#if !defined(SVR4) || !defined(sun)
+# include <math.h>
+#endif
+#include <ctype.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,
+ curclass,
+ domain_len; /* strlen(domain) */
+
+static FILE *fp = NULL,
+ *dbfp = NULL;
+
+static char *ProgName;
+
+static void usage __P((const char *));
+static int getzone __P((struct zoneinfo *, u_int32_t, int)),
+ print_output __P((u_char *, int, u_char *)),
+ netread __P((int, char *, int, int));
+static SIG_FN read_alarm __P(());
+static const char *soa_zinfo __P((struct zoneinfo *, u_char *, u_char*));
+
+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);
+ if (!ddtfile)
+ panic(errno, "malloc(ddtfile)");
+#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);
+ if (!tmpname)
+ panic(errno, "malloc(tmpname)");
+#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 {
+#ifdef HAVE_SETVBUF
+ 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, (u_long)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++) {
+ 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);
+ 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 0.0.0.0 (%s) for %s",
+ tm, zp->z_origin);
+ 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_init();
+ _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, nscnt, soacnt, error = 0;
+ u_int cnt;
+ u_char *cp, *nmp, *eom, *tmp ;
+ u_char *buf = NULL;
+ u_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 qdcount, ancount, aucount, class, type;
+ const char *badsoa_msg = "Nil";
+
+#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
+ bzero((char *)&sv, sizeof sv);
+ sv.sa_handler = (SIG_FN (*)()) 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
+ bzero((char *)&sv, sizeof sv);
+ sv.sv_handler = read_alarm;
+ 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
+ curclass = zp->z_class;
+#else
+ curclass = C_IN;
+#endif
+ error = 0;
+ if (buf == NULL) {
+ if ((buf = (u_char *)malloc(2 * PACKETSZ)) == NULL) {
+ syslog(LOG_INFO, "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_INFO, "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) {
+ if (!quiet)
+ syslog(LOG_INFO,
+ "connect(%s) for zone %s failed: %m",
+ inet_ntoa(sin.sin_addr), zp->z_origin);
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+#ifndef GEN_AXFR
+ tryagain:
+#endif
+ n = res_mkquery(QUERY, zp->z_origin, curclass,
+ T_SOA, NULL, 0, NULL, buf, bufsize);
+ if (n < 0) {
+ if (!quiet)
+ syslog(LOG_INFO,
+ "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_INFO, "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_INFO,
+ "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_nquery(buf, len, ddt);
+ }
+#endif
+ hp = (HEADER *) buf;
+ qdcount = ntohs(hp->qdcount);
+ ancount = ntohs(hp->ancount);
+ aucount = ntohs(hp->nscount);
+
+ /*
+ * close socket if any of these apply:
+ * 1) rcode != NOERROR
+ * 2) not an authority response
+ * 3) not an answer to our question
+ * 4) both the number of answers and authority count < 1)
+ */
+ if (hp->rcode != NOERROR || !hp->aa || qdcount != 1 ||
+ (ancount < 1 && aucount < 1)) {
+#ifndef GEN_AXFR
+ if (curclass == C_IN) {
+ dprintf(1, (ddt, "SOA failed, trying C_HS\n"));
+ curclass = C_HS;
+ goto tryagain;
+ }
+#endif
+ syslog(LOG_NOTICE,
+ "[%s] %s for %s, SOA query got rcode %d, aa %d, ancount %d, aucount %d",
+ inet_ntoa(sin.sin_addr),
+ (hp->aa
+ ? (qdcount==1 ?"no SOA found" :"bad response")
+ : "not authoritative"),
+ zp->z_origin[0] != '\0' ? zp->z_origin : ".",
+ hp->rcode, hp->aa, ancount, aucount);
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ zp_start = *zp;
+ if ((int)len < HFIXEDSZ + QFIXEDSZ) {
+ badsoa_msg = "too short";
+ badsoa:
+ syslog(LOG_INFO,
+ "malformed SOA from [%s], zone %s: %s",
+ inet_ntoa(sin.sin_addr), zp->z_origin,
+ badsoa_msg);
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ /*
+ * Step through response.
+ */
+ tmp = buf + HFIXEDSZ;
+ eom = buf + len;
+ /* Query Section. */
+ n = dn_expand(buf, eom, tmp, name2, sizeof name2);
+ if (n < 0) {
+ badsoa_msg = "qname error";
+ goto badsoa;
+ }
+ tmp += n;
+ GETSHORT(type, tmp);
+ GETSHORT(class, tmp);
+ if (class != curclass || type != T_SOA ||
+ strcasecmp(zp->z_origin, name2) != 0) {
+ syslog(LOG_INFO,
+ "wrong query in resp from [%s], zone %s: [%s %s %s]\n",
+ inet_ntoa(sin.sin_addr), zp->z_origin,
+ name2, p_class(class), p_type(type));
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ /* ... Answer Section. */
+ n = dn_expand(buf, eom, tmp, name2, sizeof name2);
+ if (n < 0) {
+ badsoa_msg = "aname error";
+ goto badsoa;
+ }
+ tmp += n;
+ if (strcasecmp(zp->z_origin, name2) != 0) {
+ syslog(LOG_INFO,
+ "wrong answer in resp from [%s], zone %s: [%s %s %s]\n",
+ inet_ntoa(sin.sin_addr), zp->z_origin,
+ name2, p_class(class), p_type(type));
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ badsoa_msg = soa_zinfo(&zp_start, tmp, eom);
+ if (badsoa_msg)
+ goto badsoa;
+ if (SEQ_GT(zp_start.z_serial, serial_no) || !serial_no) {
+ const char *l, *nl;
+ dprintf(1, (ddt, "need update, serial %lu\n",
+ (u_long)zp_start.z_serial));
+ hp = (HEADER *) buf;
+ soacnt = 0;
+ nscnt = 0;
+ gettime(&tt);
+ for (l = Version; l; l = nl) {
+ size_t len;
+ if ((nl = strchr(l, '\n')) != NULL) {
+ len = nl - l;
+ nl = nl + 1;
+ } else {
+ len = strlen(l);
+ nl = NULL;
+ }
+ while (isspace((unsigned char) *l))
+ l++;
+ if (*l)
+ fprintf(dbfp, "; BIND version %.*s\n",
+ (int)len, l);
+ }
+ fprintf(dbfp, "; zone '%s' last serial %lu\n",
+ domain, (u_long)serial_no);
+ fprintf(dbfp, "; from %s at %s",
+ inet_ntoa(sin.sin_addr),
+ ctimel(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,
+ curclass, type,
+ NULL, 0,
+ NULL, buf, bufsize);
+ if (n < 0) {
+ if (!quiet) {
+#ifdef STUBS
+ if (zp->z_type == Z_STUB)
+ syslog(LOG_INFO,
+ (type == T_SOA)
+ ? "zone %s: res_mkquery T_SOA failed"
+ : "zone %s: res_mkquery T_NS failed",
+ zp->z_origin);
+ else
+#endif
+ syslog(LOG_INFO,
+ "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_INFO,
+ "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_nquery(buf, len, ddt);
+ }
+ if (fp)
+ fp_nquery(buf, len, fp);
+#endif
+ if (len < HFIXEDSZ) {
+ badrec:
+ error++;
+ syslog(LOG_INFO,
+ "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_INFO,
+ "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_INFO,
+ "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+PACKETSZ, nmp,
+ name, sizeof name) < 0) {
+ badsoa_msg = "soa name error";
+ goto badsoa;
+ }
+ if (strcasecmp(name, zp->z_origin)!=0){
+ syslog(LOG_INFO,
+ "wrong zone name in AXFR (wanted \"%s\", got \"%s\")",
+ zp->z_origin, name);
+ badsoa_msg = "wrong soa name";
+ goto badsoa;
+ }
+ if (eom - tmp
+ <= 2 * INT16SZ + INT32SZ) {
+ badsoa_msg = "soa header";
+ goto badsoa;
+ }
+ tmp += 2 * INT16SZ + INT32SZ;
+ if ((n = dn_skipname(tmp, eom)) < 0) {
+ badsoa_msg = "soa mname";
+ goto badsoa;
+ }
+ tmp += n;
+ if ((n = dn_skipname(tmp, eom)) < 0) {
+ badsoa_msg = "soa hname";
+ goto badsoa;
+ }
+ tmp += n;
+ if (eom - tmp <= INT32SZ) {
+ badsoa_msg = "soa dlen";
+ goto badsoa;
+ }
+ GETLONG(serial, tmp);
+ dprintf(3, (ddt,
+ "first SOA for %s, serial %lu\n",
+ name, (u_long)serial));
+ continue;
+ }
+ if (dn_expand(buf, buf+PACKETSZ, nmp,
+ name2, sizeof name2) == -1) {
+ badsoa_msg = "soa name error#2";
+ goto badsoa;
+ }
+ if (strcasecmp((char *)name,
+ (char *)name2) != 0) {
+ syslog(LOG_INFO,
+ "got extra SOA for \"%s\" in zone \"%s\"",
+ name2, name);
+ continue;
+ }
+ tmp -= INT16SZ; /* Put TYPE back. */
+ badsoa_msg = soa_zinfo(&zp_finish, tmp, eom);
+ if (badsoa_msg)
+ goto badsoa;
+ dprintf(2, (ddt,
+ "SOA, serial %lu\n",
+ (u_long)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_INFO,
+ "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(NETREAD_BROKEN)
+ 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_INFO, setitimerStr);
+ return (-1);
+ }
+ errno = 0;
+ n = recv(fd, buf, len, 0);
+ if (n == 0 && errno == 0) {
+#if defined(NETREAD_BROKEN)
+ if (++retries < 42) /* doug adams */
+ continue;
+#endif
+ syslog(LOG_INFO, "premature EOF, fetching \"%s\"",
+ domain);
+ return (-1);
+ }
+ if (n < 0) {
+ if (errno == 0) {
+#if defined(NETREAD_BROKEN)
+ if (++retries < 42) /* doug adams */
+ continue;
+#endif
+ syslog(LOG_INFO,
+ "recv(len=%d): n=%d && !errno",
+ len, n);
+ return (-1);
+ }
+ if (errno == EINTR) {
+ if (!read_interrupted) {
+ /* It wasn't a timeout; ignore it. */
+ continue;
+ }
+ errno = ETIMEDOUT;
+ }
+ syslog(LOG_INFO, "recv(len=%d): %m", len);
+ return (-1);
+ }
+ buf += n;
+ len -= n;
+ }
+ if (setitimer(ITIMER_REAL, &zeroival, NULL) < 0) {
+ syslog(LOG_INFO, setitimerStr);
+ return (-1);
+ }
+ return (0);
+}
+
+static const char *
+soa_zinfo(zp, cp, eom)
+ register struct zoneinfo *zp;
+ register u_char *cp;
+ u_char *eom;
+{
+ register int n;
+ int type, class;
+ u_long ttl;
+
+ /* Are type, class, and ttl OK? */
+ if (eom - cp < 3 * INT16SZ + INT32SZ)
+ return ("zinfo too short");
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ cp += INT16SZ; /* dlen */
+ if (type != T_SOA || class != curclass)
+ return ("zinfo wrong typ/cla/ttl");
+ /* Skip master name and contact name, we can't validate them. */
+ if ((n = dn_skipname(cp, eom)) == -1)
+ return ("zinfo mname");
+ cp += n;
+ if ((n = dn_skipname(cp, eom)) == -1)
+ return ("zinfo hname");
+ cp += n;
+ /* Grab the data fields. */
+ if (eom - cp < 5 * INT32SZ)
+ return ("zinfo dlen");
+ 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 (NULL);
+}
+
+/*
+ * 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 = "";
+
+ 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_LOC:
+ case T_NSAP:
+ 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;
+
+ case T_PX:
+ /* grab preference */
+ bcopy((char *)cp, data, INT16SZ);
+ cp1 = (u_char *)data + INT16SZ;
+ cp += INT16SZ;
+
+ /* get MAP822 name */
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)cp1, sizeof data - INT16SZ);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ cp1 += (n = (strlen((char *) cp1) + 1));
+ n1 = sizeof data - n;
+
+ /* get MAPX400 name */
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1);
+ if (n < 0)
+ return (-1);
+
+ cp1 += strlen((char *) cp1) + 1;
+ n = cp1 - (u_char *)data;
+ cp1 = (u_char *)data;
+ break;
+
+ default:
+ syslog(LOG_INFO, "\"%s %s %s\" - unknown type (%d)",
+ dname, p_class(class), p_type(type), type);
+ hp->rcode = NOTIMP;
+ return (-1);
+ }
+ if (n > MAXDATA) {
+ dprintf(1, (ddt,
+ "update type %d: %d bytes is too much data\n",
+ type, n));
+ hp->rcode = 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) < (size_t)8)
+ tab = 1;
+ } else {
+ (void) fprintf(dbfp, "%s\t", ignore);
+ tab = 1;
+ }
+
+ if (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);
+ fputs(inet_ntoa(*(struct in_addr *) &n), dbfp);
+ 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;
+ for (i = 0; i < 2; i++) {
+ if (i != 0)
+ (void) putc(' ', dbfp);
+ n = *cp++;
+ cp1 = cp + n;
+ if (cp1 > cp2)
+ cp1 = cp2;
+ (void) putc('"', dbfp);
+ j = 0;
+ while (cp < cp1) {
+ if (*cp == '\0') {
+ cp = cp1;
+ break;
+ }
+ if ((*cp == '\n') || (*cp == '"')) {
+ (void) putc('\\', dbfp);
+ }
+ (void) putc(*cp++, dbfp);
+ j++;
+ }
+ if (j == 0 && (type != T_ISDN || i == 0))
+ (void) putc('?', dbfp);
+ (void) putc('"', dbfp);
+ }
+ (void) putc('\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, (u_long)n);
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, " %lu", (u_long)n);
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, " %lu", (u_long)n);
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, " %lu", (u_long)n);
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, " %lu )\n", (u_long)n);
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ GETSHORT(n, cp);
+ (void) fprintf(dbfp, "%lu", (u_long)n);
+ (void) fprintf(dbfp, " %s.\n", cp);
+ break;
+
+ case T_PX:
+ GETSHORT(n, cp);
+ (void) fprintf(dbfp, "%lu", (u_long)n);
+ (void) fprintf(dbfp, " %s.", cp);
+ cp += strlen((char *) cp) + 1;
+ (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;
+
+#ifdef LOC_RR
+ case T_LOC:
+ (void) fprintf(dbfp, "%s\n", loc_ntoa(cp, NULL));
+ break;
+#endif /* LOC_RR */
+
+ case T_UID:
+ case T_GID:
+ if (n == INT32SZ) {
+ GETLONG(n, cp);
+ (void) fprintf(dbfp, "%lu\n", (u_long)n);
+ }
+ break;
+
+ case T_WKS:
+ GETLONG(addr, cp);
+ addr = htonl(addr);
+ fputs(inet_ntoa(*(struct in_addr *) &addr), dbfp);
+ fputc(' ', dbfp);
+ 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 */
diff --git a/usr.sbin/named/named/Makefile b/usr.sbin/named/named/Makefile
new file mode 100644
index 00000000000..315b34895e1
--- /dev/null
+++ b/usr.sbin/named/named/Makefile
@@ -0,0 +1,18 @@
+# $NetBSD: Makefile,v 1.1 1996/02/02 15:28:00 mrg Exp $
+# from: $Id: Makefile,v 8.1 1994/12/15 06:23:45 vixie Exp
+
+.PATH: ${.CURDIR}/../man
+
+PROG= named
+SRCS= version.c db_dump.c db_glue.c db_load.c db_lookup.c db_reload.c \
+ db_save.c db_secure.c db_update.c dmalloc.c ns_forw.c \
+ ns_init.c ns_main.c ns_maint.c ns_ncache.c ns_req.c ns_resp.c \
+ ns_sort.c ns_stats.c ns_validate.c storage.c tree.c
+MAN= named.8
+
+makeversionc:
+ (sed -e "s|%VERSION%|${VER}|" \
+ < ${.CURDIR}/Version.c > ${.CURDIR}/version.c)
+
+.include <bsd.prog.mk>
+.include "../../Makefile.inc"
diff --git a/usr.sbin/named/named/Version.c b/usr.sbin/named/named/Version.c
new file mode 100644
index 00000000000..5e224bf6dec
--- /dev/null
+++ b/usr.sbin/named/named/Version.c
@@ -0,0 +1,90 @@
+/* $NetBSD: Version.c,v 1.1 1996/02/02 15:28:02 mrg Exp $ */
+
+/*
+ * @(#)Version.c 4.9 (Berkeley) 7/21/90
+ * $Id: Version.c,v 8.1 1994/12/15 06:24:14 vixie Exp
+ */
+
+#ifndef lint
+char sccsid[] = "@(#)named %VERSION%";
+char rcsid[] = "$Id: Version.c,v 8.1 1994/12/15 06:24:14 vixie Exp ";
+#endif /* not lint */
+
+char Version[] = "named %VERSION%";
+
+#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/named/db_defs.h b/usr.sbin/named/named/db_defs.h
new file mode 100644
index 00000000000..799994626b0
--- /dev/null
+++ b/usr.sbin/named/named/db_defs.h
@@ -0,0 +1,182 @@
+/* $NetBSD: db_defs.h,v 1.1 1996/02/02 15:28:06 mrg Exp $ */
+
+/*
+ * from db.h 4.16 (Berkeley) 6/1/90
+ * $Id: db_defs.h,v 8.3 1995/06/19 20:55:40 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_PRIMING 0x20 /* is this update the result of priming? */
+
+#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
+
+/*
+ * getnum() options
+ */
+#define GETNUM_NONE 0x00 /* placeholder */
+#define GETNUM_SERIAL 0x01 /* treat as serial number */
+#define GETNUM_SCALED 0x02 /* permit "k", "m" suffixes, scale result */
diff --git a/usr.sbin/named/named/db_dump.c b/usr.sbin/named/named/db_dump.c
new file mode 100644
index 00000000000..bc01ad9cc34
--- /dev/null
+++ b/usr.sbin/named/named/db_dump.c
@@ -0,0 +1,910 @@
+/* $NetBSD: db_dump.c,v 1.1 1996/02/02 15:28:11 mrg Exp $ */
+
+#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 8.8 1995/12/06 20:34:38 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", ctimel(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_NOTICE, "%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;
+ }
+ }
+
+ 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%lx)\n", (u_long)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"));
+ syslog(LOG_NOTICE, "dumping nameserver data\n");
+
+ if ((fp = fopen(dumpfile, "w")) == NULL)
+ return;
+ gettime(&tt);
+ fprintf(fp, "; Dumped at %s", ctimel(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);
+ syslog(LOG_NOTICE, "finished dumping nameserver data\n");
+}
+
+#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;
+
+ if (!zp->z_origin)
+ continue;
+
+ fprintf(fp, "; %s (type %d, class %d, source %s)\n",
+ zp->z_origin
+ ? (*zp->z_origin ? zp->z_origin : ".")
+ : "Nil",
+ 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, (int)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);
+#ifdef BIND_NOTIFY
+ if (zp->z_notifylist) {
+ register struct notify *ap;
+
+ for (ap = zp->z_notifylist; ap; ap = ap->next)
+ fprintf(fp, ";\tNotify [%s] %s",
+ inet_ntoa(ap->addr),
+ ctime(&ap->last));
+ }
+#endif
+ }
+ fprintf(fp, ";; --zone table--\n");
+ return (0);
+}
+
+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) < (size_t)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);
+ fputs(inet_ntoa(*(struct in_addr *)&n),
+ fp);
+ 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++) != '\0') {
+ fprintf(fp, "\"%.*s\"", (int)n, cp);
+ cp += n;
+ } else
+ fprintf(fp, "\"\"");
+ if ((n = *cp++) != '\0')
+ 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", (u_long)n);
+ GETLONG(n, cp);
+ fprintf(fp, " %lu", (u_long)n);
+ GETLONG(n, cp);
+ fprintf(fp, " %lu", (u_long)n);
+ GETLONG(n, cp);
+ fprintf(fp, " %lu", (u_long)n);
+ GETLONG(n, cp);
+ fprintf(fp, " %lu )", (u_long)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", (u_long)n);
+ fprintf(fp, " %s.", cp);
+ break;
+
+ case T_PX:
+ GETSHORT(n, cp);
+ fprintf(fp, "%lu", (u_long)n);
+ fprintf(fp, " %s.", cp);
+ cp += strlen((char *)cp) + 1;
+ 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++) != '\0') {
+ 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;
+#ifdef LOC_RR
+ case T_LOC:
+ (void) fputs(loc_ntoa(dp->d_data, NULL), fp);
+ break;
+#endif /* LOC_RR */
+ 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);
+ fputs(inet_ntoa(*(struct in_addr *)&addr), fp);
+ 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) {
+ TmpBuf = "BAD_MALLOC";
+ }
+ if (btoa(cp, dp->d_size, TmpBuf, TmpSize)
+ == CONV_OVERFLOW) {
+ 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/named/db_func.h b/usr.sbin/named/named/db_func.h
new file mode 100644
index 00000000000..4397c9c6a96
--- /dev/null
+++ b/usr.sbin/named/named/db_func.h
@@ -0,0 +1,118 @@
+/* $NetBSD: db_func.h,v 1.1 1996/02/02 15:28:16 mrg Exp $ */
+
+/* db_proc.h - prototypes for functions in db_*.c
+ *
+ * $Id: db_func.h,v 8.7 1995/12/22 10:20:30 vixie Exp
+ */
+
+/* ++from db_update.c++ */
+extern int db_update __P((char name[],
+ struct databuf *odp,
+ struct databuf *newdp,
+ int flags,
+ struct hashbuf *htp)),
+ findMyZone __P((struct namebuf *np, int class));
+/* --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((const char *, int));
+#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
+extern u_int db_getclev __P((const char *));
+/* --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 *, int)),
+ getnum __P((FILE *, const char *, int)),
+ db_load __P((const char *, const char *,
+ struct zoneinfo *, const char *)),
+ 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 const char *sin_ntoa __P((const struct sockaddr_in *));
+extern void panic __P((int, const char *)),
+ 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((const u_char *, int)),
+ nhash __P((const char *)),
+ samedomain __P((const char *, const char *));
+extern char *protocolname __P((int)),
+ *servicename __P((u_int16_t, char *)),
+ *savestr __P((const 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
+#ifdef LOC_RR
+extern u_int32_t loc_aton __P((const char *ascii, u_char *binary));
+extern char * loc_ntoa __P((const u_char *binary, char *ascii));
+#endif
+extern char * ctimel __P((long));
+extern struct in_addr data_inaddr __P((const u_char *data));
+extern void setsignal __P((int, int, SIG_FN (*)())),
+ resignal __P((int, int, SIG_FN (*)()));
+/* --from db_glue.c-- */
+
+/* ++from db_lookup.c++ */
+extern struct namebuf *nlookup __P((const char *, struct hashbuf **,
+ const 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/named/db_glob.h b/usr.sbin/named/named/db_glob.h
new file mode 100644
index 00000000000..aedf4bf9789
--- /dev/null
+++ b/usr.sbin/named/named/db_glob.h
@@ -0,0 +1,95 @@
+/* $NetBSD: db_glob.h,v 1.1 1996/02/02 15:28:21 mrg Exp $ */
+
+/*
+ * from db.h 4.16 (Berkeley) 6/1/90
+ * $Id: db_glob.h,v 8.3 1995/12/06 20:34:38 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);
+
+ /* no minimum ttl */
+DECL int min_cache_ttl INIT(0);
+
+ /* 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/named/db_glue.c b/usr.sbin/named/named/db_glue.c
new file mode 100644
index 00000000000..9ca4fc22bdd
--- /dev/null
+++ b/usr.sbin/named/named/db_glue.c
@@ -0,0 +1,1226 @@
+/* $NetBSD: db_glue.c,v 1.1 1996/02/02 15:28:26 mrg Exp $ */
+
+#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 8.10 1995/12/22 10:20:30 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/inet.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "named.h"
+
+struct valuelist {
+ struct valuelist *next, *prev;
+ char *name;
+ char *proto;
+ int port;
+};
+static struct valuelist *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
+
+/*XXX: sin_ntoa() should probably be in libc*/
+const char *
+sin_ntoa(sin)
+ const struct sockaddr_in *sin;
+{
+ static char ret[sizeof "[111.222.333.444].55555"];
+
+ if (!sin)
+ strcpy(ret, "[sin_ntoa(NULL)]");
+ else
+ sprintf(ret, "[%s].%u",
+ inet_ntoa(sin->sin_addr),
+ ntohs(sin->sin_port));
+ return (ret);
+}
+
+/*
+ * XXX: some day we'll make this a varargs function
+ */
+void
+panic(err, msg)
+ int err;
+ const char *msg;
+{
+ if (err == -1)
+ syslog(LOG_CRIT, "%s - ABORT", msg);
+ else
+ syslog(LOG_CRIT, "%s: %s - ABORT", msg, strerror(err));
+ signal(SIGIOT, SIG_DFL); /* no POSIX needed here. */
+ abort();
+}
+
+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));
+ if (!slp)
+ panic(errno, "malloc(servent)");
+ slp->name = savestr(sp->s_name);
+ slp->proto = savestr(sp->s_proto);
+ slp->port = ntohs((u_int16_t)sp->s_port); /* host byt order */
+ 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));
+ if (!slp)
+ panic(errno, "malloc(protoent)");
+ slp->name = savestr(pp->p_name);
+ slp->port = pp->p_proto; /* host byte order */
+ 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); /* host byte order */
+ }
+ 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, /* net byte order */
+ char *proto)
+#else
+static struct servent *
+cgetservbyport(port, proto)
+ u_int16_t port; /* net byte order */
+ char *proto;
+#endif
+{
+ register struct valuelist **list = &servicelist;
+ register struct valuelist *lp = *list;
+ static struct servent serv;
+
+ port = ntohs(port);
+ for (; lp != NULL; lp = lp->next) {
+ if (port != (u_int16_t)lp->port) /* host byte order */
+ 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; /* host byte order */
+{
+ register struct valuelist **list = &protolist;
+ register struct valuelist *lp = *list;
+ static struct protoent prot;
+
+ for (; lp != NULL; lp = lp->next)
+ if (lp->port == proto) { /* host byte order */
+ 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; /* host byte order */
+ 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) /* host byte order */
+#else
+char *
+servicename(port, proto)
+ u_int16_t port; /* host byte order */
+ 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);
+}
+
+u_int
+db_getclev(origin)
+ const char *origin;
+{
+ u_int lev = 0;
+ dprintf(12, (ddt, "db_getclev of \"%s\"", origin));
+ if (origin && *origin)
+ lev++;
+ while (origin && (origin = strchr(origin, '.'))) {
+ origin++;
+ lev++;
+ }
+ dprintf(12, (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;
+
+ do {
+ errno = 0;
+ s = close(fd);
+ } while (s < 0 && errno == EINTR);
+
+ if (s < 0 && errno != EBADF)
+ syslog(LOG_INFO, "close(%d) failed: %m", fd);
+ 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_INFO, "fclose(%d) failed: %m", fd);
+ 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)
+ const char *str;
+{
+ char *cp;
+
+ cp = (char *)malloc(strlen(str) + 1);
+ if (!cp)
+ panic(errno, "malloc(savestr)");
+ 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(%lx, %lx, %lx) -> %lx\n",
+ (u_long)dp, (u_long)np->n_data, (u_long)pdp, (u_long)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"))
+ ) {
+ syslog(LOG_ERR,
+ "rm_name(%#lx(%s)): non-nil %s pointer\n",
+ (u_long)np, np->n_dname?np->n_dname:"Nil", msg);
+ panic(-1, "rm_name");
+ }
+
+ /* 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_INFO, "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)
+ panic(errno, "malloc(saveinv)");
+ ip->i_next = NULL;
+ bzero((char *)ip->i_dname, sizeof(ip->i_dname));
+ return (ip);
+}
+
+/*
+ * Compute hash value from data.
+ */
+int
+dhash(dp, dlen)
+ register const u_char *dp;
+ int dlen;
+{
+ register u_char *cp;
+ register unsigned hval;
+ register int n;
+
+ n = dlen;
+ if (n > 8)
+ n = 8;
+ hval = 0;
+ while (--n >= 0) {
+ hval <<= 1;
+ hval += *dp++;
+ }
+ return (hval % INVHASHSZ);
+}
+#endif /*INVQ*/
+
+/* int
+ * nhash(name)
+ * compute hash for this name and return it; ignore case differences
+ */
+int
+nhash(name)
+ register const char *name;
+{
+ register u_char ch;
+ register unsigned hval;
+
+ hval = 0;
+ while ((ch = (u_char)*name++) != (u_char)'\0') {
+ if (isascii(ch) && isupper(ch))
+ ch = tolower(ch);
+ hval <<= 1;
+ hval += ch;
+ }
+ 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);
+}
+
+#ifdef LOC_RR
+/*
+ * routines to convert between on-the-wire RR format and zone file format.
+ * Does not contain conversion to/from decimal degrees; divide or multiply
+ * by 60*60*1000 for that.
+ */
+
+static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
+ 1000000,10000000,100000000,1000000000};
+
+/* takes an XeY precision/size value, returns a string representation. */
+static const char *
+precsize_ntoa(prec)
+ u_int8_t prec;
+{
+ static char retbuf[sizeof("90000000.00")];
+ unsigned long val;
+ int mantissa, exponent;
+
+ mantissa = (int)((prec >> 4) & 0x0f) % 10;
+ exponent = (int)((prec >> 0) & 0x0f) % 10;
+
+ val = mantissa * poweroften[exponent];
+
+ (void) sprintf(retbuf,"%d.%.2d", val/100, val%100);
+ return (retbuf);
+}
+
+/* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer. */
+static u_int8_t
+precsize_aton(strptr)
+ char **strptr;
+{
+ unsigned int mval = 0, cmval = 0;
+ u_int8_t retval = 0;
+ register char *cp;
+ register int exponent;
+ register int mantissa;
+
+ cp = *strptr;
+
+ while (isdigit(*cp))
+ mval = mval * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /* centimeters */
+ cp++;
+ if (isdigit(*cp)) {
+ cmval = (*cp++ - '0') * 10;
+ if (isdigit(*cp)) {
+ cmval += (*cp++ - '0');
+ }
+ }
+ }
+ cmval = (mval * 100) + cmval;
+
+ for (exponent = 0; exponent < 9; exponent++)
+ if (cmval < poweroften[exponent+1])
+ break;
+
+ mantissa = cmval / poweroften[exponent];
+ if (mantissa > 9)
+ mantissa = 9;
+
+ retval = (mantissa << 4) | exponent;
+
+ *strptr = cp;
+
+ return (retval);
+}
+
+/* converts ascii lat/lon to unsigned encoded 32-bit number. moves pointer. */
+static u_int32_t
+latlon2ul(latlonstrptr,which)
+ char **latlonstrptr;
+ int *which;
+{
+ register char *cp;
+ u_int32_t retval;
+ int deg = 0, min = 0, secs = 0, secsfrac = 0;
+
+ cp = *latlonstrptr;
+
+ while (isdigit(*cp))
+ deg = deg * 10 + (*cp++ - '0');
+
+ while (isspace(*cp))
+ cp++;
+
+ if (!(isdigit(*cp)))
+ goto fndhemi;
+
+ while (isdigit(*cp))
+ min = min * 10 + (*cp++ - '0');
+
+ while (isspace(*cp))
+ cp++;
+
+ if (!(isdigit(*cp)))
+ goto fndhemi;
+
+ while (isdigit(*cp))
+ secs = secs * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /* decimal seconds */
+ cp++;
+ if (isdigit(*cp)) {
+ secsfrac = (*cp++ - '0') * 100;
+ if (isdigit(*cp)) {
+ secsfrac += (*cp++ - '0') * 10;
+ if (isdigit(*cp)) {
+ secsfrac += (*cp++ - '0');
+ }
+ }
+ }
+ }
+
+ while (!isspace(*cp)) /* if any trailing garbage */
+ cp++;
+
+ while (isspace(*cp))
+ cp++;
+
+ fndhemi:
+ switch (*cp) {
+ case 'N': case 'n':
+ case 'E': case 'e':
+ retval = ((unsigned)1<<31)
+ + (((((deg * 60) + min) * 60) + secs) * 1000)
+ + secsfrac;
+ break;
+ case 'S': case 's':
+ case 'W': case 'w':
+ retval = ((unsigned)1<<31)
+ - (((((deg * 60) + min) * 60) + secs) * 1000)
+ - secsfrac;
+ break;
+ default:
+ retval = 0; /* invalid value -- indicates error */
+ break;
+ }
+
+ switch (*cp) {
+ case 'N': case 'n':
+ case 'S': case 's':
+ *which = 1; /* latitude */
+ break;
+ case 'E': case 'e':
+ case 'W': case 'w':
+ *which = 2; /* longitude */
+ break;
+ default:
+ *which = 0; /* error */
+ break;
+ }
+
+ cp++; /* skip the hemisphere */
+
+ while (!isspace(*cp)) /* if any trailing garbage */
+ cp++;
+
+ while (isspace(*cp)) /* move to next field */
+ cp++;
+
+ *latlonstrptr = cp;
+
+ return (retval);
+}
+
+/* converts a zone file representation in a string to an RDATA on-the-wire
+ * representation. */
+u_int32_t
+loc_aton(ascii, binary)
+ const char *ascii;
+ u_char *binary;
+{
+ const char *cp, *maxcp;
+ u_char *bcp;
+
+ u_int32_t latit = 0, longit = 0, alt = 0;
+ u_int32_t lltemp1 = 0, lltemp2 = 0;
+ int altmeters = 0, altfrac = 0, altsign = 1;
+ u_int8_t hp = 0x16; /* default = 1e6 cm = 10000.00m = 10km */
+ u_int8_t vp = 0x13; /* default = 1e3 cm = 10.00m */
+ u_int8_t siz = 0x12; /* default = 1e2 cm = 1.00m */
+ int which1 = 0, which2 = 0;
+
+ cp = ascii;
+ maxcp = cp + strlen(ascii);
+
+ lltemp1 = latlon2ul(&cp, &which1);
+
+ lltemp2 = latlon2ul(&cp, &which2);
+
+ switch (which1 + which2) {
+ case 3: /* 1 + 2, the only valid combination */
+ if ((which1 == 1) && (which2 == 2)) { /* normal case */
+ latit = lltemp1;
+ longit = lltemp2;
+ } else if ((which1 == 2) && (which2 == 1)) { /* reversed */
+ longit = lltemp1;
+ latit = lltemp2;
+ } else { /* some kind of brokenness */
+ return 0;
+ }
+ break;
+ default: /* we didn't get one of each */
+ return 0;
+ }
+
+ /* altitude */
+ if (*cp == '-') {
+ altsign = -1;
+ cp++;
+ }
+
+ if (*cp == '+')
+ cp++;
+
+ while (isdigit(*cp))
+ altmeters = altmeters * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /* decimal meters */
+ cp++;
+ if (isdigit(*cp)) {
+ altfrac = (*cp++ - '0') * 10;
+ if (isdigit(*cp)) {
+ altfrac += (*cp++ - '0');
+ }
+ }
+ }
+
+ alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
+
+ while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */
+ cp++;
+
+ while (isspace(*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ siz = precsize_aton(&cp);
+
+ while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */
+ cp++;
+
+ while (isspace(*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ hp = precsize_aton(&cp);
+
+ while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */
+ cp++;
+
+ while (isspace(*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ vp = precsize_aton(&cp);
+
+ defaults:
+
+ bcp = binary;
+ *bcp++ = (u_int8_t) 0; /* version byte */
+ *bcp++ = siz;
+ *bcp++ = hp;
+ *bcp++ = vp;
+ PUTLONG(latit,bcp);
+ PUTLONG(longit,bcp);
+ PUTLONG(alt,bcp);
+
+ return (16); /* size of RR in octets */
+}
+
+/* takes an on-the-wire LOC RR and prints it in zone file (human readable)
+ format. */
+char *
+loc_ntoa(binary,ascii)
+ const u_char *binary;
+ char *ascii;
+{
+ static char tmpbuf[255*3];
+
+ register char *cp;
+ register const u_char *rcp;
+
+ int latdeg, latmin, latsec, latsecfrac;
+ int longdeg, longmin, longsec, longsecfrac;
+ char northsouth, eastwest;
+ int altmeters, altfrac, altsign;
+
+ const int referencealt = 100000 * 100;
+
+ int32_t latval, longval, altval;
+ u_int32_t templ;
+ u_int8_t sizeval, hpval, vpval, versionval;
+
+ char *sizestr, *hpstr, *vpstr;
+
+ rcp = binary;
+ cp = (ascii != NULL) ? ascii : tmpbuf;
+
+ versionval = *rcp++;
+
+ if (versionval) {
+ sprintf(cp,"; error: unknown LOC RR version");
+ return (cp);
+ }
+
+ sizeval = *rcp++;
+
+ hpval = *rcp++;
+ vpval = *rcp++;
+
+ GETLONG(templ,rcp);
+ latval = (templ - ((unsigned)1<<31));
+
+ GETLONG(templ,rcp);
+ longval = (templ - ((unsigned)1<<31));
+
+ GETLONG(templ,rcp);
+ if (templ < referencealt) { /* below WGS 84 spheroid */
+ altval = referencealt - templ;
+ altsign = -1;
+ } else {
+ altval = templ - referencealt;
+ altsign = 1;
+ }
+
+ if (latval < 0) {
+ northsouth = 'S';
+ latval = -latval;
+ }
+ else
+ northsouth = 'N';
+
+ latsecfrac = latval % 1000;
+ latval = latval / 1000;
+ latsec = latval % 60;
+ latval = latval / 60;
+ latmin = latval % 60;
+ latval = latval / 60;
+ latdeg = latval;
+
+ if (longval < 0) {
+ eastwest = 'W';
+ longval = -longval;
+ }
+ else
+ eastwest = 'E';
+
+ longsecfrac = longval % 1000;
+ longval = longval / 1000;
+ longsec = longval % 60;
+ longval = longval / 60;
+ longmin = longval % 60;
+ longval = longval / 60;
+ longdeg = longval;
+
+ altfrac = altval % 100;
+ altmeters = (altval / 100) * altsign;
+
+ sizestr = savestr(precsize_ntoa(sizeval));
+ hpstr = savestr(precsize_ntoa(hpval));
+ vpstr = savestr(precsize_ntoa(vpval));
+
+ sprintf(cp,
+ "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm",
+ latdeg, latmin, latsec, latsecfrac, northsouth,
+ longdeg, longmin, longsec, longsecfrac, eastwest,
+ altmeters, altfrac, sizestr, hpstr, vpstr);
+
+ free(sizestr);
+ free(hpstr);
+ free(vpstr);
+
+ return (cp);
+}
+
+#endif /* LOC_RR */
+
+/*
+ * Since the fields in a "struct timeval" are longs, and the argument to ctime
+ * is a pointer to a time_t (which might not be a long), here's a bridge.
+ */
+char *
+ctimel(l)
+ long l;
+{
+ time_t t = (time_t)l;
+
+ return (ctime(&t));
+}
+
+/*
+ * This is nec'y for systems that croak when deref'ing unaligned pointers.
+ * SPARC is an example. Note that in_addr.s_addr needn't be a 32-bit int,
+ * so we want to avoid bcopy and let the compiler do the casting for us.
+ */
+struct in_addr
+data_inaddr(data)
+ const u_char *data;
+{
+ struct in_addr ret;
+ u_int32_t tmp;
+
+ bcopy((char *)data, (char *)&tmp, INADDRSZ);
+ ret.s_addr = tmp;
+ return (ret);
+}
+
+/* Signal abstraction. */
+
+void
+setsignal(catch, block, handler)
+ int catch, block;
+ SIG_FN (*handler)();
+{
+#ifdef POSIX_SIGNALS
+ /* Modern system - preferred. */
+ struct sigaction sa;
+ memset(&sa, 0, sizeof sa);
+ sa.sa_handler = handler;
+ sigemptyset(&sa.sa_mask);
+ if (block != -1)
+ sigaddset(&sa.sa_mask, block);
+ (void) sigaction(catch, &sa, NULL);
+#else /*POSIX_SIGNALS*/
+#ifdef SYSV
+ /* Ancient system - ugly. */
+ if (block != -1)
+ syslog(LOG_DEBUG, "danger - unable to block signal %d from %d",
+ block, catch);
+ (void) signal(catch, handler);
+#else /*SYSV*/
+ /* BSD<=4.3 system - odd. */
+ struct sigvec sv;
+ bzero(&sv, sizeof sv);
+ sv.sv_handler = handler;
+ sv.sv_mask = sigmask(block);
+ (void) sigvec(catch, &sv, NULL);
+#endif /*SYSV*/
+#endif /*POSIX_SIGNALS*/
+}
+
+void
+resignal(catch, block, handler)
+ int catch, block;
+ SIG_FN (*handler)();
+{
+#if !defined(POSIX_SIGNALS) && defined(SYSV)
+ /* Unreliable signals. Set it back up again. */
+ setsignal(catch, block, handler);
+#endif
+}
diff --git a/usr.sbin/named/named/db_load.c b/usr.sbin/named/named/db_load.c
new file mode 100644
index 00000000000..5b3f9a801db
--- /dev/null
+++ b/usr.sbin/named/named/db_load.c
@@ -0,0 +1,1415 @@
+/* $NetBSD: db_load.c,v 1.1 1996/02/02 15:28:28 mrg Exp $ */
+
+#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 8.15 1995/12/31 23:28:17 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 <resolv.h>
+#include <errno.h>
+
+#include "named.h"
+
+static int gettoken __P((register FILE *, const char *)),
+ getnonblank __P((FILE *, const char *)),
+ getprotocol __P((FILE *, const char *)),
+ getservices __P((int, char *, FILE *, const char *));
+static void makename __P((char *, const char *));
+static int empty_token = 0;
+int getnum_error;
+
+/*
+ * 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 M_CLASS_CNT (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 },
+ { "nsap_ptr", T_NSAP_PTR },
+ { "uid", T_UID },
+ { "gid", T_GID },
+ { "px", T_PX },
+#ifdef notdef
+ { "any", T_ANY }, /* any is a QTYPE, not TYPE */
+#endif
+#ifdef LOC_RR
+ { "loc", T_LOC },
+#endif /* LOC_RR */
+#ifdef ALLOW_T_UNSPEC
+ { "unspec", T_UNSPEC },
+#endif /* ALLOW_T_UNSPEC */
+};
+#define M_TYPE_CNT (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, def_domain)
+ * load a database from `filename' into zone `zp'. append `in_origin'
+ * to all nonterminal domain names in the file. `def_domain' is the
+ * default domain for include files or NULL for zone base files.
+ * returns:
+ * -1 = can't open file
+ * 0 = success
+ * >0 = number of errors encountered
+ */
+int
+db_load(filename, in_origin, zp, def_domain)
+ const char *filename, *in_origin;
+ struct zoneinfo *zp;
+ const char *def_domain;
+{
+ static int read_soa, read_ns, rrcount;
+ register char *cp;
+ register struct map *mp;
+ char domain[MAXDNAME];
+ char origin[MAXDNAME];
+ char tmporigin[MAXDNAME];
+ char buf[MAXDATA];
+ char data[MAXDATA];
+ const char *cp1, *op;
+ int c, class, type, dbflags, dataflags, multiline;
+ u_int32_t ttl;
+ struct databuf *dp;
+ FILE *fp;
+ int slineno, i, errs, didinclude;
+ register u_int32_t n;
+ struct stat sb;
+ struct in_addr ina;
+ int escape;
+#ifdef DO_WARN_SERIAL
+ u_int32_t serial;
+#endif
+
+ errs = 0;
+ didinclude = 0;
+ if (!def_domain) {
+ /* This is not the result of a $INCLUDE. */
+ rrcount = 0;
+ read_soa = 0;
+ read_ns = 0;
+ clev = db_getclev(in_origin);
+ }
+
+ dprintf(1, (ddt,"db_load(%s, %s, %d, %s)\n",
+ filename, in_origin, zp - zones,
+ def_domain ? def_domain : "Nil"));
+
+ (void) strcpy(origin, in_origin);
+ if ((fp = fopen(filename, "r")) == NULL) {
+ syslog(LOG_WARNING, "%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;
+#ifdef STUBS
+ } else if (zp->z_type == Z_STUB && clev == 0) {
+ dbflags = DB_NODATA | DB_NOHINTS;
+ dataflags = DB_F_HINT;
+#endif
+ } else {
+ dbflags = DB_NODATA;
+ dataflags = 0;
+ }
+ gettime(&tt);
+ if (fstat(fileno(fp), &sb) < 0) {
+ syslog(LOG_WARNING, "%s: %m", filename);
+ sb.st_mtime = (int)tt.tv_sec;
+ }
+ slineno = lineno;
+ lineno = 1;
+ if (def_domain)
+ strcpy(domain, def_domain);
+ else
+ 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, 0))
+ /* file name*/
+ break;
+ if (!getword(tmporigin, sizeof(tmporigin), fp, 1))
+ strcpy(tmporigin, origin);
+ else {
+ makename(tmporigin, origin);
+ endline(fp);
+ }
+ didinclude = 1;
+ errs += db_load((char *)buf, tmporigin, zp, domain);
+ continue;
+
+ case ORIGIN:
+ (void) strcpy((char *)buf, origin);
+ if (!getword(origin, sizeof(origin), fp, 1))
+ 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, 1))
+ 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';
+ /* FALLTHROUGH */
+ case CURRENT:
+ gotdomain:
+ if (!getword((char *)buf, sizeof(buf), fp, 0)) {
+ if (c == CURRENT)
+ continue;
+ break;
+ }
+ cp = buf;
+ ttl = USE_MINIMUM;
+ if (isdigit(*cp)) {
+ n = 0;
+ do {
+ if (n > (INT_MAX - (*cp - '0')) / 10) {
+ syslog(LOG_INFO,
+ "%s: line %d: number > %lu\n",
+ filename, lineno, (u_long)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, 0))
+ break;
+ }
+ for (mp = m_class; mp < m_class+M_CLASS_CNT; mp++)
+ if (!strcasecmp((char *)buf, mp->token)) {
+ class = mp->val;
+ (void) getword((char *)buf,
+ sizeof(buf), fp, 0);
+ break;
+ }
+ for (mp = m_type; mp < m_type+M_TYPE_CNT; 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_INFO, "%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
+ switch (type) {
+ case T_SOA:
+ case T_MINFO:
+ case T_RP:
+ case T_NS:
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ escape = 1;
+ break;
+ default:
+ escape = 0;
+ }
+ if (!getword((char *)buf, sizeof(buf), fp, escape))
+ 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_INFO,
+ "%s: line %d: %s too long",
+ filename, lineno, (type == T_ISDN) ?
+ "ISDN-address" : "CPU type");
+ 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, 0))
+ i = 0;
+ else {
+ endline(fp);
+ i = strlen((char *)buf);
+ }
+ if (i == 0) {
+ if (type == T_ISDN) {
+ data[n++] = 0;
+ break;
+ }
+ else
+ /* goto err; */
+ /* XXX tolerate for now */
+ data[n++] = 1;
+ data[n++] = '?';
+ syslog(LOG_INFO,
+ "%s: line %d: OS-type missing",
+ filename,
+ empty_token ? (lineno - 1) : lineno);
+ break;
+ }
+ if (i > 255) {
+ syslog(LOG_INFO,
+ "%s:%d: %s too long",
+ filename, lineno, (type == T_ISDN) ?
+ "ISDN-sa" : "OS type");
+ 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, 1))
+ goto err;
+ makename(cp, origin);
+ cp += strlen((char *)cp) + 1;
+ if (type != T_SOA) {
+ n = cp - data;
+ break;
+ }
+ if (class != zp->z_class) {
+ errs++;
+ syslog(LOG_INFO,
+ "%s:%d: %s",
+ filename, lineno,
+ "SOA class not same as zone's");
+ }
+ if (strcasecmp(zp->z_origin, domain) != 0) {
+ errs++;
+ syslog(LOG_ERR,
+ "%s: line %d: SOA for \"%s\" not at zone top \"%s\"",
+ filename, lineno, domain,
+ zp->z_origin);
+ }
+ c = getnonblank(fp, filename);
+ if (c == '(') {
+ multiline = 1;
+ } else {
+ multiline = 0;
+ ungetc(c, fp);
+ }
+#ifdef DO_WARN_SERIAL
+ serial = zp->z_serial;
+#endif
+ zp->z_serial = getnum(fp, filename,
+ GETNUM_SERIAL);
+ if (getnum_error)
+ errs++;
+ n = (u_int32_t) zp->z_serial;
+ PUTLONG(n, cp);
+#ifdef DO_WARN_SERIAL
+ if (serial && SEQ_GT(serial, zp->z_serial)) {
+ syslog(LOG_NOTICE,
+ "%s:%d: WARNING: new serial number < old (%lu < %lu)",
+ filename , lineno,
+ zp->z_serial, serial);
+ }
+#endif
+ zp->z_refresh = getnum(fp, filename,
+ GETNUM_NONE);
+ if (getnum_error) {
+ errs++;
+ zp->z_refresh = INIT_REFRESH;
+ }
+ 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
+ ) {
+ ns_refreshtime(zp, MIN(sb.st_mtime,
+ tt.tv_sec));
+ }
+ zp->z_retry = getnum(fp, filename,
+ GETNUM_NONE);
+ if (getnum_error) {
+ errs++;
+ zp->z_retry = INIT_REFRESH;
+ }
+ n = (u_int32_t) zp->z_retry;
+ PUTLONG(n, cp);
+ zp->z_expire = getnum(fp, filename,
+ GETNUM_NONE);
+ if (getnum_error) {
+ errs++;
+ zp->z_expire = INIT_REFRESH;
+ }
+ n = (u_int32_t) zp->z_expire;
+ PUTLONG (n, cp);
+ zp->z_minimum = getnum(fp, filename,
+ GETNUM_NONE);
+ if (getnum_error) {
+ errs++;
+ zp->z_minimum = 120;
+ }
+ n = (u_int32_t) zp->z_minimum;
+ PUTLONG (n, cp);
+ n = cp - data;
+ if (multiline) {
+ if (getnonblank(fp, filename) != ')')
+ goto err;
+ }
+ read_soa++;
+ if (zp->z_expire < zp->z_refresh ) {
+ syslog(LOG_WARNING,
+ "%s: WARNING SOA expire value is less then SOA refresh (%lu < %lu)",
+ filename, zp->z_expire, zp->z_refresh);
+ }
+ 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:
+ if (strcasecmp(zp->z_origin, domain) == 0)
+ read_ns++;
+ /* FALLTHROUGH */
+ 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, 1))
+ 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_PX:
+ n = 0;
+ data[0] = '\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, 0))
+ goto err;
+ (void) strcpy((char *)cp, (char *)buf);
+ makename(cp, origin);
+ /* advance pointer to next field */
+ cp += strlen((char *)cp) +1;
+ if (!getword((char *)buf, sizeof(buf), fp, 0))
+ 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:
+ 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_INFO,
+ "%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, (u_char *)data,
+ sizeof data);
+ if (n == 0)
+ goto err;
+ endline(fp);
+ break;
+#ifdef LOC_RR
+ case T_LOC:
+ cp = buf + (n = strlen(buf));
+ *cp = ' ';
+ cp++;
+ 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 process the whole line */
+ n = loc_aton(buf, (u_char *)data);
+ if (n == 0)
+ goto err;
+ endline(fp);
+ break;
+#endif /* LOC_RR */
+#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) {
+ errs++;
+ syslog(LOG_INFO,
+ "Load T_UNSPEC: input buffer overflow");
+ } else {
+ errs++;
+ syslog(LOG_INFO,
+ "Load T_UNSPEC: Data in bad atob format");
+ }
+ }
+ }
+ break;
+#endif /* ALLOW_T_UNSPEC */
+
+ default:
+ goto err;
+ }
+#ifndef PURGE_ZONE
+#ifdef STUBS
+ if (type == T_SOA && zp->z_type == Z_STUB)
+ continue;
+#endif
+#endif
+#ifdef NO_GLUE
+ /*
+ * Ignore data outside the zone.
+ */
+ if (zp->z_type != Z_CACHE &&
+ !samedomain(domain, zp->z_origin))
+ {
+ syslog(LOG_INFO,
+ "%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);
+ } else {
+ rrcount++;
+ }
+ continue;
+
+ case ERROR:
+ break;
+ }
+ err:
+ errs++;
+ syslog(LOG_NOTICE, "%s: line %d: database format error (%s)",
+ filename, empty_token ? (lineno - 1) : lineno, buf);
+ if (!empty_token)
+ endline(fp);
+ }
+ (void) my_fclose(fp);
+ lineno = slineno;
+ if (!def_domain) {
+ 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) {
+ const char *msg = NULL;
+
+ if (read_soa == 0)
+ msg = "no SOA RR found";
+ else if (read_soa != 1)
+ msg = "multiple SOA RRs found";
+ else if (read_ns == 0)
+ msg = "no NS RRs found at zone top";
+ else if (!rrcount)
+ msg = "no relevant RRs found";
+ if (msg != NULL) {
+ errs++;
+ syslog(LOG_WARNING,
+ "Zone \"%s\" (file %s): %s",
+ zp->z_origin, filename, msg);
+ }
+ }
+ }
+#ifdef SECURE_ZONES
+ build_secure_netlist(zp);
+#endif
+ if (!def_domain)
+ syslog(LOG_INFO,
+ "%s zone \"%s\" %s (serial %lu)",
+ zoneTypeString(zp), zp->z_origin,
+ errs ? "rejected due to errors" : "loaded",
+ (u_long)zp->z_serial);
+ if (errs)
+ zp->z_flags |= Z_DB_BAD;
+#ifdef BIND_NOTIFY
+ /* XXX: this needs to be delayed, both according to the spec, and
+ * because the metadata needed by sysnotify() (and its sysquery())
+ * could be in other zones that we (at startup) havn't loaded yet.
+ */
+ if (!errs && !def_domain &&
+ (zp->z_type == Z_PRIMARY || zp->z_type == Z_SECONDARY))
+ sysnotify(zp->z_origin, zp->z_class, T_SOA);
+#endif
+ return (errs);
+}
+
+static int
+gettoken(fp, src)
+ register FILE *fp;
+ const 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, 0)) {
+ if (!strcasecmp("include", op))
+ return (INCLUDE);
+ if (!strcasecmp("origin", op))
+ return (ORIGIN);
+ }
+ syslog(LOG_NOTICE,
+ "%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, preserve)
+ * get next word, skipping blanks & comments.
+ * '\' '\n' outside of "quotes" is considered a blank.
+ * parameters:
+ * buf - destination
+ * size - of destination
+ * fp - file to read from
+ * preserve - should we preserve \ before \\ and \.?
+ * return value:
+ * 0 = no word; perhaps EOL or EOF
+ * 1 = word was read
+ */
+int
+getword(buf, size, fp, preserve)
+ char *buf;
+ int size;
+ FILE *fp;
+ int preserve;
+{
+ register char *cp = buf;
+ register int c;
+
+ empty_token = 0; /* XXX global side effect. */
+ while ((c = getc(fp)) != EOF) {
+ if (c == ';') {
+ /* Comment. Skip to end of line. */
+ while ((c = getc(fp)) != EOF && c != '\n')
+ NULL;
+ c = '\n';
+ }
+ if (c == '\n') {
+ /*
+ * Unescaped newline. It's a terminator unless we're
+ * already midway into a token.
+ */
+ if (cp != buf)
+ ungetc(c, fp);
+ else
+ lineno++;
+ break;
+ }
+ if (c == '"') {
+ /* "Quoted string." Gather the whole string here. */
+ while ((c = getc(fp)) != EOF && c!='"' && c!='\n') {
+ if (c == '\\') {
+ if ((c = getc(fp)) == EOF)
+ c = '\\';
+ if (preserve &&
+ (c == '\\' || c == '.')) {
+ if (cp >= buf+size-1)
+ break;
+ *cp++ = '\\';
+ }
+ if (c == '\n')
+ lineno++;
+ }
+ if (cp >= buf+size-1)
+ break;
+ *cp++ = c;
+ }
+ /*
+ * Newline string terminators are
+ * not token terminators.
+ */
+ if (c == '\n') {
+ lineno++;
+ break;
+ }
+ /* Sample following character, check for terminator. */
+ if ((c = getc(fp)) != EOF)
+ ungetc(c, fp);
+ if (c == EOF || isspace(c)) {
+ *cp = '\0';
+ return (1);
+ }
+ continue;
+ }
+ if (c == '\\') {
+ /* Do escape processing. */
+ if ((c = getc(fp)) == EOF)
+ c = '\\';
+ if (preserve && (c == '\\' || c == '.')) {
+ if (cp >= buf+size-1)
+ break;
+ *cp++ = '\\';
+ }
+ }
+ if (isspace(c)) {
+ /* Blank of some kind. Skip run. */
+ while (isspace(c = getc(fp)) && c != '\n')
+ NULL;
+ ungetc(c, fp);
+ /* Blank means terminator if the token is nonempty. */
+ if (cp != buf) /* Trailing whitespace */
+ break;
+ continue; /* Leading whitespace */
+ }
+ 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, opt)
+ FILE *fp;
+ const char *src;
+ int opt;
+{
+ register int c, n;
+ int seendigit = 0;
+ int seendecimal = 0;
+ int m = 0;
+ int allow_dots = 0;
+
+ getnum_error = 0;
+#ifdef DOTTED_SERIAL
+ if (opt & GETNUM_SERIAL)
+ allow_dots++;
+#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 (getnum_error)
+ continue;
+ if (!isdigit(c)) {
+ if (c == ')' && seendigit) {
+ (void) ungetc(c, fp);
+ break;
+ }
+ if (seendigit && (opt & GETNUM_SCALED) &&
+ strchr("KkMmGg", c) != NULL) {
+ switch (c) {
+ case 'K': case 'k':
+ n *= 1024;
+ break;
+ case 'M': case 'm':
+ n *= (1024 * 1024);
+ break;
+ case 'G': case 'g':
+ n *= (1024 * 1024 * 1024);
+ break;
+ }
+ break;
+ }
+ if (seendecimal || c != '.' || !allow_dots) {
+ syslog(LOG_NOTICE, "%s:%d: expected a number",
+ src, lineno);
+ getnum_error = 1;
+ } else {
+ if (!seendigit)
+ n = 1;
+#ifdef SENSIBLE_DOTS
+ n *= 10000;
+#else
+ 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 (getnum_error)
+ return (0);
+ if (m > 9999) {
+ syslog(LOG_INFO,
+ "%s:%d: number after the decimal point exceeds 9999",
+ src, lineno);
+ getnum_error = 1;
+ return (0);
+ }
+ 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;
+ const 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_INFO, "%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;
+ const char *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)) != '\0') {
+ if (c == '\n') {
+ (void) ungetc(c,fp);
+ break;
+ } else if (c == EOF) {
+ break;
+ }
+ }
+}
+
+#define MAXPORT 1024
+#define MAXLEN 24
+
+static int
+getprotocol(fp, src)
+ FILE *fp;
+ const char *src;
+{
+ int k;
+ char b[MAXLEN];
+
+ (void) getword(b, sizeof(b), fp, 0);
+
+ k = protocolnumber(b);
+ if (k == -1)
+ syslog(LOG_INFO, "%s: line %d: unknown protocol: %s.",
+ src, lineno, b);
+ return(k);
+}
+
+static int
+getservices(n, data, fp, src)
+ int n;
+ char *data;
+ FILE *fp;
+ const char *src;
+{
+ 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, 0) || 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_INFO,
+ "%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_INFO,
+ "%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_INFO, "%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, **end;
+ char buf[BUFSIZ], *maskp;
+ struct in_addr ina;
+
+ for (end = netlistp; *end; end = &(**end).next)
+ ;
+ ntp = NULL;
+ dprintf(1, (ddt, "get_netlist(%s)", print_tag));
+ while (getword(buf, sizeof(buf), fp, 0)) {
+ if (strlen(buf) == 0)
+ break;
+ if ((maskp = strchr(buf, '&')) != NULL)
+ *maskp++ = '\0';
+ dprintf(1, (ddt," %s", buf));
+ if (!ntp) {
+ ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
+ if (!ntp)
+ panic(errno, "malloc(netinfo)");
+ }
+ if (!inet_aton(buf, &ntp->my_addr)) {
+ syslog(LOG_INFO, "%s contains bogus element (%s)",
+ print_tag, buf);
+ continue;
+ }
+ if (maskp) {
+ if (!inet_aton(maskp, &ina)) {
+ syslog(LOG_INFO,
+ "%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_INFO,
+ "%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%lx addr x%lx mask x%lx",
+ (u_long)ntp, (u_long)ntp->addr,
+ (u_long)ntp->mask);
+ fprintf(ddt, " my_addr x%lx",
+ (u_long)ntp->my_addr.s_addr);
+ fprintf(ddt, " %s", inet_ntoa(ntp->my_addr));
+ fprintf(ddt, " next x%lx\n", (u_long)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/named/db_lookup.c b/usr.sbin/named/named/db_lookup.c
new file mode 100644
index 00000000000..91d9096d1d4
--- /dev/null
+++ b/usr.sbin/named/named/db_lookup.c
@@ -0,0 +1,198 @@
+/* $NetBSD: db_lookup.c,v 1.1 1996/02/02 15:28:31 mrg Exp $ */
+
+#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 8.3 1995/12/06 20:34:38 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)
+ const char *name;
+ struct hashbuf **htpp;
+ const char **fname;
+ int insert;
+{
+ register struct namebuf *np;
+ register const char *cp;
+ register int c;
+ register unsigned hval;
+ register struct hashbuf *htp;
+ struct namebuf *parent = NULL;
+ int escaped = 0;
+
+ htp = *htpp;
+ hval = 0;
+ *fname = "???";
+ for (cp = name; c = *cp++; ) {
+ if (!escaped && (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;
+ if (escaped)
+ escaped = 0;
+ else if (c == '\\')
+ escaped = 1;
+ }
+ cp--;
+ /*
+ * 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 &&
+ strncasecmp(name, np->n_dname, cp - name) == 0) {
+ *fname = name;
+ return (np);
+ }
+ }
+ if (!insert) {
+ /*
+ * Look for wildcard in this hash table.
+ * Don't use a cached "*" name as a wildcard,
+ * only authoritative.
+ */
+ hval = ('*' & HASHMASK) % htp->h_size;
+ for (np = htp->h_tab[hval]; np != NULL; np = np->n_next) {
+ if (np->n_dname[0] == '*' && np->n_dname[1] == '\0' &&
+ np->n_data && np->n_data->d_zone != 0) {
+ *fname = name;
+ return (np);
+ }
+ }
+ return (parent);
+ }
+ np = savename(name, cp - 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;
+ 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%lx, %d, %d) %d, %d\n",
+ (u_long)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/named/db_reload.c b/usr.sbin/named/named/db_reload.c
new file mode 100644
index 00000000000..923a7a2eb93
--- /dev/null
+++ b/usr.sbin/named/named/db_reload.c
@@ -0,0 +1,127 @@
+/* $NetBSD: db_reload.c,v 1.1 1996/02/02 15:28:33 mrg Exp $ */
+
+#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 8.1 1994/12/15 06:24:14 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/named/db_save.c b/usr.sbin/named/named/db_save.c
new file mode 100644
index 00000000000..73906e8cf42
--- /dev/null
+++ b/usr.sbin/named/named/db_save.c
@@ -0,0 +1,209 @@
+/* $NetBSD: db_save.c,v 1.1 1996/02/02 15:28:35 mrg Exp $ */
+
+#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 8.2 1995/06/29 09:26:17 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 <errno.h>
+
+#include "named.h"
+
+/*
+ * Allocate a name buffer & save name.
+ */
+struct namebuf *
+savename(name, len)
+ const char *name;
+ int len;
+{
+ register struct namebuf *np;
+
+ np = (struct namebuf *) malloc(sizeof(struct namebuf));
+ if (np == NULL)
+ panic(errno, "savename: malloc");
+ bzero((char*)np, sizeof(struct namebuf));
+ np->n_dname = malloc(len + 1);
+ if (np == NULL)
+ panic(errno, "savename: malloc");
+ strncpy(np->n_dname, name, len);
+ np->n_dname[len] = '\0';
+ 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;
+ int bytes = (type == T_NS) ? DATASIZE(size)+INT32SZ : DATASIZE(size);
+
+ dp = (struct databuf *)
+#ifdef DMALLOC
+ dmalloc(file, line, bytes)
+#else
+ malloc(bytes)
+#endif
+ ;
+ if (dp == NULL)
+ panic(errno, "savedata: malloc");
+ bzero((char*)dp, bytes);
+ 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(%#lx) cnt=%d, sz=%d, newsz=%d\n",
+ (u_long)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/named/db_secure.c b/usr.sbin/named/named/db_secure.c
new file mode 100644
index 00000000000..bd5a412573b
--- /dev/null
+++ b/usr.sbin/named/named/db_secure.c
@@ -0,0 +1,155 @@
+/* $NetBSD: db_secure.c,v 1.1 1996/02/02 15:28:36 mrg Exp $ */
+
+#ifndef LINT
+static char rcsid[] = "$Id: db_secure.c,v 8.5 1995/12/06 20:34:38 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 <errno.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;
+ const char *fname;
+ char *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, zp->z_class, 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)
+ panic(errno, "malloc(netinfo)");
+ }
+ if (!inet_aton(buf, &ntp->my_addr)) {
+ syslog(LOG_INFO,
+ "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_INFO,
+ "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)) {
+ syslog(LOG_INFO,
+ "build_secure_netlist (%s): addr (%s) is not in mask (%#lx)",
+ zp->z_origin,
+ inet_ntoa(ntp->my_addr),
+ (u_long)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)) {
+ syslog(LOG_INFO,
+ "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%lx addr x%lx mask x%lx",
+ (u_long)ntp, (u_long)ntp->addr,
+ (u_long)ntp->mask);
+ fprintf(ddt, " my_addr %#lx",
+ (u_long)ntp->my_addr.s_addr);
+ fprintf(ddt, " %s", inet_ntoa(ntp->my_addr));
+ fprintf(ddt, " next x%lx\n", (u_long)ntp->next);
+ }
+ }
+#endif
+ return (errs);
+}
+#endif /*SECURE_ZONES*/
diff --git a/usr.sbin/named/named/db_update.c b/usr.sbin/named/named/db_update.c
new file mode 100644
index 00000000000..90a02d3e905
--- /dev/null
+++ b/usr.sbin/named/named/db_update.c
@@ -0,0 +1,735 @@
+/* $NetBSD: db_update.c,v 1.1 1996/02/02 15:28:37 mrg Exp $ */
+
+#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 8.7 1995/12/06 20:34:38 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 <resolv.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_class == C_HS) &&
+ 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);
+}
+
+
+#ifdef NO_GLUE
+#define ISVALIDGLUE(xdp) ((xdp)->d_type == T_NS || (xdp)->d_type == T_A)
+#else
+#define ISVALIDGLUE(xdp) (1)
+#endif /*NO_GLUE*/
+
+
+/* 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;
+ const char *fname;
+
+ dprintf(3, (ddt, "db_update(%s, 0x%lx, 0x%lx, 0%o, 0x%lx)%s\n",
+ name, (u_long)odp, (u_long)newdp, flags, (u_long)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 && ((zn = findMyZone(np, newdp->d_class)) != DB_Z_CACHE) &&
+#ifdef STUBS
+ (zones[zn].z_type != Z_STUB) &&
+#endif
+ (flags & DB_NOTAUTH)) {
+ int foundRR = 0;
+
+ /*
+ * Don't generate the warning 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)
+ dprintf(5, (ddt,
+ "[%s].%d update? to auth zone \"%s\" (%s)",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port),
+ zones[zn].z_origin,
+ name));
+ return (AUTH);
+ }
+
+ if (newdp && zn && !(flags & DB_NOTAUTH)) {
+ if (db_getclev(zones[zn].z_origin) > newdp->d_clev) {
+ dprintf(5,(ddt, "attempted update child zone %s, %s\n",
+ zones[zn].z_origin, name));
+ return(AUTH);
+ }
+ }
+
+ /* some special checks for root NS' A RR's */
+ isHintNS = isRefByNS(name, fcachetab);
+#ifdef DEPRECATED
+ if (newdp && isHintNS && newdp->d_type == T_A) {
+ /* 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;
+ }
+ }
+#endif
+
+ /* Reflect certain updates in hint cache also... */
+ /* Don't stick data we are authoritative for in hints. */
+ if (!(flags & DB_NOHINTS) &&
+ (flags & DB_PRIMING) &&
+ (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 %lx freed\n",
+ (u_long)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_INFO,
+ "%s has CNAME and other data (illegal)\n",
+ name);
+ goto skip;
+ }
+ if (!newdp || newdp->d_class != dp->d_class)
+ goto skip;
+
+ /* 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 0 /* caught by findMyZone() now. */
+ /* 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);
+#endif
+
+ /* if the new data is authoritative but
+ * but isn't as credible, reject it.
+ */
+ if (newdp->d_cred == DB_C_ZONE &&
+ dp->d_cred == DB_C_ZONE) {
+ /* Both records are from a zone file.
+ * If their credibility levels differ,
+ * we're dealing with a zone cut. The
+ * record with lower clev is from the
+ * upper zone's file and is therefore
+ * glue.
+ */
+ if (newdp->d_clev < dp->d_clev) {
+ if (!ISVALIDGLUE(newdp)) {
+ syslog(LOG_INFO,
+ "domain %s %s record in zone %s should be in zone %s, ignored",
+ name, p_type(newdp->d_type),
+ zones[newdp->d_zone].z_origin,
+ zones[dp->d_zone].z_origin);
+ }
+ return (AUTH);
+ }
+ if (newdp->d_clev > dp->d_clev) {
+ if (!ISVALIDGLUE(dp)) {
+ syslog(LOG_INFO,
+ "domain %s %s record in zone %s should be in zone %s, deleted",
+ name, p_type(dp->d_type),
+ zones[dp->d_zone].z_origin,
+ zones[newdp->d_zone].z_origin);
+ }
+ goto delete;
+ }
+ }
+#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) {
+ /* better credibility.
+ * 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 &&
+ dp->d_cred == DB_C_ZONE ) {
+ /* Both records are from a zone file.
+ * If their credibility levels differ,
+ * we're dealing with a zone cut. The
+ * record with lower clev is from the
+ * upper zone's file and is therefore
+ * glue.
+ */
+
+ /* XXX - Tricky situation here is you
+ * have 2 zones a.b.c and sub.a.b.c
+ * being served by the same server.
+ * named will send NS records for
+ * sub.a.b.c during zone transfer of
+ * a.b.c zone. If we're secondary for
+ * both zones, and we reload zone
+ * a.b.c, we'll get the NS records
+ * (and possibly A records to go with
+ * them?) for sub.a.b.c as part of the
+ * a.b.c zone transfer. But we've
+ * already got a more credible record
+ * from the sub.a.b.c zone. So we want
+ * to ignore the new record, but we
+ * shouldn't syslog because there's
+ * nothing the user can do to prevent
+ * the situation. Perhaps we should
+ * only complain when we are primary?
+ */
+
+ if (newdp->d_clev < dp->d_clev) {
+ if (!ISVALIDGLUE(newdp)) {
+ syslog(LOG_INFO,
+ "domain %s %s record in zone %s should be in zone %s, ignored",
+ name, p_type(newdp->d_type),
+ zones[newdp->d_zone].z_origin,
+ zones[dp->d_zone].z_origin);
+ }
+ return (AUTH);
+ }
+ if (newdp->d_clev > dp->d_clev) {
+ if (!ISVALIDGLUE(dp)) {
+ syslog(LOG_INFO,
+ "domain %s %s record in zone %s should be in zone %s, deleted",
+ name, p_type(dp->d_type),
+ zones[dp->d_zone].z_origin,
+ zones[newdp->d_zone].z_origin);
+ }
+ goto delete;
+ }
+ }
+
+ /* 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,
+ INT32SZ + sizeof(u_char)))
+ 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 %ld +%d\n",
+ (u_long)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 %lx\n",
+ (newdp->d_flags&DB_F_HINT) ? " hint":"", (u_long)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, len2;
+
+ 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:
+ case T_LOC:
+#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;
+ len2 = *cp2;
+ if (len != len2)
+ return (1);
+ if (strncasecmp((char *)++cp1, (char *)++cp2, len))
+ return (1);
+ cp1 += len;
+ cp2 += len;
+ len = *cp1;
+ len2 = *cp2;
+ if (len != len2)
+ return (1);
+ 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_PX:
+ cp1 = dp1->d_data;
+ cp2 = dp2->d_data;
+ if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* cmp prio */
+ return (1);
+ if (strcasecmp((char *)cp1, (char *)cp2))
+ return (1);
+ cp1 += strlen((char *)cp1) + 1;
+ cp2 += strlen((char *)cp2) + 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/named/dmalloc.c b/usr.sbin/named/named/dmalloc.c
new file mode 100644
index 00000000000..8e3075cf2d8
--- /dev/null
+++ b/usr.sbin/named/named/dmalloc.c
@@ -0,0 +1,316 @@
+/* $NetBSD: dmalloc.c,v 1.1 1996/02/02 15:28:39 mrg Exp $ */
+
+/* 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 8.2 1995/12/06 20:34:38 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);
+ if (!d)
+ return (NULL);
+ 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/named/dmalloc.h b/usr.sbin/named/named/dmalloc.h
new file mode 100644
index 00000000000..cb68c497e3f
--- /dev/null
+++ b/usr.sbin/named/named/dmalloc.h
@@ -0,0 +1,70 @@
+/* $NetBSD: dmalloc.h,v 1.1 1996/02/02 15:28:40 mrg Exp $ */
+
+/* dmalloc - debugging layer on top of malloc
+ * vix 22mar92 [written]
+ *
+ * $Id: dmalloc.h,v 8.1 1994/12/15 06:24:14 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/named.h b/usr.sbin/named/named/named.h
new file mode 100644
index 00000000000..6a07783dc90
--- /dev/null
+++ b/usr.sbin/named/named/named.h
@@ -0,0 +1,21 @@
+/* $NetBSD: named.h,v 1.1 1996/02/02 15:28:41 mrg Exp $ */
+
+/* named.h - include the local definitions in the right order
+ * vix 28aug93 [original]
+ *
+ * $Id: named.h,v 8.1 1994/12/15 06:24:14 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/named/ns_defs.h b/usr.sbin/named/named/ns_defs.h
new file mode 100644
index 00000000000..eef87090ba8
--- /dev/null
+++ b/usr.sbin/named/named/ns_defs.h
@@ -0,0 +1,403 @@
+/* $NetBSD: ns_defs.h,v 1.1 1996/02/02 15:28:42 mrg Exp $ */
+
+/*
+ * from ns.h 4.33 (Berkeley) 8/23/90
+ * $Id: ns_defs.h,v 8.4 1995/12/22 10:20:30 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_PER_NS 2 /* max # of xfers per peer nameserver */
+#define XFER_BUFSIZE (16*1024) /* arbitrary but bigger than most MTU's */
+
+#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 */
+
+#define USE_MINIMUM 0xffffffff
+
+ /* sequence-space arithmetic */
+#define SEQ_GT(a,b) ((int32_t)((a)-(b)) > 0)
+
+ /* wildcard predicate */
+#define WILDCARD_P(str) (str[0] == '*' && str[1] == '\0')
+
+ /* cheap garbage collection */
+#define FREE_ONCE(p) { if (p) { free(p); p = NULL; } }
+
+/* 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
+#ifdef BIND_NOTIFY
+ /* XXX - this will have to move to the name when we do !SOA notify */
+ struct notify *z_notifylist; /* list of servers we should notify */
+#endif
+};
+
+#ifdef BIND_NOTIFY
+struct notify {
+ struct in_addr addr; /* of server */
+ time_t last; /* when they asked */
+ struct notify *next;
+ /* XXX - this will need a type field when we do !SOA notify */
+};
+#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 */
+#define Z_XFER_ABORTED 0x2000 /* zone transfer has been aborted */
+#define Z_XFER_GONE 0x4000 /* zone transfer process is gone */
+
+ /* 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) */
+#if defined(LAME_DELEGATION) || defined(VALIDATE)
+ char q_domain[MAXDNAME]; /* domain for servers we are querying */
+#endif
+#ifdef BIND_NOTIFY
+ int q_notifyzone; /* zone which needs a sysnotify()
+ * when the reply to this comes in.
+ */
+#endif
+};
+
+ /* 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 */
+#ifdef XSTATS
+ nssNotNsQ, /* query received from remote port != ns_port */
+ nssSentNaAns, /* sent them a non autoritative answer */
+ nssSentNXD, /* sent them a negative response */
+#endif
+ 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) (ddt && (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/named/ns_forw.c b/usr.sbin/named/named/ns_forw.c
new file mode 100644
index 00000000000..1f5994324ee
--- /dev/null
+++ b/usr.sbin/named/named/ns_forw.c
@@ -0,0 +1,994 @@
+/* $NetBSD: ns_forw.c,v 1.1 1996/02/02 15:28:44 mrg Exp $ */
+
+#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 8.9 1995/12/22 10:20:30 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 = nsqhead; 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();
+#if defined(LAME_DELEGATION) || defined(VALIDATE)
+ 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 && !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(nsid_next());
+ hp->ancount = htons(0);
+ hp->nscount = htons(0);
+ hp->arcount = htons(0);
+ if ((qp->q_msg = (u_char *)malloc((unsigned)msglen)) == NULL) {
+ syslog(LOG_NOTICE, "forw: malloc: %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,
+ (int)(qp->q_time - tt.tv_sec)));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_nquery(msg, msglen, ddt);
+#endif
+ if (sendto(ds, (char *)msg, msglen, 0, (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0) {
+ if (!haveComplained((char*)(long)nsa->sin_addr.s_addr, sendtoStr))
+ syslog(LOG_INFO, "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)
+ const char *tag1, *tag2;
+{
+ struct complaint {
+ const 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));
+ if (cur) {
+ cur->tag1 = tag1;
+ cur->tag2 = tag2;
+ cur->expire = tt.tv_sec + INIT_REFRESH; /* "10:00" */
+ 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.
+ */
+static void
+nslookupComplain(sysloginfo, queryname, complaint, dname, a_rr, nsdp)
+ const char *sysloginfo, *queryname, *complaint, *dname;
+ const struct databuf *a_rr, *nsdp;
+{
+#ifdef STATS
+ char nsbuf[20];
+ char abuf[20];
+#endif
+ char *a, *ns;
+
+ dprintf(2, (ddt, "NS '%s' %s\n", dname, complaint));
+ if (sysloginfo && queryname && !haveComplained(queryname, complaint))
+ {
+ char buf[999];
+
+ a = ns = (char *)NULL;
+#ifdef STATS
+ if (nsdp) {
+ if (nsdp->d_ns) {
+ strcpy(nsbuf, inet_ntoa(nsdp->d_ns->addr));
+ ns = nsbuf;
+ } else {
+ ns = zones[nsdp->d_zone].z_origin;
+ }
+ }
+ if (a_rr->d_ns) {
+ strcpy(abuf, inet_ntoa(a_rr->d_ns->addr));
+ a = abuf;
+ } else {
+ a = zones[a_rr->d_zone].z_origin;
+ }
+#endif
+ /* syslog only takes 5 params */
+ if ( a != NULL || ns != NULL)
+ sprintf(buf, "%s: query(%s) %s (%s:%s) learnt (A=%s:NS=%s)",
+ sysloginfo, queryname,
+ complaint, dname,
+ inet_ntoa(data_inaddr(a_rr->d_data)),
+ a ? a : "<Not Available>",
+ ns ? ns : "<Not Available>" );
+ else
+ sprintf(buf, "%s: query(%s) %s (%s:%s)",
+ sysloginfo, queryname,
+ complaint, dname,
+ inet_ntoa(data_inaddr(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;
+ const char *syslogdname;
+ const 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;
+ const char *fname;
+ int oldn, naddr, class, found_arr;
+ time_t curtime;
+
+ dprintf(3, (ddt, "nslookup(nsp=0x%lx, qp=0x%lx, \"%s\")\n",
+ (u_long)nsp, (u_long)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 (%#lx)\n",
+ dname, class, nsdp->d_type,
+ (u_long)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 %lx\n",
+ dname, fname, (u_long)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;
+
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ if (dp->d_type == T_CNAME && dp->d_class == class)
+ goto skipserver;
+ if (dp->d_type != T_A || dp->d_class != class)
+ continue;
+ if (data_inaddr(dp->d_data).s_addr == INADDR_ANY) {
+ static char *complaint = "Bogus (0.0.0.0) A RR";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp, nsdp);
+ continue;
+ }
+#ifdef INADDR_LOOPBACK
+ if (ntohl(data_inaddr(dp->d_data).s_addr) ==
+ INADDR_LOOPBACK) {
+ static char *complaint = "Bogus LOOPBACK A RR";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp, nsdp);
+ continue;
+ }
+#endif
+#ifdef INADDR_BROADCAST
+ if (ntohl(data_inaddr(dp->d_data).s_addr) ==
+ INADDR_BROADCAST) {
+ static char *complaint = "Bogus BROADCAST A RR";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp, nsdp);
+ continue;
+ }
+#endif
+#ifdef IN_MULTICAST
+ if (IN_MULTICAST(ntohl(data_inaddr(dp->d_data).s_addr))) {
+ static char *complaint = "Bogus MULTICAST A RR";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp, nsdp);
+ 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) &&
+#ifdef DATUMREFCNT
+ (dp->d_ttl < curtime) &&
+#else
+ (dp->d_ttl < (curtime+900)) &&
+#endif
+ !(dp->d_flags & DB_F_HINT) )
+ {
+ dprintf(3, (ddt,
+ "nslookup: stale entry '%s'\n",
+ np->n_dname));
+ /* Cache invalidate the NS RR's */
+#ifndef DATUMREFCNT
+ if (dp->d_ttl < curtime)
+#endif
+ {
+ delete_all(np, class, T_A);
+ n = oldn;
+ found_arr = 0;
+ goto need_sysquery;
+ }
+ }
+#ifdef VALIDATE
+ /* anant@isi.edu validation procedure, maintains a
+ * table of server names-addresses used recently
+ */
+ store_name_addr(dname, data_inaddr(dp->d_data),
+ syslogdname, sysloginfo);
+#endif /*VALIDATE*/
+
+ found_arr++;
+ nsa = data_inaddr(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, nsdp);
+ 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, nsdp);
+ return (-1);
+ }
+#ifdef BOGUSNS
+ /*
+ * 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;
+#endif
+
+ n++;
+ if (n >= NSMAX)
+ goto out;
+ skipaddr:
+ NULL;
+ }
+ dprintf(8, (ddt, "nslookup: %d ns addrs\n", n));
+ need_sysquery:
+ if (found_arr == 0 && !(qp->q_flags & Q_SYSTEM))
+ (void) sysquery(dname, class, T_A, NULL, 0, QUERY);
+ skipserver:
+ NULL;
+ }
+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%lx, %ld sec)\n",
+ (u_long)qp, (long)t);
+ if (qp->q_time)
+ fprintf(ddt,
+ "WARNING: schedretry(%#lx, %ld) q_time already %ld\n",
+ (u_long)qp, (long)t, (long)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(%#lx, %d)\n", (u_long)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%lx) id=%d\n", (u_long)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%lx): expired @ %lu (%d secs before now (%lu))\n",
+ (u_long)qp, (u_long)qp->q_expire,
+ (int)(tt.tv_sec - qp->q_expire),
+ (u_long)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 = (NoRecurse == 0);
+ hp->rd = 1;
+ hp->rcode = SERVFAIL;
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_nquery(qp->q_msg, n, ddt);
+#endif
+ if (send_msg((u_char *)hp, n, qp)) {
+ dprintf(1, (ddt, "gave up retry(x%lx) nsid=%d id=%d\n",
+ (u_long)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_nquery(qp->q_msg, qp->q_msglen, ddt);
+#endif
+ /* NOSTRICT */
+ if (sendto(ds, (char*)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 (nsqhead)
+ qremove(nsqhead);
+ nsqhead = QINFO_NULL;
+}
+
+void
+qremove(qp)
+ register struct qinfo *qp;
+{
+ dprintf(3, (ddt, "qremove(x%lx)\n", (u_long)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 = nsqhead; 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;
+
+ qp = (struct qinfo *)
+#ifdef DMALLOC
+ dcalloc(file, line, 1, sizeof(struct qinfo));
+#else
+ calloc(1, sizeof(struct qinfo));
+#endif
+ if (qp == NULL) {
+ dprintf(5, (ddt, "qnew: calloc error\n"));
+ syslog(LOG_ERR, "forw: %m");
+ exit(12);
+ }
+ dprintf(5, (ddt, "qnew(x%lx)\n", (u_long)qp));
+#ifdef BIND_NOTIFY
+ qp->q_notifyzone = DB_Z_CACHE;
+#endif
+ qp->q_link = nsqhead;
+ nsqhead = qp;
+ return (qp);
+}
+
+void
+qfree(qp)
+ struct qinfo *qp;
+{
+ register struct qinfo *np;
+ register struct databuf *dp;
+#ifdef DATUMREFCNT
+ int i;
+#endif
+
+ dprintf(3, (ddt, "Qfree(x%lx)\n", (u_long)qp));
+ if (qp->q_next)
+ dprintf(1, (ddt, "WARNING: qfree of linked ptr x%lx\n",
+ (u_long)qp));
+ 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( nsqhead == qp ) {
+ nsqhead = qp->q_link;
+ } else {
+ for( np=nsqhead; 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/named/ns_func.h b/usr.sbin/named/named/ns_func.h
new file mode 100644
index 00000000000..03d3663bc36
--- /dev/null
+++ b/usr.sbin/named/named/ns_func.h
@@ -0,0 +1,163 @@
+/* $NetBSD: ns_func.h,v 1.1 1996/02/02 15:28:46 mrg Exp $ */
+
+/* ns_func.h - declarations for ns_*.c's externally visible functions
+ *
+ * $Id: ns_func.h,v 8.6 1995/12/22 10:20:30 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((const char *, int, int,
+ struct in_addr *, int, int));
+extern struct notify *findNotifyPeer __P((const struct zoneinfo *,
+ struct in_addr));
+extern void sysnotify __P((const char *, int, 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, int *));
+/* --from ns_resp.c-- */
+
+/* ++from ns_req.c++ */
+extern void ns_req __P((u_char *, int, int,
+ struct qstream *,
+ struct sockaddr_in *,
+ int)),
+ free_addinfo __P((void)),
+ free_nsp __P((struct databuf **));
+extern int stale __P((struct databuf *)),
+ make_rr __P((const char *, struct databuf *,
+ u_char *, int, int)),
+ doaddinfo __P((HEADER *, u_char *, int)),
+ doaddauth __P((HEADER *, u_char *, int,
+ struct namebuf *,
+ struct databuf *));
+#ifdef BIND_NOTIFY
+extern int findZonePri __P((const struct zoneinfo *,
+ const struct sockaddr_in *));
+#endif
+/* --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((const char *, const char *)),
+ nslookup __P((struct databuf *nsp[],
+ struct qinfo *qp,
+ const char *syslogdname,
+ const char *sysloginfo)),
+ qcomp __P((struct qserv *, struct qserv *));
+extern struct qdatagram *aIsUs __P((struct in_addr));
+extern void 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)),
+ nsid_init __P((void));
+extern u_int16_t nsid_next __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
+#ifdef PURGE_ZONE
+ purge_zone __P((const char *, struct hashbuf *, int)),
+#endif
+ loadxfer __P((void)),
+ qserial_query __P((struct zoneinfo *)),
+ qserial_answer __P((struct qinfo *, u_int32_t));
+extern void holdsigchld __P((void));
+extern void releasesigchld __P((void));
+extern SIG_FN reapchild __P(());
+extern void endxfer __P((void));
+extern const char * zoneTypeString __P((const struct zoneinfo *));
+#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_refreshtime __P((struct zoneinfo *, time_t)),
+ ns_retrytime __P((struct zoneinfo *, time_t)),
+ 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));
+#ifdef XSTATS
+extern void ns_logstats __P((void));
+#endif
+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 *, char *, struct sockaddr_in *,
+ int, int, char *, int, int)),
+#else
+ validate __P((char *, char *, struct sockaddr_in *,
+ int, int, char *, int)),
+#endif
+ dovalidate __P((u_char *, int, u_char *, int, int,
+ char *, struct sockaddr_in *, int *)),
+ update_msg __P((u_char *, int *, int Vlist[], int));
+extern void store_name_addr __P((const char *, struct in_addr,
+ const char *, const char *));
+/* --from ns_validate.c-- */
diff --git a/usr.sbin/named/named/ns_glob.h b/usr.sbin/named/named/ns_glob.h
new file mode 100644
index 00000000000..dd40ee22f4f
--- /dev/null
+++ b/usr.sbin/named/named/ns_glob.h
@@ -0,0 +1,272 @@
+/* $NetBSD: ns_glob.h,v 1.1 1996/02/02 15:28:48 mrg Exp $ */
+
+/*
+ * from ns.h 4.33 (Berkeley) 8/23/90
+ * $Id: ns_glob.h,v 8.6 1995/12/22 10:20:30 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 *nsqhead INIT(QINFO_NULL);
+
+ /* list of forwarding hosts */
+DECL struct fwdinfo *fwdtab INIT(NULL);
+
+ /* 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);
+
+#ifdef CLEANCACHE
+ /* What's the minimum interval between cache cleanings? */
+DECL int cache_interval INIT(60*60);
+#endif
+
+#ifdef XSTATS
+ /* What's the minimum interval between stats output? */
+DECL int stats_interval INIT(60*60);
+#endif
+
+ /* need to process finished zone transfers */
+DECL int needendxfer INIT(0);
+
+ /* 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 XSTATS
+ /* need to exit
+ * set by shutdown signal handler
+ * (onintr)
+ */
+DECL int needToExit INIT(0);
+#endif /* XSTATS */
+
+#ifdef QRYLOG
+ /* is query logging turned on? */
+DECL int qrylog INIT(0);
+#endif /*QRYLOG*/
+
+ /* should this server not recurse? */
+DECL int NoRecurse INIT(0);
+
+ /* should this server never fetch glue? */
+DECL int NoFetchGlue 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;
+
+ /* 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 const char *statsfile INIT(STATSFILE);
+#else
+DECL const char *statsfile INIT(_PATH_STATS);
+#endif
+
+DECL const 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);
+
+ /* max number of transfers to any given name server */
+DECL int max_xfers_per_ns INIT(MAX_XFERS_PER_NS);
+
+#ifndef INVQ
+ /* should IQUERY be answered bogusly rather than with NOTIMPL? */
+DECL int fake_iquery INIT(0);
+#endif
diff --git a/usr.sbin/named/named/ns_init.c b/usr.sbin/named/named/ns_init.c
new file mode 100644
index 00000000000..c7aed147a4f
--- /dev/null
+++ b/usr.sbin/named/named/ns_init.c
@@ -0,0 +1,963 @@
+/* $NetBSD: ns_init.c,v 1.1 1996/02/02 15:28:50 mrg Exp $ */
+
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_init.c 4.38 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: ns_init.c,v 8.12 1995/12/29 07:16:18 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/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <syslog.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "named.h"
+
+#undef nsaddr
+
+enum limit { Datasize };
+
+static void zoneinit __P((struct zoneinfo *)),
+ get_forwarders __P((FILE *)),
+ boot_read __P((const char *filename, int includefile)),
+#ifdef DEBUG
+ content_zone __P((int)),
+#endif
+ free_forwarders __P((void)),
+ ns_limit __P((const char *name, int value)),
+ ns_rlimit __P((const char *name, enum limit limit,
+ long value)),
+ ns_option __P((const char *name));
+
+static struct zoneinfo *find_zone __P((char *, int, int));
+
+/*
+ * Set new refresh time for zone. Use a random number in the last half of
+ * the refresh limit; we want it to be substantially correct while still
+ * preventing slave synchronization.
+ */
+void
+ns_refreshtime(zp, timebase)
+ struct zoneinfo *zp;
+ time_t timebase;
+{
+ u_long refresh = (zp->z_refresh > 0) ? zp->z_refresh : INIT_REFRESH;
+ time_t half = (refresh + 1) / 2;
+
+ zp->z_time = timebase + half + (rand() % half);
+}
+
+/*
+ * Set new retry time for zone.
+ */
+void
+ns_retrytime(zp, timebase)
+ struct zoneinfo *zp;
+ time_t timebase;
+{
+ zp->z_time = timebase + zp->z_retry;
+}
+
+/*
+ * 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;
+ zones[0].z_origin = "";
+ } 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, 0);
+
+ /* 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(filename, includefile)
+ const char *filename;
+ int includefile;
+{
+ 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 *flag;
+#endif
+ int slineno; /* Saved global line number. */
+ int i;
+
+ if ((fp = fopen(filename, "r")) == NULL) {
+ syslog(LOG_ERR, "%s: %m", filename);
+ if (includefile)
+ return;
+ exit(1);
+ }
+
+ slineno = lineno;
+ lineno = 1;
+
+ while (!feof(fp) && !ferror(fp)) {
+ /* read named.boot keyword and process args */
+ if (!getword(buf, sizeof(buf), fp, 0)) {
+ /*
+ * This is a blank line, a commented line, or the
+ * '\n' of the previous line.
+ */
+ continue;
+ }
+ if (strcasecmp(buf, "directory") == 0) {
+ (void) getword(buf, sizeof(buf), fp, 0);
+ 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, filename, GETNUM_NONE);
+ continue;
+ } else if (strcasecmp(buf, "limit") == 0) {
+ (void) getword(buf, sizeof(buf), fp, 0);
+ ns_limit(buf, getnum(fp, filename, GETNUM_SCALED));
+ continue;
+ } else if (strcasecmp(buf, "options") == 0) {
+ while (getword(buf, sizeof(buf), fp, 0))
+ ns_option(buf);
+ continue;
+ } else if (strcasecmp(buf, "forwarders") == 0) {
+ get_forwarders(fp);
+ continue;
+ } else if (strcasecmp(buf, "slave") == 0) {
+ forward_only++;
+ 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, 1))
+ localdomain = savestr(buf);
+ continue;
+#endif
+ } else if (strcasecmp(buf, "include") == 0) {
+ if (getword(buf, sizeof(buf), fp, 0))
+ boot_read(buf, 1);
+ 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);
+
+ if (class != C_IN) {
+ syslog(LOG_NOTICE,
+ "cache directive with non-IN class is not supported (yet)");
+ endline(fp);
+ continue;
+ }
+ }
+#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_NOTICE,
+ "%s: line %d: unknown directive '%s'\n",
+ filename, lineno, buf);
+ endline(fp);
+ continue;
+ }
+
+ /*
+ * read zone origin
+ */
+ if (!getword(obuf, sizeof(obuf), fp, 1)) {
+ syslog(LOG_NOTICE, "%s: line %d: missing origin\n",
+ filename, lineno);
+ continue;
+ }
+ i = strlen(obuf);
+ if ((obuf[i-1] == '.') && (i != 1))
+ syslog(LOG_INFO,
+ "%s: line %d: zone \"%s\" has trailing dot\n",
+ filename, 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, 0)) {
+ syslog(LOG_NOTICE, "%s: line %d: missing %s\n",
+ filename, 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];
+ 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) {
+ syslog(LOG_NOTICE,
+ "no memory for more zones");
+ 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, 0)) {
+#ifdef notyet
+ zp->z_refresh = atoi(buf);
+ if (zp->z_refresh <= 0) {
+ syslog(LOG_NOTICE,
+ "%s: line %d: bad refresh time '%s', ignored\n",
+ filename, lineno, buf);
+ zp->z_refresh = 0;
+ } else if (cache_file == NULL)
+ cache_file = source;
+#else
+ syslog(LOG_NOTICE,
+ "%s: line %d: cache refresh ignored\n",
+ filename, 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, NULL);
+ break;
+
+ case Z_PRIMARY:
+ source = savestr(buf);
+#ifdef ALLOW_UPDATES
+ if (getword(buf, sizeof(buf), fp, 0)) {
+ endline(fp);
+ flag = buf;
+ while (flag) {
+ char *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_NOTICE,
+ "%s: line %d: bad flag '%s'\n",
+ filename, 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;
+#ifdef PURGE_ZONE
+ purge_zone(zp->z_origin, hashtab, zp->z_class);
+#endif
+ dprintf(1, (ddt, "reloading zone\n"));
+ if (!db_load(zp->z_source, zp->z_origin, zp, NULL))
+ 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, 0));
+ 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%ld.%d", _PATH_TMPDIR,
+ (long)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 (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))
+ && reloading) {
+ zp->z_time = tt.tv_sec;
+ needmaint = 1;
+ }
+ }
+#endif /* FORCED_RELOAD */
+ break;
+
+ }
+ if ((zp->z_flags & Z_FOUND) && /* already found? */
+ (zp - zones) != DB_Z_CACHE) /* cache never sets Z_FOUND */
+ syslog(LOG_NOTICE,
+ "Zone \"%s\" declared more than once",
+ zp->z_origin);
+ 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)
+ ns_refreshtime(zp, tt.tv_sec);
+ if (zp->z_time <= tt.tv_sec)
+ needmaint = 1;
+ dprintf(1, (ddt, " z_time %lu, z_refresh %lu\n",
+ (u_long)zp->z_time, (u_long)zp->z_refresh));
+ }
+ (void) my_fclose(fp);
+ lineno = slineno;
+}
+
+static void
+zoneinit(zp)
+ register struct zoneinfo *zp;
+{
+ struct stat sb;
+ int result;
+
+ /*
+ * 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;
+ result = stat(zp->z_source, &sb);
+#ifdef PURGE_ZONE
+ if (result != -1)
+ purge_zone(zp->z_origin, hashtab, zp->z_class);
+#endif
+ if (result == -1 || db_load(zp->z_source, zp->z_origin, zp, NULL)) {
+ /*
+ * Set zone to be refreshed immediately.
+ */
+ zp->z_refresh = INIT_REFRESH;
+ zp->z_retry = INIT_REFRESH;
+ if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))) {
+ 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++) {
+ if (zones[zoneNum].z_type == Z_NIL)
+ continue;
+ 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, 0)) {
+ if (strlen(buf) == 0)
+ break;
+ dprintf(1, (ddt," %s",buf));
+ if (!ftp) {
+ ftp = (struct fwdinfo *)malloc(sizeof(struct fwdinfo));
+ if (!ftp)
+ panic(errno, "malloc(fwdinfo)");
+ }
+ if (inet_aton(buf, &ftp->fwdaddr.sin_addr)) {
+ ftp->fwdaddr.sin_port = ns_port;
+ ftp->fwdaddr.sin_family = AF_INET;
+ } else {
+ syslog(LOG_NOTICE, "'%s' (ignored, NOT dotted quad)",
+ buf);
+ continue;
+ }
+#ifdef FWD_LOOP
+ if (aIsUs(ftp->fwdaddr.sin_addr)) {
+ syslog(LOG_NOTICE,
+ "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%lx [%s] next x%lx\n",
+ (u_long)ftp,
+ inet_ntoa(ftp->fwdaddr.sin_addr),
+ (u_long)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
+
+static void
+ns_limit(name, value)
+ const char *name;
+ int value;
+{
+ if (!strcasecmp(name, "transfers-in")) {
+ max_xfers_running = value;
+ } else if (!strcasecmp(name, "transfers-per-ns")) {
+ max_xfers_per_ns = value;
+ } else if (!strcasecmp(name, "datasize")) {
+ ns_rlimit("datasize", Datasize, value);
+ } else {
+ syslog(LOG_ERR,
+ "error: unrecognized limit in bootfile: \"%s\"",
+ name);
+ exit(1);
+ }
+}
+
+static void
+ns_rlimit(name, limit, value)
+ const char *name;
+ enum limit limit;
+ long value;
+{
+#ifndef HAVE_GETRUSAGE
+# ifdef LINT
+ name; limit; value;
+# endif
+ syslog(LOG_WARNING, "warning: unimplemented limit in bootfile: \"%s\"",
+ name);
+#else
+ struct rlimit limits;
+ int rlimit;
+
+ switch (limit) {
+ case Datasize:
+ rlimit = RLIMIT_DATA;
+ break;
+ default:
+ abort();
+ }
+ if (getrlimit(rlimit, &limits) < 0) {
+ syslog(LOG_WARNING, "getrlimit(%s): %m", name);
+ return;
+ }
+ limits.rlim_cur = value;
+ if (setrlimit(rlimit, &limits) < 0) {
+ syslog(LOG_WARNING, "setrlimit(%s, %ld): %m", name, value);
+ return;
+ }
+#endif
+}
+
+static void
+ns_option(name)
+ const char *name;
+{
+ if (!strcasecmp(name, "no-recursion")) {
+ NoRecurse = 1;
+ } else if (!strcasecmp(name, "no-fetch-glue")) {
+ NoFetchGlue = 1;
+#ifdef QRYLOG
+ } else if (!strcasecmp(name, "query-log")) {
+ qrylog = 1;
+#endif
+ } else if (!strcasecmp(name, "forward-only")) {
+ forward_only = 1;
+#ifndef INVQ
+ } else if (!strcasecmp(name, "fake-iquery")) {
+ fake_iquery = 1;
+#endif
+ } else {
+ syslog(LOG_ERR,
+ "error: unrecognized option in bootfile: \"%s\"",
+ name);
+ exit(1);
+ }
+}
diff --git a/usr.sbin/named/named/ns_main.c b/usr.sbin/named/named/ns_main.c
new file mode 100644
index 00000000000..bd5ef38daff
--- /dev/null
+++ b/usr.sbin/named/named/ns_main.c
@@ -0,0 +1,1674 @@
+/* $NetBSD: ns_main.c,v 1.1 1996/02/02 15:28:51 mrg Exp $ */
+
+#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 8.13 1996/01/09 20:23:55 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) 1995 Internet Software Consortium\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * Internet Name server (see RCF1035 & others).
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#if !defined(SYSV) && defined(XXX)
+#include <sys/wait.h>
+#endif /* !SYSV */
+#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>
+#if defined(__osf__)
+# include <sys/mbuf.h>
+# include <net/route.h>
+#endif
+#if defined(_AIX)
+# include <sys/time.h>
+# define TIME_H_INCLUDED
+#endif
+#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,
+ /* TCP send window size */
+ sbufsize = 16 * 1024;
+
+static struct sockaddr_in nsaddr;
+static u_int16_t local_ns_port, /* our service port */
+ nsid_state;
+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 = 0;
+ const int on = 1;
+ int rfd, size, len;
+ time_t lasttime, maxctime;
+ u_char buf[BUFSIZ];
+#ifdef POSIX_SIGNALS
+ struct sigaction sact;
+#else
+#ifndef SYSV
+ struct sigvec vec;
+#endif
+#endif
+#ifdef NeXT
+ int old_sigmask;
+#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);
+
+ /* BSD has a better random number generator but it's not clear
+ * that we need it here.
+ */
+ gettime(&tt);
+ srand(((unsigned)getpid()) + (unsigned)tt.tv_usec);
+
+ /*
+ ** 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, "%ld\n", (long)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;
+ nsid_init();
+
+ /*
+ ** 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_NOTICE, "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_NOTICE,
+ "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);
+ }
+ /* Retry opening the socket a few times */
+ my_close(vs);
+ sleep(3);
+ }
+ 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.
+ */
+ setsignal(SIGINT, -1, setdumpflg);
+ setsignal(SIGQUIT, -1, setchkptflg);
+ setsignal(SIGIOT, -1, setstatsflg);
+ setsignal(SIGUSR1, -1, setIncrDbgFlg);
+ setsignal(SIGUSR2, -1, setNoDbgFlg);
+
+#if defined(SIGWINCH) && defined(QRYLOG)
+ setsignal(SIGWINCH, -1, setQrylogFlg);
+#endif
+
+ /*
+ * Get list of local addresses and set up datagram sockets.
+ */
+ FD_ZERO(&mask);
+ FD_SET(vs, &mask);
+ 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;
+
+ setsignal(SIGALRM, SIGCHLD, maint_alarm);
+ setsignal(SIGCHLD, SIGALRM, reapchild);
+ setsignal(SIGPIPE, -1, (SIG_FN (*)())SIG_IGN);
+ setsignal(SIGHUP, -1, onhup);
+
+#if defined(SIGXFSZ)
+ /* Wierd DEC Hesiodism, harmless. */
+ setsignal(SIGXFSZ, -1, onhup);
+#endif
+
+#ifdef SIGSYS
+ setsignal(SIGSYS, -1, 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 */
+ setsignal(SIGTERM, -1, onintr);
+#endif
+
+#ifdef XSTATS
+ /* Catch SIGTERM so we can write stats before exiting. */
+ setsignal(SIGTERM, -1, 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);
+#if defined(SYSV) || defined(hpux)
+ 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, "%ld\n", (long)getpid());
+ (void) my_fclose(fp);
+ }
+#endif
+
+ syslog(LOG_NOTICE, "Ready to answer queries.\n");
+ prime_cache();
+ FD_ZERO(&mask);
+ FD_SET(vs, &mask);
+ if (vs >= nfds)
+ nfds = vs + 1;
+ for (dqp = datagramq; dqp != QDATAGRAM_NULL; dqp = dqp->dq_next) {
+ FD_SET(dqp->dq_dfd, &mask);
+ if (dqp->dq_dfd >= nfds)
+ nfds = dqp->dq_dfd + 1;
+ }
+#ifdef NeXT
+ old_sigmask = sigblock(sigmask(SIGCHLD));
+#endif
+ 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 */
+#ifdef XSTATS
+ if (needToExit) {
+ ns_logstats();
+ exit(0);
+ }
+#endif /* XSTATS */
+ if (needreload) {
+ needreload = 0;
+ db_reload();
+ }
+ if (needStatsDump) {
+ needStatsDump = 0;
+ ns_stats();
+ }
+ if (needendxfer) {
+ holdsigchld();
+ needendxfer = 0; /* should be safe even if not held */
+ endxfer(); /* releases SIGCHLD */
+ }
+ releasesigchld();
+ 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;
+#ifdef NeXT
+ sigsetmask(old_sigmask); /* Let queued signals run. */
+#endif
+ n = select(nfds, &tmpmask, (fd_set *)NULL, (fd_set *)NULL, tp);
+#ifdef NeXT
+ old_sigmask = sigblock(sigmask(SIGCHLD));
+#endif
+ if (n < 0 && errno != EINTR) {
+ syslog(LOG_ERR, "select(nfds = %d): %m", nfds);
+ 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 < 42; udpcnt++) { /*XXX*/
+ int from_len = sizeof(from_addr);
+
+ if ((n = recvfrom(dqp->dq_dfd, (char *)buf,
+ MIN(PACKETSZ, sizeof buf), 0,
+ (struct sockaddr *)&from_addr, &from_len)) < 0)
+ {
+#if defined(SPURIOUS_ECONNREFUSED)
+ if ((n < 0) && (errno == ECONNREFUSED))
+ break;
+#endif
+ if ((n < 0) && (errno == PORT_WOULDBLK))
+ break;
+ syslog(LOG_INFO, "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,
+ ctimel(tt.tv_sec)));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_nquery(buf, n, 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)) {
+ int 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_INFO, "accept: %m");
+ continue;
+ }
+ if ((n = fcntl(rfd, F_GETFL, 0)) < 0) {
+ syslog(LOG_INFO, "fcntl(rfd, F_GETFL): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ if (fcntl(rfd, F_SETFL, n|PORT_NONBLOCK) != 0) {
+ syslog(LOG_INFO, "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_INFO,
+ "getsockopt(rfd, IP_OPTIONS): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ if (len != 0) {
+ nameserIncr(from_addr.sin_addr, nssRcvdOpts);
+ if (!haveComplained((char*)(long)
+ from_addr.sin_addr.s_addr,
+ "rcvd ip options")) {
+ syslog(LOG_INFO,
+ "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_INFO,
+ "setsockopt(!IP_OPTIONS): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ }
+#endif
+ if (setsockopt(rfd, SOL_SOCKET, SO_SNDBUF,
+ (char*)&sbufsize, sizeof(sbufsize)) < 0){
+ syslog(LOG_INFO,
+ "setsockopt(rfd, SO_SNDBUF, %d): %m",
+ sbufsize);
+ (void) my_close(rfd);
+ continue;
+ }
+ if (setsockopt(rfd, SOL_SOCKET, SO_KEEPALIVE,
+ (char *)&on, sizeof(on)) < 0) {
+ syslog(LOG_INFO,
+ "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);
+ if (rfd >= nfds)
+ nfds = rfd + 1;
+ 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%lx\n",
+ (u_long)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%lx rfd %d size %d time %d next x%lx\n",
+ (u_long)sp, sp->s_rfd, sp->s_size,
+ sp->s_time, (u_long)sp->s_next));
+ dprintf(5, (ddt,
+ "\tbufsize %d buf x%lx bufp x%lx\n",
+ sp->s_bufsize,
+ (u_long)sp->s_buf, (u_long)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 = ntohs(sp->s_tempsize);
+ if (sp->s_bufsize == 0) {
+ if (!(sp->s_buf = (u_char *)
+ malloc(rbufsize))
+ ) {
+ 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 = (NoRecurse == 0);
+ 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[32768], *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) && !defined(M_UNIX)
+#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_NOTICE, "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));
+ if (!ntp)
+ panic(errno, "malloc(netinfo)");
+ }
+ ntp->my_addr = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr;
+#ifdef SIOCGIFNETMASK
+ if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
+ syslog(LOG_NOTICE, "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_NOTICE, "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_NOTICE, "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); /* With apologies to The Who. */
+
+ /*
+ * Create separate qdatagram structure for socket
+ * wildcard address.
+ */
+ if (first) {
+ if (!(dqp = (struct qdatagram *)calloc(1, sizeof(*dqp))))
+ panic(errno, "malloc(qdatagram)");
+ 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)
+ panic(errno, "malloc(netinfo)");
+ 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",
+ (u_long)ntp->addr, (u_long)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 m, n;
+ 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_NOTICE, "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, (char*)&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_NOTICE, "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_NOTICE, "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_NOTICE, "bind(dfd=%d, [%s].%d): %m",
+ dqp->dq_dfd, inet_ntoa(nsaddr.sin_addr),
+ ntohs(nsaddr.sin_port));
+#if !defined(sun)
+ syslog(LOG_ERR, "exiting");
+ exit(1);
+#endif
+ }
+ FD_SET(dqp->dq_dfd, &mask);
+}
+
+/*
+** 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;
+
+ resignal(SIGHUP, -1, onhup);
+ 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;
+
+ resignal(SIGALRM, SIGCHLD, maint_alarm);
+ 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()
+{
+ int save_errno = errno;
+
+ resignal(SIGTERM, -1, onintr);
+ needToExit = 1;
+ errno = save_errno;
+}
+#endif /* ALLOW_UPDATES */
+
+#ifdef XSTATS
+/*
+ * Signal handler to write log information
+ */
+static SIG_FN
+onintr()
+{
+ int save_errno = errno;
+
+ resignal(SIGTERM, -1, onintr);
+ needToExit = 1; /* XXX variable reuse */
+ errno = save_errno;
+}
+#endif /* XSTATS */
+
+/*
+ * 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;
+
+ resignal(SIGINT, -1, setdumpflg);
+ 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_NOTICE, "can't open debug file %s: %m",
+ debugfile);
+ debug = 0;
+ } else {
+#if defined(HAVE_SETVBUF)
+ setvbuf(ddt, NULL, _IOLBF, BUFSIZ);
+#else
+ setlinebuf(ddt);
+#endif
+ if ((n = fcntl(fileno(ddt), F_GETFL, 0)) < 0) {
+ syslog(LOG_INFO,
+ "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;
+
+ resignal(SIGUSR1, -1, setIncrDbgFlg);
+#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;
+
+ resignal(SIGUSR2, -1, setNoDbgFlg);
+ setdebug(0);
+ errno = save_errno;
+}
+
+#if defined(QRYLOG) && defined(SIGWINCH)
+/*
+** Set flag for query logging
+*/
+static SIG_FN
+setQrylogFlg()
+{
+ int save_errno = errno;
+
+ resignal(SIGWINCH, -1, setQrylogFlg);
+ 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;
+
+ resignal(SIGIOT, -1, setstatsflg);
+ needStatsDump = 1;
+ errno = save_errno;
+}
+
+static SIG_FN
+setchkptflg()
+{
+ int save_errno = errno;
+
+ resignal(SIGQUIT, -1, setchkptflg);
+ 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;
+
+ resignal(SIGSYS, -1, sigprof);
+ 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%lx)\n", (u_long)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(%#lx, %d) rfcnt=%d\n",
+ (u_long)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 from this generation (except 0.0.0.0)
+ * will be deleted, and syslog() will be called.
+ * known bugs:
+ * the above text is impenetrable.
+ * side effects:
+ * global list `datagramq' is modified.
+ */
+void
+dqflush(gen)
+ register time_t gen;
+{
+ register struct qdatagram *this, *prev, *next;
+
+ prev = NULL;
+ for (this = datagramq; this != NULL; this = next) {
+ next = this->dq_next;
+ if (gen != (time_t)0) {
+ if (this->dq_addr.s_addr == INADDR_ANY ||
+ this->dq_gen == gen) {
+ prev = this;
+ continue;
+ }
+ syslog(LOG_NOTICE, "interface [%s] missing; deleting",
+ inet_ntoa(this->dq_addr));
+ }
+ FD_CLR(this->dq_dfd, &mask);
+ my_close(this->dq_dfd);
+ free(this);
+ if (prev == NULL)
+ datagramq = next;
+ else
+ prev->dq_next = next;
+ }
+}
+
+/* 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));
+}
+
+/*
+ * These are here in case we ever want to get more clever, like perhaps
+ * using a bitmap to keep track of outstanding queries and a random
+ * allocation scheme to make it a little harder to predict them. Note
+ * that the resolver will need the same protection so the cleverness
+ * should be put there rather than here; this is just an interface layer.
+ */
+
+void
+nsid_init()
+{
+ nsid_state = res_randomid();
+}
+
+u_int16_t
+nsid_next()
+{
+ if (nsid_state == 65535)
+ nsid_state = 0;
+ else
+ nsid_state++;
+ return (nsid_state);
+}
+
+#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/named/ns_maint.c b/usr.sbin/named/named/ns_maint.c
new file mode 100644
index 00000000000..6c002826183
--- /dev/null
+++ b/usr.sbin/named/named/ns_maint.c
@@ -0,0 +1,1103 @@
+/* $NetBSD: ns_maint.c,v 1.1 1996/02/02 15:28:53 mrg Exp $ */
+
+#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 8.11 1995/12/22 10:20:30 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 *)),
+ tryxfer __P((void));
+
+#define qserial_qfull() (qserials_running == MAXQSERIAL)
+
+#ifdef CLEANCACHE
+static time_t cache_time;
+#endif
+#ifdef XSTATS
+static time_t stats_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", ctimel(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();
+ ns_refreshtime(zp, tt.tv_sec);
+ break;
+
+ case Z_SECONDARY:
+#ifdef STUBS
+ case Z_STUB:
+#endif
+ if (zp->z_serial != 0 &&
+ ((zp->z_lastupdate + zp->z_expire) <
+ tt.tv_sec)
+ ) {
+ zp->z_serial = 0;
+ }
+ if (zp->z_flags &
+ (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL)) {
+ ns_refreshtime(zp, tt.tv_sec);
+ break;
+ }
+ if (zp->z_flags & Z_XFER_RUNNING) {
+ abortxfer(zp);
+ 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);
+ ns_refreshtime(zp, tt.tv_sec);
+ }
+ break;
+#endif /* ALLOW_UPDATES */
+ }
+ gettime(&tt);
+ }
+ }
+#ifdef CLEANCACHE
+ if ((cache_time + cache_interval) <= tt.tv_sec) {
+ if (cache_time)
+ remove_zone(hashtab, 0, 0);
+ cache_time = tt.tv_sec;
+ }
+#endif
+#ifdef XSTATS
+ if (stats_time + stats_interval <= tt.tv_sec) {
+ if (stats_time)
+ ns_logstats();
+ stats_time = tt.tv_sec;
+ }
+#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 + cache_interval;
+#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 %lu sec\n",
+ (u_long)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;
+ ns_refreshtime(zp, tt.tv_sec);
+ /*
+ * 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? */
+}
+
+/*
+ * Query for the serial number of a zone, so that
+ * we can check to see if we need to transfer it.
+ */
+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, QUERY);
+ if (!qp) {
+ syslog(LOG_INFO, "qserial_query(%s): sysquery FAILED",
+ 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;
+ ns_refreshtime(zp, tt.tv_sec);
+ 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, (u_long)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);
+ }
+ if (was_qfull)
+ needmaint = 1;
+}
+
+/*
+ * Hold and release SIGCHLD
+ */
+#ifdef POSIX_SIGNALS
+static sigset_t sset;
+#else
+#ifndef SYSV
+static int omask;
+#endif
+#endif /* POSIX_SIGNALS */
+
+void holdsigchld()
+{
+#ifdef POSIX_SIGNALS
+ sigemptyset(&sset);
+ sigaddset(&sset,SIGCHLD);
+ sigprocmask(SIG_BLOCK,&sset,NULL);
+#else /* POSIX_SIGNALS */
+#ifndef SYSV
+ omask = sigblock(sigmask(SIGCHLD));
+#else /* SYSV */
+ /* XXX - out of luck? */
+#endif /* SYSV */
+#endif /* POSIX_SIGNALS */
+}
+
+void releasesigchld()
+{
+#ifdef POSIX_SIGNALS
+ sigprocmask(SIG_UNBLOCK,&sset,NULL);
+#else
+#ifndef SYSV
+ (void) sigsetmask(omask);
+#endif
+#endif /* POSIX_SIGNALS */
+}
+
+ /* State of all running zone transfers */
+static struct {
+ pid_t xfer_pid;
+ int xfer_state; /* see below */
+#ifdef sequent
+ union wait xfer_status;
+#else
+ int xfer_status;
+#endif
+} xferstatus[MAX_XFERS_RUNNING];
+#define XFER_IDLE 0
+#define XFER_RUNNING 1
+#define XFER_DONE 2
+
+/*
+ * 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, i;
+ 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++] = _PATH_XFER;
+ argv[argc++] = "-z";
+ argv[argc++] = zp->z_origin;
+ argv[argc++] = "-f";
+ argv[argc++] = zp->z_source;
+ argv[argc++] = "-s";
+ sprintf(serial_str, "%lu", (u_long)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_NOTICE,
+ "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) {
+ for (i = 0; i < argc; i++)
+ fprintf(ddt, "Arg %d=%s\n", i, argv[i]);
+ }
+#endif /* ECHOARGS */
+#endif /* DEBUG */
+
+ gettime(&tt);
+ holdsigchld();
+ for (i = 0; i < MAX_XFERS_RUNNING; i++) {
+ if (xferstatus[i].xfer_pid == 0) {
+ xferstatus[i].xfer_state = XFER_RUNNING;
+ break;
+ }
+ }
+ if ((pid = vfork()) == -1) {
+ syslog(LOG_ERR, "xfer vfork: %m");
+ releasesigchld();
+ 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. */
+ xferstatus[i].xfer_pid = pid; /* XXX - small race condition here if we
+ * can't hold signals */
+ 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;
+ releasesigchld();
+}
+
+const char *
+zoneTypeString(zp)
+ const struct zoneinfo *zp;
+{
+ static char ret[sizeof "(4294967296?)"]; /* 2^32 */
+
+ switch (zp->z_type) {
+ case Z_PRIMARY: return ("primary");
+ case Z_SECONDARY: return ("secondary");
+#ifdef STUBS
+ case Z_STUB: return ("stub");
+#endif
+ case Z_CACHE: return ("cache");
+ default:
+ sprintf(ret, "(%lu?)", (u_long)zp->z_type);
+ return (ret);
+ }
+}
+
+#ifdef DEBUG
+void
+printzoneinfo(zonenum)
+ int zonenum;
+{
+ struct timeval tt;
+ struct zoneinfo *zp = &zones[zonenum];
+
+ if (!debug)
+ return;
+
+ if (!zp->z_origin)
+ return;
+
+ fprintf(ddt, "printzoneinfo(%d):\n", zonenum);
+
+ gettime(&tt);
+ fprintf(ddt, "origin ='%s'", zp->z_origin[0] ? zp->z_origin : ".");
+#ifdef GEN_AXFR
+ fprintf(ddt, ", class = %d", zp->z_class);
+#endif
+ fprintf(ddt, ", type = %s", zoneTypeString(zp));
+ if (zp->z_source)
+ fprintf(ddt,", source = %s\n", zp->z_source);
+ fprintf(ddt, "z_refresh = %lu", (u_long)zp->z_refresh);
+ fprintf(ddt, ", retry = %lu", (u_long)zp->z_retry);
+ fprintf(ddt, ", expire = %lu", (u_long)zp->z_expire);
+ fprintf(ddt, ", minimum = %lu", (u_long)zp->z_minimum);
+ fprintf(ddt, ", serial = %lu\n", (u_long)zp->z_serial);
+ fprintf(ddt, "z_time = %lu", (u_long)zp->z_time);
+ if (zp->z_time) {
+ fprintf(ddt, ", now time : %lu sec", (u_long)tt.tv_sec);
+ fprintf(ddt, ", time left: %lu sec",
+ (long)(zp->z_time - tt.tv_sec));
+ }
+ fprintf(ddt, "; flags %lx\n", (u_long)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; NULL) {
+ if (dp->d_zone == zone
+#ifdef CLEANCACHE
+ && (all || stale(dp))
+#endif
+ ) {
+ dp = rm_datum(dp, np, pdp);
+ } else {
+ pdp = dp;
+ dp = dp->d_next;
+ }
+ } /*for(pdp)*/
+
+ if (np->n_hash) {
+ /* call recursively to remove subdomains. */
+ remove_zone(np->n_hash, zone
+#ifdef CLEANCACHE
+ , all
+#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;
+ }
+ } /*for(pnp)*/
+ } /*for(npp)*/
+}
+
+#ifdef PURGE_ZONE
+static void purge_z_2 __P((struct hashbuf *, int));
+static bottom_of_zone __P((struct databuf *, int));
+
+void
+purge_zone(dname, htp, class)
+ const char *dname;
+ register struct hashbuf *htp;
+ int class;
+{
+ const char *fname;
+ struct databuf *dp, *pdp;
+ struct namebuf *np;
+ struct hashbuf *phtp = htp;
+
+ dprintf(1, (ddt, "purge_zone(%s,%d)\n", dname, class));
+ if ((np = nlookup(dname, &phtp, &fname, 0)) && dname == fname &&
+ !WILDCARD_P(dname)) {
+ for (pdp = NULL, dp = np->n_data; dp != NULL; ) {
+ if (dp->d_class == class)
+ dp = rm_datum(dp, np, pdp);
+ else {
+ pdp = dp;
+ dp = dp->d_next;
+ }
+ }
+
+ if (np->n_hash) {
+ purge_z_2(np->n_hash, class);
+ if (np->n_hash->h_cnt == 0) {
+ free((char*)np->n_hash);
+ np->n_hash = NULL;
+ }
+ }
+
+ /* remove entry from cache, if required */
+ if ((np->n_hash == NULL) && (np->n_data == NULL)) {
+ struct namebuf **npp, **nppend;
+ struct namebuf *npn, *pnp, *nnp;
+
+ dprintf(3,(ddt, "purge_zone: cleaning cache\n"));
+
+ /* walk parent hashtable looking for ourself */
+ if (np->n_parent)
+ phtp = np->n_parent->n_hash;
+ else
+ phtp = htp; /* top / root zone */
+
+ if (phtp) {
+ nppend = phtp->h_tab + phtp->h_size;
+ for (npp = phtp->h_tab; npp < nppend; npp++) {
+ for (pnp = NULL, nnp = *npp;
+ nnp != NULL;
+ nnp = npn) {
+ if (nnp == np) {
+ dprintf(3, (ddt,
+ "purge_zone: found our selves\n"
+ ));
+ npn = rm_name(nnp,npp,pnp);
+ phtp->h_cnt--;
+ } else {
+ npn = nnp->n_next;
+ pnp = nnp;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void
+purge_z_2(htp, class)
+ register struct hashbuf *htp;
+ register int class;
+{
+ 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) {
+ if (!bottom_of_zone(np->n_data, class)) {
+ for (pdp = NULL, dp = np->n_data; dp != NULL; ) {
+ if (dp->d_class == class)
+ dp = rm_datum(dp, np, pdp);
+ else {
+ pdp = dp;
+ dp = dp->d_next;
+ }
+ }
+ if (np->n_hash) {
+ /* call recursively to rm subdomains */
+ purge_z_2(np->n_hash, class);
+
+ /* 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;
+ }
+ }
+ }
+}
+
+static int
+bottom_of_zone(dp, class)
+ struct databuf *dp;
+ int class;
+{
+ for ( ; dp ; dp = dp->d_next) {
+ if (dp->d_class != class)
+ continue;
+ if (dp->d_zone == 0)
+ continue;
+#ifdef NCACHE
+ if (dp->d_rcode) /* this should not occur */
+ continue;
+#endif
+ if (dp->d_type == T_SOA)
+ return (1);
+ }
+ dprintf(3, (ddt, "bottom_of_zone() == 0\n"));
+ return (0);
+}
+#endif
+
+/*
+ * 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;
+{
+ if (zp->z_flags & (Z_XFER_GONE|Z_XFER_ABORTED)) {
+ int i;
+
+ for (i = 0; i < MAX_XFERS_RUNNING; i++) {
+ if (xferstatus[i].xfer_pid == zp->z_xferpid) {
+ xferstatus[i].xfer_pid = 0;
+ xferstatus[i].xfer_state = XFER_IDLE;
+ break;
+ }
+ }
+
+ if (zp->z_flags & Z_XFER_GONE)
+ syslog(LOG_WARNING,
+ "zone transfer timeout for \"%s\"; pid %lu missing",
+ zp->z_origin, (u_long)zp->z_xferpid);
+ else if (kill(zp->z_xferpid, SIGKILL) == -1)
+ syslog(LOG_WARNING,
+ "zone transfer timeout for \"%s\"; kill pid %lu: %m",
+ zp->z_origin, (u_long)zp->z_xferpid);
+ else
+ syslog(LOG_WARNING,
+"zone transfer timeout for \"%s\"; second kill\
+pid %lu - forgetting, processes may accumulate",
+ zp->z_origin, (u_long)zp->z_xferpid);
+
+ zp->z_xferpid = 0;
+ xfers_running--;
+ (void)nxfers(zp, -1);
+ zp->z_flags &= ~(Z_XFER_RUNNING|Z_XFER_ABORTED|Z_XFER_GONE);
+ } else if (kill(zp->z_xferpid, SIGKILL) == -1) {
+ if (errno == ESRCH)
+ /* No warning on first time, it may have just exited */
+ zp->z_flags |= Z_XFER_GONE;
+ else {
+ syslog(LOG_WARNING,
+ "zone transfer timeout for \"%s\"; pid %lu kill failed %m",
+ zp->z_origin, (u_long)zp->z_xferpid);
+ zp->z_flags |= Z_XFER_ABORTED;
+ }
+ } else {
+ syslog(LOG_NOTICE,
+ "zone transfer timeout for \"%s\"; pid %lu killed",
+ zp->z_origin, (u_long)zp->z_xferpid);
+ zp->z_flags |= Z_XFER_ABORTED;
+ }
+}
+
+/*
+ * SIGCHLD signal handler: process exit of xfer's.
+ * (Note: also called when outgoing transfer completes.)
+ */
+SIG_FN
+reapchild()
+{
+ int pid, i, save_errno;
+#if defined(sequent)
+ union wait status;
+#else
+ int status;
+#endif /* sequent */
+
+#if defined(MUST_REARM_SIGS)
+ (void)signal(SIGCLD, (SIG_FN (*)()) reapchild);
+#endif
+ save_errno = errno;
+ gettime(&tt);
+#if defined(USE_WAITPID)
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+#else /* USE_WAITPID */
+ {
+ pid = wait(&status);
+#endif /* USE_WAITPID */
+ for (i = 0; i < MAX_XFERS_RUNNING; i++) {
+ if (xferstatus[i].xfer_pid == pid) {
+ xferstatus[i].xfer_status = status;
+ xferstatus[i].xfer_state = XFER_DONE;
+ needendxfer++;
+ break;
+ }
+ }
+ }
+ errno = save_errno;
+}
+
+/*
+ * Finish processing of of finished xfers
+ */
+void
+endxfer()
+{
+ register struct zoneinfo *zp;
+ int exitstatus, pid, i;
+#if defined(sequent)
+ union wait status;
+#else
+ int status;
+#endif /* sequent */
+
+ gettime(&tt);
+
+ for (i = 0; i < MAX_XFERS_RUNNING; i++) {
+ if (xferstatus[i].xfer_state != XFER_DONE)
+ continue;
+ pid = xferstatus[i].xfer_pid;
+ status = xferstatus[i].xfer_status;
+ exitstatus = WIFEXITED(status) ?WEXITSTATUS(status) :0;
+
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ if (zp->z_xferpid != pid)
+ continue;
+ xfers_running--;
+ (void) nxfers(zp, -1);
+ zp->z_xferpid = 0;
+ zp->z_flags &=
+ ~(Z_XFER_RUNNING|Z_XFER_ABORTED|Z_XFER_GONE);
+ 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));
+ }
+ ns_retrytime(zp, tt.tv_sec);
+ } else {
+ switch (exitstatus) {
+ case XFER_UPTODATE:
+ markUpToDate(zp);
+ break;
+
+ case XFER_SUCCESS:
+ /* XXX should incorporate loadxfer() */
+ zp->z_flags |= Z_NEED_RELOAD;
+ zp->z_flags &= ~Z_SYSLOGGED;
+ needzoneload++;
+ break;
+
+ case XFER_TIMEOUT:
+ if (!(zp->z_flags & Z_SYSLOGGED)) {
+ zp->z_flags |= Z_SYSLOGGED;
+ syslog(LOG_NOTICE,
+ "zoneref: Masters for secondary zone \"%s\" unreachable",
+ zp->z_origin);
+ }
+ ns_retrytime(zp, tt.tv_sec);
+ 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;
+ ns_retrytime(zp, tt.tv_sec);
+ break;
+ }
+ break;
+ }
+ }
+ xferstatus[i].xfer_state = XFER_IDLE;
+ xferstatus[i].xfer_pid = 0;
+ }
+ releasesigchld();
+ tryxfer();
+}
+
+/*
+ * Try to start some xfers - new "fair scheduler" by Bob Heiney @DEC (1995)
+ */
+static void
+tryxfer() {
+ static struct zoneinfo *zp = NULL;
+ static struct zoneinfo *lastzones = NULL;
+ static int lastnzones = 0;
+ struct zoneinfo *startzp, *stopzp;
+
+ /* initialize, and watch out for changes in zones! */
+ if (lastzones != zones) {
+ if (lastzones != NULL)
+ syslog(LOG_INFO, "zones changed: %p != %p",
+ lastzones, zones);
+ lastzones = zones;
+ zp = zones;
+ }
+
+ /* did zones shrink? */
+ if (lastnzones > nzones) {
+ syslog(LOG_INFO, "zones shrunk");
+ zp = zones;
+ }
+ lastnzones = nzones;
+
+ if (zp == zones)
+ stopzp = &zones[nzones-1];
+ else
+ stopzp = zp - 1;
+
+ dprintf(3, (ddt, "tryxfer start zp=%p stopzp=%p def=%d running=%d\n",
+ zp, stopzp, xfers_deferred, xfers_running));
+
+ startzp = zp;
+ for (;;) {
+ int xfers;
+
+ if (!xfers_deferred || xfers_running >= max_xfers_running)
+ break;
+
+ if ((xfers = nxfers(zp, 0)) != -1 &&
+ xfers < max_xfers_per_ns &&
+ (zp->z_flags & Z_NEED_XFER)) {
+ nxfers(zp, 1);
+ xfers_deferred--;
+ startxfer(zp);
+ }
+
+ if (zp == stopzp) {
+ dprintf(3, (ddt, "tryxfer stop mark\n"));
+ zp = startzp;
+ break;
+ }
+
+ zp++;
+ /* wrap around? */
+ if (zp == &zones[nzones])
+ zp = zones;
+ }
+ dprintf(3, (ddt, "tryxfer stop zp=%p\n", 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);
+ remove_zone(hashtab, zp - zones
+#ifdef CLEANCACHE
+ , 1
+#endif
+ );
+#ifdef PURGE_ZONE
+ purge_zone(zp->z_origin, hashtab, zp->z_class);
+#endif
+ if (!db_load(zp->z_source, zp->z_origin, zp, NULL))
+ zp->z_flags |= Z_AUTH;
+ if (zp->z_flags & Z_TMP_FILE)
+ (void) unlink(zp->z_source);
+ }
+ }
+ 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/named/ns_ncache.c b/usr.sbin/named/named/ns_ncache.c
new file mode 100644
index 00000000000..de084c48702
--- /dev/null
+++ b/usr.sbin/named/named/ns_ncache.c
@@ -0,0 +1,155 @@
+/* $NetBSD: ns_ncache.c,v 1.1 1996/02/02 15:28:55 mrg Exp $ */
+
+/**************************************************************************
+ * 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, 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: [%s %s %s] rcode:%d ttl:%l\n",
+ dname, p_type(type), p_class(class),
+ dp->d_rcode, (long)(dp->d_ttl-tt.tv_sec)));
+ return;
+}
+
+#endif /*NCACHE*/
diff --git a/usr.sbin/named/named/ns_req.c b/usr.sbin/named/named/ns_req.c
new file mode 100644
index 00000000000..9a1ecc230f6
--- /dev/null
+++ b/usr.sbin/named/named/ns_req.c
@@ -0,0 +1,2153 @@
+/* $NetBSD: ns_req.c,v 1.1 1996/02/02 15:28:57 mrg Exp $ */
+
+#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 8.15 1995/12/29 07:16:18 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 */
+ char *a_rname; /* referred by */
+ u_int16_t a_rtype; /* referred by */
+ u_int16_t 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));
+
+static enum req_action req_iquery __P((HEADER *hp, u_char **cpp, u_char *eom,
+ int *buflenp, u_char *msg,
+ struct sockaddr_in *from));
+
+#ifdef BIND_NOTIFY
+static enum req_action req_notify __P((HEADER *hp, u_char **cpp, u_char *eom,
+ u_char *msg,struct sockaddr_in *from));
+#endif
+
+static void fwritemsg __P((FILE *, u_char *, int)),
+#ifdef DEBUG
+ printSOAdata __P((struct databuf)),
+#endif
+ doaxfr __P((struct namebuf *, FILE *,
+ struct namebuf *, int)),
+ startxfr __P((struct qstream *, struct namebuf *,
+ u_char *, int, int, const char *));
+
+#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((const char *, const char *,
+ u_int16_t, 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;
+#ifdef DEBUG
+ const char *sortmsgtxt;
+#endif
+ enum req_action action;
+ int n;
+
+#ifdef DEBUG
+ if (debug > 3) {
+ fprintf(ddt, "ns_req(from=%s)\n", sin_ntoa(from));
+ fp_nquery(msg, msglen, 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;
+ }
+
+ /* it's not a response so 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;
+ buflen -= HFIXEDSZ;
+
+ 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;
+
+ case IQUERY:
+ action = req_iquery(hp, &cp, eom, &buflen, msg, from);
+ break;
+
+#ifdef BIND_NOTIFY
+ case NS_NOTIFY_OP:
+ action = req_notify(hp, &cp, eom, 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;
+ }
+
+ case ZONEREF:
+ dprintf(1, (ddt, "Refresh Zone\n"));
+ /*FALLTHROUGH*/
+#endif /* ALLOW_UPDATES */
+
+ default:
+ dprintf(1, (ddt, "ns_req: Opcode %d not implemented\n",
+ hp->opcode));
+ /* XXX - should syslog, limited by haveComplained */
+ hp->qdcount = htons(0);
+ hp->ancount = htons(0);
+ hp->nscount = htons(0);
+ hp->arcount = htons(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:
+ panic(-1, "ns_req: bad action variable");
+ /*NOTREACHED*/
+ }
+
+ /*
+ * apply final polish
+ */
+ hp->qr = 1; /* set Response flag */
+ hp->ra = (NoRecurse == 0);
+
+ n = doaddinfo(hp, cp, buflen);
+ cp += n;
+ buflen -= n;
+
+#ifdef DEBUG
+#ifdef SORT_RESPONSE
+ sortmsgtxt = local(from) == NULL ? "Remote" : "Local";
+#else /*SORT*/
+ sortmsgtxt = "(not sorting)";
+#endif /*SORT*/
+ dprintf(1, (ddt, "ns_req: answer -> %s fd=%d id=%d size=%d %s\n",
+ sin_ntoa(from), (qsp == QSTREAM_NULL) ? dfd : qsp->s_rfd,
+ ntohs(hp->id), cp - msg, sortmsgtxt));
+ if (debug >= 10)
+ fp_nquery(msg, cp - msg, ddt);
+#endif /*DEBUG*/
+ if (qsp == QSTREAM_NULL) {
+ if (sendto(dfd, (char*)msg, cp - msg, 0,
+ (struct sockaddr *)from,
+ sizeof(*from)) < 0) {
+ if (!haveComplained((char*)(long)from->sin_addr.s_addr,
+ sendtoStr))
+ syslog(LOG_INFO,
+ "ns_req: sendto(%s): %m",
+ sin_ntoa(from));
+ nameserIncr(from->sin_addr, nssSendtoErr);
+ }
+ nameserIncr(from->sin_addr, nssSentAns);
+#ifdef XSTATS
+ if (hp->rcode == NXDOMAIN)
+ nameserIncr(from->sin_addr, nssSentNXD);
+ if (!hp->aa)
+ nameserIncr(from->sin_addr, nssSentNaAns);
+#endif
+ } else {
+ (void) writemsg(qsp->s_rfd, msg, cp - msg);
+ sq_done(qsp);
+ }
+
+ if (needs_prime_cache) {
+ prime_cache(); /* Now is a safe time */
+ }
+}
+
+#ifdef BIND_NOTIFY
+int
+findZonePri(zp, from)
+ register const struct zoneinfo *zp;
+ const struct sockaddr_in *from;
+{
+ register u_int32_t from_addr = from->sin_addr.s_addr;
+ register int i;
+
+ for (i = 0; (u_int)i < zp->z_addrcnt; i++)
+ if (zp->z_addr[i].s_addr == from_addr)
+ return (i);
+ return (-1);
+}
+
+static enum req_action
+req_notify(hp, cpp, eom, msg, from)
+ HEADER *hp;
+ u_char **cpp, *eom, *msg;
+ struct sockaddr_in *from;
+{
+ int n, type, class, zn;
+ char dnbuf[MAXDNAME];
+ struct namebuf *np;
+ const char *fname;
+ struct hashbuf *htp = hashtab; /* lookup relative to root */
+
+ /* valid notify's have one question and zero answers */
+ if ((ntohs(hp->qdcount) != 1)
+ || ntohs(hp->ancount) != 0
+ || ntohs(hp->nscount) != 0
+ || ntohs(hp->arcount) != 0) {
+ dprintf(1, (ddt, "FORMERR Notify header counts wrong\n"));
+ hp->qdcount = htons(0);
+ hp->ancount = htons(0);
+ hp->nscount = htons(0);
+ hp->arcount = htons(0);
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+
+ 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);
+ syslog(LOG_INFO, "rcvd NOTIFY(%s %s %s)",
+ dnbuf, p_class(class), p_type(type));
+ /* XXX - when answers are allowed, we'll need to do compression
+ * correctly here, and we will need to check for packet underflow.
+ */
+ np = nlookup(dnbuf, &htp, &fname, 0);
+ if (!np) {
+ syslog(LOG_INFO, "rcvd NOTIFY for \"%s\", name not in cache",
+ dnbuf);
+ hp->rcode = SERVFAIL;
+ return (Finish);
+ }
+ zn = findMyZone(np, class);
+ if (zn == DB_Z_CACHE || zones[zn].z_type != Z_SECONDARY) {
+ /* this can come if a user did an AXFR of some zone somewhere
+ * and that zone's server now wants to tell us that the SOA
+ * has changed. AXFR's always come from nonpriv ports so it
+ * isn't possible to know whether it was the server or just
+ * "dig". this condition can be avoided by using secure zones
+ * since that way only real secondaries can AXFR from you.
+ */
+ syslog(LOG_INFO,
+ "NOTIFY for non-secondary name (%s), from %s",
+ dnbuf, sin_ntoa(from));
+ goto refuse;
+ }
+ if (findZonePri(&zones[zn], from) == -1) {
+ syslog(LOG_INFO,
+ "NOTIFY from non-master server (zone %s), from %s",
+ zones[zn].z_origin, sin_ntoa(from));
+ goto refuse;
+ }
+ switch (type) {
+ case T_SOA:
+ if (strcasecmp(dnbuf, zones[zn].z_origin) != 0) {
+ syslog(LOG_INFO,
+ "NOTIFY(SOA) for non-origin (%s), from %s",
+ dnbuf, sin_ntoa(from));
+ goto refuse;
+ }
+ if (zones[zn].z_flags &
+ (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL|Z_XFER_RUNNING)) {
+ syslog(LOG_INFO,
+ "NOTIFY(SOA) for zone already xferring (%s)",
+ dnbuf);
+ goto noerror;
+ }
+ zones[zn].z_time = tt.tv_sec;
+ qserial_query(&zones[zn]);
+ /* XXX: qserial_query() can fail due to queue full condition;
+ * we should detect that case here and do something.
+ */
+ break;
+ default:
+ /* unimplemented, but it's not a protocol error, just
+ * something to be ignored.
+ */
+ break;
+ }
+ noerror:
+ hp->rcode = NOERROR;
+ return (Finish);
+ refuse:
+ hp->rcode = REFUSED;
+ return (Finish);
+}
+#endif /*BIND_NOTIFY*/
+
+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;
+ const char *fname;
+ struct hashbuf *htp;
+ struct databuf *nsp[NSMAX];
+ struct namebuf *np, *anp;
+ struct qinfo *qp;
+ struct netinfo *lp;
+#ifdef SECURE_ZONES
+ struct zoneinfo *zp;
+#endif
+ struct databuf *dp;
+
+ nameserIncr(from->sin_addr, nssRcvdQ);
+
+#ifdef XSTATS
+ /* Statistics for queries coming from port <> 53, suspect some kind of forwarder */
+ if (from->sin_port != ns_port)
+ nameserIncr(from->sin_addr, nssNotNsQ);
+#endif
+
+#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)
+ || ntohs(hp->ancount) != 0
+ || ntohs(hp->nscount) != 0
+ || ntohs(hp->arcount) != 0) {
+ dprintf(1, (ddt, "FORMERR Query header counts wrong\n"));
+ hp->qdcount = htons(0);
+ hp->ancount = htons(0);
+ hp->nscount = htons(0);
+ hp->arcount = htons(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 for \"%s\"",
+ sin_ntoa(from), *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 for %s",
+ sin_ntoa(from), *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 for \"%s\"",
+ sin_ntoa(from), *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 class=%d\n",
+ dname, ntohs(hp->id), type, class));
+ htp = hashtab; /* lookup relative to root */
+ if ((anp = 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
+ /* (gdmr) Make sure the class is correct. If we have the same name
+ * with more than one class then we can't refuse a request for one
+ * class just because another class is blocked. We *really* ought
+ * to look for the correct type too, but since everything in a
+ * particular class of zone has the same secure_zone attribute it
+ * doesn't really matter which type we use! Alternatively, this lot
+ * could all be moved to after the finddata(), by which time only
+ * the correct class/type combinations will be left.
+ */
+ dp = np->n_data;
+ while (dp && (dp->d_class != class))
+ dp = dp->d_next;
+ if (dp) {
+ zp = &zones[dp->d_zone];
+ if (zp->secure_nets
+ && !addr_on_netlist(from->sin_addr, zp->secure_nets)) {
+ syslog(LOG_NOTICE, "Unauthorized request %s from %s",
+ dname, sin_ntoa(from));
+ dprintf(1, (ddt, "req: refuse %s from %s class %d (%d)\n",
+ dname, sin_ntoa(from), class, zp->z_class));
+ return (Refuse);
+ }
+ }
+#endif
+ foundname++;
+ answers = *cpp;
+ count = *cpp - msg;
+
+#ifdef NCACHE
+ /* Look for NXDOMAIN record with appropriate class
+ * if found return immediately
+ */
+ for (dp = np->n_data; dp ; dp = dp->d_next) {
+ if (!stale(dp) && (dp->d_rcode == NXDOMAIN) &&
+ (dp->d_class == class)) {
+#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->nscount = htons((u_int16_t)count);
+ }
+#endif
+ hp->rcode = NXDOMAIN;
+ hp->aa = 1;
+ return (Finish);
+ }
+ }
+
+ /* 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 = htons(ntohs(hp->ancount) + (u_int16_t)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));
+
+#ifdef SORT_RESPONSE
+ if ((lp = local(from)) != NULL)
+ sort_response(answers, count, lp, *cpp);
+#endif
+#ifdef BIND_NOTIFY
+ if (type == T_SOA &&
+ from->sin_port == ns_port &&
+ np->n_data) {
+ int zn = np->n_data->d_zone;
+
+ if (zn != DB_Z_CACHE) {
+ struct notify *ap;
+
+ /* Old? */
+ ap = findNotifyPeer(&zones[zn], from->sin_addr);
+ /* New? */
+ if (!ap && (ap = (struct notify *)malloc(sizeof *ap))) {
+ ap->addr = from->sin_addr;
+ ap->next = zones[zn].z_notifylist;
+ zones[zn].z_notifylist = ap;
+ }
+ /* Old or New? */
+ if (ap)
+ ap->last = tt.tv_sec;
+ }
+ }
+#endif /*BIND_NOTIFY*/
+ if (type == T_AXFR) {
+ 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:
+ /*
+ * If we're already out of room in the response, we're done.
+ */
+ if (hp->tc)
+ return (Finish);
+
+ /*
+ * 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:
+ /* We are authoritative for this np. */
+ 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 (ntohs(hp->ancount) != 0) {
+ /* don't add NS records for NOERROR NODATA
+ as some servers can get confused */
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ switch (findns(&np, class, nsp, &count, 1)) {
+ case NXDOMAIN:
+ case SERVFAIL:
+ break;
+ default:
+ if (np &&
+ (type != T_NS || np != anp)
+ ) {
+ n = add_data(np, nsp, *cpp,
+ *buflenp, &count);
+ 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:
+ /* We're authoritative but the zone isn't loaded. */
+ 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) {
+ /*
+ * If the qtype was NS, and the np of the authority is
+ * the same as the np of the data, we don't need to add
+ * another copy of the answer here in the authority
+ * section.
+ */
+ if (!founddata || type != T_NS || anp != np) {
+ n = add_data(np, nsp, *cpp, *buflenp, &count);
+ 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
+ /* Our caller will handle the Additional section. */
+ 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) {
+ syslog(LOG_INFO, "ns_req: Out Of Memory");
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+ }
+ id = hp->id;
+ omsglen = *msglenp;
+ bcopy(msg, omsg, omsglen);
+ n = res_mkquery(QUERY, dname, class, type,
+ NULL, 0, NULL, msg,
+ *msglenp + *buflenp);
+ if (n < 0) {
+ syslog(LOG_INFO, "res_mkquery(%s) failed", dname);
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+ }
+ *msglenp = n;
+ }
+ 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') {
+ syslog(LOG_NOTICE,
+ "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
+ for (dp = np->n_data; dp ; dp = dp->d_next)
+ if (dp->d_zone && match(dp, class, T_NS))
+ break;
+ if (dp) {
+ /*
+ * we know the child zone exists but are
+ * missing glue.
+ *
+ * nslookup has called sysquery() to get the
+ * missing glue.
+ *
+ * for UDP, drop the response and let the
+ * client retry. for TCP, we should probably
+ * (XXX) hold open the TCP connection for a
+ * while in case the sysquery() comes back
+ * soon. meanwhile we SERVFAIL.
+ */
+ if (qsp)
+ goto do_servfail;
+ break;
+ }
+ np = np->n_parent;
+ }
+ goto fetchns; /* Try again. */
+ case FW_SERVFAIL:
+ do_servfail:
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+ }
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Return);
+}
+
+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;
+{
+ int dlen, alen, n, type, class, count;
+ char dnbuf[MAXDNAME], anbuf[PACKETSZ], *data, *fname;
+
+ nameserIncr(from->sin_addr, nssRcvdIQ);
+
+ if (ntohs(hp->ancount) != 1
+ || ntohs(hp->qdcount) != 0
+ || ntohs(hp->nscount) != 0
+ || ntohs(hp->arcount) != 0) {
+ dprintf(1, (ddt, "FORMERR IQuery header counts wrong\n"));
+ hp->qdcount = htons(0);
+ hp->ancount = htons(0);
+ hp->nscount = htons(0);
+ hp->arcount = htons(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:
+#ifndef INVQ
+ if (!fake_iquery)
+ return (Refuse);
+#endif
+#ifdef INVQ
+ case T_UID:
+ case T_GID:
+#endif
+ 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;
+
+#ifdef QRYLOG
+ if (qrylog) {
+ syslog(LOG_INFO, "XX /%s/%s/-%s",
+ inet_ntoa(from->sin_addr),
+ inet_ntoa(data_inaddr((u_char *)data)),
+ p_type(type));
+ }
+#endif /*QRYLOG*/
+
+#ifdef INVQ
+ {
+ register struct invbuf *ip;
+
+ for (ip = invtab[dhash((u_char *)data, dlen)];
+ ip != NULL;
+ ip = ip->i_next) {
+ int i;
+
+ for (i = 0; i < INVBLKSZ; i++) {
+ struct namebuf *np;
+ struct databuf *dp;
+
+ 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++;
+ }
+ }
+ }
+ }
+#else /*INVQ*/
+ /*
+ * We can only get here if we are compiled without INVQ (the default)
+ * and the type is T_A and the option "fake-iquery" is on in the boot
+ * file.
+ *
+ * What we do here is send back a bogus response of "[dottedquad]".
+ * A better strategy would be to turn this into a PTR query, but that
+ * would legitimize inverse queries in a way they do not deserve.
+ */
+ sprintf(dnbuf, "[%s]", inet_ntoa(data_inaddr((u_char *)data)));
+ *buflenp -= QFIXEDSZ;
+ n = dn_comp(dnbuf, *cpp, *buflenp, NULL, NULL);
+ if (n < 0) {
+ hp->tc = 1;
+ return (Finish);
+ }
+ *cpp += n;
+ PUTSHORT((u_int16_t)type, *cpp);
+ PUTSHORT((u_int16_t)class, *cpp);
+ *buflenp -= n;
+ count++;
+#endif /*INVQ*/
+ 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);
+}
+
+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) {
+ syslog(LOG_ERR, "fwritemsg: %m");
+ _exit(1);
+ }
+}
+
+/*
+ * 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);
+
+#ifdef STUBS
+ case Z_STUB:
+ /* root stub zones have DB_F_HINT set */
+ if (dp->d_flags & DB_F_HINT)
+ return (0);
+ /* FALLTROUGH */
+#endif
+ case Z_SECONDARY:
+ /*
+ * 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_NOTICE,
+ "secondary zone \"%s\" expired",
+ zp->z_origin);
+ }
+ zp->z_flags &= ~Z_AUTH;
+ return (1);
+ }
+ if (zp->z_lastupdate > tt.tv_sec) {
+ if (!haveComplained(zp->z_origin, (char*)stale)) {
+ syslog(LOG_NOTICE,
+ "secondary zone \"%s\" time warp",
+ 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 %ld (x%lx)\n",
+ dp->d_ttl, (long)(dp->d_ttl - tt.tv_sec),
+ (u_long)dp->d_flags));
+ return (1);
+
+ default:
+ /* FALLTHROUGH */ ;
+
+ }
+ panic(-1, "stale: impossible condition");
+ /* 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)
+ const 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 u_int32_t ttl;
+ u_char **edp = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+
+ dprintf(5, (ddt, "make_rr(%s, %lx, %lx, %d, %d) %d zone %d ttl %lu\n",
+ name, (u_long)dp, (u_long)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
+ ) {
+ panic(-1, "make_rr: impossible d_rcode value");
+ }
+#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, %#lx\n",
+ ttl, (u_long)dp->d_flags));
+ ttl = 0;
+ }
+ } else {
+ if (dp->d_ttl != USE_MINIMUM)
+ 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, name,
+ dp->d_type, 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;
+
+ if ((buflen -= INT16SZ) < 0)
+ return (-1);
+
+ /* copy preference */
+ bcopy(cp1, cp, INT16SZ);
+ cp += INT16SZ;
+ cp1 += 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, name, dp->d_type, dp->d_class);
+ break;
+
+ case T_PX:
+ cp1 = dp->d_data;
+
+ if ((buflen -= INT16SZ) < 0)
+ return (-1);
+
+ /* copy preference */
+ bcopy(cp1, cp, INT16SZ);
+ cp += INT16SZ;
+ cp1 += INT16SZ;
+
+ n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ buflen -= n;
+ cp1 += strlen((char *)cp1) + 1;
+ 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);
+ 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 const char *dname,
+ register const char *rname,
+ u_int16_t rtype,
+ u_int16_t class)
+#else
+static void
+addname(dname, rname, rtype, class)
+ register const char *dname;
+ register const char *rname;
+ u_int16_t rtype;
+ 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, dname) == 0)
+ return;
+
+ /* add domain name to additional section */
+ if (addcount < NADDRECS) {
+ addcount++;
+ ap->a_dname = savestr(dname);
+ ap->a_rname = savestr(rname);
+ ap->a_rtype = rtype;
+ 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;
+ const char *fname;
+ int n, count;
+
+ if (!addcount)
+ return (0);
+
+ 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,
+ foundcname = 0,
+ save_count = count,
+ save_msglen = msglen;
+ u_char *save_cp = cp;
+
+ dprintf(3, (ddt, "do additional \"%s\" (from \"%s\")\n",
+ ap->a_dname, ap->a_rname));
+ 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) {
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ if (match(dp, (int)ap->a_class, T_CNAME) ||
+ match(dp, C_IN, T_CNAME)) {
+ foundcname++;
+ break;
+ }
+ 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;
+ }
+ /*
+ * 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
+ */
+ dprintf(5, (ddt,
+ "addinfo: not enough room, remaining msglen = %d\n",
+ save_msglen));
+ 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 (!NoFetchGlue && !foundcname && (foundstale || !foundany)) {
+ /* ask a real server for this info */
+ (void) sysquery(ap->a_dname, (int)ap->a_class, T_A,
+ NULL, 0, QUERY);
+ }
+ if (foundcname) {
+ if (!haveComplained((char*)(long)nhash(ap->a_dname),
+ (char*)(long)nhash(ap->a_rname))) {
+ syslog(LOG_INFO,
+ "\"%s %s %s\" points to a CNAME (%s)",
+ ap->a_rname, p_class(ap->a_class),
+ p_type(ap->a_rtype), ap->a_dname);
+ }
+ }
+ free(ap->a_dname);
+ free(ap->a_rname);
+ }
+ 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(ntohs(hp->nscount) + 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;
+ const char *fname;
+ char dname[MAXDNAME];
+ HEADER *hp;
+ int fndns;
+
+ if (np == top)
+ dprintf(1, (ddt, "doaxfr()\n"));
+ fndns = 0;
+ bzero((char*)msg, sizeof msg);
+ hp = (HEADER *) msg;
+ hp->opcode = QUERY;
+ hp->qr = 1;
+ hp->rcode = NOERROR;
+ hp->ancount = htons(1);
+ cp = 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 != NULL && 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) ||
+ ((tnp == NULL) && (top->n_dname[0] == '\0')))
+ 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)) {
+ 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) {
+ syslog(LOG_NOTICE,
+ "InitDynUpdate: Couldn't find SOA RR 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(%#lx): origin(%#lx)='%s'\n",
+ (u_long)dp, (u_long)cp, cp);
+ cp += strlen(cp) + 1; /* skip origin string */
+ fprintf(ddt, "printSOAdata: in-charge(%#lx)='%s'\n",
+ (u_long)cp, cp);
+ cp += strlen(cp) + 1; /* skip in-charge string */
+ fprintf(ddt, "printSOAdata: serial(%lx)=%d\n",
+ cp, (u_long)_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;
+#ifdef HAVE_SETVBUF
+ char *buf;
+#endif
+#ifdef SO_SNDBUF
+ static const int sndbuf = XFER_BUFSIZE * 2;
+#endif
+#ifdef SO_LINGER
+ static const struct linger ll = { 1, 120 };
+#endif
+
+ dprintf(5, (ddt, "startxfr()\n"));
+
+ /*
+ * child does the work while
+ * the parent continues
+ */
+ switch (pid = fork()) {
+ case -1:
+ syslog(LOG_NOTICE, "startxfr(%s -> %s) failing; fork: %m",
+ dname, sin_ntoa(&qsp->s_from));
+ return;
+ case 0:
+ /* child */
+ break;
+ default:
+ /* parent */
+ syslog(LOG_DEBUG, "zone transfer of \"%s\" to %s (pid %lu)",
+ dname, sin_ntoa(&qsp->s_from), 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);
+#ifdef HAVE_SETVBUF
+ /* some systems (DEC OSF/1, SunOS) don't initialize the stdio buffer
+ * if all you do between fdopen() and fclose() are fwrite()'s. even
+ * on systems where the buffer is correctly set, it is too small.
+ */
+ if ((buf = malloc(XFER_BUFSIZE)) != NULL)
+ (void) setvbuf(rfp, buf, _IOFBF, XFER_BUFSIZE);
+#endif
+#ifdef SO_SNDBUF
+ /* the default seems to be 4K, and we'd like it to have enough room
+ * to parallelize sending the pushed data with accumulating more
+ * write() data from us.
+ */
+ (void) setsockopt(qsp->s_rfd, SOL_SOCKET, SO_SNDBUF,
+ (char *)&sndbuf, sizeof sndbuf);
+#endif
+ /* XXX: some day we would like to only send the size and header out
+ * when we fill a 64K DNS/AXFR "message" rather than on each RR.
+ * (PVM@ISI gets credit for this idea.)
+ */
+ fwritemsg(rfp, soa, soalen);
+ doaxfr(np, rfp, np, class);
+ fwritemsg(rfp, soa, soalen);
+ (void) fflush(rfp);
+#ifdef SO_LINGER
+ /* kernels that map pages for IO end up failing if the pipe is full
+ * at exit and we take away the final buffer. this is really a kernel
+ * bug but it's harmless on systems that are not broken, so...
+ */
+ setsockopt(qsp->s_rfd, SOL_SOCKET, SO_LINGER,
+ (char *)&ll, sizeof ll);
+ close(qsp->s_rfd);
+#endif
+ _exit(0);
+ /* NOTREACHED */
+}
+
+void
+free_addinfo() {
+ struct addinfo *ap;
+
+ for (ap = addinfo; --addcount >= 0; ap++) {
+ free(ap->a_dname);
+ free(ap->a_rname);
+ }
+ addcount = 0;
+}
+
+#ifdef DATUMREFCNT
+void
+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/named/ns_resp.c b/usr.sbin/named/named/ns_resp.c
new file mode 100644
index 00000000000..456ab34b406
--- /dev/null
+++ b/usr.sbin/named/named/ns_resp.c
@@ -0,0 +1,2595 @@
+/* $NetBSD: ns_resp.c,v 1.1 1996/02/02 15:29:03 mrg Exp $ */
+
+#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 8.19 1996/01/09 20:23:55 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 const char skipnameFailedAnswer[] = "skipname failed in answer",
+ skipnameFailedAuth[] = "skipname failed in authority",
+ skipnameFailedQuery[] = "skipname failed in query",
+ outofDataQuery[] = "ran out of data in query",
+ outofDataAnswer[] = "ran out of data in answer",
+ notSingleQuery[] = "not exactly one query",
+ expandFailedQuery[] = "dn_expand failed in query",
+ expandFailedAnswer[] = "dn_expand failed in answer",
+ expandFailedAuth[] = "dn_expand failed in authority",
+ outofDataAuth[] = "ran out of data in authority",
+ dlenOverrunAnswer[] = "dlen overrun in answer",
+ dlenOverrunAuth[] = "dlen overrun in authority",
+ dlenUnderrunAnswer[] = "dlen underrun in answer",
+ outofDataFinal[] = "out of data in final pass",
+ outofDataAFinal[] = "out of data after final pass",
+ editFailed[] = "edit of response failed";
+
+static char *
+learntFrom(qp, server)
+ struct qinfo *qp;
+ struct sockaddr_in *server;
+{
+ static char *buf = NULL;
+ char *a, *ns, *na;
+ struct databuf *db;
+ char nsbuf[20];
+ char abuf[20];
+ int i;
+
+ if (buf) {
+ free(buf);
+ buf = NULL;
+ }
+
+ a = ns = na = "<Not Available>";
+
+ for (i = 0; i < (int)qp->q_naddr; i++) {
+ if (qp->q_addr[i].ns_addr.sin_addr.s_addr ==
+ server->sin_addr.s_addr) {
+ db = qp->q_addr[i].ns;
+ if (db) {
+#ifdef STATS
+ if (db->d_ns) {
+ strcpy(nsbuf,
+ inet_ntoa(db->d_ns->addr));
+ ns = nsbuf;
+ } else {
+ ns = zones[db->d_zone].z_origin;
+ }
+#endif
+
+#ifdef NCACHE
+ if (!db->d_rcode)
+#endif
+ na = (char*)qp->q_addr[i].ns->d_data;
+ }
+
+#ifdef STATS
+ db = qp->q_addr[i].nsdata;
+ if (db) {
+ if (db->d_ns) {
+ strcpy(abuf,
+ inet_ntoa(db->d_ns->addr));
+ a = abuf;
+ } else {
+ a = zones[db->d_zone].z_origin;
+ }
+ }
+#endif
+ break;
+ }
+ }
+
+ if ((a == ns) && (ns == na)) /* all "UNKNOWN" */
+ return ("");
+
+#ifdef STATS
+# define LEARNTFROM " '%s': learnt (A=%s,NS=%s)"
+#else
+# define LEARNTFROM " '%s'"
+#endif
+ buf = malloc(strlen(a = (*a ? a : "\".\"")) +
+ strlen(ns = (*ns ? ns : "\".\"")) +
+ strlen(na = (*na ? na : "\".\"")) +
+ sizeof(LEARNTFROM));
+ if (!buf)
+ return ("");
+ sprintf(buf, LEARNTFROM, na, a, ns);
+ return (buf);
+}
+
+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;
+ u_char *eom = msg + msglen;
+ register u_char *tempcp;
+#ifdef VALIDATE
+ struct sockaddr_in *server = &from_addr;
+ struct { char *name; int type, class; u_int cred; } defer_rm[99];
+ int defer_rm_count;
+#endif
+ struct sockaddr_in *nsa;
+ struct databuf *nsp[NSMAX];
+ int i, c, n, qdcount, ancount, aucount, nscount, arcount;
+ int qtype, qclass, dbflags;
+ int restart; /* flag for processing cname response */
+ int validanswer;
+ int cname;
+ int count, founddata, foundname;
+ int buflen;
+ int newmsglen;
+ char name[MAXDNAME], qname[MAXDNAME];
+ char *dname;
+ const char *fname;
+ const char *formerrmsg = "brain damage";
+ u_char newmsg[PACKETSZ];
+ 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 high level formatting problems by parsing the header.
+ */
+ qdcount = ntohs(hp->qdcount);
+ ancount = ntohs(hp->ancount);
+ aucount = ntohs(hp->nscount); /* !!! */
+ arcount = ntohs(hp->arcount);
+ free_addinfo(); /* sets addcount to zero */
+ cp = msg + HFIXEDSZ;
+ dpp = dnptrs;
+ *dpp++ = msg;
+ if ((*cp & INDIR_MASK) == 0)
+ *dpp++ = cp;
+ *dpp = NULL;
+ if (qdcount == 1) {
+ n = dn_expand(msg, eom, cp, qname, sizeof(qname));
+ if (n <= 0) {
+ formerrmsg = expandFailedQuery;
+ goto formerr;
+ }
+ cp += n;
+ GETSHORT(qtype, cp);
+ GETSHORT(qclass, cp);
+ if (cp > eom) {
+ formerrmsg = outofDataQuery;
+ goto formerr;
+ }
+ if (qp->q_msg && qp->q_msglen &&
+ !res_nameinquery(qname, qtype, qclass,
+ qp->q_msg, qp->q_msg + qp->q_msglen)) {
+ char msgbuf[MAXDNAME*2];
+
+ sprintf(msgbuf,
+ "query section mismatch (%s %s %s)",
+ qname, p_class(qclass), p_type(qtype));
+ formerrmsg = msgbuf;
+ goto formerr;
+ }
+ } else {
+ /* Pedantic. */
+ qname[0] = '\0';
+ qtype = 0;
+ qclass = 0;
+ }
+
+ /* cp now points after the query section. */
+
+ /*
+ * 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 (it's sick)
+ * The server can't understand our query and return FORMERR
+ * In all these cases, we drop the packet, disable retries on
+ * this server and immediately force a retry.
+ */
+ if ((hp->rcode != NOERROR && hp->rcode != NXDOMAIN)
+ || (hp->opcode != QUERY
+#ifdef BIND_NOTIFY
+ && hp->opcode != NS_NOTIFY_OP
+#endif
+ )) {
+ 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;
+ }
+ /* mark server as bad */
+ if (!qp->q_fwd)
+ for (i = 0; i < (int)qp->q_naddr; i++)
+ if (qp->q_addr[i].ns_addr.sin_addr.s_addr
+ == from_addr.sin_addr.s_addr)
+ qp->q_addr[i].nretry = MAXRETRY;
+ /*
+ * XXX: doesn't handle responses sent from the wrong
+ * interface on a multihomed server.
+ */
+ if (qp->q_fwd ||
+ qp->q_addr[qp->q_curaddr].ns_addr.sin_addr.s_addr
+ == from_addr.sin_addr.s_addr)
+ retry(qp);
+ return;
+ }
+
+ if (qdcount != 1) {
+ /* We don't generate or forward these (yet). */
+ formerrmsg = notSingleQuery;
+ goto formerr;
+ }
+
+#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.
+ * Workaround: disable recursion on authoritative servers so that
+ * the ambiguity does not arise.
+ */
+ /*
+ * If we weren't using a forwarder, 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; (u_int)n < qp->q_naddr; n++, qs++)
+ if (qs->ns_addr.sin_addr.s_addr ==
+ from_addr.sin_addr.s_addr)
+ break;
+ if ((u_int)n >= qp->q_naddr) {
+ if (!haveComplained((char*)(long)from_addr.sin_addr.s_addr,
+ "unexpected source")) {
+ syslog(LOG_INFO,
+ "Response from unexpected source (%s)",
+ sin_ntoa(&from_addr));
+ }
+ /*
+ * 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",
+ sin_ntoa(&from_addr),
+ sin_ntoa(&qs->ns_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 %lu/%lu now %lu/%lu rtt %ld\n",
+ (u_long)stp->tv_sec, (u_long)stp->tv_usec,
+ (u_long)tt.tv_sec, (u_long)tt.tv_usec,
+ (long)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, sin_ntoa(&qs->ns_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;
+ (u_int)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,
+ sin_ntoa(&qs->ns_addr),
+ ns2->d_nstime));
+ }
+ }
+
+#ifdef BIND_NOTIFY
+ /* for now, NOTIFY isn't defined for ANCOUNT!=0, AUCOUNT!=0,
+ * or ADCOUNT!=0. therefore the only real work to be done for
+ * a NOTIFY-QR is to remove it from the query queue.
+ */
+ if (hp->opcode == NS_NOTIFY_OP) {
+ qremove(qp);
+ return;
+ }
+#endif
+
+#ifdef LAME_DELEGATION
+ /*
+ * Non-authoritative, no answer, no error
+ */
+ if (qdcount == 1 && hp->rcode == NOERROR && !hp->aa && ancount == 0
+ && aucount > 0
+#ifdef BIND_NOTIFY
+ && hp->opcode != NS_NOTIFY_OP
+#endif
+ ) {
+ u_char *tp;
+ int type, class;
+#ifdef DEBUG
+ if (debug > 0)
+ fp_nquery(msg, msglen, ddt);
+#endif
+ /*
+ * Since there is no answer section (ancount == 0),
+ * we must be pointing at the authority section (aucount > 0).
+ */
+ tp = cp;
+ n = dn_expand(msg, eom, tp, name, sizeof name);
+ if (n < 0) {
+ formerrmsg = expandFailedAuth;
+ goto formerr;
+ }
+ tp += n;
+ GETSHORT(type, tp);
+ if (tp >= eom) {
+ formerrmsg = outofDataAuth;
+ goto formerr;
+ }
+ GETSHORT(class, tp);
+ if (tp >= eom) {
+ 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. Note that for now we only log the message
+ * if the T_NS was C_IN, which is technically wrong (NS is
+ * visible in all classes) but necessary anyway (non-IN
+ * classes tend to not have good strong delegation graphs).
+ */
+
+ if (type == T_NS && samedomain(qp->q_domain, name)) {
+ nameserIncr(from_addr.sin_addr, nssRcvdLDel);
+ /* mark server as bad */
+ if (!qp->q_fwd)
+ for (i = 0; i < (int)qp->q_naddr; i++)
+ if (qp->q_addr[i].ns_addr.sin_addr.s_addr
+ == from_addr.sin_addr.s_addr)
+ qp->q_addr[i].nretry = MAXRETRY;
+#ifdef LAME_LOGGING
+ if (class == C_IN &&
+ !haveComplained((char*)(long)nhash(sin_ntoa(&from_addr)),
+ (char*)(long)nhash(qp->q_domain)))
+ syslog(LAME_LOGGING,
+ "Lame server on '%s' (in '%s'?): %s%s\n",
+ qname, qp->q_domain,
+ sin_ntoa(&from_addr),
+ learntFrom(qp, &from_addr));
+
+#endif /* LAME_LOGGING */
+ /* XXX - doesn't handle responses sent from the wrong
+ * interface on a multihomed server
+ */
+ if (qp->q_fwd ||
+ qp->q_addr[qp->q_curaddr].ns_addr.sin_addr.s_addr
+ == from_addr.sin_addr.s_addr)
+ retry(qp);
+ return;
+ }
+ }
+#endif /* LAME_DELEGATION */
+
+ if (qp->q_flags & Q_ZSERIAL) {
+ if (hp->aa && ancount > 0 && hp->rcode == NOERROR &&
+ qtype == T_SOA && ((qclass == C_IN) || (qclass == C_HS))) {
+ int n;
+ u_int16_t type, class, dlen;
+ u_int32_t serial;
+ u_char *tp = cp;
+
+ n = dn_expand(msg, eom, tp, name, sizeof name);
+ if (n < 0) {
+ formerrmsg = expandFailedAnswer;
+ goto formerr;
+ }
+ tp += n; /* name */
+ GETSHORT(type, tp); /* type */
+ GETSHORT(class, tp); /* class */
+ tp += INT32SZ; /* ttl */
+ GETSHORT(dlen, tp); /* dlen */
+ if (tp >= eom) {
+ formerrmsg = outofDataAnswer;
+ goto formerr;
+ }
+ if (strcasecmp(qname, name) ||
+ qtype != type ||
+ qclass != class) {
+ char msgbuf[MAXDNAME*2];
+
+ sprintf(msgbuf,
+ "qserial answer mismatch (%s %s %s)",
+ name, p_class(class), p_type(type));
+ formerrmsg = msgbuf;
+ goto formerr;
+ }
+ if ((u_int)dlen < (5 * INT32SZ)) {
+ formerrmsg = dlenUnderrunAnswer;
+ goto formerr;
+ }
+
+ if (0 >= (n = dn_skipname(tp, eom))) {
+ formerrmsg = skipnameFailedAnswer;
+ goto formerr;
+ }
+ tp += n; /* mname */
+ if (0 >= (n = dn_skipname(tp, eom))) {
+ 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;
+
+ /* -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;
+
+#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 (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 */
+
+ if (qp->q_flags & Q_SYSTEM)
+ dbflags = DB_NOTAUTH | DB_NODATA;
+ else
+ dbflags = DB_NOTAUTH | DB_NODATA | DB_NOHINTS;
+ count = c;
+ if (qp->q_flags & Q_PRIMING)
+ dbflags |= DB_PRIMING;
+ 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 */
+ }
+
+ tp = cp;
+
+ restart = 0;
+ validanswer = 0;
+ nscount = 0;
+ cname = 0;
+#ifdef VALIDATE
+ defer_rm_count = 0;
+#endif
+
+ for (i = 0; i < count; i++) {
+ struct databuf *ns3 = NULL;
+ u_char cred;
+ int VCode;
+ u_int16_t type, class;
+
+ if (cp >= eom) {
+ formerrmsg = outofDataFinal;
+ goto formerr;
+ }
+
+ /* Get the DNAME. */
+ tempcp = cp;
+ n = dn_expand(msg, eom, tempcp, name, sizeof name);
+ if (n <= 0) {
+ formerrmsg = outofDataFinal;
+ goto formerr;
+ }
+ tempcp += n;
+ GETSHORT(type, tempcp);
+ GETSHORT(class, tempcp);
+
+ /*
+ * See if there are any NS RRs in the authority section
+ * for the negative caching logic below. We'll count
+ * these before validation.
+ */
+ if (type == T_NS && i >= ancount && i < ancount + aucount)
+ nscount++;
+
+ /* Decide what credibility this ought to have in the cache. */
+ if (i < ancount)
+ cred = (hp->aa && !strcasecmp(name, qname))
+ ? DB_C_AUTH
+ : DB_C_ANSWER;
+ else
+ cred = (qp->q_flags & Q_PRIMING)
+ ? DB_C_ANSWER
+ : DB_C_ADDITIONAL;
+#ifdef VALIDATE
+ if ((n = dovalidate(msg, msglen, cp, 0,
+ dbflags, qp->q_domain, server,
+ &VCode)) < 0) {
+ formerrmsg = outofDataFinal;
+ goto formerr;
+ }
+ if (VCode == INVALID && !(qp->q_flags & Q_SYSTEM)) {
+ /*
+ * If anything in the answer section fails
+ * validation this means that it definitely did
+ * not reside below the domain owning the NS RRs
+ * that we sent the query to. This means either
+ * that it was the target of a CNAME early in the
+ * response, in which case we will treat this the
+ * same as if the answer was incomplete and restart
+ * the query on the CNAME target, or that someone
+ * was trying to spoof us.
+ */
+ if (i < ancount)
+ restart = 1;
+ /*
+ * Restart or no, if we're here it means we are not
+ * going to cache this RR. That being the case, we
+ * must burn down whatever partial RRset we've got
+ * in the cache now, lest we inadvertently answer
+ * with a truncated RRset in some future section.
+ */
+ for (c = 0; c < defer_rm_count; c++)
+ if (!strcasecmp(defer_rm[c].name, name) &&
+ defer_rm[c].class == class &&
+ defer_rm[c].type == type)
+ break;
+ if (c < defer_rm_count) {
+ if (defer_rm[c].cred < cred)
+ defer_rm[c].cred = cred;
+ } else {
+ if (defer_rm_count+1 >=
+ (sizeof defer_rm / sizeof defer_rm[0])) {
+ formerrmsg = "too many RRs in ns_resp";
+ goto formerr;
+ }
+ defer_rm[defer_rm_count].name = savestr(name);
+ defer_rm[defer_rm_count].type = type;
+ defer_rm[defer_rm_count].class = class;
+ defer_rm[defer_rm_count].cred = cred;
+ defer_rm_count++;
+ }
+ } else {
+#endif
+ if (i < ancount) {
+ /*
+ * If there are any non-CNAME RRs (or
+ * CNAME RRs if they are an acceptable)
+ * then the query is complete unless an
+ * intermediate CNAME didn't pass validation,
+ * but that's OK.
+ */
+ if (type != T_CNAME || qtype == T_CNAME ||
+ qtype == T_ANY)
+ validanswer = 1;
+ else
+ cname = 1;
+ }
+ n = doupdate(msg, msglen, cp, 0, &ns3, dbflags, cred);
+#ifdef VALIDATE
+ }
+#endif
+ if (n < 0) {
+ dprintf(1, (ddt, "resp: leaving, doupdate failed\n"));
+ formerrmsg = outofDataFinal;
+ goto formerr;
+ }
+ cp += n;
+ }
+#ifdef VALIDATE
+ if (defer_rm_count > 0) {
+ for (i = 0; i < defer_rm_count; i++) {
+ register struct databuf *db = NULL;
+
+ fname = "";
+ htp = hashtab; /* lookup relative to root */
+ np = nlookup(defer_rm[i].name, &htp, &fname, 0);
+ if (np && fname == defer_rm[i].name &&
+ defer_rm[i].class != C_ANY &&
+ defer_rm[i].type != T_ANY) {
+ /*
+ * If doupdate() wouldn't have cached this
+ * RR anyway, there's no need to delete it.
+ */
+ for (db = np->n_data;
+ db != NULL;
+ db = db->d_next) {
+ if (!db->d_zone &&
+ match(db, defer_rm[i].class,
+ defer_rm[i].type) &&
+ db->d_cred >= defer_rm[i].cred) {
+ break;
+ }
+ }
+ if (db == NULL)
+ delete_all(np, defer_rm[i].class,
+ defer_rm[i].type);
+ /* XXX: should delete name node if empty? */
+ }
+ syslog(LOG_DEBUG, "defer_rm [%s %s %s] (np%#x, db%#x)",
+ defer_rm[i].name,
+ p_class(defer_rm[i].class),
+ p_type(defer_rm[i].type),
+ np, db);
+ free(defer_rm[i].name);
+ }
+ }
+#endif
+
+ if (cp > eom) {
+ formerrmsg = outofDataAFinal;
+ goto formerr;
+ }
+
+ 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));
+#ifdef BIND_NOTIFY
+ if (qp->q_notifyzone != DB_Z_CACHE) {
+ struct zoneinfo *zp = &zones[qp->q_notifyzone];
+
+ /*
+ * Clear this first since sysnotify() might set it.
+ */
+ qp->q_notifyzone = DB_Z_CACHE;
+ sysnotify(zp->z_origin, zp->z_class, T_SOA);
+ }
+#endif
+ qremove(qp);
+ return;
+ }
+
+ if (ancount && !validanswer)
+ /*
+ * Everything passed validation but we didn't get the
+ * final answer. The response must have contained
+ * a dangling CNAME. Force a restart of the query.
+ */
+ restart = 1;
+
+ /*
+ * If there are addresses and this is a local query,
+ * sort them appropriately for the local context.
+ */
+#ifdef SORT_RESPONSE
+ if (!restart && ancount > 1 && (lp = local(&qp->q_from)) != NULL)
+ sort_response(tp, ancount, lp, eom);
+#endif
+
+ /*
+ * An answer to a T_ANY query or a successful answer to a
+ * regular query with no indirection, then just return answer.
+ */
+ if (!restart && ancount && (qtype == T_ANY || !qp->q_cmsglen)) {
+ 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 || qclass == C_ANY)) {
+ /* we have an authoritative NO */
+ dprintf(3, (ddt, "resp: leaving auth NO\n"));
+ if (qp->q_cmsglen) {
+ /* XXX - what about additional CNAMEs in the chain? */
+ 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;
+ /*
+ * Even with VALIDATE, if restart==0 and ancount > 0, we should
+ * have some valid data because because the data in the answer
+ * section is owned by the query name and that passes the
+ * validation test by definition
+ *
+ * XXX - the restart stuff doesn't work if any of the answer RRs
+ * is not cacheable (TTL==0 or unknown RR type), since all of the
+ * answer must pass through the cache and be re-assembled.
+ */
+ if ((!restart || !cname) && qp->q_cmsglen && ancount) {
+ dprintf(1, (ddt, "Cname second pass\n"));
+ newmsglen = MIN(PACKETSZ, qp->q_cmsglen);
+ bcopy(qp->q_cmsg, newmsg, newmsglen);
+ } else {
+ newmsglen = MIN(PACKETSZ, msglen);
+ bcopy(msg, newmsg, newmsglen);
+ }
+ hp = (HEADER *) newmsg;
+ hp->ancount = htons(0);
+ hp->nscount = htons(0);
+ hp->arcount = htons(0);
+ dnptrs[0] = newmsg;
+ dnptrs[1] = NULL;
+ cp = newmsg + HFIXEDSZ;
+ /*
+ * Keep in mind that none of this code works when QDCOUNT>1.
+ * cp ends up pointed just past the query section in both cases.
+ */
+ /*
+ * Arrange for dname to contain the query name. The query
+ * name can be either the original query name if restart==0
+ * or the target of the last CNAME if we are following a
+ * CNAME chain and were referred.
+ */
+ n = dn_expand(newmsg, newmsg + newmsglen, cp, dname,
+ sizeof name);
+ if (n < 0) {
+ dprintf(1, (ddt, "dn_expand failed\n"));
+ goto servfail;
+ }
+ cp += n + QFIXEDSZ;
+ buflen = sizeof(newmsg) - (cp - newmsg);
+
+ cname = 0;
+ try_again:
+ dprintf(1, (ddt, "resp: nlookup(%s) qtype=%d\n", dname, qtype));
+ 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, qclass, qtype, hp, &dname, &buflen, &count);
+ if (n == 0)
+ goto fetch_ns; /* NO data available */
+ cp += n;
+ buflen -= n;
+ hp->ancount = htons(ntohs(hp->ancount) + (u_int16_t)count);
+ if (fname != dname && qtype != T_CNAME && qtype != 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:
+
+ if (hp->tc)
+ goto return_newmsg;
+
+ /*
+ * 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, qclass, 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 (qclass != 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, &count);
+ 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 %s %s)\n",
+ dname, p_class(qclass), p_type(qtype)));
+ syslog(LOG_INFO,
+ "MAXQUERIES exceeded, possible data loop in resolving (%s)",
+ dname);
+ goto servfail;
+ }
+
+ /* Reset the query control structure */
+#ifdef DATUMREFCNT
+ /* XXX - this code should be shared with qfree()'s similar logic. */
+ for (i = 0; (u_int)i < qp->q_naddr; i++) {
+ static const char freed[] = "freed", busy[] = "busy";
+ const char *result;
+
+ if (qp->q_addr[i].ns != NULL) {
+ if ((--(qp->q_addr[i].ns->d_rcnt)))
+ result = busy;
+ else
+ result = freed;
+ dprintf(1, (ddt, "ns_resp: ns %s rcnt %d (%s)\n",
+ qp->q_addr[i].ns->d_data,
+ qp->q_addr[i].ns->d_rcnt,
+ result));
+ if (result == freed)
+ free((char*)qp->q_addr[i].ns);
+ }
+ if (qp->q_addr[i].nsdata != NULL) {
+ if ((--(qp->q_addr[i].nsdata->d_rcnt)))
+ result = busy;
+ else
+ result = freed;
+ dprintf(1, (ddt,
+ "ns_resp: nsdata %08.8X rcnt %d (%s)\n",
+ *(int32_t *)(qp->q_addr[i].nsdata->d_data),
+ qp->q_addr[i].nsdata->d_rcnt,
+ result));
+ if (result == freed)
+ free((char*)qp->q_addr[i].nsdata);
+ }
+ }
+#endif
+ qp->q_naddr = 0;
+ qp->q_curaddr = 0;
+ qp->q_fwd = fwdtab;
+#if defined(LAME_DELEGATION) || defined(VALIDATE)
+ 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; (u_int)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_cmsg) {
+ qp->q_cmsg = qp->q_msg;
+ qp->q_cmsglen = qp->q_msglen;
+ } else if (qp->q_msg)
+ (void) free(qp->q_msg);
+ if ((qp->q_msg = (u_char *)malloc(BUFSIZ)) == NULL) {
+ syslog(LOG_NOTICE, "resp: malloc error\n");
+ goto servfail;
+ }
+ n = res_mkquery(QUERY, dname, qclass, qtype,
+ NULL, 0, NULL, qp->q_msg, BUFSIZ);
+ if (n < 0) {
+ syslog(LOG_INFO, "resp: res_mkquery(%s) failed",
+ dname);
+ goto servfail;
+ }
+ qp->q_msglen = n;
+ hp = (HEADER *) qp->q_msg;
+ hp->rd = 0;
+ } else
+ hp = (HEADER *) qp->q_msg;
+ hp->id = qp->q_nsid = htons(nsid_next());
+ if (qp->q_fwd)
+ hp->rd = 1;
+ unsched(qp);
+ schedretry(qp, retrytime(qp));
+ nsa = Q_NEXTADDR(qp, 0);
+ dprintf(1, (ddt, "resp: forw -> %s ds=%d nsid=%d id=%d %dms\n",
+ sin_ntoa(nsa), 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_nquery(qp->q_msg, qp->q_msglen, ddt);
+#endif
+ if (sendto(ds, (char*)qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0) {
+ if (!haveComplained((char*)(long)nsa->sin_addr.s_addr, sendtoStr))
+ syslog(LOG_INFO, "ns_resp: sendto(%s): %m",
+ sin_ntoa(nsa));
+ 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:
+ if (!haveComplained((char*)(long)from_addr.sin_addr.s_addr,
+ (char*)(long)nhash(formerrmsg)))
+ syslog(LOG_INFO, "Malformed response from %s (%s)\n",
+ sin_ntoa(&from_addr), 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 = (NoRecurse == 0);
+ (void) send_msg(msg, msglen, qp);
+ qremove(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+
+ return_newmsg:
+ nameserIncr(qp->q_from.sin_addr, nssSentAns);
+
+#ifdef XSTATS
+ if (!hp->aa)
+ nameserIncr(qp->q_from.sin_addr, nssSentNaAns);
+ if (hp->rcode == NXDOMAIN)
+ nameserIncr(qp->q_from.sin_addr, nssSentNXD);
+#endif
+ n = doaddinfo(hp, cp, buflen);
+ cp += n;
+ buflen -= n;
+ hp->qr = 1;
+ hp->id = qp->q_id;
+ hp->rd = 1;
+ hp->ra = (NoRecurse == 0);
+ (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->qr = 1;
+ hp->id = qp->q_id;
+ hp->rd = 1;
+ hp->ra = (NoRecurse == 0);
+ (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 %#lx, flags %#lx)\n",
+ zone, (u_long)savens, (u_long)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:
+ case T_LOC:
+#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;
+
+ case T_PX:
+ /* grab preference */
+ bcopy(cp, data, INT16SZ);
+ cp1 = data + INT16SZ;
+ cp += INT16SZ;
+
+ /* get MAP822 name */
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1,
+ sizeof data - INT16SZ);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += (n = strlen((char *)cp1) + 1);
+ n1 = sizeof(data) - n;
+ 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;
+ 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 = 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 *temp, qname[MAXDNAME];
+ 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*)(long)from_addr.sin_addr.s_addr,
+ "bogus root NS"))
+ syslog(LOG_NOTICE,
+ "bogus root NS %s rcvd from %s on query for \"%s\"",
+ data, sin_ntoa(&from_addr), qname);
+ return (cp - rrp);
+ }
+#ifdef BOGUSNS
+ if (bogusns) {
+ if (!haveComplained((char*)(long)from_addr.sin_addr.s_addr,
+ "bogus nonroot NS"))
+ syslog(LOG_INFO,
+ "bogus nonroot NS %s rcvd from %s on query for \"%s\"",
+ data, sin_ntoa(&from_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) id=%d\n",
+ sin_ntoa(&qp->q_from),
+ qp->q_stream == QSTREAM_NULL ? "UDP" : "TCP",
+ qp->q_stream == QSTREAM_NULL ? qp->q_dfd
+ : qp->q_stream->s_rfd,
+ ntohs(qp->q_id));
+ }
+ if (debug > 4) {
+ struct qinfo *tqp;
+
+ for (tqp = nsqhead; tqp!=QINFO_NULL; tqp = tqp->q_link) {
+ fprintf(ddt,
+ "qp %#lx q_id: %d q_nsid: %d q_msglen: %d ",
+ (u_long)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: %#lx q_link: %#lx\n",
+ (u_long)qp->q_next, (u_long)qp->q_link);
+ }
+ }
+ if (debug > 5)
+ fp_nquery(msg, msglen, ddt);
+#endif /* DEBUG */
+ if (qp->q_stream == QSTREAM_NULL) {
+ if (sendto(qp->q_dfd, (char*)msg, msglen, 0,
+ (struct sockaddr *)&qp->q_from,
+ sizeof(qp->q_from)) < 0) {
+ if (!haveComplained((char*)(long)qp->q_from.sin_addr.s_addr,
+ sendtoStr))
+#if defined(SPURIOUS_ECONNREFUSED)
+ if (errno != ECONNREFUSED)
+#endif
+ syslog(LOG_INFO,
+ "send_msg: sendto(%s): %m",
+ sin_ntoa(&qp->q_from));
+ 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, QUERY);
+}
+#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, QUERY)))
+ priming = 0;
+ else
+ qp->q_flags |= (Q_SYSTEM | Q_PRIMING);
+ }
+ needs_prime_cache = 0;
+ return;
+}
+
+#ifdef BIND_NOTIFY
+struct notify *
+findNotifyPeer(zp, ina)
+ const struct zoneinfo *zp;
+ struct in_addr ina;
+{
+ register struct notify *ap;
+
+ for (ap = zp->z_notifylist; ap; ap = ap->next)
+ if (ap->addr.s_addr == ina.s_addr)
+ break;
+ return (ap);
+}
+
+/* sysnotify(dname, class, type)
+ * cause a NOTIFY request to be sysquery()'d to each secondary server
+ * of the zone that "dname" is within.
+ */
+void
+sysnotify(dname, class, type)
+ const char *dname;
+ int class, type;
+{
+ char *soaname, *zname;
+ const char *fname;
+ register struct databuf *dp;
+ struct in_addr nss[NSMAX];
+ int nns, na, zn, nsc;
+ struct hashbuf *htp;
+ struct zoneinfo *zp;
+ struct notify *ap;
+ struct namebuf *np;
+
+ htp = hashtab;
+ np = nlookup(dname, &htp, &fname, 0);
+ if (!np)
+ panic(-1, "sysnotify: can't find name");
+ zn = findMyZone(np, class);
+ if (zn == DB_Z_CACHE)
+ panic(-1, "sysnotify: not auth zone");
+ zp = &zones[zn];
+ if (zp->z_type != Z_PRIMARY && zp->z_type != Z_SECONDARY)
+ panic(-1, "sysnotify: not pri/sec");
+ zname = zp->z_origin;
+/*
+**DBG** syslog(LOG_INFO, "sysnotify: found \"%s\" in \"%s\" (%s)",
+**DBG** dname, zname, zoneTypeString(zp));
+*/
+ nns = na = 0;
+ /*
+ * Send to recent AXFR peers.
+ */
+ for (ap = zp->z_notifylist; ap; ap = ap->next) {
+ if (tt.tv_sec - ap->last >= zp->z_refresh) {
+ /* XXX - probably should do GC here. */
+ continue;
+ }
+ nss[0] = ap->addr;
+ nsc = 1;
+ nns++;
+ na++;
+ sysquery(dname, class, T_SOA, nss, nsc, NS_NOTIFY_OP);
+ }
+ if (zp->z_type != Z_PRIMARY)
+ goto done;
+ /*
+ * Master.
+ */
+ htp = hashtab;
+ np = nlookup(zname, &htp, &fname, 0);
+ if (!np)
+ panic(-1, "sysnotify: found name but not zone");
+ soaname = NULL;
+ for (dp = np->n_data; dp; dp = dp->d_next) {
+ if (!dp->d_zone || !match(dp, class, T_SOA))
+ continue;
+ if (soaname) {
+ syslog(LOG_NOTICE, "multiple SOA's for zone \"%s\"?",
+ zname);
+ return;
+ }
+ soaname = (char *) dp->d_data;
+ }
+ if (!soaname) {
+ syslog(LOG_NOTICE, "no SOA found for zone \"%s\"", zname);
+ return;
+ }
+
+ for (dp = np->n_data; dp; dp = dp->d_next) {
+ register struct databuf *adp;
+ struct namebuf *anp;
+
+ if (!dp->d_zone || !match(dp, class, T_NS))
+ continue;
+ /* NS RDATA is server name. */
+ if (strcasecmp((char*)dp->d_data, soaname) == 0)
+ continue;
+ htp = hashtab;
+ anp = nlookup((char*)dp->d_data, &htp, &fname, 0);
+ if (!anp) {
+ syslog(LOG_INFO, "sysnotify: can't nlookup(%s)?",
+ (char*)dp->d_data);
+ continue;
+ }
+ nsc = 0;
+ for (adp = anp->n_data; adp; adp = adp->d_next) {
+ struct in_addr ina;
+ if (!match(adp, class, T_A))
+ continue;
+ ina = data_inaddr(adp->d_data);
+ /* Don't send to things we handled above. */
+ ap = findNotifyPeer(zp, ina);
+ if (ap && tt.tv_sec - ap->last < zp->z_refresh)
+ goto nextns;
+ if (nsc < NSMAX)
+ nss[nsc++] = ina;
+ } /*next A*/
+ if (nsc == 0) {
+ struct qinfo *qp;
+
+ qp = sysquery((char*)dp->d_data, /*NS name*/
+ class, /*XXX: C_IN?*/
+ T_A, 0, 0, QUERY);
+ if (qp)
+ qp->q_notifyzone = zn;
+ continue;
+ }
+ (void) sysquery(dname, class, T_SOA, nss, nsc, NS_NOTIFY_OP);
+ nns++;
+ na += nsc;
+ nextns:;
+ } /*next NS*/
+ done:
+ if (nns || na) {
+ char tmp[MAXDNAME*2];
+
+ /* Many syslog()'s only take 5 args. */
+ sprintf(tmp, "%s %s %s", dname, p_class(class), p_type(type));
+ syslog(LOG_INFO, "Sent NOTIFY for \"%s\" (%s); %d NS, %d A",
+ tmp, zname, nns, na);
+ }
+}
+#endif /*BIND_NOTIFY*/
+
+struct qinfo *
+sysquery(dname, class, type, nss, nsc, opcode)
+ const char *dname;
+ int class, type;
+ struct in_addr *nss;
+ int nsc, opcode;
+{
+ register struct qinfo *qp, *oqp;
+ register HEADER *hp;
+ struct namebuf *np;
+ struct databuf *nsp[NSMAX];
+ struct hashbuf *htp;
+ struct sockaddr_in *nsa;
+ const char *fname;
+ int n, count;
+
+#ifdef DATUMREFCNT
+ nsp[0] = NULL;
+#endif
+ dprintf(3, (ddt, "sysquery(%s, %d, %d, %#lx, %d)\n",
+ dname, class, type, (u_long)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) {
+ syslog(LOG_INFO, "sysquery: nlookup error on %s?",
+ dname);
+ err1:
+ qfree(qp);
+ return (NULL);
+ }
+
+ n = findns(&np, class, nsp, &count, 0);
+ switch (n) {
+ case NXDOMAIN:
+ case SERVFAIL:
+ syslog(LOG_DEBUG, "sysquery: findns error (%d) on %s?",
+ n, dname);
+ err2:
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ goto err1;
+ }
+ }
+
+ /* 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;
+#if defined(LAME_DELEGATION) || defined(VALIDATE)
+ getname(np, qp->q_domain, sizeof(qp->q_domain));
+#endif /* LAME_DELEGATION */
+
+ if ((qp->q_msg = (u_char *)malloc(BUFSIZ)) == NULL) {
+ syslog(LOG_NOTICE, "sysquery: malloc failed");
+ goto err2;
+ }
+ n = res_mkquery(opcode, dname, class,
+ type, NULL, 0, NULL,
+ qp->q_msg, BUFSIZ);
+ if (n < 0) {
+ syslog(LOG_INFO, "sysquery: res_mkquery(%s) failed", dname);
+ goto err2;
+ }
+ qp->q_msglen = n;
+ hp = (HEADER *) qp->q_msg;
+ hp->id = qp->q_nsid = htons(nsid_next());
+ hp->rd = (qp->q_fwd ? 1 : 0);
+
+ /* First check for an already pending query for this data */
+ for (oqp = nsqhead; oqp != QINFO_NULL; oqp = oqp->q_link) {
+ if ((oqp != qp)
+ && (oqp->q_msglen == qp->q_msglen)
+ && bcmp((char *)oqp->q_msg+2,
+ qp->q_msg+2,
+ qp->q_msglen-2) == 0
+ ) {
+#ifdef BIND_NOTIFY
+ /* XXX - need fancier test to suppress duplicate
+ * NOTIFYs to the same server (compare nss?)
+ */
+ if (opcode != NS_NOTIFY_OP)
+#endif /*BIND_NOTIFY*/
+ {
+ dprintf(3, (ddt, "sysquery: duplicate\n"));
+ goto err2;
+ }
+ }
+ }
+
+ 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 {
+ count = nslookup(nsp, qp, dname, "sysquery");
+ if (count <= 0) {
+ if (count < 0)
+ syslog(LOG_INFO,
+ "sysquery: nslookup reports danger (%s)",
+ dname);
+ else
+ /* "." domain gets LOG_WARNING here. */
+ syslog(dname[0] ? LOG_INFO : LOG_WARNING,
+ "sysquery: no addrs found for NS (%s)",
+ dname);
+ goto err2;
+ }
+ }
+
+ 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 dfd=%d nsid=%d id=%d retry=%ld\n",
+ sin_ntoa(nsa), qp->q_dfd,
+ ntohs(qp->q_nsid), ntohs(qp->q_id),
+ qp->q_time));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_nquery(qp->q_msg, qp->q_msglen, ddt);
+#endif
+ if (sendto(qp->q_dfd, (char*)qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0) {
+ if (!haveComplained((char*)(long)nsa->sin_addr.s_addr, sendtoStr))
+ syslog(LOG_INFO, "sysquery: sendto(%s): %m",
+ sin_ntoa(nsa));
+ 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_NOTICE, "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_NOTICE,
+ "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;
+ const 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 %#lx\n",
+ dname, fname, (u_long)tnp));
+ sysquery(dname, dp->d_class, T_A, NULL,
+ 0, QUERY);
+ 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)
+ sysquery(dname, dp->d_class, T_A, NULL,
+ 0, QUERY);
+ }
+ }
+}
+
+/* int findns(npp, class, nsp, countp, flag)
+ * Find NS' or an SOA
+ * npp, class:
+ * dname whose most enclosing 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 %#lx '%s'\n",
+ (u_long)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 &&
+#ifdef PURGE_ZONE
+ ((zones[dp->d_zone].z_type == Z_PRIMARY) ||
+ (zones[dp->d_zone].z_type == Z_SECONDARY)) &&
+#endif
+ 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;
+#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!
+ *
+ * XXX: this is horribly bogus.
+ */
+ if ((dp->d_zone == 0) &&
+#ifdef DATUMREFCNT
+ (dp->d_ttl < tt.tv_sec) &&
+#else
+ (dp->d_ttl < (tt.tv_sec+900)) &&
+#endif
+ !(dp->d_flags & DB_F_HINT)) {
+ dprintf(1, (ddt, "findns: stale entry '%s'\n",
+ np->n_dname));
+ /* Cache invalidate the NS RR's. */
+#ifndef DATUMREFCNT
+ if (dp->d_ttl < tt.tv_sec)
+#endif
+ 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_INFO, "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;
+#ifdef DEBUG
+ if (buflen > PACKETSZ)
+ dprintf(1, (ddt, "finddata(): buflen=%d\n", buflen));
+#endif
+ 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_INFO,
+ "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_INFO,
+ "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 != DB_Z_CACHE &&
+ (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(%#lx, %d, %d) [%s %s]\n",
+ (u_long)dp, class, type,
+ p_class(dp->d_class), p_type(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 occured. Typically you are
+ * adding NS records to a response.
+ */
+int
+add_data(np, dpp, cp, buflen, countp)
+ struct namebuf *np;
+ struct databuf **dpp;
+ register u_char *cp;
+ int buflen, *countp;
+{
+ register struct databuf *dp;
+ char dname[MAXDNAME];
+ register int n, bytes;
+
+ bytes = *countp = 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 (-bytes); /* Truncation */
+ cp += n;
+ buflen -= n;
+ bytes += n;
+ (*countp)++;
+ }
+ return (bytes);
+}
+
+/*
+ * This is best thought of as a "cache invalidate" function.
+ * It is called whenever a piece of data is determined to have
+ * become invalid either through a timeout or a validation
+ * failure. 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(%#lx:\"%s\" %s %s)\n",
+ (u_long)np, np->n_dname, p_class(class), p_type(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/named/ns_sort.c b/usr.sbin/named/named/ns_sort.c
new file mode 100644
index 00000000000..def3092d61a
--- /dev/null
+++ b/usr.sbin/named/named/ns_sort.c
@@ -0,0 +1,173 @@
+/* $NetBSD: ns_sort.c,v 1.1 1996/02/02 15:29:07 mrg Exp $ */
+
+#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 8.3 1995/12/22 10:20:30 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));
+
+#ifdef SORT_RESPONSE
+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(%#lx, %d, [%s])\n",
+ (u_long)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);
+}
+#endif
diff --git a/usr.sbin/named/named/ns_stats.c b/usr.sbin/named/named/ns_stats.c
new file mode 100644
index 00000000000..28554fbfd1b
--- /dev/null
+++ b/usr.sbin/named/named/ns_stats.c
@@ -0,0 +1,400 @@
+/* $NetBSD: ns_stats.c,v 1.1 1996/02/02 15:29:09 mrg Exp $ */
+
+#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 8.4 1995/06/29 09:26:17 vixie Exp ";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986,1994
+ * -
+ * Copyright (c) 1986,1994
+ * 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 <arpa/inet.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", "NSAP_PTR", "SIG",
+ "KEY", "PX", "invalid(GPOS)", "AAAA", "LOC",
+ 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 = time(NULL);
+ register FILE *f;
+ register int i;
+
+ syslog(LOG_NOTICE, "dumping nameserver stats\n");
+
+ if (!(f = fopen(statsfile, "a"))) {
+ syslog(LOG_NOTICE, "cannot open stat file, \"%s\"\n",
+ statsfile);
+ return;
+ }
+
+ fprintf(f, "+++ Statistics Dump +++ (%ld) %s",
+ (long)timenow, ctime(&timenow));
+ fprintf(f, "%ld\ttime since boot (secs)\n",
+ (long)(timenow - boottime));
+ fprintf(f, "%ld\ttime since reset (secs)\n",
+ (long)(timenow - resettime));
+
+#ifdef DMALLOC
+ /* malloc statistics */
+ dmallocstats(f);
+#endif
+
+ /* query type statistics */
+ fprintf(f, "%lu\tUnknown query types\n", (u_long)typestats[0]);
+ for(i=1; i < T_ANY+1; i++)
+ if (typestats[i])
+ if (typenames[i])
+ fprintf(f, "%lu\t%s queries\n",
+ (u_long)typestats[i], typenames[i]);
+ else
+ fprintf(f, "%lu\ttype %d queries\n",
+ (u_long)typestats[i], i);
+
+ /* name server statistics */
+ nameserStats(f);
+
+ fprintf(f, "--- Statistics Dump --- (%ld) %s",
+ (long)timenow, ctime(&timenow));
+ (void) my_fclose(f);
+ syslog(LOG_NOTICE, "done dumping nameserver stats\n");
+}
+
+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 */
+ "SErr", /* sent failed (in sendto) */
+#ifdef XSTATS
+ "RNotNsQ", /* received from remote port != ns_port */
+ "SNaAns", /* sent them a non autoritative answer */
+ "SNXD", /* sent them a negative response */
+#endif
+ };
+#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;
+ const char *pre = "\t";
+
+ for (i = 0; i < (int)nssLast; i++) {
+ fprintf(f, "%s%lu", pre, (u_long)stats[i]);
+ pre = ((i+1) % 5) ? " " : " ";
+ }
+ fputc('\n', f);
+}
+
+static void
+nameserStatsHdr(f)
+ FILE *f;
+{
+ int i;
+ const 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*/
+}
+
+#ifdef XSTATS
+/* Benoit Grange, log minimal statistics, called from ns_maint */
+void
+ns_logstats()
+{
+ char buffer[1024];
+ char buffer2[32], header[64];
+ time_t timenow = time(NULL);
+ int i;
+
+#ifdef HAVE_GETRUSAGE
+# define tv_float(tv) ((tv).tv_sec + ((tv).tv_usec / 1000000.0))
+ struct rusage usage, childu;
+
+ getrusage(RUSAGE_SELF, &usage);
+ getrusage(RUSAGE_CHILDREN, &childu);
+
+ sprintf(buffer, "CPU=%gu/%gs CHILDCPU=%gu/%gs",
+ tv_float(usage.ru_utime), tv_float(usage.ru_stime),
+ tv_float(childu.ru_utime), tv_float(childu.ru_stime));
+ syslog(LOG_INFO, "USAGE %lu %lu %s", timenow, boottime, buffer);
+# undef tv_float
+#endif
+
+ sprintf(header, "NSTATS %lu %lu", timenow, boottime);
+ strcpy(buffer, header);
+
+ for (i = 0; i < T_ANY+1; i++) {
+ if (typestats[i]) {
+ if (typenames[i])
+ sprintf(buffer2, " %s=%lu",
+ typenames[i], typestats[i]);
+ else
+ sprintf(buffer2, " %d=%lu", i, typestats[i]);
+ if (strlen(buffer) + strlen(buffer2) >
+ sizeof(buffer) - 1) {
+ syslog(LOG_INFO, buffer);
+ strcpy(buffer, header);
+ }
+ strcat(buffer, buffer2);
+ }
+ }
+ syslog(LOG_INFO, buffer);
+
+ sprintf(header, "XSTATS %lu %lu", (u_long)timenow, (u_long)boottime);
+ strcpy(buffer, header);
+ for (i = 0; i < (int)nssLast; i++) {
+ sprintf(buffer2, " %s=%lu",
+ statNames[i]?statNames[i]:"?", (u_long)globalStats[i]);
+ if (strlen(buffer) + strlen(buffer2) > sizeof(buffer) - 1) {
+ syslog(LOG_INFO, buffer);
+ strcpy(buffer, header);
+ }
+ strcat(buffer, buffer2);
+ }
+ syslog(LOG_INFO, buffer);
+}
+
+#endif /*XSTATS*/
diff --git a/usr.sbin/named/named/ns_validate.c b/usr.sbin/named/named/ns_validate.c
new file mode 100644
index 00000000000..3a6fc1deb90
--- /dev/null
+++ b/usr.sbin/named/named/ns_validate.c
@@ -0,0 +1,1247 @@
+/* $NetBSD: ns_validate.c,v 1.1 1996/02/02 15:29:12 mrg Exp $ */
+
+/**************************************************************************
+ * 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 <arpa/inet.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, qdomain, 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 (domain lives below the qdomain)
+ * return VALID_CACHE;
+ * 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, qdomain, server, type, class, data, dlen
+#ifdef NCACHE
+ ,rcode
+#endif
+ )
+ char *dname, *qdomain;
+ struct sockaddr_in *server;
+ int type, class;
+ char *data;
+ int dlen;
+#ifdef NCACHE
+ int rcode;
+#endif
+{
+ struct namebuf *np, *dnamep;
+ struct hashbuf *htp;
+ struct databuf *nsp[NSMAX];
+ int count;
+ const 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 = "";
+ dprintf(5, (ddt,
+ "validate:namebuf found np:%#lx, d:\"%s\", f:\"%s\"\n",
+ (u_long)np, dname, fname));
+ /* save the namebuf if we were able to locate the exact dname */
+ if (!strcasecmp(dname, fname)) {
+ dnamep = np;
+ exactmatch = 1;
+ }
+ 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\n"));
+ if (needs_prime_cache)
+ needs_prime_cache = 0;
+ if (samedomain(dname, qdomain) ||
+ 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:
+ case T_LOC:
+#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);
+
+ case T_PX:
+ x = memcmp(dp->d_data, data,
+ INT16SZ);
+ if (x != 0)
+ break;
+ td = data + INT16SZ;
+ tdp = dp->d_data + INT16SZ;
+
+ /* compare first string */
+ x = strncasecmp(td, (char *)tdp,
+ strlen((char *)td) + 1);
+ if (x != 0)
+ break;
+ td += (strlen(td) + 1);
+ tdp += (strlen((char *)tdp) + 1);
+
+ /* compare second string */
+ 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%lx, d:\"%s\"\n",
+ inet_ntoa(*saddr), (u_long)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;
+ const char *dname, *fname;
+ int class;
+ int qcomp();
+
+ dprintf(3, (ddt, "check_in_tables(nsp=x%lx, qp=x%x, '%s')\n",
+ (u_long)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)
+ const char *servername;
+ struct in_addr serveraddr;
+ const char *syslogdname;
+ const 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*)
+ nhash(nameaddrlist[i].nsname),
+ (char*)nhash(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 = savestr(servername);
+ return;
+ }
+ }
+ /* we have to add this one to our cache */
+
+ nameaddrlist[firstNA].nsname = savestr(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, qdomain, server, VCode)
+ u_char *msg, *rrp;
+ int msglen, zone, flags;
+ char *qdomain;
+ 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_nquery(msg, msglen, 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:
+ case T_LOC:
+#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;
+
+ case T_PX:
+ /* grab preference */
+ bcopy((char *)cp, data, INT16SZ);
+ cp1 = data + INT16SZ;
+ cp += INT16SZ;
+
+ /* get first name */
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)cp1, sizeof(data) - INT16SZ);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += (n = strlen((char *)cp1) + 1);
+ n1 = sizeof(data) - n;
+
+ /* get second name */
+ 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;
+ 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 = FORMERR;
+ return (-1);
+ }
+
+ *VCode = validate(dname, qdomain, 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));
+ if (!validateQ)
+ panic(errno, "malloc(validateQ)");
+ validateQ->type = type;
+ validateQ->class = class;
+ validateQ->dname = savestr(dname);
+ validateQ->data = savestr(data); /* XXX no \0 */
+ 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));
+ if (!tempVQ)
+ panic(errno, "malloc(tempVQ)");
+ tempVQ->type = type;
+ tempVQ->class = class;
+ tempVQ->dname = savestr(dname);
+ tempVQ->data = savestr(data); /* XXX no \0 */
+ 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
+
+#ifdef BAD_IDEA
+/* 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_nquery(msg, *msglen, 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));
+ if (!RRlen)
+ panic(errno, "malloc(RRlen)");
+ 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_expand() 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:
+ case T_LOC:
+#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;
+
+ case T_PX:
+ /* grab preference */
+ bcopy(cp, newcp, INT16SZ);
+ cp += INT16SZ;
+ newcp += INT16SZ;
+
+ /* get first 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;
+ newcp += n_new;
+ newlen += n_new+INT16SZ;
+ rembuflen -= n_new+INT16SZ;
+ dlen = n_new+INT16SZ;
+ 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;
+ PUTSHORT(dlen, tempcp);
+ 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_nquery(msg, *msglen, ddt);
+#endif
+ free((char *)RRlen);
+ return (n);
+badend:
+ dprintf(2, (ddt, "encountered problems: UPDATE_MSG\n"));
+ free((char *)RRlen);
+ return (-1);
+}
+#endif /*BAD_IDEA*/
+
+#endif /*VALIDATE*/
diff --git a/usr.sbin/named/named/pathnames.h b/usr.sbin/named/named/pathnames.h
new file mode 100644
index 00000000000..2d632068733
--- /dev/null
+++ b/usr.sbin/named/named/pathnames.h
@@ -0,0 +1,124 @@
+/* $NetBSD: pathnames.h,v 1.1 1996/02/02 15:29:16 mrg Exp $ */
+
+/*
+ * @(#)pathnames.h 5.4 (Berkeley) 6/1/90
+ * $Id: pathnames.h,v 8.1 1994/12/15 06:24:14 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/named/storage.c b/usr.sbin/named/named/storage.c
new file mode 100644
index 00000000000..925e6f82d3a
--- /dev/null
+++ b/usr.sbin/named/named/storage.c
@@ -0,0 +1,206 @@
+/* $NetBSD: storage.c,v 1.1 1996/02/02 15:29:21 mrg Exp $ */
+
+/*
+ * ++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"
+extern void panic __P((int, const char *));
+
+#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 8.1 1994/12/15 06:24:14 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 ) {
+ panic(errno, "rt_malloc: malloc failure");
+ } 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 )
+ panic(-1, "rt_free: corrupt magic");
+ }
+ mp->mdb_len = 0; /* successful free */
+ goto ok;
+ }
+ panic(-1, "rt_free: bad pointer");
+ 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/named/tree.c b/usr.sbin/named/named/tree.c
new file mode 100644
index 00000000000..71835f69a43
--- /dev/null
+++ b/usr.sbin/named/named/tree.c
@@ -0,0 +1,572 @@
+/* $NetBSD: tree.c,v 1.1 1996/02/02 15:29:24 mrg Exp $ */
+
+/* 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/named/tree.h b/usr.sbin/named/named/tree.h
new file mode 100644
index 00000000000..059781a2597
--- /dev/null
+++ b/usr.sbin/named/named/tree.h
@@ -0,0 +1,50 @@
+/* $NetBSD: tree.h,v 1.1 1996/02/02 15:29:28 mrg Exp $ */
+
+/* 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 8.1 1994/12/15 06:24:14 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/named/version.c b/usr.sbin/named/named/version.c
new file mode 100644
index 00000000000..6304fba7571
--- /dev/null
+++ b/usr.sbin/named/named/version.c
@@ -0,0 +1,90 @@
+/* $NetBSD: version.c,v 1.1 1996/02/02 15:29:32 mrg Exp $ */
+
+/*
+ * @(#)Version.c 4.9 (Berkeley) 7/21/90
+ * $Id: Version.c,v 8.1 1994/12/15 06:24:14 vixie Exp
+ */
+
+#ifndef lint
+char sccsid[] = "@(#)named 4.9.3-P1";
+char rcsid[] = "$Id: Version.c,v 8.1 1994/12/15 06:24:14 vixie Exp ";
+#endif /* not lint */
+
+char Version[] = "named 4.9.3-P1";
+
+#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/ndc/Makefile b/usr.sbin/named/ndc/Makefile
new file mode 100644
index 00000000000..4054be7b725
--- /dev/null
+++ b/usr.sbin/named/ndc/Makefile
@@ -0,0 +1,25 @@
+# $NetBSD: Makefile,v 1.1 1996/02/02 15:29:48 mrg Exp $
+# from: $Id: Makefile,v 8.1 1994/12/15 06:23:47 vixie Exp
+
+.PATH: ${.CURDIR}/../named \
+ ${.CURDIR}/../man
+
+all: ndc ndc.cat8
+
+CLEANFILES+= ndc
+MAN= ndc.8
+
+realinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ndc ${DESTDIR}${BINDIR}/ndc
+
+ndc: ndc.sh Makefile ${.CURDIR}/../Makefile.inc
+ sed -e "s|%PIDDIR%|${PIDDIR}|" \
+ -e "s|%PS%|${PS}|" \
+ -e "s|%DESTSBIN%|${BINDIR}|" \
+ -e "s|%IOT%|${IOT}|" \
+ < ${.CURDIR}/ndc.sh > ndc
+ chmod +x ndc
+
+.include <bsd.prog.mk>
+.include "../../Makefile.inc"
diff --git a/usr.sbin/named/ndc/ndc.sh b/usr.sbin/named/ndc/ndc.sh
new file mode 100644
index 00000000000..402de9dc0c0
--- /dev/null
+++ b/usr.sbin/named/ndc/ndc.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+#
+# $NetBSD: ndc.sh,v 1.1 1996/02/02 15:29:52 mrg Exp $
+
+USAGE='echo \
+ "usage: $0 \
+ (status|dumpdb|reload|stats|trace|notrace|querylog|start|stop|restart) \
+ ... \
+ "; exit 1'
+
+PATH=%DESTSBIN%:/bin:/usr/bin:/usr/ucb:$PATH
+PIDFILE=%PIDDIR%/named.pid
+
+if [ -f $PIDFILE ]
+then
+ PID=`cat $PIDFILE`
+ PS=`%PS% $PID | tail -1 | grep $PID`
+ RUNNING=1
+ [ `echo $PS | wc -w` -ne 0 ] || {
+ PS="named (pid $PID?) not running"
+ RUNNING=0
+ }
+else
+ PS="named (no pid file) not running"
+ RUNNING=0
+fi
+
+for ARG
+do
+ case $ARG in
+ start|stop|restart)
+ ;;
+ *)
+ [ $RUNNING -eq 0 ] && {
+ echo $PS
+ exit 1
+ }
+ esac
+
+ case $ARG in
+ status) echo "$PS";;
+ dumpdb) kill -INT $PID && echo Dumping Database;;
+ reload) kill -HUP $PID && echo Reloading Database;;
+ stats) kill -%IOT% $PID && echo Dumping Statistics;;
+ trace) kill -USR1 $PID && echo Trace Level Incremented;;
+ notrace) kill -USR2 $PID && echo Tracing Cleared;;
+ querylog|qrylog) kill -WINCH $PID && echo Query Logging Toggled;;
+ start)
+ [ $RUNNING -eq 1 ] && {
+ echo "$0: start: named (pid $PID) already running"
+ continue
+ }
+ rm -f $PIDFILE
+ named && {
+ sleep 5
+ echo Name Server Started
+ }
+ ;;
+ stop)
+ [ $RUNNING -eq 0 ] && {
+ echo "$0: stop: named not running"
+ continue
+ }
+ kill $PID && {
+ sleep 5
+ rm -f $PIDFILE
+ echo Name Server Stopped
+ }
+ ;;
+ restart)
+ [ $RUNNING -eq 1 ] && {
+ kill $PID && sleep 5
+ }
+ rm -f $PIDFILE
+ named && {
+ sleep 5
+ echo Name Server Restarted
+ }
+ ;;
+ *) eval "$USAGE";;
+ esac
+done
+test -z "$ARG" && eval "$USAGE"
+
+exit 0
diff --git a/usr.sbin/named/nslookup/Makefile b/usr.sbin/named/nslookup/Makefile
new file mode 100644
index 00000000000..74b34bb34a0
--- /dev/null
+++ b/usr.sbin/named/nslookup/Makefile
@@ -0,0 +1,22 @@
+# $NetBSD: Makefile,v 1.1 1996/02/02 15:29:56 mrg Exp $
+# from: $Id: Makefile,v 8.1 1994/12/15 06:23:48 vixie Exp
+
+.PATH: ${.CURDIR}/../nslookup \
+ ${.CURDIR}/../man
+
+PROG= nslookup
+SRCS= main.c getinfo.c debug.c send.c skip.c list.c subr.c commands.l
+CFLAGS+= ${INCLUDE}
+DPADD= ${LIBL}
+LDADD= -ll
+CLEANFILES+= commands.c lex.yy.c lex.yy.o
+MAN= nslookup.8
+
+beforeinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${.CURDIR}/../nslookup/nslookup.help \
+ ${DESTDIR}/usr/share/misc/nslookup.help
+
+.include <bsd.prog.mk>
+.include "../Makefile.inc"
+.include "../../Makefile.inc"
diff --git a/usr.sbin/named/nslookup/commands.l b/usr.sbin/named/nslookup/commands.l
new file mode 100644
index 00000000000..748f02db40d
--- /dev/null
+++ b/usr.sbin/named/nslookup/commands.l
@@ -0,0 +1,221 @@
+%{
+
+/* $NetBSD: commands.l,v 1.1 1996/02/02 15:29:58 mrg Exp $ */
+
+/*
+ * ++Copyright++ 1985
+ * -
+ * Copyright (c) 1985
+ * 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
+static char sccsid[] = "@(#)commands.l 5.13 (Berkeley) 7/24/90";
+#endif /* not lint */
+
+/*
+ *******************************************************************************
+ *
+ * commands.l
+ *
+ * Andrew Cherenson CS298-26 Fall 1985
+ *
+ * Lex input file for the nslookup program command interpreter.
+ * When a sequence is recognized, the associated action
+ * routine is called. The action routine may need to
+ * parse the string for additional information.
+ *
+ * Recognized commands: (identifiers are shown in uppercase)
+ *
+ * server NAME - set default server to NAME, using default server
+ * lserver NAME - set default server to NAME, using initial server
+ * finger [NAME] - finger the optional NAME
+ * exit - exit the program
+ * root - set default server to the root
+ * ls NAME - list the domain NAME
+ * view FILE - sorts and view the file with more
+ * set OPTION - set an option
+ * help - print help information
+ * ? - print help information
+ * NAME - print info about the host/domain NAME
+ * using default server.
+ * NAME1 NAME2 - as above, but use NAME2 as server
+ *
+ *
+ * yylex Results:
+ * 0 upon end-of-file.
+ * 1 after each command.
+ *
+ *******************************************************************************
+ */
+
+#include "res.h"
+extern char rootServerName[];
+extern void PrintHelp();
+
+%}
+WS [ \t]
+FLET [A-Za-z0-9.*\\]
+LET [A-Za-z0-9.*]
+NAME [A-Za-z0-9.*=_/-]
+%%
+^{WS}*server{WS}+{LET}{NAME}*{WS}*$ {
+ /*
+ * 0 == use current server to find
+ * the new one.
+ * 1 == use original server to find
+ * the new one.
+ */
+ SetDefaultServer(yytext, 0);
+ return(1);
+ }
+^{WS}*lserver{WS}+{LET}{NAME}*{WS}*$ {
+ SetDefaultServer(yytext, 1);
+ return(1);
+ }
+^{WS}*exit{WS}*$ {
+ return(0);
+ }
+^{WS}*root{WS}*$ {
+ SetDefaultServer(rootServerName, 1);
+ return(1);
+ }
+^{WS}*finger({WS}+{LET}{NAME}*)?{WS}+>>?{WS}*{NAME}+{WS}*$ {
+ /*
+ * 2nd arg.
+ * 0 == output to stdout
+ * 1 == output to file
+ */
+ Finger(yytext, 1);
+ return(1);
+ }
+^{WS}*finger({WS}+{LET}{NAME}*)?{WS}*$ {
+ Finger(yytext, 0);
+ return(1);
+ }
+^{WS}*view{WS}+{NAME}+{WS}*$ {
+ ViewList(yytext);
+ return(1);
+ }
+^{WS}*ls{WS}+(("-a"|"-d"|"-h"|"-m"|"-s"){WS}+)?{LET}{NAME}*{WS}+>>?{WS}+{NAME}+{WS}*$ {
+ /*
+ * 2nd arg.
+ * 0 == output to stdout
+ * 1 == output to file
+ */
+ ListHosts(yytext, 1);
+ return(1);
+ }
+^{WS}*ls{WS}+(("-a"|"-d"|"-h"|"-m"|"-s"){WS}+)?{LET}{NAME}*{WS}*$ {
+ ListHosts(yytext, 0);
+ return(1);
+ }
+^{WS}*ls{WS}+-t{WS}+({LET}{NAME}*{WS}+)?{LET}{NAME}*{WS}+>>?{WS}+{NAME}+{WS}*$ {
+ /*
+ * 2nd arg.
+ * 0 == output to stdout
+ * 1 == output to file
+ */
+ ListHostsByType(yytext, 1);
+ return(1);
+ }
+^{WS}*ls{WS}+-t{WS}+({LET}{NAME}*{WS}+)?{LET}{NAME}*{WS}*$ {
+ ListHostsByType(yytext, 0);
+ return(1);
+ }
+^{WS}*set{WS}+{NAME}+{WS}*$ {
+ SetOption(yytext);
+ return(1);
+ }
+^{WS}*help{WS}*$ {
+ PrintHelp();
+ return(1);
+ }
+^{WS}*"?"{WS}*$ {
+ extern void PrintHelp();
+
+ PrintHelp();
+ return(1);
+ }
+^{WS}*{FLET}{NAME}*{WS}+>>?{WS}*{NAME}+{WS}*$ {
+ /*
+ * 0 == output to stdout
+ * 1 == output to file
+ */
+ LookupHost(yytext, 1);
+ return(1);
+ }
+^{WS}*{FLET}{NAME}*{WS}*$ {
+ LookupHost(yytext, 0);
+ return(1);
+ }
+^{WS}*{FLET}{NAME}*{WS}+{LET}{NAME}*{WS}+>>?{WS}*{NAME}+{WS}*$ {
+ /*
+ * 0 == output to stdout
+ * 1 == output to file
+ */
+ LookupHostWithServer(yytext, 1);
+ return(1);
+ }
+^{WS}*{FLET}{NAME}*{WS}+{LET}{NAME}*{WS}*$ {
+ LookupHostWithServer(yytext, 0);
+ return(1);
+ }
+^{WS}*\n {
+ return(1);
+ }
+^.*\n {
+ printf("Unrecognized command: %s",
+ yytext);
+ return(1);
+ }
+\n { ; }
+%%
diff --git a/usr.sbin/named/nslookup/debug.c b/usr.sbin/named/nslookup/debug.c
new file mode 100644
index 00000000000..5dbebe1f6d3
--- /dev/null
+++ b/usr.sbin/named/nslookup/debug.c
@@ -0,0 +1,547 @@
+/* $NetBSD: debug.c,v 1.1 1996/02/02 15:30:01 mrg Exp $ */
+
+/*
+ * ++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--
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)debug.c 5.26 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: debug.c,v 8.2 1995/06/29 09:26:34 vixie Exp ";
+#endif /* not lint */
+
+/*
+ *******************************************************************************
+ *
+ * debug.c --
+ *
+ * Routines to print out packets received from a name server query.
+ *
+ * Modified version of 4.3BSD BIND res_debug.c 5.30 6/27/90
+ *
+ *******************************************************************************
+ */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <netdb.h>
+#include <stdio.h>
+#include "res.h"
+#include "conf/portability.h"
+
+/*
+ * Imported from res_debug.c
+ */
+extern char *_res_resultcodes[];
+extern char *_res_opcodes[];
+
+/*
+ * Used to highlight the start of a record when printing it.
+ */
+#define INDENT " -> "
+
+
+
+/*
+ * Print the contents of a query.
+ * This is intended to be primarily a debugging routine.
+ */
+
+Print_query(msg, eom, printHeader)
+ char *msg, *eom;
+ int printHeader;
+{
+ Fprint_query(msg, eom, printHeader,stdout);
+}
+
+Fprint_query(msg, eom, printHeader,file)
+ u_char *msg, *eom;
+ int printHeader;
+ FILE *file;
+{
+ register u_char *cp;
+ register HEADER *hp;
+ register int n;
+ short class;
+ short type;
+
+ /*
+ * Print header fields.
+ */
+ hp = (HEADER *)msg;
+ cp = msg + HFIXEDSZ;
+ if (printHeader || (_res.options & RES_DEBUG2)) {
+ fprintf(file," HEADER:\n");
+ fprintf(file,"\topcode = %s", _res_opcodes[hp->opcode]);
+ fprintf(file,", id = %d", ntohs(hp->id));
+ fprintf(file,", rcode = %s\n", _res_resultcodes[hp->rcode]);
+ fprintf(file,"\theader flags: ");
+ if (hp->qr) {
+ fprintf(file," response");
+ } else {
+ fprintf(file," query");
+ }
+ if (hp->aa)
+ fprintf(file,", auth. answer");
+ if (hp->tc)
+ fprintf(file,", truncation");
+ if (hp->rd)
+ fprintf(file,", want recursion");
+ if (hp->ra)
+ fprintf(file,", recursion avail.");
+ fprintf(file,"\n\tquestions = %d", ntohs(hp->qdcount));
+ fprintf(file,", answers = %d", ntohs(hp->ancount));
+ fprintf(file,", authority records = %d", ntohs(hp->nscount));
+ fprintf(file,", additional = %d\n\n", ntohs(hp->arcount));
+ }
+
+ /*
+ * Print question records.
+ */
+ if (n = ntohs(hp->qdcount)) {
+ fprintf(file," QUESTIONS:\n");
+ while (--n >= 0) {
+ fprintf(file,"\t");
+ cp = Print_cdname(cp, msg, eom, file);
+ if (cp == NULL)
+ return;
+ type = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ class = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ fprintf(file,", type = %s", p_type(type));
+ fprintf(file,", class = %s\n", p_class(class));
+ }
+ }
+ /*
+ * Print authoritative answer records
+ */
+ if (n = ntohs(hp->ancount)) {
+ fprintf(file," ANSWERS:\n");
+ while (--n >= 0) {
+ fprintf(file, INDENT);
+ cp = Print_rr(cp, msg, eom, file);
+ if (cp == NULL)
+ return;
+ }
+ }
+ /*
+ * print name server records
+ */
+ if (n = ntohs(hp->nscount)) {
+ fprintf(file," AUTHORITY RECORDS:\n");
+ while (--n >= 0) {
+ fprintf(file, INDENT);
+ cp = Print_rr(cp, msg, eom, file);
+ if (cp == NULL)
+ return;
+ }
+ }
+ /*
+ * print additional records
+ */
+ if (n = ntohs(hp->arcount)) {
+ fprintf(file," ADDITIONAL RECORDS:\n");
+ while (--n >= 0) {
+ fprintf(file, INDENT);
+ cp = Print_rr(cp, msg, eom, file);
+ if (cp == NULL)
+ return;
+ }
+ }
+ fprintf(file,"\n------------\n");
+}
+
+
+u_char *
+Print_cdname_sub(cp, msg, eom, file, format)
+ u_char *cp, *msg, *eom;
+ FILE *file;
+ int format;
+{
+ int n;
+ char name[MAXDNAME];
+
+ n = dn_expand(msg, eom, cp, name, sizeof name);
+ if (n < 0)
+ return (NULL);
+ if (name[0] == '\0') {
+ (void) strcpy(name, "(root)");
+ }
+ if (format) {
+ fprintf(file, "%-30s", name);
+ } else {
+ fputs(name, file);
+ }
+ return (cp + n);
+}
+
+u_char *
+Print_cdname(cp, msg, eom, file)
+ u_char *cp, *msg, *eom;
+ FILE *file;
+{
+ return (Print_cdname_sub(cp, msg, eom, file, 0));
+}
+
+u_char *
+Print_cdname2(cp, msg, eom, file)
+ u_char *cp, *msg, *eom;
+ FILE *file;
+{
+ return (Print_cdname_sub(cp, msg, eom, file, 1));
+}
+
+/*
+ * Print resource record fields in human readable form.
+ */
+u_char *
+Print_rr(cp, msg, eom, file)
+ u_char *cp, *msg, *eom;
+ FILE *file;
+{
+ int type, class, dlen, n, c;
+ u_int32_t rrttl, ttl;
+ struct in_addr inaddr;
+ u_char *cp1, *cp2;
+ int debug;
+
+ if ((cp = Print_cdname(cp, msg, eom, file)) == NULL) {
+ fprintf(file, "(name truncated?)\n");
+ return (NULL); /* compression error */
+ }
+
+ type = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ class = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ rrttl = _getlong((u_char*)cp);
+ cp += INT32SZ;
+ dlen = _getshort((u_char*)cp);
+ cp += INT16SZ;
+
+ debug = _res.options & (RES_DEBUG|RES_DEBUG2);
+ if (debug) {
+ if (_res.options & RES_DEBUG2) {
+ fprintf(file,"\n\ttype = %s, class = %s, dlen = %d",
+ p_type(type), p_class(class), dlen);
+ }
+ if (type == T_SOA) {
+ fprintf(file,"\n\tttl = %lu (%s)", rrttl, p_time(rrttl));
+ }
+ (void) putc('\n', file);
+ }
+
+ cp1 = cp;
+
+ /*
+ * Print type specific data, if appropriate
+ */
+ switch (type) {
+ case T_A:
+ switch (class) {
+ case C_IN:
+ case C_HS:
+ bcopy(cp, (char *)&inaddr, INADDRSZ);
+ if (dlen == 4) {
+ fprintf(file,"\tinternet address = %s\n",
+ inet_ntoa(inaddr));
+ cp += dlen;
+ } else if (dlen == 7) {
+ fprintf(file,"\tinternet address = %s",
+ inet_ntoa(inaddr));
+ fprintf(file,", protocol = %d", cp[4]);
+ fprintf(file,", port = %d\n",
+ (cp[5] << 8) + cp[6]);
+ cp += dlen;
+ }
+ break;
+ default:
+ fprintf(file,"\taddress, class = %d, len = %d\n",
+ class, dlen);
+ cp += dlen;
+ }
+ break;
+
+ case T_CNAME:
+ fprintf(file,"\tcanonical name = ");
+ goto doname;
+
+ case T_MG:
+ fprintf(file,"\tmail group member = ");
+ goto doname;
+ case T_MB:
+ fprintf(file,"\tmail box = ");
+ goto doname;
+ case T_MR:
+ fprintf(file,"\tmailbox rename = ");
+ goto doname;
+ case T_MX:
+ fprintf(file,"\tpreference = %u",_getshort((u_char*)cp));
+ cp += INT16SZ;
+ fprintf(file,", mail exchanger = ");
+ goto doname;
+ case T_PX:
+ fprintf(file,"\tpreference = %u",_getshort((u_char*)cp));
+ cp += INT16SZ;
+ fprintf(file,", RFC 822 = ");
+ cp = Print_cdname(cp, msg, eom, file);
+ fprintf(file,"\nX.400 = ");
+ cp = Print_cdname(cp, msg, eom, file);
+ (void) putc('\n', file);
+ break;
+ case T_RT:
+ fprintf(file,"\tpreference = %u",_getshort((u_char*)cp));
+ cp += INT16SZ;
+ fprintf(file,", router = ");
+ goto doname;
+ case T_AFSDB:
+ fprintf(file,"\tsubtype = %d",_getshort((u_char*)cp));
+ cp += INT16SZ;
+ fprintf(file,", DCE/AFS server = ");
+ goto doname;
+ case T_NS:
+ fprintf(file,"\tnameserver = ");
+ goto doname;
+ case T_PTR:
+ fprintf(file,"\tname = ");
+doname:
+ cp = Print_cdname(cp, msg, eom, file);
+ (void) putc('\n', file);
+ break;
+
+ case T_HINFO:
+ cp2 = cp + dlen;
+ if (n = *cp++) {
+ fprintf(file,"\tCPU = %.*s", n, cp);
+ cp += n;
+ }
+ if ((cp < cp2) && (n = *cp++)) {
+ fprintf(file,"\tOS = %.*s\n", n, cp);
+ cp += n;
+ } else fprintf(file, "\n*** Warning *** OS-type missing\n");
+ break;
+
+ case T_ISDN:
+ cp2 = cp + dlen;
+ if (n = *cp++) {
+ fprintf(file,"\tISDN = \"%.*s", n, cp);
+ cp += n;
+ }
+ if ((cp < cp2) && (n = *cp++)) {
+ fprintf(file,"-%.*s\"\n", n, cp);
+ cp += n;
+ } else fprintf(file,"\"\n");
+ break;
+
+
+ case T_SOA:
+ if (!debug)
+ (void) putc('\n', file);
+ fprintf(file,"\torigin = ");
+ cp = Print_cdname(cp, msg, eom, file);
+ fprintf(file,"\n\tmail addr = ");
+ cp = Print_cdname(cp, msg, eom, file);
+ fprintf(file,"\n\tserial = %lu", _getlong((u_char*)cp));
+ cp += INT32SZ;
+ ttl = _getlong((u_char*)cp);
+ fprintf(file,"\n\trefresh = %lu (%s)", ttl, p_time(ttl));
+ cp += INT32SZ;
+ ttl = _getlong((u_char*)cp);
+ fprintf(file,"\n\tretry = %lu (%s)", ttl, p_time(ttl));
+ cp += INT32SZ;
+ ttl = _getlong((u_char*)cp);
+ fprintf(file,"\n\texpire = %lu (%s)", ttl, p_time(ttl));
+ cp += INT32SZ;
+ ttl = _getlong((u_char*)cp);
+ fprintf(file,
+ "\n\tminimum ttl = %lu (%s)\n", ttl, p_time(ttl));
+ cp += INT32SZ;
+ break;
+
+ case T_MINFO:
+ if (!debug)
+ (void) putc('\n', file);
+ fprintf(file,"\trequests = ");
+ cp = Print_cdname(cp, msg, eom, file);
+ fprintf(file,"\n\terrors = ");
+ cp = Print_cdname(cp, msg, eom, file);
+ (void) putc('\n', file);
+ break;
+ case T_RP:
+ if (!debug)
+ (void) putc('\n', file);
+ fprintf(file,"\tmailbox = ");
+ cp = Print_cdname(cp, msg, eom, file);
+ fprintf(file,"\n\ttext = ");
+ cp = Print_cdname(cp, msg, eom, file);
+ (void) putc('\n', file);
+ break;
+
+ case T_TXT:
+ (void) fputs("\ttext = \"", file);
+ cp2 = cp1 + dlen;
+ while (cp < cp2) {
+ if (n = (unsigned char) *cp++) {
+ for (c = n; c > 0 && cp < cp2; c--)
+ if ((*cp == '\n') || (*cp == '"')) {
+ (void) putc('\\', file);
+ (void) putc(*cp++, file);
+ } else
+ (void) putc(*cp++, file);
+ }
+ }
+ (void) fputs("\"\n", file);
+ break;
+
+ case T_X25:
+ (void) fputs("\tX25 = \"", file);
+ cp2 = cp1 + dlen;
+ while (cp < cp2) {
+ if (n = (unsigned char) *cp++) {
+ for (c = n; c > 0 && cp < cp2; c--)
+ if (*cp == '\n') {
+ (void) putc('\\', file);
+ (void) putc(*cp++, file);
+ } else
+ (void) putc(*cp++, file);
+ }
+ }
+ (void) fputs("\"\n", file);
+ break;
+
+ case T_NSAP:
+ fprintf(file, "\tnsap = %s\n", inet_nsap_ntoa(dlen, cp, NULL));
+ cp += dlen;
+ break;
+
+ case T_UINFO:
+ fprintf(file,"\tuser info = %s\n", cp);
+ cp += dlen;
+ break;
+
+ case T_UID:
+ case T_GID:
+ if (dlen == 4) {
+ fprintf(file,"\t%cid = %u\n",type == T_UID ? 'u' : 'g',
+ _getlong((u_char*)cp));
+ cp += INT32SZ;
+ } else {
+ fprintf(file,"\t%cid of length %d?\n",
+ type == T_UID ? 'u' : 'g', dlen);
+ cp += dlen;
+ }
+ break;
+
+ case T_WKS: {
+ struct protoent *protoPtr;
+
+ if (dlen < INT32SZ + 1)
+ break;
+ if (!debug)
+ (void) putc('\n', file);
+ bcopy(cp, (char *)&inaddr, INADDRSZ);
+ cp += INT32SZ;
+ if ((protoPtr = getprotobynumber(*cp)) != NULL) {
+ fprintf(file,"\tinet address = %s, protocol = %s\n\t",
+ inet_ntoa(inaddr), protoPtr->p_name);
+ } else {
+ fprintf(file,"\tinet address = %s, protocol = %d\n\t",
+ inet_ntoa(inaddr), *cp);
+ }
+ cp++;
+ n = 0;
+ while (cp < cp1 + dlen) {
+ c = *cp++;
+ do {
+ struct servent *s;
+
+ if (c & 0200) {
+ s = getservbyport((int)htons(n),
+ protoPtr ? protoPtr->p_name : NULL);
+ if (s != NULL) {
+ fprintf(file," %s", s->s_name);
+ } else {
+ fprintf(file," #%d", n);
+ }
+ }
+ c <<= 1;
+ } while (++n & 07);
+ }
+ putc('\n',file);
+ }
+ break;
+
+ case T_NULL:
+ fprintf(file, "\tNULL (dlen %d)\n", dlen);
+ cp += dlen;
+ break;
+
+ default:
+ fprintf(file,"\t??? unknown type %d ???\n", type);
+ cp += dlen;
+ }
+ if (_res.options & RES_DEBUG && type != T_SOA) {
+ fprintf(file,"\tttl = %lu (%s)\n", rrttl, p_time(rrttl));
+ }
+ if (cp != cp1 + dlen) {
+ fprintf(file,
+ "\n*** Error: record size incorrect (%d != %d)\n\n",
+ cp - cp1, dlen);
+ cp = NULL;
+ }
+ return (cp);
+}
diff --git a/usr.sbin/named/nslookup/getinfo.c b/usr.sbin/named/nslookup/getinfo.c
new file mode 100644
index 00000000000..a84bb2e1c54
--- /dev/null
+++ b/usr.sbin/named/nslookup/getinfo.c
@@ -0,0 +1,845 @@
+/* $NetBSD: getinfo.c,v 1.1 1996/02/02 15:30:05 mrg Exp $ */
+
+/*
+ * ++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--
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)getinfo.c 5.26 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: getinfo.c,v 8.3 1995/12/29 07:16:27 vixie Exp ";
+#endif /* not lint */
+
+/*
+ ******************************************************************************
+ *
+ * getinfo.c --
+ *
+ * Routines to create requests to name servers
+ * and interpret the answers.
+ *
+ * Adapted from 4.3BSD BIND gethostnamadr.c
+ *
+ ******************************************************************************
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "res.h"
+#include "conf/portability.h"
+
+extern char *_res_resultcodes[];
+extern char *res_skip();
+
+#define MAXALIASES 35
+#define MAXADDRS 35
+#define MAXDOMAINS 35
+#define MAXSERVERS 10
+
+static char *addr_list[MAXADDRS + 1];
+
+static char *host_aliases[MAXALIASES];
+static int host_aliases_len[MAXALIASES];
+static u_char hostbuf[BUFSIZ+1];
+
+typedef struct {
+ char *name;
+ char *domain[MAXDOMAINS];
+ int numDomains;
+ char *address[MAXADDRS];
+ int numAddresses;
+} ServerTable;
+
+ServerTable server[MAXSERVERS];
+
+typedef union {
+ HEADER qb1;
+ u_char qb2[PACKETSZ*2];
+} querybuf;
+
+typedef union {
+ int32_t al;
+ char ac;
+} align;
+
+#define GetShort(cp) _getshort(cp); cp += INT16SZ;
+
+
+/*
+ ******************************************************************************
+ *
+ * GetAnswer --
+ *
+ * Interprets an answer packet and retrieves the following
+ * information:
+ *
+ * Results:
+ * SUCCESS the info was retrieved.
+ * NO_INFO the packet did not contain an answer.
+ * NONAUTH non-authoritative information was found.
+ * ERROR the answer was malformed.
+ * Other errors returned in the packet header.
+ *
+ ******************************************************************************
+ */
+
+static int
+GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer)
+ struct in_addr *nsAddrPtr;
+ char *msg;
+ int queryType;
+ int msglen;
+ Boolean iquery;
+ register HostInfo *hostPtr;
+ Boolean isServer;
+{
+ register HEADER *headerPtr;
+ register u_char *cp;
+ querybuf answer;
+ char **aliasPtr;
+ u_char *eom, *bp;
+ char **addrPtr;
+ char *namePtr;
+ char *dnamePtr;
+ int type, class;
+ int qdcount, ancount, arcount, nscount, buflen;
+ int origClass;
+ int numAliases = 0;
+ int numAddresses = 0;
+ int n, i, j;
+ int len;
+ int dlen;
+ int status;
+ int numServers;
+ Boolean haveAnswer;
+ Boolean printedAnswers = FALSE;
+
+
+ /*
+ * If the hostPtr was used before, free up the calloc'd areas.
+ */
+ FreeHostInfoPtr(hostPtr);
+
+ status = SendRequest(nsAddrPtr, msg, msglen, (char *) &answer,
+ sizeof(answer), &n);
+
+ if (status != SUCCESS) {
+ if (_res.options & RES_DEBUG2)
+ printf("SendRequest failed\n");
+ return (status);
+ }
+ eom = (u_char *) &answer + n;
+
+ headerPtr = (HEADER *) &answer;
+
+ if (headerPtr->rcode != NOERROR) {
+ return (headerPtr->rcode);
+ }
+
+ qdcount = ntohs(headerPtr->qdcount);
+ ancount = ntohs(headerPtr->ancount);
+ arcount = ntohs(headerPtr->arcount);
+ nscount = ntohs(headerPtr->nscount);
+
+ /*
+ * If there are no answer, n.s. or additional records
+ * then return with an error.
+ */
+ if (ancount == 0 && nscount == 0 && arcount == 0) {
+ return (NO_INFO);
+ }
+
+
+ bp = hostbuf;
+ buflen = sizeof(hostbuf);
+ cp = (u_char *) &answer + HFIXEDSZ;
+
+ /* Skip over question section. */
+ while (qdcount-- > 0) {
+ cp += dn_skipname(cp, eom) + QFIXEDSZ;
+ }
+
+ aliasPtr = host_aliases;
+ addrPtr = addr_list;
+ haveAnswer = FALSE;
+
+ /*
+ * Scan through the answer resource records.
+ * Answers for address query types are saved.
+ * Other query type answers are just printed.
+ */
+ if (ancount != 0) {
+ if (!isServer && !headerPtr->aa) {
+ printf("Non-authoritative answer:\n");
+ }
+
+ if (queryType != T_A && !(iquery && queryType == T_PTR)) {
+ while (--ancount >= 0 && cp < eom) {
+ if ((cp = (u_char *)Print_rr(cp,
+ (char *)&answer, eom, stdout)) == NULL) {
+ return(ERROR);
+ }
+ }
+ printedAnswers = TRUE;
+ } else {
+ while (--ancount >= 0 && cp < eom) {
+ n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
+ if (n < 0) {
+ return(ERROR);
+ }
+ cp += n;
+ type = GetShort(cp);
+ class = GetShort(cp);
+ cp += INT32SZ; /* skip TTL */
+ dlen = GetShort(cp);
+ if (type == T_CNAME) {
+ /*
+ * Found an alias.
+ */
+ cp += dlen;
+ if (aliasPtr >= &host_aliases[MAXALIASES-1]) {
+ continue;
+ }
+ *aliasPtr++ = (char *)bp;
+ n = strlen((char *)bp) + 1;
+ host_aliases_len[numAliases] = n;
+ numAliases++;
+ bp += n;
+ buflen -= n;
+ continue;
+ } else if (type == T_PTR) {
+ /*
+ * Found a "pointer" to the real name.
+ */
+ n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
+ if (n < 0) {
+ cp += n;
+ continue;
+ }
+ cp += n;
+ len = strlen((char *)bp) + 1;
+ hostPtr->name = Calloc(1, len);
+ bcopy(bp, hostPtr->name, len);
+ haveAnswer = TRUE;
+ break;
+ } else if (type != T_A) {
+ cp += dlen;
+ continue;
+ }
+ if (haveAnswer) {
+ /*
+ * If we've already got 1 address, we aren't interested
+ * in addresses with a different length or class.
+ */
+ if (dlen != hostPtr->addrLen) {
+ cp += dlen;
+ continue;
+ }
+ if (class != origClass) {
+ cp += dlen;
+ continue;
+ }
+ } else {
+ /*
+ * First address: record its length and class so we
+ * only save additonal ones with the same attributes.
+ */
+ hostPtr->addrLen = dlen;
+ origClass = class;
+ hostPtr->addrType = (class == C_IN) ? AF_INET : AF_UNSPEC;
+ len = strlen((char *)bp) + 1;
+ hostPtr->name = Calloc(1, len);
+ bcopy(bp, hostPtr->name, len);
+ }
+ bp += (((long)bp) % sizeof(align));
+
+ if (bp + dlen >= &hostbuf[sizeof(hostbuf)]) {
+ if (_res.options & RES_DEBUG) {
+ printf("Size (%d) too big\n", dlen);
+ }
+ break;
+ }
+ bcopy(cp, *addrPtr++ = (char *)bp, dlen);
+ bp +=dlen;
+ cp += dlen;
+ numAddresses++;
+ haveAnswer = TRUE;
+ }
+ }
+ }
+
+ if ((queryType == T_A || queryType == T_PTR) && haveAnswer) {
+
+ /*
+ * Go through the alias and address lists and return them
+ * in the hostPtr variable.
+ */
+
+ if (numAliases > 0) {
+ hostPtr->aliases =
+ (char **) Calloc(1 + numAliases, sizeof(char *));
+ for (i = 0; i < numAliases; i++) {
+ hostPtr->aliases[i] = Calloc(1, host_aliases_len[i]);
+ bcopy(host_aliases[i],
+ hostPtr->aliases[i],
+ host_aliases_len[i]);
+ }
+ hostPtr->aliases[i] = NULL;
+ }
+ if (numAddresses > 0) {
+ hostPtr->addrList =
+ (char **)Calloc(1+numAddresses, sizeof(char *));
+ for (i = 0; i < numAddresses; i++) {
+ hostPtr->addrList[i] = Calloc(1, hostPtr->addrLen);
+ bcopy(addr_list[i], hostPtr->addrList[i], hostPtr->addrLen);
+ }
+ hostPtr->addrList[i] = NULL;
+ }
+#ifdef verbose
+ if (headerPtr->aa || nscount == 0) {
+ hostPtr->servers = NULL;
+ return (SUCCESS);
+ }
+#else
+ hostPtr->servers = NULL;
+ return (SUCCESS);
+#endif
+ }
+
+ /*
+ * At this point, for the T_A query type, only empty answers remain.
+ * For other query types, additional information might be found
+ * in the additional resource records part.
+ */
+
+ if (!headerPtr->aa && (queryType != T_A) && (nscount > 0 || arcount > 0)) {
+ if (printedAnswers) {
+ putchar('\n');
+ }
+ printf("Authoritative answers can be found from:\n");
+ }
+
+ cp = (u_char *)res_skip((char *) &answer, 2, eom);
+
+ numServers = 0;
+ if (queryType != T_A) {
+ /*
+ * If we don't need to save the record, just print it.
+ */
+ while (--nscount >= 0 && cp < eom) {
+ if ((cp = (u_char *)Print_rr(cp,
+ (char *) &answer, eom, stdout)) == NULL) {
+ return(ERROR);
+ }
+ }
+ } else {
+ while (--nscount >= 0 && cp < eom) {
+ /*
+ * Go through the NS records and retrieve the names of hosts
+ * that serve the requested domain.
+ */
+
+ n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
+ if (n < 0) {
+ return(ERROR);
+ }
+ cp += n;
+ len = strlen((char *)bp) + 1;
+ dnamePtr = Calloc(1, len); /* domain name */
+ bcopy(bp, dnamePtr, len);
+
+ type = GetShort(cp);
+ class = GetShort(cp);
+ cp += INT32SZ; /* skip TTL */
+ dlen = GetShort(cp);
+
+ if (type != T_NS) {
+ cp += dlen;
+ } else {
+ Boolean found;
+
+ n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
+ if (n < 0) {
+ return(ERROR);
+ }
+ cp += n;
+ len = strlen((char *)bp) + 1;
+ namePtr = Calloc(1, len); /* server host name */
+ bcopy(bp, namePtr, len);
+
+ /*
+ * Store the information keyed by the server host name.
+ */
+ found = FALSE;
+ for (j = 0; j < numServers; j++) {
+ if (strcmp(namePtr, server[j].name) == 0) {
+ found = TRUE;
+ free(namePtr);
+ break;
+ }
+ }
+ if (found) {
+ server[j].numDomains++;
+ if (server[j].numDomains <= MAXDOMAINS) {
+ server[j].domain[server[j].numDomains-1] = dnamePtr;
+ }
+ } else {
+ if (numServers >= MAXSERVERS) {
+ break;
+ }
+ server[numServers].name = namePtr;
+ server[numServers].domain[0] = dnamePtr;
+ server[numServers].numDomains = 1;
+ server[numServers].numAddresses = 0;
+ numServers++;
+ }
+ }
+ }
+ }
+
+ /*
+ * Additional resource records contain addresses of servers.
+ */
+ cp = (u_char *)res_skip((char *) &answer, 3, eom);
+
+ if (queryType != T_A) {
+ /*
+ * If we don't need to save the record, just print it.
+ */
+ while (--arcount >= 0 && cp < eom) {
+ if ((cp = (u_char *)Print_rr(cp,
+ (char *) &answer, eom, stdout)) == NULL) {
+ return(ERROR);
+ }
+ }
+ } else {
+ while (--arcount >= 0 && cp < eom) {
+ n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
+ if (n < 0) {
+ break;
+ }
+ cp += n;
+ type = GetShort(cp);
+ class = GetShort(cp);
+ cp += INT32SZ; /* skip TTL */
+ dlen = GetShort(cp);
+
+ if (type != T_A) {
+ cp += dlen;
+ continue;
+ } else {
+ for (j = 0; j < numServers; j++) {
+ if (strcmp((char *)bp, server[j].name) == 0) {
+ server[j].numAddresses++;
+ if (server[j].numAddresses <= MAXADDRS) {
+ server[j].address[server[j].numAddresses-1] =
+ Calloc(1,dlen);
+ bcopy(cp,
+ server[j].address[server[j].numAddresses-1],dlen);
+ break;
+ }
+ }
+ }
+ cp += dlen;
+ }
+ }
+ }
+
+ /*
+ * If we are returning name server info, transfer it to the hostPtr.
+ */
+ if (numServers > 0) {
+ hostPtr->servers = (ServerInfo **)
+ Calloc(numServers+1, sizeof(ServerInfo *));
+
+ for (i = 0; i < numServers; i++) {
+ hostPtr->servers[i] = (ServerInfo *) Calloc(1, sizeof(ServerInfo));
+ hostPtr->servers[i]->name = server[i].name;
+
+
+ hostPtr->servers[i]->domains = (char **)
+ Calloc(server[i].numDomains+1,sizeof(char *));
+ for (j = 0; j < server[i].numDomains; j++) {
+ hostPtr->servers[i]->domains[j] = server[i].domain[j];
+ }
+ hostPtr->servers[i]->domains[j] = NULL;
+
+
+ hostPtr->servers[i]->addrList = (char **)
+ Calloc(server[i].numAddresses+1,sizeof(char *));
+ for (j = 0; j < server[i].numAddresses; j++) {
+ hostPtr->servers[i]->addrList[j] = server[i].address[j];
+ }
+ hostPtr->servers[i]->addrList[j] = NULL;
+
+ }
+ hostPtr->servers[i] = NULL;
+ }
+
+ switch (queryType) {
+ case T_A:
+ return NONAUTH;
+ case T_PTR:
+ if (iquery)
+ return NO_INFO;
+ /* fall through */
+ default:
+ return SUCCESS;
+ }
+}
+
+/*
+*******************************************************************************
+*
+* GetHostInfo --
+*
+* Retrieves host name, address and alias information
+* for a domain.
+*
+* Algorithm from res_search().
+*
+* Results:
+* ERROR - res_mkquery failed.
+* + return values from GetAnswer()
+*
+*******************************************************************************
+*/
+
+int
+GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer)
+ struct in_addr *nsAddrPtr;
+ int queryClass;
+ int queryType;
+ char *name;
+ HostInfo *hostPtr;
+ Boolean isServer;
+{
+ int n;
+ register int result;
+ register char *cp, **domain;
+ Boolean got_nodata = FALSE;
+ struct in_addr ina;
+ Boolean tried_as_is = FALSE;
+
+ /* Catch explicit addresses */
+ if ((queryType == T_A) && IsAddr(name, &ina)) {
+ hostPtr->name = Calloc(strlen(name)+3, 1);
+ (void)sprintf(hostPtr->name,"[%s]",name);
+ hostPtr->aliases = NULL;
+ hostPtr->servers = NULL;
+ hostPtr->addrType = AF_INET;
+ hostPtr->addrLen = INADDRSZ;
+ hostPtr->addrList = (char **)Calloc(2, sizeof(char *));
+ hostPtr->addrList[0] = Calloc(INT32SZ, sizeof(char));
+ bcopy((char *)&ina, hostPtr->addrList[0], INADDRSZ);
+ hostPtr->addrList[1] = NULL;
+ return(SUCCESS);
+ }
+
+ result = NXDOMAIN;
+ for (cp = name, n = 0; *cp; cp++)
+ if (*cp == '.')
+ n++;
+ if (n == 0 && (cp = hostalias(name))) {
+ printf("Aliased to \"%s\"\n\n", cp);
+ return (GetHostDomain(nsAddrPtr, queryClass, queryType,
+ cp, (char *)NULL, hostPtr, isServer));
+ }
+
+ /*
+ * If there are dots in the name already, let's just give it a try
+ * 'as is'. The threshold can be set with the "ndots" option.
+ */
+ if (n >= (int)_res.ndots) {
+ result = GetHostDomain(nsAddrPtr, queryClass, queryType,
+ name, (char *)NULL, hostPtr, isServer);
+ if (result == SUCCESS)
+ return (result);
+ if (result == NO_INFO)
+ got_nodata++;
+ tried_as_is++;
+ }
+
+ /*
+ * We do at least one level of search if
+ * - there is no dot and RES_DEFNAME is set, or
+ * - there is at least one dot, there is no trailing dot,
+ * and RES_DNSRCH is set.
+ */
+ if ((n == 0 && _res.options & RES_DEFNAMES) ||
+ (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
+ for (domain = _res.dnsrch; *domain; domain++) {
+ result = GetHostDomain(nsAddrPtr, queryClass, queryType,
+ name, *domain, hostPtr, isServer);
+ /*
+ * If no server present, give up.
+ * If name isn't found in this domain,
+ * keep trying higher domains in the search list
+ * (if that's enabled).
+ * On a NO_INFO error, keep trying, otherwise
+ * a wildcard entry of another type could keep us
+ * from finding this entry higher in the domain.
+ * If we get some other error (negative answer or
+ * server failure), then stop searching up,
+ * but try the input name below in case it's fully-qualified.
+ */
+ if (result == SUCCESS || result == NO_RESPONSE)
+ return result;
+ if (result == NO_INFO)
+ got_nodata++;
+ if ((result != NXDOMAIN && result != NO_INFO) ||
+ (_res.options & RES_DNSRCH) == 0)
+ break;
+ }
+ /* if we have not already tried the name "as is", do that now.
+ * note that we do this regardless of how many dots were in the
+ * name or whether it ends with a dot.
+ */
+ if (!tried_as_is &&
+ (result = GetHostDomain(nsAddrPtr, queryClass, queryType,
+ name, (char *)NULL, hostPtr, isServer)
+ ) == SUCCESS)
+ return (result);
+ if (got_nodata)
+ result = NO_INFO;
+ return (result);
+}
+
+/*
+ * Perform a query on the concatenation of name and domain,
+ * removing a trailing dot from name if domain is NULL.
+ */
+GetHostDomain(nsAddrPtr, queryClass, queryType, name, domain, hostPtr, isServer)
+ struct in_addr *nsAddrPtr;
+ int queryClass;
+ int queryType;
+ char *name, *domain;
+ HostInfo *hostPtr;
+ Boolean isServer;
+{
+ querybuf buf;
+ char nbuf[2*MAXDNAME+2];
+ char *longname = nbuf;
+ int n;
+
+ if (domain == NULL) {
+ /*
+ * Check for trailing '.';
+ * copy without '.' if present.
+ */
+ n = strlen(name) - 1;
+ if (name[n] == '.' && n < sizeof(nbuf) - 1) {
+ bcopy(name, nbuf, n);
+ nbuf[n] = '\0';
+ } else
+ longname = name;
+ } else {
+ (void)sprintf(nbuf, "%.*s.%.*s",
+ MAXDNAME, name, MAXDNAME, domain);
+ longname = nbuf;
+ }
+ n = res_mkquery(QUERY, longname, queryClass, queryType,
+ NULL, 0, 0, buf.qb2, sizeof(buf));
+ if (n < 0) {
+ if (_res.options & RES_DEBUG) {
+ printf("Res_mkquery failed\n");
+ }
+ return (ERROR);
+ }
+
+ n = GetAnswer(nsAddrPtr, queryType, (char *)&buf, n, 0, hostPtr, isServer);
+
+ /*
+ * GetAnswer didn't find a name, so set it to the specified one.
+ */
+ if (n == NONAUTH) {
+ if (hostPtr->name == NULL) {
+ int len = strlen(longname) + 1;
+ hostPtr->name = Calloc(len, sizeof(char));
+ bcopy(longname, hostPtr->name, len);
+ }
+ }
+ return(n);
+}
+
+
+/*
+*******************************************************************************
+*
+* GetHostInfoByAddr --
+*
+* Performs a PTR lookup in in-addr.arpa to find the host name
+* that corresponds to the given address.
+*
+* Results:
+* ERROR - res_mkquery failed.
+* + return values from GetAnswer()
+*
+*******************************************************************************
+*/
+
+int
+GetHostInfoByAddr(nsAddrPtr, address, hostPtr)
+ struct in_addr *nsAddrPtr;
+ struct in_addr *address;
+ HostInfo *hostPtr;
+{
+ int n;
+ querybuf buf;
+ char qbuf[MAXDNAME];
+ char *p = (char *) &address->s_addr;
+
+ (void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
+ ((unsigned)p[3] & 0xff),
+ ((unsigned)p[2] & 0xff),
+ ((unsigned)p[1] & 0xff),
+ ((unsigned)p[0] & 0xff));
+ n = res_mkquery(QUERY, qbuf, C_IN, T_PTR, NULL, 0, NULL,
+ buf.qb2, sizeof buf);
+ if (n < 0) {
+ if (_res.options & RES_DEBUG) {
+ printf("res_mkquery() failed\n");
+ }
+ return (ERROR);
+ }
+ n = GetAnswer(nsAddrPtr, T_PTR, (char *) &buf, n, 1, hostPtr, 1);
+ if (n == SUCCESS) {
+ hostPtr->addrType = AF_INET;
+ hostPtr->addrLen = 4;
+ hostPtr->addrList = (char **)Calloc(2, sizeof(char *));
+ hostPtr->addrList[0] = Calloc(INT32SZ, sizeof(char));
+ bcopy((char *)p, hostPtr->addrList[0], INADDRSZ);
+ hostPtr->addrList[1] = NULL;
+ }
+ return n;
+}
+
+/*
+*******************************************************************************
+*
+* FreeHostInfoPtr --
+*
+* Deallocates all the calloc'd areas for a HostInfo variable.
+*
+*******************************************************************************
+*/
+
+void
+FreeHostInfoPtr(hostPtr)
+ register HostInfo *hostPtr;
+{
+ int i, j;
+
+ if (hostPtr->name != NULL) {
+ free(hostPtr->name);
+ hostPtr->name = NULL;
+ }
+
+ if (hostPtr->aliases != NULL) {
+ i = 0;
+ while (hostPtr->aliases[i] != NULL) {
+ free(hostPtr->aliases[i]);
+ i++;
+ }
+ free((char *)hostPtr->aliases);
+ hostPtr->aliases = NULL;
+ }
+
+ if (hostPtr->addrList != NULL) {
+ i = 0;
+ while (hostPtr->addrList[i] != NULL) {
+ free(hostPtr->addrList[i]);
+ i++;
+ }
+ free((char *)hostPtr->addrList);
+ hostPtr->addrList = NULL;
+ }
+
+ if (hostPtr->servers != NULL) {
+ i = 0;
+ while (hostPtr->servers[i] != NULL) {
+
+ if (hostPtr->servers[i]->name != NULL) {
+ free(hostPtr->servers[i]->name);
+ }
+
+ if (hostPtr->servers[i]->domains != NULL) {
+ j = 0;
+ while (hostPtr->servers[i]->domains[j] != NULL) {
+ free(hostPtr->servers[i]->domains[j]);
+ j++;
+ }
+ free((char *)hostPtr->servers[i]->domains);
+ }
+
+ if (hostPtr->servers[i]->addrList != NULL) {
+ j = 0;
+ while (hostPtr->servers[i]->addrList[j] != NULL) {
+ free(hostPtr->servers[i]->addrList[j]);
+ j++;
+ }
+ free((char *)hostPtr->servers[i]->addrList);
+ }
+ free((char *)hostPtr->servers[i]);
+ i++;
+ }
+ free((char *)hostPtr->servers);
+ hostPtr->servers = NULL;
+ }
+}
diff --git a/usr.sbin/named/nslookup/list.c b/usr.sbin/named/nslookup/list.c
new file mode 100644
index 00000000000..de282eca469
--- /dev/null
+++ b/usr.sbin/named/nslookup/list.c
@@ -0,0 +1,1026 @@
+/* $NetBSD: list.c,v 1.1 1996/02/02 15:30:09 mrg Exp $ */
+
+/*
+ * ++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--
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)list.c 5.23 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: list.c,v 8.3 1994/12/19 08:35:16 vixie Exp ";
+#endif /* not lint */
+
+/*
+ *******************************************************************************
+ *
+ * list.c --
+ *
+ * Routines to obtain info from name and finger servers.
+ *
+ * Adapted from 4.3BSD BIND ns_init.c and from finger.c.
+ *
+ *******************************************************************************
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include "res.h"
+#include "conf/portability.h"
+
+extern char *_res_resultcodes[]; /* res_debug.c */
+extern char *pager;
+
+typedef union {
+ HEADER qb1;
+ u_char qb2[PACKETSZ];
+} querybuf;
+
+extern HostInfo *defaultPtr;
+extern HostInfo curHostInfo;
+extern int curHostValid;
+extern int queryType;
+extern int queryClass;
+
+static int sockFD = -1;
+int ListSubr();
+
+/*
+ * During a listing to a file, hash marks are printed
+ * every HASH_SIZE records.
+ */
+
+#define HASH_SIZE 50
+
+
+/*
+ *******************************************************************************
+ *
+ * ListHosts --
+ * ListHostsByType --
+ *
+ * Requests the name server to do a zone transfer so we
+ * find out what hosts it knows about.
+ *
+ * For ListHosts, there are five types of output:
+ * - Internet addresses (default)
+ * - cpu type and operating system (-h option)
+ * - canonical and alias names (-a option)
+ * - well-known service names (-s option)
+ * - ALL records (-d option)
+ * ListHostsByType prints records of the default type or of a speicific
+ * type.
+ *
+ * To see all types of information sorted by name, do the following:
+ * ls -d domain.edu > file
+ * view file
+ *
+ * Results:
+ * SUCCESS the listing was successful.
+ * ERROR the server could not be contacted because
+ * a socket could not be obtained or an error
+ * occured while receiving, or the output file
+ * could not be opened.
+ *
+ *******************************************************************************
+ */
+
+void
+ListHostsByType(string, putToFile)
+ char *string;
+ int putToFile;
+{
+ int i, qtype, result;
+ char *namePtr;
+ char name[NAME_LEN];
+ char option[NAME_LEN];
+
+ /*
+ * Parse the command line. It maybe of the form "ls -t domain"
+ * or "ls -t type domain".
+ */
+
+ i = sscanf(string, " ls -t %s %s", option, name);
+ if (putToFile && i == 2 && name[0] == '>') {
+ i--;
+ }
+ if (i == 2) {
+ qtype = StringToType(option, -1, stderr);
+ if (qtype == -1)
+ return;
+ namePtr = name;
+ } else if (i == 1) {
+ namePtr = option;
+ qtype = queryType;
+ } else {
+ fprintf(stderr, "*** ls: invalid request %s\n",string);
+ return;
+ }
+ result = ListSubr(qtype, namePtr, putToFile ? string : NULL);
+ if (result != SUCCESS)
+ fprintf(stderr, "*** Can't list domain %s: %s\n",
+ namePtr, DecodeError(result));
+}
+
+void
+ListHosts(string, putToFile)
+ char *string;
+ int putToFile;
+{
+ int i, qtype, result;
+ char *namePtr;
+ char name[NAME_LEN];
+ char option[NAME_LEN];
+
+ /*
+ * Parse the command line. It maybe of the form "ls domain",
+ * "ls -X domain".
+ */
+ i = sscanf(string, " ls %s %s", option, name);
+ if (putToFile && i == 2 && name[0] == '>') {
+ i--;
+ }
+ if (i == 2) {
+ if (strcmp("-a", option) == 0) {
+ qtype = T_CNAME;
+ } else if (strcmp("-h", option) == 0) {
+ qtype = T_HINFO;
+ } else if (strcmp("-m", option) == 0) {
+ qtype = T_MX;
+ } else if (strcmp("-p", option) == 0) {
+ qtype = T_PX;
+ } else if (strcmp("-s", option) == 0) {
+ qtype = T_WKS;
+ } else if (strcmp("-d", option) == 0) {
+ qtype = T_ANY;
+ } else {
+ qtype = T_A;
+ }
+ namePtr = name;
+ } else if (i == 1) {
+ namePtr = option;
+ qtype = T_A;
+ } else {
+ fprintf(stderr, "*** ls: invalid request %s\n",string);
+ return;
+ }
+ result = ListSubr(qtype, namePtr, putToFile ? string : NULL);
+ if (result != SUCCESS)
+ fprintf(stderr, "*** Can't list domain %s: %s\n",
+ namePtr, DecodeError(result));
+}
+
+int
+ListSubr(qtype, domain, cmd)
+ int qtype;
+ char *domain;
+ char *cmd;
+{
+ querybuf buf;
+ struct sockaddr_in sin;
+ HEADER *headerPtr;
+ int msglen;
+ int amtToRead;
+ int numRead;
+ int numAnswers = 0;
+ int result;
+ int soacnt = 0;
+ u_short len;
+ u_char *cp, *nmp;
+ char dname[2][NAME_LEN];
+ char file[NAME_LEN];
+ static u_char *answer = NULL;
+ static int answerLen = 0;
+ enum {
+ NO_ERRORS,
+ ERR_READING_LEN,
+ ERR_READING_MSG,
+ ERR_PRINTING
+ } error = NO_ERRORS;
+
+ /*
+ * Create a query packet for the requested domain name.
+ */
+ msglen = res_mkquery(QUERY, domain, queryClass, T_AXFR,
+ NULL, 0, 0, buf.qb2, sizeof buf);
+ if (msglen < 0) {
+ if (_res.options & RES_DEBUG) {
+ fprintf(stderr, "*** ls: res_mkquery failed\n");
+ }
+ return (ERROR);
+ }
+
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(nsport);
+
+ /*
+ * Check to see if we have the address of the server or the
+ * address of a server who knows about this domain.
+ *
+ * For now, just use the first address in the list.
+ */
+
+ if (defaultPtr->addrList != NULL) {
+ sin.sin_addr = *(struct in_addr *) defaultPtr->addrList[0];
+ } else {
+ sin.sin_addr = *(struct in_addr *)defaultPtr->servers[0]->addrList[0];
+ }
+
+ /*
+ * Set up a virtual circuit to the server.
+ */
+ if ((sockFD = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("ls: socket");
+ return(ERROR);
+ }
+ if (connect(sockFD, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ int e;
+ if (errno == ECONNREFUSED) {
+ e = NO_RESPONSE;
+ } else {
+ perror("ls: connect");
+ e = ERROR;
+ }
+ (void) close(sockFD);
+ sockFD = -1;
+ return e;
+ }
+
+ /*
+ * Send length & message for zone transfer
+ */
+
+ __putshort(msglen, (u_char *)&len);
+
+ if (write(sockFD, (char *)&len, INT16SZ) != INT16SZ ||
+ write(sockFD, (char *) &buf, msglen) != msglen) {
+ perror("ls: write");
+ (void) close(sockFD);
+ sockFD = -1;
+ return(ERROR);
+ }
+
+ fprintf(stdout,"[%s]\n",
+ (defaultPtr->addrList != NULL) ? defaultPtr->name :
+ defaultPtr->servers[0]->name);
+
+ if (cmd == NULL) {
+ filePtr = stdout;
+ } else {
+ filePtr = OpenFile(cmd, file);
+ if (filePtr == NULL) {
+ fprintf(stderr, "*** Can't open %s for writing\n", file);
+ (void) close(sockFD);
+ sockFD = -1;
+ return(ERROR);
+ }
+ fprintf(filePtr, "> %s\n", cmd);
+ fprintf(filePtr,"[%s]\n",
+ (defaultPtr->addrList != NULL) ? defaultPtr->name :
+ defaultPtr->servers[0]->name);
+ }
+
+#if 0
+ if (qtype == T_CNAME) {
+ fprintf(filePtr, "%-30s", "Alias");
+ } else if (qtype == T_TXT) {
+ fprintf(filePtr, "%-30s", "Key");
+ } else {
+ fprintf(filePtr, "%-30s", "Host or domain name");
+ }
+ switch (qtype) {
+ case T_A:
+ fprintf(filePtr, " %-30s\n", "Internet Address");
+ break;
+ case T_HINFO:
+ fprintf(filePtr, " %-30s\n", "CPU & OS");
+ break;
+ case T_CNAME:
+ fprintf(filePtr, " %-30s\n", "Canonical Name");
+ break;
+ case T_MX:
+ fprintf(filePtr, " %-30s\n", "Metric & Host");
+ break;
+ case T_PX:
+ fprintf(filePtr, " %-30s\n", "Mapping information");
+ break;
+ case T_AFSDB:
+ fprintf(filePtr, " %-30s\n", "Subtype & Host");
+ break;
+ case T_X25:
+ fprintf(filePtr, " %-30s\n", "X25 Address");
+ break
+ case T_ISDN:
+ fprintf(filePtr, " %-30s\n", "ISDN Address");
+ break
+ case T_WKS:
+ fprintf(filePtr, " %-4s %s\n", "Protocol", "Services");
+ break;
+ case T_MB:
+ fprintf(filePtr, " %-30s\n", "Mailbox");
+ break;
+ case T_MG:
+ fprintf(filePtr, " %-30s\n", "Mail Group");
+ break;
+ case T_MR:
+ fprintf(filePtr, " %-30s\n", "Mail Rename");
+ break;
+ case T_MINFO:
+ fprintf(filePtr, " %-30s\n", "Mail List Requests & Errors");
+ break;
+ case T_UINFO:
+ fprintf(filePtr, " %-30s\n", "User Information");
+ break;
+ case T_UID:
+ fprintf(filePtr, " %-30s\n", "User ID");
+ break;
+ case T_GID:
+ fprintf(filePtr, " %-30s\n", "Group ID");
+ break;
+ case T_TXT:
+ fprintf(filePtr, " %-30s\n", "Text");
+ break;
+ case T_RP:
+ fprintf(filePtr, " %-30s\n", "Responsible Person");
+ break;
+ case T_RT:
+ fprintf(filePtr, " %-30s\n", "Router");
+ break;
+ case T_NSAP:
+ fprintf(filePtr, " %-30s\n", "NSAP address");
+ break;
+ case T_NSAP_PTR:
+ fprintf(filePtr, " %-30s\n", "NSAP pointer");
+ break;
+ case T_NS:
+ fprintf(filePtr, " %-30s\n", "Name Servers");
+ break;
+ case T_PTR:
+ fprintf(filePtr, " %-30s\n", "Pointers");
+ break;
+ case T_SOA:
+ fprintf(filePtr, " %-30s\n", "Start of Authority");
+ break;
+ case T_ANY:
+ fprintf(filePtr, " %-30s\n", "Resource Record Info.");
+ break;
+ }
+#endif
+
+
+ dname[0][0] = '\0';
+ while (1) {
+ unsigned short tmp;
+
+ /*
+ * Read the length of the response.
+ */
+
+ cp = (u_char *)&tmp;
+ amtToRead = INT16SZ;
+ while ((numRead = read(sockFD, cp, amtToRead)) > 0) {
+ cp += numRead;
+ if ((amtToRead -= numRead) <= 0)
+ break;
+ }
+ if (numRead <= 0) {
+ error = ERR_READING_LEN;
+ break;
+ }
+
+ if ((len = _getshort((u_char*)&tmp)) == 0) {
+ break; /* nothing left to read */
+ }
+
+ /*
+ * The server sent too much data to fit the existing buffer --
+ * allocate a new one.
+ */
+ if (len > (u_int)answerLen) {
+ if (answerLen != 0) {
+ free(answer);
+ }
+ answerLen = len;
+ answer = (u_char *)Malloc(answerLen);
+ }
+
+ /*
+ * Read the response.
+ */
+
+ amtToRead = len;
+ cp = answer;
+ while (amtToRead > 0 && (numRead=read(sockFD, cp, amtToRead)) > 0) {
+ cp += numRead;
+ amtToRead -= numRead;
+ }
+ if (numRead <= 0) {
+ error = ERR_READING_MSG;
+ break;
+ }
+
+ result = PrintListInfo(filePtr, answer, cp, qtype, dname[0]);
+ if (result != SUCCESS) {
+ error = ERR_PRINTING;
+ break;
+ }
+
+ numAnswers++;
+ if (cmd != NULL && ((numAnswers % HASH_SIZE) == 0)) {
+ fprintf(stdout, "#");
+ fflush(stdout);
+ }
+ cp = answer + HFIXEDSZ;
+ if (ntohs(((HEADER* )answer)->qdcount) > 0)
+ cp += dn_skipname((u_char *)cp,
+ (u_char *)answer + len) + QFIXEDSZ;
+ nmp = cp;
+ cp += dn_skipname((u_char *)cp, (u_char *)answer + len);
+ if ((_getshort((u_char*)cp) == T_SOA)) {
+ (void) dn_expand(answer, answer + len, nmp,
+ dname[soacnt], sizeof dname[0]);
+ if (soacnt) {
+ if (strcmp(dname[0], dname[1]) == 0)
+ break;
+ } else
+ soacnt++;
+ }
+ }
+
+ if (cmd != NULL) {
+ fprintf(stdout, "%sReceived %d record%s.\n",
+ (numAnswers >= HASH_SIZE) ? "\n" : "",
+ numAnswers,
+ (numAnswers != 1) ? "s" : "");
+ }
+
+ (void) close(sockFD);
+ sockFD = -1;
+ if (cmd != NULL && filePtr != NULL) {
+ fclose(filePtr);
+ filePtr = NULL;
+ }
+
+ switch (error) {
+ case NO_ERRORS:
+ return (SUCCESS);
+
+ case ERR_READING_LEN:
+ return(ERROR);
+
+ case ERR_PRINTING:
+ return(result);
+
+ case ERR_READING_MSG:
+ headerPtr = (HEADER *) answer;
+ fprintf(stderr,"*** ls: error receiving zone transfer:\n");
+ fprintf(stderr,
+ " result: %s, answers = %d, authority = %d, additional = %d\n",
+ _res_resultcodes[headerPtr->rcode],
+ ntohs(headerPtr->ancount), ntohs(headerPtr->nscount),
+ ntohs(headerPtr->arcount));
+ return(ERROR);
+ default:
+ return(ERROR);
+ }
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * PrintListInfo --
+ *
+ * Used by the ListInfo routine to print the answer
+ * received from the name server. Only the desired
+ * information is printed.
+ *
+ * Results:
+ * SUCCESS the answer was printed without a problem.
+ * NO_INFO the answer packet did not contain an answer.
+ * ERROR the answer was malformed.
+ * Misc. errors returned in the packet header.
+ *
+ *******************************************************************************
+ */
+
+#define NAME_FORMAT " %-30s"
+
+static Boolean
+strip_domain(string, domain)
+ char *string, *domain;
+{
+ register char *dot;
+
+ if (*domain != '\0') {
+ dot = string;
+ while ((dot = strchr(dot, '.')) != NULL && strcasecmp(domain, ++dot))
+ ;
+ if (dot != NULL) {
+ dot[-1] = '\0';
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+PrintListInfo(file, msg, eom, qtype, domain)
+ FILE *file;
+ u_char *msg, *eom;
+ int qtype;
+ char *domain;
+{
+ register u_char *cp;
+ HEADER *headerPtr;
+ int type, class, dlen, nameLen;
+ u_int32_t ttl;
+ int n, pref;
+ struct in_addr inaddr;
+ char name[NAME_LEN];
+ char name2[NAME_LEN];
+ Boolean stripped;
+
+ /*
+ * Read the header fields.
+ */
+ headerPtr = (HEADER *)msg;
+ cp = msg + HFIXEDSZ;
+ if (headerPtr->rcode != NOERROR) {
+ return(headerPtr->rcode);
+ }
+
+ /*
+ * We are looking for info from answer resource records.
+ * If there aren't any, return with an error. We assume
+ * there aren't any question records.
+ */
+
+ if (ntohs(headerPtr->ancount) == 0) {
+ return(NO_INFO);
+ } else {
+ if (ntohs(headerPtr->qdcount) > 0) {
+ nameLen = dn_skipname(cp, eom);
+ if (nameLen < 0)
+ return (ERROR);
+ cp += nameLen + QFIXEDSZ;
+ }
+ nameLen = dn_expand(msg, eom, cp, name, sizeof name);
+ if (nameLen < 0)
+ return (ERROR);
+ cp += nameLen;
+
+ type = _getshort((u_char*)cp);
+ cp += INT16SZ;
+
+ if (!(type == qtype || qtype == T_ANY) &&
+ !((type == T_NS || type == T_PTR) && qtype == T_A))
+ return(SUCCESS);
+
+ class = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ ttl = _getlong((u_char*)cp);
+ cp += INT32SZ;
+ dlen = _getshort((u_char*)cp);
+ cp += INT16SZ;
+
+ if (name[0] == 0)
+ strcpy(name, "(root)");
+
+ /* Strip the domain name from the data, if desired. */
+ stripped = FALSE;
+ if ((_res.options & RES_DEBUG) == 0) {
+ if (type != T_SOA) {
+ stripped = strip_domain(name, domain);
+ }
+ }
+ if (!stripped && nameLen < sizeof(name)-1) {
+ strcat(name, ".");
+ }
+
+ fprintf(file, NAME_FORMAT, name);
+
+ if (qtype == T_ANY) {
+ if (_res.options & RES_DEBUG) {
+ fprintf(file,"\t%lu %-5s", ttl, p_class(queryClass));
+ }
+ fprintf(file," %-5s", p_type(type));
+ }
+
+ /* XXX merge this into debug.c's print routines */
+
+ switch (type) {
+ case T_A:
+ if (class == C_IN) {
+ bcopy(cp, (char *)&inaddr, INADDRSZ);
+ if (dlen == 4) {
+ fprintf(file," %s", inet_ntoa(inaddr));
+ } else if (dlen == 7) {
+ fprintf(file," %s", inet_ntoa(inaddr));
+ fprintf(file," (%d, %d)", cp[4],(cp[5] << 8) + cp[6]);
+ } else
+ fprintf(file, " (dlen = %d?)", dlen);
+ }
+ break;
+
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ nameLen = dn_expand(msg, eom, cp, name2, sizeof name2);
+ if (nameLen < 0) {
+ fprintf(file, " ***\n");
+ return (ERROR);
+ }
+ fprintf(file, " %s", name2);
+ break;
+
+ case T_NS:
+ case T_PTR:
+ case T_NSAP_PTR:
+ putc(' ', file);
+ if (qtype != T_ANY)
+ fprintf(file,"%s = ", type == T_PTR ? "host" : "server");
+ cp = (u_char *)Print_cdname2(cp, msg, eom, file);
+ break;
+
+ case T_HINFO:
+ case T_ISDN:
+ {
+ u_char *cp2 = cp + dlen;
+ if (n = *cp++) {
+ (void)sprintf(name,"%.*s", n, cp);
+ fprintf(file," %-10s", name);
+ cp += n;
+ } else {
+ fprintf(file," %-10s", " ");
+ }
+ if (cp == cp2)
+ break;
+ if (n = *cp++) {
+ fprintf(file," %.*s", n, cp);
+ cp += n;
+ }
+ }
+ break;
+
+ case T_SOA:
+ nameLen = dn_expand(msg, eom, cp, name2, sizeof name2);
+ if (nameLen < 0) {
+ fprintf(file, " ***\n");
+ return (ERROR);
+ }
+ cp += nameLen;
+ fprintf(file, " %s", name2);
+ nameLen = dn_expand(msg, eom, cp, name2, sizeof name2);
+ if (nameLen < 0) {
+ fprintf(file, " ***\n");
+ return (ERROR);
+ }
+ cp += nameLen;
+ fprintf(file, " %s. (", name2);
+ for (n = 0; n < 5; n++) {
+ u_int32_t u;
+
+ u = _getlong((u_char*)cp);
+ cp += INT32SZ;
+ fprintf(file,"%s%lu", n? " " : "", u);
+ }
+ fprintf(file, ")");
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ pref = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ fprintf(file," %-3d ",pref);
+ nameLen = dn_expand(msg, eom, cp, name2, sizeof name2);
+ if (nameLen < 0) {
+ fprintf(file, " ***\n");
+ return (ERROR);
+ }
+ fprintf(file, " %s", name2);
+ break;
+
+ case T_PX:
+ pref = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ fprintf(file," %-3d ",pref);
+ nameLen = dn_expand(msg, eom, cp, name2, sizeof name2);
+ if (nameLen < 0) {
+ fprintf(file, " ***\n");
+ return (ERROR);
+ }
+ fprintf(file, " %s", name2);
+ cp += strlen((char *)cp) + 1;
+ nameLen = dn_expand(msg, eom, cp, name2, sizeof name2);
+ if (nameLen < 0) {
+ fprintf(file, " ***\n");
+ return (ERROR);
+ }
+ fprintf(file, " %s", name2);
+ break;
+
+ case T_TXT:
+ case T_X25:
+ {
+ u_char *cp2 = cp + dlen;
+ int c;
+
+ (void) fputs(" \"", file);
+ while (cp < cp2) {
+ if (n = (unsigned char) *cp++) {
+ for (c = n; c > 0 && cp < cp2; c--)
+ if ((*cp == '\n') || (*cp == '"')) {
+ (void) putc('\\', file);
+ (void) putc(*cp++, file);
+ } else
+ (void) putc(*cp++, file);
+ }
+ }
+ (void) putc('"', file);
+ }
+ break;
+
+ case T_NSAP:
+ fprintf(file, " %s", inet_nsap_ntoa(dlen, cp, NULL));
+ break;
+
+ case T_MINFO:
+ case T_RP:
+ (void) putc(' ', file);
+ cp = (u_char *)Print_cdname(cp, msg, eom, file);
+ fprintf(file, " ");
+ cp = (u_char *)Print_cdname(cp, msg, eom, file);
+ break;
+
+ case T_UINFO:
+ fprintf(file, " %s", cp);
+ break;
+
+ case T_UID:
+ case T_GID:
+ fprintf(file, " %lu", _getlong((u_char*)cp));
+ break;
+
+ case T_WKS:
+ if (class == C_IN) {
+ struct protoent *pp;
+ struct servent *ss;
+ u_short port;
+
+ cp += 4; /* skip inet address */
+ dlen -= 4;
+
+ setprotoent(1);
+ setservent(1);
+ n = *cp & 0377;
+ pp = getprotobynumber(n);
+ if (pp == 0)
+ fprintf(file," %-3d ", n);
+ else
+ fprintf(file," %-3s ", pp->p_name);
+ cp++; dlen--;
+
+ port = 0;
+ while (dlen-- > 0) {
+ n = *cp++;
+ do {
+ if (n & 0200) {
+ ss = getservbyport((int)htons(port),
+ pp->p_name);
+ if (ss == 0)
+ fprintf(file," %u", port);
+ else
+ fprintf(file," %s", ss->s_name);
+ }
+ n <<= 1;
+ } while (++port & 07);
+ }
+ endprotoent();
+ endservent();
+ }
+ break;
+ }
+ fprintf(file,"\n");
+ }
+ return(SUCCESS);
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * ViewList --
+ *
+ * A hack to view the output of the ls command in sorted
+ * order using more.
+ *
+ *******************************************************************************
+ */
+
+ViewList(string)
+ char *string;
+{
+ char file[PATH_MAX];
+ char command[PATH_MAX];
+
+ sscanf(string, " view %s", file);
+ (void)sprintf(command, "grep \"^ \" %s | sort | %s", file, pager);
+ system(command);
+}
+
+/*
+ *******************************************************************************
+ *
+ * Finger --
+ *
+ * Connects with the finger server for the current host
+ * to request info on the specified person (long form)
+ * who is on the system (short form).
+ *
+ * Results:
+ * SUCCESS the finger server was contacted.
+ * ERROR the server could not be contacted because
+ * a socket could not be obtained or connected
+ * to or the service could not be found.
+ *
+ *******************************************************************************
+ */
+
+Finger(string, putToFile)
+ char *string;
+ int putToFile;
+{
+ struct servent *sp;
+ struct sockaddr_in sin;
+ register FILE *f;
+ register int c;
+ register int lastc;
+ char name[NAME_LEN];
+ char file[NAME_LEN];
+
+ /*
+ * We need a valid current host info to get an inet address.
+ */
+ if (!curHostValid) {
+ fprintf(stderr, "Finger: no current host defined.\n");
+ return (ERROR);
+ }
+
+ if (sscanf(string, " finger %s", name) == 1) {
+ if (putToFile && (name[0] == '>')) {
+ name[0] = '\0';
+ }
+ } else {
+ name[0] = '\0';
+ }
+
+ sp = getservbyname("finger", "tcp");
+ if (sp == 0) {
+ fprintf(stderr, "Finger: unknown service\n");
+ return (ERROR);
+ }
+
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = curHostInfo.addrType;
+ sin.sin_port = sp->s_port;
+ bcopy(curHostInfo.addrList[0], (char *)&sin.sin_addr,
+ curHostInfo.addrLen);
+
+ /*
+ * Set up a virtual circuit to the host.
+ */
+
+ sockFD = socket(curHostInfo.addrType, SOCK_STREAM, 0);
+ if (sockFD < 0) {
+ fflush(stdout);
+ perror("finger: socket");
+ return (ERROR);
+ }
+
+ if (connect(sockFD, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+ fflush(stdout);
+ perror("finger: connect");
+ close(sockFD);
+ sockFD = -1;
+ return (ERROR);
+ }
+
+ if (!putToFile) {
+ filePtr = stdout;
+ } else {
+ filePtr = OpenFile(string, file);
+ if (filePtr == NULL) {
+ fprintf(stderr, "*** Can't open %s for writing\n", file);
+ close(sockFD);
+ sockFD = -1;
+ return(ERROR);
+ }
+ fprintf(filePtr,"> %s\n", string);
+ }
+ fprintf(filePtr, "[%s]\n", curHostInfo.name);
+
+ if (name[0] != '\0') {
+ write(sockFD, "/W ", 3);
+ }
+ write(sockFD, name, strlen(name));
+ write(sockFD, "\r\n", 2);
+ f = fdopen(sockFD, "r");
+ lastc = '\n';
+ while ((c = getc(f)) != EOF) {
+ switch (c) {
+ case 0210:
+ case 0211:
+ case 0212:
+ case 0214:
+ c -= 0200;
+ break;
+ case 0215:
+ c = '\n';
+ break;
+ }
+ putc(lastc = c, filePtr);
+ }
+ if (lastc != '\n') {
+ putc('\n', filePtr);
+ }
+ putc('\n', filePtr);
+
+ close(sockFD);
+ sockFD = -1;
+
+ if (putToFile) {
+ fclose(filePtr);
+ filePtr = NULL;
+ }
+ return (SUCCESS);
+}
+
+ListHost_close()
+{
+ if (sockFD != -1) {
+ (void) close(sockFD);
+ sockFD = -1;
+ }
+}
diff --git a/usr.sbin/named/nslookup/main.c b/usr.sbin/named/nslookup/main.c
new file mode 100644
index 00000000000..50b9c491147
--- /dev/null
+++ b/usr.sbin/named/nslookup/main.c
@@ -0,0 +1,1114 @@
+/* $NetBSD: main.c,v 1.1 1996/02/02 15:30:13 mrg Exp $ */
+
+/*
+ * ++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--
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1985,1989 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 5.42 (Berkeley) 3/3/91";
+static char rcsid[] = "$Id: main.c,v 8.2 1995/12/22 10:20:42 vixie Exp ";
+#endif /* not lint */
+
+/*
+ ******************************************************************************
+ *
+ * main.c --
+ *
+ * Main routine and some action routines for the name server
+ * lookup program.
+ *
+ * Andrew Cherenson
+ * U.C. Berkeley Computer Science Div.
+ * CS298-26, Fall 1985
+ *
+ ******************************************************************************
+ */
+
+#include <sys/param.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+#include "res.h"
+#include "pathnames.h"
+#include "conf/portability.h"
+
+
+/*
+ * Name of a top-level name server. Can be changed with
+ * the "set root" command.
+ */
+
+#ifndef ROOT_SERVER
+#define ROOT_SERVER "a.root-servers.net."
+#endif
+char rootServerName[NAME_LEN] = ROOT_SERVER;
+
+
+/*
+ * Import the state information from the resolver library.
+ */
+
+extern struct __res_state _res;
+
+
+/*
+ * Info about the most recently queried host.
+ */
+
+HostInfo curHostInfo;
+int curHostValid = FALSE;
+
+
+/*
+ * Info about the default name server.
+ */
+
+HostInfo *defaultPtr = NULL;
+char defaultServer[NAME_LEN];
+struct in_addr defaultAddr;
+
+
+/*
+ * Initial name server query type is Address.
+ */
+
+int queryType = T_A;
+int queryClass = C_IN;
+
+/*
+ * Stuff for Interrupt (control-C) signal handler.
+ */
+
+extern SIG_FN IntrHandler();
+FILE *filePtr;
+jmp_buf env;
+
+
+/*
+ * Browser command for help and view.
+ */
+char *pager;
+
+static void CvtAddrToPtr();
+static void ReadRC();
+
+
+/*
+ ******************************************************************************
+ *
+ * main --
+ *
+ * Initializes the resolver library and determines the address
+ * of the initial name server. The yylex routine is used to
+ * read and perform commands.
+ *
+ ******************************************************************************
+ */
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *wantedHost = NULL;
+ Boolean useLocalServer;
+ int result;
+ int i;
+ struct hostent *hp;
+
+ /*
+ * Initialize the resolver library routines.
+ */
+
+ if (res_init() == -1) {
+ fprintf(stderr,"*** Can't initialize resolver.\n");
+ exit(1);
+ }
+
+ /*
+ * Allocate space for the default server's host info and
+ * find the server's address and name. If the resolver library
+ * already has some addresses for a potential name server,
+ * then use them. Otherwise, see if the current host has a server.
+ * Command line arguments may override the choice of initial server.
+ */
+
+ defaultPtr = (HostInfo *) Calloc(1, sizeof(HostInfo));
+
+ /*
+ * Parse the arguments:
+ * no args = go into interactive mode, use default host as server
+ * 1 arg = use as host name to be looked up, default host will be server
+ * non-interactive mode
+ * 2 args = 1st arg:
+ * if it is '-', then
+ * ignore but go into interactive mode
+ * else
+ * use as host name to be looked up,
+ * go into non-interactive mode
+ * 2nd arg: name or inet address of server
+ *
+ * "Set" options are specified with a leading - and must come before
+ * any arguments. For example, to find the well-known services for
+ * a host, type "nslookup -query=wks host"
+ */
+
+ ReadRC(); /* look for options file */
+
+ ++argv; --argc; /* skip prog name */
+
+ while (argc && *argv[0] == '-' && argv[0][1]) {
+ (void) SetOption (&(argv[0][1]));
+ ++argv; --argc;
+ }
+ if (argc > 2) {
+ Usage();
+ }
+ if (argc && *argv[0] != '-') {
+ wantedHost = *argv; /* name of host to be looked up */
+ }
+
+ useLocalServer = FALSE;
+ if (argc == 2) {
+ struct in_addr addr;
+
+ /*
+ * Use an explicit name server. If the hostname lookup fails,
+ * default to the server(s) in resolv.conf.
+ */
+
+ if (inet_aton(*++argv, &addr)) {
+ _res.nscount = 1;
+ _res.nsaddr.sin_addr = addr;
+ } else {
+ hp = gethostbyname(*argv);
+ if (hp == NULL) {
+ fprintf(stderr, "*** Can't find server address for '%s': ",
+ *argv);
+ herror((char *)NULL);
+ fputc('\n', stderr);
+ } else {
+ for (i = 0; i < MAXNS && hp->h_addr_list[i] != NULL; i++) {
+ bcopy(hp->h_addr_list[i],
+ (char *)&_res.nsaddr_list[i].sin_addr,
+ hp->h_length);
+ }
+ _res.nscount = i;
+ }
+ }
+ }
+
+
+ if (_res.nscount == 0 || useLocalServer) {
+ LocalServer(defaultPtr);
+ } else {
+ for (i = 0; i < _res.nscount; i++) {
+ if (_res.nsaddr_list[i].sin_addr.s_addr == INADDR_ANY) {
+ LocalServer(defaultPtr);
+ break;
+ } else {
+ result = GetHostInfoByAddr(&(_res.nsaddr_list[i].sin_addr),
+ &(_res.nsaddr_list[i].sin_addr),
+ defaultPtr);
+ if (result != SUCCESS) {
+ fprintf(stderr,
+ "*** Can't find server name for address %s: %s\n",
+ inet_ntoa(_res.nsaddr_list[i].sin_addr),
+ DecodeError(result));
+ } else {
+ defaultAddr = _res.nsaddr_list[i].sin_addr;
+ break;
+ }
+ }
+ }
+
+ /*
+ * If we have exhausted the list, tell the user about the
+ * command line argument to specify an address.
+ */
+
+ if (i == _res.nscount) {
+ fprintf(stderr, "*** Default servers are not available\n");
+ exit(1);
+ }
+
+ }
+ strcpy(defaultServer, defaultPtr->name);
+
+
+#ifdef DEBUG
+#ifdef DEBUG2
+ _res.options |= RES_DEBUG2;
+#endif
+ _res.options |= RES_DEBUG;
+ _res.retry = 2;
+#endif /* DEBUG */
+
+ /*
+ * If we're in non-interactive mode, look up the wanted host and quit.
+ * Otherwise, print the initial server's name and continue with
+ * the initialization.
+ */
+
+ if (wantedHost != (char *) NULL) {
+ LookupHost(wantedHost, 0);
+ } else {
+ PrintHostInfo(stdout, "Default Server:", defaultPtr);
+
+ pager = getenv("PAGER");
+ if (pager == NULL) {
+ pager = _PATH_PAGERCMD;
+ }
+
+ /*
+ * Setup the environment to allow the interrupt handler to return here.
+ */
+
+ (void) setjmp(env);
+
+ /*
+ * Return here after a longjmp.
+ */
+
+ signal(SIGINT, IntrHandler);
+ signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * Read and evaluate commands. The commands are described in commands.l
+ * Yylex returns 0 when ^D or 'exit' is typed.
+ */
+
+ printf("> ");
+ fflush(stdout);
+ while(yylex()) {
+ printf("> ");
+ fflush(stdout);
+ }
+ }
+ exit(0);
+}
+
+
+LocalServer(defaultPtr)
+ HostInfo *defaultPtr;
+{
+ char hostName[NAME_LEN];
+
+ (void) gethostname(hostName, sizeof(hostName));
+
+ defaultAddr.s_addr = htonl(INADDR_ANY);
+ (void) GetHostInfoByName(&defaultAddr, C_IN, T_A,
+ "0.0.0.0", defaultPtr, 1);
+ free(defaultPtr->name);
+ defaultPtr->name = Calloc(1, sizeof(hostName)+1);
+ strcpy(defaultPtr->name, hostName);
+}
+
+
+/*
+ ******************************************************************************
+ *
+ * Usage --
+ *
+ * Lists the proper methods to run the program and exits.
+ *
+ ******************************************************************************
+ */
+
+Usage()
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr,
+" nslookup [-opt ...] # interactive mode using default server\n");
+ fprintf(stderr,
+" nslookup [-opt ...] - server # interactive mode using 'server'\n");
+ fprintf(stderr,
+" nslookup [-opt ...] host # just look up 'host' using default server\n");
+ fprintf(stderr,
+" nslookup [-opt ...] host server # just look up 'host' using 'server'\n");
+ exit(1);
+}
+
+/*
+ ******************************************************************************
+ *
+ * IsAddr --
+ *
+ * Returns TRUE if the string looks like an Internet address.
+ * A string with a trailing dot is not an address, even if it looks
+ * like one.
+ *
+ ******************************************************************************
+ */
+
+Boolean
+IsAddr(host, addrPtr)
+ char *host;
+ struct in_addr *addrPtr; /* If return TRUE, contains IP address */
+{
+ register char *cp;
+
+ if (isdigit(host[0])) {
+ /* Make sure it has only digits and dots. */
+ for (cp = host; *cp; ++cp) {
+ if (!isdigit(*cp) && *cp != '.')
+ return FALSE;
+ }
+ /* If it has a trailing dot, don't treat it as an address. */
+ if (*--cp != '.') {
+ return inet_aton(host, addrPtr);
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ ******************************************************************************
+ *
+ * SetDefaultServer --
+ *
+ * Changes the default name server to the one specified by
+ * the first argument. The command "server name" uses the current
+ * default server to lookup the info for "name". The command
+ * "lserver name" uses the original server to lookup "name".
+ *
+ * Side effects:
+ * This routine will cause a core dump if the allocation requests fail.
+ *
+ * Results:
+ * SUCCESS The default server was changed successfully.
+ * NONAUTH The server was changed but addresses of
+ * other servers who know about the requested server
+ * were returned.
+ * Errors No info about the new server was found or
+ * requests to the current server timed-out.
+ *
+ ******************************************************************************
+ */
+
+int
+SetDefaultServer(string, local)
+ char *string;
+ Boolean local;
+{
+ register HostInfo *newDefPtr;
+ struct in_addr *servAddrPtr;
+ struct in_addr addr;
+ char newServer[NAME_LEN];
+ int result;
+ int i;
+
+ /*
+ * Parse the command line. It maybe of the form "server name",
+ * "lserver name" or just "name".
+ */
+
+ if (local) {
+ i = sscanf(string, " lserver %s", newServer);
+ } else {
+ i = sscanf(string, " server %s", newServer);
+ }
+ if (i != 1) {
+ i = sscanf(string, " %s", newServer);
+ if (i != 1) {
+ fprintf(stderr,"SetDefaultServer: invalid name: %s\n", string);
+ return(ERROR);
+ }
+ }
+
+ /*
+ * Allocate space for a HostInfo variable for the new server. Don't
+ * overwrite the old HostInfo struct because info about the new server
+ * might not be found and we need to have valid default server info.
+ */
+
+ newDefPtr = (HostInfo *) Calloc(1, sizeof(HostInfo));
+
+
+ /*
+ * A 'local' lookup uses the original server that the program was
+ * initialized with.
+ *
+ * Check to see if we have the address of the server or the
+ * address of a server who knows about this domain.
+ * XXX For now, just use the first address in the list.
+ */
+
+ if (local) {
+ servAddrPtr = &defaultAddr;
+ } else if (defaultPtr->addrList != NULL) {
+ servAddrPtr = (struct in_addr *) defaultPtr->addrList[0];
+ } else {
+ servAddrPtr = (struct in_addr *) defaultPtr->servers[0]->addrList[0];
+ }
+
+ result = ERROR;
+ if (IsAddr(newServer, &addr)) {
+ result = GetHostInfoByAddr(servAddrPtr, &addr, newDefPtr);
+ /* If we can't get the name, fall through... */
+ }
+ if (result != SUCCESS && result != NONAUTH) {
+ result = GetHostInfoByName(servAddrPtr, C_IN, T_A,
+ newServer, newDefPtr, 1);
+ }
+
+ if (result == SUCCESS || result == NONAUTH) {
+ /*
+ * Found info about the new server. Free the resources for
+ * the old server.
+ */
+
+ FreeHostInfoPtr(defaultPtr);
+ free((char *)defaultPtr);
+ defaultPtr = newDefPtr;
+ strcpy(defaultServer, defaultPtr->name);
+ PrintHostInfo(stdout, "Default Server:", defaultPtr);
+ return(SUCCESS);
+ } else {
+ fprintf(stderr, "*** Can't find address for server %s: %s\n",
+ newServer, DecodeError(result));
+ free((char *)newDefPtr);
+
+ return(result);
+ }
+}
+
+/*
+ ******************************************************************************
+ *
+ * DoLoookup --
+ *
+ * Common subroutine for LookupHost and LookupHostWithServer.
+ *
+ * Results:
+ * SUCCESS - the lookup was successful.
+ * Misc. Errors - an error message is printed if the lookup failed.
+ *
+ ******************************************************************************
+ */
+
+static int
+DoLookup(host, servPtr, serverName)
+ char *host;
+ HostInfo *servPtr;
+ char *serverName;
+{
+ int result;
+ struct in_addr *servAddrPtr;
+ struct in_addr addr;
+
+ /* Skip escape character */
+ if (host[0] == '\\')
+ host++;
+
+ /*
+ * If the user gives us an address for an address query,
+ * silently treat it as a PTR query. If the query type is already
+ * PTR, then convert the address into the in-addr.arpa format.
+ *
+ * Use the address of the server if it exists, otherwise use the
+ * address of a server who knows about this domain.
+ * XXX For now, just use the first address in the list.
+ */
+
+ if (servPtr->addrList != NULL) {
+ servAddrPtr = (struct in_addr *) servPtr->addrList[0];
+ } else {
+ servAddrPtr = (struct in_addr *) servPtr->servers[0]->addrList[0];
+ }
+
+ /*
+ * RFC1123 says we "SHOULD check the string syntactically for a
+ * dotted-decimal number before looking it up [...]" (p. 13).
+ */
+ if (queryType == T_A && IsAddr(host, &addr)) {
+ result = GetHostInfoByAddr(servAddrPtr, &addr, &curHostInfo);
+ } else {
+ if (queryType == T_PTR) {
+ CvtAddrToPtr(host);
+ }
+ result = GetHostInfoByName(servAddrPtr, queryClass, queryType, host,
+ &curHostInfo, 0);
+ }
+
+ switch (result) {
+ case SUCCESS:
+ /*
+ * If the query was for an address, then the &curHostInfo
+ * variable can be used by Finger.
+ * There's no need to print anything for other query types
+ * because the info has already been printed.
+ */
+ if (queryType == T_A) {
+ curHostValid = TRUE;
+ PrintHostInfo(filePtr, "Name:", &curHostInfo);
+ }
+ break;
+
+ /*
+ * No Authoritative answer was available but we got names
+ * of servers who know about the host.
+ */
+ case NONAUTH:
+ PrintHostInfo(filePtr, "Name:", &curHostInfo);
+ break;
+
+ case NO_INFO:
+ fprintf(stderr, "*** No %s (%s) records available for %s\n",
+ DecodeType(queryType), p_type(queryType), host);
+ break;
+
+ case TIME_OUT:
+ fprintf(stderr, "*** Request to %s timed-out\n", serverName);
+ break;
+
+ default:
+ fprintf(stderr, "*** %s can't find %s: %s\n", serverName, host,
+ DecodeError(result));
+ }
+ return result;
+}
+
+/*
+ ******************************************************************************
+ *
+ * LookupHost --
+ *
+ * Asks the default name server for information about the
+ * specified host or domain. The information is printed
+ * if the lookup was successful.
+ *
+ * Results:
+ * ERROR - the output file could not be opened.
+ * + results of DoLookup
+ *
+ ******************************************************************************
+ */
+
+int
+LookupHost(string, putToFile)
+ char *string;
+ Boolean putToFile;
+{
+ char host[NAME_LEN];
+ char file[PATH_MAX];
+ int result;
+
+ /*
+ * Invalidate the current host information to prevent Finger
+ * from using bogus info.
+ */
+
+ curHostValid = FALSE;
+
+ /*
+ * Parse the command string into the host and
+ * optional output file name.
+ *
+ */
+
+ sscanf(string, " %s", host); /* removes white space */
+ if (!putToFile) {
+ filePtr = stdout;
+ } else {
+ filePtr = OpenFile(string, file);
+ if (filePtr == NULL) {
+ fprintf(stderr, "*** Can't open %s for writing\n", file);
+ return(ERROR);
+ }
+ fprintf(filePtr,"> %s\n", string);
+ }
+
+ PrintHostInfo(filePtr, "Server:", defaultPtr);
+
+ result = DoLookup(host, defaultPtr, defaultServer);
+
+ if (putToFile) {
+ fclose(filePtr);
+ filePtr = NULL;
+ }
+ return(result);
+}
+
+/*
+ ******************************************************************************
+ *
+ * LookupHostWithServer --
+ *
+ * Asks the name server specified in the second argument for
+ * information about the host or domain specified in the first
+ * argument. The information is printed if the lookup was successful.
+ *
+ * Address info about the requested name server is obtained
+ * from the default name server. This routine will return an
+ * error if the default server doesn't have info about the
+ * requested server. Thus an error return status might not
+ * mean the requested name server doesn't have info about the
+ * requested host.
+ *
+ * Comments from LookupHost apply here, too.
+ *
+ * Results:
+ * ERROR - the output file could not be opened.
+ * + results of DoLookup
+ *
+ ******************************************************************************
+ */
+
+int
+LookupHostWithServer(string, putToFile)
+ char *string;
+ Boolean putToFile;
+{
+ char file[PATH_MAX];
+ char host[NAME_LEN];
+ char server[NAME_LEN];
+ int result;
+ static HostInfo serverInfo;
+
+ curHostValid = FALSE;
+
+ sscanf(string, " %s %s", host, server);
+ if (!putToFile) {
+ filePtr = stdout;
+ } else {
+ filePtr = OpenFile(string, file);
+ if (filePtr == NULL) {
+ fprintf(stderr, "*** Can't open %s for writing\n", file);
+ return(ERROR);
+ }
+ fprintf(filePtr,"> %s\n", string);
+ }
+
+ result = GetHostInfoByName(
+ defaultPtr->addrList ?
+ (struct in_addr *) defaultPtr->addrList[0] :
+ (struct in_addr *) defaultPtr->servers[0]->addrList[0],
+ C_IN, T_A, server, &serverInfo, 1);
+
+ if (result != SUCCESS) {
+ fprintf(stderr,"*** Can't find address for server %s: %s\n", server,
+ DecodeError(result));
+ } else {
+ PrintHostInfo(filePtr, "Server:", &serverInfo);
+
+ result = DoLookup(host, &serverInfo, server);
+ }
+ if (putToFile) {
+ fclose(filePtr);
+ filePtr = NULL;
+ }
+ return(result);
+}
+
+/*
+ ******************************************************************************
+ *
+ * SetOption --
+ *
+ * This routine is used to change the state information
+ * that affect the lookups. The command format is
+ * set keyword[=value]
+ * Most keywords can be abbreviated. Parsing is very simplistic--
+ * A value must not be separated from its keyword by white space.
+ *
+ * Valid keywords: Meaning:
+ * all lists current values of options.
+ * ALL lists current values of options, including
+ * hidden options.
+ * [no]d2 turn on/off extra debugging mode.
+ * [no]debug turn on/off debugging mode.
+ * [no]defname use/don't use default domain name.
+ * [no]search use/don't use domain search list.
+ * domain=NAME set default domain name to NAME.
+ * [no]ignore ignore/don't ignore trunc. errors.
+ * query=value set default query type to value,
+ * value is one of the query types in RFC883
+ * without the leading T_. (e.g., A, HINFO)
+ * [no]recurse use/don't use recursive lookup.
+ * retry=# set number of retries to #.
+ * root=NAME change root server to NAME.
+ * time=# set timeout length to #.
+ * [no]vc use/don't use virtual circuit.
+ * port TCP/UDP port to server.
+ *
+ * Deprecated:
+ * [no]primary use/don't use primary server.
+ *
+ * Results:
+ * SUCCESS the command was parsed correctly.
+ * ERROR the command was not parsed correctly.
+ *
+ ******************************************************************************
+ */
+
+int
+SetOption(option)
+ register char *option;
+{
+ char type[NAME_LEN];
+ char *ptr;
+ int tmp;
+
+ while (isspace(*option))
+ ++option;
+ if (strncmp (option, "set ", 4) == 0)
+ option += 4;
+ while (isspace(*option))
+ ++option;
+
+ if (*option == 0) {
+ fprintf(stderr, "*** Invalid set command\n");
+ return(ERROR);
+ } else {
+ if (strncmp(option, "all", 3) == 0) {
+ ShowOptions();
+ } else if (strncmp(option, "ALL", 3) == 0) {
+ ShowOptions();
+ } else if (strncmp(option, "d2", 2) == 0) { /* d2 (more debug) */
+ _res.options |= (RES_DEBUG | RES_DEBUG2);
+ } else if (strncmp(option, "nod2", 4) == 0) {
+ _res.options &= ~RES_DEBUG2;
+ printf("d2 mode disabled; still in debug mode\n");
+ } else if (strncmp(option, "def", 3) == 0) { /* defname */
+ _res.options |= RES_DEFNAMES;
+ } else if (strncmp(option, "nodef", 5) == 0) {
+ _res.options &= ~RES_DEFNAMES;
+ } else if (strncmp(option, "do", 2) == 0) { /* domain */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%s", _res.defdname);
+ res_re_init();
+ }
+ } else if (strncmp(option, "deb", 1) == 0) { /* debug */
+ _res.options |= RES_DEBUG;
+ } else if (strncmp(option, "nodeb", 5) == 0) {
+ _res.options &= ~(RES_DEBUG | RES_DEBUG2);
+ } else if (strncmp(option, "ig", 2) == 0) { /* ignore */
+ _res.options |= RES_IGNTC;
+ } else if (strncmp(option, "noig", 4) == 0) {
+ _res.options &= ~RES_IGNTC;
+ } else if (strncmp(option, "po", 2) == 0) { /* port */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%hu", &nsport);
+ }
+#ifdef deprecated
+ } else if (strncmp(option, "pri", 3) == 0) { /* primary */
+ _res.options |= RES_PRIMARY;
+ } else if (strncmp(option, "nopri", 5) == 0) {
+ _res.options &= ~RES_PRIMARY;
+#endif
+ } else if (strncmp(option, "q", 1) == 0 || /* querytype */
+ strncmp(option, "ty", 2) == 0) { /* type */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%s", type);
+ queryType = StringToType(type, queryType, stderr);
+ }
+ } else if (strncmp(option, "cl", 2) == 0) { /* query class */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%s", type);
+ queryClass = StringToClass(type, queryClass, stderr);
+ }
+ } else if (strncmp(option, "rec", 3) == 0) { /* recurse */
+ _res.options |= RES_RECURSE;
+ } else if (strncmp(option, "norec", 5) == 0) {
+ _res.options &= ~RES_RECURSE;
+ } else if (strncmp(option, "ret", 3) == 0) { /* retry */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%d", &tmp);
+ if (tmp >= 0) {
+ _res.retry = tmp;
+ }
+ }
+ } else if (strncmp(option, "ro", 2) == 0) { /* root */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%s", rootServerName);
+ }
+ } else if (strncmp(option, "sea", 3) == 0) { /* search list */
+ _res.options |= RES_DNSRCH;
+ } else if (strncmp(option, "nosea", 5) == 0) {
+ _res.options &= ~RES_DNSRCH;
+ } else if (strncmp(option, "srchl", 5) == 0) { /* domain search list */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ res_dnsrch(++ptr);
+ }
+ } else if (strncmp(option, "ti", 2) == 0) { /* timeout */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%d", &tmp);
+ if (tmp >= 0) {
+ _res.retrans = tmp;
+ }
+ }
+ } else if (strncmp(option, "v", 1) == 0) { /* vc */
+ _res.options |= RES_USEVC;
+ } else if (strncmp(option, "nov", 3) == 0) {
+ _res.options &= ~RES_USEVC;
+ } else {
+ fprintf(stderr, "*** Invalid option: %s\n", option);
+ return(ERROR);
+ }
+ }
+ return(SUCCESS);
+}
+
+/*
+ * Fake a reinitialization when the domain is changed.
+ */
+res_re_init()
+{
+ register char *cp, **pp;
+ int n;
+
+ /* find components of local domain that might be searched */
+ pp = _res.dnsrch;
+ *pp++ = _res.defdname;
+ for (cp = _res.defdname, n = 0; *cp; cp++)
+ if (*cp == '.')
+ n++;
+ cp = _res.defdname;
+ for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH; n--) {
+ cp = strchr(cp, '.');
+ *pp++ = ++cp;
+ }
+ *pp = 0;
+ _res.options |= RES_INIT;
+}
+
+#define SRCHLIST_SEP '/'
+
+res_dnsrch(cp)
+ register char *cp;
+{
+ register char **pp;
+ int n;
+
+ (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
+ if ((cp = strchr(_res.defdname, '\n')) != NULL)
+ *cp = '\0';
+ /*
+ * Set search list to be blank-separated strings
+ * on rest of line.
+ */
+ cp = _res.defdname;
+ pp = _res.dnsrch;
+ *pp++ = cp;
+ for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
+ if (*cp == SRCHLIST_SEP) {
+ *cp = '\0';
+ n = 1;
+ } else if (n) {
+ *pp++ = cp;
+ n = 0;
+ }
+ }
+ if ((cp = strchr(pp[-1], SRCHLIST_SEP)) != NULL) {
+ *cp = '\0';
+ }
+ *pp = NULL;
+}
+
+
+/*
+ ******************************************************************************
+ *
+ * ShowOptions --
+ *
+ * Prints out the state information used by the resolver
+ * library and other options set by the user.
+ *
+ ******************************************************************************
+ */
+
+void
+ShowOptions()
+{
+ register char **cp;
+
+ PrintHostInfo(stdout, "Default Server:", defaultPtr);
+ if (curHostValid) {
+ PrintHostInfo(stdout, "Host:", &curHostInfo);
+ }
+
+ printf("Set options:\n");
+ printf(" %sdebug \t", (_res.options & RES_DEBUG) ? "" : "no");
+ printf(" %sdefname\t", (_res.options & RES_DEFNAMES) ? "" : "no");
+ printf(" %ssearch\t", (_res.options & RES_DNSRCH) ? "" : "no");
+ printf(" %srecurse\n", (_res.options & RES_RECURSE) ? "" : "no");
+
+ printf(" %sd2\t\t", (_res.options & RES_DEBUG2) ? "" : "no");
+ printf(" %svc\t\t", (_res.options & RES_USEVC) ? "" : "no");
+ printf(" %signoretc\t", (_res.options & RES_IGNTC) ? "" : "no");
+ printf(" port=%u\n", nsport);
+
+ printf(" querytype=%s\t", p_type(queryType));
+ printf(" class=%s\t", p_class(queryClass));
+ printf(" timeout=%d\t", _res.retrans);
+ printf(" retry=%d\n", _res.retry);
+ printf(" root=%s\n", rootServerName);
+ printf(" domain=%s\n", _res.defdname);
+
+ if (cp = _res.dnsrch) {
+ printf(" srchlist=%s", *cp);
+ for (cp++; *cp; cp++) {
+ printf("%c%s", SRCHLIST_SEP, *cp);
+ }
+ putchar('\n');
+ }
+ putchar('\n');
+}
+#undef SRCHLIST_SEP
+
+/*
+ ******************************************************************************
+ *
+ * PrintHelp --
+ *
+ * Displays the help file.
+ *
+ ******************************************************************************
+ */
+
+void
+PrintHelp()
+{
+ char cmd[PATH_MAX];
+
+ sprintf(cmd, "%s %s", pager, _PATH_HELPFILE);
+ system(cmd);
+}
+
+/*
+ ******************************************************************************
+ *
+ * CvtAddrToPtr --
+ *
+ * Convert a dotted-decimal Internet address into the standard
+ * PTR format (reversed address with .in-arpa. suffix).
+ *
+ * Assumes the argument buffer is large enougth to hold the result.
+ *
+ ******************************************************************************
+ */
+
+static void
+CvtAddrToPtr(name)
+ char *name;
+{
+ char *p;
+ int ip[4];
+ struct in_addr addr;
+
+ if (IsAddr(name, &addr)) {
+ p = inet_ntoa(addr);
+ if (sscanf(p, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]) == 4) {
+ sprintf(name, "%d.%d.%d.%d.in-addr.arpa.",
+ ip[3], ip[2], ip[1], ip[0]);
+ }
+ }
+}
+
+/*
+ ******************************************************************************
+ *
+ * ReadRC --
+ *
+ * Use the contents of ~/.nslookuprc as options.
+ *
+ ******************************************************************************
+ */
+
+static void
+ReadRC()
+{
+ register FILE *fp;
+ register char *cp;
+ char buf[PATH_MAX];
+
+ if ((cp = getenv("HOME")) != NULL) {
+ (void) strcpy(buf, cp);
+ (void) strcat(buf, _PATH_NSLOOKUPRC);
+
+ if ((fp = fopen(buf, "r")) != NULL) {
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ if ((cp = strchr(buf, '\n')) != NULL) {
+ *cp = '\0';
+ }
+ (void) SetOption(buf);
+ }
+ (void) fclose(fp);
+ }
+ }
+}
diff --git a/usr.sbin/named/nslookup/nslookup.help b/usr.sbin/named/nslookup/nslookup.help
new file mode 100644
index 00000000000..cbc914c62ec
--- /dev/null
+++ b/usr.sbin/named/nslookup/nslookup.help
@@ -0,0 +1,34 @@
+$NetBSD: nslookup.help,v 1.1 1996/02/02 15:30:17 mrg Exp $
+from: $Id: nslookup.help,v 8.2 1995/06/29 09:26:34 vixie Exp
+
+Commands: (identifiers are shown in uppercase, [] means optional)
+NAME - print info about the host/domain NAME using default server
+NAME1 NAME2 - as above, but use NAME2 as server
+help or ? - print info on common commands; see nslookup(1) for details
+set OPTION - set an option
+ all - print options, current server and host
+ [no]debug - print debugging information
+ [no]d2 - print exhaustive debugging information
+ [no]defname - append domain name to each query
+ [no]recurse - ask for recursive answer to query
+ [no]vc - always use a virtual circuit
+ domain=NAME - set default domain name to NAME
+ srchlist=N1[/N2/.../N6] - set domain to N1 and search list to N1,N2, etc.
+ root=NAME - set root server to NAME
+ retry=X - set number of retries to X
+ timeout=X - set initial time-out interval to X seconds
+ querytype=X - set query type, e.g., A,ANY,CNAME,HINFO,MX,PX,NS,PTR,SOA,TXT,WKS
+ type=X - synonym for querytype
+ class=X - set query class to one of IN (Internet), CHAOS, HESIOD or ANY
+server NAME - set default server to NAME, using current default server
+lserver NAME - set default server to NAME, using initial server
+finger [USER] - finger the optional USER at the current default host
+root - set current default server to the root
+ls [opt] DOMAIN [> FILE] - list addresses in DOMAIN (optional: output to FILE)
+ -a - list canonical names and aliases
+ -h - list HINFO (CPU type and operating system)
+ -s - list well-known services
+ -d - list all records
+ -t TYPE - list records of the given type (e.g., A,CNAME,MX, etc.)
+view FILE - sort an 'ls' output file and view it with more
+exit - exit the program, ^D also exits
diff --git a/usr.sbin/named/nslookup/pathnames.h b/usr.sbin/named/nslookup/pathnames.h
new file mode 100644
index 00000000000..2f8ba319872
--- /dev/null
+++ b/usr.sbin/named/nslookup/pathnames.h
@@ -0,0 +1,73 @@
+/* $NetBSD: pathnames.h,v 1.1 1996/02/02 15:30:21 mrg Exp $ */
+
+/*
+ * ++Copyright++ 1990
+ * -
+ * Copyright (c) 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--
+ */
+
+/*
+ * @(#)pathnames.h 5.1 (Berkeley) 5/28/90
+ * $Id: pathnames.h,v 8.1 1994/12/15 06:24:31 vixie Exp
+ */
+
+#define _PATH_NSLOOKUPRC "/.nslookuprc"
+#define _PATH_PAGERCMD "more"
+
+#ifndef _PATH_HELPFILE
+#if defined(BSD) && BSD >= 198810
+#define _PATH_HELPFILE "/usr/share/misc/nslookup.help"
+#else
+#define _PATH_HELPFILE "/usr/lib/nslookup.help"
+#endif
+#endif
+
diff --git a/usr.sbin/named/nslookup/res.h b/usr.sbin/named/nslookup/res.h
new file mode 100644
index 00000000000..d2e42a5c105
--- /dev/null
+++ b/usr.sbin/named/nslookup/res.h
@@ -0,0 +1,174 @@
+/* $NetBSD: res.h,v 1.1 1996/02/02 15:30:25 mrg Exp $ */
+
+/*
+ * ++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--
+ */
+
+/*
+ * @(#)res.h 5.10 (Berkeley) 6/1/90
+ * $Id: res.h,v 8.1 1994/12/15 06:24:31 vixie Exp
+ */
+
+/*
+ *******************************************************************************
+ *
+ * res.h --
+ *
+ * Definitions used by modules of the name server lookup program.
+ *
+ * Copyright (c) 1985
+ * Andrew Cherenson
+ * U.C. Berkeley
+ * CS298-26 Fall 1985
+ *
+ *******************************************************************************
+ */
+
+#define TRUE 1
+#define FALSE 0
+typedef int Boolean;
+
+/*
+ * Define return statuses in addtion to the ones defined in namserv.h
+ * let SUCCESS be a synonym for NOERROR
+ *
+ * TIME_OUT - a socket connection timed out.
+ * NO_INFO - the server didn't find any info about the host.
+ * ERROR - one of the following types of errors:
+ * dn_expand, res_mkquery failed
+ * bad command line, socket operation failed, etc.
+ * NONAUTH - the server didn't have the desired info but
+ * returned the name(s) of some servers who should.
+ * NO_RESPONSE - the server didn't respond.
+ *
+ */
+
+#define SUCCESS 0
+#define TIME_OUT -1
+#define NO_INFO -2
+#define ERROR -3
+#define NONAUTH -4
+#define NO_RESPONSE -5
+
+/*
+ * Define additional options for the resolver state structure.
+ *
+ * RES_DEBUG2 more verbose debug level
+ */
+
+#define RES_DEBUG2 0x80000000
+
+/*
+ * Maximum length of server, host and file names.
+ */
+
+#define NAME_LEN 256
+
+
+/*
+ * Modified struct hostent from <netdb.h>
+ *
+ * "Structures returned by network data base library. All addresses
+ * are supplied in host order, and returned in network order (suitable
+ * for use in system calls)."
+ */
+
+typedef struct {
+ char *name; /* official name of host */
+ char **domains; /* domains it serves */
+ char **addrList; /* list of addresses from name server */
+} ServerInfo;
+
+typedef struct {
+ char *name; /* official name of host */
+ char **aliases; /* alias list */
+ char **addrList; /* list of addresses from name server */
+ int addrType; /* host address type */
+ int addrLen; /* length of address */
+ ServerInfo **servers;
+} HostInfo;
+
+
+/*
+ * FilePtr is used for directing listings to a file.
+ * It is global so the Control-C handler can close it.
+ */
+
+extern FILE *filePtr;
+
+/*
+ * TCP/UDP port of server.
+ */
+extern unsigned short nsport;
+
+/*
+ * External routines:
+ */
+
+extern Boolean IsAddr();
+extern int Print_query();
+extern unsigned char *Print_cdname();
+extern unsigned char *Print_cdname2(); /* fixed width */
+extern unsigned char *Print_rr();
+extern char *DecodeType(); /* descriptive version of p_type */
+extern char *DecodeError();
+extern char *Calloc();
+extern char *Malloc();
+extern void NsError();
+extern void PrintServer();
+extern void PrintHostInfo();
+extern void ShowOptions();
+extern void FreeHostInfoPtr();
+extern FILE *OpenFile();
+extern char *res_skip();
diff --git a/usr.sbin/named/nslookup/send.c b/usr.sbin/named/nslookup/send.c
new file mode 100644
index 00000000000..6e3793a0320
--- /dev/null
+++ b/usr.sbin/named/nslookup/send.c
@@ -0,0 +1,414 @@
+/* $NetBSD: send.c,v 1.1 1996/02/02 15:30:27 mrg Exp $ */
+
+/*
+ * ++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--
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)send.c 5.18 (Berkeley) 3/2/91";
+static char rcsid[] = "$Id: send.c,v 8.1 1994/12/15 06:24:31 vixie Exp ";
+#endif /* not lint */
+
+/*
+ ******************************************************************************
+ *
+ * send.c --
+ *
+ * Routine to send request packets to a name server.
+ *
+ * Based on "@(#)res_send.c 6.25 (Berkeley) 6/1/90".
+ *
+ ******************************************************************************
+ */
+
+
+/*
+ * Send query to name server and wait for reply.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <errno.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include "res.h"
+#include "conf/portability.h"
+
+static int s = -1; /* socket used for communications */
+
+
+#ifndef FD_SET
+#define NFDBITS 32
+#define FD_SETSIZE 32
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
+#endif
+
+
+
+unsigned short nsport = NAMESERVER_PORT;
+
+
+
+/*
+ ******************************************************************************
+ *
+ * SendRequest --
+ *
+ * Sends a request packet to a name server whose address
+ * is specified by the first argument and returns with
+ * the answer packet.
+ *
+ * Results:
+ * SUCCESS - the request was sent and an answer
+ * was received.
+ * TIME_OUT - the virtual circuit connection timed-out
+ * or a reply to a datagram wasn't received.
+ *
+ *
+ ******************************************************************************
+ */
+
+int
+SendRequest(nsAddrPtr, buf, buflen, answer, anslen, trueLenPtr)
+ struct in_addr *nsAddrPtr;
+ char *buf;
+ int buflen;
+ char *answer;
+ u_int anslen;
+ int *trueLenPtr;
+{
+ register int n;
+ int try, v_circuit, resplen;
+ int gotsomewhere = 0, connected = 0;
+ int connreset = 0;
+ u_short id, len;
+ char *cp;
+ fd_set dsmask;
+ struct timeval timeout;
+ HEADER *hp = (HEADER *) buf;
+ HEADER *anhp = (HEADER *) answer;
+ struct iovec iov[2];
+ int terrno = ETIMEDOUT;
+ char junk[512];
+ struct sockaddr_in sin;
+
+ if (_res.options & RES_DEBUG2) {
+ printf("------------\nSendRequest(), len %d\n", buflen);
+ Print_query(buf, buf+buflen, 1);
+ }
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(nsport);
+ sin.sin_addr = *nsAddrPtr;
+ v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
+ id = hp->id;
+ /*
+ * Send request, RETRY times, or until successful
+ */
+ for (try = 0; try < _res.retry; try++) {
+ usevc:
+ if (v_circuit) {
+ int truncated = 0;
+
+ /*
+ * Use virtual circuit;
+ * at most one attempt per server.
+ */
+ try = _res.retry;
+ if (s < 0) {
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ terrno = errno;
+ if (_res.options & RES_DEBUG)
+ perror("socket (vc) failed");
+ continue;
+ }
+ if (connect(s, (struct sockaddr *)&sin,
+ sizeof(struct sockaddr)) < 0) {
+ terrno = errno;
+ if (_res.options & RES_DEBUG)
+ perror("connect failed");
+ (void) close(s);
+ s = -1;
+ continue;
+ }
+ }
+ /*
+ * Send length & message
+ */
+ __putshort(buflen, (u_char *)&len);
+ iov[0].iov_base = (caddr_t)&len;
+ iov[0].iov_len = INT16SZ;
+ iov[1].iov_base = buf;
+ iov[1].iov_len = buflen;
+ if (writev(s, iov, 2) != INT16SZ + buflen) {
+ terrno = errno;
+ if (_res.options & RES_DEBUG)
+ perror("write failed");
+ (void) close(s);
+ s = -1;
+ continue;
+ }
+ /*
+ * Receive length & response
+ */
+ cp = answer;
+ len = INT16SZ;
+ while ((n = read(s, (char *)cp, (int)len)) > 0) {
+ cp += n;
+ if ((len -= n) <= 0)
+ break;
+ }
+ if (n <= 0) {
+ terrno = errno;
+ if (_res.options & RES_DEBUG)
+ perror("read failed");
+ (void) close(s);
+ s = -1;
+ /*
+ * A long running process might get its TCP
+ * connection reset if the remote server was
+ * restarted. Requery the server instead of
+ * trying a new one. When there is only one
+ * server, this means that a query might work
+ * instead of failing. We only allow one reset
+ * per query to prevent looping.
+ */
+ if (terrno == ECONNRESET && !connreset) {
+ connreset = 1;
+ }
+ continue;
+ }
+ cp = answer;
+ if ((resplen = _getshort((u_char*)cp)) > anslen) {
+ if (_res.options & RES_DEBUG)
+ fprintf(stderr, "response truncated\n");
+ len = anslen;
+ truncated = 1;
+ } else
+ len = resplen;
+ while (len != 0 &&
+ (n = read(s, (char *)cp, (int)len)) > 0) {
+ cp += n;
+ len -= n;
+ }
+ if (n <= 0) {
+ terrno = errno;
+ if (_res.options & RES_DEBUG)
+ perror("read failed");
+ (void) close(s);
+ s = -1;
+ continue;
+ }
+ if (truncated) {
+ /*
+ * Flush rest of answer
+ * so connection stays in synch.
+ */
+ anhp->tc = 1;
+ len = resplen - anslen;
+ while (len != 0) {
+ n = (len > sizeof(junk) ?
+ sizeof(junk) : len);
+ if ((n = read(s, junk, n)) > 0)
+ len -= n;
+ else
+ break;
+ }
+ }
+ } else {
+ /*
+ * Use datagrams.
+ */
+ if (s < 0) {
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ terrno = errno;
+ if (_res.options & RES_DEBUG)
+ perror("socket (dg) failed");
+ continue;
+ }
+ }
+#if BSD >= 43
+ if (connected == 0) {
+ if (connect(s, (struct sockaddr *)&sin,
+ sizeof(struct sockaddr)) < 0) {
+ if (_res.options & RES_DEBUG)
+ perror("connect");
+ continue;
+ }
+ connected = 1;
+ }
+ if (send(s, buf, buflen, 0) != buflen) {
+ if (_res.options & RES_DEBUG)
+ perror("send");
+ continue;
+ }
+#else /* BSD */
+ if (sendto(s, buf, buflen, 0,
+ (struct sockaddr *) &sin,
+ sizeof(sin)) != buflen) {
+ if (_res.options & RES_DEBUG)
+ perror("sendto");
+ continue;
+ }
+#endif
+
+ /*
+ * Wait for reply
+ */
+ timeout.tv_sec = (_res.retrans << try);
+ if (timeout.tv_sec <= 0)
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+wait:
+ FD_ZERO(&dsmask);
+ FD_SET(s, &dsmask);
+ n = select(s+1, &dsmask, (fd_set *)NULL,
+ (fd_set *)NULL, &timeout);
+ if (n < 0) {
+ if (_res.options & RES_DEBUG)
+ perror("select");
+ continue;
+ }
+ if (n == 0) {
+ /*
+ * timeout
+ */
+ if (_res.options & RES_DEBUG)
+ printf("timeout (%d secs)\n",
+ timeout.tv_sec);
+#if BSD >= 43
+ gotsomewhere = 1;
+#endif
+ continue;
+ }
+ if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
+ if (_res.options & RES_DEBUG)
+ perror("recvfrom");
+ continue;
+ }
+ gotsomewhere = 1;
+ if (id != anhp->id) {
+ /*
+ * response from old query, ignore it
+ */
+ if (_res.options & RES_DEBUG2) {
+ printf("------------\nOld answer:\n");
+ Print_query(answer, answer+resplen, 1);
+ }
+ goto wait;
+ }
+ if (!(_res.options & RES_IGNTC) && anhp->tc) {
+ /*
+ * get rest of answer;
+ * use TCP with same server.
+ */
+ if (_res.options & RES_DEBUG)
+ printf("truncated answer\n");
+ (void) close(s);
+ s = -1;
+ v_circuit = 1;
+ goto usevc;
+ }
+ }
+ if (_res.options & RES_DEBUG) {
+ if (_res.options & RES_DEBUG2)
+ printf("------------\nGot answer (%d bytes):\n",
+ resplen);
+ else
+ printf("------------\nGot answer:\n");
+ Print_query(answer, answer+resplen, 1);
+ }
+ (void) close(s);
+ s = -1;
+ *trueLenPtr = resplen;
+ return (SUCCESS);
+ }
+ if (s >= 0) {
+ (void) close(s);
+ s = -1;
+ }
+ if (v_circuit == 0)
+ if (gotsomewhere == 0)
+ return NO_RESPONSE; /* no nameservers found */
+ else
+ return TIME_OUT; /* no answer obtained */
+ else
+ if (errno == ECONNREFUSED)
+ return NO_RESPONSE;
+ else
+ return ERROR;
+}
+
+/*
+ * This routine is for closing the socket if a virtual circuit is used and
+ * the program wants to close it.
+ *
+ * Called from the interrupt handler.
+ */
+SendRequest_close()
+{
+ if (s != -1) {
+ (void) close(s);
+ s = -1;
+ }
+}
diff --git a/usr.sbin/named/nslookup/skip.c b/usr.sbin/named/nslookup/skip.c
new file mode 100644
index 00000000000..c8abdd1d7aa
--- /dev/null
+++ b/usr.sbin/named/nslookup/skip.c
@@ -0,0 +1,213 @@
+/* $NetBSD: skip.c,v 1.1 1996/02/02 15:30:28 mrg Exp $ */
+
+/*
+ * ++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--
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)skip.c 5.12 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: skip.c,v 8.1 1994/12/15 06:24:31 vixie Exp ";
+#endif /* not lint */
+
+/*
+ *******************************************************************************
+ *
+ * skip.c --
+ *
+ * Routines to skip over portions of a query buffer.
+ *
+ * Note: this file has been submitted for inclusion in
+ * BIND resolver library. When this has been done, this file
+ * is no longer necessary (assuming there haven't been any
+ * changes).
+ *
+ * Adapted from 4.3BSD BIND res_debug.c
+ *
+ *******************************************************************************
+ */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdio.h>
+#include "conf/portability.h"
+
+char *res_skip_rr();
+
+
+/*
+ *******************************************************************************
+ *
+ * res_skip --
+ *
+ * Skip the contents of a query.
+ *
+ * Interpretation of numFieldsToSkip argument:
+ * res_skip returns pointer to:
+ * 1 -> start of question records.
+ * 2 -> start of authoritative answer records.
+ * 3 -> start of additional records.
+ * 4 -> first byte after end of additional records.
+ *
+ * Results:
+ * (address) - success operation.
+ * NULL - a resource record had an incorrect format.
+ *
+ *******************************************************************************
+ */
+
+char *
+res_skip(msg, numFieldsToSkip, eom)
+ char *msg;
+ int numFieldsToSkip;
+ char *eom;
+{
+ register char *cp;
+ register HEADER *hp;
+ register int tmp;
+ register int n;
+
+ /*
+ * Skip the header fields.
+ */
+ hp = (HEADER *)msg;
+ cp = msg + HFIXEDSZ;
+
+ /*
+ * skip question records.
+ */
+ if (n = ntohs(hp->qdcount) ) {
+ while (--n >= 0 && cp < eom) {
+ tmp = dn_skipname((u_char *)cp, (u_char *)eom);
+ if (tmp == -1) return(NULL);
+ cp += tmp;
+ cp += INT16SZ; /* type */
+ cp += INT16SZ; /* class */
+ }
+ }
+ if (--numFieldsToSkip <= 0) return(cp);
+
+ /*
+ * skip authoritative answer records
+ */
+ if (n = ntohs(hp->ancount)) {
+ while (--n >= 0 && cp < eom) {
+ cp = res_skip_rr(cp, eom);
+ if (cp == NULL) return(NULL);
+ }
+ }
+ if (--numFieldsToSkip == 0) return(cp);
+
+ /*
+ * skip name server records
+ */
+ if (n = ntohs(hp->nscount)) {
+ while (--n >= 0 && cp < eom) {
+ cp = res_skip_rr(cp, eom);
+ if (cp == NULL) return(NULL);
+ }
+ }
+ if (--numFieldsToSkip == 0) return(cp);
+
+ /*
+ * skip additional records
+ */
+ if (n = ntohs(hp->arcount)) {
+ while (--n >= 0 && cp < eom) {
+ cp = res_skip_rr(cp, eom);
+ if (cp == NULL) return(NULL);
+ }
+ }
+
+ return(cp);
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * res_skip_rr --
+ *
+ * Skip over resource record fields.
+ *
+ * Results:
+ * (address) - success operation.
+ * NULL - a resource record had an incorrect format.
+ *******************************************************************************
+ */
+
+char *
+res_skip_rr(cp, eom)
+ char *cp;
+ char *eom;
+{
+ int tmp;
+ int dlen;
+
+ if ((tmp = dn_skipname((u_char *)cp, (u_char *)eom)) == -1)
+ return (NULL); /* compression error */
+ cp += tmp;
+ if ((cp + RRFIXEDSZ) > eom)
+ return (NULL);
+ cp += INT16SZ; /* type */
+ cp += INT16SZ; /* class */
+ cp += INT32SZ; /* ttl */
+ dlen = _getshort((u_char*)cp);
+ cp += INT16SZ; /* dlen */
+ cp += dlen;
+ if (cp > eom)
+ return (NULL);
+ return (cp);
+}
diff --git a/usr.sbin/named/nslookup/subr.c b/usr.sbin/named/nslookup/subr.c
new file mode 100644
index 00000000000..fd8a548ca73
--- /dev/null
+++ b/usr.sbin/named/nslookup/subr.c
@@ -0,0 +1,581 @@
+/* $NetBSD: subr.c,v 1.1 1996/02/02 15:30:30 mrg Exp $ */
+
+/*
+ * ++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--
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)subr.c 5.24 (Berkeley) 3/2/91";
+static char rcsid[] = "$Id: subr.c,v 8.4 1995/12/03 08:31:19 vixie Exp ";
+#endif /* not lint */
+
+/*
+ *******************************************************************************
+ *
+ * subr.c --
+ *
+ * Miscellaneous subroutines for the name server
+ * lookup program.
+ *
+ * Copyright (c) 1985
+ * Andrew Cherenson
+ * U.C. Berkeley
+ * CS298-26 Fall 1985
+ *
+ *******************************************************************************
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include "res.h"
+#include "conf/portability.h"
+
+
+
+/*
+ *******************************************************************************
+ *
+ * IntrHandler --
+ *
+ * This routine is called whenever a control-C is typed.
+ * It performs three main functions:
+ * - closes an open socket connection,
+ * - closes an open output file (used by LookupHost, et al.),
+ * - jumps back to the main read-eval loop.
+ *
+ * If a user types a ^C in the middle of a routine that uses a socket,
+ * the routine would not be able to close the socket. To prevent an
+ * overflow of the process's open file table, the socket and output
+ * file descriptors are closed by the interrupt handler.
+ *
+ * Side effects:
+ * Open file descriptors are closed.
+ * If filePtr is valid, it is closed.
+ * Flow of control returns to the main() routine.
+ *
+ *******************************************************************************
+ */
+
+SIG_FN
+IntrHandler()
+{
+ extern jmp_buf env;
+#if defined(BSD) && BSD >= 199006 && !defined(RISCOS_BSD) && !defined(__osf__)
+ extern FILE *yyin; /* scanner input file */
+ extern void yyrestart(); /* routine to restart scanner after interrupt */
+#endif
+
+ SendRequest_close();
+ ListHost_close();
+ if (filePtr != NULL && filePtr != stdout) {
+ fclose(filePtr);
+ filePtr = NULL;
+ }
+ printf("\n");
+#if defined(BSD) && BSD >= 199006 && !defined(RISCOS_BSD) && !defined(__osf__)
+ yyrestart(yyin);
+#endif
+ longjmp(env, 1);
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * Malloc --
+ * Calloc --
+ *
+ * Calls the malloc library routine with SIGINT blocked to prevent
+ * corruption of malloc's data structures. We need to do this because
+ * a control-C doesn't kill the program -- it causes a return to the
+ * main command loop.
+ *
+ * NOTE: This method doesn't prevent the pointer returned by malloc
+ * from getting lost, so it is possible to get "core leaks".
+ *
+ * If malloc fails, the program exits.
+ *
+ * Results:
+ * (address) - address of new buffer.
+ *
+ *******************************************************************************
+ */
+
+char *
+Malloc(size)
+ int size;
+{
+ char *ptr;
+
+#ifdef SYSV
+#if defined(SVR3) || defined(SVR4)
+ sighold(SIGINT);
+ ptr = malloc((unsigned) size);
+ sigrelse(SIGINT);
+#else
+ { SIG_FN (*old)();
+ old = signal(SIGINT, SIG_IGN);
+ ptr = malloc((unsigned) size);
+ signal(SIGINT, old);
+ }
+#endif
+#else
+#ifdef POSIX_SIGNALS
+ { sigset_t sset;
+ sigemptyset(&sset);
+ sigaddset(&sset,SIGINT);
+ sigprocmask(SIG_BLOCK,&sset,NULL);
+ ptr = malloc((unsigned) size);
+ sigprocmask(SIG_UNBLOCK,&sset,NULL);
+ }
+#else
+ { int saveMask;
+ saveMask = sigblock(sigmask(SIGINT));
+ ptr = malloc((unsigned) size);
+ (void) sigsetmask(saveMask);
+ }
+#endif
+#endif
+ if (ptr == NULL) {
+ fflush(stdout);
+ fprintf(stderr, "*** Can't allocate memory\n");
+ fflush(stderr);
+ abort();
+ /*NOTREACHED*/
+ } else {
+ return(ptr);
+ }
+}
+
+char *
+Calloc(num, size)
+ register int num, size;
+{
+ char *ptr = Malloc(num*size);
+ bzero(ptr, num*size);
+ return(ptr);
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * PrintHostInfo --
+ *
+ * Prints out the HostInfo structure for a host.
+ *
+ *******************************************************************************
+ */
+
+void
+PrintHostInfo(file, title, hp)
+ FILE *file;
+ char *title;
+ register HostInfo *hp;
+{
+ register char **cp;
+ register ServerInfo **sp;
+ char comma;
+ int i;
+
+ fprintf(file, "%-7s %s", title, hp->name);
+
+ if (hp->addrList != NULL) {
+ if (hp->addrList[1] != NULL) {
+ fprintf(file, "\nAddresses:");
+ } else {
+ fprintf(file, "\nAddress:");
+ }
+ comma = ' ';
+ i = 0;
+ for (cp = hp->addrList; cp && *cp; cp++) {
+ i++;
+ if (i > 4) {
+ fprintf(file, "\n\t");
+ comma = ' ';
+ i = 0;
+ }
+ fprintf(file,"%c %s", comma, inet_ntoa(*(struct in_addr *)*cp));
+ comma = ',';
+ }
+ }
+
+ if (hp->aliases != NULL) {
+ fprintf(file, "\nAliases:");
+ comma = ' ';
+ i = 10;
+ for (cp = hp->aliases; cp && *cp && **cp; cp++) {
+ i += strlen(*cp) + 2;
+ if (i > 75) {
+ fprintf(file, "\n\t");
+ comma = ' ';
+ i = 10;
+ }
+ fprintf(file, "%c %s", comma, *cp);
+ comma = ',';
+ }
+ }
+
+ if (hp->servers != NULL) {
+ fprintf(file, "\nServed by:\n");
+ for (sp = hp->servers; *sp != NULL ; sp++) {
+
+ fprintf(file, "- %s\n\t", (*sp)->name);
+
+ comma = ' ';
+ i = 0;
+ for (cp = (*sp)->addrList; cp && *cp && **cp; cp++) {
+ i++;
+ if (i > 4) {
+ fprintf(file, "\n\t");
+ comma = ' ';
+ i = 0;
+ }
+ fprintf(file,
+ "%c %s", comma, inet_ntoa(*(struct in_addr *)*cp));
+ comma = ',';
+ }
+ fprintf(file, "\n\t");
+
+ comma = ' ';
+ i = 10;
+ for (cp = (*sp)->domains; cp && *cp && **cp; cp++) {
+ i += strlen(*cp) + 2;
+ if (i > 75) {
+ fprintf(file, "\n\t");
+ comma = ' ';
+ i = 10;
+ }
+ fprintf(file, "%c %s", comma, *cp);
+ comma = ',';
+ }
+ fprintf(file, "\n");
+ }
+ }
+
+ fprintf(file, "\n\n");
+}
+
+/*
+ *******************************************************************************
+ *
+ * OpenFile --
+ *
+ * Parses a command string for a file name and opens
+ * the file.
+ *
+ * Results:
+ * file pointer - the open was successful.
+ * NULL - there was an error opening the file or
+ * the input string was invalid.
+ *
+ *******************************************************************************
+ */
+
+FILE *
+OpenFile(string, file)
+ char *string;
+ char *file;
+{
+ char *redirect;
+ FILE *tmpPtr;
+
+ /*
+ * Open an output file if we see '>' or >>'.
+ * Check for overwrite (">") or concatenation (">>").
+ */
+
+ redirect = strchr(string, '>');
+ if (redirect == NULL) {
+ return(NULL);
+ }
+ if (redirect[1] == '>') {
+ sscanf(redirect, ">> %s", file);
+ tmpPtr = fopen(file, "a+");
+ } else {
+ sscanf(redirect, "> %s", file);
+ tmpPtr = fopen(file, "w");
+ }
+
+ if (tmpPtr != NULL) {
+ redirect[0] = '\0';
+ }
+
+ return(tmpPtr);
+}
+
+/*
+ *******************************************************************************
+ *
+ * DecodeError --
+ *
+ * Converts an error code into a character string.
+ *
+ *******************************************************************************
+ */
+
+char *
+DecodeError(result)
+ int result;
+{
+ switch (result) {
+ case NOERROR: return("Success"); break;
+ case FORMERR: return("Format error"); break;
+ case SERVFAIL: return("Server failed"); break;
+ case NXDOMAIN: return("Non-existent host/domain"); break;
+ case NOTIMP: return("Not implemented"); break;
+ case REFUSED: return("Query refused"); break;
+#ifdef NOCHANGE
+ case NOCHANGE: return("No change"); break;
+#endif
+ case TIME_OUT: return("Timed out"); break;
+ case NO_INFO: return("No information"); break;
+ case ERROR: return("Unspecified error"); break;
+ case NONAUTH: return("Non-authoritative answer"); break;
+ case NO_RESPONSE: return("No response from server"); break;
+ default: break;
+ }
+ return("BAD ERROR VALUE");
+}
+
+
+int
+StringToClass(class, dflt, errorfile)
+ char *class;
+ int dflt;
+ FILE *errorfile;
+{
+ if (strcasecmp(class, "IN") == 0)
+ return(C_IN);
+ if (strcasecmp(class, "HESIOD") == 0 ||
+ strcasecmp(class, "HS") == 0)
+ return(C_HS);
+ if (strcasecmp(class, "CHAOS") == 0)
+ return(C_CHAOS);
+ if (strcasecmp(class, "ANY") == 0)
+ return(C_ANY);
+ if (errorfile)
+ fprintf(errorfile, "unknown query class: %s\n", class);
+ return(dflt);
+}
+
+
+/*
+ *******************************************************************************
+ *
+ * StringToType --
+ *
+ * Converts a string form of a query type name to its
+ * corresponding integer value.
+ *
+ *******************************************************************************
+ */
+
+int
+StringToType(type, dflt, errorfile)
+ char *type;
+ int dflt;
+ FILE *errorfile;
+{
+ if (strcasecmp(type, "A") == 0)
+ return(T_A);
+ if (strcasecmp(type, "NS") == 0)
+ return(T_NS); /* authoritative server */
+ if (strcasecmp(type, "MX") == 0)
+ return(T_MX); /* mail exchanger */
+ if (strcasecmp(type, "PX") == 0)
+ return(T_PX); /* mapping information */
+ if (strcasecmp(type, "CNAME") == 0)
+ return(T_CNAME); /* canonical name */
+ if (strcasecmp(type, "SOA") == 0)
+ return(T_SOA); /* start of authority zone */
+ if (strcasecmp(type, "MB") == 0)
+ return(T_MB); /* mailbox domain name */
+ if (strcasecmp(type, "MG") == 0)
+ return(T_MG); /* mail group member */
+ if (strcasecmp(type, "MR") == 0)
+ return(T_MR); /* mail rename name */
+ if (strcasecmp(type, "WKS") == 0)
+ return(T_WKS); /* well known service */
+ if (strcasecmp(type, "PTR") == 0)
+ return(T_PTR); /* domain name pointer */
+ if (strcasecmp(type, "HINFO") == 0)
+ return(T_HINFO); /* host information */
+ if (strcasecmp(type, "MINFO") == 0)
+ return(T_MINFO); /* mailbox information */
+ if (strcasecmp(type, "AXFR") == 0)
+ return(T_AXFR); /* zone transfer */
+ if (strcasecmp(type, "MAILA") == 0)
+ return(T_MAILA); /* mail agent */
+ if (strcasecmp(type, "MAILB") == 0)
+ return(T_MAILB); /* mail box */
+ if (strcasecmp(type, "ANY") == 0)
+ return(T_ANY); /* matches any type */
+ if (strcasecmp(type, "UINFO") == 0)
+ return(T_UINFO); /* user info */
+ if (strcasecmp(type, "UID") == 0)
+ return(T_UID); /* user id */
+ if (strcasecmp(type, "GID") == 0)
+ return(T_GID); /* group id */
+ if (strcasecmp(type, "TXT") == 0)
+ return(T_TXT); /* text */
+ if (strcasecmp(type, "RP") == 0)
+ return(T_RP); /* responsible person */
+ if (strcasecmp(type, "X25") == 0)
+ return(T_X25); /* x25 address */
+ if (strcasecmp(type, "ISDN") == 0)
+ return(T_ISDN); /* isdn address */
+ if (strcasecmp(type, "RT") == 0)
+ return(T_RT); /* router */
+ if (strcasecmp(type, "AFSDB") == 0)
+ return(T_AFSDB); /* DCE or AFS server */
+ if (strcasecmp(type, "NSAP") == 0)
+ return(T_NSAP); /* NSAP address */
+ if (strcasecmp(type, "NSAP_PTR") == 0)
+ return(T_NSAP_PTR); /* NSAP reverse pointer */
+ if (errorfile)
+ fprintf(errorfile, "unknown query type: %s\n", type);
+ return(dflt);
+}
+
+/*
+ *******************************************************************************
+ *
+ * DecodeType --
+ *
+ * Converts a query type to a descriptive name.
+ * (A more verbose form of p_type.)
+ *
+ *
+ *******************************************************************************
+ */
+
+static char nbuf[20];
+
+char *
+DecodeType(type)
+ int type;
+{
+ switch (type) {
+ case T_A:
+ return("address");
+ case T_NS:
+ return("name server");
+ case T_CNAME:
+ return("canonical name");
+ case T_SOA:
+ return("start of authority");
+ case T_MB:
+ return("mailbox");
+ case T_MG:
+ return("mail group member");
+ case T_MR:
+ return("mail rename");
+ case T_NULL:
+ return("null");
+ case T_WKS:
+ return("well-known service");
+ case T_PTR:
+ return("domain name pointer");
+ case T_HINFO:
+ return("host information");
+ case T_MINFO:
+ return("mailbox information");
+ case T_MX:
+ return("mail exchanger");
+ case T_PX:
+ return("mapping information");
+ case T_TXT:
+ return("text");
+ case T_RP:
+ return("responsible person");
+ case T_AFSDB:
+ return("DCE or AFS server");
+ case T_X25:
+ return("X25 address");
+ case T_ISDN:
+ return("ISDN address");
+ case T_RT:
+ return("router");
+ case T_NSAP:
+ return("nsap address");
+ case T_NSAP_PTR:
+ return("domain name pointer");
+ case T_UINFO:
+ return("user information");
+ case T_UID:
+ return("user ID");
+ case T_GID:
+ return("group ID");
+ case T_AXFR:
+ return("zone transfer");
+ case T_MAILB:
+ return("mailbox-related data");
+ case T_MAILA:
+ return("mail agent");
+ case T_ANY:
+ return("\"any\"");
+ default:
+ (void) sprintf(nbuf, "%d", type);
+ return (nbuf);
+ }
+}
diff --git a/usr.sbin/named/reload/Makefile b/usr.sbin/named/reload/Makefile
new file mode 100644
index 00000000000..c64c1dbcbcd
--- /dev/null
+++ b/usr.sbin/named/reload/Makefile
@@ -0,0 +1,22 @@
+# $NetBSD: Makefile,v 1.1 1996/02/02 15:30:32 mrg Exp $
+# from: $Id: Makefile,v 8.1 1994/12/15 06:23:46 vixie Exp
+
+.PATH: ${.CURDIR}/../named \
+ ${.CURDIR}/../man
+
+all: named.reload named.reload.cat8
+
+CLEANFILES+= named.reload
+MAN= named.reload.8
+
+realinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ named.reload ${DESTDIR}${BINDIR}/named.reload
+
+named.reload: named.reload.sh Makefile ${.CURDIR}/../Makefile.inc
+ sed -e "s|%DESTSBIN%|${BINDIR}|" \
+ < ${.CURDIR}/named.reload.sh > named.reload
+ chmod +x named.reload
+
+.include <bsd.prog.mk>
+.include "../../Makefile.inc"
diff --git a/usr.sbin/named/reload/named.reload.sh b/usr.sbin/named/reload/named.reload.sh
new file mode 100644
index 00000000000..3b9a395d4ea
--- /dev/null
+++ b/usr.sbin/named/reload/named.reload.sh
@@ -0,0 +1,8 @@
+#!/bin/sh -
+#
+# $NetBSD: named.reload.sh,v 1.1 1996/02/02 15:30:33 mrg Exp $
+# from named.reload 5.2 (Berkeley) 6/27/89
+# from: $Id: named.reload.sh,v 8.1 1994/12/15 06:24:14 vixie Exp
+#
+
+exec %DESTSBIN%/ndc reload
diff --git a/usr.sbin/named/restart/Makefile b/usr.sbin/named/restart/Makefile
new file mode 100644
index 00000000000..dd57a21444d
--- /dev/null
+++ b/usr.sbin/named/restart/Makefile
@@ -0,0 +1,22 @@
+# $NetBSD: Makefile,v 1.1 1996/02/02 15:30:35 mrg Exp $
+# from: $Id: Makefile,v 8.1 1994/12/15 06:23:47 vixie Exp
+
+.PATH: ${.CURDIR}/../named \
+ ${.CURDIR}/../man
+
+all: named.restart named.restart.cat8
+
+CLEANFILES+= named.restart
+MAN= named.restart.8
+
+realinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ named.restart ${DESTDIR}${BINDIR}/named.restart
+
+named.restart: named.restart.sh Makefile ${.CURDIR}/../Makefile.inc
+ sed -e "s|%DESTSBIN%|${BINDIR}|" \
+ < ${.CURDIR}/named.restart.sh > named.restart
+ chmod +x named.restart
+
+.include <bsd.prog.mk>
+.include "../../Makefile.inc"
diff --git a/usr.sbin/named/restart/named.restart.sh b/usr.sbin/named/restart/named.restart.sh
new file mode 100644
index 00000000000..59d6c48ce61
--- /dev/null
+++ b/usr.sbin/named/restart/named.restart.sh
@@ -0,0 +1,8 @@
+#!/bin/sh -
+#
+# $NetBSD: named.restart.sh,v 1.1 1996/02/02 15:30:36 mrg Exp $
+# from named.restart 5.4 (Berkeley) 6/27/89
+# from: $Id: named.restart.sh,v 8.1 1994/12/15 06:24:14 vixie Exp
+#
+
+exec %DESTSBIN%/ndc restart