summaryrefslogtreecommitdiffstats
path: root/contrib/bind/named
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind/named')
-rw-r--r--contrib/bind/named/Makefile196
-rw-r--r--contrib/bind/named/Makefile.reno83
-rw-r--r--contrib/bind/named/Version.c88
-rw-r--r--contrib/bind/named/db_defs.h183
-rw-r--r--contrib/bind/named/db_dump.c924
-rw-r--r--contrib/bind/named/db_func.h113
-rw-r--r--contrib/bind/named/db_glob.h93
-rw-r--r--contrib/bind/named/db_glue.c835
-rw-r--r--contrib/bind/named/db_load.c1501
-rw-r--r--contrib/bind/named/db_lookup.c249
-rw-r--r--contrib/bind/named/db_reload.c126
-rw-r--r--contrib/bind/named/db_save.c208
-rw-r--r--contrib/bind/named/db_secure.c153
-rw-r--r--contrib/bind/named/db_update.c737
-rw-r--r--contrib/bind/named/dmalloc.c315
-rw-r--r--contrib/bind/named/dmalloc.h68
-rw-r--r--contrib/bind/named/named-xfer.c1644
-rw-r--r--contrib/bind/named/named.h19
-rw-r--r--contrib/bind/named/named.reload.sh7
-rw-r--r--contrib/bind/named/named.restart.sh7
-rw-r--r--contrib/bind/named/ndc.sh83
-rw-r--r--contrib/bind/named/ns_defs.h397
-rw-r--r--contrib/bind/named/ns_forw.c1094
-rw-r--r--contrib/bind/named/ns_func.h166
-rw-r--r--contrib/bind/named/ns_glob.h291
-rw-r--r--contrib/bind/named/ns_init.c1110
-rw-r--r--contrib/bind/named/ns_main.c1669
-rw-r--r--contrib/bind/named/ns_maint.c1100
-rw-r--r--contrib/bind/named/ns_ncache.c154
-rw-r--r--contrib/bind/named/ns_req.c2179
-rw-r--r--contrib/bind/named/ns_resp.c2743
-rw-r--r--contrib/bind/named/ns_sort.c171
-rw-r--r--contrib/bind/named/ns_stats.c399
-rw-r--r--contrib/bind/named/ns_validate.c1246
-rw-r--r--contrib/bind/named/pathnames.h122
-rw-r--r--contrib/bind/named/storage.c205
-rw-r--r--contrib/bind/named/tree.c570
-rw-r--r--contrib/bind/named/tree.h48
-rw-r--r--contrib/bind/named/tree.man3154
39 files changed, 21450 insertions, 0 deletions
diff --git a/contrib/bind/named/Makefile b/contrib/bind/named/Makefile
new file mode 100644
index 0000000..edd6533
--- /dev/null
+++ b/contrib/bind/named/Makefile
@@ -0,0 +1,196 @@
+#
+# @(#)Makefile.dist 5.4 (Berkeley) 8/15/90
+# $Id: Makefile,v 8.7 1995/12/22 10:20:30 vixie Exp $
+#
+
+## ++Copyright++ 1987, 1988, 1990
+## -
+## Copyright (c) 1987, 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--
+
+## NOTE: customizing this Makefile is almost certainly the wrong thing to do.
+## unless you are a developer and intend to run "make" here a lot of times
+## per day, you should just run "make" from the top-level directory after
+## configuring _that_ Makefile with the right system-dependent values.
+
+VER = LOCAL-`date +%y%m%d.%H%M%S`
+SHELL = /bin/sh
+DESTDIR =
+
+INDOT=
+XFER_INDOT=
+#(sunos)
+#INDOT=in.
+#XFER_INDOT=in.
+
+HOSTNAMECMD = hostname || uname -n
+
+#(these defaults are reasonable for a BSD/OS test environment;
+# for real configuration, edit ../Makefile and run make from there.)
+
+COMPINCL = ../compat/include
+INCL= ../include
+RES= ../res/libresolv.a
+DESTSBIN = ${DESTDIR}/usr/sbin
+DESTEXEC = ${DESTDIR}/usr/libexec
+PIDDIR = /var/run
+CC= cc
+#CC= gcc2 -Wimplicit -Wunused -Wreturn-type
+SHELL= /bin/sh
+CDEBUG= -g
+LIBS=
+COMPLIB= ../compat/lib/lib44bsd.a
+PATH_XFER = ${DESTEXEC}/${XFER_INDOT}named-xfer
+DEFS = -D_PATH_XFER=\"${PATH_XFER}\" -D_PATH_PIDFILE=\"${PIDDIR}/named.pid\"
+INSTALL = install
+PS=ps
+IOT=ABRT
+
+CFLAGS = ${CDEBUG} -I${INCL} -I${COMPINCL} ${DEFS}
+
+HDRS= db_defs.h db_glob.h ns_defs.h ns_glob.h named.h pathnames.h tree.h
+SRCS= db_dump.c db_load.c db_lookup.c db_reload.c db_save.c db_update.c \
+ db_secure.c db_glue.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 ns_validate.c ns_ncache.c \
+ storage.c dmalloc.c tree.c
+OBJS= db_dump.o db_load.o db_lookup.o db_reload.o db_save.o db_update.o \
+ db_secure.o db_glue.o \
+ ns_forw.o ns_init.o ns_main.o ns_maint.o ns_req.o ns_resp.o \
+ ns_sort.o ns_stats.o ns_validate.o ns_ncache.o \
+ storage.o dmalloc.o tree.o
+XFERSRCS= named-xfer.c
+XFEROBJ= named-xfer.o db_glue.o storage.o dmalloc.o version.o
+
+all: named named-xfer named.reload named.restart ndc
+
+named: ${OBJS} ${RES} ${COMPLIB} version.o
+ ${CC} ${CDEBUG} ${LDFLAGS} -o $@ version.o ${OBJS} \
+ ${RES} ${COMPLIB} ${LIBS}
+
+version.o: version.c
+
+version.c: Version.c Makefile ../Makefile ${SRCS} ${HDRS}
+ (u=$${USER-root} d=`pwd` h=`${HOSTNAMECMD}` t=`date`; \
+ sed -e "s|%WHEN%|$${t}|" -e "s|%VERSION%|"${VER}"|" \
+ -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+ < Version.c > version.c)
+
+named.reload: named.reload.sh Makefile
+ sed -e "s|%INDOT%|${INDOT}|" \
+ -e "s|%DESTSBIN%|${DESTSBIN}|" \
+ < named.reload.sh > named.reload
+ chmod +x named.reload
+
+named.restart: named.restart.sh Makefile
+ sed -e "s|%INDOT%|${INDOT}|" \
+ -e "s|%DESTSBIN%|${DESTSBIN}|" \
+ < named.restart.sh > named.restart
+ chmod +x named.restart
+
+ndc: ndc.sh Makefile
+ sed -e "s|%PIDDIR%|${PIDDIR}|" \
+ -e "s|%INDOT%|${INDOT}|" \
+ -e "s|%PS%|${PS}|" \
+ -e "s|%IOTPS%|${IOT}|" \
+ -e "s|%DESTSBIN%|${DESTSBIN}|" \
+ -e "s|%IOT%|${IOT}|" \
+ < ndc.sh > ndc
+ chmod +x ndc
+
+named-xfer: ${XFEROBJ} ${RES} ${COMPLIB}
+ ${CC} ${CDEBUG} ${LDFLAGS} -o $@ ${XFEROBJ} \
+ ${RES} ${COMPLIB} ${LIBS}
+
+centerline_named:
+ #load -I${INCL} -I${COMPINCL} ${CFLAGS} ${SRCS} \
+ version.c ${RES} ${COMPLIB} ${LIBS}
+
+centerline_obj:
+ #load -I${INCL} -I${COMPINCL} ${CFLAGS} ${OBJS} \
+ version.o ${RES} ${COMPLIB} ${LIBS}
+
+centerline_xfer:
+ #load -DXFER ${CFLAGS} ${XFERSRCS} ${RES} ${COMPLIB} ${LIBS}
+
+clean:
+ rm -f ${OBJS} ${XFEROBJ} core named named-xfer version.o version.c
+ rm -f *~ *.BAK *.CKP
+ rm -f tags .depend core named.reload named.restart ndc
+ rm -f *.orig
+
+depend .depend: ${SRCS} ${XFERSRCS}
+ mkdep ${CPPFLAGS} -I${INCL} -I${COMPINCL} ${SRCS} ${XFERSRCS}
+
+install:
+ ${INSTALL} -c -s -o bin -g bin -m 555 \
+ named ${DESTDIR}${DESTSBIN}/${INDOT}named
+ ${INSTALL} -c -s -o bin -g bin -m 555 \
+ named-xfer ${DESTDIR}${PATH_XFER}
+ ${INSTALL} -c -o bin -g bin -m 555 \
+ named.restart ${DESTDIR}${DESTSBIN}/${INDOT}named.restart
+ ${INSTALL} -c -o bin -g bin -m 555 \
+ named.reload ${DESTDIR}${DESTSBIN}/${INDOT}named.reload
+ ${INSTALL} -c -o bin -g bin -m 555 \
+ ndc ${DESTDIR}${DESTSBIN}/${INDOT}ndc
+ @echo "*** Install symlinks if needed ***"
+
+lint: ${SRCS} ${HDRS} ${XFERSRCS}
+ lint -x -Dlint ${CFLAGS} ${SRCS} ${XFERSRCS} 2>&1 \
+ | grep -v 'warning: nested comments not supported'
+
+tags: ${SRCS} ${XFERSRCS} Makefile
+ ctags -t `echo ${SRCS} ${HDRS} ${XFERSRCS}|tr ' ' '\012'|sort -u`
+
+$(SRCS):: $(HDRS)
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
diff --git a/contrib/bind/named/Makefile.reno b/contrib/bind/named/Makefile.reno
new file mode 100644
index 0000000..2bddd9e
--- /dev/null
+++ b/contrib/bind/named/Makefile.reno
@@ -0,0 +1,83 @@
+#
+# @(#)Makefile 5.8 (Berkeley) 7/28/90
+# $Id: Makefile.reno,v 8.1 1994/12/15 06:24:14 vixie 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--
+
+### -DALLOW_T_UNSPEC -Dmalloc=rt_malloc -Dfree=rt_free
+### ALLOC=storage.o
+PROG= named
+MAN8= named.0
+CFLAGS= -O -DDEBUG -DSTATS
+LDADD= -lutil
+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
+
+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)
+
+afterinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m 555 ${.CURDIR}/named.restart \
+ ${.CURDIR}/named.reload ${DESTDIR}${BINDIR}
+
+.include <bsd.prog.mk>
diff --git a/contrib/bind/named/Version.c b/contrib/bind/named/Version.c
new file mode 100644
index 0000000..60a7ba8
--- /dev/null
+++ b/contrib/bind/named/Version.c
@@ -0,0 +1,88 @@
+/*
+ * @(#)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% %WHEN% %WHOANDWHERE%";
+char rcsid[] = "$Id: Version.c,v 8.1 1994/12/15 06:24:14 vixie Exp $";
+#endif /* not lint */
+
+char Version[] = "named %VERSION% %WHEN%\n\t%WHOANDWHERE%";
+
+#ifdef COMMENT
+
+SCCS/s.Version.c:
+
+D 4.8.3 90/06/27 17:05:21 bloom 37 35 00031/00028/00079
+Version distributed with 4.3 Reno tape (June 1990)
+
+D 4.8.2 89/09/18 13:57:11 bloom 35 34 00020/00014/00087
+Interim fixes release
+
+D 4.8.1 89/02/08 17:12:15 karels 34 33 00026/00017/00075
+branch for 4.8.1
+
+D 4.8 88/07/09 14:27:00 karels 33 28 00043/00031/00049
+4.8 is here!
+
+D 4.7 87/11/20 13:15:52 karels 25 24 00000/00000/00062
+4.7.3 beta
+
+D 4.6 87/07/21 12:15:52 karels 25 24 00000/00000/00062
+4.6 declared stillborn
+
+D 4.5 87/02/10 12:33:25 kjd 24 18 00000/00000/00062
+February 1987, Network Release. Child (bind) grows up, parent (kevin) leaves home.
+
+D 4.4 86/10/01 10:06:26 kjd 18 12 00020/00017/00042
+October 1, 1986 Network Distribution
+
+D 4.3 86/06/04 12:12:18 kjd 12 7 00015/00028/00044
+Version distributed with 4.3BSD
+
+D 4.2 86/04/30 20:57:16 kjd 7 1 00056/00000/00016
+Network distribution Freeze and one more version until 4.3BSD
+
+D 1.1 86/04/30 19:30:00 kjd 1 0 00016/00000/00000
+date and time created 86/04/30 19:30:00 by kjd
+
+code versions:
+
+Makefile
+ Makefile 4.14 (Berkeley) 2/28/88
+db.h
+ db.h 4.13 (Berkeley) 2/17/88
+db_dump.c
+ db_dump.c 4.20 (Berkeley) 2/17/88
+db_load.c
+ db_load.c 4.26 (Berkeley) 2/28/88
+db_lookup.c
+ db_lookup.c 4.14 (Berkeley) 2/17/88
+db_reload.c
+ db_reload.c 4.15 (Berkeley) 2/28/88
+db_save.c
+ db_save.c 4.13 (Berkeley) 2/17/88
+db_update.c
+ db_update.c 4.16 (Berkeley) 2/28/88
+ns_forw.c
+ ns_forw.c 4.26 (Berkeley) 3/28/88
+ns_init.c
+ ns_init.c 4.23 (Berkeley) 2/28/88
+ns_main.c
+ Copyright (c) 1986 Regents of the University of California.\n\
+ ns_main.c 4.30 (Berkeley) 3/7/88
+ns_maint.c
+ ns_maint.c 4.23 (Berkeley) 2/28/88
+ns_req.c
+ ns_req.c 4.32 (Berkeley) 3/31/88
+ns_resp.c
+ ns_resp.c 4.50 (Berkeley) 4/7/88
+ns_sort.c
+ ns_sort.c 4.3 (Berkeley) 2/17/88
+ns_stats.c
+ ns_stats.c 4.3 (Berkeley) 2/17/88
+newvers.sh
+ newvers.sh 4.4 (Berkeley) 3/28/88
+
+#endif /* COMMENT */
diff --git a/contrib/bind/named/db_defs.h b/contrib/bind/named/db_defs.h
new file mode 100644
index 0000000..7356818
--- /dev/null
+++ b/contrib/bind/named/db_defs.h
@@ -0,0 +1,183 @@
+/*
+ * from db.h 4.16 (Berkeley) 6/1/90
+ * $Id: db_defs.h,v 8.4 1996/05/17 09:10:46 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 {
+ 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 */
+ char _n_name[sizeof(void*)]; /* Counted str, malloc'ed. */
+};
+#define NAMESIZE(n) (sizeof(struct namebuf) - sizeof(void*) + 1 + n + 1)
+#define NAMELEN(nb) ((nb)._n_name[0])
+#define NAME(nb) ((nb)._n_name + 1)
+
+#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/contrib/bind/named/db_dump.c b/contrib/bind/named/db_dump.c
new file mode 100644
index 0000000..421c121
--- /dev/null
+++ b/contrib/bind/named/db_dump.c
@@ -0,0 +1,924 @@
+#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.14 1996/08/05 08:31:30 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/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.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 (NAME(*np)[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=%lu, lastupdate=%lu, serial=%u,\n",
+ (u_long)zp->z_time, (u_long)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=%lu, xaddr=[%s], state=%04x, pid=%d\n",
+ (u_long)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 (NAME(*np)[0] == '\0') {
+ if (origin[0] == '\0')
+ fprintf(fp, ".\t");
+ else
+ fprintf(fp, ".%s.\t", origin); /* ??? */
+ } else
+ fprintf(fp, "%s\t", NAME(*np));
+ if (NAMELEN(*np) < (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 != USE_MINIMUM &&
+ 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;
+ case T_AAAA: {
+ char t[sizeof
+ "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"
+ ];
+
+ (void) fputs(inet_ntop(AF_INET6, dp->d_data,
+ t, sizeof t),
+ fp);
+ break;
+ }
+#ifdef LOC_RR
+ case T_LOC: {
+ char t[256];
+
+ (void) fputs(loc_ntoa(dp->d_data, t), 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, "%d %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 %d %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/contrib/bind/named/db_func.h b/contrib/bind/named/db_func.h
new file mode 100644
index 0000000..60b7f32
--- /dev/null
+++ b/contrib/bind/named/db_func.h
@@ -0,0 +1,113 @@
+/* db_proc.h - prototypes for functions in db_*.c
+ *
+ * $Id: db_func.h,v 8.9 1996/06/02 08:20:39 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
+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 struct namebuf *np_parent __P((struct namebuf *));
+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/contrib/bind/named/db_glob.h b/contrib/bind/named/db_glob.h
new file mode 100644
index 0000000..b339b5b
--- /dev/null
+++ b/contrib/bind/named/db_glob.h
@@ -0,0 +1,93 @@
+/*
+ * 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/contrib/bind/named/db_glue.c b/contrib/bind/named/db_glue.c
new file mode 100644
index 0000000..647ae80
--- /dev/null
+++ b/contrib/bind/named/db_glue.c
@@ -0,0 +1,835 @@
+#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.13 1996/06/02 08:20:39 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988
+ * -
+ * Copyright (c) 1986, 1988
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/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 = strdup(str);
+
+ if (!cp)
+ panic(errno, "malloc(savestr)");
+ 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, NAME(*np), msg);
+ panic(-1, "rm_name");
+ }
+
+ /* unlink */
+ if (pnp) {
+ pnp->n_next = nnp;
+ } else {
+ *pp = nnp;
+ }
+
+ /* deallocate */
+ 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) {
+ i = NAMELEN(*np);
+ if (i + 1 >= buflen) {
+ *cp = '\0';
+ syslog(LOG_INFO, "domain name too long: %s...\n", buf);
+ strcpy(buf, "Name_Too_Long");
+ return;
+ }
+ if (cp != buf)
+ *cp++ = '.';
+ bcopy(NAME(*np), cp, i);
+ 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);
+}
+
+/*
+ * 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/contrib/bind/named/db_load.c b/contrib/bind/named/db_load.c
new file mode 100644
index 0000000..dda27c9
--- /dev/null
+++ b/contrib/bind/named/db_load.c
@@ -0,0 +1,1501 @@
+#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.22 1996/08/05 08:31:30 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/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.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 makename_ok __P((char *name, const char *origin,
+ int class,
+ enum transport transport,
+ enum context context,
+ const char *filename, int lineno));
+
+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 },
+ { "aaaa", T_AAAA },
+#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 */
+
+#define MAKENAME_OK(N) if (!makename_ok(N, origin, class, \
+ transport, context, \
+ filename, lineno)) { \
+ errs++; \
+ sprintf(buf, "bad name \"%s\"", N); \
+ goto err; \
+ }
+
+/* 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;
+ enum transport transport;
+ enum context context;
+#ifdef DO_WARN_SERIAL
+ u_int32_t serial;
+#endif
+
+ switch (zp->z_type) {
+ case Z_PRIMARY:
+ case Z_CACHE:
+ transport = primary_trans;
+ break;
+ case Z_SECONDARY:
+ case Z_STUB:
+ transport = secondary_trans;
+ break;
+ default:
+ transport = response_trans; /*guessing*/
+ break;
+ }
+ 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_NOTICE, "%s: Line %d: Unknown type: %s.\n",
+ filename, lineno, buf);
+ break;
+ fndtype:
+ context = ns_ownercontext(type, transport);
+ if (!ns_nameok(domain, class, transport, context)) {
+ errs++;
+ syslog(LOG_NOTICE,
+ "%s:%d: owner name error\n",
+ filename, lineno);
+ break;
+ }
+#ifdef ALLOW_T_UNSPEC
+ /* Don't do anything here for T_UNSPEC...
+ * read input separately later
+ */
+ if (type != T_UNSPEC) {
+#endif
+ context = domain_ctx;
+ 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:
+ context = hostname_ctx;
+ goto soa_rp_minfo;
+ case T_RP:
+ case T_MINFO:
+ context = mailname_ctx;
+ /* FALLTHROUGH */
+ soa_rp_minfo:
+ (void) strcpy((char *)data, (char *)buf);
+
+ MAKENAME_OK(data);
+ cp = data + strlen((char *)data) + 1;
+ if (!getword((char *)cp,
+ (sizeof data) - (cp - data),
+ fp, 1))
+ goto err;
+ if (type == T_RP)
+ context = domain_ctx;
+ else
+ context = mailname_ctx;
+ MAKENAME_OK(cp);
+ 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++;
+ context = hostname_ctx;
+ goto cname_etc;
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ context = domain_ctx;
+ goto cname_etc;
+ case T_PTR:
+ context = ns_ptrcontext(domain);
+ cname_etc:
+ (void) strcpy((char *)data, (char *)buf);
+ MAKENAME_OK(data);
+ 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);
+ context = hostname_ctx;
+ MAKENAME_OK(cp);
+ /* advance pointer to end of data */
+ cp += strlen((char *)cp) +1;
+
+ /* now save length */
+ n = (cp - data);
+ break;
+
+ case T_PX:
+ context = domain_ctx;
+ 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_OK(cp);
+ /* 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_OK(cp);
+ /* 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;
+ case T_AAAA:
+ if (inet_pton(AF_INET6, buf, data) <= 0)
+ goto err;
+ n = IN6ADDRSZ;
+ 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,
+ (dataflags & DB_F_HINT)
+ ? 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(errs ? LOG_WARNING : 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, spaceok;
+
+ 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;
+ }
+ spaceok = 0;
+ if (c == '\\') {
+ /* Do escape processing. */
+ if ((c = getc(fp)) == EOF)
+ c = '\\';
+ if (preserve && (c == '\\' || c == '.')) {
+ if (cp >= buf+size-1)
+ break;
+ *cp++ = '\\';
+ }
+ if (c == ' ' || c == '\t')
+ spaceok++;
+ }
+ if (isspace(c) && !spaceok) {
+ /* 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);
+ }
+ }
+}
+
+static int
+makename_ok(name, origin, class, transport, context, filename, lineno)
+ char *name;
+ const char *origin;
+ int class;
+ enum transport transport;
+ enum context context;
+ const char *filename;
+ int lineno;
+{
+ int ret = 1;
+
+ makename(name, origin);
+ if (!ns_nameok(name, class, transport, context)) {
+ syslog(LOG_INFO, "%s:%d: database naming error\n",
+ filename, lineno);
+ ret = 0;
+ }
+ return (ret);
+}
+
+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/contrib/bind/named/db_lookup.c b/contrib/bind/named/db_lookup.c
new file mode 100644
index 0000000..4582589
--- /dev/null
+++ b/contrib/bind/named/db_lookup.c
@@ -0,0 +1,249 @@
+#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.7 1996/08/05 08:31: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--
+ */
+
+/*
+ * Table lookup routines.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <syslog.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 (ns_wildcard(NAME(*np)))
+ *fname = name;
+ return (np);
+ }
+ htp = savehash((struct hashbuf *)NULL);
+ np->n_hash = htp;
+ }
+ *htpp = htp;
+ break;
+ }
+
+ /* rotate left HASHSHIFT */
+ hval = (hval << HASHSHIFT) |
+ (hval>>((sizeof(hval)*8)-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 &&
+ (NAMELEN(*np) == (cp - name)) &&
+ (strncasecmp(name, NAME(*np), 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 (ns_wildcard(NAME(*np)) &&
+ 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);
+}
+
+/* struct namebuf *
+ * np_parent(struct namebuf *np)
+ * Find the "parent" namebuf of np.
+ * This is tricky since the parent of "com" is "" and both are stored
+ * in the same hashbuf.
+ * See also:
+ * the AXFR wart description in ns_req.c
+ */
+struct namebuf *
+np_parent(np)
+ struct namebuf *np;
+{
+ struct hashbuf *htp;
+ struct namebuf *np2;
+
+ if (np->n_parent != NULL || NAME(*np)[0] == '\0')
+ return (np->n_parent);
+
+ /* Try to figure out if np is pointing into the cache or hints. */
+ /* Try the cache first. */
+ htp = hashtab;
+ try_again:
+ /* Search the hash chain that np should be part of. */
+ for (np2 = htp->h_tab[np->n_hashval % htp->h_size];
+ np2 != NULL;
+ np2 = np2->n_next) {
+
+ if (np == np2) { /* found it! */
+ /* "" hashes into the first bucket */
+ for (np = htp->h_tab[0]; np ; np=np->n_next) {
+ if (NAME(*np)[0] == '\0')
+ /* found the root namebuf */
+ return (np);
+ }
+ dprintf(1, (ddt,
+ "np_parent(0x%lx) couldn't find root entry\n",
+ (u_long) np));
+ return (NULL); /* XXX shouldn't happen */
+ }
+ }
+ /* Try the hints. */
+ if (htp == hashtab) {
+ htp = fcachetab;
+ goto try_again;
+ }
+ dprintf(1, (ddt, "np_parent(0x%lx) couldn't namebuf\n", (u_long) np));
+ return (NULL); /* XXX shouldn't happen */
+}
+
+/* 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/contrib/bind/named/db_reload.c b/contrib/bind/named/db_reload.c
new file mode 100644
index 0000000..46fa7fe
--- /dev/null
+++ b/contrib/bind/named/db_reload.c
@@ -0,0 +1,126 @@
+#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.2 1996/08/05 08:31: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/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/contrib/bind/named/db_save.c b/contrib/bind/named/db_save.c
new file mode 100644
index 0000000..88b31d1
--- /dev/null
+++ b/contrib/bind/named/db_save.c
@@ -0,0 +1,208 @@
+#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.4 1996/08/05 08:31: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--
+ */
+
+/*
+ * Buffer allocation and deallocation routines.
+ */
+
+#include <sys/types.h>
+#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 <assert.h>
+
+#include "named.h"
+
+/*
+ * Allocate a name buffer & save name.
+ */
+struct namebuf *
+savename(name, len)
+ const char *name;
+ int len;
+{
+ register struct namebuf *np;
+
+ assert(len >= 0 && len <= (MAXLABEL * 2));
+ np = (struct namebuf *) malloc(NAMESIZE(len));
+ if (np == NULL)
+ panic(errno, "savename: malloc");
+ bzero((char*)np, NAMESIZE(len));
+ NAMELEN(*np) = len;
+ bcopy(name, NAME(*np), len);
+ NAME(*np)[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/contrib/bind/named/db_secure.c b/contrib/bind/named/db_secure.c
new file mode 100644
index 0000000..0ec8353
--- /dev/null
+++ b/contrib/bind/named/db_secure.c
@@ -0,0 +1,153 @@
+#ifndef LINT
+static char rcsid[] = "$Id: db_secure.c,v 8.6 1996/05/17 09:10:46 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(NAME(*snp), 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/contrib/bind/named/db_update.c b/contrib/bind/named/db_update.c
new file mode 100644
index 0000000..c706c66
--- /dev/null
+++ b/contrib/bind/named/db_update.c
@@ -0,0 +1,737 @@
+#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.12 1996/08/05 08:31: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 <stdio.h>
+#include <syslog.h>
+
+#include <sys/types.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, int class)
+ * 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_parent(np)) {
+ 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 \
+ || (xdp)->d_type == T_AAAA)
+#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 +%ld\n",
+ (u_long)dp->d_ttl,
+ (u_long)
+ (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_AAAA:
+ 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/contrib/bind/named/dmalloc.c b/contrib/bind/named/dmalloc.c
new file mode 100644
index 0000000..03593e2
--- /dev/null
+++ b/contrib/bind/named/dmalloc.c
@@ -0,0 +1,315 @@
+/* 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.3 1996/05/17 09:10:46 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);
+ if (ptr)
+ 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/contrib/bind/named/dmalloc.h b/contrib/bind/named/dmalloc.h
new file mode 100644
index 0000000..9d0b44a
--- /dev/null
+++ b/contrib/bind/named/dmalloc.h
@@ -0,0 +1,68 @@
+/* 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/contrib/bind/named/named-xfer.c b/contrib/bind/named/named-xfer.c
new file mode 100644
index 0000000..b71ebfb
--- /dev/null
+++ b/contrib/bind/named/named-xfer.c
@@ -0,0 +1,1644 @@
+/*
+ * 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.15 1996/08/05 08:31:30 vixie Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#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*/
+ ancount = ntohs(hp->ancount);
+ 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, eom - buf,
+ 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_AAAA:
+ 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);
+ cp += n;
+ 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 (strchr("\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 (strchr("\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_AAAA: {
+ char t[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+
+ fprintf(dbfp, "%s\n", inet_ntop(AF_INET6, cp, t, sizeof t));
+ 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/contrib/bind/named/named.h b/contrib/bind/named/named.h
new file mode 100644
index 0000000..0575a5c
--- /dev/null
+++ b/contrib/bind/named/named.h
@@ -0,0 +1,19 @@
+/* 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/contrib/bind/named/named.reload.sh b/contrib/bind/named/named.reload.sh
new file mode 100644
index 0000000..0b6495a
--- /dev/null
+++ b/contrib/bind/named/named.reload.sh
@@ -0,0 +1,7 @@
+#!/bin/sh -
+#
+# from named.reload 5.2 (Berkeley) 6/27/89
+# $Id: named.reload.sh,v 8.1 1994/12/15 06:24:14 vixie Exp $
+#
+
+exec %DESTSBIN%/%INDOT%ndc reload
diff --git a/contrib/bind/named/named.restart.sh b/contrib/bind/named/named.restart.sh
new file mode 100644
index 0000000..4d073e6
--- /dev/null
+++ b/contrib/bind/named/named.restart.sh
@@ -0,0 +1,7 @@
+#!/bin/sh -
+#
+# from named.restart 5.4 (Berkeley) 6/27/89
+# $Id: named.restart.sh,v 8.1 1994/12/15 06:24:14 vixie Exp $
+#
+
+exec %DESTSBIN%/%INDOT%ndc restart
diff --git a/contrib/bind/named/ndc.sh b/contrib/bind/named/ndc.sh
new file mode 100644
index 0000000..883dabc
--- /dev/null
+++ b/contrib/bind/named/ndc.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+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
+ %INDOT%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
+ %INDOT%named && {
+ sleep 5
+ echo Name Server Restarted
+ }
+ ;;
+ *) eval "$USAGE";;
+ esac
+done
+test -z "$ARG" && eval "$USAGE"
+
+exit 0
diff --git a/contrib/bind/named/ns_defs.h b/contrib/bind/named/ns_defs.h
new file mode 100644
index 0000000..6bd10e5
--- /dev/null
+++ b/contrib/bind/named/ns_defs.h
@@ -0,0 +1,397 @@
+/*
+ * from ns.h 4.33 (Berkeley) 8/23/90
+ * $Id: ns_defs.h,v 8.6 1996/05/17 09:10:46 vixie Exp $
+ */
+
+/*
+ * ++Copyright++ 1986
+ * -
+ * Copyright (c) 1986
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+/*
+ * Global 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)
+
+ /* 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 { nssRcvdR, /* sent us an answer */
+ nssRcvdNXD, /* sent us a negative response */
+ nssRcvdFwdR, /* sent us a response we had to fwd */
+ nssRcvdDupR, /* sent us an extra answer */
+ nssRcvdFail, /* sent us a SERVFAIL */
+ nssRcvdFErr, /* sent us a FORMERR */
+ nssRcvdErr, /* sent us some other error */
+ 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 */
+ nssSentDupQ, /* sent them a retry */
+ nssSendtoErr, /* error in sendto */
+#ifdef XSTATS
+ nssRcvdQ, /* sent us a query */
+ nssRcvdIQ, /* sent us an inverse query */
+ nssRcvdFwdQ, /* sent us a query we had to fwd */
+ nssRcvdDupQ, /* sent us a retry */
+ nssRcvdTCP, /* sent us a query using TCP */
+ nssSentFwdR, /* fwdd a response to them */
+ nssSentFail, /* sent them a SERVFAIL */
+ nssSentFErr, /* sent them a FORMERR */
+ 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/contrib/bind/named/ns_forw.c b/contrib/bind/named/ns_forw.c
new file mode 100644
index 0000000..362bf8b
--- /dev/null
+++ b/contrib/bind/named/ns_forw.c
@@ -0,0 +1,1094 @@
+#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.14 1996/08/05 08:31: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/types.h>
+#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)));
+#ifdef XSTATS
+ nameserIncr(fp->sin_addr, nssRcvdDupQ);
+#endif
+ 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*)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);
+ }
+#ifdef XSTATS
+ nameserIncr(fp->sin_addr, nssRcvdFwdQ);
+#endif
+ 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;
+ const char *a_type;
+ int print_a;
+
+ dprintf(2, (ddt, "NS '%s' %s\n", dname, complaint));
+ if (sysloginfo && queryname && !haveComplained(queryname, complaint))
+ {
+ char buf[999];
+
+ a = ns = (char *)NULL;
+ print_a = (a_rr->d_type == T_A);
+ a_type = p_type(a_rr->d_type);
+#ifdef NCACHE
+ if (a_rr->d_rcode) {
+ print_a = 0;
+ switch(a_rr->d_rcode) {
+ case NXDOMAIN:
+ a_type = "NXDOMAIN";
+ break;
+ case NOERROR_NODATA:
+ a_type = "NODATA";
+ break;
+ }
+ }
+#endif
+#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 (%s=%s:NS=%s)",
+ sysloginfo, queryname,
+ complaint, dname,
+ print_a ?
+ inet_ntoa(data_inaddr(a_rr->d_data)) : "",
+ a_type,
+ a ? a : "<Not Available>",
+ ns ? ns : "<Not Available>" );
+ else
+ sprintf(buf, "%s: query(%s) %s (%s:%s)",
+ sysloginfo, queryname,
+ complaint, dname,
+ print_a ?
+ 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, potential_ns;
+ time_t curtime;
+
+ dprintf(3, (ddt, "nslookup(nsp=0x%lx, qp=0x%lx, \"%s\")\n",
+ (u_long)nsp, (u_long)qp, syslogdname));
+
+ potential_ns = 0;
+ 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) {
+ dprintf(3, (ddt, "%s: not found %s %lx\n",
+ dname, fname, (u_long)np));
+ found_arr = 0;
+ goto need_sysquery;
+ }
+ if (fname != dname) {
+ if (findMyZone(np, class) == DB_Z_CACHE) {
+ /*
+ * lifted from findMyZone()
+ * We really need to know if the NS
+ * is the bottom of one of our zones
+ * to see if we've got missing glue
+ */
+ for (; np; np = np_parent(np))
+ for (dp = np->n_data; dp; dp=dp->d_next)
+ if (match(dp, class, T_NS)) {
+#ifdef NCACHE
+ if (dp->d_rcode)
+ break;
+#endif
+ if (dp->d_zone) {
+ static char *complaint =
+ "Glue A RR missing";
+ nslookupComplain(sysloginfo,
+ syslogdname,
+ complaint,
+ dname, dp,
+ nsdp);
+ goto skipserver;
+ } else {
+ found_arr = 0;
+ goto need_sysquery;
+ }
+ }
+ /* shouldn't happen, but ... */
+ found_arr = 0;
+ goto need_sysquery;
+ } else {
+ static char *complaint =
+ "Authoritative A RR missing";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp, nsdp);
+ continue;
+ }
+ }
+ found_arr = 0;
+ oldn = n;
+
+ /* look for name server addresses */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ struct in_addr nsa;
+
+ if (dp->d_type == T_CNAME && dp->d_class == class) {
+ static char *complaint = "NS points to CNAME";
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp, nsdp);
+ goto skipserver;
+ }
+ if (dp->d_type != T_A || dp->d_class != class)
+ continue;
+#ifdef NCACHE
+ if (dp->d_rcode) {
+ static char *complaint =
+ "A RR negative cache entry";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp, nsdp);
+ goto skipserver;
+ }
+#endif
+ 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",
+ NAME(*np)));
+ /* 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)
+ *
+ * try to limp along instead of denying service
+ * gdonl mar96
+ */
+ if (aIsUs(nsa)) {
+ static char *complaint = "contains our address";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp, nsdp);
+ continue;
+ }
+ /*
+ * 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)
+ *
+ * try to limp along instead of denying service
+ * gdonl mar96
+ */
+ 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);
+ continue;
+ }
+#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) {
+ potential_ns++;
+ if (!(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;
+ if (n == 0 && potential_ns == 0 && !fwdtab) {
+ static char *complaint = "No possible A RRs";
+ if (sysloginfo && syslogdname &&
+ !haveComplained(syslogdname, complaint))
+ {
+ syslog(LOG_INFO, "%s: query(%s) %s",
+ sysloginfo, syslogdname, complaint);
+ }
+ return(-1);
+ }
+#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)));
+ }
+#ifdef XSTATS
+ nameserIncr(qp->q_from.sin_addr, nssSentFail);
+#endif
+ qremove(qp);
+ return;
+
+found:
+ if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0)
+ qp->q_addr[n].stime = tt;
+ qp->q_curaddr = n;
+ hp = (HEADER *)qp->q_msg;
+ hp->rd = (qp->q_fwd ? 1 : 0);
+ 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/contrib/bind/named/ns_func.h b/contrib/bind/named/ns_func.h
new file mode 100644
index 0000000..204aee2
--- /dev/null
+++ b/contrib/bind/named/ns_func.h
@@ -0,0 +1,166 @@
+/* ns_func.h - declarations for ns_*.c's externally visible functions
+ *
+ * $Id: ns_func.h,v 8.9 1996/05/20 15:10:01 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 *));
+extern enum context ns_ptrcontext __P((const char *owner));
+extern enum context ns_ownercontext __P((int type, enum transport));
+extern int ns_nameok __P((const char *name, int class,
+ enum transport, enum context));
+extern int ns_wildcard __P((const char *name));
+/* --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/contrib/bind/named/ns_glob.h b/contrib/bind/named/ns_glob.h
new file mode 100644
index 0000000..46abaf7
--- /dev/null
+++ b/contrib/bind/named/ns_glob.h
@@ -0,0 +1,291 @@
+/*
+ * from ns.h 4.33 (Berkeley) 8/23/90
+ * $Id: ns_glob.h,v 8.9 1996/05/20 15:10:01 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
+
+enum context { domain_ctx, owner_ctx, mailname_ctx, hostname_ctx };
+DECL const char *context_strings[]
+#ifdef MAIN_PROGRAM
+ = { "domain", "owner", "mail", "host", NULL }
+#endif
+;
+
+enum transport { primary_trans, secondary_trans, response_trans, num_trans };
+DECL const char *transport_strings[]
+#ifdef MAIN_PROGRAM
+ = { "primary", "secondary", "response", NULL }
+#endif
+;
+
+enum severity { ignore, warn, fail };
+DECL const char *severity_strings[]
+#ifdef MAIN_PROGRAM
+ = { "ignore", "warn", "fail", NULL }
+#endif
+;
diff --git a/contrib/bind/named/ns_init.c b/contrib/bind/named/ns_init.c
new file mode 100644
index 0000000..3ca8180
--- /dev/null
+++ b/contrib/bind/named/ns_init.c
@@ -0,0 +1,1110 @@
+#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.17 1996/08/05 08:31: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/types.h>
+#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_checknames __P((const char *names,
+ const char *severity)),
+ 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));
+
+static enum severity checkname_severity[num_trans];
+
+/*
+ * 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);
+
+ memset(checkname_severity, '\0', sizeof checkname_severity);
+ checkname_severity[primary_trans] = fail;
+ checkname_severity[secondary_trans] = warn;
+ checkname_severity[response_trans] = ignore;
+
+ 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, "check-names") == 0) {
+ (void) getword(buf, sizeof(buf), fp, 0);
+ (void) getword(obuf, sizeof(obuf), fp, 0);
+ ns_checknames(buf, obuf);
+ 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 multiple 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 int
+select_string(strings, string)
+ const char *strings[];
+ const char *string;
+{
+ int i;
+
+ for (i = 0; strings[i] != NULL; i++)
+ if (!strcasecmp(strings[i], string))
+ return (i);
+ return (-1);
+}
+
+static void
+ns_checknames(transport_str, severity_str)
+ const char *transport_str;
+ const char *severity_str;
+{
+ enum transport transport;
+ enum severity severity;
+ int i;
+
+ if ((i = select_string(transport_strings, transport_str)) == -1) {
+ syslog(LOG_ERR,
+ "error: unrecognized transport type in bootfile: \"%s\"",
+ transport_str);
+ exit(1);
+ }
+ transport = (enum transport) i;
+
+ if ((i = select_string(severity_strings, severity_str)) == -1) {
+ syslog(LOG_ERR,
+ "error: unrecognized severity type in bootfile: \"%s\"",
+ severity_str);
+ exit(1);
+ }
+ severity = (enum severity) i;
+
+ checkname_severity[transport] = severity;
+ syslog(LOG_INFO, "check-names %s %s", transport_str, severity_str);
+}
+
+enum context
+ns_ptrcontext(owner)
+ const char *owner;
+{
+ if (samedomain(owner, "in-addr.arpa") || samedomain(owner, "ip6.int"))
+ return (hostname_ctx);
+ return (domain_ctx);
+}
+
+enum context
+ns_ownercontext(type, transport)
+ int type;
+ enum transport transport;
+{
+ enum context context;
+
+ switch (type) {
+ case T_A:
+ case T_WKS:
+ case T_MX:
+ switch (transport) {
+ case primary_trans:
+ case secondary_trans:
+ context = owner_ctx;
+ break;
+ case response_trans:
+ context = hostname_ctx;
+ break;
+ default:
+ abort();
+ }
+ break;
+ case T_MB:
+ case T_MG:
+ context = mailname_ctx;
+ default:
+ context = domain_ctx;
+ break;
+ }
+ return (context);
+}
+
+int
+ns_nameok(name, class, transport, context)
+ const char *name;
+ int class;
+ enum transport transport;
+ enum context context;
+{
+ int ok = 1;
+ enum severity severity = checkname_severity[transport];
+
+ if (severity == ignore)
+ return (1);
+ switch (context) {
+ case domain_ctx:
+ ok = (class != C_IN) || res_dnok(name);
+ break;
+ case owner_ctx:
+ ok = (class != C_IN) || res_ownok(name);
+ break;
+ case mailname_ctx:
+ ok = res_mailok(name);
+ break;
+ case hostname_ctx:
+ ok = res_hnok(name);
+ break;
+ default:
+ abort();
+ }
+ if (!ok) {
+ syslog((transport == response_trans) ? LOG_INFO : LOG_NOTICE,
+ "%s name \"%s %s\" (%s) is invalid - %s",
+ context_strings[context],
+ name, p_class(class),
+ transport_strings[transport],
+ (severity == fail) ? "rejecting" : "proceeding anyway");
+ if (severity == warn)
+ ok = 1;
+ }
+ return (ok);
+}
+
+int
+ns_wildcard(name)
+ const char *name;
+{
+ if (*name != '*')
+ return (0);
+ return (*++name == '\0');
+}
+
+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 = limits.rlim_max = 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/contrib/bind/named/ns_main.c b/contrib/bind/named/ns_main.c
new file mode 100644
index 0000000..bac7d5a
--- /dev/null
+++ b/contrib/bind/named/ns_main.c
@@ -0,0 +1,1669 @@
+#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.17 1996/08/05 08:31:30 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/types.h>
+#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;
+ 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, "w");
+ 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();
+ nfds = getdtablesize(); /* get the number of file descriptors */
+ if (nfds > FD_SETSIZE) {
+ nfds = FD_SETSIZE; /* Bulletproofing */
+ syslog(LOG_NOTICE, "Return from getdtablesize() > FD_SETSIZE");
+ }
+#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: %m");
+ sleep(60);
+ }
+ if (n <= 0)
+ continue;
+
+ for (dqp = datagramq;
+ dqp != QDATAGRAM_NULL;
+ dqp = dqp->dq_next) {
+ if (FD_ISSET(dqp->dq_dfd, &tmpmask))
+ for (udpcnt = 0; udpcnt < 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*)
+ 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);
+ 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) {
+#ifdef XSTATS
+ nameserIncr(sp->s_from.sin_addr, nssRcvdTCP);
+#endif
+ 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",
+ (u_long)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/contrib/bind/named/ns_maint.c b/contrib/bind/named/ns_maint.c
new file mode 100644
index 0000000..631210b
--- /dev/null
+++ b/contrib/bind/named/ns_maint.c
@@ -0,0 +1,1100 @@
+#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.16 1996/08/05 08:31: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 && (!NoRecurse || !NoFetchGlue))
+ 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, (u_long)serial,
+ inet_ntoa(from_addr.sin_addr),
+ (u_long)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
+ if (debug) {
+ for (i = 0; i < argc; i++)
+ fprintf(ddt, " %s", argv[i]);
+ fprintf(ddt, "\n");
+ }
+#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",
+ (u_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 &&
+ !ns_wildcard(NAME(*np))) {
+ 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/contrib/bind/named/ns_ncache.c b/contrib/bind/named/ns_ncache.c
new file mode 100644
index 0000000..eb8faaf
--- /dev/null
+++ b/contrib/bind/named/ns_ncache.c
@@ -0,0 +1,154 @@
+/**************************************************************************
+ * ns_ncache.c
+ * author: anant kumar
+ * last modification: March 17, 1993
+ *
+ * implements negative caching
+ */
+
+#include <sys/types.h>
+#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:%ld\n",
+ dname, p_type(type), p_class(class),
+ dp->d_rcode, (long)(dp->d_ttl-tt.tv_sec)));
+ return;
+}
+
+#endif /*NCACHE*/
diff --git a/contrib/bind/named/ns_req.c b/contrib/bind/named/ns_req.c
new file mode 100644
index 0000000..c485f59
--- /dev/null
+++ b/contrib/bind/named/ns_req.c
@@ -0,0 +1,2179 @@
+#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.20 1996/08/05 08:31:30 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/types.h>
+#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*)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;
+
+#ifdef XSTATS
+ nameserIncr(from->sin_addr, nssRcvdQ);
+#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);
+ 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 (NAME(*np)[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_parent(np);
+ }
+ 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;
+
+#ifdef XSTATS
+ nameserIncr(from->sin_addr, nssRcvdIQ);
+#endif
+
+ 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", NAME(*np)));
+ 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, (u_long)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) {
+ if ((dp->d_flags & DB_F_HINT) != 0
+ || dp->d_ttl < (u_int32_t)tt.tv_sec) {
+ ttl = 0;
+ } else
+ ttl = dp->d_ttl - (u_int32_t) tt.tv_sec;
+ } 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) &&
+ !match(dp, (int)ap->a_class, T_AAAA) &&
+ !match(dp, C_IN, T_AAAA)) {
+ continue;
+ }
+ foundany++;
+ if (stale(dp)) {
+ foundstale++;
+ dprintf(1, (ddt,
+ "doaddinfo: stale entry '%s'%s\n",
+ NAME(*np),
+ (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*)nhash(ap->a_dname),
+ (char*)nhash(ap->a_rname))) {
+ syslog(LOG_DEBUG,
+ "\"%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) || (NAME(*top)[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) && (NAME(*top)[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) && (NAME(*top)[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 (NAME(*np)[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)=%lu\n",
+ (u_long)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;
+ int pipefd[2];
+ char c;
+#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"));
+
+ /* create a pipe to synchronize parent and child */
+ if (pipe(pipefd) != 0) {
+ syslog(LOG_NOTICE, "startxfr(%s -> %s) failing; pipe: %m",
+ dname, sin_ntoa(&qsp->s_from));
+ sqrm(qsp);
+ return;
+ }
+
+ /*
+ * 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));
+ close(pipefd[0]);
+ close(pipefd[1]);
+ sqrm(qsp);
+ return;
+ case 0:
+ /* child */
+ break;
+ default:
+ /* parent */
+ syslog(LOG_DEBUG, "zone transfer of \"%s\" to %s (pid %lu)",
+ dname, sin_ntoa(&qsp->s_from), (u_long)pid);
+ close(pipefd[0]); /* close the read end */
+ sqrm(qsp);
+ /* close the write end to release the child */
+ close(pipefd[1]);
+ 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);
+
+ close(pipefd[1]); /* close the write end */
+ /*
+ * Wait for parent to close the write end of the pipe which
+ * we'll see as an EOF. The parent won't close the write end
+ * until it has closed the fd we'll be writing to, at which
+ * point it will be safe for us to proceed.
+ *
+ * We shouldn't get interrupted, but ...
+ */
+ while (read(pipefd[0], &c, 1) == -1 && errno == EINTR)
+ ; /* nothing */
+ close(pipefd[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/contrib/bind/named/ns_resp.c b/contrib/bind/named/ns_resp.c
new file mode 100644
index 0000000..f64306e
--- /dev/null
+++ b/contrib/bind/named/ns_resp.c
@@ -0,0 +1,2743 @@
+#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.27 1996/08/05 08:31:30 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/types.h>
+#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",
+ badNameFound[] = "found an invalid domain name";
+
+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], msgbuf[MAXDNAME*2];
+ 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 (!ns_nameok(qname, qclass, response_trans,
+ ns_ownercontext(qtype, response_trans))) {
+ formerrmsg = badNameFound;
+ goto formerr;
+ }
+ 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)) {
+ 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*)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 (!ns_nameok(name, class, response_trans,
+ ns_ownercontext(type, response_trans))) {
+ formerrmsg = badNameFound;
+ 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*)nhash(sin_ntoa(&from_addr)),
+ (char*)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 (!ns_nameok(name, class, response_trans,
+ ns_ownercontext(type, response_trans))){
+ formerrmsg = badNameFound;
+ goto formerr;
+ }
+ if (strcasecmp(qname, name) ||
+ qtype != type ||
+ qclass != class) {
+ 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);
+ } else {
+ retry(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 */
+ /*
+ * XXX - if this response is forwarded to the client
+ * the truncated section is included. We will not
+ * validate it, and if it somehow corrupt, we won't
+ * notice.
+ *
+ * XXX - if the answer section is truncated and we got
+ * this response after being redirected by a CNAME, we
+ * will not include any part of the final answer in our
+ * response to the client. This will make the client
+ * think that there are no RRs of the appropriate type.
+ */
+ }
+
+ 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);
+ if (!ns_nameok(name, class, response_trans,
+ ns_ownercontext(type, response_trans))) {
+ formerrmsg = badNameFound;
+ goto formerr;
+ }
+
+ /*
+ * 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 && count && !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.
+ *
+ * Don't set restart if count==0, since this means
+ * the response was truncated in the answer section,
+ * causing us to set count to 0 which will cause
+ * validanswer to be 0 as well even though the answer
+ * section probably contained valid RRs (just not
+ * a complete set).
+ * XXX - this works right if we can just forward this
+ * response to the client, but not if we found a CNAME
+ * in a prior response and restarted 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;
+ }
+ if (!res_dnok(dname)) {
+ dprintf(1, (ddt, "bad name (%s)\n", dname));
+ 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"));
+ if (cname) /* a remote CNAME that does not have data */
+ goto return_newmsg;
+ goto servfail;
+ } else {
+ dprintf(3, (ddt, "resp: no addrs found for NS's\n"));
+ /*
+ * Timeout while sysquery looks up the NS addresses.
+ *
+ * Hopefully we'll have them when the client asks
+ * again.
+ *
+ * too bad we can't just wait for the sysquery
+ * response to restart this query (it's too hard).
+ *
+ * We could try to crawl back up the tree looking
+ * for reachable servers, but we may have just
+ * gotten delegated down here by a response with
+ * no A RRs for the servers. If we blindly tried
+ * this strategy, we bang on the same server forever.
+ */
+ goto timeout;
+ }
+ }
+ 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*)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 */
+#ifdef XSTATS
+ nameserIncr(nsa->sin_addr, nssSentFwdR);
+#endif
+ 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*)from_addr.sin_addr.s_addr,
+ (char*)nhash(formerrmsg)))
+ syslog(LOG_INFO, "Malformed response from %s (%s)\n",
+ sin_ntoa(&from_addr), formerrmsg);
+#ifdef XSTATS
+ nameserIncr(from_addr.sin_addr, nssSentFErr);
+#endif
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+
+ return_msg:
+ nameserIncr(from_addr.sin_addr, nssRcvdFwdR);
+#ifdef XSTATS
+ nameserIncr(qp->q_from.sin_addr, nssSentFwdR);
+#endif
+ /* 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:
+#ifdef XSTATS
+ nameserIncr(qp->q_from.sin_addr, nssSentFail);
+#endif
+ hp = (HEADER *)(qp->q_cmsglen ? 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, (qp->q_cmsglen ? qp->q_cmsglen : qp->q_msglen),
+ qp);
+ timeout:
+ 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;
+ enum context context;
+#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);
+ if (!ns_nameok(dname, class, response_trans,
+ ns_ownercontext(type, response_trans))) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ 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_AAAA:
+ 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);
+ }
+ if (!ns_nameok((char *)data, class, response_trans,
+ (type == T_PTR)
+ ? ns_ptrcontext(dname)
+ : domain_ctx)) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = data;
+ n = strlen((char *)data) + 1;
+ break;
+
+ case T_SOA:
+ context = hostname_ctx;
+ goto soa_rp_minfo;
+ case T_RP:
+ case T_MINFO:
+ context = mailname_ctx;
+ /* FALLTHROUGH */
+ soa_rp_minfo:
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if (!ns_nameok((char *)data, class, response_trans, context)) {
+ 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);
+ }
+ if (type == T_RP)
+ context = domain_ctx;
+ else
+ context = mailname_ctx;
+ if (!ns_nameok((char *)cp1, class, response_trans, context)) {
+ 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);
+ }
+ if (!ns_nameok((char *)cp1, class, response_trans,
+ hostname_ctx)) {
+ 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);
+ }
+ if (!ns_nameok((char *)cp1, class, response_trans,
+ domain_ctx)) {
+ 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);
+ }
+ if (!ns_nameok((char *)cp1, class, response_trans,
+ domain_ctx)) {
+ 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*)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*)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*)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 {
+ fetch_a:
+ count = nslookup(nsp, qp, dname, "sysquery");
+ if (count <= 0) {
+ if (count < 0) {
+ syslog(LOG_INFO,
+ "sysquery: nslookup reports danger (%s)",
+ dname);
+ goto err2;
+ } else if (np && NAME(*np)[0] == '\0') {
+ syslog(LOG_WARNING,
+ "sysquery: no addrs found for root NS (%s)",
+ dname);
+ if (class == C_IN && !priming)
+ needs_prime_cache = 1;
+ goto err2;
+ }
+ if (np) {
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+ nsp[0] = NULL;
+#endif
+ np = np_parent(np);
+ n = findns(&np, class, nsp, &count, 0);
+ switch (n) {
+ case NXDOMAIN: /*FALLTHROUGH*/
+ case SERVFAIL:
+ syslog(LOG_DEBUG,
+ "sysquery: findns error (%d) on %s?",
+ n, dname);
+ goto err2;
+ }
+ goto fetch_a;
+ }
+ 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),
+ (long)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*)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 (NAME(*np)[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 (NAME(*np)[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",
+ NAME(*tnp)));
+ /* 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 || NAME(*np)[0] == '\0'))
+ htp = fcachetab;
+ else
+ htp = hashtab;
+
+ try_again:
+ if (htp == fcachetab && class == C_IN && !priming)
+ needs_prime_cache = 1;
+ if (np == NULL) {
+ /* find the root */
+ for (np = htp->h_tab[0]; np != NULL; np = np->n_next)
+ if (NAME(*np)[0] == '\0')
+ break;
+ }
+ while (np != NULL) {
+ dprintf(5, (ddt, "findns: np %#lx '%s'\n",
+ (u_long)np, NAME(*np)));
+ /* 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",
+ NAME(*np)));
+#ifdef DATUMREFCNT
+ /*
+ * We may have already added NS databufs
+ * and are going to throw them away. Fix
+ * fix reference counts. We don't need
+ * free() them here as we just got them
+ * from the cache.
+ */
+ while (nspp > &nsp[0])
+ (*--nspp)->d_rcnt--;
+#endif
+ /* Cache invalidate the NS RR's. */
+#ifndef DATUMREFCNT
+ if (dp->d_ttl < tt.tv_sec)
+#endif
+ delete_all(np, class, T_NS);
+ nsp[0] = NULL;
+ 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, NAME(*np)));
+ *nspp = NULL;
+ *npp = np;
+ return (OK); /* Success, got some NS's */
+ }
+try_parent:
+ np = np_parent(np);
+ }
+ if (htp == hashtab) {
+ htp = fcachetab;
+ 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",
+ NAME(*np)));
+ 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, NAME(*np), 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/contrib/bind/named/ns_sort.c b/contrib/bind/named/ns_sort.c
new file mode 100644
index 0000000..0f53cce
--- /dev/null
+++ b/contrib/bind/named/ns_sort.c
@@ -0,0 +1,171 @@
+#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/contrib/bind/named/ns_stats.c b/contrib/bind/named/ns_stats.c
new file mode 100644
index 0000000..9a29fb1
--- /dev/null
+++ b/contrib/bind/named/ns_stats.c
@@ -0,0 +1,399 @@
+#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.7 1996/08/05 08:31:30 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/types.h>
+#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] = {
+ "RR", /* sent us an answer */
+ "RNXD", /* sent us a negative response */
+ "RFwdR", /* sent us a response we had to fwd */
+ "RDupR", /* sent us an extra answer */
+ "RFail", /* sent us a SERVFAIL */
+ "RFErr", /* sent us a FORMERR */
+ "RErr", /* sent us some other error */
+ "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 */
+ "SDupQ", /* sent them a retry */
+ "SErr", /* sent failed (in sendto) */
+#ifdef XSTATS
+ "RQ", /* sent us a query */
+ "RIQ", /* sent us an inverse query */
+ "RFwdQ", /* sent us a query we had to fwd */
+ "RDupQ", /* sent us a retry */
+ "RTCP", /* sent us a query using TCP */
+ "SFwdR", /* fwdd a response to them */
+ "SFail", /* sent them a SERVFAIL */
+ "SFErr", /* sent them a FORMERR */
+ "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", (u_long)timenow, (u_long)boottime,
+ buffer);
+# undef tv_float
+#endif
+
+ sprintf(header, "NSTATS %lu %lu", (u_long)timenow, (u_long)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/contrib/bind/named/ns_validate.c b/contrib/bind/named/ns_validate.c
new file mode 100644
index 0000000..00df9d7
--- /dev/null
+++ b/contrib/bind/named/ns_validate.c
@@ -0,0 +1,1246 @@
+/**************************************************************************
+ * 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/types.h>
+#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, NAME(*np))) {
+
+ /* 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/contrib/bind/named/pathnames.h b/contrib/bind/named/pathnames.h
new file mode 100644
index 0000000..7ded7d2
--- /dev/null
+++ b/contrib/bind/named/pathnames.h
@@ -0,0 +1,122 @@
+/*
+ * @(#)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/contrib/bind/named/storage.c b/contrib/bind/named/storage.c
new file mode 100644
index 0000000..2fa53cd
--- /dev/null
+++ b/contrib/bind/named/storage.c
@@ -0,0 +1,205 @@
+/*
+ * ++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/types.h>
+#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.2 1996/08/05 08:31:30 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/contrib/bind/named/tree.c b/contrib/bind/named/tree.c
new file mode 100644
index 0000000..58607ea
--- /dev/null
+++ b/contrib/bind/named/tree.c
@@ -0,0 +1,570 @@
+/* tree - balanced binary tree library
+ *
+ * vix 05apr94 [removed vixie.h dependencies; cleaned up formatting, names]
+ * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
+ * vix 23jun86 [added delete uar to add for replaced nodes]
+ * vix 20jun86 [added tree_delete per wirth a+ds (mod2 v.) p. 224]
+ * vix 06feb86 [added tree_mung()]
+ * vix 02feb86 [added tree balancing from wirth "a+ds=p" p. 220-221]
+ * vix 14dec85 [written]
+ */
+
+
+/* This program text was created by Paul Vixie using examples from the book:
+ * "Algorithms & Data Structures," Niklaus Wirth, Prentice-Hall, 1986, ISBN
+ * 0-13-022005-1. Any errors in the conversion from Modula-2 to C are Paul
+ * Vixie's.
+ *
+ * This code and associated documentation is hereby placed in the public
+ * domain, with the wish that my name and Prof. Wirth's not be removed
+ * from the source or documentation.
+ */
+
+
+#ifndef LINT
+static char RCSid[] = "$Id:";
+#endif
+
+
+/*#define DEBUG "tree"*/
+
+
+#include <stdio.h>
+#ifndef _PATH_XFER
+# include <stdlib.h>
+#else
+# include "../conf/portability.h"
+#endif
+#include "tree.h"
+
+
+#ifdef DEBUG
+static int debugDepth = 0;
+static char *debugFuncs[256];
+# define ENTER(proc) { \
+ debugFuncs[debugDepth] = proc; \
+ fprintf(stderr, "ENTER(%d:%s.%s)\n", \
+ debugDepth, DEBUG,
+ debugFuncs[debugDepth]); \
+ debugDepth++; \
+ }
+# define RET(value) { \
+ debugDepth--; \
+ fprintf(stderr, "RET(%d:%s.%s)\n", \
+ debugDepth, DEBUG, \
+ debugFuncs[debugDepth]); \
+ return (value); \
+ }
+# define RETV { \
+ debugDepth--; \
+ fprintf(stderr, "RETV(%d:%s.%s)\n", \
+ debugDepth, DEBUG, \
+ debugFuncs[debugDepth]); \
+ return; \
+ }
+# define MSG(msg) fprintf(stderr, "MSG(%s)\n", msg);
+#else
+# define ENTER(proc) ;
+# define RET(value) return (value);
+# define RETV return;
+# define MSG(msg) ;
+#endif
+
+
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif
+
+
+static tree * sprout __P( (tree **, tree_t, int *, int (*)(), void (*)()) );
+static int delete __P( (tree **, int (*)(), tree_t, void (*)(),
+ int *, int *) );
+static void del __P( (tree **, int *, tree **, void (*)(), int *) );
+static void bal_L __P( (tree **, int *) );
+static void bal_R __P( (tree **, int *) );
+
+
+void
+tree_init(ppr_tree)
+ tree **ppr_tree;
+{
+ ENTER("tree_init")
+ *ppr_tree = NULL;
+ RETV
+}
+
+
+tree_t
+tree_srch(ppr_tree, pfi_compare, p_user)
+ tree **ppr_tree;
+ int (*pfi_compare)();
+ tree_t p_user;
+{
+ register int i_comp;
+
+ ENTER("tree_srch")
+
+ if (*ppr_tree) {
+ i_comp = (*pfi_compare)(p_user, (**ppr_tree).data);
+
+ if (i_comp > 0)
+ RET(tree_srch(&(**ppr_tree).right,
+ pfi_compare,
+ p_user))
+
+ if (i_comp < 0)
+ RET(tree_srch(&(**ppr_tree).left,
+ pfi_compare,
+ p_user))
+
+ /* not higher, not lower... this must be the one.
+ */
+ RET((**ppr_tree).data)
+ }
+
+ /* grounded. NOT found.
+ */
+ RET(NULL)
+}
+
+
+tree_t
+tree_add(ppr_tree, pfi_compare, p_user, pfv_uar)
+ tree **ppr_tree;
+ int (*pfi_compare)();
+ tree_t p_user;
+ void (*pfv_uar)();
+{
+ int i_balance = FALSE;
+
+ ENTER("tree_add")
+ if (!sprout(ppr_tree, p_user, &i_balance, pfi_compare, pfv_uar))
+ RET(NULL)
+ RET(p_user)
+}
+
+
+int
+tree_delete(ppr_p, pfi_compare, p_user, pfv_uar)
+ tree **ppr_p;
+ int (*pfi_compare)();
+ tree_t p_user;
+ void (*pfv_uar)();
+{
+ int i_balance = FALSE,
+ i_uar_called = FALSE;
+
+ ENTER("tree_delete");
+ RET(delete(ppr_p, pfi_compare, p_user, pfv_uar,
+ &i_balance, &i_uar_called))
+}
+
+
+int
+tree_trav(ppr_tree, pfi_uar)
+ tree **ppr_tree;
+ int (*pfi_uar)();
+{
+ ENTER("tree_trav")
+
+ if (!*ppr_tree)
+ RET(TRUE)
+
+ if (!tree_trav(&(**ppr_tree).left, pfi_uar))
+ RET(FALSE)
+ if (!(*pfi_uar)((**ppr_tree).data))
+ RET(FALSE)
+ if (!tree_trav(&(**ppr_tree).right, pfi_uar))
+ RET(FALSE)
+ RET(TRUE)
+}
+
+
+void
+tree_mung(ppr_tree, pfv_uar)
+ tree **ppr_tree;
+ void (*pfv_uar)();
+{
+ ENTER("tree_mung")
+ if (*ppr_tree) {
+ tree_mung(&(**ppr_tree).left, pfv_uar);
+ tree_mung(&(**ppr_tree).right, pfv_uar);
+ if (pfv_uar)
+ (*pfv_uar)((**ppr_tree).data);
+ free(*ppr_tree);
+ *ppr_tree = NULL;
+ }
+ RETV
+}
+
+
+static tree *
+sprout(ppr, p_data, pi_balance, pfi_compare, pfv_delete)
+ tree **ppr;
+ tree_t p_data;
+ int *pi_balance;
+ int (*pfi_compare)();
+ void (*pfv_delete)();
+{
+ tree *p1, *p2, *sub;
+ int cmp;
+
+ ENTER("sprout")
+
+ /* are we grounded? if so, add the node "here" and set the rebalance
+ * flag, then exit.
+ */
+ if (!*ppr) {
+ MSG("grounded. adding new node, setting h=true")
+ *ppr = (tree *) malloc(sizeof(tree));
+ if (*ppr) {
+ (*ppr)->left = NULL;
+ (*ppr)->right = NULL;
+ (*ppr)->bal = 0;
+ (*ppr)->data = p_data;
+ *pi_balance = TRUE;
+ }
+ RET(*ppr);
+ }
+
+ /* compare the data using routine passed by caller.
+ */
+ cmp = (*pfi_compare)(p_data, (*ppr)->data);
+
+ /* if LESS, prepare to move to the left.
+ */
+ if (cmp < 0) {
+ MSG("LESS. sprouting left.")
+ sub = sprout(&(*ppr)->left, p_data, pi_balance,
+ pfi_compare, pfv_delete);
+ if (sub && *pi_balance) { /* left branch has grown */
+ MSG("LESS: left branch has grown")
+ switch ((*ppr)->bal) {
+ case 1: /* right branch WAS longer; bal is ok now */
+ MSG("LESS: case 1.. bal restored implicitly")
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ break;
+ case 0: /* balance WAS okay; now left branch longer */
+ MSG("LESS: case 0.. balnce bad but still ok")
+ (*ppr)->bal = -1;
+ break;
+ case -1: /* left branch was already too long. rebal */
+ MSG("LESS: case -1: rebalancing")
+ p1 = (*ppr)->left;
+ if (p1->bal == -1) { /* LL */
+ MSG("LESS: single LL")
+ (*ppr)->left = p1->right;
+ p1->right = *ppr;
+ (*ppr)->bal = 0;
+ *ppr = p1;
+ } else { /* double LR */
+ MSG("LESS: double LR")
+
+ p2 = p1->right;
+ p1->right = p2->left;
+ p2->left = p1;
+
+ (*ppr)->left = p2->right;
+ p2->right = *ppr;
+
+ if (p2->bal == -1)
+ (*ppr)->bal = 1;
+ else
+ (*ppr)->bal = 0;
+
+ if (p2->bal == 1)
+ p1->bal = -1;
+ else
+ p1->bal = 0;
+ *ppr = p2;
+ } /*else*/
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ } /*switch*/
+ } /*if*/
+ RET(sub)
+ } /*if*/
+
+ /* if MORE, prepare to move to the right.
+ */
+ if (cmp > 0) {
+ MSG("MORE: sprouting to the right")
+ sub = sprout(&(*ppr)->right, p_data, pi_balance,
+ pfi_compare, pfv_delete);
+ if (sub && *pi_balance) {
+ MSG("MORE: right branch has grown")
+
+ switch ((*ppr)->bal) {
+ case -1:
+ MSG("MORE: balance was off, fixed implicitly")
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ break;
+ case 0:
+ MSG("MORE: balance was okay, now off but ok")
+ (*ppr)->bal = 1;
+ break;
+ case 1:
+ MSG("MORE: balance was off, need to rebalance")
+ p1 = (*ppr)->right;
+ if (p1->bal == 1) { /* RR */
+ MSG("MORE: single RR")
+ (*ppr)->right = p1->left;
+ p1->left = *ppr;
+ (*ppr)->bal = 0;
+ *ppr = p1;
+ } else { /* double RL */
+ MSG("MORE: double RL")
+
+ p2 = p1->left;
+ p1->left = p2->right;
+ p2->right = p1;
+
+ (*ppr)->right = p2->left;
+ p2->left = *ppr;
+
+ if (p2->bal == 1)
+ (*ppr)->bal = -1;
+ else
+ (*ppr)->bal = 0;
+
+ if (p2->bal == -1)
+ p1->bal = 1;
+ else
+ p1->bal = 0;
+
+ *ppr = p2;
+ } /*else*/
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ } /*switch*/
+ } /*if*/
+ RET(sub)
+ } /*if*/
+
+ /* not less, not more: this is the same key! replace...
+ */
+ MSG("FOUND: Replacing data value")
+ *pi_balance = FALSE;
+ if (pfv_delete)
+ (*pfv_delete)((*ppr)->data);
+ (*ppr)->data = p_data;
+ RET(*ppr)
+}
+
+
+static int
+delete(ppr_p, pfi_compare, p_user, pfv_uar, pi_balance, pi_uar_called)
+ tree **ppr_p;
+ int (*pfi_compare)();
+ tree_t p_user;
+ void (*pfv_uar)();
+ int *pi_balance;
+ int *pi_uar_called;
+{
+ tree *pr_q;
+ int i_comp, i_ret;
+
+ ENTER("delete")
+
+ if (*ppr_p == NULL) {
+ MSG("key not in tree")
+ RET(FALSE)
+ }
+
+ i_comp = (*pfi_compare)((*ppr_p)->data, p_user);
+ if (i_comp > 0) {
+ MSG("too high - scan left")
+ i_ret = delete(&(*ppr_p)->left, pfi_compare, p_user, pfv_uar,
+ pi_balance, pi_uar_called);
+ if (*pi_balance)
+ bal_L(ppr_p, pi_balance);
+ } else if (i_comp < 0) {
+ MSG("too low - scan right")
+ i_ret = delete(&(*ppr_p)->right, pfi_compare, p_user, pfv_uar,
+ pi_balance, pi_uar_called);
+ if (*pi_balance)
+ bal_R(ppr_p, pi_balance);
+ } else {
+ MSG("equal")
+ pr_q = *ppr_p;
+ if (pr_q->right == NULL) {
+ MSG("right subtree null")
+ *ppr_p = pr_q->left;
+ *pi_balance = TRUE;
+ } else if (pr_q->left == NULL) {
+ MSG("right subtree non-null, left subtree null")
+ *ppr_p = pr_q->right;
+ *pi_balance = TRUE;
+ } else {
+ MSG("neither subtree null")
+ del(&pr_q->left, pi_balance, &pr_q,
+ pfv_uar, pi_uar_called);
+ if (*pi_balance)
+ bal_L(ppr_p, pi_balance);
+ }
+ if (!*pi_uar_called && pfv_uar)
+ (*pfv_uar)(pr_q->data);
+ free(pr_q); /* thanks to wuth@castrov.cuc.ab.ca */
+ i_ret = TRUE;
+ }
+ RET(i_ret)
+}
+
+
+static void
+del(ppr_r, pi_balance, ppr_q, pfv_uar, pi_uar_called)
+ tree **ppr_r;
+ int *pi_balance;
+ tree **ppr_q;
+ void (*pfv_uar)();
+ int *pi_uar_called;
+{
+ ENTER("del")
+
+ if ((*ppr_r)->right != NULL) {
+ del(&(*ppr_r)->right, pi_balance, ppr_q,
+ pfv_uar, pi_uar_called);
+ if (*pi_balance)
+ bal_R(ppr_r, pi_balance);
+ } else {
+ if (pfv_uar)
+ (*pfv_uar)((*ppr_q)->data);
+ *pi_uar_called = TRUE;
+ (*ppr_q)->data = (*ppr_r)->data;
+ *ppr_q = *ppr_r;
+ *ppr_r = (*ppr_r)->left;
+ *pi_balance = TRUE;
+ }
+
+ RETV
+}
+
+
+static void
+bal_L(ppr_p, pi_balance)
+ tree **ppr_p;
+ int *pi_balance;
+{
+ tree *p1, *p2;
+ int b1, b2;
+
+ ENTER("bal_L")
+ MSG("left branch has shrunk")
+
+ switch ((*ppr_p)->bal) {
+ case -1:
+ MSG("was imbalanced, fixed implicitly")
+ (*ppr_p)->bal = 0;
+ break;
+ case 0:
+ MSG("was okay, is now one off")
+ (*ppr_p)->bal = 1;
+ *pi_balance = FALSE;
+ break;
+ case 1:
+ MSG("was already off, this is too much")
+ p1 = (*ppr_p)->right;
+ b1 = p1->bal;
+ if (b1 >= 0) {
+ MSG("single RR")
+ (*ppr_p)->right = p1->left;
+ p1->left = *ppr_p;
+ if (b1 == 0) {
+ MSG("b1 == 0")
+ (*ppr_p)->bal = 1;
+ p1->bal = -1;
+ *pi_balance = FALSE;
+ } else {
+ MSG("b1 != 0")
+ (*ppr_p)->bal = 0;
+ p1->bal = 0;
+ }
+ *ppr_p = p1;
+ } else {
+ MSG("double RL")
+ p2 = p1->left;
+ b2 = p2->bal;
+ p1->left = p2->right;
+ p2->right = p1;
+ (*ppr_p)->right = p2->left;
+ p2->left = *ppr_p;
+ if (b2 == 1)
+ (*ppr_p)->bal = -1;
+ else
+ (*ppr_p)->bal = 0;
+ if (b2 == -1)
+ p1->bal = 1;
+ else
+ p1->bal = 0;
+ *ppr_p = p2;
+ p2->bal = 0;
+ }
+ }
+ RETV
+}
+
+
+static void
+bal_R(ppr_p, pi_balance)
+ tree **ppr_p;
+ int *pi_balance;
+{
+ tree *p1, *p2;
+ int b1, b2;
+
+ ENTER("bal_R")
+ MSG("right branch has shrunk")
+ switch ((*ppr_p)->bal) {
+ case 1:
+ MSG("was imbalanced, fixed implicitly")
+ (*ppr_p)->bal = 0;
+ break;
+ case 0:
+ MSG("was okay, is now one off")
+ (*ppr_p)->bal = -1;
+ *pi_balance = FALSE;
+ break;
+ case -1:
+ MSG("was already off, this is too much")
+ p1 = (*ppr_p)->left;
+ b1 = p1->bal;
+ if (b1 <= 0) {
+ MSG("single LL")
+ (*ppr_p)->left = p1->right;
+ p1->right = *ppr_p;
+ if (b1 == 0) {
+ MSG("b1 == 0")
+ (*ppr_p)->bal = -1;
+ p1->bal = 1;
+ *pi_balance = FALSE;
+ } else {
+ MSG("b1 != 0")
+ (*ppr_p)->bal = 0;
+ p1->bal = 0;
+ }
+ *ppr_p = p1;
+ } else {
+ MSG("double LR")
+ p2 = p1->right;
+ b2 = p2->bal;
+ p1->right = p2->left;
+ p2->left = p1;
+ (*ppr_p)->left = p2->right;
+ p2->right = *ppr_p;
+ if (b2 == -1)
+ (*ppr_p)->bal = 1;
+ else
+ (*ppr_p)->bal = 0;
+ if (b2 == 1)
+ p1->bal = -1;
+ else
+ p1->bal = 0;
+ *ppr_p = p2;
+ p2->bal = 0;
+ }
+ }
+ RETV
+}
diff --git a/contrib/bind/named/tree.h b/contrib/bind/named/tree.h
new file mode 100644
index 0000000..7d027b9
--- /dev/null
+++ b/contrib/bind/named/tree.h
@@ -0,0 +1,48 @@
+/* tree.h - declare structures used by tree library
+ *
+ * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
+ * vix 27jun86 [broken out of tree.c]
+ *
+ * $Id: tree.h,v 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/contrib/bind/named/tree.man3 b/contrib/bind/named/tree.man3
new file mode 100644
index 0000000..5be48783
--- /dev/null
+++ b/contrib/bind/named/tree.man3
@@ -0,0 +1,154 @@
+.TH TREE 3 "5 April 1994"
+.\" from .TH TREE 3 "22 Jan 1993"
+.\" from .TH TREE 2 "23 June 1986"
+.UC 4
+.SH NAME
+tree_init, tree_mung, tree_srch, tree_add, tree_delete, tree_trav
+\- balanced binary tree routines
+.SH SYNOPSIS
+.nf
+.B void
+.B tree_init(tree)
+.B void **tree;
+.PP
+.B void *
+.B tree_srch(tree, compare, data)
+.B void **tree;
+.B int (*compare)();
+.B void *data;
+.PP
+.B void
+.B tree_add(tree, compare, data, del_uar)
+.B void **tree;
+.B int (*compare)();
+.B void *data;
+.B void (*del_uar)();
+.PP
+.B int
+.B tree_delete(tree, compare, data, del_uar)
+.B void **tree;
+.B int (*compare)();
+.B void *data;
+.B void (*del_uar)();
+.PP
+.B int
+.B tree_trav(tree, trav_uar)
+.B void **tree;
+.B int (*trav_uar)();
+.PP
+.B void
+.B tree_mung(tree, del_uar)
+.B void **tree;
+.B void (*del_uar)();
+.fi
+.SH DESCRIPTION
+These functions create and manipulate a balanced binary (AVL) tree. Each node
+of the tree contains the expected left & right subtree pointers, a short int
+balance indicator, and a pointer to the user data. On a 32 bit system, this
+means an overhead of 4+4+2+4 bytes per node (or, on a RISC or otherwise
+alignment constrained system with implied padding, 4+4+4+4 bytes per node).
+There is no key data type enforced by this package; a caller supplied
+compare routine is used to compare user data blocks.
+.PP
+Balanced binary trees are very fast on searches and replacements, but have a
+moderately high cost for additions and deletions. If your application does a
+lot more searches and replacements than it does additions and deletions, the
+balanced (AVL) binary tree is a good choice for a data structure.
+.PP
+.I Tree_init
+creates an empty tree and binds it to
+.I tree
+(which for this and all other routines in this package should be declared as
+a pointer to void or int, and passed by reference), which can then be used by
+other routines in this package. Note that more than one
+.I tree
+variable can exist at once; thus multiple trees can be manipulated
+simultaneously.
+.PP
+.I Tree_srch
+searches a tree for a specific node and returns either
+.I NULL
+if no node was found, or the value of the user data pointer if the node
+was found.
+.I compare
+is the address of a function to compare two user data blocks. This routine
+should work much the way
+.IR strcmp (3)
+does; in fact,
+.I strcmp
+could be used if the user data was a \s-2NUL\s+2 terminated string.
+.I data
+is the address of a user data block to be used by
+.I compare
+as the search criteria. The tree is searched for a node where
+.I compare
+returns 0.
+.PP
+.I Tree_add
+inserts or replaces a node in the specified tree. The tree specified by
+.I tree
+is searched as in
+.I tree_srch,
+and if a node is found to match
+.I data,
+then the
+.I del_uar
+function, if non\-\s-2NULL\s+2, is called with the address of the user data
+block for the node (this routine should deallocate any dynamic memory which
+is referenced exclusively by the node); the user data pointer for the node
+is then replaced by the value of
+.I data.
+If no node is found to match, a new node is added (which may or may not
+cause a transparent rebalance operation), with a user data pointer equal to
+.I data.
+A rebalance may or may not occur, depending on where the node is added
+and what the rest of the tree looks like.
+.I Tree_add
+will return the
+.I data
+pointer unless catastrophe occurs in which case it will return \s-2NULL\s+2.
+.PP
+.I Tree_delete
+deletes a node from
+.I tree.
+A rebalance may or may not occur, depending on where the node is removed from
+and what the rest of the tree looks like.
+.I Tree_delete
+returns TRUE if a node was deleted, FALSE otherwise.
+.PP
+.I Tree_trav
+traverses all of
+.I tree,
+calling
+.I trav_uar
+with the address of each user data block. If
+.I trav_uar
+returns FALSE at any time,
+.I tree_trav
+will immediately return FALSE to its caller. Otherwise all nodes will be
+reached and
+.I tree_trav
+will return TRUE.
+.PP
+.I Tree_mung
+deletes every node in
+.I tree,
+calling
+.I del_uar
+(if it is not \s-2NULL\s+2) with the user data address from each node (see
+.I tree_add
+and
+.I tree_delete
+above). The tree is left in the same state that
+.I tree_init
+leaves it in \- i.e., empty.
+.SH BUGS
+Should have a way for the caller to specify application specific
+.I malloc
+and
+.I free
+functions to be used internally when allocating meta data.
+.SH AUTHOR
+Paul Vixie, converted and augumented from Modula\-2 examples in
+.I Algorithms & Data Structures,
+Niklaus Wirth, Prentice\-Hall, ISBN 0\-13\-022005\-1.
OpenPOWER on IntegriCloud