diff options
author | dm <dm@cvs.openbsd.org> | 1996-02-19 19:54:44 +0000 |
---|---|---|
committer | dm <dm@cvs.openbsd.org> | 1996-02-19 19:54:44 +0000 |
commit | 34dfcd3c571a64de57872aa758d1b228d7b22a02 (patch) | |
tree | 22b14dd50dff4fc41ec5c5f2ee3e20f4b7f1d141 /usr.sbin/named | |
parent | d134390523f594c4e7f1b453b8026b993a1aeebb (diff) |
netbsd: bind 4.9.3
Diffstat (limited to 'usr.sbin/named')
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 Binary files differnew file mode 100644 index 00000000000..b7a9c922b3e --- /dev/null +++ b/usr.sbin/named/dig/debug.o diff --git a/usr.sbin/named/dig/dig b/usr.sbin/named/dig/dig Binary files differnew file mode 100644 index 00000000000..5ee6a7d0c49 --- /dev/null +++ b/usr.sbin/named/dig/dig 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 Binary files differnew file mode 100644 index 00000000000..d41ac47e8dc --- /dev/null +++ b/usr.sbin/named/dig/dig.o diff --git a/usr.sbin/named/dig/list.o b/usr.sbin/named/dig/list.o Binary files differnew file mode 100644 index 00000000000..418801ff340 --- /dev/null +++ b/usr.sbin/named/dig/list.o diff --git a/usr.sbin/named/dig/send.o b/usr.sbin/named/dig/send.o Binary files differnew file mode 100644 index 00000000000..5ec66a308a5 --- /dev/null +++ b/usr.sbin/named/dig/send.o diff --git a/usr.sbin/named/dig/subr.o b/usr.sbin/named/dig/subr.o Binary files differnew file mode 100644 index 00000000000..32941f971da --- /dev/null +++ b/usr.sbin/named/dig/subr.o 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 |