summaryrefslogtreecommitdiffstats
path: root/contrib/bind/bin/named
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1998-05-03 04:11:49 +0000
committerpeter <peter@FreeBSD.org>1998-05-03 04:11:49 +0000
commit0666320b4eda500556d2c671c9527c9000057492 (patch)
tree759849259eae9f7cb0d3ddbd7a131081c6688068 /contrib/bind/bin/named
parent58ca52f41726d17758909ddafba7b6b6766c789c (diff)
downloadFreeBSD-src-0666320b4eda500556d2c671c9527c9000057492.zip
FreeBSD-src-0666320b4eda500556d2c671c9527c9000057492.tar.gz
Import (trimmed) ISC bind-8.1.2-t3b. This will be updated to 8.1.2 on
final release. Obtained from: ftp.isc.org
Diffstat (limited to 'contrib/bind/bin/named')
-rw-r--r--contrib/bind/bin/named/Makefile126
-rw-r--r--contrib/bind/bin/named/db_defs.h233
-rw-r--r--contrib/bind/bin/named/db_dict.c111
-rw-r--r--contrib/bind/bin/named/db_dump.c635
-rw-r--r--contrib/bind/bin/named/db_func.h151
-rw-r--r--contrib/bind/bin/named/db_glob.h94
-rw-r--r--contrib/bind/bin/named/db_glue.c616
-rw-r--r--contrib/bind/bin/named/db_load.c2218
-rw-r--r--contrib/bind/bin/named/db_lookup.c269
-rw-r--r--contrib/bind/bin/named/db_save.c221
-rw-r--r--contrib/bind/bin/named/db_update.c932
-rwxr-xr-xcontrib/bind/bin/named/named-bootconf.pl324
-rw-r--r--contrib/bind/bin/named/named.conf426
-rw-r--r--contrib/bind/bin/named/named.h68
-rw-r--r--contrib/bind/bin/named/ns_config.c2366
-rw-r--r--contrib/bind/bin/named/ns_defs.h756
-rw-r--r--contrib/bind/bin/named/ns_forw.c1132
-rw-r--r--contrib/bind/bin/named/ns_func.h380
-rw-r--r--contrib/bind/bin/named/ns_glob.h317
-rw-r--r--contrib/bind/bin/named/ns_glue.c416
-rw-r--r--contrib/bind/bin/named/ns_init.c512
-rw-r--r--contrib/bind/bin/named/ns_lexer.c750
-rw-r--r--contrib/bind/bin/named/ns_lexer.h45
-rw-r--r--contrib/bind/bin/named/ns_main.c2200
-rw-r--r--contrib/bind/bin/named/ns_maint.c1210
-rw-r--r--contrib/bind/bin/named/ns_ncache.c226
-rw-r--r--contrib/bind/bin/named/ns_parser.c2376
-rw-r--r--contrib/bind/bin/named/ns_parser.h110
-rw-r--r--contrib/bind/bin/named/ns_parser.y1473
-rw-r--r--contrib/bind/bin/named/ns_parseutil.c242
-rw-r--r--contrib/bind/bin/named/ns_parseutil.h65
-rw-r--r--contrib/bind/bin/named/ns_req.c1669
-rw-r--r--contrib/bind/bin/named/ns_resp.c3298
-rw-r--r--contrib/bind/bin/named/ns_stats.c415
-rw-r--r--contrib/bind/bin/named/ns_udp.c123
-rw-r--r--contrib/bind/bin/named/ns_update.c2393
-rw-r--r--contrib/bind/bin/named/ns_xfr.c642
-rw-r--r--contrib/bind/bin/named/pathnames.c55
-rw-r--r--contrib/bind/bin/named/pathtemplate.h70
-rw-r--r--contrib/bind/bin/named/test/127.0.0.zone11
-rw-r--r--contrib/bind/bin/named/test/localhost.zone10
-rw-r--r--contrib/bind/bin/named/test/named.conf29
-rw-r--r--contrib/bind/bin/named/test/root.hint37
-rw-r--r--contrib/bind/bin/named/version.c89
44 files changed, 29841 insertions, 0 deletions
diff --git a/contrib/bind/bin/named/Makefile b/contrib/bind/bin/named/Makefile
new file mode 100644
index 0000000..7e30cd0
--- /dev/null
+++ b/contrib/bind/bin/named/Makefile
@@ -0,0 +1,126 @@
+## Copyright (c) 1996, 1997 by Internet Software Consortium
+##
+## 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.
+##
+## THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+## ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+## OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+## CONSORTIUM 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.
+
+# $Id: Makefile,v 8.31 1998/03/20 00:49:46 halley Exp $
+
+DESTDIR=
+CC= cc
+SHELL= /bin/sh
+
+CDEBUG= -g
+
+#(net2 and its descendents)
+SYSTYPE = bsdos
+TOP = ../..
+INCL = ${TOP}/include
+PORTINCL = ${TOP}/port/${SYSTYPE}/include
+LIBBIND = ${TOP}/lib/libbind.a
+A=a
+O=o
+LEX = lex -I
+YACC = yacc -d
+SYSLIBS = -ll -lutil
+PIDDIR = /var/run
+DESTBIN = /usr/local/bin
+DESTSBIN = /usr/local/sbin
+DESTEXEC = /usr/local/libexec
+DESTMAN = /usr/share/man
+DESTHELP= /usr/share/misc
+AR= ar cruv
+INSTALL= install
+STRIP=-s
+
+PS=ps
+LDFLAGS=
+CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} ${DEFS}
+
+VER= LOCAL-`date +%y%m%d.%H%M%S`
+HOSTNAMECMD= hostname || uname -n
+
+PROG= named
+HDRS= db_defs.h db_glob.h ns_defs.h ns_glob.h named.h pathnames.h
+SRCS= db_dump.c db_load.c db_lookup.c db_save.c db_update.c \
+ db_glue.c \
+ ns_parser.c ns_lexer.c ns_parseutil.c \
+ ns_forw.c ns_init.c ns_main.c ns_maint.c ns_req.c \
+ ns_resp.c ns_stats.c ns_ncache.c ns_xfr.c ns_glue.c \
+ ns_udp.c ns_config.c ns_update.c
+OBJS= db_dump.${O} db_load.${O} db_lookup.${O} db_save.${O} db_update.${O} \
+ db_glue.${O} \
+ ns_parser.${O} ns_lexer.${O} ns_parseutil.${O} \
+ ns_forw.${O} ns_init.${O} ns_main.${O} ns_maint.${O} ns_req.${O} \
+ ns_resp.${O} ns_stats.${O} ns_ncache.${O} ns_xfr.${O} ns_glue.${O} \
+ ns_udp.${O} ns_config.${O} ns_update.${O}
+
+all: ${PROG} pathnames
+
+${PROG}: pathnames.h ${OBJS} ${LIBBIND} Makefile tmp_version.${O}
+ ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} tmp_version.${O} \
+ ${LIBBIND} ${SYSLIBS}
+
+ns_parser.c ns_parser.h: ns_parser.y
+ ${YACC} ns_parser.y
+ mv y.tab.c ns_parser.c
+ mv y.tab.h ns_parser.h
+
+tmp_version.${O}: tmp_version.c
+
+tmp_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 > tmp_version.c)
+
+pathnames.h: ${TOP}/.settings Makefile
+ rm -f pathnames.h
+ sed -e "s|%DESTSBIN%|${DESTSBIN}|" \
+ -e "s|%DESTEXEC%|${DESTEXEC}|" \
+ -e "s|%DESTETC%|${DESTETC}|" \
+ -e "s|%DESTRUN%|${DESTRUN}|" \
+ < pathtemplate.h > pathnames.h
+
+pathnames: pathnames.${O} pathnames.h ${LIBBIND} Makefile
+ ${CC} ${CDEBUG} ${LDFLAGS} -o $@ pathnames.${O} \
+ ${LIBBIND} ${SYSLIBS}
+
+distclean: clean
+ rm -f ns_parser.c ns_parser.h
+
+clean: FRC
+ rm -f ${PROG} ${OBJS} core .depend
+ rm -f *.BAK *.CKP *~ *.orig
+ rm -f tmp_version.c tmp_version.${O}
+ rm -f pathnames pathnames.${O} tmp_pathnames.h pathnames.h
+ rm -f y.tab.h y.tab.c
+
+depend: ${SRCS} pathnames.h
+ mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${DEFS} ${SRCS}
+
+${DESTDIR}${DESTSBIN}:
+ mkdir -p ${DESTDIR}${DESTSBIN}
+
+install: ${DESTDIR}${DESTSBIN} ${PROG}
+ ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTSBIN}/${PROG}
+
+links: FRC
+ @ln -s SRC/*.[chy] SRC/test .; rm -f ns_parser.[ch]
+
+tags: FRC
+ ctags ${SRCS} *.h
+
+FRC:
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
diff --git a/contrib/bind/bin/named/db_defs.h b/contrib/bind/bin/named/db_defs.h
new file mode 100644
index 0000000..ab93480
--- /dev/null
+++ b/contrib/bind/bin/named/db_defs.h
@@ -0,0 +1,233 @@
+/*
+ * from db.h 4.16 (Berkeley) 6/1/90
+ * $Id: db_defs.h,v 8.17 1998/02/17 17:17:43 vixie Exp $
+ */
+
+/* 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.
+ */
+
+/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/*
+ * 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 (2*MAXDNAME + 5*INT32SZ)
+
+#define DB_ROOT_TIMBUF 3600
+#define TIMBUF 300
+
+#define DICT_INDEXBITS 24
+#define DICT_MAXLENGTH 127
+#define DICT_INSERT_P 0x0001
+
+/*
+ * Hash table structures.
+ */
+struct databuf {
+ struct databuf *d_next; /* linked list */
+ struct nameser *d_ns; /* NS from whence this came */
+ 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;
+ u_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_size; /* size of data area */
+ u_int32_t d_rcnt;
+ unsigned d_rcode :4; /* rcode for negative caching */
+ unsigned d_mark :12; /* place to mark data */
+ u_int16_t d_nstime; /* NS response time, milliseconds */
+ u_char d_data[sizeof(void*)]; /* dynamic (padded) */
+};
+#define DATASIZE(n) (sizeof(struct databuf) - sizeof(void*) + n)
+
+#ifdef BIND_UPDATE
+/*
+ * d_mark definitions
+ */
+#define D_MARK_DELETED 0x01
+#define D_MARK_ADDED 0x02
+#define D_MARK_FOUND 0x04
+#endif
+
+/*
+ * d_flags definitions
+ */
+#define DB_F_HINT 0x01 /* databuf belongs to fcachetab */
+#define DB_F_ACTIVE 0x02 /* databuf is linked into a cache */
+#define DB_F_FREE 0x04 /* databuf has been freed */
+
+/*
+ * 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_name */
+ 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 (dynamic). */
+};
+#define NAMESIZE(n) (sizeof(struct namebuf) - sizeof(void*) + 1 + n + 1)
+#define NAMELEN(nb) (((u_char *)((nb)._n_name))[0])
+#define NAME(nb) ((nb)._n_name + 1)
+
+struct hashbuf {
+ int h_size; /* size of hash table */
+ int h_cnt; /* number of entries */
+ struct namebuf *h_tab[1]; /* allocated as needed */
+};
+#define HASHSIZE(s) (sizeof(struct hashbuf) + (s-1) * sizeof(struct namebuf *))
+
+#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 65535 /* normal db_dump() */
+#define DB_Z_SPECIAL(z) ((z) == DB_Z_CACHE || (z) == DB_Z_ALL)
+
+/*
+ * 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)
+#ifdef BIND_UPDATE
+#define SERIAL (-11)
+#endif
+
+/*
+ * 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 */
+
+/*
+ * Database access abstractions.
+ */
+#define foreach_rr(dp, np, ty, cl, zn) \
+ for ((dp) = (np)->n_data; (dp) != NULL; (dp) = (dp)->d_next) \
+ if ((cl) != C_ANY && (cl) != (dp)->d_class) \
+ continue; \
+ else if ((ty) != T_ANY && (ty) != (dp)->d_type) \
+ continue; \
+ else if (((zn) == DB_Z_CACHE) \
+ ? stale(dp) \
+ : (zn) != (dp)->d_zone) \
+ continue; \
+ else if ((dp)->d_rcode) \
+ continue; \
+ else \
+ /* Caller code follows in sequence. */
+
+#define DRCNTINC(x) \
+ do { \
+ if (++((x)->d_rcnt) == 0) \
+ ns_panic(ns_log_db, 1, "++d_rcnt == 0"); \
+ } while (0)
+
+#define DRCNTDEC(x) \
+ do { \
+ if (((x)->d_rcnt)-- == 0) \
+ ns_panic(ns_log_db, 1, "d_rcnt-- == 0"); \
+ } while (0)
diff --git a/contrib/bind/bin/named/db_dict.c b/contrib/bind/bin/named/db_dict.c
new file mode 100644
index 0000000..a0b8921
--- /dev/null
+++ b/contrib/bind/bin/named/db_dict.c
@@ -0,0 +1,111 @@
+#if !defined(lint) && !defined(SABER)
+static char rcsid[] = "$Id: db_dict.c,v 8.1 1997/09/26 17:55:40 halley Exp $";
+#endif /* not lint */
+
+/*
+ * Portions Copyright (c) 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#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 <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+#define DICT_BLOCKBITS 8
+#define DICT_BLOCKSHIFT 16
+#define DICT_BLOCKMAX (1 << DICT_BLOCKBITS)
+#define DICT_OFFSETBITS 16
+#define DICT_OFFSETSHIFT 0
+#define DICT_OFFSETMAX (1 << DICT_OFFSETBITS)
+
+#define DICT_CONSUMED(Length) ((Length) + 1)
+#define DICT_INDEX(Block,Offset) (((Block) << DICT_BLOCKSHIFT) | \
+ ((Offset) << DICT_OFFSETSHIFT))
+
+static int dict_new(const char *, int);
+
+static char * blocks[DICT_BLOCKMAX];
+static int offsets[DICT_BLOCKMAX];
+static int cur_block = 0;
+static int cur_offset = -1;
+
+int
+dict_lookup(const char *text, int length, int flags) {
+ int block, offset, ret;
+
+ /* XXX this is a proof of concept, some kind of hash is needed. */
+ for (block = 0; block <= cur_block; block++) {
+ const char *cur = &blocks[block][0];
+ const char *end = &blocks[block][offsets[block]];
+
+ while (cur < end) {
+ int xlength = *cur;
+
+ if (xlength == length &&
+ memcmp(cur+1, text, length) == 0)
+ return (DICT_INDEX(block, offset));
+ cur += DICT_CONSUMED(length);
+ }
+ }
+ if ((flags & DICT_INSERT_P) != 0)
+ return (dict_new(text, length));
+ return (-ENOENT);
+}
+
+static int
+dict_new(const char *text, int length) {
+ int ret;
+
+ if (length < 0 || length > DICT_MAXLENGTH)
+ return (-E2BIG);
+ if (cur_offset + DICT_CONSUMED(length) >= DICT_OFFSETMAX) {
+ if (cur_block + 1 == DICT_BLOCKMAX)
+ return (-ENOSPC);
+ cur_block++;
+ blocks[cur_block] = memget(DICT_OFFSETMAX);
+ if (blocks[cur_block] == NULL)
+ return (-ENOMEM);
+ cur_offset = 0;
+ }
+ assert(cur_offset >= 0);
+ assert(cur_offset + DICT_CONSUMED(length) < DICT_OFFSETMAX);
+ ret = DICT_INDEX(cur_block, cur_offset);
+ blocks[cur_block][cur_offset] = length;
+ memcpy(&blocks[cur_block][cur_offset+1], text, length);
+ cur_offset += DICT_CONSUMED(length);
+ offsets[cur_block] = cur_offset;
+ return (ret);
+}
diff --git a/contrib/bind/bin/named/db_dump.c b/contrib/bind/bin/named/db_dump.c
new file mode 100644
index 0000000..9c15af3
--- /dev/null
+++ b/contrib/bind/bin/named/db_dump.c
@@ -0,0 +1,635 @@
+#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.24 1998/02/13 19:49:09 halley Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#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 <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+static const char *MkCredStr(int);
+
+/*
+ * Dump current data base in a format similar to RFC 883.
+ */
+
+void
+doadump()
+{
+ FILE *fp;
+
+ ns_notice(ns_log_db, "dumping nameserver data");
+
+ if ((fp = write_open(server_options->dump_filename)) == 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);
+ ns_notice(ns_log_db, "finished dumping nameserver data");
+}
+
+int
+zt_dump(FILE *fp) {
+ 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);
+ if (zp->z_axfr_src.s_addr != 0)
+ fprintf(fp, "; update source [%s]\n",
+ inet_ntoa(zp->z_axfr_src));
+ }
+ fprintf(fp, ";; --zone table--\n");
+ return (0);
+}
+
+int
+db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) {
+ struct databuf *dp = NULL;
+ struct namebuf *np;
+ struct namebuf **npp, **nppend;
+ char dname[MAXDNAME];
+ u_int32_t n;
+ u_int32_t addr;
+ int j, i, found_data, tab, printed_origin;
+ u_char *cp, *end;
+ const char *proto, *sep;
+ int16_t type;
+ u_int16_t keyflags;
+ u_char *sigdata;
+ u_char *savecp;
+ char temp_base64[NS_MD5RSA_MAX_BASE64];
+
+ found_data = 0;
+ 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;
+ /* XXX why are we not calling stale() here? */
+ if (dp->d_zone == DB_Z_CACHE &&
+ dp->d_ttl <= (u_int32_t)tt.tv_sec &&
+ (dp->d_flags & DB_F_HINT) == 0)
+ continue;
+ if (!printed_origin) {
+ fprintf(fp, "$ORIGIN %s.\n", origin);
+ printed_origin++;
+ }
+ tab = 0;
+ if (dp->d_rcode == NXDOMAIN ||
+ dp->d_rcode == NOERROR_NODATA) {
+ fputc(';', fp);
+ } else if (found_data == 0 || found_data == 1) {
+ found_data = 2;
+ }
+ 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) < (unsigned)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;";
+ type = dp->d_type;
+ if (dp->d_rcode == NXDOMAIN ||
+ dp->d_rcode == NOERROR_NODATA) {
+#ifdef RETURNSOA
+ if (dp->d_size == 0) {
+#endif
+
+ fprintf(fp, "%s%s-$",
+ (dp->d_rcode == NXDOMAIN)
+ ?"NXDOMAIN" :"NODATA",
+ sep);
+ goto eoln;
+#ifdef RETURNSOA
+ } else {
+ type = T_SOA;
+ }
+#endif
+ }
+ /*
+ * Print type specific data
+ */
+ /* XXX why are we not using ns_sprintrr() here? */
+ switch (type) {
+ case T_A:
+ switch (dp->d_class) {
+ case C_IN:
+ case C_HS:
+ fputs(inet_ntoa(ina_get(cp)), 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: {
+ char buf[256];
+
+ if ((n = *cp++) != '\0') {
+ memcpy(buf, cp, n); buf[n] = '\0';
+ fprintf(fp, "\"%.*s\"", (int)n, buf);
+ cp += n;
+ } else
+ fprintf(fp, "\"\"");
+ if ((n = *cp++) != '\0') {
+ memcpy(buf, cp, n); buf[n] = '\0';
+ fprintf(fp, " \"%.*s\"", (int)n, buf);
+ } else
+ fprintf(fp, " \"\"");
+ break;
+ }
+
+ case T_SOA:
+ fprintf(fp, "%s.", cp);
+ cp += strlen((char *)cp) + 1;
+ fprintf(fp, " %s. (\n", cp);
+#if defined(RETURNSOA)
+ if (dp->d_rcode)
+ fputs(";", fp);
+#endif
+ cp += strlen((char *)cp) + 1;
+ NS_GET32(n, cp);
+ fprintf(fp, "\t\t%u", n);
+ NS_GET32(n, cp);
+ fprintf(fp, " %u", n);
+ NS_GET32(n, cp);
+ fprintf(fp, " %u", n);
+ NS_GET32(n, cp);
+ fprintf(fp, " %u", n);
+ NS_GET32(n, cp);
+ fprintf(fp, " %u )", n);
+#if defined(RETURNSOA)
+ if (dp->d_rcode) {
+ fprintf(fp,";%s.;%s%s-$",cp,
+ (dp->d_rcode == NXDOMAIN) ?
+ "NXDOMAIN" : "NODATA",
+ sep);
+ }
+#endif
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ NS_GET16(n, cp);
+ fprintf(fp, "%u", n);
+ fprintf(fp, " %s.", cp);
+ break;
+
+ case T_PX:
+ NS_GET16(n, cp);
+ fprintf(fp, "%u", n);
+ fprintf(fp, " %s.", cp);
+ cp += strlen((char *)cp) + 1;
+ fprintf(fp, " %s.", cp);
+ break;
+
+ case T_X25:
+ if ((n = *cp++) != '\0')
+ fprintf(fp, " \"%.*s\"", (int)n, cp);
+ else
+ fprintf(fp, " \"\"");
+ break;
+
+ case T_TXT:
+ end = (u_char *)dp->d_data + dp->d_size;
+ while (cp < end) {
+ (void) putc('"', fp);
+ if ((n = *cp++) != '\0') {
+ for (j = n ; j > 0 && cp < end ; j--) {
+ if (*cp == '\n' || *cp == '"' || *cp == '\\')
+ (void) putc('\\', fp);
+ (void) putc(*cp++, fp);
+ }
+ }
+ (void) putc('"', fp);
+ if (cp < end)
+ (void) putc(' ', 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;
+ }
+
+ case T_LOC: {
+ char t[256];
+
+ (void) fputs(loc_ntoa(dp->d_data, t), fp);
+ break;
+ }
+
+ case T_NAPTR: {
+ u_int32_t order, preference;
+
+ NS_GET16(order, cp);
+ fprintf(fp, "%u", order);
+
+ NS_GET16(preference, cp);
+ fprintf(fp, "%u", preference);
+
+ if ((n = *cp++) != 0) {
+ fprintf(fp, "\"%.*s\"", (int)n, cp);
+ cp += n;
+ }
+ if ((n = *cp++) != 0) {
+ fprintf(fp, "\"%.*s\"", (int)n, cp);
+ cp += n;
+ }
+ if ((n = *cp++) != 0) {
+ fprintf(fp, " \"%.*s\"", (int)n, cp);
+ cp += n;
+ }
+ fprintf(fp, " %s.", cp);
+
+ break;
+ }
+
+ case T_SRV: {
+ u_int priority, weight, port;
+
+ NS_GET16(priority, cp);
+ NS_GET16(weight, cp);
+ NS_GET16(port, cp);
+ fprintf(fp, "\t%u %u %u %s.",
+ priority, weight, port, cp);
+ break;
+ }
+
+ case T_WKS:
+ fputs(inet_ntoa(ina_get(cp)), fp);
+ cp += INADDRSZ;
+ 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;
+
+ case T_KEY:
+ savecp = cp; /* save the beginning */
+ /*>>> Flags (unsigned_16) */
+ NS_GET16(keyflags,cp);
+ fprintf(fp, "0x%04x ", keyflags);
+ /*>>> Protocol (8-bit decimal) */
+ fprintf(fp, "%3u ", *cp++);
+ /*>>> Algorithm id (8-bit decimal) */
+ fprintf(fp, "%3u ", *cp++);
+
+ /*>>> Public-Key Data (multidigit BASE64) */
+ /* containing ExponentLen, Exponent, and Modulus */
+ i = b64_ntop(cp, dp->d_size - (cp - savecp),
+ temp_base64,
+ sizeof temp_base64);
+ if (i < 0)
+ fprintf(fp, "; BAD BASE64");
+ else
+ fprintf(fp, "%s", temp_base64);
+ break;
+
+ case T_SIG:
+ sigdata = cp;
+ /* RRtype (char *) */
+ NS_GET16(n,cp);
+ fprintf(fp, "%s ", p_type(n));
+ /* Algorithm id (8-bit decimal) */
+ fprintf(fp, "%d ", *cp++);
+ /* Labels (8-bit decimal) (not saved in file) */
+ /* FIXME -- check value and print err if bad */
+ cp++;
+ /* OTTL (u_long) */
+ NS_GET32(n, cp);
+ fprintf(fp, "%u ", n);
+ /* Texp (u_long) */
+ NS_GET32(n, cp);
+ fprintf(fp, "%s ", p_secstodate (n));
+ /* Tsig (u_long) */
+ NS_GET32(n, cp);
+ fprintf(fp, "%s ", p_secstodate (n));
+ /* Kfootprint (unsigned_16) */
+ NS_GET16(n, cp);
+ fprintf(fp, "%u ", n);
+ /* Signer's Name (char *) */
+ fprintf(fp, "%s ", cp);
+ cp += strlen((char *)cp) + 1;
+ /* Signature (base64 of any length) */
+ i = b64_ntop(cp, dp->d_size - (cp - sigdata),
+ temp_base64,
+ sizeof temp_base64);
+ if (i < 0)
+ fprintf(fp, "; BAD BASE64");
+ else
+ fprintf(fp, "%s", temp_base64);
+ break;
+
+ case T_NXT:
+ fprintf(fp, "%s.", cp);
+ n = strlen ((char *)cp) + 1;
+ cp += n;
+ i = 8 * (dp->d_size - n); /* How many bits? */
+ for (n = 0; n < (u_int32_t)i; n++) {
+ if (NS_NXT_BIT_ISSET(n, cp))
+ fprintf(fp," %s",__p_type(n));
+ }
+ break;
+
+ 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:
+ if (dp->d_ns != NULL){
+ fprintf(fp, "%s[%s]",
+ sep, inet_ntoa(dp->d_ns->addr));
+ sep = " ";
+ }
+ 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(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);
+}
diff --git a/contrib/bind/bin/named/db_func.h b/contrib/bind/bin/named/db_func.h
new file mode 100644
index 0000000..2d4c05b
--- /dev/null
+++ b/contrib/bind/bin/named/db_func.h
@@ -0,0 +1,151 @@
+/* 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.
+ */
+
+/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/* db_proc.h - prototypes for functions in db_*.c
+ *
+ * $Id: db_func.h,v 8.22 1997/12/04 06:47:00 halley Exp $
+ */
+
+/* ++from db_update.c++ */
+extern int db_update(const char *name,
+ struct databuf *odp,
+ struct databuf *newdp,
+ struct databuf **savedpp,
+ int flags,
+ struct hashbuf *htp,
+ struct sockaddr_in from),
+ db_cmp(const struct databuf *, const struct databuf *),
+ findMyZone(struct namebuf *np, int class);
+void fixttl(struct databuf *dp);
+/* --from db_update.c-- */
+
+/* ++from db_save.c++ */
+extern struct namebuf *savename(const char *, int);
+extern struct databuf *savedata(int, int, u_int32_t, u_char *, int);
+extern struct hashbuf *savehash(struct hashbuf *);
+/* --from db_save.c-- */
+
+/* ++from db_dump.c++ */
+extern int db_dump(struct hashbuf *, FILE *, int, char *),
+ zt_dump(FILE *);
+extern void doadump(void);
+/* --from db_dump.c-- */
+
+/* ++from db_load.c++ */
+extern void endline(FILE *);
+extern int getword(char *, size_t, FILE *, int),
+ getnum(FILE *, const char *, int),
+ db_load(const char *, const char *,
+ struct zoneinfo *, const char *);
+extern int getnonblank(FILE *, const char *),
+ getservices(int, char *, FILE *, const char *);
+extern char getprotocol(FILE *, const char *);
+extern int makename(char *, const char *, int);
+#ifdef BIND_NOTIFY
+extern void notify_after_load(evContext, void *, const void *),
+ db_cancel_pending_notifies(void);
+#endif
+/* --from db_load.c-- */
+
+/* ++from db_glue.c++ */
+extern void buildservicelist(void),
+ destroyservicelist(void),
+ buildprotolist(void),
+ destroyprotolist(void),
+ getname(struct namebuf *, char *, int);
+extern int servicenumber(const char *),
+ protocolnumber(const char *),
+ get_class(const char *),
+ samedomain(const char *, const char *);
+extern u_int dhash(const u_char *, int),
+ nhash(const char *);
+extern const char *protocolname(int),
+ *servicename(u_int16_t, const char *);
+#ifndef BSD
+extern int getdtablesize(void);
+#endif
+extern struct databuf *rm_datum(struct databuf *,
+ struct namebuf *,
+ struct databuf *,
+ struct databuf **);
+extern struct namebuf *rm_name(struct namebuf *,
+ struct namebuf **,
+ struct namebuf *);
+extern void rm_hash(struct hashbuf *);
+extern void db_freedata(struct databuf *);
+/* --from db_glue.c-- */
+
+/* ++from db_lookup.c++ */
+extern struct namebuf *nlookup(const char *, struct hashbuf **,
+ const char **, int);
+extern struct namebuf *np_parent __P((struct namebuf *));
+extern int match(struct databuf *, int, int);
+/* --from db_lookup.c-- */
+
+/* ++from db_dict.c++ */
+int dict_lookup(const char *, int, int);
+/* --from db_dict.c-- */
diff --git a/contrib/bind/bin/named/db_glob.h b/contrib/bind/bin/named/db_glob.h
new file mode 100644
index 0000000..79d915d
--- /dev/null
+++ b/contrib/bind/bin/named/db_glob.h
@@ -0,0 +1,94 @@
+/*
+ * from db.h 4.16 (Berkeley) 6/1/90
+ * $Id: db_glob.h,v 8.8 1997/06/09 17:46:51 halley Exp $
+ */
+
+/* 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.
+ */
+
+/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/*
+ * Global variables for data base routines.
+ */
+
+ /* ONE_WEEK maximum ttl */
+DECL u_int max_cache_ttl INIT(7*24*60*60);
+
+ /* no minimum ttl */
+DECL u_int min_cache_ttl INIT(0);
+
+ /* current line number */
+DECL int lineno;
+
+ /* root hash table */
+DECL struct hashbuf *hashtab INIT(NULL);
+
+ /* hash table of cache read from file */
+DECL struct hashbuf *fcachetab INIT(NULL);
+
+#ifdef FORCED_RELOAD
+DECL int reloading INIT(0);
+#endif /* FORCED_RELOAD */
diff --git a/contrib/bind/bin/named/db_glue.c b/contrib/bind/bin/named/db_glue.c
new file mode 100644
index 0000000..bc6aed4
--- /dev/null
+++ b/contrib/bind/bin/named/db_glue.c
@@ -0,0 +1,616 @@
+#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.27 1998/02/14 00:41:39 halley Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#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 <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+struct valuelist {
+ struct valuelist * next;
+ struct valuelist * prev;
+ char * name;
+ char * proto;
+ int port;
+};
+static struct valuelist *servicelist, *protolist;
+
+void
+buildservicelist() {
+ struct servent *sp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setservent(0);
+#else
+ setservent(1);
+#endif
+ while ((sp = getservent()) != NULL) {
+ slp = (struct valuelist *)memget(sizeof(struct valuelist));
+ if (!slp)
+ panic("memget(servent)", NULL);
+ slp->name = savestr(sp->s_name, 1);
+ slp->proto = savestr(sp->s_proto, 1);
+ 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
+destroyservicelist() {
+ struct valuelist *slp, *slp_next;
+
+ for (slp = servicelist; slp != NULL; slp = slp_next) {
+ slp_next = slp->next;
+ freestr(slp->name);
+ freestr(slp->proto);
+ memput(slp, sizeof *slp);
+ }
+}
+
+void
+buildprotolist() {
+ struct protoent *pp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setprotoent(0);
+#else
+ setprotoent(1);
+#endif
+ while ((pp = getprotoent()) != NULL) {
+ slp = (struct valuelist *)memget(sizeof(struct valuelist));
+ if (!slp)
+ panic("memget(protoent)", NULL);
+ slp->name = savestr(pp->p_name, 1);
+ slp->port = pp->p_proto; /* host byte order */
+ slp->next = protolist;
+ slp->prev = NULL;
+ if (protolist)
+ protolist->prev = slp;
+ protolist = slp;
+ }
+ endprotoent();
+}
+
+void
+destroyprotolist() {
+ struct valuelist *plp, *plp_next;
+
+ for (plp = protolist; plp != NULL; plp = plp_next) {
+ plp_next = plp->next;
+ freestr(plp->name);
+ memput(plp, sizeof *plp);
+ }
+}
+
+static int
+findservice(const char *s, struct valuelist **list) {
+ 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(const char *p) {
+ return (findservice(p, &servicelist));
+}
+
+/*
+ * Convert protocol name or (ascii) number to int.
+ */
+int
+protocolnumber(const char *p) {
+ return (findservice(p, &protolist));
+}
+
+static struct servent *
+cgetservbyport(u_int16_t port, const char *proto) { /* Host byte order. */
+ struct valuelist **list = &servicelist;
+ 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(int proto) { /* Host byte order. */
+ struct valuelist **list = &protolist;
+ 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);
+}
+
+const char *
+protocolname(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);
+}
+
+const char *
+servicename(u_int16_t port, const char *proto) { /* Host byte order. */
+ 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);
+}
+
+static struct map map_class[] = {
+ { "in", C_IN },
+ { "chaos", C_CHAOS },
+ { "hs", C_HS },
+ { NULL, 0 }
+};
+
+int
+get_class(const char *class) {
+ const 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);
+}
+
+/* rm_datum(dp, np, pdp, savedpp)
+ * remove datum 'dp' from name 'np'. pdp is previous data pointer.
+ * if savedpp is not NULL, and compiled with BIND_UPDATE, save
+ * datum dp there rather than freeing the memory (caller will take
+ * care of freeing it)
+ * return value:
+ * "next" field from removed datum, suitable for relinking
+ */
+struct databuf *
+rm_datum(struct databuf *dp, struct namebuf *np, struct databuf *pdp,
+ struct databuf **savedpp) {
+ struct databuf *ndp = dp->d_next;
+
+ ns_debug(ns_log_db, 3, "rm_datum(%lx, %lx, %lx, %lx) -> %lx",
+ (u_long)dp, (u_long)np->n_data, (u_long)pdp,
+ (u_long)savedpp, (u_long)ndp);
+ if ((dp->d_flags & DB_F_ACTIVE) == 0)
+ panic("rm_datum: DB_F_ACTIVE not set", NULL);
+ if (pdp == NULL)
+ np->n_data = ndp;
+ else
+ pdp->d_next = ndp;
+#ifdef BIND_UPDATE
+ if (savedpp != NULL) {
+ /* mark deleted or pending deletion */
+ dp->d_mark |= D_MARK_DELETED;
+ dp->d_next = *savedpp;
+ *savedpp = dp;
+ } else
+ dp->d_next = NULL;
+#else
+ dp->d_next = NULL;
+#endif
+ dp->d_flags &= ~DB_F_ACTIVE;
+ DRCNTDEC(dp);
+ if (dp->d_rcnt) {
+#ifdef DEBUG
+ int32_t ii;
+#endif
+
+ switch(dp->d_type) {
+ case T_NS:
+ ns_debug(ns_log_db, 3, "rm_datum: %s rcnt = %d",
+ dp->d_data, dp->d_rcnt);
+ break;
+#ifdef DEBUG
+ case T_A:
+ memcpy(&ii, dp->d_data, sizeof ii);
+ ns_debug(ns_log_db, 3,
+ "rm_datum: %08.8X rcnt = %d",
+ ii, dp->d_rcnt);
+ break;
+#endif
+ default:
+ ns_debug(ns_log_db, 3,
+ "rm_datum: rcnt = %d", dp->d_rcnt);
+ }
+ } else
+#ifdef BIND_UPDATE
+ if (savedpp == NULL)
+#endif
+ db_freedata(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(struct namebuf *np, struct namebuf **pp, struct namebuf *pnp) {
+ struct namebuf *nnp = np->n_next;
+ const char *msg;
+
+ /* verify */
+ if ( (np->n_data && (msg = "data"))
+ || (np->n_hash && (msg = "hash"))
+ ) {
+ ns_panic(ns_log_db, 1, "rm_name(%#x(%s)): non-nil %s pointer",
+ np, NAME(*np), msg);
+ }
+
+ /* unlink */
+ if (pnp)
+ pnp->n_next = nnp;
+ else
+ *pp = nnp;
+
+ /* deallocate */
+ memput(np, NAMESIZE(NAMELEN(*np)));
+
+ /* done */
+ return (nnp);
+}
+
+void
+rm_hash(struct hashbuf *htp) {
+ REQUIRE(htp != NULL);
+ REQUIRE(htp->h_cnt == 0);
+
+ memput(htp, HASHSIZE(htp->h_size));
+}
+
+/*
+ * Get the domain name of 'np' and put in 'buf'. Bounds checking is done.
+ */
+void
+getname(struct namebuf *np, char *buf, int buflen) {
+ char *cp;
+ int i;
+
+ cp = buf;
+ while (np != NULL) {
+ i = (int) NAMELEN(*np);
+ if (i + 1 >= buflen) {
+ *cp = '\0';
+ ns_info(ns_log_db,
+ "domain name too long: %s...", buf);
+ strcpy(buf, "Name_Too_Long");
+ return;
+ }
+ if (cp != buf)
+ *cp++ = '.';
+ memcpy(cp, NAME(*np), i);
+ cp += i;
+ buflen -= i + 1;
+ np = np->n_parent;
+ }
+ *cp = '\0';
+}
+
+/*
+ * Compute hash value from data.
+ */
+u_int
+dhash(const u_char *dp, int dlen) {
+ u_char *cp;
+ u_int hval;
+ int n;
+
+ n = dlen;
+ if (n > 8)
+ n = 8;
+ hval = 0;
+ while (--n >= 0) {
+ hval <<= 1;
+ hval += *dp++;
+ }
+ return (hval % INVHASHSZ);
+}
+
+/* u_int
+ * nhash(name)
+ * compute hash for this name and return it; ignore case differences
+ */
+u_int
+nhash(const char *name) {
+ u_char ch;
+ u_int 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"
+*/
+
+int
+samedomain(const char *a, const char *b) {
+ size_t la, lb;
+ int diff, i, escaped;
+ const char *cp;
+
+ la = strlen(a);
+ lb = strlen(b);
+
+ /* ignore a trailing label separator (i.e. an unescaped dot) in 'a' */
+ if (la && a[la-1] == '.') {
+ escaped = 0;
+ /* note this loop doesn't get executed if la==1 */
+ for (i = la - 2; i >= 0; i--)
+ if (a[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else {
+ break;
+ }
+ if (!escaped)
+ la--;
+ }
+ /* ignore a trailing label separator (i.e. an unescaped dot) in 'b' */
+ if (lb && b[lb-1] == '.') {
+ escaped = 0;
+ /* note this loop doesn't get executed if lb==1 */
+ for (i = lb - 2; i >= 0; i--)
+ if (b[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else {
+ break;
+ }
+ if (!escaped)
+ 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 a trailing dot. */
+ if (lb == la)
+ return (strncasecmp(a, b, lb) == 0);
+
+ /* Ok, we know la > lb. */
+
+ diff = la - lb;
+
+ /* If 'a' is only 1 character longer than 'b', then it can't be
+ a subdomain of 'b' (because of the need for the '.' label
+ separator). */
+ if (diff < 2)
+ return (0);
+
+ /* If the character before the last 'lb' characters of 'b'
+ isn't '.', then it can't be a match (this lets us avoid
+ having "foobar.com" match "bar.com"). */
+ if (a[diff-1] != '.')
+ return (0);
+
+ /* We're not sure about that '.', however. It could be escaped
+ and thus not a really a label separator. */
+ escaped=0;
+ for (i = diff-2; i >= 0; i--)
+ if (a[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ }
+ else
+ break;
+ if (escaped)
+ return (0);
+
+ /* We use strncasecmp because we might be trying to
+ * ignore trailing dots. */
+ cp = a + diff;
+ return (strncasecmp(cp, b, lb) == 0);
+}
+
+void
+db_freedata(struct databuf *dp) {
+ int bytes = (dp->d_type == T_NS) ?
+ DATASIZE(dp->d_size)+INT32SZ : DATASIZE(dp->d_size);
+
+ if (dp->d_rcnt != 0)
+ panic("db_freedata: d_rcnt != 0", NULL);
+ if ((dp->d_flags & (DB_F_ACTIVE|DB_F_FREE)) != 0)
+ panic("db_freedata: %s set",
+ (dp->d_flags & DB_F_FREE) != 0 ? "DB_F_FREE" :
+ "DB_F_ACTIVE");
+ if (dp->d_next != NULL)
+ panic("db_free: d_next != NULL", NULL);
+ dp->d_flags |= DB_F_FREE;
+ memput(dp, bytes);
+}
diff --git a/contrib/bind/bin/named/db_load.c b/contrib/bind/bin/named/db_load.c
new file mode 100644
index 0000000..d05a969
--- /dev/null
+++ b/contrib/bind/bin/named/db_load.c
@@ -0,0 +1,2218 @@
+#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.41 1998/02/13 20:02:28 halley Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/*
+ * Load zone from ASCII file on local host. Format similar to RFC 883.
+ */
+
+/* Import. */
+
+#include "port_before.h"
+
+#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 <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+/* Forward. */
+
+static int gettoken(FILE *, const char *);
+static int getttl(FILE *, const char *, int, u_int32_t *, int *);
+static int getcharstring(char *, char *, int, int, int, FILE *,
+ const char *);
+static int makename_ok(char *name, const char *origin, int class,
+ struct zoneinfo *zp,
+ enum transport transport,
+ enum context context,
+ const char *owner, const char *filename,
+ int lineno, int size);
+static int getmlword(char *, size_t, FILE *, int);
+static int getallwords(char *, size_t, FILE *, int);
+static u_int32_t wordtouint32(char *);
+static int datepart(const char *, int, int, int, int *);
+static u_int32_t datetosecs(const char *, int *);
+static int get_nxt_types(u_char *, FILE *, const char *);
+static void fixup_soa(const char *fn, struct zoneinfo *zp);
+#ifdef BIND_NOTIFY
+static void notify_after_delay(evContext ctx, void *uap,
+ struct timespec due,
+ struct timespec inter);
+#endif
+static int wordtouint32_error = 0;
+static int empty_token = 0;
+static int getmlword_nesting = 0;
+
+/* Global. */
+
+static int clev; /* a zone deeper in a hierarchy has more credibility */
+
+#ifdef BIND_NOTIFY
+static notify_info_list pending_notifies;
+#endif
+
+/*
+ * Parser token values
+ */
+#define CURRENT 1
+#define DOT 2
+#define AT 3
+#define DNAME 4
+#define INCLUDE 5
+#define ORIGIN 6
+#define ERROR 7
+
+#define MAKENAME_OK(N) \
+ do { \
+ if (!makename_ok(N, origin, class, zp, \
+ transport, context, \
+ domain, filename, lineno, \
+ sizeof(data) - ((u_char*)N - data))) { \
+ errs++; \
+ sprintf(buf, "bad name \"%s\"", N); \
+ goto err; \
+ } \
+ } while (0)
+
+/* Public. */
+
+/* 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(const char *filename, const char *in_origin,
+ struct zoneinfo *zp, const char *def_domain)
+{
+ static int read_soa, read_ns, rrcount;
+
+ const char *errtype = "Database";
+ char *cp;
+ char domain[MAXDNAME], origin[MAXDNAME], tmporigin[MAXDNAME];
+ char buf[MAXDATA];
+ u_char data[MAXDATA];
+ const char *op;
+ int c, someclass, class, type, dbflags, dataflags, multiline;
+ int slineno, i, errs, didinclude, escape, success, dateerror;
+ u_int32_t ttl, n, serial;
+ u_long tmplong;
+ struct databuf *dp;
+ FILE *fp;
+ struct stat sb;
+ struct in_addr ina;
+ enum transport transport;
+ enum context context;
+ u_int32_t sig_type;
+ u_int32_t keyflags;
+ struct sockaddr_in empty_from;
+
+ empty_from.sin_family = AF_INET;
+ empty_from.sin_addr.s_addr = htonl(INADDR_ANY);
+ empty_from.sin_port = htons(0);
+
+/*
+ * We use an 'if' inside of the 'do' below because otherwise the Solaris
+ * compiler detects that the 'while' is never executed because of the 'goto'
+ * and complains.
+ */
+#define ERRTO(msg) do { if (1) { errtype = msg; goto err; } } while (0)
+
+ 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 = nlabels(in_origin);
+ }
+
+ ns_debug(ns_log_load, 1, "db_load(%s, %s, %d, %s)",
+ filename, in_origin, zp - zones,
+ def_domain ? def_domain : "Nil");
+
+ strcpy(origin, in_origin);
+ if ((fp = fopen(filename, "r")) == NULL) {
+ ns_warning(ns_log_load, "%s: %s", filename, strerror(errno));
+ 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) {
+ ns_warning(ns_log_load, "%s: %s", filename, strerror(errno));
+ 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(buf, sizeof buf, fp, 0))
+ /* file name*/
+ break;
+ if (!getword(tmporigin, sizeof(tmporigin), fp, 1))
+ strcpy(tmporigin, origin);
+ else {
+ if (makename(tmporigin, origin,
+ sizeof(tmporigin)) == -1)
+ ERRTO("$INCLUDE makename failed");
+ endline(fp);
+ }
+ didinclude = 1;
+ errs += db_load(buf, tmporigin, zp, domain);
+ continue;
+
+ case ORIGIN:
+ (void) strcpy(buf, origin);
+ if (!getword(origin, sizeof(origin), fp, 1))
+ break;
+ ns_debug(ns_log_load, 3, "db_load: origin %s, buf %s",
+ origin, buf);
+ if (makename(origin, buf, sizeof(origin)) == -1)
+ ERRTO("$ORIGIN makename failed");
+ ns_debug(ns_log_load, 3, "db_load: origin now %s",
+ origin);
+ continue;
+
+ case DNAME:
+ if (!getword(domain, sizeof(domain), fp, 1))
+ break;
+ if (makename(domain, origin, sizeof(domain)) == -1)
+ ERRTO("ownername makename failed");
+ goto gotdomain;
+
+ case AT:
+ (void) strcpy(domain, origin);
+ goto gotdomain;
+
+ case DOT:
+ domain[0] = '\0';
+ /* FALLTHROUGH */
+ case CURRENT:
+ gotdomain:
+ if (!getword(buf, sizeof buf, fp, 0)) {
+ if (c == CURRENT)
+ continue;
+ break;
+ }
+ if (ns_parse_ttl(buf, &tmplong) < 0)
+ ttl = USE_MINIMUM;
+ else {
+ ttl = (u_int32_t)tmplong;
+ if (ttl > MAXIMUM_TTL) {
+ ns_info(ns_log_load,
+ "%s: Line %d: TTL > %u; converted to 0",
+ filename, lineno, MAXIMUM_TTL);
+ ttl = 0;
+ }
+ if (zp->z_type == Z_CACHE) {
+ /*
+ * This allows the cache entry to age
+ * while sitting on disk (powered off).
+ */
+ if (ttl > max_cache_ttl)
+ ttl = max_cache_ttl;
+ ttl += sb.st_mtime;
+ }
+ if (!getword(buf, sizeof buf, fp, 0))
+ break;
+ }
+
+ /* Parse class (IN, etc) */
+ someclass = sym_ston(__p_class_syms, buf, &success);
+ if (success && someclass != C_ANY) {
+ class = someclass;
+ (void) getword(buf, sizeof buf, fp, 0);
+ }
+
+ /* Parse RR type (A, MX, etc) */
+ type = sym_ston(__p_type_syms, buf, &success);
+ if (success == 0 || type == ns_t_any) {
+ ns_info(ns_log_load,
+ "%s: Line %d: Unknown type: %s.",
+ filename, lineno, buf);
+ errs++;
+ break;
+ }
+
+ context = ns_ownercontext(type, transport);
+ if (!ns_nameok(domain, class, zp, transport, context,
+ domain, inaddr_any)) {
+ errs++;
+ ns_notice(ns_log_load,
+ "%s:%d: owner name error",
+ filename, lineno);
+ break;
+ }
+ context = domain_ctx;
+ switch (type) {
+ case ns_t_key:
+ case ns_t_sig:
+ case ns_t_nxt:
+ /*
+ * Don't do anything here for these types --
+ * they read their own input separately later.
+ */
+ goto dont_get_word;
+
+ case ns_t_soa:
+ case ns_t_minfo:
+ case ns_t_rp:
+ case ns_t_ns:
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_ptr:
+ escape = 1;
+ break;
+ default:
+ escape = 0;
+ }
+ if (!getword(buf, sizeof buf, fp, escape))
+ break;
+ ns_debug(ns_log_load, 3,
+ "d='%s', c=%d, t=%d, ttl=%u, data='%s'",
+ domain, class, type, ttl, buf);
+ /*
+ * Convert the ascii data 'buf' to the proper format
+ * based on the type and pack into 'data'.
+ */
+ dont_get_word:
+ switch (type) {
+ case ns_t_a:
+ if (!inet_aton(buf, &ina))
+ ERRTO("IP Address");
+ (void) ina_put(ina, data);
+ n = NS_INT32SZ;
+ break;
+
+ case ns_t_soa:
+ context = hostname_ctx;
+ goto soa_rp_minfo;
+ case ns_t_rp:
+ case ns_t_minfo:
+ context = mailname_ctx;
+ /* FALLTHROUGH */
+ soa_rp_minfo:
+ (void) strcpy((char *)data, buf);
+
+ MAKENAME_OK((char *)data);
+ cp = (char *)(data + strlen((char *)data) + 1);
+ if (!getword(cp,
+ (sizeof data) -
+ (cp - (char*)data),
+ fp, 1))
+ ERRTO("Domain Name");
+ if (type == ns_t_rp)
+ context = domain_ctx;
+ else
+ context = mailname_ctx;
+ MAKENAME_OK(cp);
+ cp += strlen((char *)cp) + 1;
+ if (type != ns_t_soa) {
+ n = cp - (char *)data;
+ break;
+ }
+ if (class != zp->z_class) {
+ errs++;
+ ns_info(ns_log_load, "%s:%d: %s",
+ filename, lineno,
+ "SOA class not same as zone's");
+ }
+ if (strcasecmp(zp->z_origin, domain) != 0) {
+ errs++;
+ ns_error(ns_log_load,
+ "%s:%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);
+ }
+ serial = zp->z_serial;
+ zp->z_serial = getnum(fp, filename,
+ GETNUM_SERIAL);
+ if (getnum_error)
+ errs++;
+ n = (u_int32_t) zp->z_serial;
+ PUTLONG(n, cp);
+ if (serial != 0 &&
+ SEQ_GT(serial, zp->z_serial)) {
+ ns_notice(ns_log_load,
+ "%s:%d: WARNING: new serial number < old (%lu < %lu)",
+ filename , lineno,
+ zp->z_serial, serial);
+ }
+ if (getttl(fp, filename, lineno, &n,
+ &multiline) <= 0) {
+ errs++;
+ n = INIT_REFRESH;
+ }
+ PUTLONG(n, cp);
+ zp->z_refresh = MAX(n, MIN_REFRESH);
+ 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));
+ sched_zone_maint(zp);
+ }
+#ifdef BIND_UPDATE
+ if ((zp->z_type == Z_PRIMARY) &&
+ (zp->z_flags & Z_DYNAMIC))
+ if ((u_int32_t)zp->z_soaincrintvl >
+ zp->z_refresh/3) {
+ ns_info(ns_log_load,
+ "zone soa update time truncated to 1/3rd of refresh time");
+ zp->z_soaincrintvl =
+ zp->z_refresh / 3;
+ }
+#endif
+
+ if (getttl(fp, filename, lineno, &n,
+ &multiline) <= 0) {
+ errs++;
+ n = INIT_REFRESH;
+ }
+ PUTLONG(n, cp);
+ zp->z_retry = MAX(n, MIN_RETRY);
+ if (getttl(fp, filename, lineno,
+ &zp->z_expire, &multiline) <= 0) {
+ errs++;
+ zp->z_expire = INIT_REFRESH;
+ }
+ n = zp->z_expire;
+ PUTLONG(n, cp);
+ if (getttl(fp, filename, lineno, &n,
+ &multiline) <= 0) {
+ errs++;
+ n = 120;
+ }
+ PUTLONG(n, cp);
+ if (n > MAXIMUM_TTL) {
+ ns_info(ns_log_load,
+ "%s: Line %d: SOA minimum TTL > %u; converted to 0",
+ filename, lineno, MAXIMUM_TTL);
+ zp->z_minimum = 0;
+ } else
+ zp->z_minimum = n;
+ n = cp - (char *)data;
+ if (multiline) {
+ buf[0] = getnonblank(fp, filename);
+ buf[1] = '\0';
+ if (buf[0] != ')')
+ ERRTO("SOA \")\"");
+ endline(fp);
+ }
+ read_soa++;
+ if (zp->z_type == Z_PRIMARY)
+ fixup_soa(filename, zp);
+ break;
+
+ case ns_t_wks:
+ /* Address */
+ if (!inet_aton(buf, &ina))
+ ERRTO("WKS IP Address");
+ (void) ina_put(ina, data);
+ /* Protocol */
+ data[INADDRSZ] = getprotocol(fp, filename);
+ /* Services */
+ n = getservices(NS_INT32SZ + sizeof(char),
+ (char *)data, fp, filename);
+ break;
+
+ case ns_t_ns:
+ if (strcasecmp(zp->z_origin, domain) == 0)
+ read_ns++;
+ context = hostname_ctx;
+ goto cname_etc;
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ context = domain_ctx;
+ goto cname_etc;
+ case ns_t_ptr:
+ context = ns_ptrcontext(domain);
+ cname_etc:
+ (void) strcpy((char *)data, buf);
+ MAKENAME_OK((char *)data);
+ n = strlen((char *)data) + 1;
+ break;
+
+ case ns_t_naptr:
+ /* Order Preference Flags Service Replacement Regexp */
+ n = 0;
+ cp = buf;
+ /* Order */
+ while (isdigit(*cp))
+ n = n * 10 + (*cp++ - '0');
+ /* catch bad values */
+ if (cp == buf || n > 65535)
+ ERRTO("NAPTR Order");
+ cp = (char *)data;
+ PUTSHORT((u_int16_t)n, cp);
+
+ /* Preference */
+ n = getnum(fp, filename, GETNUM_NONE);
+ if (getnum_error || n > 65536)
+ ERRTO("NAPTR Preference");
+ PUTSHORT((u_int16_t)n, cp);
+
+ /* Flags */
+ if (!getword(buf, sizeof buf, fp, 0))
+ ERRTO("NAPTR Flags");
+ n = strlen(buf);
+ *cp++ = n;
+ memcpy(cp, buf, (int)n);
+ cp += n;
+
+ /* Service Classes */
+ if (!getword(buf, sizeof buf, fp, 0))
+ ERRTO("NAPTR Service Classes");
+ n = strlen(buf);
+ *cp++ = n;
+ memcpy(cp, buf, (int)n);
+ cp += n;
+
+ /* Pattern */
+ if (!getword(buf, sizeof buf, fp, 0))
+ ERRTO("NAPTR Pattern");
+ n = strlen(buf);
+ *cp++ = n;
+ memcpy(cp, buf, (int)n);
+ cp += n;
+
+ /* Replacement */
+ if (!getword(buf, sizeof buf, fp, 1))
+ ERRTO("NAPTR Replacement");
+ (void) strcpy((char *)cp, buf);
+ context = domain_ctx;
+ MAKENAME_OK(cp);
+ /* advance pointer to end of data */
+ cp += strlen((char *)cp) +1;
+
+ /* now save length */
+ n = (cp - (char *)data);
+ break;
+
+
+ case ns_t_mx:
+ case ns_t_afsdb:
+ case ns_t_rt:
+ case ns_t_srv:
+ n = 0;
+ cp = buf;
+ while (isdigit(*cp))
+ n = n * 10 + (*cp++ - '0');
+ /* catch bad values */
+ if ((cp == buf) || (n > 65535))
+ ERRTO("Priority");
+ cp = (char *)data;
+ PUTSHORT((u_int16_t)n, cp);
+
+ if (type == ns_t_srv) {
+ n = getnum(fp, filename, GETNUM_NONE);
+ if (getnum_error || n > 65536)
+ ERRTO("SRV RR");
+ PUTSHORT((u_int16_t)n, cp);
+
+ n = getnum(fp, filename, GETNUM_NONE);
+ if (getnum_error || n > 65536)
+ ERRTO("SRV RR");
+ PUTSHORT((u_int16_t)n, cp);
+ }
+
+ if (!getword(buf, sizeof buf, fp, 1))
+ ERRTO("Domain Name");
+ (void) strcpy((char *)cp, buf);
+ context = hostname_ctx;
+ MAKENAME_OK(cp);
+ /* advance pointer to end of data */
+ cp += strlen((char *)cp) +1;
+
+ /* now save length */
+ n = (cp - (char *)data);
+ break;
+
+ case ns_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))
+ ERRTO("PX Priority");
+ cp = (char *)data;
+ PUTSHORT((u_int16_t)n, cp);
+
+ if (!getword(buf, sizeof buf, fp, 0))
+ ERRTO("PX Domain1");
+ (void) strcpy((char *)cp, buf);
+ MAKENAME_OK(cp);
+ /* advance pointer to next field */
+ cp += strlen((char *)cp) + 1;
+ if (!getword(buf, sizeof buf, fp, 0))
+ ERRTO("PX Domain2");
+ (void) strcpy((char *)cp, buf);
+ MAKENAME_OK(cp);
+ /* advance pointer to end of data */
+ cp += strlen((char *)cp) + 1;
+
+ /* now save length */
+ n = (cp - (char *)data);
+ break;
+
+ case ns_t_hinfo:
+ n = getcharstring(buf, (char *)data, type,
+ 2, 2, fp, filename);
+ if (n == 0)
+ ERRTO("HINFO RR");
+ break;
+
+ case ns_t_isdn:
+ n = getcharstring(buf, (char *)data, type,
+ 1, 2, fp, filename);
+ if (n == 0)
+ ERRTO("ISDN RR");
+ break;
+
+ case ns_t_txt:
+ n = getcharstring(buf, (char *)data, type,
+ 1, 0, fp, filename);
+ if (n == 0)
+ ERRTO("TXT RR");
+ break;
+
+
+ case ns_t_x25:
+ n = getcharstring(buf, (char *)data, type,
+ 1, 1, fp, filename);
+ if (n == 0)
+ ERRTO("X25 RR");
+ break;
+
+ case ns_t_nsap:
+ n = inet_nsap_addr(buf, (u_char *)data,
+ sizeof data);
+ if (n == 0)
+ ERRTO("NSAP RR");
+ endline(fp);
+ break;
+
+ case ns_t_aaaa:
+ if (inet_pton(AF_INET6, buf, data) <= 0)
+ ERRTO("IPv4 Address");
+ n = NS_IN6ADDRSZ;
+ endline(fp);
+ break;
+
+ case ns_t_key: {
+ /* The KEY record looks like this in the db file:
+ * Name Cl KEY Flags Proto Algid PublicKeyData
+ * where:
+ * Name,Cl per usual
+ * KEY RR type
+ * Flags 4 digit hex value (unsigned_16)
+ * Proto 8 bit u_int
+ * Algid 8 bit u_int
+ * PublicKeyData
+ * a string of base64 digits,
+ * skipping any embedded whitespace.
+ */
+ u_int32_t al, pr;
+ int nk, klen;
+ char *expstart;
+ u_int expbytes, modbytes;
+
+ i = 0;
+ data[i] = '\0';
+ cp = (char *)data;
+ getmlword_nesting = 0; /* KLUDGE err recov. */
+ /*>>> Flags (unsigned_16) */
+ if (!getmlword((char*)buf, sizeof buf, fp, 0))
+ ERRTO("KEY Flags Field");
+ keyflags = wordtouint32(buf);
+ if (wordtouint32_error || 0xFFFF < keyflags)
+ goto err;
+ if (keyflags & NS_KEY_RESERVED_BITMASK)
+ ERRTO("KEY Reserved Flag Bit");
+ PUTSHORT(keyflags, cp);
+
+ /*>>> Protocol (8-bit decimal) */
+ if (!getmlword((char*)buf, sizeof buf, fp, 0))
+ ERRTO("KEY Protocol Field");
+ pr = wordtouint32(buf);
+ if (wordtouint32_error || 255 < pr)
+ ERRTO("KEY Protocol Field");
+ *cp++ = (u_char) pr;
+
+ /*>>> Algorithm id (8-bit decimal) */
+ if (!getmlword((char*)buf, sizeof buf, fp, 0))
+ ERRTO("KEY Algorithm ID");
+ al = wordtouint32(buf);
+ if (wordtouint32_error ||
+ 0 == al || 255 == al || 255 < al)
+ ERRTO("KEY Algorithm ID");
+ *cp++ = (u_char) al;
+
+ /*>>> Public Key data is in BASE64.
+ * We don't care what algorithm it uses or what
+ * the internal structure of the BASE64 data is.
+ */
+ if (!getallwords(buf, MAXDATA, fp, 0))
+ klen = 0;
+ else {
+ /* Convert from BASE64 to binary. */
+ klen = b64_pton(buf, (u_char*)cp,
+ sizeof data -
+ (cp - (char *)data));
+ if (klen < 0)
+ ERRTO("KEY Public Key");
+ }
+
+ /* set total length */
+ n = cp + klen - (char *)data;
+
+ /*
+ * Now check for valid key flags & algs & etc,
+ * from the RFC.
+ */
+
+ if (keyflags & (NS_KEY_ZONEKEY | NS_KEY_IPSEC
+ | NS_KEY_EMAIL))
+ pr |= 1; /* A nonzero proto. */
+ if (NS_KEY_TYPE_NO_KEY ==
+ (keyflags & NS_KEY_TYPEMASK))
+ nk = 1; /* No-key */
+ else
+ nk = 0; /* have a key */
+
+ if ((keyflags & NS_KEY_ZONEKEY) &&
+ (NS_KEY_TYPE_CONF_ONLY ==
+ (keyflags & NS_KEY_TYPEMASK)))
+ /* Zone key must have Auth bit set. */
+ ERRTO("KEY Zone Key Auth. bit");
+
+ if (al == 0 && nk == 0)
+ ERRTO("KEY Algorithm");
+ if (al != 0 && pr == 0)
+ ERRTO("KEY Protocols");
+
+ if (nk == 1 && klen != 0)
+ ERRTO("KEY No-Key Flags Set");
+
+ if (nk == 0 && klen == 0)
+ ERRTO("KEY Type Spec'd");
+
+ /* Check algorithm-ID and key structure, for
+ the algorithm-ID's that we know about. */
+ switch (al) {
+ case NS_ALG_MD5RSA:
+ if (klen == 0)
+ break;
+ expstart = cp;
+ expbytes = *expstart++;
+ if (expbytes == 0)
+ GETSHORT(expbytes, expstart);
+
+ if (expbytes < 1)
+ ERRTO("Exponent too short");
+ if (expbytes >
+ (NS_MD5RSA_MAX_BITS + 7) / 8
+ )
+ ERRTO("Exponent too long");
+ if (*expstart == 0)
+ ERRTO("Exponent w/ 0");
+
+ modbytes = klen -
+ (expbytes + (expstart - cp));
+ if (modbytes <
+ (NS_MD5RSA_MIN_BITS + 7) / 8
+ )
+ ERRTO("Modulus too short");
+ if (modbytes >
+ (NS_MD5RSA_MAX_BITS + 7) / 8
+ )
+ ERRTO("Modulus too long");
+ if (*(expstart+expbytes) == 0)
+ ERRTO("Modulus starts w/ 0");
+ break;
+
+ case NS_ALG_EXPIRE_ONLY:
+ if (klen != 0)
+ ERRTO(
+ "Key provided for expire-only algorithm"
+ );
+ break;
+ case NS_ALG_PRIVATE_OID:
+ if (klen == 0)
+ ERRTO("No ObjectID in key");
+ break;
+ }
+
+ endline(fp); /* flush the rest of the line */
+ break;
+ } /*T_KEY*/
+
+ case ns_t_sig:
+ {
+ /* The SIG record looks like this in the db file:
+ Name Cl SIG RRtype Algid [OTTL] Texp Tsig Kfoot Signer Sig
+
+ where: Name and Cl are as usual
+ SIG is a keyword
+ RRtype is a char string
+ ALGid is 8 bit u_int
+ OTTL is 32 bit u_int (optionally present)
+ Texp is YYYYMMDDHHMMSS
+ Tsig is YYYYMMDDHHMMSS
+ Kfoot is 16-bit unsigned decimal integer
+ Signer is a char string
+ Sig is 64 to 319 base-64 digits
+ A missing OTTL is detected by the magnitude of the Texp value
+ that follows it, which is larger than any u_int.
+ The Labels field in the binary RR does not appear in the
+ text RR.
+
+ It's too crazy to run these pages of SIG code at the right
+ margin. I'm exdenting them for readability.
+ */
+ int siglen;
+ u_int32_t al;
+ u_int32_t signtime, exptime, timetilexp;
+ u_int32_t origTTL;
+ time_t now;
+
+ /* The TTL gets checked against the Original TTL,
+ and bounded by the signature expiration time, which
+ are both under the signature. We can't let TTL drift
+ based on the SOA record. If defaulted, fix it now.
+ (It's not clear to me why USE_MINIMUM isn't eliminated
+ before putting ALL RR's into the database. -gnu@toad.com) */
+ if (ttl == USE_MINIMUM)
+ ttl = zp->z_minimum;
+
+ i = 0;
+ data[i] = '\0';
+ getmlword_nesting = 0; /* KLUDGE err recovery */
+
+ /* RRtype (char *) */
+ if (!getmlword((char*)buf, sizeof buf, fp, 0))
+ ERRTO("SIG record doesn't specify type");
+ sig_type = sym_ston(__p_type_syms, buf, &success);
+ if (!success || sig_type == ns_t_any) {
+ /*
+ * We'll also accept a numeric RR type,
+ * for signing RR types that this version
+ * of named doesn't yet understand.
+ * In the ns_t_any case, we rely on wordtouint32
+ * to fail when scanning the string "ANY".
+ */
+ sig_type = wordtouint32 (buf);
+ if (wordtouint32_error || sig_type > 0xFFFF)
+ ERRTO("Unknown RR type in SIG record");
+ }
+ cp = (char *)&data[i];
+ PUTSHORT((u_int16_t)sig_type, cp);
+ i += 2;
+
+ /* Algorithm id (8-bit decimal) */
+ if (!getmlword(buf, sizeof buf, fp, 0))
+ ERRTO("Missing algorithm ID");
+ al = wordtouint32(buf);
+ if (0 == al || wordtouint32_error || 255 <= al)
+ goto err;
+ data[i] = (u_char) al;
+ i++;
+
+ /*
+ * Labels (8-bit decimal)
+ * Not given in the file. Must compute.
+ */
+ n = dn_count_labels(domain);
+ if (0 >= n || 255 < n)
+ ERRTO("SIG label count invalid");
+ data[i] = (u_char) n;
+ i++;
+
+ /*
+ * OTTL (optional u_int32_t) and
+ * Texp (u_int32_t date)
+ */
+ if (!getmlword(buf, sizeof buf, fp, 0))
+ ERRTO("OTTL and expiration time missing");
+ /*
+ * See if OTTL is missing and this is a date.
+ * This relies on good, silent error checking
+ * in datetosecs.
+ */
+ exptime = datetosecs(buf, &dateerror);
+ if (!dateerror) {
+ /* Output TTL as OTTL */
+ origTTL = ttl;
+ cp = (char *)&data[i];
+ PUTLONG (origTTL, cp);
+ i += 4;
+ } else {
+ /* Parse and output OTTL; scan TEXP */
+ origTTL = wordtouint32(buf);
+ if (0 >= origTTL || wordtouint32_error ||
+ (origTTL > 0x7fffffff))
+ goto err;
+ cp = (char *)&data[i];
+ PUTLONG(origTTL, cp);
+ i += 4;
+ if (!getmlword(buf, sizeof buf, fp, 0))
+ ERRTO("Expiration time missing");
+ exptime = datetosecs(buf, &dateerror);
+ }
+ if (dateerror || exptime > 0x7fffffff || exptime <= 0)
+ ERRTO("Invalid expiration time");
+ cp = (char *)&data[i];
+ PUTLONG(exptime, cp);
+ i += 4;
+
+ /* Tsig (u_int32_t) */
+ if (!getmlword(buf, sizeof buf, fp, 0))
+ ERRTO("Missing signature time");
+ signtime = datetosecs(buf, &dateerror);
+ if (0 == signtime || dateerror)
+ ERRTO("Invalid signature time");
+ cp = (char *)&data[i];
+ PUTLONG(signtime, cp);
+ i += 4;
+
+ /* Kfootprint (unsigned_16) */
+ if (!getmlword(buf, sizeof buf, fp, 0))
+ ERRTO("Missing key footprint");
+ n = wordtouint32(buf);
+ if (wordtouint32_error || n >= 0x0ffff)
+ ERRTO("Invalid key footprint");
+ cp = (char *)&data[i];
+ PUTSHORT((u_int16_t)n, cp);
+ i += 2;
+
+ /* Signer's Name */
+ if (!getmlword((char*)buf, sizeof buf, fp, 0))
+ ERRTO("Missing signer's name");
+ cp = (char *)&data[i];
+ strcpy(cp,buf);
+ context = domain_ctx;
+ MAKENAME_OK(cp);
+ i += strlen(cp) + 1;
+
+ /*
+ * Signature (base64 of any length)
+ * We don't care what algorithm it uses or what
+ * the internal structure of the BASE64 data is.
+ */
+ if (!getallwords(buf, sizeof buf, fp, 0)) {
+ siglen = 0;
+ } else {
+ cp = (char *)&data[i];
+ siglen = b64_pton(buf, (u_char*)cp, sizeof data - i);
+ if (siglen < 0)
+ goto err;
+ }
+
+ /* set total length and we're done! */
+ n = i + siglen;
+
+ /*
+ * Check signature time, expiration, and adjust TTL. Note
+ * that all time values are in GMT (UTC), *not* local time.
+ */
+
+ now = time (0);
+
+ /* Don't let bogus name servers increase the signed TTL */
+ if (ttl > origTTL)
+ ERRTO("TTL is greater than signed original TTL");
+
+ /* Don't let bogus signers "sign" in the future. */
+ if (signtime > (u_int32_t)now)
+ ERRTO("signature time is in the future");
+
+ /* Ignore received SIG RR's that are already expired. */
+ if (exptime <= (u_int32_t)now)
+ ERRTO("expiration time is in the past");
+
+ /* Lop off the TTL at the expiration time. */
+ timetilexp = exptime - now;
+ if (timetilexp < ttl) {
+ ns_debug(ns_log_load, 1,
+ "shrinking expiring %s SIG TTL from %d to %d",
+ p_secstodate(exptime), ttl, timetilexp);
+ ttl = timetilexp;
+ }
+
+ /*
+ * Check algorithm-ID and key structure, for
+ * the algorithm-ID's that we know about.
+ */
+ switch (al) {
+ case NS_ALG_MD5RSA:
+ if (siglen == 0)
+ ERRTO("No key for RSA algorithm");
+ if (siglen < 1)
+ ERRTO("Signature too short");
+ if (siglen > (NS_MD5RSA_MAX_BITS + 7) / 8)
+ ERRTO("Signature too long");
+ /* We rely on cp from parse */
+ if (*cp == 0)
+ ERRTO("Signature starts with zeroes");
+ break;
+
+ case NS_ALG_EXPIRE_ONLY:
+ if (siglen != 0)
+ ERRTO(
+ "Signature supplied to expire-only algorithm");
+ break;
+ case NS_ALG_PRIVATE_OID:
+ if (siglen == 0)
+ ERRTO("No ObjectID in key");
+ break;
+ }
+
+ /* Should we complain about algorithm-ID's that we
+ don't understand? It may help debug some obscure
+ cases, but in general we should accept any RR whether
+ we could cryptographically process it or not; it
+ may be being published for some newer DNS clients
+ to validate themselves. */
+
+ endline(fp); /* flush the rest of the line */
+
+ break; /* Accept this RR. */
+ }
+
+ case ns_t_nxt:
+ /* The NXT record looks like:
+ Name Cl NXT nextname RRT1 RRT2 MX A SOA ...
+
+ where: Name and Cl are as usual
+ NXT is a keyword
+ nextname is the next valid name in
+ the zone after "Name". All
+ names between the two are
+ known to be nonexistent.
+ RRT's... are a series of RR type
+ names, which indicate that
+ RR's of these types are
+ published for "Name", and
+ that no RR's of any other
+ types are published for
+ "Name".
+
+ When a NXT record is cryptographically
+ signed, it proves the nonexistence of an
+ RR (actually a whole set of RR's). */
+
+ getmlword_nesting = 0; /* KLUDGE err recov. */
+ if (!getmlword(buf, sizeof buf, fp, 1))
+ goto err;
+ (void) strcpy((char *)data, buf);
+ MAKENAME_OK((char *)data);
+ n = strlen((char *)data) + 1;
+ cp = n + (char *)data;
+ n += get_nxt_types((u_char *)cp, fp, filename);
+ break;
+
+ case ns_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;
+
+ default:
+ goto err;
+ }
+ /*
+ * Ignore data outside the zone.
+ */
+ if (zp->z_type != Z_CACHE &&
+ !samedomain(domain, zp->z_origin))
+ {
+ ns_info(ns_log_load,
+ "%s:%d: data \"%s\" outside zone \"%s\" (ignored)",
+ filename, lineno, domain,
+ zp->z_origin);
+ continue;
+ }
+ 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, NULL, dbflags,
+ (dataflags & DB_F_HINT)
+ ? fcachetab
+ : hashtab, empty_from))
+ != OK) {
+ if (c != DATAEXISTS)
+ ns_debug(ns_log_load, 1,
+ "update failed %s %d",
+ domain, type);
+ db_freedata(dp);
+ } else {
+ rrcount++;
+ }
+ continue;
+
+ case ERROR:
+ break;
+ }
+ err:
+ errs++;
+ ns_notice(ns_log_load, "%s:%d: %s error (%s)",
+ filename, empty_token ? (lineno - 1) : lineno,
+ errtype, 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++;
+ ns_warning(ns_log_load,
+ "Zone \"%s\" (file %s): %s",
+ zp->z_origin, filename, msg);
+ }
+ }
+ }
+ if (!def_domain) {
+ if (errs)
+ ns_warning(ns_log_load,
+ "%s zone \"%s\" (%s) rejected due to errors (serial %u)",
+ zoneTypeString(zp), zp->z_origin,
+ p_class(zp->z_class), zp->z_serial);
+ else
+ ns_info(ns_log_load,
+ "%s zone \"%s\" (%s) loaded (serial %u)",
+ zoneTypeString(zp), zp->z_origin,
+ p_class(zp->z_class), zp->z_serial);
+ }
+ if (errs) {
+ zp->z_flags |= Z_DB_BAD;
+ zp->z_ftime = 0;
+ }
+#ifdef BIND_NOTIFY
+ if (!errs && !def_domain &&
+ (zp->z_type == z_master || zp->z_type == z_slave)) {
+ static const char no_room[] =
+ "%s failed, cannot notify for zone %s";
+ notify_info ni;
+
+ ni = memget(sizeof *ni);
+ if (ni == NULL)
+ ns_info(ns_log_load, no_room, "memget", zp->z_origin);
+ else {
+ ni->name = savestr(zp->z_origin, 0);
+ if (ni->name == NULL) {
+ memput(ni, sizeof *ni);
+ ns_info(ns_log_load, no_room,
+ "memget", zp->z_origin);
+ } else {
+ ni->class = zp->z_class;
+ ni->state = notify_info_waitfor;
+ if (evWaitFor(ev,
+ (const void *)notify_after_load,
+ notify_after_load, ni,
+ &ni->wait_id) < 0) {
+ ns_error(ns_log_load,
+ "evWaitFor() failed: %s",
+ strerror(errno));
+ freestr(ni->name);
+ memput(ni, sizeof *ni);
+ } else {
+ APPEND(pending_notifies, ni, link);
+ ns_need(MAIN_NEED_NOTIFY);
+ }
+ }
+ }
+ }
+#endif
+ return (errs);
+}
+
+static int
+gettoken(FILE *fp, const char *src) {
+ 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);
+ }
+ ns_notice(ns_log_db,
+ "%s:%d: Unknown $ option: $%s",
+ 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; lineno was incremented.
+ * 1 = word was read
+ */
+int
+getword(char *buf, size_t size, FILE *fp, int preserve) {
+ char *cp = buf;
+ 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')
+ (void)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)
+ switch (c) {
+ case '\\':
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ 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)
+ switch (c) {
+ case '\\':
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ 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')
+ (void)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);
+}
+
+/*
+ * int
+ * getttl(fp, fn, ln, ttl, multiline)
+ * read a word from the file and parse it as a TTL.
+ * return:
+ * 1 ttl found
+ * 0 word not read (EOF or EOL?)
+ * -1 word read but it wasn't a ttl
+ * side effects:
+ * *ttl is written if the return value is to be 1.
+ */
+static int
+getttl(FILE *fp, const char *fn, int lineno, u_int32_t *ttl, int *multiline) {
+ char buf[MAXDATA];
+ u_long tmp;
+ int ch;
+ int len;
+
+ while (!feof(fp) && !getword(buf, sizeof buf, fp, 0) && *multiline)
+ (void)NULL;
+ len = strlen(buf);
+ if (*multiline && len && buf[len-1] == ')') {
+ buf[len-1] = '\0';
+ *multiline = 0;
+ }
+ if (ns_parse_ttl(buf, &tmp) < 0) {
+ ns_notice(ns_log_db, "%s:%d: expected a TTL, got \"%s\"",
+ fn, lineno, buf);
+ return (-1);
+ }
+ if (*multiline) {
+ ch = getnonblank(fp, fn);
+ if (ch == EOF)
+ return (-1);
+ if (ch == ';')
+ endline(fp);
+ else
+ ungetc(ch, fp);
+ }
+ *ttl = (u_int32_t)tmp;
+ return (1);
+}
+
+/* Get multiline words. Same parameters as getword. Handles any
+ number of leading ('s or )'s in the words it sees.
+ FIXME: We kludge recognition of ( and ) for multiline input.
+ Each paren must appear at the start of a (blank-separated) word,
+ which is particularly counter-intuitive for ). Good enough for now,
+ until Paul rewrites the parser. (gnu@toad.com, oct96)
+*/
+static int
+getmlword(char *buf, size_t size, FILE *fp, int preserve) {
+ char *p;
+
+ do {
+ while (!getword (buf, size, fp, preserve)) {
+ /* No more words on this line. See if doing the
+ multiline thing. */
+ if (!getmlword_nesting) { /* Nope... */
+ ungetc('\n', fp); /* Push back newline */
+ lineno--; /* Unbump the lineno */
+ empty_token = 0; /* Undo this botch */
+ return 0;
+ }
+ if (feof(fp) || ferror(fp))
+ return 0; /* Error, no terminating ')' */
+ /* Continue reading til we get a word... */
+ }
+ while ('(' == *buf) {
+ /* Word starts with paren. Multiline mode.
+ Move the rest of the word down over the paren. */
+ getmlword_nesting++;
+ p = buf;
+ while (0 != (p[0]=p[1])) p++;
+ }
+ while (')' == *buf) {
+ getmlword_nesting--;
+ p = buf;
+ while (0 != (p[0]=p[1])) p++;
+ }
+ } while (buf[0] == 0); /* loop til we get a non-( non-) word */
+
+ return 1; /* Got a word... */
+}
+
+/* Get all the remaining words on a line, concatenated into one big
+ long (not too long!) string, with the whitespace squeezed out.
+ This routine, like getword(), does not swallow the newline if words seen.
+ This routine, unlike getword(), never swallows the newline if no words.
+ Parameters are the same as getword(). Result is:
+ 0 got no words at all
+ 1 got one or more words
+ -1 got too many words, they don't all fit; or missing close paren
+*/
+static int
+getallwords(char *buf, size_t size, FILE *fp, int preserve) {
+ char *runningbuf = buf;
+ int runningsize = size;
+ int len;
+
+ while (runningsize > 0) {
+ if (!getmlword (runningbuf, runningsize, fp, preserve)) {
+ return runningbuf!=buf; /* 1 or 0 */
+ }
+ len = strlen(runningbuf);
+ runningbuf += len;
+ runningsize -= len;
+ }
+ return -1; /* Error, String too long */
+}
+
+int
+getnum(FILE *fp, const char *src, int opt) {
+ 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) {
+ ns_notice(ns_log_db,
+ "%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) {
+ ns_info(ns_log_db,
+ "%s:%d: number after the decimal point exceeds 9999",
+ src, lineno);
+ getnum_error = 1;
+ return (0);
+ }
+ if (seendecimal) {
+ ns_info(ns_log_db,
+ "%s:%d: decimal serial number interpreted as %d",
+ src, lineno, n+m);
+ }
+ return (n + m);
+}
+
+#ifndef BIND_UPDATE
+static
+#endif
+int
+getnonblank(FILE *fp, const char *src) {
+ 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);
+ }
+ ns_info(ns_log_db, "%s:%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.
+ */
+int
+makename(char *name, const char *origin, int size) {
+ int n;
+ u_char domain[MAXCDNAME];
+
+ switch (ns_name_pton(name, domain, sizeof(domain))) {
+ case -1:
+ return (-1);
+ case 1: /* FULLY QUALIFIED */
+ break;
+ case 0: /* UNQUALIFIED */
+ if (strcmp(name, "@") == 0) /* must test raw name */
+ domain[0] = 0;
+ if ((n = dn_skipname(domain, domain+sizeof(domain))) == -1)
+ return (-1);
+ /* step back over root, append origin */
+ switch (ns_name_pton(origin, domain+n-1, sizeof(domain)-n+1)) {
+ case -1:
+ return (-1);
+ case 0:
+ case 1:
+ break;
+ }
+ break;
+ }
+ if (ns_name_ntop(domain, name, size) == -1)
+ return (-1);
+ if (name[0] == '.') /* root */
+ name[0] = '\0';
+ return (0);
+}
+
+static int
+makename_ok(char *name, const char *origin, int class, struct zoneinfo *zp,
+ enum transport transport, enum context context,
+ const char *owner, const char *filename, int lineno, int size)
+{
+ int ret = 1;
+
+ if (makename(name, origin, size) == -1) {
+ ns_info(ns_log_db, "%s:%d: makename failed",
+ filename, lineno);
+ return (0);
+ }
+ if (!ns_nameok(name, class, zp, transport, context, owner,
+ inaddr_any)) {
+ ns_info(ns_log_db, "%s:%d: database naming error",
+ filename, lineno);
+ ret = 0;
+ }
+ return (ret);
+}
+
+void
+endline(FILE *fp) {
+ 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
+
+#ifndef BIND_UPDATE
+static
+#endif
+char
+getprotocol(FILE *fp, const char *src) {
+ int k;
+ char b[MAXLEN];
+
+ (void) getword(b, sizeof(b), fp, 0);
+
+ k = protocolnumber(b);
+ if (k == -1)
+ ns_info(ns_log_db, "%s:%d: unknown protocol: %s.",
+ src, lineno, b);
+ return ((char) k);
+}
+
+#ifndef BIND_UPDATE
+static
+#endif
+int
+getservices(int offset, char *data, FILE *fp, const char *src) {
+ int j, ch, k, maxl, bracket;
+ char bm[MAXPORT/8];
+ char b[MAXLEN];
+
+ 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')
+ (void)NULL;
+ if (ch == '\n')
+ lineno++;
+ break;
+ }
+ k = servicenumber(b);
+ if (k == -1) {
+ ns_info(ns_log_db,
+ "%s:%d: Unknown service '%s'",
+ src, lineno, b);
+ continue;
+ }
+ if ((k < MAXPORT) && (k)) {
+ bm[k/8] |= (0x80>>(k%8));
+ if (k > maxl)
+ maxl = k;
+ } else {
+ ns_info(ns_log_db,
+ "%s:%d: port no. (%d) too big",
+ src, lineno, k);
+ }
+ }
+ if (bracket)
+ ns_info(ns_log_db, "%s:%d: missing close paren",
+ src, lineno);
+ maxl = maxl/8+1;
+ memcpy(data+offset, bm, maxl);
+ return (maxl+offset);
+}
+
+/*
+ * Converts a word to a u_int32_t. Error if any non-numeric
+ * characters in the word, except leading or trailing white space.
+ */
+static u_int32_t
+wordtouint32(buf)
+ char *buf;
+{
+ u_long result;
+ u_int32_t res2;
+ char *bufend;
+
+ wordtouint32_error = 0;
+ result = strtoul(buf, &bufend, 0);
+ if (bufend == buf)
+ wordtouint32_error = 1;
+ else
+ while ('\0' != *bufend) {
+ if (isspace(*bufend))
+ bufend++;
+ else {
+ wordtouint32_error = 1;
+ break;
+ }
+ }
+ /* Check for truncation between u_long and u_int32_t */
+ res2 = result;
+ if (res2 != result)
+ wordtouint32_error = 1;
+ return (res2);
+}
+
+
+/*
+ * Parse part of a date. Set error flag if any error.
+ * Don't reset the flag if there is no error.
+ */
+static int
+datepart(const char *buf, int size, int min, int max, int *errp) {
+ int result = 0;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (!isdigit(buf[i]))
+ *errp = 1;
+ result = (result * 10) + buf[i] - '0';
+ }
+ if (result < min)
+ *errp = 1;
+ if (result > max)
+ *errp = 1;
+ return (result);
+}
+
+
+/* Convert a date in ASCII into the number of seconds since
+ 1 January 1970 (GMT assumed). Format is yyyymmddhhmmss, all
+ digits required, no spaces allowed. */
+
+static u_int32_t
+datetosecs(const char *cp, int *errp) {
+ struct tm time;
+ u_int32_t result;
+ int mdays, i;
+ static const int days_per_month[12] =
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+ if (strlen(cp) != 14) {
+ *errp = 1;
+ return 0;
+ }
+ *errp = 0;
+
+ memset(&time, 0, sizeof time);
+ time.tm_year = datepart(cp + 0, 4, 1990, 9999, errp) - 1900;
+ time.tm_mon = datepart(cp + 4, 2, 01, 12, errp) - 1;
+ time.tm_mday = datepart(cp + 6, 2, 01, 31, errp);
+ time.tm_hour = datepart(cp + 8, 2, 00, 23, errp);
+ time.tm_min = datepart(cp + 10, 2, 00, 59, errp);
+ time.tm_sec = datepart(cp + 12, 2, 00, 59, errp);
+ if (*errp) /* Any parse errors? */
+ return (0);
+
+ /*
+ * OK, now because timegm() is not available in all environments,
+ * we will do it by hand. Roll up sleeves, curse the gods, begin!
+ */
+
+#define SECS_PER_DAY ((u_int32_t)24*60*60)
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+ result = time.tm_sec; /* Seconds */
+ result += time.tm_min * 60; /* Minutes */
+ result += time.tm_hour * (60*60); /* Hours */
+ result += (time.tm_mday - 1) * SECS_PER_DAY; /* Days */
+
+ /* Months are trickier. Look without leaping, then leap */
+ mdays = 0;
+ for (i = 0; i < time.tm_mon; i++)
+ mdays += days_per_month[i];
+ result += mdays * SECS_PER_DAY; /* Months */
+ if (time.tm_mon > 1 && isleap (1900+time.tm_year))
+ result += SECS_PER_DAY; /* Add leapday for this year */
+
+ /* First figure years without leapdays, then add them in. */
+ /* The loop is slow, FIXME, but simple and accurate. */
+ result += (time.tm_year - 70) * (SECS_PER_DAY*365); /* Years */
+ for (i = 70; i < time.tm_year; i++)
+ if (isleap (1900+i))
+ result += SECS_PER_DAY; /* Add leapday for prev year */
+
+ return (result);
+}
+
+
+#define MAXCHARSTRING 255
+
+static int
+getcharstring(char *buf, char *data, int type,
+ int minfields, int maxfields,
+ FILE *fp, const char *src)
+{
+ int nfield = 0, done = 0, n = 0, i;
+ char *b = buf;
+
+ do {
+ nfield++;
+ i = strlen(buf);
+#ifdef ALLOW_LONG_TXT_RDATA
+ b = buf;
+ if (type == ns_t_txt || type == ns_t_x25) {
+ while (i > MAXCHARSTRING
+ && n + MAXCHARSTRING + 1 < MAXDATA) {
+ data[n] = MAXCHARSTRING;
+ memmove(data + n + 1, b, MAXCHARSTRING);
+ n += MAXCHARSTRING + 1;
+ b += MAXCHARSTRING;
+ i -= MAXCHARSTRING;
+ }
+ }
+#endif /* ALLOW_LONG_TXT_RDATA */
+ if (i > MAXCHARSTRING) {
+ ns_info(ns_log_db,
+ "%s:%d: RDATA field %d too long",
+ src, lineno, nfield);
+ return (0);
+ }
+ if (n + i + 1 > MAXDATA) {
+ ns_info(ns_log_db,
+ "%s:%d: total RDATA too long",
+ src, lineno);
+ return (0);
+ }
+ data[n] = i;
+ memmove(data + n + 1, b, (int)i);
+ n += i + 1;
+ done = (maxfields && nfield >= maxfields);
+ } while (!done && getword(buf, MAXDATA, fp, 0));
+
+ if (nfield < minfields) {
+ ns_info(ns_log_db,
+ "%s:%d: expected %d RDATA fields, only saw %d",
+ src, lineno, minfields, nfield);
+ return (0);
+ }
+
+ if (done)
+ endline(fp);
+
+ return (n);
+}
+
+
+/*
+ * get_nxt_types(): Read the list of types in the NXT record.
+ *
+ * Data is the array where the bit flags are stored; it must
+ * contain at least ns_t_any/NS_NXT_BITS bytes.
+ * FP is the input FILE *.
+ * Filename is the sourcefile
+ *
+ * The result is how many bytes are significant in the result.
+ * ogud@tis.com 1995
+ */
+static int
+get_nxt_types(u_char *data, FILE *fp, const char *filename) {
+ char b[MAXLABEL]; /* Not quite the right size, but good enough */
+ int maxtype=0;
+ int success;
+ int type;
+ int errs = 0;
+
+ memset(data, 0, ns_t_any/NS_NXT_BITS+1);
+
+ while (getmlword(b, sizeof(b), fp, 0)) {
+ if (feof(fp) || ferror(fp))
+ break;
+ if (strlen(b) == 0 || b[0] == '\n')
+ continue;
+
+ /* Parse RR type (A, MX, etc) */
+ type = sym_ston(__p_type_syms, (char *)b, &success);
+ if ((!success) || type == ns_t_any) {
+ errs++;
+ ns_info(ns_log_db,
+ "%s: Line %d: Unknown type: %s in NXT record.",
+ filename, lineno, b);
+ continue;
+ }
+ NS_NXT_BIT_SET(type, data);
+ if (type > maxtype)
+ maxtype = type;
+ }
+ if (errs)
+ return (0);
+ else
+ return (maxtype/NS_NXT_BITS+1);
+}
+
+/* sanity checks PRIMARY ONLY */
+static void
+fixup_soa(const char *fn, struct zoneinfo *zp) {
+ /* Sanity: give enough time for the zone to transfer (retry). */
+ if (zp->z_expire < (zp->z_refresh + zp->z_retry))
+ ns_notice(ns_log_db,
+ "%s: WARNING SOA expire value is less than SOA refresh+retry (%u < %u+%u)",
+ fn, zp->z_expire, zp->z_refresh, zp->z_retry);
+
+ /* Sanity. */
+ if (zp->z_expire < (zp->z_refresh + 10 * zp->z_retry))
+ ns_warning(ns_log_db,
+"%s: WARNING SOA expire value is less than refresh + 10 * retry \
+(%u < (%u + 10 * %u))",
+ fn, zp->z_expire, zp->z_refresh, zp->z_retry);
+
+ /*
+ * Sanity: most hardware/telco faults are detected and fixed within
+ * a week, secondaries should continue to operate for this time.
+ * (minimum of 4 days for long weekends)
+ */
+ if (zp->z_expire < (7 * 24 * 3600))
+ ns_warning(ns_log_db,
+ "%s: WARNING SOA expire value is less than 7 days (%u)",
+ fn, zp->z_expire);
+
+ /*
+ * Sanity: maximum down time if we havn't talked for six months
+ * war must have broken out.
+ */
+ if (zp->z_expire > ( 183 * 24 * 3600))
+ ns_warning(ns_log_db,
+ "%s: WARNING SOA expire value is greater than 6 months (%u)",
+ fn, zp->z_expire);
+
+ /* Sanity. */
+ if (zp->z_refresh < (zp->z_retry * 2))
+ ns_warning(ns_log_db,
+ "%s: WARNING SOA refresh value is less than 2 * retry (%u < %u * 2)",
+ fn, zp->z_refresh, zp->z_retry);
+}
+
+#ifdef BIND_NOTIFY
+static void
+free_notify_info(notify_info ni) {
+ if (ni->state == notify_info_waitfor)
+ evUnwait(ev, ni->wait_id);
+ else if (ni->state == notify_info_delay)
+ evClearTimer(ev, ni->timer_id);
+ freestr(ni->name);
+ memput(ni, sizeof *ni);
+}
+
+void
+notify_after_load(evContext ctx, void *uap, const void *tag) {
+ int delay, max_delay;
+ notify_info ni = uap;
+
+ INSIST(tag == (const void *)notify_after_load);
+
+ /* delay notification for from five seconds up to fifteen minutes */
+ max_delay = MIN(nzones/5, 895);
+ max_delay = MAX(max_delay, 25);
+ delay = 5 + (rand() % max_delay);
+ ns_debug(ns_log_notify, 3, "notify_after_load: uap %p tag %p delay %d",
+ uap, tag, delay);
+ if (evSetTimer(ctx, notify_after_delay, ni,
+ evAddTime(evNowTime(), evConsTime(delay, 0)),
+ evConsTime(0, 0), &ni->timer_id) < 0) {
+ ns_error(ns_log_notify, "evSetTimer() failed: %s",
+ strerror(errno));
+ UNLINK(pending_notifies, ni, link);
+ ni->state = notify_info_error;
+ free_notify_info(ni);
+ }
+ ni->state = notify_info_delay;
+}
+
+static void
+notify_after_delay(evContext ctx, void *uap,
+ struct timespec due,
+ struct timespec inter)
+{
+ notify_info ni = uap;
+
+ UNLINK(pending_notifies, ni, link);
+ ni->state = notify_info_done;
+ sysnotify(ni->name, ni->class, ns_t_soa);
+ free_notify_info(ni);
+}
+
+void
+db_cancel_pending_notifies(void) {
+ notify_info ni, ni_next;
+ for (ni = HEAD(pending_notifies); ni != NULL; ni = ni_next) {
+ ni_next = NEXT(ni, link);
+ free_notify_info(ni);
+ }
+ INIT_LIST(pending_notifies);
+}
+#endif
diff --git a/contrib/bind/bin/named/db_lookup.c b/contrib/bind/bin/named/db_lookup.c
new file mode 100644
index 0000000..ddf17ad
--- /dev/null
+++ b/contrib/bind/bin/named/db_lookup.c
@@ -0,0 +1,269 @@
+#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.13 1998/02/13 19:52:54 halley Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/*
+ * Table lookup routines.
+ */
+
+#include "port_before.h"
+
+#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 <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+
+#include "port_after.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(const char *name, struct hashbuf **htpp,
+ const char **fname, int insert)
+{
+ struct namebuf *np;
+ const char *cp;
+ int c;
+ u_int hval;
+ struct hashbuf *htp;
+ struct namebuf *parent = NULL;
+ int escaped = 0;
+
+ htp = *htpp;
+ hval = 0;
+ *fname = "???";
+ for (cp = name; (c = *cp++) != 0; (void)NULL) {
+ 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 += ((isascii(c) && 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 &&
+ ((size_t)NAMELEN(*np) == (size_t)(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);
+ }
+ ns_debug(ns_log_db, 1,
+ "np_parent(0x%lx) couldn't find root entry",
+ (u_long) np);
+ return (NULL); /* XXX shouldn't happen */
+ }
+ }
+ /* Try the hints. */
+ if (htp == hashtab) {
+ htp = fcachetab;
+ goto try_again;
+ }
+ ns_debug(ns_log_db, 1, "np_parent(0x%lx) couldn't namebuf",
+ (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(struct databuf *dp, int class, int 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/bin/named/db_save.c b/contrib/bind/bin/named/db_save.c
new file mode 100644
index 0000000..a05c40f
--- /dev/null
+++ b/contrib/bind/bin/named/db_save.c
@@ -0,0 +1,221 @@
+#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.15 1998/01/26 22:40:08 halley Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/*
+ * Buffer allocation and deallocation routines.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+/*
+ * Allocate a name buffer & save name.
+ */
+struct namebuf *
+savename(const char *name, int len) {
+ struct namebuf *np;
+
+ /*
+ * Note that MAXLABEL * 4 < 256, so a single length byte is enough.
+ * Also, we use MAXLABEL * 4 because each label character can
+ * expand into up to four characters when rendered in canonical
+ * form.
+ */
+ INSIST(len >= 0 && len <= (MAXLABEL * 4));
+ np = (struct namebuf *) memget(NAMESIZE(len));
+ if (np == NULL)
+ panic("savename: memget", NULL);
+ memset(np, 0, NAMESIZE(len));
+ NAMELEN(*np) = (unsigned)len;
+ memcpy(NAME(*np), name, len);
+ NAME(*np)[len] = '\0';
+ return (np);
+}
+
+/*
+ * Allocate a data buffer & save data.
+ */
+struct databuf *
+savedata(class, type, ttl, data, size)
+ int class, type;
+ u_int32_t ttl;
+ u_char *data;
+ int size;
+{
+ struct databuf *dp;
+ int bytes = (type == T_NS) ? DATASIZE(size)+INT32SZ : DATASIZE(size);
+
+ dp = (struct databuf *)memget(bytes);
+ if (dp == NULL)
+ panic("savedata: memget", NULL);
+ memset(dp, 0, 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;
+ dp->d_rcode = NOERROR;
+ dp->d_ns = NULL;
+ dp->d_nstime = 0;
+ memcpy(dp->d_data, data, dp->d_size);
+ return (dp);
+}
+
+int hashsizes[] = { /* hashtable sizes */
+ 2,
+ 11,
+ 113,
+ 337,
+ 977,
+ 2053,
+ 4073,
+ 8011,
+ 16001,
+ 99887,
+ 0
+};
+
+/*
+ * Allocate a data buffer & save data.
+ */
+struct hashbuf *
+savehash(oldhtp)
+ struct hashbuf *oldhtp;
+{
+ struct hashbuf *htp;
+ struct namebuf *np, *nnp, **hp;
+ int n, newsize;
+
+ if (oldhtp == NULL)
+ newsize = hashsizes[0];
+ else {
+ for (n = 0; (newsize = hashsizes[n++]) != 0; (void)NULL)
+ if (oldhtp->h_size == newsize) {
+ newsize = hashsizes[n];
+ break;
+ }
+ if (newsize == 0)
+ newsize = oldhtp->h_size * 2 + 1;
+ }
+ ns_debug(ns_log_db, 4, "savehash GROWING to %d", newsize);
+ htp = (struct hashbuf *) memget(HASHSIZE(newsize));
+ if (htp == NULL)
+ ns_panic(ns_log_db, 0, "savehash: %s", strerror(errno));
+ htp->h_size = newsize;
+ memset(htp->h_tab, 0, newsize * sizeof(struct namebuf *));
+ if (oldhtp == NULL) {
+ htp->h_cnt = 0;
+ return (htp);
+ }
+ ns_debug(ns_log_db, 4, "savehash(%#lx) cnt=%d, sz=%d, newsz=%d",
+ (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;
+ }
+ }
+ oldhtp->h_cnt = 0; /* Keep rm_hash() happy. */
+ rm_hash(oldhtp);
+ return (htp);
+}
diff --git a/contrib/bind/bin/named/db_update.c b/contrib/bind/bin/named/db_update.c
new file mode 100644
index 0000000..ab70663
--- /dev/null
+++ b/contrib/bind/bin/named/db_update.c
@@ -0,0 +1,932 @@
+#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.23 1998/02/13 20:01:38 halley Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.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 <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+/* 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(const char *name, struct hashbuf *htp) {
+ struct namebuf *np;
+ 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 &&
+ !dp->d_rcode &&
+ !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(struct namebuf *np, int class) {
+ for ((void)NULL; np; np = np_parent(np)) {
+ 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);
+}
+
+
+#define ISVALIDGLUE(xdp) ((xdp)->d_type == T_NS || (xdp)->d_type == T_A \
+ || (xdp)->d_type == T_AAAA)
+
+/* int
+ * db_update(name, odp, newdp, savedpp, flags, htp, from)
+ * 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 clean_cache() and made
+ * general enough for this use, and for clean_cache()'s continued use.
+ * vix, 21jul94
+ */
+int
+db_update(const char *name,
+ struct databuf *odp, struct databuf *newdp,
+ struct databuf **savedpp,
+ int flags, struct hashbuf *htp, struct sockaddr_in from)
+{
+ struct databuf *dp, *pdp;
+ struct namebuf *np;
+ int zn, isHintNS;
+ int check_ttl = 0;
+ const char *fname;
+#ifdef BIND_UPDATE
+ int i, found_other_ns = 0;
+ struct databuf *tmpdp;
+ u_char *cp1, *cp2;
+ u_int32_t dp_serial, newdp_serial;
+#endif
+
+ ns_debug(ns_log_db, 3, "db_update(%s, %#x, %#x, %#x, 0%o, %#x)%s",
+ name, odp, newdp, savedpp, flags, htp,
+ (odp && (odp->d_flags&DB_F_HINT)) ? " hint" : "");
+ np = nlookup(name, &htp, &fname, newdp != NULL);
+ if (np == NULL || fname != name)
+ return (NONAME);
+
+ if (newdp && zones[newdp->d_zone].z_type == Z_PRIMARY)
+ check_ttl = 1;
+
+ /* 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)
+ ns_debug(ns_log_db, 5,
+ "[%s].%d update? to auth zone \"%s\" (%s)",
+ inet_ntoa(from.sin_addr),
+ ntohs(from.sin_port),
+ zones[zn].z_origin,
+ name);
+ return (AUTH);
+ }
+
+ if (newdp && zn && !(flags & DB_NOTAUTH)) {
+ if (nlabels(zones[zn].z_origin) > newdp->d_clev) {
+ ns_debug(ns_log_db, 5,
+ "attempted update child zone %s, %s",
+ 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) {
+ ns_debug(ns_log_db, 3,
+ "upgrading credibility for A RR (%s)",
+ 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) &&
+ (DB_Z_SPECIAL(odp->d_zone)) &&
+ !(odp->d_flags & DB_F_HINT) &&
+ (!newdp || !newdp->d_rcode) &&
+ ((name[0] == '\0' && odp->d_type == T_NS) ||
+ (odp->d_type == T_A && isHintNS)
+ )
+ )
+ {
+ ns_debug(ns_log_db, 3, "db_update: hint '%s' %u",
+ 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, NULL,
+ (flags|DB_NOHINTS),
+ fcachetab, from)
+ != OK) {
+ ns_debug(ns_log_db, 3,
+ "db_update: hint %#x freed", dp);
+ db_freedata(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.
+ */
+ /* Check that CNAMEs are only accompanied by
+ * Secure DNS RR's (KEY, SIG, and NXT).
+ */
+ if (((dp->d_type == T_CNAME &&
+ odp->d_type != T_KEY &&
+ odp->d_type != T_SIG &&
+ odp->d_type != T_NXT) ||
+ (odp->d_type == T_CNAME &&
+ dp->d_type != T_KEY &&
+ dp->d_type != T_SIG &&
+ dp->d_type != T_NXT)) &&
+ odp->d_class == dp->d_class &&
+ /* XXXRTH d_mark removed in 4.9.5,
+ but still here for dynamic
+ update */
+ odp->d_mark == dp->d_mark &&
+ !dp->d_rcode &&
+ !odp->d_rcode &&
+#ifdef BIND_UPDATE
+ /* updating a CNAME with another CNAME is permitted */
+ (dp->d_type != T_CNAME ||
+ odp->d_type != T_CNAME) &&
+#endif
+ zones[odp->d_zone].z_type != Z_CACHE) {
+ ns_info(ns_log_db,
+ "%s has CNAME and other data (invalid)",
+ 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)) {
+ ns_info(ns_log_db,
+ "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)) {
+ ns_info(ns_log_db,
+ "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;
+ }
+ }
+
+ /* 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 */
+
+ goto skip;
+ } /*if {class,type} did not match*/
+
+ /*
+ * {type,class} did match. This is the replace case.
+ */
+ ns_debug(ns_log_db, 5,
+ "db_update: flags = %#x, sizes = %d, %d (cmp %d)",
+ flags, odp->d_size, dp->d_size,
+ db_cmp(dp, odp));
+ if (newdp) {
+ ns_debug(ns_log_db, 4,
+ "credibility for %s is %d(%d) from [%s].%d, is %d(%d) in cache",
+ *name ? name : ".",
+ newdp->d_cred,
+ newdp->d_clev,
+ inet_ntoa(from.sin_addr),
+ ntohs(from.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)) {
+ ns_info(ns_log_db,
+ "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)) {
+ ns_info(ns_log_db,
+ "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.
+ */
+
+ /*
+ * 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);
+ }
+
+ /*
+ * Some RR types should not be aggregated.
+ */
+ if (dp->d_type == T_SOA) {
+#ifdef BIND_UPDATE
+ u_int32_t dp_ser, ndp_ser;
+ u_char *dp_cp, *ndp_cp;
+
+ dp_cp = findsoaserial(dp->d_data);
+ ndp_cp = findsoaserial(newdp->d_data);
+ GETLONG(dp_ser, dp_cp);
+ GETLONG(ndp_ser, ndp_cp);
+
+ if (SEQ_GT(ndp_ser, dp_ser))
+ goto delete;
+ else
+ return (SERIAL);
+#else
+ goto delete;
+#endif /*BIND_UPDATE*/
+ }
+ if (dp->d_type == T_WKS &&
+ !memcmp(dp->d_data, newdp->d_data,
+ INT32SZ + sizeof(u_char)))
+ goto delete;
+ if (dp->d_type == T_CNAME &&
+ !NS_OPTION_P(OPTION_MULTIPLE_CNAMES))
+ goto delete;
+#ifdef BIND_UPDATE
+ if (dp->d_type == T_SIG)
+ /*
+ * Type covered has already been
+ * checked.
+ */
+ goto delete;
+#endif
+ if (check_ttl) {
+ if (newdp->d_ttl != dp->d_ttl)
+ ns_warning(ns_log_db,
+ "%s %s %s differing ttls: corrected",
+ name[0]?name:".",
+ p_class(dp->d_class),
+ p_type(dp->d_type));
+ if (newdp->d_ttl > dp->d_ttl) {
+ newdp->d_ttl = dp->d_ttl;
+ } else {
+ dp->d_ttl = newdp->d_ttl;
+ }
+ }
+ }
+ if ((flags & DB_NODATA) && !db_cmp(dp, odp)) {
+ /* Refresh ttl if cache entry. */
+ if (dp->d_zone == DB_Z_CACHE) {
+ if (odp->d_zone != DB_Z_CACHE) {
+ /* Changing cache->auth. */
+ dp->d_zone = odp->d_zone;
+ dp->d_ttl = odp->d_ttl;
+ ns_debug(ns_log_db, 4,
+ "db_update: cache entry now in auth zone");
+ return (DATAEXISTS);
+ }
+ fixttl(odp);
+ if (odp->d_ttl > dp->d_ttl)
+ dp->d_ttl = odp->d_ttl;
+ ns_debug(ns_log_db, 3,
+ "db_update: new ttl %u +%lu",
+ 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.
+ */
+ if (odp->d_size > 0)
+ if (db_cmp(dp, odp))
+ goto skip;
+ if (odp->d_clev < dp->d_clev)
+ goto skip;
+ if (odp->d_cred < dp->d_cred)
+ goto skip;
+#ifdef BIND_UPDATE
+ if (!strcasecmp(name, zones[dp->d_zone].z_origin) &&
+ !newdp) {
+ /* do not delete SOA or NS records as a set */
+ /* XXXRTH isn't testing d_size unnecessary? */
+ if ((odp->d_size == 0) &&
+ (odp->d_class == C_ANY) &&
+ (odp->d_type == T_ANY ||
+ odp->d_type == T_SOA ||
+ odp->d_type == T_NS) &&
+ (dp->d_type == T_SOA ||
+ dp->d_type == T_NS))
+ goto skip;
+ /* XXXRTH I added this to prevent SOA deletion
+ I'm using the same style of comparison as
+ the other code in this section. Do we
+ really need to look at dp->d_type here?
+ We're in the "match" section... */
+ if ((odp->d_type == T_SOA) &&
+ (dp->d_type == T_SOA))
+ goto skip;
+ /* do not delete the last NS record
+ for the zone */
+ if ((odp->d_type == T_NS) &&
+ (dp->d_type == T_NS)) {
+ found_other_ns = 0;
+ for (tmpdp = np->n_data;
+ tmpdp && !found_other_ns;
+ tmpdp = tmpdp->d_next)
+ if ((tmpdp->d_type == T_NS) &&
+ (tmpdp != dp))
+ found_other_ns = 1;
+ if (!found_other_ns) {
+ ns_debug(ns_log_db, 3,
+ "cannot delete last remaining NS record for zone %s",
+ name);
+ goto skip;
+ }
+ }
+ }
+#endif
+
+ foundRR = 1;
+ if (flags & DB_DELETE) {
+ delete:
+#ifdef BIND_UPDATE
+ /*
+ * XXX assume here that savedpp!=NULL iff. db_update
+ * has been called by the dyanmic update code.
+ * Maybe a new flag is more appropriate?
+ */
+ if (savedpp != NULL)
+ foundRR = 1;
+#endif
+ dp = rm_datum(dp, np, pdp, savedpp);
+ } else {
+ skip: pdp = dp;
+ dp = dp->d_next;
+ }
+ }
+ if (!foundRR) {
+ if (flags & DB_DELETE)
+ return (NODATA);
+ if (flags & DB_MEXIST)
+ return (NODATA);
+ }
+ }
+ /* XXX: delete a terminal namebuf also if all databuf's
+ * underneath of it have been deleted) */
+ if (newdp == NULL)
+ return (OK);
+ /* XXX: empty nodes bypass credibility checks above; should check
+ * response source address here if flags&NOTAUTH.
+ */
+ fixttl(newdp);
+ ns_debug(ns_log_db, 3, "db_update: adding%s %#x",
+ (newdp->d_flags&DB_F_HINT) ? " hint":"", newdp);
+
+ if (NS_OPTION_P(OPTION_HOSTSTATS) &&
+ newdp->d_zone == DB_Z_CACHE &&
+ (newdp->d_flags & DB_F_HINT) == 0)
+ newdp->d_ns = nameserFind(from.sin_addr, NS_F_INSERT);
+
+ /* Add to end of list, generally preserving order */
+ newdp->d_next = NULL;
+ if ((dp = np->n_data) == NULL) {
+ DRCNTINC(newdp);
+ if (newdp->d_flags & DB_F_ACTIVE)
+ panic("db_update: DB_F_ACTIVE set", NULL);
+ newdp->d_flags |= DB_F_ACTIVE;
+ 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);
+ DRCNTINC(newdp);
+ if (newdp->d_flags & DB_F_ACTIVE)
+ panic("db_update: DB_F_ACTIVE set", NULL);
+ newdp->d_flags |= DB_F_ACTIVE;
+ dp->d_next = newdp;
+ return (OK);
+}
+
+void
+fixttl(struct databuf *dp) {
+ if (dp->d_zone == DB_Z_CACHE && (dp->d_flags & DB_F_HINT) == 0) {
+ if (dp->d_ttl <= (u_int32_t)tt.tv_sec)
+ return;
+ else if (dp->d_ttl < (u_int32_t)tt.tv_sec+min_cache_ttl)
+ dp->d_ttl = (u_int32_t)tt.tv_sec+min_cache_ttl;
+ else if (dp->d_ttl > (u_int32_t)tt.tv_sec+max_cache_ttl)
+ dp->d_ttl = (u_int32_t)tt.tv_sec+max_cache_ttl;
+ }
+}
+
+/*
+ * Compare type, class and data from databufs for equivalence.
+ * All domain names in RR's must be compared case-insensitively.
+ * Return 0 if equivalent, nonzero otherwise.
+ */
+int
+db_cmp(const struct databuf *dp1, const struct databuf *dp2) {
+ const u_char *cp1, *cp2;
+ int len, len2;
+
+ /* XXXDYNUP- should be changed to
+ if (!match(dp1, dp2->d_type, dp2->d_class) */
+ if (dp1->d_type != dp2->d_type || dp1->d_class != dp2->d_class)
+ return (1);
+ /* XXXDYNUP - should be changed to (dp1->d_size != dp2->d_size &&
+ dp1->d_size != 0 && dp2->d_size != 0) */
+ if (dp1->d_size != dp2->d_size)
+ return (1);
+ /* d_mark is only used for dynamic updates currently */
+#ifndef BIND_UPDATE
+ if (dp1->d_mark != dp2->d_mark)
+ return (1); /* old and new RR's are distinct */
+#endif
+ 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);
+
+ switch (dp1->d_type) {
+
+ case T_A:
+ case T_WKS:
+ case T_NULL:
+ case T_NSAP:
+ case T_AAAA:
+ case T_LOC:
+ case T_KEY:
+ /* Only binary data */
+ return (memcmp(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:
+ /* Only a domain name */
+ return (strcasecmp((char *)dp1->d_data, (char *)dp2->d_data));
+
+ case T_SIG:
+ /* Binary data, a domain name, more binary data */
+ if (dp1->d_size < NS_SIG_SIGNER)
+ return (1);
+ if (memcmp(dp1->d_data, dp2->d_data, NS_SIG_SIGNER))
+ return (1);
+ len = NS_SIG_SIGNER +
+ strlen((char *)dp1->d_data + NS_SIG_SIGNER);
+ if (strcasecmp((char *)dp1->d_data + NS_SIG_SIGNER,
+ (char *)dp2->d_data + NS_SIG_SIGNER))
+ return (1);
+ return (memcmp(dp1->d_data + len,
+ dp2->d_data + len,
+ dp1->d_size - len));
+
+ case T_NXT:
+ /* First a domain name, then binary data */
+ if (strcasecmp((char *)dp1->d_data, (char *)dp2->d_data))
+ return (1);
+ len = strlen((char *)dp1->d_data)+1;
+ return (memcmp(dp1->d_data + len,
+ dp2->d_data + len,
+ dp1->d_size - len));
+
+ 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 (memcmp(cp1, cp2, INT32SZ * 5));
+
+ case T_NAPTR: {
+ int t1,t2;
+
+ if (dp1->d_size != dp2->d_size)
+ return (1);
+ cp1 = dp1->d_data;
+ cp2 = dp2->d_data;
+
+ /* Order */
+ if (*cp1++ != *cp2++ || *cp1++ != *cp2++)
+ return (1);
+
+ /* Preference */
+ if (*cp1++ != *cp2++ || *cp1++ != *cp2++)
+ return (1);
+
+ /* Flags */
+ t1 = *cp1++; t2 = *cp2++;
+ if (t1 != t2 || memcmp(cp1, cp2, t1))
+ return (1);
+ cp1 += t1; cp2 += t2;
+
+ /* Services */
+ t1 = *cp1++; t2 = *cp2++;
+ if (t1 != t2 || memcmp(cp1, cp2, t1))
+ return (1);
+ cp1 += t1; cp2 += t2;
+
+ /* Regexp */
+ t1 = *cp1++; t2 = *cp2++;
+ if (t1 != t2 || memcmp(cp1, cp2, t1))
+ return (1);
+ cp1 += t1; cp2 += t2;
+
+ /* Replacement */
+ t1 = strlen((char *)cp1); t2 = strlen((char *)cp2);
+ if (t1 != t2 || memcmp(cp1, cp2, t1))
+ return (1);
+ cp1 += t1 + 1; cp2 += t2 + 1;
+
+ /* they all checked out! */
+ return (0);
+ }
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ case T_SRV:
+ cp1 = dp1->d_data;
+ cp2 = dp2->d_data;
+ if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* cmp prio */
+ return (1);
+ if (dp1->d_type == T_SRV) {
+ if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* weight */
+ return (1);
+ if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* port */
+ 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 (memcmp(dp1->d_data, dp2->d_data, dp1->d_size));
+
+ default:
+ return (1);
+ }
+}
diff --git a/contrib/bind/bin/named/named-bootconf.pl b/contrib/bind/bin/named/named-bootconf.pl
new file mode 100755
index 0000000..ce474c4
--- /dev/null
+++ b/contrib/bind/bin/named/named-bootconf.pl
@@ -0,0 +1,324 @@
+#!/usr/bin/perl
+
+## Copyright (c) 1996, 1997 by Internet Software Consortium
+##
+## 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.
+##
+## THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+## ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+## OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+## CONSORTIUM 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.
+
+## $Id: named-bootconf.pl,v 8.16 1998/02/13 19:48:25 halley Exp $
+
+# This is a filter. Input is a named.boot. Output is a named.conf.
+
+$new_config = "";
+
+$have_options = 0;
+%options = ();
+%options_comments = ();
+@topology = ();
+@topology_comments = ();
+@bogus = ();
+@bogus_comments = ();
+@transfer_acl = ();
+@transfer_comments = ();
+$logging = "";
+
+while(<>) {
+ next if /^$/;
+
+ # skip comment-only lines
+ if (/^\s*;+\s*(.*)$/) {
+ $new_config .= "// $1\n";
+ next;
+ }
+
+ # handle continued lines
+ while (/\\$/) {
+ s/\\$/ /;
+ $_ .= <>;
+ }
+
+ chop;
+
+ # deal with lines ending in a coment
+ if (s/\s*;+\s*(.*)$//) {
+ $comment = "// $1";
+ } else {
+ $comment = "";
+ }
+
+ ($directive, @rest) = split;
+
+ $class = "";
+ if ($directive =~ /^(.*)\/(.*)$/) {
+ $directive = $1;
+ $class = $2;
+ }
+
+ if ($directive eq "primary") {
+ $zname = shift(@rest);
+ &maybe_print_comment("","\n");
+ $new_config .= "zone \"$zname\" ";
+ if ($class ne "") {
+ $new_config .= "$class ";
+ }
+ $new_config .= "{\n";
+ $new_config .= "\ttype master;\n";
+ $filename = shift(@rest);
+ $new_config .= "\tfile \"$filename\";\n";
+ $new_config .= "};\n\n";
+ } elsif ($directive eq "secondary" || $directive eq "stub") {
+ if ($directive eq "secondary") {
+ $type = "slave";
+ } else {
+ $type = "stub";
+ }
+ $zname = shift(@rest);
+ &maybe_print_comment("","\n");
+ $new_config .= "zone \"$zname\" ";
+ if ($class ne "") {
+ $new_config .= "$class ";
+ }
+ $new_config .= "{\n";
+ $new_config .= "\ttype $type;\n";
+ $filename = pop(@rest);
+ if ($filename =~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) {
+ push(@rest, $filename);
+ $filename = "";
+ } else {
+ $new_config .= "\tfile \"$filename\";\n";
+ }
+ $new_config .= "\tmasters {\n";
+ foreach $master (@rest) {
+ $new_config .= "\t\t$master;\n";
+ }
+ $new_config .= "\t};\n";
+ $new_config .= "};\n\n";
+ } elsif ($directive eq "cache") {
+ $zname = shift(@rest);
+ &maybe_print_comment("","\n");
+ $new_config .= "zone \"$zname\" {\n";
+ $new_config .= "\ttype hint;\n";
+ $filename = shift(@rest);
+ $new_config .= "\tfile \"$filename\";\n";
+ $new_config .= "};\n\n";
+ } elsif ($directive eq "directory") {
+ $options{"directory"} = "\"$rest[0]\"";
+ $options_comments{"directory"} = $comment;
+ $have_options = 1;
+ } elsif ($directive eq "check-names") {
+ $type = shift(@rest);
+ if ($type eq "primary") {
+ $type = "master";
+ } elsif ($type eq "secondary") {
+ $type = "slave";
+ }
+ $action = shift(@rest);
+ $options{"check-names $type"} = $action;
+ $options_comments{"check-names $type"} = $comment;
+ $have_options = 1;
+ } elsif ($directive eq "forwarders") {
+ $options{"forwarders"}="{\n";
+ foreach $forwarder (@rest) {
+ $options{"forwarders"} .= "\t\t$forwarder;\n";
+ }
+ $options{"forwarders"} .= "\t}";
+ $options_comments{"forwarders"} = $comment;
+ $have_options = 1;
+ } elsif ($directive eq "slave") {
+ &handle_options("forward-only");
+ } elsif ($directive eq "options") {
+ &handle_options(@rest);
+ } elsif ($directive eq "limit") {
+ &handle_limit(@rest);
+ } elsif ($directive eq "include") {
+ $new_config .=
+ "// make sure your include is still in the right place\n";
+ $comment = "\t" . $comment;
+ $new_config .= "include \"$rest[0]\";$comment\n\n";
+ } elsif ($directive eq "xfrnets" || $directive eq "tcplist") {
+ if ($comment ne "") {
+ $comment = "\t$comment";
+ }
+ foreach $elt (@rest) {
+ push(@transfer_acl, $elt);
+ push(@transfer_comments, $comment);
+ }
+ $have_options = 1;
+ } elsif ($directive eq "sortlist") {
+ if ($comment ne "") {
+ $comment = "\t$comment";
+ }
+ foreach $elt (@rest) {
+ push(@topology, $elt);
+ push(@topology_comments, $comment);
+ }
+ } elsif ($directive eq "bogusns") {
+ if ($comment ne "") {
+ $comment = "\t$comment";
+ }
+ foreach $elt (@rest) {
+ push(@bogus, $elt);
+ push(@bogus_comments, $comment);
+ }
+ } elsif ($directive eq "max-fetch") {
+ $options{"transfers-in"}=$rest[0];
+ $options_comments{"transfers-in"}=$comment;
+ $have_options = 1;
+ } else {
+ $new_config .= "// NOTE: unconverted directive '$directive @rest'\n\n";
+ }
+}
+
+print "// generated by named-bootconf.pl\n\n";
+if ($have_options) {
+ print "options {\n";
+ foreach $option (sort(keys(%options))) {
+ print "\t$option $options{$option};";
+ if ($options_comments{$option} ne "") {
+ print "\t$options_comments{$option}";
+ }
+ print "\n";
+ }
+ if (@transfer_acl > 0) {
+ print "\tallow-transfer {\n";
+ for ($i = 0; $i <= $#transfer_acl; $i++) {
+ &print_maybe_masked("\t\t", $transfer_acl[$i],
+ $transfer_comments[$i]);
+ }
+ print "\t};\n";
+ }
+ print "\t/*
+\t * If there is a firewall between you and nameservers you want
+\t * to talk to, you might need to uncomment the query-source
+\t * directive below. Previous versions of BIND always asked
+\t * questions using port 53, but BIND 8.1 uses an unprivileged
+\t * port by default.
+\t */
+\t// query-source address * port 53;
+";
+
+ print "};\n\n";
+}
+if ($logging ne "") {
+ print "logging {\n$logging};\n\n";
+}
+if (@topology > 0) {
+ print "// Note: the following will be supported in a future release.\n";
+ print "/*\n";
+ print "host { any; } {\n\ttopology {\n";
+ for ($i = 0; $i <= $#topology; $i++) {
+ &print_maybe_masked("\t\t", $topology[$i],
+ $topology_comments[$i]);
+ }
+ print "\t};\n};\n";
+ print "*/\n";
+ print "\n";
+}
+if (@bogus > 0) {
+ for ($i = 0; $i <= $#bogus; $i++) {
+ print "server $bogus[$i] { bogus yes; };$bogus_comments[$i]\n";
+ }
+ print "\n";
+}
+print $new_config;
+
+exit 0;
+
+sub maybe_print_comment {
+ $prefix = shift;
+ $suffix = shift;
+ if ($comment ne "") {
+ $new_config .= sprintf("%s%s%s", $prefix, $comment, $suffix);
+ }
+}
+
+sub handle_options {
+ foreach $option (@_) {
+ if ($option eq "forward-only") {
+ $options{"forward"}="only";
+ $options_comments{"forward"}=$comment;
+ $have_options = 1;
+ } elsif ($option eq "no-recursion") {
+ $options{"recursion"}="no";
+ $options_comments{"recursion"}=$comment;
+ $have_options = 1;
+ } elsif ($option eq "no-fetch-glue") {
+ $options{"fetch-glue"}="no";
+ $options_comments{"fetch-glue"}=$comment;
+ $have_options = 1;
+ } elsif ($option eq "fake-iquery") {
+ $options{"fake-iquery"}="yes";
+ $options_comments{"fake-iquery"}=$comment;
+ $have_options = 1;
+ } elsif ($option eq "query-log") {
+ if ($comment ne "") {
+ $logging .= "\t$comment\n";
+ }
+ $logging .= "\tcategory queries { default_syslog; };\n";
+ } else {
+ $options{"// NOTE: unconverted option '$option'"}="";
+ $options_comments{"// NOTE: unconverted option '$option'"}=
+ $comment;
+ $have_options = 1;
+ }
+ }
+}
+
+sub handle_limit {
+ $limit = shift;
+ if ($limit eq "datasize" || $limit eq "transfers-in"
+ || $limit eq "transfers-per-ns" || $limit eq "files") {
+ $options{$limit}=$_[0];
+ $options_comments{$limit}=$comment;
+ $have_options = 1;
+ } else {
+ $options{"// NOTE: unconverted limit '$limit @_'"}="";
+ $options_comments{"// NOTE: unconverted limit '$limit @_'"}=$comment;
+ $have_options = 1;
+ }
+}
+
+sub print_maybe_masked {
+ # this assumes a contiguous netmask starting at the MSB
+ $prefix = shift;
+ $elt = shift;
+ $elt_comment = shift;
+ if ($elt =~ /^(.*)&(.*)$/) {
+ $address = $1;
+ $mask = $2;
+ ($m1,$m2,$m3,$m4) = split(/\./, $mask);
+ $mask_val = ($m1 << 24) + ($m2 << 16) +($m3 << 8) + $m4;
+ $zero_bits = 0;
+ while (($mask_val % 2) == 0) {
+ $mask_val /= 2;
+ $zero_bits++;
+ }
+ $mask_bits = 32 - $zero_bits;
+ } else {
+ $address = $elt;
+ ($a1,$a2,$a3,$a4) = split(/\./, $address);
+ if ($a1 < 128) {
+ $mask_bits = 8;
+ } elsif ($a1 < 192) {
+ $mask_bits = 16;
+ } else {
+ $mask_bits = 24;
+ }
+ }
+
+ print "$prefix$address";
+ if ($mask_bits != 32) {
+ print "/$mask_bits";
+ }
+ print ";$elt_comment\n";
+}
diff --git a/contrib/bind/bin/named/named.conf b/contrib/bind/bin/named/named.conf
new file mode 100644
index 0000000..8df9bc1
--- /dev/null
+++ b/contrib/bind/bin/named/named.conf
@@ -0,0 +1,426 @@
+/*
+ * This is a worthless, nonrunnable example of a named.conf file that has
+ * every conceivable syntax element in use. We use it to test the parser.
+ * It could also be used as a conceptual template for users of new features.
+ */
+
+/*
+ * C-style comments are OK
+ */
+
+// So are C++-style comments
+
+# So are shell-style comments
+
+// watch out for ";" -- it's important!
+
+options {
+ directory "."; // use current directory
+ named-xfer "/usr/libexec/named-xfer"; // _PATH_XFER
+ dump-file "named_dump.db"; // _PATH_DUMPFILE
+ pid-file "/var/run/named.pid"; // _PATH_PIDFILE
+ statistics-file "named.stats"; // _PATH_STATS
+ memstatistics-file "named.memstats"; // _PATH_MEMSTATS
+ check-names master fail;
+ check-names slave warn;
+ check-names response ignore;
+ host-statistics yes;
+ deallocate-on-exit no; // Painstakingly deallocate all
+ // objects when exiting instead of
+ // letting the OS clean up for us.
+ // Useful a memory leak is suspected.
+ // Final statistics are written to the
+ // memstatistics-file.
+ datasize default;
+ stacksize default;
+ coresize default;
+ files unlimited;
+ recursion yes;
+ fetch-glue yes;
+ fake-iquery no;
+ notify yes; // send NOTIFY messages. You can set
+ // notify on a zone-by-zone
+ // basis in the "zone" statement
+ // see (below)
+ auth-nxdomain yes; // always set AA on NXDOMAIN.
+ // don't set this to 'no' unless
+ // you know what you're doing -- older
+ // servers won't like it.
+ multiple-cnames no; // if yes, then a name my have more
+ // than one CNAME RR. This use
+ // is non-standard and is not
+ // recommended, but it is available
+ // because previous releases supported
+ // it and it was used by large sites
+ // for load balancing.
+ allow-query { any; };
+ allow-transfer { any; };
+ transfers-in 10; // DEFAULT_XFERS_RUNNING, cannot be
+ // set > than MAX_XFERS_RUNNING (20)
+ transfers-per-ns 2; // DEFAULT_XFERS_PER_NS
+ transfers-out 0; // not implemented
+ max-transfer-time-in 120; // MAX_XFER_TIME; the default number
+ // of minutes an inbound zone transfer
+ // may run. May be set on a per-zone
+ // basis.
+ /*
+ * The "transfer-format" option specifies the way outbound zone
+ * transfers (i.e. from us to them) are formatted. Two values are
+ * allowed:
+ *
+ * one-answer Each RR gets its own DNS message.
+ * This format is not very efficient,
+ * but is widely understood. All
+ * versions of BIND prior to 8.1 generate
+ * this format for outbound zone
+ * and require it on inbound transfers.
+ *
+ * many-answers As many RRs as will fit are put into
+ * each DNS message. This format is
+ * the most efficient, but is only known
+ * to work with BIND 8. Patches to
+ * BIND 4.9.5 named-xfer that enable it
+ * to understand 'many-answers' will be
+ * available.
+ *
+ * If you are going to be doing zone transfers to older servers, you
+ * shouldn't use 'many-answers'. 'transfer-format' may also be set
+ * on a host-by-host basis using the 'server' statement (see below).
+ */
+ transfer-format one-answer;
+ query-source address * port *;
+ /*
+ * The "forward" option is only meaningful if you've defined
+ * forwarders. "first" gives the normal BIND
+ * forwarding behavior, i.e. ask the forwarders first, and if that
+ * doesn't work then do the full lookup. You can also say
+ * "forward only;" which is what used to be specified with
+ * "slave" or "options forward-only". "only" will never attempt
+ * a full lookup; only the forwarders will be used.
+ */
+ forward first;
+ forwarders { }; // default is no forwarders
+ /*
+ * Here's a forwarders example that isn't trivial
+ */
+ /*
+ forwarders {
+ 1.2.3.4;
+ 5.6.7.8;
+ };
+ */
+ topology { localhost; localnets; }; // prefer local nameservers
+ /*
+ * Here's a more complicated topology example; it's commented out
+ * because only one topology block is allowed.
+ *
+ topology {
+ 10/8; // prefer network 10.0.0.0
+ // netmask 255.0.0.0 most
+ !1.2.3/24; // don't like 1.2.3.0 netmask
+ // 255.255.255.0 at all
+ { 1.2/16; 3/8; }; // like 1.2.0.0 netmask 255.255.0.0
+ // and 3.0.0.0 netmask 255.0.0.0
+ // equally well, but less than 10/8
+ };
+ */
+
+ listen-on port 53 { any; }; // listen for queries on port 53 on
+ // any interface on the system
+ // (i.e. all interfaces). The
+ // "port 53" is optional; if you
+ // don't specify a port, port 53
+ // is assumed.
+ /*
+ * Multiple listen-on statements are allowed. Here's a more
+ * complicated example:
+ */
+ /*
+ listen-on { 5.6.7.8; }; // listen on port 53 on interface
+ // 5.6.7.8
+ listen-on port 1234 { // listen on port 1234 on any
+ !1.2.3.4; // interface on network 1.2.3
+ 1.2.3/24; // netmask 255.255.255.0, except for
+ }; // interface 1.2.3.4.
+ */
+
+ /*
+ * Interval Timers
+ */
+ cleaning-interval 60; // clean the cache of expired RRs
+ // every 'cleaning-interval' minutes
+ interface-interval 60; // scan for new or deleted interfaces
+ // every 'interface-interval' minutes
+ statistics-interval 60; // log statistics every
+ // 'statistics-interval' minutes
+};
+
+zone "master.demo.zone" {
+ type master; // what used to be called "primary"
+ file "master.demo.zone";
+ check-names fail;
+ allow-update { none; };
+ allow-transfer { any; };
+ allow-query { any; };
+ // notify yes; // send NOTIFY messages for this
+ // zone? The global option is used
+ // if "notify" is not specified
+ // here.
+ also-notify { }; // don't notify any nameservers other
+ // than those on the NS list for this
+ // zone
+};
+
+zone "slave.demo.zone" {
+ type slave; // what used to be called "secondary"
+ file "slave.demo.zone";
+ masters {
+ 1.2.3.4; // where to zone transfer from
+ 5.6.7.8;
+ };
+ transfer-source 10.0.0.53; // fixes multihoming problems
+ check-names warn;
+ allow-update { none; };
+ allow-transfer { any; };
+ allow-query { any; };
+ max-transfer-time-in 120; // if not set, global option is used.
+ also-notify { }; // don't notify any nameservers other
+ // than those on the NS list for this
+ // zone
+};
+
+zone "stub.demo.zone" {
+ type stub; // stub zones are like slave zones,
+ // except that only the NS records
+ // are transferred.
+ file "stub.demo.zone";
+ masters {
+ 1.2.3.4; // where to zone transfer from
+ 5.6.7.8;
+ };
+ check-names warn;
+ allow-update { none; };
+ allow-transfer { any; };
+ allow-query { any; };
+ max-transfer-time-in 120; // if not set, global option is used.
+};
+
+zone "." {
+ type hint; // used to be specified w/ "cache"
+ file "cache.db";
+};
+
+acl can_query { !1.2.3/24; any; }; // network 1.2.3.0 mask 255.255.255.0
+ // is disallowed; rest are OK
+acl can_axfr { 1.2.3.4; can_query; }; // host 1.2.3.4 and any host allowed
+ // by can_query are OK
+
+zone "non-default-acl.demo.zone" {
+ type master;
+ file "foo";
+ allow-query { can_query; };
+ allow-transfer { can_axfr; };
+ allow-update {
+ 1.2.3.4;
+ 5.6.7.8;
+ };
+};
+
+key sample_key { // for TSIG; supported by parser
+ algorithm hmac-md5; // but not yet implemented in the
+ secret "your secret here"; // rest of the server
+};
+
+key key2 {
+ algorithm hmac-md5;
+ secret "ereh terces rouy";
+};
+
+server 1.2.3.4 {
+ bogus no; // if yes, we won't query or listen
+ // to this server
+ transfer-format one-answer; // set transfer format for this
+ // server (see the description of
+ // 'transfer-format' above)
+ // if not specified, the global option
+ // will be used
+ transfers 0; // not implemented
+ keys { sample_key; key2; }; // for TSIG; supported by the parser
+ // but not yet implemented in the
+ // rest of the server
+};
+
+logging {
+ /*
+ * All log output goes to one or more "channels"; you can make as
+ * many of them as you want.
+ */
+
+ channel syslog_errors { // this channel will send errors or
+ syslog user; // or worse to syslog (user facility)
+ severity error;
+ };
+
+ /*
+ * Channels have a severity level. Messages at severity levels
+ * greater than or equal to the channel's level will be logged on
+ * the channel. In order of decreasing severity, the levels are:
+ *
+ * critical a fatal error
+ * error
+ * warning
+ * notice a normal, but significant event
+ * info an informational message
+ * debug 1 the least detailed debugging info
+ * ...
+ * debug 99 the most detailed debugging info
+ */
+
+ /*
+ * Here are the built-in channels:
+ *
+ * channel default_syslog {
+ * syslog daemon;
+ * severity info;
+ * };
+ *
+ * channel default_debug {
+ * file "named.run";
+ * severity dynamic; // this means log debugging
+ * // at whatever debugging level
+ * // the server is at, and don't
+ * // log anything if not
+ * // debugging
+ * };
+ *
+ * channel null { // this is the bit bucket;
+ * file "/dev/null"; // any logging to this channel
+ * // is discarded.
+ * };
+ *
+ * channel default_stderr { // writes to stderr
+ * file "<stderr>"; // this is illustrative only;
+ * // there's currently no way
+ * // of saying "stderr" in the
+ * // configuration language.
+ * // i.e. don't try this at home.
+ * severity info;
+ * };
+ *
+ * default_stderr only works before the server daemonizes (i.e.
+ * during initial startup) or when it is running in foreground
+ * mode (-f command line option).
+ */
+
+ /*
+ * There are many categories, so you can send the logs
+ * you want to see wherever you want, without seeing logs you
+ * don't want. Right now the categories are
+ *
+ * default the catch-all. many things still
+ * aren't classified into categories, and
+ * they all end up here. also, if you
+ * don't specify any channels for a
+ * category, the default category is used
+ * instead.
+ * config high-level configuration file
+ * processing
+ * parser low-level configuration file processing
+ * queries what used to be called "query logging"
+ * lame-servers messages like "Lame server on ..."
+ * statistics
+ * panic if the server has to shut itself
+ * down due to an internal problem, it
+ * logs the problem here (as well as
+ * in the problem's native category)
+ * update dynamic update
+ * ncache negative caching
+ * xfer-in zone transfers we're receiving
+ * xfer-out zone transfers we're sending
+ * db all database operations
+ * eventlib debugging info from the event system
+ * (see below)
+ * packet dumps of packets received and sent
+ * (see below)
+ * notify the NOTIFY protocol
+ * cname messages like "XX points to a CNAME"
+ * security approved/unapproved requests
+ * os operating system problems
+ * insist consistency check failures
+ * maintenance periodic maintenance
+ * load zone loading
+ * response-checks messages like
+ * "Malformed response ..."
+ * "wrong ans. name ..."
+ * "unrelated additional info ..."
+ * "invalid RR type ..."
+ * "bad referral ..."
+ */
+
+ category parser {
+ syslog_errors; // you can log to as many channels
+ default_syslog; // as you want
+ };
+
+ category lame-servers { null; }; // don't log these at all
+
+ channel moderate_debug {
+ severity debug 3; // level 3 debugging to file
+ file "foo"; // foo
+ print-time yes; // timestamp log entries
+ print-category yes; // print category name
+ print-severity yes; // print severity level
+ /*
+ * Note that debugging must have been turned on either
+ * on the command line or with a signal to get debugging
+ * output (non-debugging output will still be written to
+ * this channel).
+ */
+ };
+
+ /*
+ * If you don't want to see "zone XXXX loaded" messages but do
+ * want to see any problems, you could do the following.
+ */
+ channel no_info_messages {
+ syslog;
+ severity notice;
+ };
+
+ category load { no_info_messages; };
+
+ /*
+ * You can also define category "default"; it gets used when no
+ * "category" statement has been given for a category.
+ */
+ category default {
+ default_syslog;
+ moderate_debug;
+ };
+
+ /*
+ * If you don't define category default yourself, the default
+ * default category will be used. It is
+ *
+ * category default { default_syslog; default_debug; };
+ */
+
+ /*
+ * If you don't define category panic yourself, the default
+ * panic category will be used. It is
+ *
+ * category panic { default_syslog; default_stderr; };
+ */
+
+ /*
+ * Two categories, 'packet' and 'eventlib', are special. Only one
+ * channel may be assigned to each of them, and it must be a
+ * file channel. If you don't define them yourself, they default to
+ *
+ * category eventlib { default_debug; };
+ *
+ * category packet { default_debug; };
+ */
+};
+
+include "filename"; // can't do within a statement
diff --git a/contrib/bind/bin/named/named.h b/contrib/bind/bin/named/named.h
new file mode 100644
index 0000000..57e787b
--- /dev/null
+++ b/contrib/bind/bin/named/named.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/*
+ * $Id: named.h,v 8.12 1997/12/04 06:52:27 halley Exp $
+ */
+
+/* Options. Leave these on. */
+#define DEBUG
+#define ADDAUTH
+#define STUBS
+#define RETURNSOA
+#define BOGUSNS
+#define TRACEROOT
+#define XFRNETS
+#define QRYLOG
+#define YPKLUDGE
+#define RENICE
+#define FORCED_RELOAD
+#define SLAVE_FORWARD
+#define BIND_UPDATE
+#define BIND_NOTIFY
+#define WANT_PIDFILE
+#define FWD_LOOP
+#define DOTTED_SERIAL
+#define SENSIBLE_DOTS
+#define ROUND_ROBIN
+#define SORT_RESPONSE
+#define DNS_SECURITY
+#undef RSAREF
+#undef BSAFE
+#define ALLOW_LONG_TXT_RDATA
+
+#if 0
+#define strdup PLEASE_USE_SAVESTR
+#define malloc PLEASE_USE_DB_MEMGET
+#define calloc PLEASE_USE_DB_MEMGET
+#define realloc PLEASE_USE_DB_MEMGET
+#define free PLEASE_USE_DB_MEMPUT
+#endif
+
+#include <isc/assertions.h>
+#include <isc/list.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/bin/named/ns_config.c b/contrib/bind/bin/named/ns_config.c
new file mode 100644
index 0000000..ff26156
--- /dev/null
+++ b/contrib/bind/bin/named/ns_config.c
@@ -0,0 +1,2366 @@
+#if !defined(lint) && !defined(SABER)
+static char rcsid[] = "$Id: ns_config.c,v 8.34 1998/03/27 00:19:47 halley Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#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 <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#ifdef HAVE_GETRUSAGE /* XXX */
+#include <sys/resource.h>
+#endif
+
+#include "named.h"
+#include "ns_parseutil.h"
+
+static int tmpnum = 0;
+static int config_initialized = 0;
+
+static int need_logging_free = 0;
+static int default_logging_installed;
+
+static int options_installed = 0;
+static int logging_installed = 0;
+static int default_options_installed;
+static int initial_configuration = 1;
+
+static char **logging_categories;
+static char *current_pid_filename = NULL;
+
+#define ZONE_SYM_TABLE_SIZE 4973
+static symbol_table zone_symbol_table;
+
+/* Zones */
+
+void
+free_zone_timerinfo(struct zoneinfo *zp) {
+ if (zp->z_timerinfo != NULL) {
+ freestr(zp->z_timerinfo->name);
+ memput(zp->z_timerinfo, sizeof *zp->z_timerinfo);
+ zp->z_timerinfo = NULL;
+ } else
+ ns_error(ns_log_config, "timer for zone '%s' had no timerinfo",
+ zp->z_origin);
+}
+
+void
+free_zone_contents(struct zoneinfo *zp, int undefine_sym) {
+ INSIST(zp != NULL);
+
+ if (undefine_sym)
+ undefine_symbol(zone_symbol_table, zp->z_origin,
+ (zp->z_type << 16) | zp->z_class);
+ if (zp->z_flags & Z_TIMER_SET) {
+ free_zone_timerinfo(zp);
+ if (evClearTimer(ev, zp->z_timer) < 0)
+ ns_error(ns_log_config,
+ "evClearTimer for zone '%s' failed in ns_init: %s",
+ zp->z_origin,
+ strerror(errno));
+ }
+ if (zp->z_origin != NULL)
+ freestr(zp->z_origin);
+ if (zp->z_source != NULL)
+ freestr(zp->z_source);
+ if (zp->z_update_acl != NULL)
+ free_ip_match_list(zp->z_update_acl);
+ if (zp->z_query_acl != NULL)
+ free_ip_match_list(zp->z_query_acl);
+ if (zp->z_transfer_acl != NULL)
+ free_ip_match_list(zp->z_transfer_acl);
+#ifdef BIND_UPDATE
+ if (zp->z_updatelog != NULL)
+ freestr(zp->z_updatelog);
+#endif /* BIND_UPDATE */
+}
+
+static void
+free_zone(struct zoneinfo *zp) {
+ INSIST(zp != NULL);
+
+ free_zone_contents(zp, 0);
+ memput(zp, sizeof *zp);
+}
+
+struct zoneinfo *
+find_zone(const char *name, int type, int class) {
+ struct zoneinfo *zp;
+ symbol_value value;
+
+ ns_debug(ns_log_config, 3, "find_zone(%s,%d,%d)", name, type, class);
+ if (lookup_symbol(zone_symbol_table, name,
+ (type<<16) | class, &value)) {
+ INSIST(value.integer >= 0 && value.integer < nzones);
+ ns_debug(ns_log_config, 3,
+ "find_zone: existing zone %d", value.integer);
+ zp = &zones[value.integer];
+ return (zp);
+ }
+ ns_debug(ns_log_config, 3, "find_zone: unknown zone");
+ return (NULL);
+}
+
+static struct zoneinfo *
+new_zone(int class, int type) {
+ struct zoneinfo *zp;
+
+ if (zones != NULL) {
+ if (type == z_hint) {
+ zp = &zones[0];
+ return (zp);
+ }
+
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++)
+ if (zp->z_type == z_nil)
+ return (zp);
+ }
+
+ /*
+ * This code assumes that nzones never decreases.
+ */
+ if (nzones % 64 == 0) {
+ ns_debug(ns_log_config, 1, "Reallocating zones structure");
+ zp = (struct zoneinfo *)
+ memget((64 + nzones) * sizeof(struct zoneinfo));
+ if (zp == NULL)
+ panic("no memory for more zones", NULL);
+ memcpy(zp, zones, nzones * sizeof(struct zoneinfo));
+ memset(&zp[nzones], 0, 64 * sizeof(struct zoneinfo));
+ memput(zones, nzones * sizeof(struct zoneinfo));
+ zones = zp;
+ }
+ zp = &zones[nzones++];
+
+ return (zp);
+}
+
+/*
+ * Check out a zoneinfo structure and return non-zero if it's OK.
+ */
+static int
+validate_zone(struct zoneinfo *zp) {
+ int warnings = 0;
+ char filename[MAXPATHLEN+1];
+
+ /* Check name */
+ if (!res_dnok(zp->z_origin)) {
+ ns_error(ns_log_config, "invalid zone name '%s'",
+ zp->z_origin);
+ return (0);
+ }
+
+ /* Check class */
+ if (zp->z_class == C_ANY || zp->z_class == C_NONE) {
+ ns_error(ns_log_config, "invalid class %d for zone '%s'",
+ zp->z_class, zp->z_origin);
+ return (0);
+ }
+
+ /* Check type. */
+ if (zp->z_type == 0) {
+ ns_error(ns_log_config, "no type specified for zone '%s'",
+ zp->z_origin);
+ return (0);
+ }
+ if (zp->z_type == z_hint && strcasecmp(zp->z_origin, "") != 0) {
+ ns_error(ns_log_config,
+ "only the root zone may be a hint zone (zone '%s')",
+ zp->z_origin);
+ return (0);
+ }
+
+ /* Check filename. */
+ if (zp->z_type == z_master && zp->z_source == NULL) {
+ ns_error(ns_log_config,
+ "'file' statement missing for master zone %s",
+ zp->z_origin);
+ return (0);
+ }
+ /*
+ * XXX We should run filename through an OS-specific
+ * validator here.
+ */
+ if (zp->z_source != NULL &&
+ strlen(zp->z_source) > MAXPATHLEN) {
+ ns_error(ns_log_config, "filename too long for zone '%s'",
+ zp->z_origin);
+ return (0);
+ }
+
+ /* Check masters */
+ if (zp->z_addrcnt != 0) {
+ if (zp->z_type != z_slave && zp->z_type != z_stub) {
+ ns_error(ns_log_config,
+ "'masters' statement present for %s zone '%s'",
+ (zp->z_type == z_master) ? "master" : "hint",
+ zp->z_origin);
+ return (0);
+ }
+ } else {
+ if (zp->z_type == z_slave || zp->z_type == z_stub) {
+ ns_error(ns_log_config,
+ "no 'masters' statement for non-master zone '%s'",
+ zp->z_origin);
+ return (0);
+ }
+ }
+
+ /* Check also-notify */
+ if (zp->z_notify_count != 0) {
+ if (zp->z_type != z_master && zp->z_type != z_slave) {
+ ns_error(ns_log_config,
+ "'also-notify' given for non-master, non-slave zone '%s'",
+ zp->z_origin);
+ return (0);
+ }
+ }
+
+#ifdef BIND_UPDATE
+ /* XXX need more checking here */
+ if (zp->z_type == z_master) {
+ if (!zp->z_soaincrintvl)
+ zp->z_soaincrintvl = SOAINCRINTVL;
+ if (!zp->z_dumpintvl)
+ zp->z_dumpintvl = DUMPINTVL;
+ if (!zp->z_deferupdcnt)
+ zp->z_deferupdcnt = DEFERUPDCNT;
+ if (!zp->z_updatelog) {
+ /* XXX OS-specific filename validation here */
+ if ((strlen(zp->z_source) + (sizeof ".log" - 1)) >
+ MAXPATHLEN) {
+ ns_error(ns_log_config,
+ "filename too long for dynamic zone '%s'",
+ zp->z_origin);
+ return (0);
+ }
+ /* this sprintf() is now safe */
+ sprintf(filename, "%s.log", zp->z_source);
+ zp->z_updatelog = savestr(filename, 1);
+ }
+ }
+#endif /* BIND_UPDATE */
+
+ return (1);
+}
+
+/*
+ * Start building a new zoneinfo structure. Returns an opaque
+ * zone_config suitable for use by the parser.
+ */
+zone_config
+begin_zone(char *name, int class) {
+ zone_config zh;
+ struct zoneinfo *zp;
+
+ /*
+ * require: name is canonical, class is a valid class
+ */
+
+ ns_debug(ns_log_config, 3, "begin_zone('%s', %d)",
+ (*name == '\0') ? "." : name, class);
+
+ zp = (struct zoneinfo *)memget(sizeof (struct zoneinfo));
+ if (zp == NULL)
+ panic("memget failed in begin_zone", NULL);
+ memset(zp, 0, sizeof (struct zoneinfo));
+ zp->z_origin = name;
+ zp->z_class = class;
+ zp->z_checknames = not_set;
+ zh.opaque = zp;
+ return (zh);
+}
+
+/*
+ * Merge new configuration information into an existing zone. The
+ * new zoneinfo must be valid.
+ */
+static void
+update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) {
+ struct stat f_time;
+ char buf[MAXPATHLEN+1];
+ int i;
+
+ INSIST(zp != NULL);
+ INSIST(new_zp != NULL);
+
+ ns_debug(ns_log_config, 1, "update_zone_info('%s', %d)",
+ (*new_zp->z_origin == '\0') ? "." : new_zp->z_origin,
+ new_zp->z_type);
+
+#ifdef BIND_UPDATE
+ /*
+ * A dynamic master zone that's becoming non-dynamic may need to be
+ * dumped before we start the update.
+ */
+ if ((zp->z_flags & Z_DYNAMIC) && !(new_zp->z_flags & Z_DYNAMIC) &&
+ ((zp->z_flags & Z_NEED_SOAUPDATE) ||
+ (zp->z_flags & Z_NEED_DUMP)))
+ (void)zonedump(zp);
+#endif
+
+ /*
+ * First do the simple stuff, making sure to free
+ * any data that was dynamically allocated.
+ */
+ if (zp->z_origin != NULL)
+ freestr(zp->z_origin);
+ zp->z_origin = new_zp->z_origin;
+ new_zp->z_origin = NULL;
+ zp->z_class = new_zp->z_class;
+ zp->z_type = new_zp->z_type;
+ zp->z_checknames = new_zp->z_checknames;
+ for (i = 0; i < new_zp->z_addrcnt; i++)
+ zp->z_addr[i] = new_zp->z_addr[i];
+ zp->z_addrcnt = new_zp->z_addrcnt;
+ if (zp->z_update_acl)
+ free_ip_match_list(zp->z_update_acl);
+ zp->z_update_acl = new_zp->z_update_acl;
+ new_zp->z_update_acl = NULL;
+ if (zp->z_query_acl)
+ free_ip_match_list(zp->z_query_acl);
+ zp->z_query_acl = new_zp->z_query_acl;
+ new_zp->z_query_acl = NULL;
+ zp->z_axfr_src = new_zp->z_axfr_src;
+ if (zp->z_transfer_acl)
+ free_ip_match_list(zp->z_transfer_acl);
+ zp->z_transfer_acl = new_zp->z_transfer_acl;
+ new_zp->z_transfer_acl = NULL;
+ zp->z_max_transfer_time_in = new_zp->z_max_transfer_time_in;
+
+ zp->z_notify = new_zp->z_notify;
+ for (i = 0; i < new_zp->z_notify_count; i++)
+ zp->z_also_notify[i] = new_zp->z_also_notify[i];
+ zp->z_notify_count = new_zp->z_notify_count;
+
+#ifdef BIND_UPDATE
+ if (new_zp->z_flags & Z_DYNAMIC)
+ zp->z_flags |= Z_DYNAMIC;
+ else
+ zp->z_flags &= ~Z_DYNAMIC;
+ zp->z_soaincrintvl = new_zp->z_soaincrintvl;
+ zp->z_dumpintvl = new_zp->z_dumpintvl;
+ zp->z_deferupdcnt = new_zp->z_deferupdcnt;
+ if (zp->z_updatelog)
+ freestr(zp->z_updatelog);
+ zp->z_updatelog = new_zp->z_updatelog;
+ new_zp->z_updatelog = NULL;
+#endif /* BIND_UPDATE */
+
+ /*
+ * now deal with files
+ */
+ switch (zp->z_type) {
+ case z_hint:
+ ns_debug(ns_log_config, 1, "source = %s", new_zp->z_source);
+ zp->z_refresh = 0; /* No dumping. */
+ /*
+ * 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(new_zp->z_source, zp->z_source) &&
+ !(zp->z_flags & Z_INCLUDE) &&
+ stat(zp->z_source, &f_time) != -1 &&
+ zp->z_ftime == f_time.st_mtime) {
+ ns_debug(ns_log_config, 1, "cache is up to date");
+ break;
+ }
+
+ /* File has changed, or hasn't been loaded yet. */
+ if (zp->z_source) {
+ freestr(zp->z_source);
+ clean_cache(fcachetab, 1);
+ }
+ zp->z_source = new_zp->z_source;
+ new_zp->z_source = NULL;
+ ns_debug(ns_log_config, 1, "reloading zone");
+ (void) db_load(zp->z_source, zp->z_origin, zp, NULL);
+ break;
+
+ case z_master:
+ ns_debug(ns_log_config, 1, "source = %s", new_zp->z_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(new_zp->z_source, zp->z_source) &&
+ !(zp->z_flags & Z_INCLUDE) &&
+ stat(zp->z_source, &f_time) != -1 &&
+ zp->z_ftime == f_time.st_mtime) {
+ ns_debug(ns_log_config, 1, "zone is up to date");
+ break; /* zone is already up to date */
+ }
+#ifdef BIND_UPDATE
+ if (zp->z_source && (zp->z_flags & Z_DYNAMIC))
+ ns_warning(ns_log_config,
+ "source file of dynamic zone '%s' has changed",
+ zp->z_origin);
+
+ primary_reload:
+#endif /* BIND_UPDATE */
+ if (zp->z_source != NULL)
+ freestr(zp->z_source);
+ zp->z_source = new_zp->z_source;
+ new_zp->z_source = NULL;
+ zp->z_flags &= ~Z_AUTH;
+ ns_stopxfrs(zp);
+ purge_zone(zp->z_origin, hashtab, zp->z_class);
+ ns_debug(ns_log_config, 1, "reloading zone");
+#ifdef BIND_UPDATE
+ if (zp->z_flags & Z_DYNAMIC) {
+ struct stat sb;
+
+ if (stat(zp->z_source, &sb) < 0)
+ ns_error(ns_log_config, "stat(%s) failed: %s",
+ zp->z_source, strerror(errno));
+ else {
+ if (sb.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))
+ ns_warning(ns_log_config,
+ "dynamic zone file '%s' is writable",
+ zp->z_source);
+ }
+ }
+#endif
+ if (!db_load(zp->z_source, zp->z_origin, zp, NULL))
+ zp->z_flags |= Z_AUTH;
+ zp->z_refresh = 0; /* no maintenance needed */
+ zp->z_time = 0;
+#ifdef BIND_UPDATE
+ zp->z_lastupdate = 0;
+ if (zp->z_flags & Z_DYNAMIC)
+ /*
+ * Note that going to primary_reload
+ * unconditionally reloads the zone.
+ */
+ if (merge_logs(zp) == 1) {
+ new_zp->z_source = savestr(zp->z_source, 1);
+ goto primary_reload;
+ }
+#endif
+ break;
+
+ case z_slave:
+#ifdef STUBS
+ case z_stub:
+#endif
+ ns_debug(ns_log_config, 1, "addrcnt = %d", zp->z_addrcnt);
+ if (!new_zp->z_source) {
+ /*
+ * We will always transfer this zone again
+ * after a reload.
+ */
+ sprintf(buf, "NsTmp%ld.%d", (long)getpid(), tmpnum++);
+ new_zp->z_source = savestr(buf, 1);
+ 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(new_zp->z_source, zp->z_source) ||
+ (stat(zp->z_source, &f_time) == -1 ||
+ (zp->z_ftime != f_time.st_mtime)))) {
+ ns_debug(ns_log_config, 1,
+ "backup file changed or missing");
+ freestr(zp->z_source);
+ zp->z_source = NULL;
+ zp->z_serial = 0; /* force xfer */
+ ns_stopxfrs(zp);
+ /*
+ * We only need to do_reload if we have
+ * successfully transferred the zone.
+ */
+ if (zp->z_flags & Z_AUTH) {
+ zp->z_flags &= ~Z_AUTH;
+ /*
+ * Purge old data and reload parent so that
+ * NS records are present during the zone
+ * transfer.
+ */
+ do_reload(zp->z_origin, zp->z_type,
+ zp->z_class);
+ }
+ }
+ if (zp->z_source == NULL) {
+ zp->z_source = new_zp->z_source;
+ new_zp->z_source = NULL;
+ }
+ if (!(zp->z_flags & Z_AUTH))
+ zoneinit(zp);
+#ifdef FORCED_RELOAD
+ else {
+ /*
+ ** Force secondary to try transfer soon
+ ** after SIGHUP.
+ */
+ if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))
+ && reloading) {
+ qserial_retrytime(zp, tt.tv_sec);
+ sched_zone_maint(zp);
+ }
+ }
+#endif /* FORCED_RELOAD */
+ break;
+ }
+ if ((zp->z_flags & Z_FOUND) && /* already found? */
+ (zp - zones) != DB_Z_CACHE) /* cache never sets Z_FOUND */
+ ns_error(ns_log_config, "Zone \"%s\" declared more than once",
+ zp->z_origin);
+ zp->z_flags |= Z_FOUND;
+ ns_debug(ns_log_config, 1,
+ "zone[%d] type %d: '%s' z_time %lu, z_refresh %u",
+ zp-zones, zp->z_type,
+ *(zp->z_origin) == '\0' ? "." : zp->z_origin,
+ (u_long)zp->z_time, zp->z_refresh);
+}
+
+/*
+ * Finish constructing a new zone. If valid, the constructed zone is
+ * merged into the zone database. The zone_config used is invalid after
+ * end_zone() completes.
+ */
+void
+end_zone(zone_config zh, int should_install) {
+ struct zoneinfo *zp, *new_zp;
+ char *zname;
+ symbol_value value;
+
+ new_zp = zh.opaque;
+ INSIST(new_zp != NULL);
+
+ zname = (new_zp->z_origin[0] == '\0') ? "." : new_zp->z_origin;
+ ns_debug(ns_log_config, 3, "end_zone('%s', %d)", zname,
+ should_install);
+
+ if (!should_install) {
+ free_zone(new_zp);
+ return;
+ }
+ if (!validate_zone(new_zp)) {
+ ns_error(ns_log_config,
+ "zone '%s' did not validate, skipping", zname);
+ free_zone(new_zp);
+ return;
+ }
+ zp = find_zone(new_zp->z_origin, new_zp->z_type, new_zp->z_class);
+ if (zp == NULL) {
+ zp = new_zone(new_zp->z_class, new_zp->z_type);
+ INSIST(zp != NULL);
+ value.integer = (zp - zones);
+ define_symbol(zone_symbol_table, savestr(new_zp->z_origin, 1),
+ (new_zp->z_type << 16) | new_zp->z_class,
+ value, SYMBOL_FREE_KEY);
+ }
+ ns_debug(ns_log_config, 5, "zone '%s', type = %d, class = %d", zname,
+ new_zp->z_type, new_zp->z_class);
+ if (new_zp->z_source != NULL)
+ ns_debug(ns_log_config, 5, " file = %s", new_zp->z_source);
+ ns_debug(ns_log_config, 5, " checknames = %d", new_zp->z_checknames);
+ if (new_zp->z_addrcnt) {
+ int i;
+
+ ns_debug(ns_log_config, 5, " masters:");
+ for (i=0; i<new_zp->z_addrcnt; i++)
+ ns_debug(ns_log_config, 5, " %s",
+ inet_ntoa(new_zp->z_addr[i]));
+ }
+
+ update_zone_info(zp, new_zp);
+ free_zone(new_zp);
+ zh.opaque = NULL;
+}
+
+int
+set_zone_type(zone_config zh, int type) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ /* Fail if type already set for this zone */
+ if (zp->z_type != 0)
+ return (0);
+ zp->z_type = type;
+ return (1);
+}
+
+int
+set_zone_filename(zone_config zh, char *filename) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ /* Fail if filename already set for this zone */
+ if (zp->z_source != NULL)
+ return (0);
+ zp->z_source = filename;
+ return (1);
+}
+
+int
+set_zone_checknames(zone_config zh, enum severity s) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ /* Fail if checknames already set for this zone */
+ if (zp->z_checknames != not_set)
+ return (0);
+ zp->z_checknames = s;
+ return (1);
+}
+
+int
+set_zone_notify(zone_config zh, int value) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ if (value)
+ zp->z_notify = znotify_yes;
+ else
+ zp->z_notify = znotify_no;
+
+ return (1);
+}
+
+int
+set_zone_update_acl(zone_config zh, ip_match_list iml) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ /* Fail if checknames already set for this zone */
+ if (zp->z_update_acl != NULL)
+ return (0);
+ zp->z_update_acl = iml;
+#ifdef BIND_UPDATE
+ if (!ip_match_is_none(iml))
+ zp->z_flags |= Z_DYNAMIC;
+ else
+ ns_debug(ns_log_config, 3, "update acl is none for '%s'",
+ zp->z_origin);
+#endif
+ return (1);
+}
+
+int
+set_zone_query_acl(zone_config zh, ip_match_list iml) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ /* Fail if checknames already set for this zone */
+ if (zp->z_query_acl != NULL)
+ return (0);
+ zp->z_query_acl = iml;
+ return (1);
+}
+
+int
+set_zone_transfer_source(zone_config zh, struct in_addr ina) {
+ struct zoneinfo *zp = zh.opaque;
+
+ zp->z_axfr_src = ina;
+ return (1);
+}
+
+int
+set_zone_transfer_acl(zone_config zh, ip_match_list iml) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ /* Fail if checknames already set for this zone */
+ if (zp->z_transfer_acl != NULL)
+ return (0);
+ zp->z_transfer_acl = iml;
+ return (1);
+}
+
+int
+set_zone_transfer_time_in(zone_config zh, long max_time) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ /* Fail if checknames already set for this zone */
+ if (zp->z_max_transfer_time_in)
+ return (0);
+ zp->z_max_transfer_time_in = max_time;
+ return (1);
+}
+
+int
+add_zone_master(zone_config zh, struct in_addr address) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ zp->z_addr[zp->z_addrcnt] = address;
+ zp->z_addrcnt++;
+ if (zp->z_addrcnt >= NSMAX) {
+ ns_warning(ns_log_config, "NSMAX reached for zone '%s'",
+ zp->z_origin);
+ zp->z_addrcnt = NSMAX - 1;
+ }
+ return (1);
+}
+
+int
+add_zone_notify(zone_config zh, struct in_addr address) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ zp->z_also_notify[zp->z_notify_count] = address;
+ zp->z_notify_count++;
+ if (zp->z_notify_count >= NSMAX) {
+ ns_warning(ns_log_config, "also-notify set full for zone '%s'",
+ zp->z_origin);
+ zp->z_notify_count = NSMAX - 1;
+ }
+ return (1);
+}
+
+/* Options */
+
+options
+new_options() {
+ options op;
+ ip_match_list iml;
+ ip_match_element ime;
+
+ op = (options)memget(sizeof (struct options));
+ if (op == NULL)
+ panic("memget failed in new_options()", NULL);
+
+ op->directory = savestr(".", 1);
+ op->pid_filename = savestr(_PATH_PIDFILE, 1);
+ op->named_xfer = savestr(_PATH_XFER, 1);
+ op->dump_filename = savestr(_PATH_DUMPFILE, 1);
+ op->stats_filename = savestr(_PATH_STATS, 1);
+ op->memstats_filename = savestr(_PATH_MEMSTATS, 1);
+ op->flags = DEFAULT_OPTION_FLAGS;
+ op->transfers_in = DEFAULT_XFERS_RUNNING;
+ op->transfers_per_ns = DEFAULT_XFERS_PER_NS;
+ op->transfers_out = 0;
+ op->transfer_format = axfr_one_answer;
+ op->max_transfer_time_in = MAX_XFER_TIME;
+ memset(&op->query_source, 0, sizeof op->query_source);
+ op->query_source.sin_family = AF_INET;
+ op->query_source.sin_addr.s_addr = htonl(INADDR_ANY);
+ op->query_source.sin_port = htons(0); /* INPORT_ANY */
+ op->query_acl = NULL;
+ op->transfer_acl = NULL;
+ /* default topology is { localhost; localnets; } */
+ iml = new_ip_match_list();
+ ime = new_ip_match_localhost();
+ add_to_ip_match_list(iml, ime);
+ ime = new_ip_match_localnets();
+ add_to_ip_match_list(iml, ime);
+ op->topology = iml;
+ op->data_size = 0UL; /* use system default */
+ op->stack_size = 0UL; /* use system default */
+ op->core_size = 0UL; /* use system default */
+ op->files = ULONG_MAX; /* unlimited */
+ op->check_names[primary_trans] = fail;
+ op->check_names[secondary_trans] = warn;
+ op->check_names[response_trans] = ignore;
+ op->listen_list = NULL;
+ op->fwdtab = NULL;
+ /* XXX init forwarding */
+ op->clean_interval = 3600;
+ op->interface_interval = 3600;
+ op->stats_interval = 3600;
+ return (op);
+}
+
+void
+free_options(options op) {
+ INSIST(op != NULL);
+
+ if (op->directory)
+ freestr(op->directory);
+ if (op->pid_filename)
+ freestr(op->pid_filename);
+ if (op->named_xfer)
+ freestr(op->named_xfer);
+ if (op->dump_filename)
+ freestr(op->dump_filename);
+ if (op->stats_filename)
+ freestr(op->stats_filename);
+ if (op->memstats_filename)
+ freestr(op->memstats_filename);
+ if (op->query_acl)
+ free_ip_match_list(op->query_acl);
+ if (op->transfer_acl)
+ free_ip_match_list(op->transfer_acl);
+ if (op->topology)
+ free_ip_match_list(op->topology);
+ if (op->listen_list)
+ free_listen_info_list(op->listen_list);
+ if (op->fwdtab)
+ free_forwarders(op->fwdtab);
+ memput(op, sizeof *op);
+}
+
+void
+set_boolean_option(options op, int bool_opt, int value) {
+ INSIST(op != NULL);
+
+ switch (bool_opt) {
+ case OPTION_NORECURSE:
+ case OPTION_NOFETCHGLUE:
+ case OPTION_FORWARD_ONLY:
+ case OPTION_FAKE_IQUERY:
+ case OPTION_NONOTIFY:
+ case OPTION_NONAUTH_NXDOMAIN:
+ case OPTION_MULTIPLE_CNAMES:
+ case OPTION_HOSTSTATS:
+ case OPTION_DEALLOC_ON_EXIT:
+ if (value)
+ op->flags |= bool_opt;
+ else
+ op->flags &= ~bool_opt;
+ break;
+ default:
+ panic("unexpected option in set_boolean_option", NULL);
+ }
+}
+
+#ifdef HAVE_GETRUSAGE
+enum limit { Datasize, Stacksize, Coresize, Files };
+
+static struct rlimit initial_data_size;
+static struct rlimit initial_stack_size;
+static struct rlimit initial_core_size;
+static struct rlimit initial_num_files;
+
+static void
+get_initial_limits() {
+# ifdef RLIMIT_DATA
+ if (getrlimit(RLIMIT_DATA, &initial_data_size) < 0)
+ ns_warning(ns_log_config, "getrlimit(DATA): %s",
+ strerror(errno));
+# endif
+# ifdef RLIMIT_STACK
+ if (getrlimit(RLIMIT_STACK, &initial_stack_size) < 0)
+ ns_warning(ns_log_config, "getrlimit(STACK): %s",
+ strerror(errno));
+# endif
+# ifdef RLIMIT_CORE
+ if (getrlimit(RLIMIT_CORE, &initial_core_size) < 0)
+ ns_warning(ns_log_config, "getrlimit(CORE): %s",
+ strerror(errno));
+# endif
+# ifdef RLIMIT_NOFILE
+ if (getrlimit(RLIMIT_NOFILE, &initial_num_files) < 0)
+ ns_warning(ns_log_config, "getrlimit(NOFILE): %s",
+ strerror(errno));
+# endif
+}
+
+static void
+ns_rlimit(enum limit limit, u_long limit_value) {
+ struct rlimit limits, old_limits;
+ int rlimit = -1;
+ char *name;
+ rlimit_type value;
+
+ if (limit_value == ULONG_MAX) {
+#ifndef RLIMIT_FILE_INFINITY
+ if (limit == Files)
+ value = MAX((rlimit_type)sysconf(_SC_OPEN_MAX),
+ initial_num_files.rlim_max);
+ else
+#endif
+ value = (rlimit_type)RLIM_INFINITY;
+ } else
+ value = (rlimit_type)limit_value;
+
+ limits.rlim_cur = limits.rlim_max = value;
+ switch (limit) {
+ case Datasize:
+#ifdef RLIMIT_DATA
+ rlimit = RLIMIT_DATA;
+#endif
+ name = "max data size";
+ if (value == 0)
+ limits = initial_data_size;
+ break;
+ case Stacksize:
+#ifdef RLIMIT_STACK
+ rlimit = RLIMIT_STACK;
+#endif
+ name = "max stack size";
+ if (value == 0)
+ limits = initial_stack_size;
+ break;
+ case Coresize:
+#ifdef RLIMIT_CORE
+ rlimit = RLIMIT_CORE;
+#endif
+ name = "max core size";
+ if (value == 0)
+ limits = initial_core_size;
+ break;
+ case Files:
+#ifdef RLIMIT_NOFILE
+ rlimit = RLIMIT_NOFILE;
+#endif
+ name = "max number of open files";
+ if (value == 0)
+ limits = initial_num_files;
+ /* XXX check < FD_SETSIZE? */
+ break;
+ default:
+ name = NULL; /* Make gcc happy. */
+ panic("impossible condition in ns_rlimit()", NULL);
+ }
+ if (rlimit == -1) {
+ ns_warning(ns_log_config,
+ "limit \"%s\" not supported on this system - ignored",
+ name);
+ return;
+ }
+ if (getrlimit(rlimit, &old_limits) < 0) {
+ ns_warning(ns_log_config, "getrlimit(%s): %s", name,
+ strerror(errno));
+ }
+ if (user_id != 0 && limits.rlim_max == RLIM_INFINITY)
+ limits.rlim_cur = limits.rlim_max = old_limits.rlim_max;
+ if (setrlimit(rlimit, &limits) < 0) {
+ ns_warning(ns_log_config, "setrlimit(%s): %s", name,
+ strerror(errno));
+ return;
+ } else {
+ if (value == 0)
+ ns_debug(ns_log_config, 3, "%s is default",
+ name);
+ else if (value == RLIM_INFINITY)
+ ns_debug(ns_log_config, 3, "%s is unlimited", name);
+ else
+#ifdef RLIMIT_LONGLONG
+ ns_debug(ns_log_config, 3, "%s is %llu", name,
+ (unsigned long long)value);
+#else
+ ns_debug(ns_log_config, 3, "%s is %lu", name, value);
+#endif
+ }
+}
+#endif /* HAVE_GETRUSAGE */
+
+listen_info_list
+new_listen_info_list() {
+ listen_info_list ll;
+
+ ll = (listen_info_list)memget(sizeof (struct listen_info_list));
+ if (ll == NULL)
+ panic("memget failed in new_listen_info_list()", NULL);
+ ll->first = NULL;
+ ll->last = NULL;
+ return (ll);
+}
+
+void
+free_listen_info_list(listen_info_list ll) {
+ listen_info li, next_li;
+
+ INSIST(ll != NULL);
+ for (li = ll->first; li != NULL; li = next_li) {
+ next_li = li->next;
+ free_ip_match_list(li->list);
+ memput(li, sizeof *li);
+ }
+ memput(ll, sizeof *ll);
+}
+
+void
+add_listen_on(options op, u_short port, ip_match_list iml) {
+ listen_info_list ll;
+ listen_info ni;
+
+ INSIST(op != NULL);
+
+ if (op->listen_list == NULL)
+ op->listen_list = new_listen_info_list();
+ ll = op->listen_list;
+ ni = (listen_info)memget(sizeof (struct listen_info));
+ if (ni == NULL)
+ panic("memget failed in add_listen_on", NULL);
+ ni->port = port;
+ ni->list = iml;
+ ni->next = NULL;
+ if (ll->last != NULL)
+ ll->last->next = ni;
+ ll->last = ni;
+ if (ll->first == NULL)
+ ll->first = ni;
+}
+
+FILE *
+write_open(char *filename) {
+ FILE *stream;
+ int fd;
+ struct stat sb;
+ int regular;
+
+ if (stat(filename, &sb) < 0) {
+ if (errno != ENOENT) {
+ ns_error(ns_log_os,
+ "write_open: stat of %s failed: %s",
+ filename, strerror(errno));
+ return (NULL);
+ }
+ regular = 1;
+ } else
+ regular = (sb.st_mode & S_IFREG);
+
+ if (!regular) {
+ ns_error(ns_log_os, "write_open: %s isn't a regular file",
+ filename);
+ return (NULL);
+ }
+
+ (void)unlink(filename);
+ fd = open(filename, O_WRONLY|O_CREAT|O_EXCL,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ if (fd < 0)
+ return (NULL);
+ stream = fdopen(fd, "w");
+ if (stream == NULL)
+ (void)close(fd);
+ return (stream);
+}
+
+void
+update_pid_file() {
+ FILE *fp;
+
+ REQUIRE(server_options != NULL);
+ REQUIRE(server_options->pid_filename != NULL);
+
+ /* XXX */ ns_debug(ns_log_default, 1, "update_pid_file()");
+ if (current_pid_filename != NULL) {
+ (void)unlink(current_pid_filename);
+ freestr(current_pid_filename);
+ current_pid_filename = NULL;
+ }
+ current_pid_filename = savestr(server_options->pid_filename, 0);
+ if (current_pid_filename == NULL) {
+ ns_error(ns_log_config,
+ "savestr() failed in update_pid_file()");
+ return;
+ }
+ fp = write_open(current_pid_filename);
+ if (fp != NULL) {
+ (void) fprintf(fp, "%ld\n", (long)getpid());
+ (void) fclose(fp);
+ } else
+ ns_error(ns_log_config, "couldn't create pid file '%s'",
+ server_options->pid_filename);
+}
+
+/*
+ * XXX This function will eventually be public and will be relocated to
+ * the UNIX OS support library.
+ */
+
+static int
+os_change_directory(const char *name) {
+ struct stat sb;
+
+ if (name == NULL ||
+ *name == '\0') {
+ errno = EINVAL;
+ return (0);
+ }
+
+ if (chdir(name) < 0)
+ return (0);
+
+ if (stat(name, &sb) < 0) {
+ ns_error(ns_log_os, "stat(%s) failed: %s", name,
+ strerror(errno));
+ return (1);
+ }
+ if (sb.st_mode & S_IWOTH)
+ ns_warning(ns_log_os, "directory %s is world-writable", name);
+
+ return (1);
+}
+
+static void
+periodic_getnetconf(evContext ctx, void *uap, struct timespec due,
+ struct timespec inter)
+{
+ getnetconf(1);
+}
+
+static void
+set_interval_timer(int which_timer, int interval) {
+ evTimerID *tid = NULL;
+ evTimerFunc func = NULL;
+
+ switch (which_timer) {
+ case CLEAN_TIMER:
+ tid = &clean_timer;
+ func = ns_cleancache;
+ break;
+ case INTERFACE_TIMER:
+ tid = &interface_timer;
+ func = periodic_getnetconf;
+ break;
+ case STATS_TIMER:
+ tid = &stats_timer;
+ func = ns_logstats;
+ break;
+ default:
+ ns_panic(ns_log_config, 1,
+ "set_interval_timer: unknown timer %d", which_timer);
+ }
+ if ((active_timers & which_timer) != 0) {
+ if (interval > 0) {
+ if (evResetTimer(ev, *tid, func, NULL,
+ evAddTime(evNowTime(),
+ evConsTime(interval, 0)),
+ evConsTime(interval, 0)) < 0)
+ ns_error(ns_log_config,
+ "evResetTimer %d interval %d failed: %s",
+ which_timer, interval,
+ strerror(errno));
+ } else {
+ if (evClearTimer(ev, *tid) < 0)
+ ns_error(ns_log_config,
+ "evClearTimer %d failed: %s",
+ which_timer, strerror(errno));
+ else
+ active_timers &= ~which_timer;
+ }
+ } else if (interval > 0) {
+ if (evSetTimer(ev, func, NULL,
+ evAddTime(evNowTime(),
+ evConsTime(interval, 0)),
+ evConsTime(interval, 0), tid) < 0)
+ ns_error(ns_log_config,
+ "evSetTimer %d interval %d failed: %s",
+ which_timer, interval, strerror(errno));
+ else
+ active_timers |= which_timer;
+ }
+}
+
+/*
+ * Set all named global options based on the global options structure
+ * generated by the parser.
+ */
+void
+set_options(options op, int is_default) {
+ listen_info li;
+ INSIST(op != NULL);
+
+ if (op->listen_list == NULL) {
+ ip_match_list iml;
+ ip_match_element ime;
+ struct in_addr address;
+
+ op->listen_list = new_listen_info_list();
+
+ address.s_addr = htonl(INADDR_ANY);
+ iml = new_ip_match_list();
+ ime = new_ip_match_pattern(address, 0);
+ add_to_ip_match_list(iml, ime);
+ add_listen_on(op, htons(NS_DEFAULTPORT), iml);
+ }
+ if (server_options != NULL)
+ free_options(server_options);
+ server_options = op;
+
+ /* XXX should validate pid filename */
+ INSIST(op->pid_filename != NULL);
+
+ if (op->directory && !os_change_directory(op->directory))
+ ns_panic(ns_log_config, 0, "can't change directory to %s: %s",
+ op->directory, strerror(errno));
+
+ /* XXX currently a value of 0 means "use default"; it would be
+ better if the options block had a "attributes updated" vector
+ (like the way X deals with GC updates) */
+
+ if (!op->transfers_in)
+ op->transfers_in = DEFAULT_XFERS_RUNNING;
+ else if (op->transfers_in > MAX_XFERS_RUNNING) {
+ ns_warning(ns_log_config,
+ "the maximum number of concurrent inbound transfers is %d",
+ MAX_XFERS_RUNNING);
+ op->transfers_in = MAX_XFERS_RUNNING;
+ }
+
+ if (!op->transfers_per_ns)
+ op->transfers_per_ns = DEFAULT_XFERS_PER_NS;
+
+ if (!op->max_transfer_time_in)
+ op->max_transfer_time_in = MAX_XFER_TIME;
+
+ /* XXX currently transfers_out is not used */
+
+ /*
+ * Limits
+ */
+
+#ifdef HAVE_GETRUSAGE
+ ns_rlimit(Datasize, op->data_size);
+ ns_rlimit(Stacksize, op->stack_size);
+ ns_rlimit(Coresize, op->core_size);
+ ns_rlimit(Files, op->files);
+#else
+ ns_info(ns_log_config, "cannot set resource limits on this system");
+#endif
+
+
+ /*
+ * Timers
+ */
+ set_interval_timer(CLEAN_TIMER, server_options->clean_interval);
+ set_interval_timer(INTERFACE_TIMER,
+ server_options->interface_interval);
+ set_interval_timer(STATS_TIMER, server_options->stats_interval);
+
+ options_installed = 1;
+ default_options_installed = is_default;
+}
+
+void
+use_default_options() {
+ set_options(new_options(), 1);
+}
+
+/*
+ * IP Matching Lists
+ */
+
+ip_match_list
+new_ip_match_list() {
+ ip_match_list iml;
+
+ iml = (ip_match_list)memget(sizeof (struct ip_match_list));
+ if (iml == NULL)
+ panic("memget failed in new_ip_match_list", NULL);
+ iml->first = NULL;
+ iml->last = NULL;
+ return (iml);
+}
+
+void
+free_ip_match_list(ip_match_list iml) {
+ ip_match_element ime, next_element;
+
+ for (ime = iml->first; ime != NULL; ime = next_element) {
+ next_element = ime->next;
+ memput(ime, sizeof *ime);
+ }
+ memput(iml, sizeof *iml);
+}
+
+ip_match_element
+new_ip_match_pattern(struct in_addr address, u_int mask_bits) {
+ ip_match_element ime;
+ u_int32_t mask;
+
+ ime = (ip_match_element)memget(sizeof (struct ip_match_element));
+ if (ime == NULL)
+ panic("memget failed in new_ip_match_pattern", NULL);
+ ime->type = ip_match_pattern;
+ ime->flags = 0;
+ ime->u.direct.address = address;
+ if (mask_bits == 0)
+ /* can't shift >= the size of a type in bits, so
+ we deal with an empty mask here */
+ mask = 0;
+ else {
+ /* set the 'mask_bits' most significant bits */
+ mask = 0xffffffffU;
+ mask >>= (32 - mask_bits);
+ mask <<= (32 - mask_bits);
+ }
+ mask = ntohl(mask);
+ ime->u.direct.mask.s_addr = mask;
+ ime->next = NULL;
+ if (!ina_onnet(ime->u.direct.address, ime->u.direct.address,
+ ime->u.direct.mask)) {
+ memput(ime, sizeof *ime);
+ ime = NULL;
+ }
+ return (ime);
+}
+
+ip_match_element
+new_ip_match_mask(struct in_addr address, struct in_addr mask) {
+ ip_match_element ime;
+
+ ime = (ip_match_element)memget(sizeof (struct ip_match_element));
+ if (ime == NULL)
+ panic("memget failed in new_ip_match_pattern", NULL);
+ ime->type = ip_match_pattern;
+ ime->flags = 0;
+ ime->u.direct.address = address;
+ ime->u.direct.mask = mask;
+ ime->next = NULL;
+ if (!ina_onnet(ime->u.direct.address, ime->u.direct.address,
+ ime->u.direct.mask)) {
+ memput(ime, sizeof *ime);
+ ime = NULL;
+ }
+ return (ime);
+}
+
+ip_match_element
+new_ip_match_indirect(ip_match_list iml) {
+ ip_match_element ime;
+
+ INSIST(iml != NULL);
+
+ ime = (ip_match_element)memget(sizeof (struct ip_match_element));
+ if (ime == NULL)
+ panic("memget failed in new_ip_match_indirect", NULL);
+ ime->type = ip_match_indirect;
+ ime->flags = 0;
+ ime->u.indirect.list = iml;
+ ime->next = NULL;
+ return (ime);
+}
+
+ip_match_element
+new_ip_match_localhost() {
+ ip_match_element ime;
+
+ ime = (ip_match_element)memget(sizeof (struct ip_match_element));
+ if (ime == NULL)
+ panic("memget failed in new_ip_match_localhost", NULL);
+ ime->type = ip_match_localhost;
+ ime->flags = 0;
+ ime->u.indirect.list = NULL;
+ ime->next = NULL;
+ return (ime);
+}
+
+ip_match_element
+new_ip_match_localnets() {
+ ip_match_element ime;
+
+ ime = (ip_match_element)memget(sizeof (struct ip_match_element));
+ if (ime == NULL)
+ panic("memget failed in new_ip_match_localnets", NULL);
+ ime->type = ip_match_localnets;
+ ime->flags = 0;
+ ime->u.indirect.list = NULL;
+ ime->next = NULL;
+ return (ime);
+}
+
+void
+ip_match_negate(ip_match_element ime) {
+ if (ime->flags & IP_MATCH_NEGATE)
+ ime->flags &= ~IP_MATCH_NEGATE;
+ else
+ ime->flags |= IP_MATCH_NEGATE;
+}
+
+void
+add_to_ip_match_list(ip_match_list iml, ip_match_element ime) {
+ INSIST(iml != NULL);
+ INSIST(ime != NULL);
+
+ if (iml->last != NULL)
+ iml->last->next = ime;
+ ime->next = NULL;
+ iml->last = ime;
+ if (iml->first == NULL)
+ iml->first = ime;
+}
+
+void
+dprint_ip_match_list(int category, ip_match_list iml, int indent,
+ char *allow, char *deny) {
+ ip_match_element ime;
+ char spaces[40+1];
+ char addr_text[sizeof "255.255.255.255"];
+ char mask_text[sizeof "255.255.255.255"];
+ char *tmp;
+
+ INSIST(iml != NULL);
+
+ if (indent > 40)
+ indent = 40;
+ if (indent)
+ memset(spaces, ' ', indent);
+ spaces[indent] = '\0';
+
+ for (ime = iml->first; ime != NULL; ime = ime->next) {
+ switch (ime->type) {
+ case ip_match_pattern:
+ memset(addr_text, 0, sizeof addr_text);
+ strncpy(addr_text, inet_ntoa(ime->u.direct.address),
+ ((sizeof addr_text) - 1));
+ memset(mask_text, 0, sizeof mask_text);
+ strncpy(mask_text, inet_ntoa(ime->u.direct.mask),
+ ((sizeof mask_text) - 1));
+ ns_debug(category, 7, "%s%saddr: %s, mask: %s",
+ spaces,
+ (ime->flags & IP_MATCH_NEGATE) ? deny : allow,
+ addr_text, mask_text);
+ break;
+ case ip_match_localhost:
+ ns_debug(category, 7, "%s%slocalhost", spaces,
+ (ime->flags & IP_MATCH_NEGATE) ?
+ deny : allow);
+ break;
+ case ip_match_localnets:
+ ns_debug(category, 7, "%s%slocalnets", spaces,
+ (ime->flags & IP_MATCH_NEGATE) ?
+ deny : allow);
+ break;
+ case ip_match_indirect:
+ ns_debug(category, 7, "%s%sindirect list %p", spaces,
+ (ime->flags & IP_MATCH_NEGATE) ? deny : allow,
+ ime->u.indirect.list);
+ if (ime->u.indirect.list != NULL)
+ dprint_ip_match_list(category,
+ ime->u.indirect.list,
+ indent+2, allow, deny);
+ break;
+ default:
+ panic("unexpected ime type in dprint_ip_match_list()",
+ NULL);
+ }
+ }
+}
+
+int
+ip_match_address(ip_match_list iml, struct in_addr address) {
+ ip_match_element ime;
+ int ret;
+ int indirect;
+
+ INSIST(iml != NULL);
+ for (ime = iml->first; ime != NULL; ime = ime->next) {
+ switch (ime->type) {
+ case ip_match_pattern:
+ indirect = 0;
+ break;
+ case ip_match_indirect:
+ indirect = 1;
+ break;
+ case ip_match_localhost:
+ ime->u.indirect.list = local_addresses;
+ indirect = 1;
+ break;
+ case ip_match_localnets:
+ ime->u.indirect.list = local_networks;
+ indirect = 1;
+ break;
+ default:
+ indirect = 0; /* Make gcc happy. */
+ panic("unexpected ime type in ip_match_address()",
+ NULL);
+ }
+ if (indirect) {
+ ret = ip_match_address(ime->u.indirect.list, address);
+ if (ret >= 0) {
+ if (ime->flags & IP_MATCH_NEGATE)
+ ret = (ret) ? 0 : 1;
+ return (ret);
+ }
+ } else {
+ if (ina_onnet(address, ime->u.direct.address,
+ ime->u.direct.mask)) {
+ if (ime->flags & IP_MATCH_NEGATE)
+ return (0);
+ else
+ return (1);
+ }
+ }
+ }
+ return (-1);
+}
+
+int
+ip_address_allowed(ip_match_list iml, struct in_addr address) {
+ int ret;
+
+ if (iml == NULL)
+ return (0);
+ ret = ip_match_address(iml, address);
+ if (ret < 0)
+ ret = 0;
+ return (ret);
+}
+
+int
+ip_match_network(ip_match_list iml, struct in_addr address,
+ struct in_addr mask) {
+ ip_match_element ime;
+ int ret;
+ int indirect;
+
+ INSIST(iml != NULL);
+ for (ime = iml->first; ime != NULL; ime = ime->next) {
+ switch (ime->type) {
+ case ip_match_pattern:
+ indirect = 0;
+ break;
+ case ip_match_indirect:
+ indirect = 1;
+ break;
+ case ip_match_localhost:
+ ime->u.indirect.list = local_addresses;
+ indirect = 1;
+ break;
+ case ip_match_localnets:
+ ime->u.indirect.list = local_networks;
+ indirect = 1;
+ break;
+ default:
+ indirect = 0; /* Make gcc happy. */
+ panic("unexpected ime type in ip_match_network()",
+ NULL);
+ }
+ if (indirect) {
+ ret = ip_match_network(ime->u.indirect.list,
+ address, mask);
+ if (ret >= 0) {
+ if (ime->flags & IP_MATCH_NEGATE)
+ ret = (ret) ? 0 : 1;
+ return (ret);
+ }
+ } else {
+ if (address.s_addr == ime->u.direct.address.s_addr &&
+ mask.s_addr == ime->u.direct.mask.s_addr) {
+ if (ime->flags & IP_MATCH_NEGATE)
+ return (0);
+ else
+ return (1);
+ }
+ }
+ }
+ return (-1);
+}
+
+int
+distance_of_address(ip_match_list iml, struct in_addr address) {
+ ip_match_element ime;
+ int ret;
+ int indirect;
+ int distance;
+
+ INSIST(iml != NULL);
+ for (distance = 1, ime = iml->first;
+ ime != NULL; ime = ime->next, distance++) {
+ switch (ime->type) {
+ case ip_match_pattern:
+ indirect = 0;
+ break;
+ case ip_match_indirect:
+ indirect = 1;
+ break;
+ case ip_match_localhost:
+ ime->u.indirect.list = local_addresses;
+ indirect = 1;
+ break;
+ case ip_match_localnets:
+ ime->u.indirect.list = local_networks;
+ indirect = 1;
+ break;
+ default:
+ indirect = 0; /* Make gcc happy. */
+ panic("unexpected ime type in distance_of_address()",
+ NULL);
+ }
+ if (indirect) {
+ ret = ip_match_address(ime->u.indirect.list, address);
+ if (ret >= 0) {
+ if (ime->flags & IP_MATCH_NEGATE)
+ ret = (ret) ? 0 : 1;
+ if (distance > MAX_TOPOLOGY_DISTANCE)
+ distance = MAX_TOPOLOGY_DISTANCE;
+ if (ret)
+ return (distance);
+ else
+ return (MAX_TOPOLOGY_DISTANCE);
+ }
+ } else {
+ if (ina_onnet(address, ime->u.direct.address,
+ ime->u.direct.mask)) {
+ if (distance > MAX_TOPOLOGY_DISTANCE)
+ distance = MAX_TOPOLOGY_DISTANCE;
+ if (ime->flags & IP_MATCH_NEGATE)
+ return (MAX_TOPOLOGY_DISTANCE);
+ else
+ return (distance);
+ }
+ }
+ }
+ return (UNKNOWN_TOPOLOGY_DISTANCE);
+}
+
+int
+ip_match_is_none(ip_match_list iml) {
+ ip_match_element ime;
+
+ if (iml == NULL)
+ return (1);
+ ime = iml->first;
+ if (ime->type == ip_match_indirect) {
+ if (ime->flags & IP_MATCH_NEGATE)
+ return (0);
+ iml = ime->u.indirect.list;
+ if (iml == NULL)
+ return (0);
+ ime = iml->first;
+ }
+ if (ime->type == ip_match_pattern) {
+ if ((ime->flags & IP_MATCH_NEGATE) &&
+ ime->u.direct.address.s_addr == 0 &&
+ ime->u.direct.mask.s_addr == 0)
+ return (1);
+ }
+ return (0);
+}
+
+
+/*
+ * Forwarder glue
+ *
+ * XXX This will go away when the rest of bind understands
+ * forward zones.
+ */
+
+void
+add_forwarder(options op, struct in_addr address) {
+ struct fwdinfo *fip = NULL, *ftp = NULL;
+
+#ifdef SLAVE_FORWARD
+ int forward_count = 0;
+#endif
+
+ INSIST(op != NULL);
+
+ /* On multiple forwarder lines, move to end of the list. */
+#ifdef SLAVE_FORWARD
+ if (op->fwdtab != NULL) {
+ forward_count++;
+ for (fip = op->fwdtab; fip->next != NULL; fip = fip->next)
+ forward_count++;
+ }
+#else
+ if (op->fwdtab != NULL) {
+ for (fip = op->fwdtab; fip->next != NULL; fip = fip->next) {
+ ;
+ }
+ }
+#endif /* SLAVE_FORWARD */
+
+ ftp = (struct fwdinfo *)memget(sizeof(struct fwdinfo));
+ if (!ftp)
+ panic("memget failed in add_forwarder", NULL);
+ ftp->fwdaddr.sin_family = AF_INET;
+ ftp->fwdaddr.sin_addr = address;
+ ftp->fwdaddr.sin_port = ns_port;
+#ifdef FWD_LOOP
+ if (aIsUs(ftp->fwdaddr.sin_addr)) {
+ ns_error(ns_log_config, "forwarder '%s' ignored, my address",
+ inet_ntoa(address));
+ memput(ftp, sizeof *ftp);
+ return;
+ }
+#endif /* FWD_LOOP */
+ ns_debug(ns_log_config, 2, "added forwarder %s", inet_ntoa(address));
+ ftp->next = NULL;
+ if (op->fwdtab == NULL)
+ op->fwdtab = ftp; /* First time only */
+ else
+ fip->next = ftp;
+#ifdef SLAVE_FORWARD
+ forward_count++;
+
+ /*
+ ** 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
+}
+
+void
+free_forwarders(struct fwdinfo *fwdtab) {
+ struct fwdinfo *ftp, *fnext;
+
+ for (ftp = fwdtab; ftp != NULL; ftp = fnext) {
+ fnext = ftp->next;
+ memput(ftp, sizeof *ftp);
+ }
+}
+
+/*
+ * Servers
+ */
+
+
+static server_info
+new_server(struct in_addr address) {
+ server_info si;
+
+ si = (server_info)memget(sizeof (struct server_info));
+ if (si == NULL)
+ panic("memget failed in new_server()", NULL);
+ si->address = address;
+ si->flags = 0U;
+ si->transfers = 0;
+ si->transfer_format = axfr_use_default;
+ si->key_list = NULL;
+ si->next = NULL;
+ return si;
+}
+
+static void
+free_server(server_info si) {
+ /* Don't free key; it'll be done when the auth table is freed. */
+ memput(si, sizeof *si);
+}
+
+server_info
+find_server(struct in_addr address) {
+ server_info si;
+
+ for (si = nameserver_info; si != NULL; si = si->next)
+ if (si->address.s_addr == address.s_addr)
+ break;
+ return (si);
+}
+
+static void
+add_server(server_info si) {
+ ip_match_element ime;
+
+ si->next = nameserver_info;
+ nameserver_info = si;
+
+ /*
+ * To ease transition, we'll add bogus nameservers to an
+ * ip matching list. This will probably be redone when the
+ * merging of nameserver data structures occurs.
+ */
+ if (si->flags & SERVER_INFO_BOGUS) {
+ ime = new_ip_match_pattern(si->address, 32);
+ INSIST(ime != NULL);
+ add_to_ip_match_list(bogus_nameservers, ime);
+ }
+ ns_debug(ns_log_config, 3, "server %s: flags %08x transfers %d",
+ inet_ntoa(si->address), si->flags, si->transfers);
+ if (si->key_list != NULL)
+ dprint_key_info_list(si->key_list);
+}
+
+static void
+free_nameserver_info() {
+ server_info si_next, si;
+
+ for (si = nameserver_info; si != NULL; si = si_next) {
+ si_next = si->next;
+ free_server(si);
+ }
+ nameserver_info = NULL;
+ if (bogus_nameservers != NULL) {
+ free_ip_match_list(bogus_nameservers);
+ bogus_nameservers = NULL;
+ }
+}
+
+server_config
+begin_server(struct in_addr address) {
+ server_config sc;
+
+ sc.opaque = new_server(address);
+ return (sc);
+}
+
+void
+end_server(server_config sc, int should_install) {
+ server_info si;
+
+ si = sc.opaque;
+
+ INSIST(si != NULL);
+
+ if (should_install)
+ add_server(si);
+ else
+ free_server(si);
+ sc.opaque = NULL;
+}
+
+void
+set_server_option(server_config sc, int bool_opt, int value) {
+ server_info si;
+
+ si = sc.opaque;
+
+ INSIST(si != NULL);
+
+ switch (bool_opt) {
+ case SERVER_INFO_BOGUS:
+ if (value)
+ si->flags |= bool_opt;
+ else
+ si->flags &= ~bool_opt;
+ break;
+ default:
+ panic("unexpected option in set_server_option", NULL);
+ }
+}
+
+void
+set_server_transfers(server_config sc, int transfers) {
+ server_info si;
+
+ si = sc.opaque;
+
+ INSIST(si != NULL);
+
+ if (transfers < 0)
+ transfers = 0;
+ si->transfers = transfers;
+}
+
+void
+set_server_transfer_format(server_config sc,
+ enum axfr_format transfer_format) {
+ server_info si;
+
+ si = sc.opaque;
+
+ INSIST(si != NULL);
+
+ si->transfer_format = transfer_format;
+}
+
+void
+add_server_key_info(server_config sc, key_info ki) {
+ server_info si;
+
+ si = sc.opaque;
+
+ INSIST(si != NULL);
+
+ if (si->key_list == NULL)
+ si->key_list = new_key_info_list();
+ add_to_key_info_list(si->key_list, ki);
+}
+
+/*
+ * Keys
+ */
+
+key_info
+new_key_info(char *name, char *algorithm, char *secret) {
+ key_info ki;
+
+ INSIST(name != NULL);
+ INSIST(algorithm != NULL);
+ INSIST(secret != NULL);
+ ki = (key_info)memget(sizeof (struct key_info));
+ if (ki == NULL)
+ panic("memget failed in new_key_info", NULL);
+ ki->name = name;
+ ki->algorithm = algorithm;
+ ki->secret = secret;
+ return (ki);
+}
+
+void
+free_key_info(key_info ki) {
+ INSIST(ki != NULL);
+ freestr(ki->name);
+ freestr(ki->algorithm);
+ freestr(ki->secret);
+ memput(ki, sizeof *ki);
+}
+
+void
+dprint_key_info(key_info ki) {
+ INSIST(ki != NULL);
+ ns_debug(ns_log_config, 7, "key %s", ki->name);
+ ns_debug(ns_log_config, 7, " algorithm %s", ki->algorithm);
+ ns_debug(ns_log_config, 7, " secret %s", ki->secret);
+}
+
+key_info_list
+new_key_info_list() {
+ key_info_list kil;
+
+ kil = (key_info_list)memget(sizeof (struct key_info_list));
+ if (kil == NULL)
+ panic("memget failed in new_key_info_list()", NULL);
+ kil->first = NULL;
+ kil->last = NULL;
+ return (kil);
+}
+
+void
+free_key_info_list(key_info_list kil) {
+ key_list_element kle, kle_next;
+
+ INSIST(kil != NULL);
+ for (kle = kil->first; kle != NULL; kle = kle_next) {
+ kle_next = kle->next;
+ /* note we do NOT free kle->info */
+ memput(kle, sizeof *kle);
+ }
+ memput(kil, sizeof *kil);
+}
+
+void
+add_to_key_info_list(key_info_list kil, key_info ki) {
+ key_list_element kle;
+
+ INSIST(kil != NULL);
+ INSIST(ki != NULL);
+
+ kle = (key_list_element)memget(sizeof (struct key_list_element));
+ if (kle == NULL)
+ panic("memget failed in add_to_key_info_list()", NULL);
+ kle->info = ki;
+ if (kil->last != NULL)
+ kil->last->next = kle;
+ kle->next = NULL;
+ kil->last = kle;
+ if (kil->first == NULL)
+ kil->first = kle;
+}
+
+void
+dprint_key_info_list(key_info_list kil) {
+ key_list_element kle;
+
+ INSIST(kil != NULL);
+
+ for (kle = kil->first; kle != NULL; kle = kle->next)
+ dprint_key_info(kle->info);
+}
+
+/*
+ * Logging.
+ */
+
+log_config
+begin_logging() {
+ log_config log_cfg;
+ log_context lc;
+
+ log_cfg = (log_config)memget(sizeof (struct log_config));
+ if (log_cfg == NULL)
+ ns_panic(ns_log_config, 0,
+ "memget failed creating log_config");
+ if (log_new_context(ns_log_max_category, logging_categories, &lc) < 0)
+ ns_panic(ns_log_config, 0,
+ "log_new_context() failed: %s", strerror(errno));
+ log_cfg->log_ctx = lc;
+ log_cfg->eventlib_channel = NULL;
+ log_cfg->packet_channel = NULL;
+ log_cfg->default_debug_active = 0;
+ return (log_cfg);
+}
+
+void
+add_log_channel(log_config log_cfg, int category, log_channel chan) {
+ log_channel_type type;
+
+ INSIST(log_cfg != NULL);
+
+ type = log_get_channel_type(chan);
+ if (category == ns_log_eventlib) {
+ if (type != log_file && type != log_null) {
+ ns_error(ns_log_config,
+ "must specify a file or null channel for the eventlib category");
+ return;
+ }
+ if (log_cfg->eventlib_channel != NULL) {
+ ns_error(ns_log_config,
+ "only one channel allowed for the eventlib category");
+ return;
+ }
+ log_cfg->eventlib_channel = chan;
+ }
+ if (category == ns_log_packet) {
+ if (type != log_file && type != log_null) {
+ ns_error(ns_log_config,
+ "must specify a file or null channel for the packet category");
+ return;
+ }
+ if (log_cfg->packet_channel != NULL) {
+ ns_error(ns_log_config,
+ "only one channel allowed for the packet category");
+ return;
+ }
+ log_cfg->packet_channel = chan;
+ }
+
+ if (log_add_channel(log_cfg->log_ctx, category, chan) < 0) {
+ ns_error(ns_log_config, "log_add_channel() failed");
+ return;
+ }
+
+ if (chan == debug_channel)
+ log_cfg->default_debug_active = 1;
+}
+
+void
+open_special_channels() {
+ int using_null = 0;
+
+ if (log_open_stream(eventlib_channel) == NULL) {
+ eventlib_channel = null_channel;
+ using_null = 1;
+ }
+ if (log_open_stream(packet_channel) == NULL) {
+ packet_channel = null_channel;
+ using_null = 1;
+ }
+
+ if (using_null &&
+ log_open_stream(null_channel) == NULL)
+ ns_panic(ns_log_config, 1, "couldn't open null channel");
+}
+
+void
+set_logging(log_config log_cfg, int is_default) {
+ log_context lc;
+ int skip_debug = 0;
+
+ INSIST(log_cfg != NULL);
+ lc = log_cfg->log_ctx;
+
+ /*
+ * Add the default category if it's not in the context already.
+ */
+ if (!log_category_is_active(lc, ns_log_default)) {
+ add_log_channel(log_cfg, ns_log_default, debug_channel);
+ add_log_channel(log_cfg, ns_log_default, syslog_channel);
+ }
+
+ /*
+ * Add the panic category if it's not in the context already.
+ */
+ if (!log_category_is_active(lc, ns_log_panic)) {
+ add_log_channel(log_cfg, ns_log_panic, stderr_channel);
+ add_log_channel(log_cfg, ns_log_panic, syslog_channel);
+ }
+
+ /*
+ * Add the eventlib category if it's not in the context already.
+ */
+ if (!log_category_is_active(lc, ns_log_eventlib))
+ add_log_channel(log_cfg, ns_log_eventlib, debug_channel);
+
+ /*
+ * Add the packet category if it's not in the context already.
+ */
+ if (!log_category_is_active(lc, ns_log_packet))
+ add_log_channel(log_cfg, ns_log_packet, debug_channel);
+
+#ifdef DEBUG
+ /*
+ * Preserve debugging state.
+ */
+ log_option(lc, LOG_OPTION_DEBUG, debug);
+ log_option(lc, LOG_OPTION_LEVEL, debug);
+#endif
+
+ /*
+ * Special case for query-log, so we can co-exist with the command
+ * line option and SIGWINCH.
+ */
+ if (log_category_is_active(lc, ns_log_queries))
+ qrylog = 1;
+
+ /*
+ * Cleanup the old context.
+ */
+ if (need_logging_free)
+ log_free_context(log_ctx);
+
+ /*
+ * The default file channels will never have their reference counts
+ * drop to zero, and so they will not be closed by the logging system
+ * when log_free_context() is called. We don't want to keep files
+ * open unnecessarily, and we want them to behave like user-created
+ * channels, so we close them here.
+ */
+ if (log_get_stream(debug_channel) != stderr)
+ (void)log_close_stream(debug_channel);
+ (void)log_close_stream(null_channel);
+
+ /*
+ * Install the new context.
+ */
+ log_ctx = lc;
+ eventlib_channel = log_cfg->eventlib_channel;
+ packet_channel = log_cfg->packet_channel;
+
+#ifdef DEBUG
+ if (debug) {
+ open_special_channels();
+ evSetDebug(ev, debug, log_get_stream(eventlib_channel));
+ }
+#endif
+
+ log_ctx_valid = 1;
+ need_logging_free = 1;
+ logging_installed = 1;
+ default_logging_installed = is_default;
+}
+
+void
+end_logging(log_config log_cfg, int should_install) {
+ if (should_install)
+ set_logging(log_cfg, 0);
+ else
+ log_free_context(log_cfg->log_ctx);
+ memput(log_cfg, sizeof (struct log_config));
+}
+
+void
+use_default_logging() {
+ log_config log_cfg;
+
+ log_cfg = begin_logging();
+ set_logging(log_cfg, 1);
+ memput(log_cfg, sizeof (struct log_config));
+}
+
+static void
+init_default_log_channels() {
+ FILE *null_stream;
+ u_int flags;
+ char *name;
+ FILE *stream;
+
+ syslog_channel = log_new_syslog_channel(0, log_info, LOG_DAEMON);
+ if (syslog_channel == NULL || log_inc_references(syslog_channel) < 0)
+ ns_panic(ns_log_config, 0, "couldn't create syslog_channel");
+
+ flags = LOG_USE_CONTEXT_LEVEL|LOG_REQUIRE_DEBUG;
+ if (foreground) {
+ name = NULL;
+ stream = stderr;
+ } else {
+ name = _PATH_DEBUG;
+ stream = NULL;
+ }
+ debug_channel = log_new_file_channel(flags, log_info, name, stream,
+ 0, ULONG_MAX);
+ if (debug_channel == NULL || log_inc_references(debug_channel) < 0)
+ ns_panic(ns_log_config, 0, "couldn't create debug_channel");
+
+ stderr_channel = log_new_file_channel(0, log_info, NULL, stderr,
+ 0, ULONG_MAX);
+ if (stderr_channel == NULL || log_inc_references(stderr_channel) < 0)
+ ns_panic(ns_log_config, 0, "couldn't create stderr_channel");
+
+ null_channel = log_new_file_channel(LOG_CHANNEL_OFF, log_info,
+ _PATH_DEVNULL, NULL, 0, ULONG_MAX);
+ if (null_channel == NULL || log_inc_references(null_channel) < 0)
+ ns_panic(ns_log_config, 0, "couldn't create null_channel");
+}
+
+static void
+shutdown_default_log_channels() {
+ log_free_channel(syslog_channel);
+ log_free_channel(debug_channel);
+ log_free_channel(stderr_channel);
+ log_free_channel(null_channel);
+}
+
+void
+init_logging() {
+ int i;
+ int size;
+ const struct ns_sym *s;
+ char category_name[256];
+
+ size = ns_log_max_category * (sizeof (char *));
+
+ logging_categories = (char **)memget(size);
+ if (logging_categories == NULL)
+ ns_panic(ns_log_config, 0, "memget failed in init_logging");
+ memset(logging_categories, 0, size);
+ for (s = category_constants; s != NULL && s->name != NULL; s++) {
+ sprintf(category_name, "%s: ", s->name);
+ logging_categories[s->number] = savestr(category_name, 1);
+ }
+
+ init_default_log_channels();
+ use_default_logging();
+}
+
+void
+shutdown_logging() {
+ int size;
+ const struct ns_sym *s;
+
+ evSetDebug(ev, 0, NULL);
+ shutdown_default_log_channels();
+ log_free_context(log_ctx);
+
+ for (s = category_constants; s != NULL && s->name != NULL; s++)
+ freestr(logging_categories[s->number]);
+ size = ns_log_max_category * (sizeof (char *));
+ memput(logging_categories, size);
+}
+
+/*
+ * Main Loader
+ */
+
+void
+init_configuration() {
+ /*
+ * Remember initial limits for use if "default" is specified in
+ * a config file.
+ */
+#ifdef HAVE_GETRUSAGE
+ get_initial_limits();
+#endif
+ zone_symbol_table = new_symbol_table(ZONE_SYM_TABLE_SIZE, NULL);
+ use_default_options();
+ parser_initialize();
+ config_initialized = 1;
+}
+
+void
+shutdown_configuration() {
+ REQUIRE(config_initialized);
+
+ if (server_options != NULL) {
+ free_options(server_options);
+ server_options = NULL;
+ }
+ if (current_pid_filename != NULL)
+ freestr(current_pid_filename);
+ free_nameserver_info();
+ free_symbol_table(zone_symbol_table);
+ parser_shutdown();
+ config_initialized = 0;
+}
+
+void
+load_configuration(const char *filename) {
+ REQUIRE(config_initialized);
+
+ ns_debug(ns_log_config, 3, "load configuration %s", filename);
+
+ /*
+ * Clean up any previous configuration and initialize
+ * global data structures we'll be updating.
+ */
+ free_nameserver_info();
+ bogus_nameservers = new_ip_match_list();
+
+ options_installed = 0;
+ logging_installed = 0;
+
+ parse_configuration(filename);
+
+ /*
+ * If the user didn't specify logging or options, but they previously
+ * had specified one or both of them, then we need to
+ * re-establish the default environment. We have to be careful
+ * about when we install default options because the parser
+ * must respect limits (e.g. data-size, number of open files)
+ * specified in the options file. In the ordinary case where the
+ * options section isn't changing on a zone reload, it would be bad
+ * to lower these limits temporarily, because we might not survive
+ * to the point where they get raised back again. The logging case
+ * has similar motivation -- we don't want to override the existing
+ * logging scheme (perhaps causing log messages to go somewhere
+ * unexpected) when the user hasn't expressed a desire for a new
+ * scheme.
+ */
+ if (!logging_installed)
+ use_default_logging();
+ if (!options_installed && !default_options_installed) {
+ use_default_options();
+ ns_warning(ns_log_config, "re-establishing default options");
+ }
+
+ update_pid_file();
+
+ /* Init or reinit the interface/port list and associated sockets. */
+ getnetconf(0);
+ opensocket_f();
+
+ initial_configuration = 0;
+}
diff --git a/contrib/bind/bin/named/ns_defs.h b/contrib/bind/bin/named/ns_defs.h
new file mode 100644
index 0000000..f81a383
--- /dev/null
+++ b/contrib/bind/bin/named/ns_defs.h
@@ -0,0 +1,756 @@
+/*
+ * from ns.h 4.33 (Berkeley) 8/23/90
+ * $Id: ns_defs.h,v 8.38 1998/03/17 03:22:27 halley Exp $
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/*
+ * 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 MIN_REFRESH 2 /* never refresh more frequently than once */
+ /* every MIN_REFRESH seconds */
+#define MIN_RETRY 1 /* never retry more frequently than once */
+ /* every MIN_RETRY seconds */
+#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 /* default max seconds for an xfer */
+#define XFER_TIME_FUDGE 10 /* MAX_XFER_TIME fudge */
+#define MAX_XFERS_RUNNING 20 /* max value of transfers_in */
+#define DEFAULT_XFERS_RUNNING 10 /* default value of transfers_in */
+#define DEFAULT_XFERS_PER_NS 2 /* default # 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 */
+
+ /* What maintainance operations need to be performed sometime soon? */
+#define MAIN_NEED_RELOAD 0x0001 /* db_reload() needed. */
+#define MAIN_NEED_MAINT 0x0002 /* ns_maint() needed. */
+#define MAIN_NEED_ENDXFER 0x0004 /* endxfer() needed. */
+#define MAIN_NEED_ZONELOAD 0x0008 /* loadxfer() needed. */
+#define MAIN_NEED_DUMP 0x0010 /* doadump() needed. */
+#define MAIN_NEED_STATSDUMP 0x0020 /* ns_stats() needed. */
+#define MAIN_NEED_EXIT 0x0040 /* exit() needed. */
+#define MAIN_NEED_QRYLOG 0x0080 /* toggle_qrylog() needed. */
+#define MAIN_NEED_DEBUG 0x0100 /* use_desired_debug() needed. */
+#define MAIN_NEED_NOTIFY 0x0200 /* do_notify_after_load() needed */
+
+ /* What global options are set? */
+#define OPTION_NORECURSE 0x0001 /* Don't recurse even if asked. */
+#define OPTION_NOFETCHGLUE 0x0002 /* Don't fetch missing glue. */
+#define OPTION_FORWARD_ONLY 0x0004 /* Don't use NS RR's, just forward. */
+#define OPTION_FAKE_IQUERY 0x0008 /* Fake up bogus response to IQUERY. */
+#define OPTION_NONOTIFY 0x0010 /* Turn off notify */
+#define OPTION_NONAUTH_NXDOMAIN 0x0020 /* Generate non-auth NXDOMAINs? */
+#define OPTION_MULTIPLE_CNAMES 0x0040 /* Allow a name to have multiple
+ * CNAME RRs */
+#define OPTION_HOSTSTATS 0x0080 /* Maintain per-host statistics? */
+#define OPTION_DEALLOC_ON_EXIT 0x0100 /* Deallocate everything on exit? */
+
+#define DEFAULT_OPTION_FLAGS (OPTION_HOSTSTATS)
+
+#ifdef BIND_UPDATE
+#define SOAINCRINTVL 300 /* default value for the time after which
+ * the zone serial number must be incremented
+ * after a successful update has occurred */
+#define DUMPINTVL 3600 /* default interval at which to dump changed zones
+ * randomized, not exact */
+#define DEFERUPDCNT 100 /* default number of updates that can happen
+ * before the zone serial number will be
+ * incremented */
+#define UPDATE_TIMER XFER_TIMER
+#endif /* BIND_UPDATE */
+
+#define USE_MINIMUM 0xffffffff
+#define MAXIMUM_TTL 0x7fffffff
+
+#define CLEAN_TIMER 0x01
+#define INTERFACE_TIMER 0x02
+#define STATS_TIMER 0x04
+
+ /* IP address accessor, network byte order. */
+#define ina_ulong(ina) (ina.s_addr)
+
+ /* IP address accessor, host byte order, read only. */
+#define ina_hlong(ina) ntohl(ina.s_addr)
+
+ /* IP address equality. */
+ /* XXX: assumes that network byte order won't affect equality. */
+#define ina_equal(a, b) (ina_ulong(a) == ina_ulong(b))
+
+ /* IP address equality with a mask. */
+#define ina_onnet(h, n, m) ((ina_ulong(h) & ina_ulong(m)) == ina_ulong(n))
+
+ /* Sequence space arithmetic. */
+#define SEQ_GT(a,b) ((int32_t)((a)-(b)) > 0)
+
+#define NS_OPTION_P(option) ((server_options == NULL) ? \
+ (panic(panic_msg_no_options, NULL), 0) : \
+ ((server_options->flags & option) != 0))
+
+#define NS_INCRSTAT(addr, which) \
+ do { \
+ if ((int)which >= (int)nssLast) \
+ ns_panic(ns_log_insist, 1, panic_msg_bad_which, \
+ __FILE__, __LINE__, #which); \
+ else { \
+ if (NS_OPTION_P(OPTION_HOSTSTATS)) { \
+ struct nameser *ns = \
+ nameserFind(addr, NS_F_INSERT); \
+ if (ns != NULL) \
+ ns->stats[(int)which]++; \
+ } \
+ globalStats[(int)which]++; \
+ } \
+ } while (0)
+
+enum severity { ignore, warn, fail, not_set };
+
+enum znotify { znotify_use_default=0, znotify_yes, znotify_no };
+
+enum axfr_format { axfr_use_default=0, axfr_one_answer, axfr_many_answers };
+
+struct ip_match_direct {
+ struct in_addr address;
+ struct in_addr mask;
+};
+
+struct ip_match_indirect {
+ struct ip_match_list *list;
+};
+
+typedef enum { ip_match_pattern, ip_match_indirect, ip_match_localhost,
+ ip_match_localnets } ip_match_type;
+
+typedef struct ip_match_element {
+ ip_match_type type;
+ u_int flags;
+ union {
+ struct ip_match_direct direct;
+ struct ip_match_indirect indirect;
+ } u;
+ struct ip_match_element *next;
+} *ip_match_element;
+
+/* Flags for ip_match_element */
+#define IP_MATCH_NEGATE 0x01 /* match means deny access */
+
+typedef struct ip_match_list {
+ ip_match_element first;
+ ip_match_element last;
+} *ip_match_list;
+
+typedef struct ztimer_info {
+ char *name;
+ int class;
+ int type;
+} *ztimer_info;
+
+/* 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 soa serial increment */
+ 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_axfr_src; /* bind() the axfr socket to this */
+ 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 */
+ int z_numxfrs; /* Ref count of concurrent xfrs. */
+ enum severity z_checknames; /* How to handle non-RFC-compliant names */
+#ifdef BIND_UPDATE
+ time_t z_dumptime; /* randomized time for next zone dump
+ * if Z_NEED_DUMP is set */
+ u_int32_t z_dumpintvl; /* time interval between zone dumps */
+ time_t z_soaincrintvl; /* interval for updating soa serial */
+ time_t z_soaincrtime; /* time for soa increment */
+ u_int32_t z_deferupdcnt; /* max number of updates before SOA
+ * serial number incremented */
+ u_int32_t z_updatecnt; /* number of update requests processed
+ * since the last SOA serial update */
+ char *z_updatelog; /* log file for updates */
+#endif
+ ip_match_list z_update_acl; /* list of who can issue dynamic
+ updates */
+ ip_match_list z_query_acl; /* sites we'll answer questions for */
+ ip_match_list z_transfer_acl; /* sites that may get a zone transfer
+ from us */
+ long z_max_transfer_time_in; /* max num seconds for AXFR */
+ enum znotify z_notify; /* Notify mode */
+ struct in_addr z_also_notify[NSMAX]; /* More nameservers to notify */
+ int z_notify_count;
+ evTimerID z_timer; /* maintenance timer */
+ ztimer_info z_timerinfo; /* UAP associated with timer */
+ time_t z_nextmaint; /* time of next maintenance */
+};
+
+ /* zone types (z_type) */
+enum zonetype { z_nil, z_master, z_slave, z_hint, z_stub, z_any };
+#define Z_NIL z_nil /* XXX */
+#define Z_MASTER z_master /* XXX */
+#define Z_PRIMARY z_master /* XXX */
+#define Z_SLAVE z_slave /* XXX */
+#define Z_SECONDARY z_slave /* XXX */
+#define Z_HINT z_hint /* XXX */
+#define Z_CACHE z_hint /* XXX */
+#define Z_STUB z_stub /* XXX */
+#define Z_ANY z_any /* XXX*2 */
+
+ /* 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 BIND_UPDATE
+#define Z_DYNAMIC 0x0400 /* allow dynamic updates */
+#define Z_NEED_DUMP 0x0800 /* zone has changed, needs a dump */
+#define Z_NEED_SOAUPDATE 0x1000 /* soa serial number needs increment */
+#endif /* BIND_UPDATE */
+#define Z_XFER_ABORTED 0x2000 /* zone transfer has been aborted */
+#define Z_XFER_GONE 0x4000 /* zone transfer process is gone */
+#define Z_TIMER_SET 0x8000 /* z_timer contains a valid id */
+
+ /* 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 */
+
+/* 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_msgsize, /* allocated size of message */
+ q_cmsglen, /* len of cname message */
+ q_cmsgsize; /* allocated size 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) */
+ char *q_domain; /* domain of most enclosing zone cut */
+ char *q_name; /* domain of query */
+ u_int16_t q_class; /* class of query */
+ u_int16_t q_type; /* type of query */
+#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_USEVC 0x08 /* forward using tcp not udp */
+
+#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
+
+/*
+ * Return codes from ns_forw:
+ */
+#define FW_OK 0
+#define FW_DUP 1
+#define FW_NOSERVER 2
+#define FW_SERVFAIL 3
+
+typedef void (*sq_closure)(struct qstream *qs);
+
+#ifdef BIND_UPDATE
+struct fdlist {
+ int fd;
+ struct fdlist *next;
+};
+#endif
+
+typedef struct _interface {
+ int dfd, /* Datagram file descriptor */
+ sfd; /* Stream file descriptor. */
+ time_t gen; /* Generation number. */
+ struct in_addr addr; /* Interface address. */
+ u_int16_t port; /* Interface port. */
+ u_int16_t flags; /* Valid bits for evXXXXID. */
+ evFileID evID_d; /* Datagram read-event. */
+ evConnID evID_s; /* Stream listen-event. */
+ LINK(struct _interface) link;
+} interface;
+
+#define INTERFACE_FILE_VALID 0x01
+#define INTERFACE_CONN_VALID 0x02
+#define INTERFACE_FORWARDING 0x04
+
+struct qstream {
+ int s_rfd; /* stream file descriptor */
+ int s_size; /* expected amount of data to rcv */
+ int s_bufsize; /* amount of data received in s_buf */
+ u_char *s_buf; /* buffer of received data */
+ u_char *s_wbuf; /* send buffer */
+ u_char *s_wbuf_send; /* next sendable byte of send buffer */
+ u_char *s_wbuf_free; /* next free byte of send buffer */
+ u_char *s_wbuf_end; /* byte after end of send buffer */
+ sq_closure s_wbuf_closure; /* callback for writable descriptor */
+ struct qstream *s_next; /* next stream */
+ struct sockaddr_in
+ s_from; /* address query came from */
+ interface *s_ifp; /* interface query came from */
+ time_t s_time; /* time stamp of last transaction */
+ int s_refcnt; /* number of outstanding queries */
+ u_char s_temp[HFIXEDSZ];
+#ifdef BIND_UPDATE
+ int s_opcode; /* type of request */
+ int s_linkcnt; /* number of client connections using
+ * this connection to forward updates
+ * to the primary */
+ struct fdlist *s_fds; /* linked list of connections to the
+ * primaries that have been used by
+ * the server to forward this client's
+ * update requests */
+#endif
+ evStreamID evID_r; /* read event. */
+ evFileID evID_w; /* writable event handle. */
+ evConnID evID_c; /* connect event handle */
+ u_int flags; /* see below */
+ struct qstream_xfr {
+ enum { s_x_base, s_x_firstsoa, s_x_zone,
+ s_x_lastsoa, s_x_done }
+ state; /* state of transfer. */
+ u_char *msg, /* current assembly message. */
+ *cp, /* where are we in msg? */
+ *eom, /* end of msg. */
+ *ptrs[128]; /* ptrs for dn_comp(). */
+ int class, /* class of an XFR. */
+ id, /* id of an XFR. */
+ opcode; /* opcode of an XFR. */
+ u_int zone; /* zone being XFR'd. */
+ struct namebuf *top; /* top np of an XFR. */
+ struct qs_x_lev { /* decompose the recursion. */
+ enum {sxl_ns, sxl_all, sxl_sub}
+ state; /* what's this level doing? */
+ int flags; /* see below (SXL_*). */
+ char dname[MAXDNAME];
+ struct namebuf *np, /* this node. */
+ *nnp, /* next node to process. */
+ **npp, /* subs. */
+ **npe; /* end of subs. */
+ struct databuf *dp; /* current rr. */
+ struct qs_x_lev *next; /* link. */
+ } *lev; /* LIFO. */
+ enum axfr_format transfer_format;
+ } xfr;
+};
+#define SXL_GLUING 0x01
+#define SXL_ZONECUT 0x02
+
+ /* flags */
+#define STREAM_MALLOC 0x01
+#define STREAM_WRITE_EV 0x02
+#define STREAM_READ_EV 0x04
+#define STREAM_CONNECT_EV 0x08
+#define STREAM_DONE_CLOSE 0x10
+#define STREAM_AXFR 0x20
+
+#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 */
+ 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 */
+ 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 */
+};
+
+enum transport { primary_trans, secondary_trans, response_trans, num_trans };
+
+/* types used by the parser or config routines */
+
+typedef struct zone_config {
+ void *opaque;
+} zone_config;
+
+typedef struct listen_info {
+ u_short port;
+ ip_match_list list;
+ struct listen_info *next;
+} *listen_info;
+
+typedef struct listen_info_list {
+ listen_info first;
+ listen_info last;
+} *listen_info_list;
+
+#ifndef RLIMIT_TYPE
+#define RLIMIT_TYPE u_long
+#endif
+typedef RLIMIT_TYPE rlimit_type;
+
+typedef struct options {
+ u_int flags;
+ char *directory;
+ char *dump_filename;
+ char *pid_filename;
+ char *stats_filename;
+ char *memstats_filename;
+ char *named_xfer;
+ int transfers_in;
+ int transfers_per_ns;
+ int transfers_out;
+ enum axfr_format transfer_format;
+ long max_transfer_time_in;
+ struct sockaddr_in query_source;
+ ip_match_list query_acl;
+ ip_match_list transfer_acl;
+ ip_match_list topology;
+ enum severity check_names[num_trans];
+ u_long data_size;
+ u_long stack_size;
+ u_long core_size;
+ u_long files;
+ listen_info_list listen_list;
+ struct fwdinfo *fwdtab;
+ /* XXX need to add forward option */
+ int clean_interval;
+ int interface_interval;
+ int stats_interval;
+} *options;
+
+typedef struct key_info {
+ char *name;
+ char *algorithm;
+ char *secret; /* XXX should be u_char? */
+} *key_info;
+
+typedef struct key_list_element {
+ key_info info;
+ struct key_list_element *next;
+} *key_list_element;
+
+typedef struct key_info_list {
+ key_list_element first;
+ key_list_element last;
+} *key_info_list;
+
+typedef struct topology_config {
+ void *opaque;
+} topology_config;
+
+#define UNKNOWN_TOPOLOGY_DISTANCE 9998
+#define MAX_TOPOLOGY_DISTANCE 9999
+
+typedef struct topology_distance {
+ ip_match_list patterns;
+ struct topology_distance *next;
+} *topology_distance;
+
+typedef struct topology_context {
+ topology_distance first;
+ topology_distance last;
+} *topology_context;
+
+typedef struct acl_table_entry {
+ char *name;
+ ip_match_list list;
+ struct acl_table_entry *next;
+} *acl_table_entry;
+
+typedef struct server_config {
+ void *opaque;
+} server_config;
+
+#define SERVER_INFO_BOGUS 0x01
+
+typedef struct server_info {
+ struct in_addr address;
+ u_int flags;
+ int transfers;
+ enum axfr_format transfer_format;
+ key_info_list key_list;
+ /* could move statistics to here, too */
+ struct server_info *next;
+} *server_info;
+
+/*
+ * enum <--> name translation
+ */
+
+struct ns_sym {
+ int number; /* Identifying number, like ns_log_default */
+ char * name; /* Its symbolic name, like "default" */
+};
+
+/*
+ * Logging options
+ */
+
+typedef enum ns_logging_categories {
+ ns_log_default = 0,
+ ns_log_config,
+ ns_log_parser,
+ ns_log_queries,
+ ns_log_lame_servers,
+ ns_log_statistics,
+ ns_log_panic,
+ ns_log_update,
+ ns_log_ncache,
+ ns_log_xfer_in,
+ ns_log_xfer_out,
+ ns_log_db,
+ ns_log_eventlib,
+ ns_log_packet,
+ ns_log_notify,
+ ns_log_cname,
+ ns_log_security,
+ ns_log_os,
+ ns_log_insist,
+ ns_log_maint,
+ ns_log_load,
+ ns_log_resp_checks,
+ ns_log_max_category
+} ns_logging_categories;
+
+typedef struct log_config {
+ log_context log_ctx;
+ log_channel eventlib_channel;
+ log_channel packet_channel;
+ int default_debug_active;
+} *log_config;
+
+struct map {
+ char * token;
+ int val;
+};
+
+#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? */
+
+#define VQEXPIRY 900 /* a VQ entry expires in 15*60 = 900 seconds */
+
+#ifdef BIND_UPDATE
+enum req_action { Finish, Refuse, Return };
+#endif
+
+#ifdef BIND_NOTIFY
+typedef enum {
+ notify_info_waitfor, notify_info_delay, notify_info_error,
+ notify_info_done
+} notify_info_state;
+
+typedef struct notify_info {
+ char *name;
+ int class;
+ notify_info_state state;
+ evWaitID wait_id;
+ evTimerID timer_id;
+ LINK(struct notify_info) link;
+} *notify_info;
+
+typedef LIST(struct notify_info) notify_info_list;
+#endif /* BIND_NOTIFY */
+
+#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/bin/named/ns_forw.c b/contrib/bind/bin/named/ns_forw.c
new file mode 100644
index 0000000..9c72825
--- /dev/null
+++ b/contrib/bind/bin/named/ns_forw.c
@@ -0,0 +1,1132 @@
+#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.34 1998/02/24 01:02:40 halley Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.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 <errno.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+struct complaint {
+ u_long tag1, tag2;
+ time_t expire;
+ struct complaint *next;
+};
+
+static struct complaint *complaints = NULL;
+static int retry_timer_set = 0;
+
+/*
+ * 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 memory allocation 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(struct databuf *nsp[], u_char *msg, int msglen,
+ struct sockaddr_in from, struct qstream *qsp, int dfd,
+ struct qinfo **qpp, const char *dname, int class, int type,
+ struct namebuf *np, int use_tcp)
+{
+ struct qinfo *qp;
+ char tmpdomain[MAXDNAME];
+ struct sockaddr_in *nsa;
+ HEADER *hp;
+ u_int16_t id;
+ int n;
+
+ ns_debug(ns_log_default, 3, "ns_forw()");
+
+ hp = (HEADER *) msg;
+ id = hp->id;
+ /* Look at them all */
+ for (qp = nsqhead; qp != NULL; qp = qp->q_link) {
+ if (qp->q_id == id &&
+ memcmp(&qp->q_from, &from, sizeof qp->q_from) == 0 &&
+ ((qp->q_cmsglen == 0 && qp->q_msglen == msglen &&
+ memcmp(qp->q_msg + 2, msg + 2, msglen - 2) == 0) ||
+ (qp->q_cmsglen == msglen &&
+ memcmp(qp->q_cmsg + 2, msg + 2, msglen - 2) == 0)
+ )) {
+ ns_debug(ns_log_default, 3, "forw: dropped DUP id=%d",
+ ntohs(id));
+ nameserIncr(from.sin_addr, nssRcvdDupQ);
+ return (FW_DUP);
+ }
+ }
+
+ qp = qnew(dname, class, type);
+ getname(np, tmpdomain, sizeof tmpdomain);
+ qp->q_domain = savestr(tmpdomain, 1);
+ qp->q_from = from; /* nslookup wants to know this */
+ n = nslookup(nsp, qp, dname, "ns_forw");
+ if (n < 0) {
+ ns_debug(ns_log_default, 2, "forw: nslookup reports danger");
+ ns_freeqry(qp);
+ return (FW_SERVFAIL);
+ }
+ if (n == 0 && !server_options->fwdtab) {
+ ns_debug(ns_log_default, 2, "forw: no nameservers found");
+ ns_freeqry(qp);
+ return (FW_NOSERVER);
+ }
+ qp->q_stream = qsp;
+ qp->q_curaddr = 0;
+ qp->q_fwd = server_options->fwdtab;
+ qp->q_dfd = dfd;
+ qp->q_id = id;
+ qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2;
+ if (use_tcp)
+ qp->q_flags |= Q_USEVC;
+ 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 *)memget((unsigned)msglen)) == NULL) {
+ ns_notice(ns_log_default, "forw: memget: %s",
+ strerror(errno));
+ ns_freeqry(qp);
+ return (FW_SERVFAIL);
+ }
+ qp->q_msgsize = msglen;
+ memcpy(qp->q_msg, msg, qp->q_msglen = msglen);
+ if (!qp->q_fwd) {
+ hp->rd = 0;
+ qp->q_addr[0].stime = tt;
+ }
+
+#ifdef SLAVE_FORWARD
+ if (NS_OPTION_P(OPTION_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);
+ ns_debug(ns_log_default, 1,
+ "forw: forw -> [%s].%d ds=%d nsid=%d id=%d %dms retry %dsec",
+ 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, log_get_stream(packet_channel));
+#endif
+ if (qp->q_flags & Q_USEVC) {
+ if (tcp_send(qp) != NOERROR) {
+ if (!haveComplained(ina_ulong(nsa->sin_addr),
+ (u_long)tcpsendStr))
+ ns_info(ns_log_default,
+ "ns_forw: tcp_send(%s) failed: %s",
+ sin_ntoa(*nsa), strerror(errno));
+ }
+ } else if (sendto(ds, (char *)msg, msglen, 0, (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0) {
+ if (!haveComplained(ina_ulong(nsa->sin_addr),
+ (u_long)sendtoStr))
+ ns_info(ns_log_default, "ns_forw: sendto(%s): %s",
+ sin_ntoa(*nsa), strerror(errno));
+ nameserIncr(nsa->sin_addr, nssSendtoErr);
+ }
+ if (NS_OPTION_P(OPTION_HOSTSTATS))
+ nameserIncr(from.sin_addr, nssRcvdFwdQ);
+ nameserIncr(nsa->sin_addr, nssSentFwdQ);
+ if (qpp)
+ *qpp = qp;
+ hp->rd = 1;
+ return (0);
+}
+
+/* haveComplained(tag1, tag2)
+ * check to see if we have complained about (tag1,tag2) recently
+ * returns:
+ * boolean: have we complained recently?
+ * side-effects:
+ * outdated complaint records removed from our static list
+ * author:
+ * Paul Vixie (DECWRL) April 1991
+ */
+int
+haveComplained(u_long tag1, u_long tag2) {
+ struct complaint *cur, *next, *prev;
+ int r = 0;
+
+ for (cur = complaints, prev = NULL;
+ cur != NULL;
+ prev = cur, cur = next) {
+ next = cur->next;
+ if (tt.tv_sec > cur->expire) {
+ if (prev)
+ prev->next = next;
+ else
+ complaints = next;
+ memput(cur, sizeof *cur);
+ cur = prev;
+ } else if (tag1 == cur->tag1 && tag2 == cur->tag2)
+ r++;
+ }
+ if (!r) {
+ cur = (struct complaint *)memget(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
+ complaints = cur;
+ }
+ }
+ return (r);
+}
+
+void
+freeComplaints(void) {
+ struct complaint *cur, *next;
+
+ for (cur = complaints; cur != NULL; cur = next) {
+ next = cur->next;
+ memput(cur, sizeof *cur);
+ }
+ complaints = NULL;
+}
+
+/* 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(const char *sysloginfo, const char *queryname,
+ const char *complaint, const char *dname,
+ const struct databuf *a_rr, const struct databuf *nsdp)
+{
+ char *a, *ns;
+ const char *a_type;
+ int print_a;
+
+ ns_debug(ns_log_default, 2, "NS '%s' %s", dname, complaint);
+ if (sysloginfo && queryname && !haveComplained((u_long)queryname,
+ (u_long)complaint)) {
+ char buf[999];
+
+ a = ns = (char *)NULL;
+ print_a = (a_rr->d_type == T_A);
+ a_type = p_type(a_rr->d_type);
+ 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;
+ }
+ }
+ if (NS_OPTION_P(OPTION_HOSTSTATS)) {
+ char nsbuf[20], abuf[20];
+
+ if (nsdp != NULL) {
+ if (nsdp->d_ns != NULL) {
+ strcpy(nsbuf,
+ inet_ntoa(nsdp->d_ns->addr));
+ ns = nsbuf;
+ } else {
+ ns = zones[nsdp->d_zone].z_origin;
+ }
+ }
+ if (a_rr->d_ns != NULL) {
+ strcpy(abuf, inet_ntoa(a_rr->d_ns->addr));
+ a = abuf;
+ } else {
+ a = zones[a_rr->d_zone].z_origin;
+ }
+ }
+ if (a != NULL || ns != NULL)
+ ns_info(ns_log_default,
+ "%s: query(%s) %s (%s:%s) learnt (%s=%s:NS=%s)",
+ sysloginfo, queryname,
+ complaint, dname,
+ print_a ?
+ inet_ntoa(ina_get(a_rr->d_data)) : "",
+ a_type,
+ a ? a : "<Not Available>",
+ ns ? ns : "<Not Available>" );
+ else
+ ns_info(ns_log_default, "%s: query(%s) %s (%s:%s)",
+ sysloginfo, queryname,
+ complaint, dname,
+ print_a ?
+ inet_ntoa(ina_get(a_rr->d_data)) : "");
+ }
+}
+
+/*
+ * 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:
+ * logs if a dangerous situation is detected and
+ * (syslogdname && sysloginfo)
+ */
+int
+nslookup(struct databuf *nsp[], struct qinfo *qp,
+ const char *syslogdname, const char *sysloginfo)
+{
+ struct namebuf *np;
+ struct databuf *dp, *nsdp;
+ struct qserv *qs;
+ int n;
+ u_int i;
+ struct hashbuf *tmphtp;
+ char *dname;
+ const char *fname;
+ int oldn, naddr, class, found_arr, potential_ns;
+ time_t curtime;
+
+ ns_debug(ns_log_default, 3, "nslookup(nsp=%#x, qp=%#x, \"%s\")",
+ nsp, 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;
+ ns_debug(ns_log_default, 3,
+ "nslookup: NS \"%s\" c=%d t=%d (flags 0x%lu)",
+ 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) {
+ ns_debug(ns_log_default, 2,
+ "skipping used NS w/name %s",
+ nsdp->d_data);
+ goto skipserver;
+ }
+ }
+
+ tmphtp = ((nsdp->d_flags & DB_F_HINT) ?fcachetab :hashtab);
+ np = nlookup(dname, &tmphtp, &fname, 1);
+ if (np == NULL) {
+ ns_debug(ns_log_default, 3, "%s: not found %s %#x",
+ dname, fname, 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)) {
+ if (dp->d_rcode)
+ break;
+ 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 {
+ /* Authoritative A RR missing. */
+ continue;
+ }
+ }
+ found_arr = 0;
+ oldn = n;
+
+ /* look for name server addresses */
+ delete_stale(np);
+ 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 const char *complaint =
+ "NS points to CNAME";
+ if (dp->d_rcode)
+ continue;
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp, nsdp);
+ goto skipserver;
+ }
+ if (dp->d_type != T_A || dp->d_class != class)
+ continue;
+ if (dp->d_rcode) {
+ static const char *complaint =
+ "A RR negative cache entry";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp, nsdp);
+ goto skipserver;
+ }
+ if (ina_hlong(ina_get(dp->d_data)) == INADDR_ANY) {
+ static const char *complaint =
+ "Bogus (0.0.0.0) A RR";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp, nsdp);
+ continue;
+ }
+#ifdef INADDR_LOOPBACK
+ if (ina_hlong(ina_get(dp->d_data))==INADDR_LOOPBACK) {
+ static const char *complaint =
+ "Bogus LOOPBACK A RR";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp, nsdp);
+ continue;
+ }
+#endif
+#ifdef INADDR_BROADCAST
+ if (ina_hlong(ina_get(dp->d_data))==INADDR_BROADCAST){
+ static const char *complaint =
+ "Bogus BROADCAST A RR";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp, nsdp);
+ continue;
+ }
+#endif
+#ifdef IN_MULTICAST
+ if (IN_MULTICAST(ina_hlong(ina_get(dp->d_data)))) {
+ static const 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 == DB_Z_CACHE) &&
+ (dp->d_ttl < (u_int32_t)curtime) &&
+ !(dp->d_flags & DB_F_HINT) )
+ {
+ ns_debug(ns_log_default, 1,
+ "nslookup: stale '%s'",
+ NAME(*np));
+ n = oldn;
+ found_arr = 0;
+ goto need_sysquery;
+ }
+
+ found_arr++;
+ nsa = ina_get(dp->d_data);
+ /* don't put in duplicates */
+ qs = qp->q_addr;
+ for (i = 0; i < (u_int)n; i++, qs++)
+ if (ina_equal(qs->ns_addr.sin_addr, nsa))
+ 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 this A RR has no RTT, initialize its RTT to a
+ * small random value.
+ */
+ if (dp->d_nstime == 0)
+ dp->d_nstime = 1 +
+ (int)(25.0*rand()/(RAND_MAX + 1.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 (memcmp(&qp->q_from, &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 (ip_match_address(bogus_nameservers, nsa) > 0)
+ goto skipserver;
+#endif
+
+ n++;
+ if (n >= NSMAX)
+ goto out;
+ skipaddr:
+ (void)NULL;
+ }
+ ns_debug(ns_log_default, 8, "nslookup: %d ns addrs", 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:
+ (void)NULL;
+ }
+ out:
+ ns_debug(ns_log_default, 3, "nslookup: %d ns addrs total", n);
+ qp->q_naddr = n;
+ if (n == 0 && potential_ns == 0 && !server_options->fwdtab) {
+ static char *complaint = "No possible A RRs";
+ if (sysloginfo && syslogdname &&
+ !haveComplained((u_long)syslogdname, (u_long)complaint))
+ {
+ ns_info(ns_log_default, "%s: query(%s) %s",
+ sysloginfo, syslogdname, complaint);
+ }
+ return(-1);
+ }
+ /* Update the refcounts before the sort. */
+ for (i = naddr; i < (u_int)n; i++) {
+ DRCNTINC(qp->q_addr[i].nsdata);
+ DRCNTINC(qp->q_addr[i].ns);
+ }
+ if (n > 1) {
+ qsort((char *)qp->q_addr, n, sizeof(struct qserv),
+ (int (*)(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(struct qserv *qs1, struct qserv *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;
+
+#ifdef DEBUG
+ if (debug >= 10) {
+ char a1[sizeof "255.255.255.255"],
+ a2[sizeof "255.255.255.255"];
+
+ strcpy(a1, inet_ntoa(qs1->ns_addr.sin_addr));
+ strcpy(a2, inet_ntoa(qs2->ns_addr.sin_addr));
+ ns_debug(ns_log_default, 10,
+ "qcomp(%s, %s) %lu (%lu) - %lu (%lu) = %lu",
+ a1, a2,
+ rtt1, RTTROUND(rtt1),
+ rtt2, RTTROUND(rtt2),
+ rtt1 - rtt2);
+ }
+#endif
+ if (RTTROUND(rtt1) == RTTROUND(rtt2)) {
+ pos1 = distance_of_address(server_options->topology,
+ qs1->ns_addr.sin_addr);
+ pos2 = distance_of_address(server_options->topology,
+ qs2->ns_addr.sin_addr);
+ pdiff = pos1 - pos2;
+ ns_debug(ns_log_default, 10, "\tpos1=%d, pos2=%d", pos1, pos2);
+ if (pdiff)
+ return (pdiff);
+ }
+ 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(struct qinfo *qp, time_t t) {
+ struct qinfo *qp1, *qp2;
+
+ ns_debug(ns_log_default, 4, "schedretry(%#x, %ld sec)", qp, (long)t);
+ if (qp->q_time)
+ ns_debug(ns_log_default, 4,
+ "WARNING: schedretry(%#lx, %ld) q_time already %ld",
+ (u_long)qp, (long)t, (long)qp->q_time);
+ gettime(&tt);
+ t += (u_long) tt.tv_sec;
+ qp->q_time = t;
+
+ if ((qp1 = retryqp) == NULL) {
+ retryqp = qp;
+ qp->q_next = NULL;
+ goto done;
+ }
+ if (t < qp1->q_time) {
+ qp->q_next = qp1;
+ retryqp = qp;
+ goto done;
+ }
+ while ((qp2 = qp1->q_next) != NULL && qp2->q_time < t)
+ qp1 = qp2;
+ qp1->q_next = qp;
+ qp->q_next = qp2;
+ done:
+ reset_retrytimer();
+}
+
+/*
+ * Unsched is called to remove a forwarded query entry.
+ */
+void
+unsched(struct qinfo *qp) {
+ struct qinfo *np;
+
+ ns_debug(ns_log_default, 3, "unsched(%#lx, %d)",
+ (u_long)qp, ntohs(qp->q_id));
+ if (retryqp == qp) {
+ retryqp = qp->q_next;
+ } else {
+ for (np = retryqp; np->q_next != NULL; np = np->q_next) {
+ if (np->q_next != qp)
+ continue;
+ np->q_next = qp->q_next; /* dequeue */
+ break;
+ }
+ }
+ qp->q_next = NULL; /* sanity check */
+ qp->q_time = 0;
+ reset_retrytimer();
+}
+
+void
+reset_retrytimer() {
+ static evTimerID id;
+
+ if (retry_timer_set) {
+ (void) evClearTimer(ev, id);
+ retry_timer_set = 0;
+ }
+
+ if (retryqp) {
+ evSetTimer(ev, retrytimer, NULL,
+ evConsTime(retryqp->q_time, 0),
+ evConsTime(0, 0), &id);
+ retry_timer_set = 1;
+ } else
+ memset(&id, 0, sizeof id);
+}
+
+void
+retrytimer(evContext ctx, void *uap, struct timespec due,
+ struct timespec ival) {
+ retry_timer_set = 0;
+ retry(retryqp);
+}
+
+/*
+ * Retry is called to retransmit query 'qp'.
+ */
+void
+retry(struct qinfo *qp) {
+ int n;
+ HEADER *hp;
+ struct sockaddr_in *nsa;
+
+ ns_debug(ns_log_default, 3, "retry(%#lx) id=%d", (u_long)qp,
+ ntohs(qp->q_id));
+
+ if (qp->q_msg == NULL) { /* XXX - why? */
+ qremove(qp);
+ return;
+ }
+
+ if (qp->q_expire < tt.tv_sec) {
+ ns_debug(ns_log_default, 1,
+ "retry(%#lx): expired @ %lu (%d secs before now (%lu))",
+ (u_long)qp, (u_long)qp->q_expire,
+ (int)(tt.tv_sec - qp->q_expire),
+ (u_long)tt.tv_sec);
+ if (qp->q_stream || (qp->q_flags & Q_PRIMING))
+ goto fail;
+ qremove(qp);
+ return;
+ }
+
+ /* try next address */
+ n = qp->q_curaddr;
+ if (qp->q_fwd != NULL) {
+ qp->q_fwd = qp->q_fwd->next;
+ if (qp->q_fwd != NULL)
+ goto found;
+ /* Out of forwarders, try direct queries. */
+ }
+ if (qp->q_naddr > 0) {
+ ++qp->q_addr[n].nretry;
+ if (!NS_OPTION_P(OPTION_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 */
+ if (qp->q_expire < tt.tv_sec) {
+ /*
+ * The query has expired. Reset it and retry from
+ * the beginning.
+ */
+ hp->rcode = NOERROR;
+ hp->qr = hp->aa = 0;
+ qp->q_fwd = server_options->fwdtab;
+ for (n = 0; n < (int)qp->q_naddr; n++)
+ qp->q_addr[n].nretry = 0;
+ n = 0;
+ qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2;
+ goto found;
+ }
+ /*
+ * The query hasn't expired yet; it probably ran out
+ * of servers or forwarders. Wait up to 60 seconds
+ * past the expire time.
+ */
+ unsched(qp);
+ schedretry(qp, (time_t)(qp->q_expire - tt.tv_sec + 60));
+ return;
+ }
+ ns_debug(ns_log_default, 5, "give up");
+ n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen);
+ hp->id = qp->q_id;
+ hp->qr = 1;
+ hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0);
+ hp->rd = 1;
+ hp->rcode = SERVFAIL;
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_nquery(qp->q_msg, n, log_get_stream(packet_channel));
+#endif
+ if (send_msg((u_char *)hp, n, qp)) {
+ ns_debug(ns_log_default, 1,
+ "gave up retry(%#lx) nsid=%d id=%d",
+ (u_long)qp, ntohs(qp->q_nsid), ntohs(qp->q_id));
+ }
+ if (NS_OPTION_P(OPTION_HOSTSTATS))
+ nameserIncr(qp->q_from.sin_addr, nssSentFail);
+ qremove(qp);
+ return;
+
+ found:
+ if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0)
+ qp->q_addr[n].stime = tt;
+ qp->q_curaddr = n;
+ hp = (HEADER *)qp->q_msg;
+ hp->rd = (qp->q_fwd ? 1 : 0);
+ nsa = Q_NEXTADDR(qp, n);
+ ns_debug(ns_log_default, 1,
+ "%s(addr=%d n=%d) -> [%s].%d ds=%d nsid=%d id=%d %dms",
+ (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,
+ log_get_stream(packet_channel));
+#endif
+ if (qp->q_flags & Q_USEVC) {
+ if (tcp_send(qp) != NOERROR)
+ ns_debug(ns_log_default, 3,
+ "error resending tcp msg: %s",
+ strerror(errno));
+ } else if (sendto(ds, (char*)qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0)
+ {
+ ns_debug(ns_log_default, 3, "error resending msg: %s",
+ strerror(errno));
+ }
+ hp->rd = 1; /* leave set to 1 for dup detection */
+ nameserIncr(nsa->sin_addr, nssSentDupQ);
+ unsched(qp);
+#ifdef SLAVE_FORWARD
+ if (NS_OPTION_P(OPTION_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(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 */
+ ns_debug(ns_log_default, 3,
+ "retrytime: nstime%ldms t%ld nretry%ld u%ld : v%ld",
+ 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 = NULL;
+ priming = 0;
+}
+
+void
+qremove(struct qinfo *qp) {
+ struct sockaddr_in empty_from;
+
+ empty_from.sin_family = AF_INET;
+ empty_from.sin_addr.s_addr = htonl(INADDR_ANY);
+ empty_from.sin_port = htons(0);
+
+ ns_debug(ns_log_default, 3, "qremove(%#lx)", (u_long)qp);
+
+ if (qp->q_flags & Q_ZSERIAL)
+ qserial_answer(qp, 0, empty_from);
+ unsched(qp);
+ ns_freeqry(qp);
+}
+
+struct qinfo *
+qfindid(u_int16_t id) {
+ struct qinfo *qp;
+
+ for (qp = nsqhead; qp != NULL; qp = qp->q_link)
+ if (qp->q_nsid == id)
+ break;
+ ns_debug(ns_log_default, 3, "qfindid(%d) -> %#lx", ntohs(id),
+ (u_long)qp);
+ return (qp);
+}
+
+struct qinfo *
+qnew(const char *name, int class, int type) {
+ struct qinfo *qp;
+
+ qp = (struct qinfo *)memget(sizeof *qp);
+ if (qp == NULL)
+ panic("qnew: memget failed", NULL);
+ memset(qp, 0, sizeof *qp);
+ ns_debug(ns_log_default, 5, "qnew(%#lx)", (u_long)qp);
+#ifdef BIND_NOTIFY
+ qp->q_notifyzone = DB_Z_CACHE;
+#endif
+ qp->q_link = nsqhead;
+ nsqhead = qp;
+ qp->q_name = savestr(name, 1);
+ qp->q_class = (u_int16_t)class;
+ qp->q_type = (u_int16_t)type;
+ qp->q_flags = 0;
+ return (qp);
+}
+
+void
+ns_freeqns(struct qinfo *qp, char *where) {
+ static const char freed[] = "freed", busy[] = "busy";
+ const char *result;
+ struct databuf *dp;
+ int i;
+
+ for (i = 0 ; i < (int)qp->q_naddr ; i++) {
+ dp = qp->q_addr[i].ns;
+ if (dp) {
+ DRCNTDEC(dp);
+ result = (dp->d_rcnt) ? busy : freed;
+ ns_debug(ns_log_default, 3, "%s: ns %s rcnt %d (%s)",
+ where, dp->d_data, dp->d_rcnt, result);
+ if (result == freed)
+ db_freedata(dp);
+ }
+ dp = qp->q_addr[i].nsdata;
+ if (dp) {
+ DRCNTDEC(dp);
+ result = (dp->d_rcnt) ? busy : freed;
+ ns_debug(ns_log_default, 3,
+ "%s: nsdata %s rcnt %d (%s)",
+ where, inet_ntoa(ina_get(dp->d_data)),
+ dp->d_rcnt, result);
+ if (result == freed)
+ db_freedata(dp);
+ }
+ }
+}
+
+void
+ns_freeqry(struct qinfo *qp) {
+ struct qinfo *np;
+ struct databuf *dp;
+
+ ns_debug(ns_log_default, 3, "ns_freeqry(%#lx)", (u_long)qp);
+ if (qp->q_next)
+ ns_debug(ns_log_default, 1,
+ "WARNING: ns_freeqry of linked ptr %#lx", (u_long)qp);
+ if (qp->q_msg != NULL)
+ memput(qp->q_msg, qp->q_msgsize);
+ if (qp->q_cmsg != NULL)
+ memput(qp->q_cmsg, qp->q_cmsgsize);
+ if (qp->q_domain != NULL)
+ freestr(qp->q_domain);
+ if (qp->q_name != NULL)
+ freestr(qp->q_name);
+ ns_freeqns(qp, "ns_freeqry");
+ if (nsqhead == qp)
+ nsqhead = qp->q_link;
+ else {
+ for(np = nsqhead;
+ np->q_link != NULL;
+ np = np->q_link) {
+ if (np->q_link != qp)
+ continue;
+ np->q_link = qp->q_link; /* dequeue */
+ break;
+ }
+ }
+ memput(qp, sizeof *qp);
+}
diff --git a/contrib/bind/bin/named/ns_func.h b/contrib/bind/bin/named/ns_func.h
new file mode 100644
index 0000000..bf58528
--- /dev/null
+++ b/contrib/bind/bin/named/ns_func.h
@@ -0,0 +1,380 @@
+/* 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.
+ */
+
+/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/* ns_func.h - declarations for ns_*.c's externally visible functions
+ *
+ * $Id: ns_func.h,v 8.43 1998/03/20 00:53:44 halley Exp $
+ */
+
+/* ++from ns_glue.c++ */
+extern struct in_addr ina_get(const u_char *data);
+extern const char *sin_ntoa(struct sockaddr_in);
+extern void ns_debug(int, int, const char *, ...),
+ ns_info(int, const char *, ...),
+ ns_notice(int, const char *, ...),
+ ns_warning(int, const char *, ...),
+ ns_error(int, const char *, ...),
+ ns_panic(int, int, const char *, ...),
+ ns_assertion_failed(char *file, int line,
+ assertion_type type, char *cond,
+ int print_errno);
+extern void panic(const char *, const void *),
+ gettime(struct timeval *);
+extern int nlabels(const char *),
+ my_close(int),
+ my_fclose(FILE *);
+extern void __freestr(char *);
+extern char *__newstr(size_t, int),
+ *__savestr(const char *, int),
+ *checked_ctime(const time_t *t),
+ *ctimel(long);
+extern u_char *ina_put(struct in_addr ina, u_char *data),
+ *savebuf(const u_char *, size_t, int);
+extern void dprintf(int level, const char *format, ...);
+#ifdef DEBUG_STRINGS
+extern char *debug_newstr(size_t, int, const char *, int),
+ *debug_savestr(const char *, int, const char *, int);
+extern void debug_freestr(char *, const char *, int);
+#define newstr(l, n) debug_newstr((l), (n), __FILE__, __LINE__)
+#define savestr(s, n) debug_savestr((s), (n), __FILE__, __LINE__)
+#define freestr(s) debug_freestr((s), __FILE__, __LINE__)
+#else
+#define newstr(l, n) __newstr((l), (n))
+#define savestr(s, n) __savestr((s), (n))
+#define freestr(s) __freestr((s))
+#endif /* DEBUG_STRINGS */
+/* --from ns_glue.c-- */
+
+/* ++from ns_resp.c++ */
+extern void ns_resp(u_char *, int, struct sockaddr_in,
+ struct qstream *),
+ prime_cache(void),
+ delete_all(struct namebuf *, int, int),
+ delete_stale(struct namebuf *);
+extern struct qinfo *sysquery(const char *, int, int,
+ struct in_addr *, int, int);
+extern void sysnotify(const char *, int, int);
+extern int doupdate(u_char *, u_char *, struct databuf **,
+ int, int, int, u_int, struct sockaddr_in),
+ send_msg(u_char *, int, struct qinfo *),
+ findns(struct namebuf **, int,
+ struct databuf **, int *, int),
+ finddata(struct namebuf *, int, int, HEADER *,
+ char **, int *, int *),
+ wanted(const struct databuf *, int, int),
+ add_data(struct namebuf *,
+ struct databuf **,
+ u_char *, int, int *),
+ trunc_adjust(u_char *, int, int);
+/* --from ns_resp.c-- */
+
+/* ++from ns_req.c++ */
+extern void ns_req(u_char *, int, int,
+ struct qstream *,
+ struct sockaddr_in,
+ int),
+ free_addinfo(void),
+ free_nsp(struct databuf **);
+extern int stale(struct databuf *),
+ make_rr(const char *, struct databuf *,
+ u_char *, int, int,
+ u_char **, u_char **),
+ doaddinfo(HEADER *, u_char *, int),
+ doaddauth(HEADER *, u_char *, int,
+ struct namebuf *,
+ struct databuf *);
+#ifdef BIND_NOTIFY
+extern int findZonePri(const struct zoneinfo *,
+ const struct sockaddr_in);
+#endif
+/* --from ns_req.c-- */
+
+/* ++from ns_xfr.c++ */
+extern void ns_xfr(struct qstream *qsp, struct namebuf *znp,
+ int zone, int class, int type,
+ int id, int opcode),
+ ns_stopxfrs(struct zoneinfo *),
+ ns_freexfr(struct qstream *);
+/* --from ns_xfr.c-- */
+
+/* ++from ns_forw.c++ */
+extern time_t retrytime(struct qinfo *);
+extern int ns_forw(struct databuf *nsp[],
+ u_char *msg,
+ int msglen,
+ struct sockaddr_in from,
+ struct qstream *qsp,
+ int dfd,
+ struct qinfo **qpp,
+ const char *dname,
+ int class,
+ int type,
+ struct namebuf *np,
+ int use_tcp),
+ haveComplained(u_long, u_long),
+ nslookup(struct databuf *nsp[],
+ struct qinfo *qp,
+ const char *syslogdname,
+ const char *sysloginfo),
+ qcomp(struct qserv *, struct qserv *);
+extern void schedretry(struct qinfo *, time_t),
+ unsched(struct qinfo *),
+ reset_retrytimer(void),
+ retrytimer(evContext ctx, void *uap,
+ struct timespec due, struct timespec ival),
+ retry(struct qinfo *),
+ qflush(void),
+ qremove(struct qinfo *),
+ ns_freeqns(struct qinfo *, char *),
+ ns_freeqry(struct qinfo *),
+ freeComplaints(void);
+extern struct qinfo *qfindid(u_int16_t),
+ *qnew(const char *, int, int);
+/* --from ns_forw.c-- */
+
+/* ++from ns_main.c++ */
+extern struct in_addr net_mask(struct in_addr);
+extern void sq_remove(struct qstream *),
+ sq_flushw(struct qstream *),
+ sq_flush(struct qstream *allbut),
+ dq_remove_gen(time_t gen),
+ dq_remove_all(),
+ sq_done(struct qstream *),
+ ns_setproctitle(char *, int),
+ getnetconf(int),
+ nsid_init(void),
+ ns_setoption(int option),
+ writestream(struct qstream *, const u_char *, int),
+ ns_need(int need),
+ opensocket_f(void);
+extern u_int16_t nsid_next(void);
+extern int sq_openw(struct qstream *, int),
+ sq_writeh(struct qstream *, sq_closure),
+ sq_write(struct qstream *, const u_char *, int),
+ ns_need_p(int option),
+ tcp_send(struct qinfo *),
+ aIsUs(struct in_addr);
+/* --from ns_main.c-- */
+
+/* ++from ns_maint.c++ */
+extern void ns_maint(void),
+ zone_maint(struct zoneinfo *),
+ sched_zone_maint(struct zoneinfo *),
+ ns_cleancache(evContext ctx, void *uap,
+ struct timespec due,
+ struct timespec inter),
+ purge_zone(const char *, struct hashbuf *, int),
+ loadxfer(void),
+ qserial_retrytime(struct zoneinfo *, time_t),
+ qserial_query(struct zoneinfo *),
+ qserial_answer(struct qinfo *, u_int32_t,
+ struct sockaddr_in),
+#ifdef DEBUG
+ printzoneinfo(int, int, int),
+#endif
+ endxfer(void),
+ ns_reload(void);
+extern int clean_cache(struct hashbuf *, int);
+extern void reapchild(evContext, void *, int);
+extern const char * zoneTypeString(const struct zoneinfo *);
+/* --from ns_maint.c-- */
+
+/* ++from ns_init.c++ */
+extern void ns_refreshtime(struct zoneinfo *, time_t),
+ ns_retrytime(struct zoneinfo *, time_t),
+ ns_init(const char *);
+extern enum context ns_ptrcontext(const char *owner);
+extern enum context ns_ownercontext(int type, enum transport);
+extern int ns_nameok(const char *name, int class,
+ struct zoneinfo *zp,
+ enum transport, enum context,
+ const char *owner,
+ struct in_addr source);
+extern int ns_wildcard(const char *name);
+extern void zoneinit(struct zoneinfo *),
+ do_reload(const char *, int, int),
+ ns_shutdown(void);
+/* --from ns_init.c-- */
+
+/* ++from ns_ncache.c++ */
+extern void cache_n_resp(u_char *, int, struct sockaddr_in);
+/* --from ns_ncache.c-- */
+
+/* ++from ns_udp.c++ */
+extern void ns_udp(void);
+/* --from ns_udp.c-- */
+
+/* ++from ns_stats.c++ */
+extern void ns_stats(void),
+ ns_freestats(void);
+extern void ns_logstats(evContext ctx, void *uap,
+ struct timespec, struct timespec);
+extern void qtypeIncr(int qtype);
+extern struct nameser *nameserFind(struct in_addr addr, int flags);
+#define NS_F_INSERT 0x0001
+#define nameserIncr(a,w) NS_INCRSTAT(a,w) /* XXX should change name. */
+/* --from ns_stats.c-- */
+
+/* ++from ns_update.c++ */
+u_char *findsoaserial(u_char *data);
+u_int32_t get_serial_unchecked(struct zoneinfo *zp);
+u_int32_t get_serial(struct zoneinfo *zp);
+void set_serial(struct zoneinfo *zp, u_int32_t serial);
+int schedule_soa_update(struct zoneinfo *, int);
+int schedule_dump(struct zoneinfo *);
+int incr_serial(struct zoneinfo *zp);
+int merge_logs(struct zoneinfo *zp);
+int zonedump(struct zoneinfo *zp);
+void dynamic_about_to_exit(void);
+enum req_action req_update(HEADER *hp, u_char *cp, u_char *eom,
+ u_char *msg, struct qstream *qsp,
+ int dfd, struct sockaddr_in from);
+void rdata_dump(struct databuf *dp, FILE *fp);
+/* --from ns_update.c-- */
+
+/* ++from ns_config.c++ */
+void free_zone_timerinfo(struct zoneinfo *);
+void free_zone_contents(struct zoneinfo *, int);
+struct zoneinfo *find_zone(const char *, int, int);
+zone_config begin_zone(char *, int);
+void end_zone(zone_config, int);
+int set_zone_type(zone_config, int);
+int set_zone_filename(zone_config, char *);
+int set_zone_checknames(zone_config, enum severity);
+int set_zone_notify(zone_config, int value);
+int set_zone_update_acl(zone_config, ip_match_list);
+int set_zone_query_acl(zone_config, ip_match_list);
+int set_zone_transfer_acl(zone_config, ip_match_list);
+int set_zone_transfer_source(zone_config, struct in_addr);
+int set_zone_transfer_time_in(zone_config, long);
+int add_zone_master(zone_config, struct in_addr);
+int add_zone_notify(zone_config, struct in_addr);
+options new_options(void);
+void free_options(options);
+void set_boolean_option(options, int, int);
+listen_info_list new_listen_info_list(void);
+void free_listen_info_list(listen_info_list);
+void add_listen_on(options, u_int16_t, ip_match_list);
+FILE * write_open(char *filename);
+void update_pid_file(void);
+void set_options(options, int);
+void use_default_options(void);
+ip_match_list new_ip_match_list(void);
+void free_ip_match_list(ip_match_list);
+ip_match_element new_ip_match_pattern(struct in_addr, u_int);
+ip_match_element new_ip_match_mask(struct in_addr, struct in_addr);
+ip_match_element new_ip_match_indirect(ip_match_list);
+ip_match_element new_ip_match_localhost(void);
+ip_match_element new_ip_match_localnets(void);
+void ip_match_negate(ip_match_element);
+void add_to_ip_match_list(ip_match_list, ip_match_element);
+void dprint_ip_match_list(int, ip_match_list, int, char *,
+ char *);
+int ip_match_address(ip_match_list, struct in_addr);
+int ip_address_allowed(ip_match_list, struct in_addr);
+int ip_match_network(ip_match_list, struct in_addr,
+ struct in_addr);
+int distance_of_address(ip_match_list, struct in_addr);
+int ip_match_is_none(ip_match_list);
+void add_forwarder(options, struct in_addr);
+void free_forwarders(struct fwdinfo *);
+server_info find_server(struct in_addr);
+server_config begin_server(struct in_addr);
+void end_server(server_config, int);
+void set_server_option(server_config, int, int);
+void set_server_transfers(server_config, int);
+void set_server_transfer_format(server_config,
+ enum axfr_format);
+void add_server_key_info(server_config, key_info);
+key_info new_key_info(char *, char *, char *);
+void free_key_info(key_info);
+void dprint_key_info(key_info);
+key_info_list new_key_info_list(void);
+void free_key_info_list(key_info_list);
+void add_to_key_info_list(key_info_list, key_info);
+void dprint_key_info_list(key_info_list);
+log_config begin_logging(void);
+void add_log_channel(log_config, int, log_channel);
+void open_special_channels(void);
+void set_logging(log_config, int);
+void end_logging(log_config, int);
+void use_default_logging(void);
+void init_logging(void);
+void shutdown_logging(void);
+void init_configuration(void);
+void shutdown_configuration(void);
+void load_configuration(const char *);
+/* --from ns_config.c-- */
+/* ++from parser.y++ */
+ip_match_list lookup_acl(char *);
+void define_acl(char *, ip_match_list);
+key_info lookup_key(char *);
+void define_key(char *, key_info);
+void parse_configuration(const char *);
+void parser_initialize(void);
+void parser_shutdown(void);
+/* --from parser.y-- */
diff --git a/contrib/bind/bin/named/ns_glob.h b/contrib/bind/bin/named/ns_glob.h
new file mode 100644
index 0000000..35f3041
--- /dev/null
+++ b/contrib/bind/bin/named/ns_glob.h
@@ -0,0 +1,317 @@
+/*
+ * from ns.h 4.33 (Berkeley) 8/23/90
+ * $Id: ns_glob.h,v 8.34 1998/03/20 01:18:07 halley Exp $
+ */
+
+/* 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.
+ */
+
+/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/*
+ * Global variables for the name server.
+ */
+
+#ifdef DEBUG
+DECL int debug INIT(0);
+DECL int desired_debug INIT(0);
+#endif
+
+ /* global event context */
+DECL evContext ev;
+
+ /* list of open streams */
+DECL struct qstream *streamq;
+
+ /* often set to the current time */
+DECL struct timeval tt;
+
+ /* head of allocated queries */
+DECL struct qinfo *nsqhead;
+
+ /* datagram socket for sysquery() and ns_forw(). */
+DECL int ds INIT(-1);
+
+ /* event ID for reads of "ds". */
+DECL evFileID ds_evID;
+
+#ifdef QRYLOG
+ /* is query logging turned on? */
+DECL int qrylog;
+#endif /*QRYLOG*/
+
+ /* port to which we send queries */
+DECL u_int16_t ns_port;
+
+ /* Source addr of our internal resolver. */
+DECL struct sockaddr_in source_addr; /* INITs to <INADDR_ANY, 0>. */
+
+ /* Used by ns_stats */
+DECL time_t boottime;
+
+DECL time_t resettime;
+
+ /* next query to retry */
+DECL struct qinfo *retryqp;
+
+ /* default configuration file */
+DECL char *conffile INIT(NULL);
+
+ /* default debug output file */
+DECL const char *debugfile INIT(_PATH_DEBUG);
+
+ /* zone information */
+DECL struct zoneinfo *zones;
+
+ /* number of zones in use */
+DECL int nzones;
+
+ /* set if we need a priming */
+DECL int needs_prime_cache;
+
+ /* is cache being primed */
+DECL int priming;
+
+ /* ptrs to dnames in msg for dn_comp */
+DECL u_char *dnptrs[40];
+
+ /* end pointer for dnptrs */
+DECL u_char **dnptrs_end
+ INIT(dnptrs + sizeof dnptrs / sizeof(u_char*));
+
+ /* number of names in addinfo */
+DECL int addcount;
+
+ /* name of cache file */
+DECL const char *cache_file;
+
+#ifdef SLAVE_FORWARD
+ /* retry time when a slave */
+DECL int slave_retry INIT(4);
+#endif
+
+#ifdef BIND_UPDATE
+DECL const char * LogSignature INIT(";BIND LOG V8\n");
+DECL const char * DumpSignature INIT(";BIND DUMP V8\n");
+DECL const char * DumpSuffix INIT(".dumptmp");
+#endif
+
+DECL const char sendtoStr[] INIT("sendto");
+DECL const char tcpsendStr[] INIT("tcp_send");
+
+ /* defined in version.c, can't use DECL/INIT */
+extern char Version[];
+extern char ShortVersion[];
+
+ /* If getnum() has an error, here will be the result. */
+DECL int getnum_error INIT(0);
+
+enum context { domain_ctx, owner_ctx, mailname_ctx, hostname_ctx };
+DECL const char *context_strings[]
+#ifdef MAIN_PROGRAM
+ = { "domain", "owner", "mail", "host", NULL }
+#endif
+;
+
+DECL const char *transport_strings[]
+#ifdef MAIN_PROGRAM
+ = { "primary", "secondary", "response", NULL }
+#endif
+;
+
+DECL const char *severity_strings[]
+#ifdef MAIN_PROGRAM
+ = { "ignore", "warn", "fail", "not_set", NULL }
+#endif
+;
+
+DECL struct in_addr inaddr_any; /* Inits to 0.0.0.0 */
+
+DECL options server_options INIT(NULL);
+
+DECL server_info nameserver_info INIT(NULL);
+
+ /* These will disappear some day in favour of "struct nameser". */
+DECL ip_match_list bogus_nameservers INIT(NULL);
+
+DECL log_context log_ctx;
+DECL int log_ctx_valid INIT(0);
+
+DECL log_channel syslog_channel INIT(NULL);
+DECL log_channel debug_channel INIT(NULL);
+DECL log_channel stderr_channel INIT(NULL);
+DECL log_channel eventlib_channel INIT(NULL);
+DECL log_channel packet_channel INIT(NULL);
+DECL log_channel null_channel INIT(NULL);
+
+DECL ip_match_list local_addresses INIT(NULL);
+DECL ip_match_list local_networks INIT(NULL);
+
+ /* are we running in no-fork mode? */
+
+DECL int foreground INIT(0);
+
+DECL const struct ns_sym logging_constants[]
+#ifdef MAIN_PROGRAM
+= {
+ { log_info, "info" },
+ { log_notice, "notice" },
+ { log_warning, "warning" },
+ { log_error, "error" },
+ { log_critical, "critical" },
+ { 0, NULL }
+}
+#endif
+;
+
+DECL const struct ns_sym syslog_constants[]
+#ifdef MAIN_PROGRAM
+= {
+ { LOG_KERN, "kern" },
+ { LOG_USER, "user" },
+ { LOG_MAIL, "mail" },
+ { LOG_DAEMON, "daemon" },
+ { LOG_AUTH, "auth" },
+ { LOG_SYSLOG, "syslog" },
+ { LOG_LPR, "lpr" },
+#ifdef LOG_NEWS
+ { LOG_NEWS, "news" },
+#endif
+#ifdef LOG_UUCP
+ { LOG_UUCP, "uucp" },
+#endif
+#ifdef LOG_CRON
+ { LOG_CRON, "cron" },
+#endif
+#ifdef LOG_AUTHPRIV
+ { LOG_AUTHPRIV, "authpriv" },
+#endif
+#ifdef LOG_FTP
+ { LOG_FTP, "ftp" },
+#endif
+ { LOG_LOCAL0, "local0"},
+ { LOG_LOCAL1, "local1"},
+ { LOG_LOCAL2, "local2"},
+ { LOG_LOCAL3, "local3"},
+ { LOG_LOCAL4, "local4"},
+ { LOG_LOCAL5, "local5"},
+ { LOG_LOCAL6, "local6"},
+ { LOG_LOCAL7, "local7"},
+ { 0, NULL }
+}
+#endif
+;
+
+DECL const struct ns_sym category_constants[]
+#ifdef MAIN_PROGRAM
+= {
+ { ns_log_default, "default" },
+ { ns_log_config, "config" },
+ { ns_log_parser, "parser" },
+ { ns_log_queries, "queries" },
+ { ns_log_lame_servers, "lame-servers" },
+ { ns_log_statistics, "statistics" },
+ { ns_log_panic, "panic" },
+ { ns_log_update, "update" },
+ { ns_log_ncache, "ncache" },
+ { ns_log_xfer_in, "xfer-in" },
+ { ns_log_xfer_out, "xfer-out" },
+ { ns_log_db, "db" },
+ { ns_log_eventlib, "eventlib" },
+ { ns_log_packet, "packet" },
+ { ns_log_notify, "notify" },
+ { ns_log_cname, "cname" },
+ { ns_log_security, "security" },
+ { ns_log_os, "os" },
+ { ns_log_insist, "insist" },
+ { ns_log_maint, "maintenance" },
+ { ns_log_load, "load" },
+ { ns_log_resp_checks, "response-checks" },
+ { 0, NULL }
+}
+#endif
+;
+
+DECL const char panic_msg_no_options[]
+ INIT("no server_options in NS_OPTION_P");
+
+DECL const char panic_msg_insist_failed[]
+ INIT("%s:%d: insist '%s' failed: %s");
+
+DECL const char panic_msg_bad_which[]
+ INIT("%s:%d: INCRSTATS(%s): bad \"which\"");
+
+DECL u_long globalStats[nssLast];
+
+DECL evTimerID clean_timer;
+DECL evTimerID interface_timer;
+DECL evTimerID stats_timer;
+DECL int active_timers INIT(0);
+
+DECL uid_t user_id;
+DECL char * user_name INIT(NULL);
+DECL gid_t group_id;
+DECL char * group_name INIT(NULL);
+DECL char * chroot_dir INIT(NULL);
diff --git a/contrib/bind/bin/named/ns_glue.c b/contrib/bind/bin/named/ns_glue.c
new file mode 100644
index 0000000..460b64d
--- /dev/null
+++ b/contrib/bind/bin/named/ns_glue.c
@@ -0,0 +1,416 @@
+#if !defined(lint) && !defined(SABER)
+static char rcsid[] = "$Id: ns_glue.c,v 8.7 1998/02/13 19:51:45 halley Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+/*
+ * IP address from unaligned octets.
+ */
+struct in_addr
+ina_get(const u_char *data) {
+ struct in_addr ret;
+ u_int32_t i;
+
+ GETLONG(i, data);
+ ina_ulong(ret) = htonl(i);
+ return (ret);
+}
+
+/*
+ * IP address to unaligned octets.
+ */
+u_char *
+ina_put(struct in_addr ina, u_char *data) {
+ PUTLONG(ntohl(ina_ulong(ina)), data);
+ return (data);
+}
+
+/*
+ * XXX: sin_ntoa() should probably be in libc.
+ */
+const char *
+sin_ntoa(struct sockaddr_in sin) {
+ static char ret[sizeof "[111.222.333.444].55555"];
+
+ sprintf(ret, "[%s].%u",
+ inet_ntoa(sin.sin_addr),
+ ntohs(sin.sin_port));
+ return (ret);
+}
+
+/*
+ * Logging Support
+ */
+
+void
+ns_debug(int category, int level, const char *format, ...) {
+ va_list args;
+
+ if (!log_ctx_valid)
+ return;
+ va_start(args, format);
+ log_vwrite(log_ctx, category, log_debug(level), format, args);
+ va_end(args);
+}
+
+void
+ns_info(int category, const char *format, ...) {
+ va_list args;
+
+ if (!log_ctx_valid)
+ return;
+ va_start(args, format);
+ log_vwrite(log_ctx, category, log_info, format, args);
+ va_end(args);
+}
+
+void
+ns_notice(int category, const char *format, ...) {
+ va_list args;
+
+ if (!log_ctx_valid)
+ return;
+ va_start(args, format);
+ log_vwrite(log_ctx, category, log_notice, format, args);
+ va_end(args);
+}
+
+void
+ns_warning(int category, const char *format, ...) {
+ va_list args;
+
+ if (!log_ctx_valid)
+ return;
+ va_start(args, format);
+ log_vwrite(log_ctx, category, log_warning, format, args);
+ va_end(args);
+}
+
+void
+ns_error(int category, const char *format, ...) {
+ va_list args;
+
+ if (!log_ctx_valid)
+ return;
+ va_start(args, format);
+ log_vwrite(log_ctx, category, log_error, format, args);
+ va_end(args);
+}
+
+void
+ns_panic(int category, int dump_core, const char *format, ...) {
+ va_list args;
+
+ if (!log_ctx_valid)
+ return;
+ va_start(args, format);
+ log_vwrite(log_ctx, category, log_critical, format, args);
+ va_end(args);
+ va_start(args, format);
+ log_vwrite(log_ctx, ns_log_panic, log_critical, format, args);
+ va_end(args);
+ if (dump_core)
+ abort();
+ else
+ exit(1);
+}
+
+void
+ns_assertion_failed(char *file, int line, assertion_type type, char *cond,
+ int print_errno)
+{
+ ns_panic(ns_log_insist, 1, "%s:%d: %s(%s)%s%s failed.",
+ file, line, assertion_type_to_text(type), cond,
+ (print_errno) ? ": " : "",
+ (print_errno) ? strerror(errno) : "");
+}
+
+/*
+ * XXX This is for compatibility and will eventually be removed.
+ */
+void
+panic(const char *msg, const void *arg) {
+ ns_panic(ns_log_default, 1, msg, arg);
+}
+
+/*
+ * How many labels in this name?
+ * Note: the root label is not included in the count.
+ */
+int
+nlabels (const char *dname) {
+ int count, i, found, escaped;
+ const char *tmpdname, *end_tmpdname;
+ int tmpdnamelen, c;
+
+ INSIST(dname != NULL);
+
+ count = 0;
+ tmpdname = dname;
+ tmpdnamelen = strlen(tmpdname);
+ /*
+ * Ignore a trailing label separator (i.e. an unescaped dot)
+ * in 'tmpdname'.
+ */
+ if (tmpdnamelen && tmpdname[tmpdnamelen-1] == '.') {
+ escaped = 0;
+ /* note this loop doesn't get executed if tmpdnamelen==1 */
+ for (i = tmpdnamelen - 2; i >= 0; i--)
+ if (tmpdname[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else {
+ break;
+ }
+ if (!escaped)
+ tmpdnamelen--;
+ }
+
+ end_tmpdname = tmpdname + tmpdnamelen;
+
+ while(tmpdname != end_tmpdname) {
+ count++;
+ /*
+ * Strip off the first label if we're not already at
+ * the root label.
+ */
+ for (escaped = found = 0;
+ (tmpdname != end_tmpdname) && !found;
+ tmpdname++) {
+ c = *tmpdname;
+ if (!escaped && (c == '.'))
+ found = 1;
+
+ if (escaped)
+ escaped = 0;
+ else if (c == '\\')
+ escaped = 1;
+ }
+ }
+
+ ns_debug(ns_log_default, 12, "nlabels of \"%s\" -> %d", dname,
+ count);
+ return (count);
+}
+
+/*
+ * Get current system time and put it in a global.
+ */
+void
+gettime(struct timeval *ttp) {
+ if (gettimeofday(ttp, NULL) < 0)
+ ns_error(ns_log_default, "gettimeofday: %s", strerror(errno));
+}
+
+/*
+ * This is useful for tracking down lost file descriptors.
+ */
+int
+my_close(int fd) {
+ int s;
+
+ do {
+ errno = 0;
+ s = close(fd);
+ } while (s < 0 && errno == EINTR);
+
+ if (s < 0 && errno != EBADF)
+ ns_info(ns_log_default, "close(%d) failed: %s", fd,
+ strerror(errno));
+ else
+ ns_debug(ns_log_default, 3, "close(%d) succeeded", fd);
+ return (s);
+}
+
+/*
+ * This is useful for tracking down lost file descriptors.
+ */
+int
+my_fclose(FILE *fp) {
+ int fd = fileno(fp),
+ s = fclose(fp);
+
+ if (s < 0)
+ ns_info(ns_log_default, "fclose(%d) failed: %m", fd,
+ strerror(errno));
+ else
+ ns_debug(ns_log_default, 3, "fclose(%d) succeeded", fd);
+ return (s);
+}
+
+/*
+ * Save a counted buffer and return a pointer to it.
+ */
+u_char *
+savebuf(const u_char *buf, size_t len, int needpanic) {
+ u_char *bp = (u_char *)memget(len);
+
+ if (bp == NULL) {
+ if (needpanic)
+ panic("savebuf: memget failed (%s)", strerror(errno));
+ else
+ return (NULL);
+ }
+ memcpy(bp, buf, len);
+ return (bp);
+}
+
+#ifdef DEBUG_STRINGS
+char *
+debug_newstr(size_t len, int needpanic, const char *file, int line) {
+ size_t size;
+
+ size = len + 3; /* 2 length bytes + NUL. */
+ printf("%s:%d: newstr %d\n", file, line, size);
+ return (__newstr(len, needpanic));
+}
+
+char *
+debug_savestr(const char *str, int needpanic, const char *file, int line) {
+ size_t len;
+
+ len = strlen(str);
+ len += 3; /* 2 length bytes + NUL. */
+ printf("%s:%d: savestr %d %s\n", file, line, len, str);
+ return (__savestr(str, needpanic));
+}
+
+void
+debug_freestr(char *str, const char *file, int line) {
+ u_char *buf, *bp;
+ size_t len;
+
+ buf = (u_char *)str - 2/*Len*/;
+ bp = buf;
+ NS_GET16(len, bp);
+ len += 3; /* 2 length bytes + NUL. */
+ printf("%s:%d: freestr %d %s\n", file, line, len, str);
+ __freestr(str);
+ return;
+}
+#endif /* DEBUG_STRINGS */
+
+/*
+ * Return a counted string buffer big enough for a string of length 'len'.
+ */
+char *
+__newstr(size_t len, int needpanic) {
+ u_char *buf, *bp;
+
+ REQUIRE(len <= 65536);
+
+ buf = (u_char *)memget(2/*Len*/ + len + 1/*Nul*/);
+ if (buf == NULL) {
+ if (needpanic)
+ panic("savestr: memget failed (%s)", strerror(errno));
+ else
+ return (NULL);
+ }
+ bp = buf;
+ NS_PUT16(len, bp);
+ return ((char *)bp);
+}
+
+/*
+ * Save a NUL terminated string and return a pointer to it.
+ */
+char *
+__savestr(const char *str, int needpanic) {
+ char *buf;
+ size_t len;
+
+ len = strlen(str);
+ if (len > 65536) {
+ if (needpanic)
+ ns_panic(ns_log_default, 1,
+ "savestr: string too long");
+ else
+ return (NULL);
+ }
+ buf = __newstr(len, needpanic);
+ memcpy(buf, str, len + 1);
+ return (buf);
+}
+
+void
+__freestr(char *str) {
+ u_char *buf, *bp;
+ size_t len;
+
+ buf = (u_char *)str - 2/*Len*/;
+ bp = buf;
+ NS_GET16(len, bp);
+ memput(buf, 2/*Len*/ + len + 1/*Nul*/);
+}
+
+char *
+checked_ctime(const time_t *t) {
+ char *ctime_result;
+
+ ctime_result = ctime(t);
+ if (ctime_result == NULL) {
+ ns_error(ns_log_default, "ctime() returned NULL!");
+ ctime_result = "<unknown time>\n";
+ }
+
+ return (ctime_result);
+}
+
+/*
+ * 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(long l) {
+ time_t t = (time_t)l;
+
+ return (checked_ctime(&t));
+}
diff --git a/contrib/bind/bin/named/ns_init.c b/contrib/bind/bin/named/ns_init.c
new file mode 100644
index 0000000..920bfeb
--- /dev/null
+++ b/contrib/bind/bin/named/ns_init.c
@@ -0,0 +1,512 @@
+#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.40 1998/04/07 18:11:58 halley Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#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 <ctype.h>
+#include <errno.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+#ifdef DEBUG
+static void content_zone(int, int);
+#endif
+
+/*
+ * 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(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(struct zoneinfo *zp, time_t timebase) {
+ zp->z_time = timebase + zp->z_retry;
+}
+
+/*
+ * Read configuration file and save it as internal state.
+ */
+void
+ns_init(const char *conffile) {
+ struct zoneinfo *zp;
+ static int loads = 0; /* number of times loaded */
+
+ ns_debug(ns_log_config, 1, "ns_init(%s)", conffile);
+ gettime(&tt);
+
+ if (loads == 0) {
+ zones = (struct zoneinfo *)memget(64 * sizeof *zones);
+ if (zones == NULL)
+ ns_panic(ns_log_config, 0,
+ "Not enough memory to allocate initial zones array");
+ memset(zones, 0, 64 * sizeof *zones);
+ 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 = savestr("", 1);
+ init_configuration();
+ } 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 DEBUG
+ if (debug >= 3) {
+ ns_debug(ns_log_config, 3, "content of zones before loading");
+ content_zone(nzones - 1, 3);
+ }
+#endif
+
+ load_configuration(conffile);
+
+ /* 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 BIND_UPDATE
+ /*
+ * A dynamic zone might have changed, so we
+ * need to dump it before removing it.
+ */
+ if ((zp->z_flags & Z_DYNAMIC) &&
+ ((zp->z_flags & Z_NEED_SOAUPDATE) ||
+ (zp->z_flags & Z_NEED_DUMP)))
+ (void)zonedump(zp);
+#endif
+ ns_stopxfrs(zp);
+ do_reload(zp->z_origin, zp->z_type, zp->z_class);
+ ns_notice(ns_log_config,
+ "%s zone \"%s\" (%s) removed",
+ zoneTypeString(zp), zp->z_origin,
+ p_class(zp->z_class));
+ free_zone_contents(zp, 1);
+ memset(zp, 0, sizeof(*zp));
+ }
+ }
+
+#ifdef DEBUG
+ if (debug >= 2) {
+ ns_debug(ns_log_config, 2, "content of zones after loading");
+ content_zone(nzones-1, 2);
+ }
+#endif
+
+ ns_debug(ns_log_config, 1, "exit ns_init()");
+ loads++;
+}
+
+void
+zoneinit(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);
+ if (result != -1) {
+ ns_stopxfrs(zp);
+ purge_zone(zp->z_origin, hashtab, zp->z_class);
+ }
+ 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;
+ sched_zone_maint(zp);
+ }
+ } else {
+ zp->z_flags |= Z_AUTH;
+ zp->z_flags &= ~Z_NEED_RELOAD;
+ ns_refreshtime(zp, tt.tv_sec);
+ sched_zone_maint(zp);
+ }
+}
+
+void
+do_reload(const char *domain, int type, int class) {
+ struct zoneinfo *zp;
+
+ ns_debug(ns_log_config, 1, "do_reload: %s %d %d",
+ *domain ? domain : ".", type, class);
+
+ /*
+ * Check if the zone has changed type. If so, we might not need to
+ * do any purging or parent reloading.
+ *
+ * If the new zone is a master zone, then it will have purged the
+ * old data and loaded, so we don't need to do anything.
+ *
+ * If the new zone is a slave or stub zone and has successfully loaded,
+ * then we don't need to do anything either.
+ *
+ * NOTE: we take care not to match ourselves.
+ */
+ if ((type != z_master &&
+ find_zone(domain, z_master, class) != NULL) ||
+ (type != z_slave &&
+ (zp = find_zone(domain, z_slave, class)) != NULL &&
+ zp->z_serial != 0) ||
+ (type != z_stub &&
+ (zp = find_zone(domain, z_stub, class)) != NULL &&
+ zp->z_serial != 0)
+ )
+ return;
+
+ /*
+ * Clean up any leftover data.
+ */
+ purge_zone(domain, hashtab, class);
+
+ /*
+ * Reload
+ */
+ while (*domain) {
+ const char *s;
+ int escaped;
+
+ /*
+ * XXX this is presentation level hair and belongs elsewhere.
+ */
+ escaped = 0;
+ for (s = domain; *s != '\0'; s++) {
+ if (!escaped) {
+ if (*s == '.')
+ break;
+ else if (*s == '\\')
+ escaped = 1;
+ } else
+ escaped = 0;
+ }
+
+ if (*s != '\0')
+ domain = s + 1; /* skip label and its separator */
+ else
+ domain = ""; /* root zone */
+
+ if ((zp = find_zone(domain, Z_STUB, class)) ||
+ (zp = find_zone(domain, Z_CACHE, class)) ||
+ (zp = find_zone(domain, Z_PRIMARY, class)) ||
+ (zp = find_zone(domain, Z_SECONDARY, class))) {
+
+ ns_debug(ns_log_config, 1, "do_reload: matched %s",
+ *domain ? domain : ".");
+
+ if (zp->z_type == Z_CACHE)
+ purge_zone(zp->z_origin, fcachetab,
+ zp->z_class);
+ else
+ purge_zone(zp->z_origin, hashtab, zp->z_class);
+
+ zp->z_flags &= ~Z_AUTH;
+
+ switch (zp->z_type) {
+ case Z_SECONDARY:
+ case Z_STUB:
+ zoneinit(zp);
+ break;
+ case Z_PRIMARY:
+ if (db_load(zp->z_source, zp->z_origin, zp, 0)
+ == 0)
+ zp->z_flags |= Z_AUTH;
+ break;
+ case Z_CACHE:
+ (void)db_load(zp->z_source, zp->z_origin, zp,
+ 0);
+ break;
+ }
+ break;
+ }
+ }
+}
+
+#ifdef DEBUG
+/* prints out the content of zones */
+static void
+content_zone(int end, int level) {
+ int i;
+
+ for (i = 1; i <= end; i++) {
+ printzoneinfo(i, ns_log_config, level);
+ }
+}
+#endif
+
+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 = domain_ctx;
+
+ 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:
+ panic("impossible condition in ns_ownercontext()",
+ NULL);
+ }
+ break;
+ case T_MB:
+ case T_MG:
+ context = mailname_ctx;
+ break;
+ default:
+ /* Nothing to do. */
+ break;
+ }
+ return (context);
+}
+
+int
+ns_nameok(const char *name, int class, struct zoneinfo *zp,
+ enum transport transport,
+ enum context context,
+ const char *owner,
+ struct in_addr source)
+{
+ enum severity severity = not_set;
+ int ok = 1;
+
+ if (zp != NULL)
+ severity = zp->z_checknames;
+ if (severity == not_set)
+ severity = server_options->check_names[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:
+ ns_panic(ns_log_default, 1,
+ "unexpected context %d in ns_nameok", (int)context);
+ }
+ if (!ok) {
+ char *s, *o;
+
+ if (source.s_addr == INADDR_ANY)
+ s = savestr(transport_strings[transport], 0);
+ else {
+ s = newstr(strlen(transport_strings[transport]) +
+ sizeof " from [000.000.000.000]", 0);
+ if (s)
+ sprintf(s, "%s from [%s]",
+ transport_strings[transport],
+ inet_ntoa(source));
+ }
+ if (strcasecmp(owner, name) == 0)
+ o = savestr("", 0);
+ else {
+ const char *t = (*owner == '\0') ? "." : owner;
+
+ o = newstr(strlen(t) + sizeof " (owner \"\")", 0);
+ if (o)
+ sprintf(o, " (owner \"%s\")", t);
+ }
+ /*
+ * We use log_write directly here to avoid duplicating
+ * the message formatting and arguments.
+ */
+ log_write(log_ctx, ns_log_default,
+ (transport == response_trans) ?
+ log_info : log_notice,
+ "%s name \"%s\"%s %s (%s) is invalid - %s",
+ context_strings[context],
+ name, o != NULL ? o : "[memget failed]",
+ p_class(class),
+ s != NULL ? s : "[memget failed]",
+ (severity == fail) ?
+ "rejecting" : "proceeding anyway");
+ if (severity == warn)
+ ok = 1;
+ if (s != NULL)
+ freestr(s);
+ if (o != NULL)
+ freestr(o);
+ }
+ return (ok);
+}
+
+int
+ns_wildcard(const char *name) {
+ if (*name != '*')
+ return (0);
+ return (*++name == '\0');
+}
+
+void
+ns_shutdown() {
+ struct zoneinfo *zp;
+
+ /* Erase zones. */
+ for (zp = &zones[0]; zp < &zones[nzones]; zp++) {
+ if (zp->z_type) {
+ if (zp->z_type != z_hint) {
+ ns_stopxfrs(zp);
+ purge_zone(zp->z_origin, hashtab, zp->z_class);
+ }
+ free_zone_contents(zp, 1);
+ }
+ }
+ memput(zones, ((nzones / 64) + 1) * 64 * sizeof *zones);
+
+ /* Erase the cache. */
+ clean_cache(hashtab, 1);
+ hashtab->h_cnt = 0; /* ??? */
+ rm_hash(hashtab);
+ clean_cache(fcachetab, 1);
+ fcachetab->h_cnt = 0; /* ??? */
+ rm_hash(fcachetab);
+
+#ifdef BIND_NOTIFY
+ db_cancel_pending_notifies();
+#endif
+ freeComplaints();
+ shutdown_configuration();
+}
diff --git a/contrib/bind/bin/named/ns_lexer.c b/contrib/bind/bin/named/ns_lexer.c
new file mode 100644
index 0000000..fe319fa
--- /dev/null
+++ b/contrib/bind/bin/named/ns_lexer.c
@@ -0,0 +1,750 @@
+#if !defined(lint) && !defined(SABER)
+static char rcsid[] = "$Id: ns_lexer.c,v 8.12 1997/12/04 08:11:52 halley Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "named.h"
+#include "ns_parser.h"
+#include "ns_parseutil.h"
+#include "ns_lexer.h"
+
+typedef enum lexer_state {
+ scan, number, identifier, ipv4, quoted_string
+} LexerState;
+
+#define LEX_EOF 0x01
+
+typedef struct lexer_file_context {
+ const char * name;
+ FILE * stream;
+ int line_number;
+ LexerState state;
+ u_int flags;
+ int warnings;
+ int errors;
+ struct lexer_file_context *
+ next;
+} *LexerFileContext;
+
+LexerFileContext current_file = NULL;
+
+#define LEX_LAST_WAS_DOT 0x01
+#define LEX_CONSECUTIVE_DOTS 0x02
+
+typedef struct lexer_identifier {
+ char buffer[LEX_MAX_IDENT_SIZE+1];
+ int index;
+ int num_dots;
+ unsigned int flags;
+} *LexerIdentifier;
+
+static LexerIdentifier id;
+
+static char special_chars[256];
+
+#define whitespace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
+#define domain_char(c) (isalnum((c)) || (c) == '.' || (c) == '-')
+#define special_char(c) (special_chars[(c)] == 1)
+#define identifier_char(c) (!whitespace(c) && !special_char(c))
+
+static int last_token;
+static YYSTYPE last_yylval;
+
+static int lexer_initialized = 0;
+
+/*
+ * Problem Reporting
+ */
+
+static char *
+token_to_text(int token, YYSTYPE lval) {
+ static char buffer[LEX_MAX_IDENT_SIZE+50];
+
+ if (token < 128) {
+ if (token == 0)
+ strcpy(buffer, "<end of file>");
+ else
+ sprintf(buffer, "'%c'", token);
+ } else {
+ switch (token) {
+ case L_EOS:
+ strcpy(buffer, ";");
+ break;
+ case L_STRING:
+ sprintf(buffer, "'%s'", lval.cp);
+ break;
+ case L_QSTRING:
+ sprintf(buffer, "\"%s\"", lval.cp);
+ break;
+ case L_IPADDR:
+ sprintf(buffer, "%s", inet_ntoa(lval.ip_addr));
+ break;
+ case L_NUMBER:
+ sprintf(buffer, "%ld", lval.num);
+ break;
+ case L_END_INCLUDE:
+ sprintf(buffer, "<end of include>");
+ break;
+ default:
+ sprintf(buffer, "%s", lval.cp);
+ }
+ }
+
+ return (buffer);
+}
+
+static char where[MAXPATHLEN + 100];
+static char message[20480];
+
+static void
+parser_complain(int is_warning, int print_last_token, const char *format,
+ va_list args)
+{
+ LexerFileContext lf;
+ int severity;
+
+ if (is_warning) {
+ severity = log_warning;
+ } else {
+ severity = log_error;
+ }
+
+ INSIST(current_file != NULL);
+ if (current_file->next != NULL) {
+ for (lf = current_file; lf != NULL; lf = lf->next) {
+ log_write(log_ctx, ns_log_parser, severity,
+ "%s '%s' line %d",
+ (lf == current_file) ?
+ "In" : "included from",
+ lf->name, lf->line_number);
+ }
+ }
+ sprintf(where, "%s:%d: ", current_file->name,
+ current_file->line_number);
+ vsprintf(message, format, args);
+ if (print_last_token)
+ log_write(log_ctx, ns_log_parser, severity, "%s%s near %s",
+ where, message,
+ token_to_text(last_token, last_yylval));
+ else
+ log_write(log_ctx, ns_log_parser, severity,
+ "%s%s", where, message);
+}
+
+int
+parser_warning(int print_last_token, const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ parser_complain(1, print_last_token, format, args);
+ va_end(args);
+ current_file->warnings++;
+ return (1);
+}
+
+int
+parser_error(int print_last_token, const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ parser_complain(0, print_last_token, format, args);
+ va_end(args);
+ current_file->errors++;
+ return (1);
+}
+
+void
+yyerror(const char *message) {
+ parser_error(1, message);
+}
+
+/*
+ * Keywords
+ */
+
+struct keyword {
+ char *name;
+ int token;
+};
+
+/*
+ * "keywords" is an array of the keywords which are the fixed syntactic
+ * elements of the configuration file. Each keyword has a string version
+ * of the keyword and a token id, which should be an identifier which
+ * matches that in a %token statement inside the parser.y file.
+ */
+static struct keyword keywords[] = {
+ {"acl", T_ACL},
+ {"address", T_ADDRESS},
+ {"algorithm", T_ALGID},
+ {"allow-query", T_ALLOW_QUERY},
+ {"allow-transfer", T_ALLOW_TRANSFER},
+ {"allow-update", T_ALLOW_UPDATE},
+ {"also-notify", T_ALSO_NOTIFY},
+ {"auth-nxdomain", T_AUTH_NXDOMAIN},
+ {"bogus", T_BOGUS},
+ {"category", T_CATEGORY},
+ {"channel", T_CHANNEL},
+ {"check-names", T_CHECK_NAMES},
+ {"cleaning-interval", T_CLEAN_INTERVAL},
+ {"coresize", T_CORESIZE},
+ {"datasize", T_DATASIZE},
+ {"deallocate-on-exit", T_DEALLOC_ON_EXIT},
+ {"debug", T_DEBUG},
+ {"default", T_DEFAULT},
+ {"directory", T_DIRECTORY},
+ {"dump-file", T_DUMP_FILE},
+ {"dynamic", T_DYNAMIC},
+ {"fail", T_FAIL},
+ {"fake-iquery", T_FAKE_IQUERY},
+ {"false", T_FALSE},
+ {"fetch-glue", T_FETCH_GLUE},
+ {"file", T_FILE},
+ {"files", T_FILES},
+ {"first", T_FIRST},
+ {"forward", T_FORWARD},
+ {"forwarders", T_FORWARDERS},
+ {"hint", T_HINT},
+ {"host-statistics", T_HOSTSTATS},
+ {"if-no-answer", T_IF_NO_ANSWER},
+ {"if-no-domain", T_IF_NO_DOMAIN},
+ {"ignore", T_IGNORE},
+ {"include", T_INCLUDE},
+ {"interface-interval", T_INTERFACE_INTERVAL},
+ {"key", T_SEC_KEY},
+ {"keys", T_KEYS},
+ {"listen-on", T_LISTEN_ON},
+ {"logging", T_LOGGING},
+ {"many-answers", T_MANY_ANSWERS},
+ {"master", T_MASTER},
+ {"masters", T_MASTERS},
+ {"max-transfer-time-in", T_MAX_TRANSFER_TIME_IN},
+ {"memstatistics-file", T_MEMSTATS_FILE},
+ {"multiple-cnames", T_MULTIPLE_CNAMES},
+ {"named-xfer", T_NAMED_XFER},
+ {"no", T_NO},
+ {"notify", T_NOTIFY},
+ {"null", T_NULL_OUTPUT},
+ {"one-answer", T_ONE_ANSWER},
+ {"only", T_ONLY},
+ {"options", T_OPTIONS},
+ {"pid-file", T_PIDFILE},
+ {"port", T_PORT},
+ {"print-category", T_PRINT_CATEGORY},
+ {"print-severity", T_PRINT_SEVERITY},
+ {"print-time", T_PRINT_TIME},
+ {"query-source", T_QUERY_SOURCE},
+ {"recursion", T_RECURSION},
+ {"response", T_RESPONSE},
+ {"secret", T_SECRET},
+ {"server", T_SERVER},
+ {"severity", T_SEVERITY},
+ {"size", T_SIZE},
+ {"slave", T_SLAVE},
+ {"stacksize", T_STACKSIZE},
+ {"statistics-file", T_STATS_FILE},
+ {"statistics-interval", T_STATS_INTERVAL},
+ {"stub", T_STUB},
+ {"syslog", T_SYSLOG},
+ {"topology", T_TOPOLOGY},
+ {"transfer-format", T_TRANSFER_FORMAT},
+ {"transfer-source", T_TRANSFER_SOURCE},
+ {"transfers", T_TRANSFERS},
+ {"transfers-in", T_TRANSFERS_IN},
+ {"transfers-out", T_TRANSFERS_OUT},
+ {"transfers-per-ns", T_TRANSFERS_PER_NS},
+ {"true", T_TRUE},
+ {"type", T_TYPE},
+ {"unlimited", T_UNLIMITED},
+ {"versions", T_VERSIONS},
+ {"warn", T_WARN},
+ {"yes", T_YES},
+ {"zone", T_ZONE},
+ {(char *) NULL, 0},
+};
+
+/*
+ * The table size should be a prime chosen to minimize collisions.
+ */
+#define KEYWORD_TABLE_SIZE 461
+
+static symbol_table keyword_table = NULL;
+
+static void
+init_keywords() {
+ struct keyword *k;
+ symbol_value value;
+
+ if (keyword_table != NULL)
+ free_symbol_table(keyword_table);
+ keyword_table = new_symbol_table(KEYWORD_TABLE_SIZE, NULL);
+ for (k = keywords; k->name != NULL; k++) {
+ value.integer = k->token;
+ define_symbol(keyword_table, k->name, 0, value, 0);
+ }
+ dprint_symbol_table(99, keyword_table);
+}
+
+/*
+ * File Contexts
+ */
+
+void
+lexer_begin_file(const char *filename, FILE *stream) {
+ LexerFileContext lf;
+
+ if (stream == NULL) {
+ stream = fopen(filename, "r");
+ if (stream == NULL) {
+ parser_error(0, "couldn't open include file '%s'",
+ filename);
+ return;
+ }
+ }
+ lf = (LexerFileContext)memget(sizeof (struct lexer_file_context));
+ if (lf == NULL)
+ panic("memget failed in lexer_begin_file", NULL);
+ INSIST(stream != NULL);
+ lf->stream = stream;
+ lf->name = filename; /* note copy by reference */
+ lf->line_number = 1;
+ lf->state = scan;
+ lf->flags = 0;
+ lf->warnings = 0;
+ lf->errors = 0;
+ lf->next = current_file;
+ current_file = lf;
+}
+
+void
+lexer_end_file(void) {
+ LexerFileContext lf;
+
+ INSIST(current_file != NULL);
+ lf = current_file;
+ current_file = lf->next;
+ fclose(lf->stream);
+ memput(lf, sizeof *lf);
+}
+
+/*
+ * Character Input
+ */
+
+static void
+scan_to_comment_end(int c_plus_plus_style) {
+ int c, nc;
+ int done = 0;
+ int prev_was_star = 0;
+
+ while (!done) {
+ c = getc(current_file->stream);
+ switch (c) {
+ case EOF:
+ if (!c_plus_plus_style)
+ parser_error(0, "EOF in comment");
+ current_file->flags |= LEX_EOF;
+ done = 1;
+ break;
+ case '*':
+ prev_was_star = 1;
+ break;
+ case '/':
+ if (prev_was_star && !c_plus_plus_style)
+ done = 1;
+ prev_was_star = 0;
+ break;
+ case '\n':
+ if (c_plus_plus_style) {
+ /* don't consume the newline because
+ we want it to be a delimiter for
+ anything before the comment
+ started */
+ ungetc(c, current_file->stream);
+ done = 1;
+ } else {
+ current_file->line_number++;
+ }
+ prev_was_star = 0;
+ break;
+ default:
+ prev_was_star = 0;
+ }
+ }
+}
+
+int
+get_next_char(int comment_ok) {
+ int c, nc;
+
+ if (current_file->flags & LEX_EOF)
+ return (EOF);
+
+ c = getc(current_file->stream);
+
+ if (comment_ok) {
+ while (c == '/' || c == '#') {
+ if (c == '#') {
+ scan_to_comment_end(1);
+ if (current_file->flags & LEX_EOF)
+ return (EOF);
+ c = getc(current_file->stream);
+ } else {
+ nc = getc(current_file->stream);
+ switch (nc) {
+ case EOF:
+ current_file->flags |= LEX_EOF;
+ return ('/');
+ case '*':
+ case '/':
+ scan_to_comment_end((nc == '/'));
+ if (current_file->flags & LEX_EOF)
+ return (EOF);
+ c = getc(current_file->stream);
+ break;
+ default:
+ ungetc((nc), current_file->stream);
+ return ('/');
+ }
+ }
+ }
+ }
+
+ if (c == EOF)
+ current_file->flags |= LEX_EOF;
+ else if (c == '\n')
+ current_file->line_number++;
+ return (c);
+}
+
+void
+put_back_char(int c) {
+ if (c == EOF)
+ current_file->flags |= LEX_EOF;
+ else {
+ ungetc((c), current_file->stream);
+ if (c == '\n')
+ current_file->line_number--;
+ }
+}
+
+
+/*
+ * Identifiers
+ */
+
+static void
+clear_identifier(LexerIdentifier id) {
+ INSIST(id != NULL);
+ id->index = 0;
+ id->num_dots = 0;
+ id->flags = 0;
+}
+
+static char *
+dup_identifier(LexerIdentifier id) {
+ char *duplicate;
+
+ INSIST(id != NULL);
+ duplicate = savestr(id->buffer, 1);
+ return (duplicate);
+}
+
+static void
+finish_identifier(LexerIdentifier id) {
+ INSIST(id != NULL && id->index < LEX_MAX_IDENT_SIZE);
+ id->buffer[id->index] = '\0';
+}
+
+static void
+add_to_identifier(LexerIdentifier id, int c) {
+ INSIST(id != NULL);
+ id->buffer[id->index] = c;
+ id->index++;
+ if (id->index >= LEX_MAX_IDENT_SIZE) {
+ parser_error(0, "identifier too long");
+ current_file->state = scan;
+ /* discard chars until we hit a non-identifier char */
+ while (identifier_char(c)) {
+ c = get_next_char(1);
+ }
+ put_back_char(c);
+ clear_identifier(id);
+ } else {
+ if (c == '.') {
+ if (id->flags & LEX_LAST_WAS_DOT)
+ id->flags |= LEX_CONSECUTIVE_DOTS;
+ id->flags |= LEX_LAST_WAS_DOT;
+ id->num_dots++;
+ } else {
+ id->flags &= ~LEX_LAST_WAS_DOT;
+ }
+ }
+}
+
+/*
+ * yylex() -- return the next token from the current input stream
+ */
+int
+yylex() {
+ int c, i;
+ int comment_ok = 1;
+ int token = -1;
+ symbol_value value;
+
+ while (token < 0) {
+ c = get_next_char(comment_ok);
+ switch(current_file->state) {
+ case scan:
+ if (c == EOF) {
+ if (current_file->next == NULL)
+ /*
+ * We don't want to call
+ * lexer_end_file() here because we
+ * want to keep the toplevel file
+ * context to log errors against.
+ */
+ token = 0;
+ else {
+ lexer_end_file();
+ token = L_END_INCLUDE;
+ }
+ break;
+ }
+ if (whitespace(c))
+ break;
+ if (identifier_char(c)) {
+ if (isdigit(c))
+ current_file->state = number;
+ else
+ current_file->state = identifier;
+ clear_identifier(id);
+ add_to_identifier(id, c);
+ } else
+ if (special_char(c)) {
+ if (c == ';') {
+ token = L_EOS;
+ break;
+ }
+ if (c == '"') {
+ clear_identifier(id);
+ current_file->state =
+ quoted_string;
+ comment_ok = 0;
+ break;
+ }
+ token = c;
+ } else {
+ parser_error(0,
+ "invalid character '%c'",
+ c);
+ }
+ break;
+
+ case number:
+ if (identifier_char(c)) {
+ if (!isdigit(c))
+ current_file->state =
+ (c == '.') ? ipv4 : identifier;
+ add_to_identifier(id, c);
+ } else {
+ put_back_char(c);
+ current_file->state = scan;
+ finish_identifier(id);
+ yylval.num = atoi(id->buffer);
+ token = L_NUMBER;
+ }
+ break;
+
+ case identifier:
+ if (identifier_char(c)) {
+ add_to_identifier(id, c);
+ } else {
+ put_back_char(c);
+ current_file->state = scan;
+ finish_identifier(id);
+ /* is it a keyword? */
+ if (lookup_symbol(keyword_table, id->buffer,
+ 0, &value)) {
+ yylval.cp = id->buffer;
+ token = value.integer;
+ } else {
+ yylval.cp = dup_identifier(id);
+ token = L_STRING;
+ }
+ }
+ break;
+
+ case ipv4:
+ if (identifier_char(c)) {
+ if (!isdigit(c)) {
+ if (c != '.' ||
+ (id->flags & LEX_CONSECUTIVE_DOTS))
+ current_file->state =
+ identifier;
+ }
+ add_to_identifier(id, c);
+ } else {
+ put_back_char(c);
+ if (id->num_dots > 3 ||
+ (id->flags & LEX_LAST_WAS_DOT))
+ current_file->state = identifier;
+ else {
+ if (id->num_dots == 1) {
+ add_to_identifier(id, '.');
+ add_to_identifier(id, '0');
+ add_to_identifier(id, '.');
+ add_to_identifier(id, '0');
+ } else if (id->num_dots == 2) {
+ add_to_identifier(id, '.');
+ add_to_identifier(id, '0');
+ }
+ current_file->state = scan;
+ finish_identifier(id);
+ token = L_IPADDR;
+ if (inet_aton(id->buffer,
+ &(yylval.ip_addr))==0) {
+ yylval.cp = dup_identifier(id);
+ token = L_STRING;
+ }
+ }
+ }
+ break;
+
+ case quoted_string:
+ if (c == EOF) {
+ parser_error(0, "EOF in quoted string");
+ return 0;
+ } else {
+ if (c == '"') {
+ comment_ok = 1;
+ current_file->state = scan;
+ finish_identifier(id);
+ yylval.cp = dup_identifier(id);
+ token = L_QSTRING;
+ } else {
+ /* XXX add backslash escapes here */
+ add_to_identifier(id, c);
+ }
+ }
+ break;
+
+ default:
+ panic("unhandled state in yylex", NULL);
+ }
+ }
+
+ last_token = token;
+ last_yylval = yylval;
+ return (token);
+}
+
+/*
+ * Initialization
+ */
+
+symbol_table constants;
+
+static void
+import_constants(const struct ns_sym *s, int type) {
+ symbol_value value;
+ for ((void)NULL; s != NULL && s->name != NULL; s++) {
+ value.integer = s->number;
+ define_symbol(constants, s->name, type, value, 0);
+ }
+}
+
+static void
+import_res_constants(const struct res_sym *r, int type) {
+ symbol_value value;
+ for ((void)NULL; r != NULL && r->name != NULL; r++) {
+ value.integer = r->number;
+ define_symbol(constants, r->name, type, value, 0);
+ }
+}
+
+#define CONSTANTS_TABLE_SIZE 397 /* should be prime */
+
+static void
+import_all_constants() {
+ constants = new_symbol_table(CONSTANTS_TABLE_SIZE, NULL);
+ import_res_constants(__p_class_syms, SYM_CLASS);
+ import_constants(category_constants, SYM_CATEGORY);
+ import_constants(logging_constants, SYM_LOGGING);
+ import_constants(syslog_constants, SYM_SYSLOG);
+}
+
+void
+lexer_initialize() {
+ memset(special_chars, 0, sizeof special_chars);
+ special_chars[';'] = 1;
+ special_chars['{'] = 1;
+ special_chars['}'] = 1;
+ special_chars['!'] = 1;
+ special_chars['/'] = 1;
+ special_chars['"'] = 1;
+ special_chars['*'] = 1;
+ id = (LexerIdentifier)memget(sizeof (struct lexer_identifier));
+ if (id == NULL)
+ panic("memget failed in init_once", NULL);
+ init_keywords();
+ import_all_constants();
+ lexer_initialized = 1;
+}
+
+void
+lexer_setup(void) {
+ REQUIRE(lexer_initialized);
+
+ current_file = NULL; /* XXX should we INSIST(current_file==NULL)? */
+ INSIST(id != NULL);
+}
+
+void
+lexer_shutdown(void) {
+ REQUIRE(lexer_initialized);
+
+ free_symbol_table(keyword_table);
+ free_symbol_table(constants);
+ memput(id, sizeof (struct lexer_identifier));
+ lexer_initialized = 0;
+}
diff --git a/contrib/bind/bin/named/ns_lexer.h b/contrib/bind/bin/named/ns_lexer.h
new file mode 100644
index 0000000..3491df3
--- /dev/null
+++ b/contrib/bind/bin/named/ns_lexer.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#ifndef NS_LEXER_H
+#define NS_LEXER_H
+
+/*
+ * Note: <stdio.h> and "ns_parseutil.h" must be included
+ * before this file is included.
+ */
+
+#define LEX_MAX_IDENT_SIZE 1024
+
+#define SYM_CLASS 0x01
+#define SYM_CATEGORY 0x02
+#define SYM_LOGGING 0x04
+#define SYM_SYSLOG 0x08
+
+int parser_warning(int, const char *, ...);
+int parser_error(int, const char *, ...);
+void yyerror(const char *);
+void lexer_begin_file(const char *, FILE *);
+void lexer_end_file(void);
+int yylex(void);
+void lexer_initialize(void);
+void lexer_setup(void);
+void lexer_shutdown(void);
+
+extern symbol_table constants;
+
+#endif /* NS_LEXER_H */
diff --git a/contrib/bind/bin/named/ns_main.c b/contrib/bind/bin/named/ns_main.c
new file mode 100644
index 0000000..a4b4360
--- /dev/null
+++ b/contrib/bind/bin/named/ns_main.c
@@ -0,0 +1,2200 @@
+#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.65 1998/04/06 23:45:32 halley Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#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, 1996, 1997 Internet Software Consortium\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * Internet Name server (see RCF1035 & others).
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifdef SVR4 /* XXX */
+# include <sys/sockio.h>
+#else
+# include <sys/mbuf.h>
+#endif
+
+#include <netinet/in.h>
+#include <net/route.h>
+#include <net/if.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <resolv.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+#include <isc/list.h>
+
+#include "port_after.h"
+
+#ifdef HAVE_GETRUSAGE /* XXX */
+#include <sys/resource.h>
+#endif
+
+#define MAIN_PROGRAM
+#include "named.h"
+#undef MAIN_PROGRAM
+
+ /* list of interfaces */
+static LIST(struct _interface) iflist;
+static int iflist_initialized = 0;
+
+ /* UDP receive, TCP send buffer size */
+static const int rbufsize = 8 * 1024,
+ /* TCP send window size */
+ sbufsize = 16 * 1024;
+
+static u_int16_t nsid_state;
+static int needs;
+
+static struct qstream *sq_add(void);
+static int opensocket_d(interface *),
+ opensocket_s(interface *);
+static void sq_query(struct qstream *),
+ dq_remove(interface *),
+ ns_handle_needs(void);
+static int sq_dowrite(struct qstream *);
+static void use_desired_debug(void);
+static void stream_write(evContext, void *, int, int);
+
+static interface * if_find(struct in_addr, u_int16_t port);
+
+static int sq_here(struct qstream *);
+
+static void stream_accept(evContext, void *, int,
+ const void *, int,
+ const void *, int),
+ stream_getlen(evContext, void *, int, int),
+ stream_getmsg(evContext, void *, int, int),
+ datagram_read(evContext, void *, int, int),
+ dispatch_message(u_char *, int, int,
+ struct qstream *,
+ struct sockaddr_in, int,
+ interface *);
+static void stream_send(evContext, void *, int,
+ const void *, int,
+ const void *, int);
+static void init_signals(void);
+static void set_signal_handler(int, SIG_FN (*)());
+static int only_digits(const char *);
+
+static void
+usage() {
+ fprintf(stderr,
+"Usage: named [-d #] [-q] [-r] [-f] [-p port] [[-b|-c] configfile]\n");
+#ifdef CAN_CHANGE_ID
+ fprintf(stderr,
+" [-u (username|uid)] [-g (groupname|gid)]\n");
+#endif
+#ifdef HAVE_CHROOT
+ fprintf(stderr,
+" [-t directory]\n");
+#endif
+ exit(1);
+}
+
+static char bad_p_option[] =
+"-p remote/local obsolete; use 'listen-on' in config file to specify local";
+
+static char bad_directory[] = "chdir failed for directory '%s': %s";
+
+/*ARGSUSED*/
+int
+main(int argc, char *argv[], char *envp[]) {
+ int n, udpcnt;
+ char *arg;
+ struct qstream *sp;
+ interface *ifp;
+ const int on = 1;
+ int rfd, size, len, debug_option;
+ char **argp, *p;
+ int ch;
+ FILE *fp; /* file descriptor for pid file */
+ struct passwd *pw;
+ struct group *gr;
+#ifdef HAVE_GETRUSAGE
+ struct rlimit rl;
+#endif
+
+ user_id = getuid();
+ group_id = getgid();
+
+ ns_port = htons(NAMESERVER_PORT);
+ desired_debug = debug;
+
+ /* 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);
+
+ (void) umask(022);
+
+ while ((ch = getopt(argc, argv, "b:c:d:g:p:t:u:w:qrf")) != EOF) {
+ switch (ch) {
+ case 'b':
+ case 'c':
+ if (conffile != NULL)
+ freestr(conffile);
+ conffile = savestr(optarg, 1);
+ break;
+
+ case 'd':
+ desired_debug = atoi(optarg);
+ if (desired_debug <= 0)
+ desired_debug = 1;
+ 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.
+ */
+ ns_port = htons((u_int16_t) atoi(optarg));
+ p = strchr(optarg, '/');
+ if (p) {
+ syslog(LOG_WARNING, bad_p_option);
+ fprintf(stderr, bad_p_option);
+ fputc('\n', stderr);
+ }
+ break;
+
+ case 'w':
+ if (chdir(optarg) < 0) {
+ syslog(LOG_CRIT, bad_directory, optarg,
+ strerror(errno));
+ fprintf(stderr, bad_directory, optarg,
+ strerror(errno));
+ fputc('\n', stderr);
+ exit(1);
+ }
+ break;
+#ifdef QRYLOG
+ case 'q':
+ qrylog = 1;
+ break;
+#endif
+
+ case 'r':
+ ns_setoption(OPTION_NORECURSE);
+ break;
+
+ case 'f':
+ foreground = 1;
+ break;
+
+ case 't':
+ chroot_dir = savestr(optarg, 1);
+ break;
+
+#ifdef CAN_CHANGE_ID
+ case 'u':
+ user_name = savestr(optarg, 1);
+ if (only_digits(user_name))
+ user_id = atoi(user_name);
+ else {
+ pw = getpwnam(user_name);
+ if (pw == NULL) {
+ fprintf(stderr,
+ "user \"%s\" unknown\n",
+ user_name);
+ exit(1);
+ }
+ user_id = pw->pw_uid;
+ if (group_name == NULL) {
+ char name[256];
+
+ sprintf(name, "%lu",
+ (u_long)pw->pw_gid);
+ group_name = savestr(name, 1);
+ group_id = pw->pw_gid;
+ }
+ }
+ break;
+
+ case 'g':
+ if (group_name != NULL)
+ freestr(group_name);
+ group_name = savestr(optarg, 1);
+ if (only_digits(group_name))
+ group_id = atoi(group_name);
+ else {
+ gr = getgrnam(group_name);
+ if (gr == NULL) {
+ fprintf(stderr,
+ "group \"%s\" unknown\n",
+ group_name);
+ exit(1);
+ }
+ group_id = gr->gr_gid;
+ }
+ break;
+#endif /* CAN_CHANGE_ID */
+
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc) {
+ if (conffile != NULL)
+ freestr(conffile);
+ conffile = savestr(*argv, 1);
+ argc--, argv++;
+ }
+ if (argc)
+ usage();
+
+ if (conffile == NULL)
+ conffile = savestr(_PATH_CONF, 1);
+
+ /*
+ * Make sure we don't inherit any open descriptors
+ * other than those that daemon() can deal with.
+ */
+ for (n = sysconf(_SC_OPEN_MAX) - 1; n >= 0; n--)
+ if (n != STDIN_FILENO &&
+ n != STDOUT_FILENO &&
+ n != STDERR_FILENO)
+ (void) close(n);
+
+ /*
+ * Chroot if desired.
+ */
+ if (chroot_dir != NULL) {
+#ifdef HAVE_CHROOT
+ if (chroot(chroot_dir) < 0) {
+ fprintf(stderr, "chroot %s failed: %s\n", chroot_dir,
+ strerror(errno));
+ exit(1);
+ }
+ if (chdir("/") < 0) {
+ fprintf(stderr, "chdir(\"/\") failed: %s\n",
+ strerror(errno));
+ exit(1);
+ }
+#else
+ fprintf(stderr, "warning: chroot() not available\n");
+ freestr(chroot_dir);
+ chroot_dir = NULL;
+#endif
+ }
+
+ /* Establish global event context. */
+ evCreate(&ev);
+
+ /*
+ * Set up logging.
+ */
+ n = LOG_PID;
+#ifdef LOG_NOWAIT
+ n |= LOG_NOWAIT;
+#endif
+#ifdef LOG_NDELAY
+ n |= LOG_NDELAY;
+#endif
+#if defined(LOG_CONS) && defined(USE_LOG_CONS)
+ n |= LOG_CONS;
+#endif
+#ifdef SYSLOG_42BSD
+ openlog("named", n);
+#else
+ openlog("named", n, LOG_DAEMON);
+#endif
+
+ init_logging();
+ set_assertion_failure_callback(ns_assertion_failed);
+
+#ifdef DEBUG
+ use_desired_debug();
+#endif
+
+ init_signals();
+
+ ns_notice(ns_log_default, "starting. %s", Version);
+
+ _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
+
+ nsid_init();
+
+ /*
+ * Initialize and load database.
+ */
+ gettime(&tt);
+ buildservicelist();
+ buildprotolist();
+ ns_init(conffile);
+ time(&boottime);
+ resettime = boottime;
+
+ /*
+ * Fork and go into background now that
+ * we've done any slow initialization
+ * and are ready to answer queries.
+ */
+
+ if (foreground == 0) {
+ if (daemon(1, 0))
+ ns_panic(ns_log_default, 1, "daemon: %s",
+ strerror(errno));
+ update_pid_file();
+ }
+
+ /* Check that udp checksums are on. */
+ ns_udp();
+
+ /*
+ * We waited until now to log this because we wanted logging to
+ * be set up the way the user prefers.
+ */
+ if (chroot_dir != NULL)
+ ns_info(ns_log_security, "chrooted to %s", chroot_dir);
+
+#ifdef CAN_CHANGE_ID
+ /*
+ * Set user and group if desired.
+ */
+ if (group_name != NULL) {
+ if (setgid(group_id) < 0)
+ ns_panic(ns_log_security, 1, "setgid(%s): %s",
+ group_name, strerror(errno));
+ ns_info(ns_log_security, "group = %s", group_name);
+ }
+ if (user_name != NULL) {
+ if (getuid() == 0 && initgroups(user_name, group_id) < 0)
+ ns_panic(ns_log_security, 1, "initgroups(%s, %d): %s",
+ user_name, (int)group_id, strerror(errno));
+ endgrent();
+ endpwent();
+ if (setuid(user_id) < 0)
+ ns_panic(ns_log_security, 1, "setuid(%s): %s",
+ user_name, strerror(errno));
+ ns_info(ns_log_security, "user = %s", user_name);
+ }
+#endif /* CAN_CHANGE_ID */
+
+ ns_notice(ns_log_default, "Ready to answer queries.");
+ gettime(&tt);
+ prime_cache();
+ for (;;) {
+ evEvent event;
+
+ if (needs)
+ ns_handle_needs();
+ INSIST_ERR(evGetNext(ev, &event, EV_WAIT) != -1);
+ INSIST_ERR(evDispatch(ev, event) != -1);
+ }
+ /* NOTREACHED */
+ return (0);
+}
+
+#ifndef IP_OPT_BUF_SIZE
+/* arbitrary size */
+#define IP_OPT_BUF_SIZE 50
+#endif
+
+static void
+stream_accept(evContext lev, void *uap, int rfd,
+ const void *lav, int lalen,
+ const void *rav, int ralen)
+{
+ interface *ifp = uap;
+ struct qstream *sp;
+ struct iovec iov;
+ int n, len;
+ const int on = 1;
+#ifdef IP_OPTIONS /* XXX */
+ u_char ip_opts[IP_OPT_BUF_SIZE];
+#endif
+ const struct sockaddr_in *la, *ra;
+
+ la = (const struct sockaddr_in *)lav;
+ ra = (const struct sockaddr_in *)rav;
+
+ INSIST(ifp != NULL);
+
+ if (rfd < 0) {
+ switch (errno) {
+ case EINTR:
+ case EAGAIN:
+#if (EWOULDBLOCK != EAGAIN)
+ case EWOULDBLOCK:
+#endif
+ case ECONNABORTED:
+#ifdef EPROTO
+ case EPROTO:
+#endif
+ case EHOSTUNREACH:
+ case EHOSTDOWN:
+ case ENETUNREACH:
+ case ENETDOWN:
+ case ECONNREFUSED:
+#ifdef ENONET
+ case ENONET:
+#endif
+ /*
+ * These errors are expected and harmless, so
+ * we ignore them.
+ */
+ return;
+ case EBADF:
+ case ENOTSOCK:
+ case EFAULT:
+ /*
+ * If one these happens, we're broken.
+ */
+ ns_panic(ns_log_default, 1, "accept: %s",
+ strerror(errno));
+ case EMFILE:
+ /*
+ * If we're out of file descriptors, find the least
+ * busy fd and close it. Then we'll return to the
+ * eventlib which will call us right back.
+ */
+ if (streamq) {
+ struct qstream *nextsp;
+ struct qstream *candidate = NULL;
+ time_t lasttime, maxctime = 0;
+
+ 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)
+ sq_remove(sp);
+ else if (lasttime > maxctime) {
+ candidate = sp;
+ maxctime = lasttime;
+ }
+ }
+ if (candidate)
+ sq_remove(candidate);
+ return;
+ }
+ /* fall through */
+ default:
+ /*
+ * Either we got an error we didn't expect, or we
+ * got EMFILE and didn't have anything left to close.
+ * Log it and press on.
+ */
+ ns_info(ns_log_default, "accept: %s", strerror(errno));
+ return;
+ }
+ }
+
+ /* Condition the socket. */
+
+/* XXX clean up */
+#if 0
+ if ((n = fcntl(rfd, F_GETFL, 0)) == -1) {
+ ns_info(ns_log_default, "fcntl(rfd, F_GETFL): %s",
+ strerror(errno));
+ (void) close(rfd);
+ return;
+ }
+ if (fcntl(rfd, F_SETFL, n|PORT_NONBLOCK) == -1) {
+ ns_info(ns_log_default, "fcntl(rfd, NONBLOCK): %s",
+ strerror(errno));
+ (void) close(rfd);
+ return;
+ }
+#endif
+#ifndef CANNOT_SET_SNDBUF
+ if (setsockopt(rfd, SOL_SOCKET, SO_SNDBUF,
+ (char*)&sbufsize, sizeof sbufsize) < 0) {
+ ns_info(ns_log_default, "setsockopt(rfd, SO_SNDBUF, %d): %s",
+ sbufsize, strerror(errno));
+ (void) close(rfd);
+ return;
+ }
+#endif
+ if (setsockopt(rfd, SOL_SOCKET, SO_KEEPALIVE,
+ (char *)&on, sizeof on) < 0) {
+ ns_info(ns_log_default, "setsockopt(rfd, KEEPALIVE): %s",
+ strerror(errno));
+ (void) close(rfd);
+ return;
+ }
+
+ /*
+ * We don't like IP options. Turn them off if the connection came in
+ * with any. log this event since it usually indicates a security
+ * problem.
+ */
+#if defined(IP_OPTIONS) /* XXX */
+ len = sizeof ip_opts;
+ if (getsockopt(rfd, IPPROTO_IP, IP_OPTIONS,
+ (char *)ip_opts, &len) < 0) {
+ ns_info(ns_log_default, "getsockopt(rfd, IP_OPTIONS): %s",
+ strerror(errno));
+ (void) close(rfd);
+ return;
+ }
+ if (len != 0) {
+ nameserIncr(ra->sin_addr, nssRcvdOpts);
+ if (!haveComplained(ina_ulong(ra->sin_addr),
+ (u_long)"rcvd ip options")) {
+ ns_info(ns_log_default,
+ "rcvd IP_OPTIONS from %s (ignored)",
+ sin_ntoa(*ra));
+ }
+ if (setsockopt(rfd, IPPROTO_IP, IP_OPTIONS, NULL, 0) < 0) {
+ ns_info(ns_log_default, "setsockopt(!IP_OPTIONS): %s",
+ strerror(errno));
+ (void) close(rfd);
+ }
+ }
+#endif
+
+ /* Create and populate a qsp for this socket. */
+ if ((sp = sq_add()) == NULL) {
+ (void) close(rfd);
+ return;
+ }
+ sp->s_rfd = rfd; /* stream file descriptor */
+ gettime(&tt);
+ sp->s_time = tt.tv_sec; /* last transaction time */
+ sp->s_from = *ra; /* address to respond to */
+ sp->s_ifp = ifp;
+ INSIST(sizeof sp->s_temp >= INT16SZ);
+ iov = evConsIovec(sp->s_temp, INT16SZ);
+ INSIST_ERR(evRead(lev, rfd, &iov, 1, stream_getlen, sp, &sp->evID_r)
+ != -1);
+ sp->flags |= STREAM_READ_EV;
+#ifdef DEBUG
+ if (debug)
+ ns_info(ns_log_default, "IP/TCP connection from %s (fd %d)",
+ sin_ntoa(sp->s_from), rfd);
+#endif
+}
+
+int
+tcp_send(struct qinfo *qp) {
+ struct qstream *sp;
+ int on = 1;
+
+ ns_debug(ns_log_default, 1, "tcp_send");
+ if ((sp = sq_add()) == NULL) {
+ return(SERVFAIL);
+ }
+ if ((sp->s_rfd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) == -1) {
+ sq_remove(sp);
+ return(SERVFAIL);
+ }
+
+ if (sq_openw(sp, qp->q_msglen + INT16SZ) == -1) {
+ sq_remove(sp);
+ return(SERVFAIL);
+ }
+ if (sq_write(sp, qp->q_msg, qp->q_msglen) == -1) {
+ sq_remove(sp);
+ return(SERVFAIL);
+ }
+
+ if (setsockopt(sp->s_rfd, SOL_SOCKET, SO_KEEPALIVE,
+ (char*)&on, sizeof(on)) < 0)
+ ns_info(ns_log_default,
+ "tcp_send: setsockopt(rfd, SO_KEEPALIVE): %s",
+ strerror(errno));
+ gettime(&tt);
+ sp->s_size = -1;
+ sp->s_time = tt.tv_sec; /* last transaction time */
+ sp->s_refcnt = 1;
+ sp->flags |= STREAM_DONE_CLOSE;
+ if (qp->q_fwd)
+ sp->s_from = qp->q_fwd->fwdaddr;
+ else
+ sp->s_from = qp->q_addr[qp->q_curaddr].ns_addr;
+ if (evConnect(ev, sp->s_rfd, &sp->s_from, sizeof(sp->s_from),
+ stream_send, sp, &sp->evID_c) == -1) {
+ sq_remove(sp);
+ return (SERVFAIL);
+ }
+ sp->flags |= STREAM_CONNECT_EV;
+ return(NOERROR);
+}
+
+static void
+stream_send(evContext lev, void *uap, int fd, const void *la, int lalen,
+ const void *ra, int ralen) {
+ struct qstream *sp = uap;
+
+ ns_debug(ns_log_default, 1, "stream_send");
+
+ sp->flags &= ~STREAM_CONNECT_EV;
+
+ if (fd == -1) {
+ /* connect failed */
+ sq_remove(sp);
+ return;
+ }
+ if (evSelectFD(ev, sp->s_rfd, EV_WRITE,
+ stream_write, sp, &sp->evID_w) < 0) {
+ sq_remove(sp);
+ return;
+ }
+ sp->flags |= STREAM_WRITE_EV;
+}
+
+static void
+stream_write(evContext ctx, void *uap, int fd, int evmask) {
+ struct qstream *sp = uap;
+ struct iovec iov;
+
+ ns_debug(ns_log_default, 1, "stream_write");
+ INSIST(evmask & EV_WRITE);
+ INSIST(fd == sp->s_rfd);
+ if (sq_dowrite(sp) < 0) {
+ sq_remove(sp);
+ return;
+ }
+ if (sp->s_wbuf_free != sp->s_wbuf_send)
+ return;
+
+ if (sp->s_wbuf) {
+ memput(sp->s_wbuf, sp->s_wbuf_end - sp->s_wbuf);
+ sp->s_wbuf = NULL;
+ }
+ (void) evDeselectFD(ev, sp->evID_w);
+ sp->flags &= ~STREAM_WRITE_EV;
+ sp->s_refcnt = 0;
+ iov = evConsIovec(sp->s_temp, INT16SZ);
+ INSIST_ERR(evRead(ctx, fd, &iov, 1, stream_getlen, sp, &sp->evID_r) !=
+ -1);
+ sp->flags |= STREAM_READ_EV;
+}
+
+static void
+stream_getlen(evContext lev, void *uap, int fd, int bytes) {
+ struct qstream *sp = uap;
+ struct iovec iov;
+
+ sp->flags &= ~STREAM_READ_EV;
+ if (bytes != INT16SZ) {
+ /*
+ * bytes == 0 is normal EOF; see if something unusual
+ * happened.
+ */
+ if (bytes < 0) {
+ /*
+ * ECONNRESET happens frequently and is not worth
+ * logging.
+ */
+ if (errno != ECONNRESET)
+ ns_info(ns_log_default,
+ "stream_getlen(%s): %s",
+ sin_ntoa(sp->s_from), strerror(errno));
+ } else if (bytes != 0)
+ ns_error(ns_log_default,
+ "stream_getlen(%s): unexpected byte count %d",
+ sin_ntoa(sp->s_from), bytes);
+ sq_remove(sp);
+ return;
+ }
+
+ /*
+ * Unpack the size, allocate memory for the query. This is
+ * tricky since in a low memory situation with possibly very
+ * large (64KB) queries, we want to make sure we can read at
+ * least the header since we need it to send back a SERVFAIL
+ * (owing to the out-of-memory condition).
+ */
+ sp->s_size = ns_get16(sp->s_temp);
+ ns_debug(ns_log_default, 5, "stream message: %d bytes", sp->s_size);
+
+ if (!(sp->flags & STREAM_MALLOC)) {
+ sp->s_bufsize = 64*1024-1; /* maximum tcp message size */
+ sp->s_buf = (u_char *)memget(sp->s_bufsize);
+ if (sp->s_buf != NULL)
+ sp->flags |= STREAM_MALLOC;
+ else {
+ sp->s_buf = sp->s_temp;
+ sp->s_bufsize = HFIXEDSZ;
+ }
+ }
+
+ iov = evConsIovec(sp->s_buf, sp->s_size);
+ if (evRead(lev, sp->s_rfd, &iov, 1, stream_getmsg, sp, &sp->evID_r)
+ == -1)
+ ns_panic(ns_log_default, 1, "evRead(fd %d): %s",
+ (void *)sp->s_rfd, strerror(errno));
+ sp->flags |= STREAM_READ_EV;
+}
+
+static void
+stream_getmsg(evContext lev, void *uap, int fd, int bytes) {
+ struct qstream *sp = uap;
+ int buflen, n;
+
+ sp->flags &= ~STREAM_READ_EV;
+ if (bytes == -1) {
+ ns_info(ns_log_default, "stream_getmsg(%s): %s",
+ sin_ntoa(sp->s_from), strerror(errno));
+ sq_remove(sp);
+ return;
+ }
+
+ gettime(&tt);
+ sp->s_time = tt.tv_sec;
+
+ ns_debug(ns_log_default, 5, "sp %#x rfd %d size %d time %d next %#x",
+ sp, sp->s_rfd, sp->s_size, sp->s_time, sp->s_next);
+ ns_debug(ns_log_default, 5, "\tbufsize %d bytes %d", sp->s_bufsize,
+ bytes);
+
+ /*
+ * Do we have enough memory for the query? If not, and if we have a
+ * query id, then we will send a SERVFAIL error back to the client.
+ */
+ if (bytes != sp->s_size) {
+ HEADER *hp = (HEADER *)sp->s_buf;
+
+ hp->qr = 1;
+ hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0);
+ hp->ancount = htons(0);
+ hp->qdcount = htons(0);
+ hp->nscount = htons(0);
+ hp->arcount = htons(0);
+ hp->rcode = SERVFAIL;
+ writestream(sp, sp->s_buf, HFIXEDSZ);
+ sp->flags |= STREAM_DONE_CLOSE;
+ return;
+ }
+
+ nameserIncr(sp->s_from.sin_addr, nssRcvdTCP);
+ sq_query(sp);
+ dispatch_message(sp->s_buf, bytes, sp->s_bufsize, sp, sp->s_from, -1,
+ sp->s_ifp);
+}
+
+static void
+datagram_read(evContext lev, void *uap, int fd, int evmask) {
+ interface *ifp = uap;
+ struct sockaddr_in from;
+ int from_len = sizeof from;
+ int n;
+ union {
+ HEADER h; /* Force alignment of 'buf'. */
+ u_char buf[PACKETSZ+1];
+ } u;
+
+ n = recvfrom(fd, (char *)u.buf, sizeof u.buf, 0,
+ (struct sockaddr *)&from, &from_len);
+
+ if (n < 0) {
+ switch (errno) {
+ case EINTR:
+ case EAGAIN:
+#if (EWOULDBLOCK != EAGAIN)
+ case EWOULDBLOCK:
+#endif
+ case EHOSTUNREACH:
+ case EHOSTDOWN:
+ case ENETUNREACH:
+ case ENETDOWN:
+ case ECONNREFUSED:
+#ifdef ENONET
+ case ENONET:
+#endif
+ /*
+ * These errors are expected and harmless, so we
+ * ignore them.
+ */
+ return;
+ case EBADF:
+ case ENOTCONN:
+ case ENOTSOCK:
+ case EFAULT:
+ /*
+ * If one these happens, we're broken.
+ */
+ ns_panic(ns_log_default, 1, "recvfrom: %s",
+ strerror(errno));
+ default:
+ /*
+ * An error we don't expect. Log it and press
+ * on.
+ */
+ ns_info(ns_log_default, "recvfrom: %s",
+ strerror(errno));
+ return;
+ }
+ }
+
+#ifndef BSD
+ /* Handle bogosity on systems that need it. */
+ if (n == 0)
+ return;
+#endif
+
+ ns_debug(ns_log_default, 1, "datagram from %s, fd %d, len %d",
+ sin_ntoa(from), fd, n);
+
+ if (n > PACKETSZ) {
+ /*
+ * The message is too big. It's probably a response to
+ * one of our questions, so we truncate it and press on.
+ */
+ n = trunc_adjust(u.buf, PACKETSZ, PACKETSZ);
+ ns_debug(ns_log_default, 1, "truncated oversize UDP packet");
+ }
+
+ gettime(&tt); /* Keep 'tt' current. */
+ dispatch_message(u.buf, n, PACKETSZ, NULL, from, fd, ifp);
+}
+
+static void
+dispatch_message(u_char *msg, int msglen, int buflen, struct qstream *qsp,
+ struct sockaddr_in from, int dfd, interface *ifp)
+{
+ HEADER *hp = (HEADER *)msg;
+
+ if (msglen < HFIXEDSZ) {
+ ns_debug(ns_log_default, 1, "dropping undersize message");
+ return;
+ }
+ if (hp->qr) {
+ ns_resp(msg, msglen, from, qsp);
+ if (qsp)
+ sq_done(qsp);
+ /* Now is a safe time for housekeeping. */
+ if (needs_prime_cache)
+ prime_cache();
+ } else if (ifp != NULL)
+ ns_req(msg, msglen, buflen, qsp, from, dfd);
+ else {
+ ns_notice(ns_log_security,
+ "refused query on non-query socket from %s",
+ sin_ntoa(from));
+ /* XXX Send refusal here. */
+ }
+}
+
+void
+getnetconf(int periodic_scan) {
+ struct ifconf ifc;
+ struct ifreq ifreq;
+ struct in_addr ina;
+ interface *ifp;
+ char buf[32768], *cp, *cplim;
+ u_int32_t nm;
+ time_t my_generation = time(NULL);
+ int s, cpsize;
+ int found;
+ listen_info li;
+ u_int16_t port;
+ ip_match_element ime;
+ u_char *mask_ptr;
+ struct in_addr mask;
+
+ ns_debug(ns_log_default, 1, "getnetconf(generation %lu)",
+ (u_long)my_generation);
+
+ /* Get interface list from system. */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ if (!periodic_scan)
+ ns_panic(ns_log_default, 1, "socket(SOCK_RAW): %s",
+ strerror(errno));
+ ns_error(ns_log_default, "socket(SOCK_RAW): %s",
+ strerror(errno));
+ return;
+ }
+
+ if (!iflist_initialized) {
+ INIT_LIST(iflist);
+ iflist_initialized = 1;
+ }
+
+ if (local_addresses != NULL)
+ free_ip_match_list(local_addresses);
+ local_addresses = new_ip_match_list();
+ if (local_networks != NULL)
+ free_ip_match_list(local_networks);
+ local_networks = new_ip_match_list();
+
+ ifc.ifc_len = sizeof buf;
+ ifc.ifc_buf = buf;
+ if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)
+ ns_panic(ns_log_default, 1, "get interface configuration: %s",
+ strerror(errno));
+
+ ns_debug(ns_log_default, 2, "getnetconf: SIOCGIFCONF: ifc_len = %d",
+ ifc.ifc_len);
+
+ /* Parse system's interface list and open some sockets. */
+ cplim = buf + ifc.ifc_len; /* skip over if's with big ifr_addr's */
+ for (cp = buf; cp < cplim; cp += cpsize) {
+ memcpy(&ifreq, cp, sizeof ifreq);
+#if defined HAVE_SA_LEN
+#ifdef FIX_ZERO_SA_LEN
+ if (ifreq.ifr_addr.sa_len == 0)
+ ifreq.ifr_addr.sa_len = 16;
+#endif
+ cpsize = sizeof ifreq.ifr_name + ifreq.ifr_addr.sa_len;
+#elif defined SIOCGIFCONF_ADDR
+ cpsize = sizeof ifreq;
+#else
+ cpsize = sizeof ifreq.ifr_name;
+ if (ioctl(s, SIOCGIFADDR, (char *)&ifreq) < 0) {
+ ns_notice(ns_log_default,
+ "get interface addr (%s): %s",
+ ifreq.ifr_name, strerror(errno));
+ continue;
+ }
+#endif
+ ina = ina_get((u_char *)&((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr);
+ if (ifreq.ifr_addr.sa_family != AF_INET) {
+ ns_debug(ns_log_default, 2,
+ "getnetconf: af %d != INET",
+ ifreq.ifr_addr.sa_family);
+ continue;
+ }
+ ns_debug(ns_log_default, 1,
+ "getnetconf: considering %s [%s]",
+ ifreq.ifr_name, inet_ntoa(ina));
+ /*
+ * Don't test IFF_UP, packets may still be received at this
+ * address if any other interface is up.
+ */
+ if (ina_hlong(ina) == INADDR_ANY) {
+ ns_debug(ns_log_default, 2,
+ "getnetconf: INADDR_ANY, ignoring.");
+ continue;
+ }
+
+ INSIST(server_options != NULL);
+ INSIST(server_options->listen_list != NULL);
+
+ found=0;
+ for (li = server_options->listen_list->first;
+ li != NULL;
+ li = li->next) {
+ if (ip_match_address(li->list, ina) > 0) {
+ found++;
+ /*
+ * Look for an already existing source
+ * interface address/port pair.
+ * This happens mostly when reinitializing.
+ * Also, if the machine has multiple point to
+ * point interfaces, then the local address
+ * may appear more than once.
+ */
+ ifp = if_find(ina, li->port);
+ if (ifp != NULL) {
+ ns_debug(ns_log_default, 1,
+ "dup interface addr [%s].%u (%s)",
+ inet_ntoa(ina),
+ ntohs(li->port),
+ ifreq.ifr_name);
+ ifp->gen = my_generation;
+ continue;
+ }
+
+ ifp = (interface *)memget(sizeof *ifp);
+ if (!ifp)
+ ns_panic(ns_log_default, 1,
+ "memget(interface)", NULL);
+ memset(ifp, 0, sizeof *ifp);
+ APPEND(iflist, ifp, link);
+ ifp->addr = ina;
+ ifp->port = li->port;
+ ifp->gen = my_generation;
+ ifp->flags = 0;
+ ifp->dfd = -1;
+ ifp->sfd = -1;
+ if (opensocket_d(ifp) < 0 ||
+ opensocket_s(ifp) < 0) {
+ dq_remove(ifp);
+ found = 0;
+ break;
+ }
+ ns_info(ns_log_default,
+ "listening on [%s].%u (%s)",
+ inet_ntoa(ina), ntohs(li->port),
+ ifreq.ifr_name);
+ }
+ }
+ if (!found)
+ ns_debug(ns_log_default, 1,
+ "not listening on addr [%s] (%s)",
+ inet_ntoa(ina), ifreq.ifr_name);
+
+ /*
+ * Add this interface's address to the list of local
+ * addresses if we haven't added it already.
+ */
+ if (ip_match_address(local_addresses, ina) < 0) {
+ ime = new_ip_match_pattern(ina, 32);
+ add_to_ip_match_list(local_addresses, ime);
+ }
+
+ /*
+ * Get interface flags.
+ */
+ if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+ ns_notice(ns_log_default, "get interface flags: %s",
+ strerror(errno));
+ continue;
+ }
+
+ if ((ifreq.ifr_flags & IFF_POINTOPOINT)) {
+ /*
+ * The local network for a PPP link is just the
+ * two ends of the link, so for each endpoint we
+ * add a pattern that will only match the endpoint.
+ */
+ if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
+ ns_notice(ns_log_default, "get dst addr: %s",
+ strerror(errno));
+ continue;
+ }
+
+ mask.s_addr = htonl(INADDR_BROADCAST);
+
+ /*
+ * Our end.
+ *
+ * Only add it if we haven't seen it before.
+ */
+ if (ip_match_network(local_networks, ina, mask) < 0) {
+ ime = new_ip_match_pattern(ina, 32);
+ add_to_ip_match_list(local_networks, ime);
+ }
+
+ /*
+ * The other end.
+ */
+ ina = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr;
+ /*
+ * Only add it if we haven't seen it before.
+ */
+ if (ip_match_network(local_networks, ina, mask) < 0) {
+ ime = new_ip_match_pattern(ina, 32);
+ add_to_ip_match_list(local_networks, ime);
+ }
+ } else {
+ /*
+ * Add this interface's network and netmask to the
+ * list of local networks.
+ */
+
+#ifdef SIOCGIFNETMASK /* XXX */
+ if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
+ ns_notice(ns_log_default, "get netmask: %s",
+ strerror(errno));
+ continue;
+ }
+ /*
+ * Use ina_get because the ifreq structure might not
+ * be aligned.
+ */
+ mask_ptr = (u_char *)
+ &((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
+ mask = ina_get(mask_ptr);
+#else
+ mask = net_mask(ina);
+#endif
+
+ ina.s_addr &= mask.s_addr; /* make network address */
+
+ /*
+ * Only add it if we haven't seen it before.
+ */
+ if (ip_match_network(local_networks, ina, mask) < 0) {
+ ime = new_ip_match_mask(ina, mask);
+ add_to_ip_match_list(local_networks, ime);
+ }
+ }
+ }
+ close(s);
+
+ ns_debug(ns_log_default, 7, "local addresses:");
+ dprint_ip_match_list(ns_log_default, local_addresses, 2, "", "");
+ ns_debug(ns_log_default, 7, "local networks:");
+ dprint_ip_match_list(ns_log_default, local_networks, 2, "", "");
+
+ /*
+ * now go through the iflist 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.
+ */
+ dq_remove_gen(my_generation);
+
+ if (EMPTY(iflist))
+ ns_warning(ns_log_default, "not listening on any interfaces");
+}
+
+/* opensocket_d(ifp)
+ * Open datagram socket bound to interface address.
+ * Returns:
+ * 0 on success.
+ * -1 on failure.
+ */
+static int
+opensocket_d(interface *ifp) {
+ struct sockaddr_in nsa;
+ const int on = 1;
+ int m, n;
+ int fd;
+
+ memset(&nsa, 0, sizeof nsa);
+ nsa.sin_family = AF_INET;
+ nsa.sin_addr = ifp->addr;
+ nsa.sin_port = ifp->port;
+
+ if ((ifp->dfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ ns_error(ns_log_default, "socket(SOCK_DGRAM): %s",
+ strerror(errno));
+ return (-1);
+ }
+#ifdef F_DUPFD /* XXX */
+ /*
+ * Leave a space for stdio to work in.
+ */
+ if ((fd = fcntl(ifp->dfd, F_DUPFD, 20)) != -1) {
+ close(ifp->dfd);
+ ifp->dfd = fd;
+ } else
+ ns_notice(ns_log_default, "fcntl(dfd, F_DUPFD, 20): %s",
+ strerror(errno));
+#endif
+ ns_debug(ns_log_default, 1, "ifp->addr %s d_dfd %d",
+ sin_ntoa(nsa), ifp->dfd);
+ if (setsockopt(ifp->dfd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof(on)) != 0) {
+ ns_notice(ns_log_default, "setsockopt(REUSEADDR): %s",
+ strerror(errno));
+ /* XXX press on regardless, this is not too serious. */
+ }
+#ifdef SO_RCVBUF /* XXX */
+ m = sizeof n;
+ if ((getsockopt(ifp->dfd, SOL_SOCKET, SO_RCVBUF, (char*)&n, &m) >= 0)
+ && (m == sizeof n)
+ && (n < rbufsize)) {
+ (void) setsockopt(ifp->dfd, SOL_SOCKET, SO_RCVBUF,
+ (char *)&rbufsize, sizeof(rbufsize));
+ }
+#endif /* SO_RCVBUF */
+ if (bind(ifp->dfd, (struct sockaddr *)&nsa, sizeof nsa)) {
+ ns_error(ns_log_default, "bind(dfd=%d, %s): %s",
+ ifp->dfd, sin_ntoa(nsa), strerror(errno));
+ return (-1);
+ }
+ if (evSelectFD(ev, ifp->dfd, EV_READ, datagram_read, ifp,
+ &ifp->evID_d) == -1) {
+ ns_error(ns_log_default, "evSelectFD(dfd=%d): %s",
+ ifp->dfd, strerror(errno));
+ return (-1);
+ }
+ ifp->flags |= INTERFACE_FILE_VALID;
+ return (0);
+}
+
+/* opensocket_s(ifp)
+ * Open stream (listener) socket bound to interface address.
+ * Returns:
+ * 0 on success.
+ * -1 on failure.
+ */
+static int
+opensocket_s(interface *ifp) {
+ struct sockaddr_in nsa;
+ const int on = 1;
+ int n;
+ int fd;
+
+ memset(&nsa, 0, sizeof nsa);
+ nsa.sin_family = AF_INET;
+ nsa.sin_addr = ifp->addr;
+ nsa.sin_port = ifp->port;
+
+ /*
+ * Open stream (listener) port.
+ */
+ n = 0;
+ again:
+ if ((ifp->sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ ns_error(ns_log_default, "socket(SOCK_STREAM): %s",
+ strerror(errno));
+ return (-1);
+ }
+#ifdef F_DUPFD /* XXX */
+ /*
+ * Leave a space for stdio to work in.
+ */
+ if ((fd = fcntl(ifp->sfd, F_DUPFD, 20)) != -1) {
+ close(ifp->sfd);
+ ifp->sfd = fd;
+ } else
+ ns_notice(ns_log_default, "fcntl(sfd, F_DUPFD, 20): %s",
+ strerror(errno));
+#endif
+ if (setsockopt(ifp->sfd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof on) != 0) {
+ ns_notice(ns_log_default, "setsockopt(REUSEADDR): %s",
+ strerror(errno));
+ /* Consider that your first warning of trouble to come. */
+ }
+ if (bind(ifp->sfd, (struct sockaddr *)&nsa, sizeof nsa) < 0) {
+ if (errno != EADDRINUSE || ++n > 4) {
+ if (errno == EADDRINUSE)
+ ns_error(ns_log_default,
+ "There may be a name server already running on %s",
+ sin_ntoa(nsa));
+ else
+ ns_error(ns_log_default,
+ "bind(sfd=%d, %s): %s", ifp->sfd,
+ sin_ntoa(nsa), strerror(errno));
+ return (-1);
+ }
+
+ /* Retry opening the socket a few times */
+ close(ifp->sfd);
+ ifp->sfd = -1;
+ sleep(30);
+ goto again;
+ }
+ if (evListen(ev, ifp->sfd, 5/*XXX*/, stream_accept, ifp, &ifp->evID_s)
+ == -1) {
+ ns_error(ns_log_default, "evListen(sfd=%d): %s",
+ ifp->sfd, strerror(errno));
+ return (-1);
+ }
+ ifp->flags |= INTERFACE_CONN_VALID;
+ return (0);
+}
+
+/* opensocket_f()
+ * Open datagram socket bound to no particular interface; use for ns_forw
+ * and sysquery.
+ */
+void
+opensocket_f() {
+ static struct sockaddr_in prev_qsrc;
+ static int been_here;
+ static interface *prev_ifp;
+ struct sockaddr_in nsa;
+ const int on = 1;
+ int n, need_close;
+ interface *ifp;
+
+ need_close = 0;
+ if (been_here) {
+ if (prev_ifp != NULL)
+ prev_ifp->flags &= ~INTERFACE_FORWARDING;
+ else if (server_options->query_source.sin_port == htons(0) ||
+ prev_qsrc.sin_addr.s_addr !=
+ server_options->query_source.sin_addr.s_addr ||
+ prev_qsrc.sin_port !=
+ server_options->query_source.sin_port)
+ need_close = 1;
+ } else
+ ds = -1;
+
+ been_here = 1;
+ INSIST(server_options != NULL);
+
+ if (need_close) {
+ evDeselectFD(ev, ds_evID);
+ close(ds);
+ ds = -1;
+ }
+
+ /*
+ * If we're already listening on the query_source address and port,
+ * we don't need to open another socket. We mark the interface, so
+ * we'll notice we're in trouble if it goes away.
+ */
+ ifp = if_find(server_options->query_source.sin_addr,
+ server_options->query_source.sin_port);
+ if (ifp != NULL) {
+ ifp->flags |= INTERFACE_FORWARDING;
+ prev_ifp = ifp;
+ ds = ifp->dfd;
+ ns_info(ns_log_default, "forwarding source address is %s",
+ sin_ntoa(server_options->query_source));
+ return;
+ }
+
+ /*
+ * If we're already using the correct query source, we're done.
+ */
+ if (ds >= 0)
+ return;
+
+ prev_qsrc = server_options->query_source;
+ prev_ifp = NULL;
+
+ if ((ds = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ ns_panic(ns_log_default, 1, "socket(SOCK_DGRAM): %s",
+ strerror(errno));
+ if (setsockopt(ds, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof on) != 0) {
+ ns_notice(ns_log_default, "setsockopt(REUSEADDR): %s",
+ strerror(errno));
+ /* XXX press on regardless, this is not too serious. */
+ }
+ if (bind(ds, (struct sockaddr *)&server_options->query_source,
+ sizeof server_options->query_source) < 0)
+ ns_panic(ns_log_default, 1, "opensocket_f: bind(%s): %s",
+ sin_ntoa(server_options->query_source),
+ strerror(errno));
+
+ n = sizeof nsa;
+ if (getsockname(ds, (struct sockaddr *)&nsa, &n) < 0)
+ ns_panic(ns_log_default, 1, "opensocket_f: getsockaddr: %s",
+ strerror(errno));
+
+ ns_debug(ns_log_default, 1, "fwd ds %d addr %s", ds, sin_ntoa(nsa));
+ ns_info(ns_log_default, "Forwarding source address is %s",
+ sin_ntoa(nsa));
+
+ if (evSelectFD(ev, ds, EV_READ, datagram_read, NULL, &ds_evID) == -1)
+ ns_panic(ns_log_default, 1, "evSelectFD(fd %d): %s",
+ (void *)ds, strerror(errno));
+ /* XXX: should probably use a different FileFunc that only accepts
+ * responses, since requests on this socket make no sense.
+ */
+}
+
+static void
+setdebug(int new_debug) {
+#ifdef DEBUG
+ int old_debug;
+
+ if (!new_debug)
+ ns_debug(ns_log_default, 1, "Debug off");
+ old_debug = debug;
+ debug = new_debug;
+ log_option(log_ctx, LOG_OPTION_DEBUG, debug);
+ log_option(log_ctx, LOG_OPTION_LEVEL, debug);
+ evSetDebug(ev, debug, log_get_stream(eventlib_channel));
+ if (debug) {
+ if (!old_debug)
+ open_special_channels();
+ ns_debug(ns_log_default, 1, "Debug level %d", debug);
+ if (!old_debug) {
+ ns_debug(ns_log_default, 1, "Version = %s", Version);
+ ns_debug(ns_log_default, 1, "conffile = %s", conffile);
+ }
+ }
+#endif
+}
+
+static SIG_FN
+onhup(int sig) {
+ ns_need(MAIN_NEED_RELOAD);
+}
+
+static SIG_FN
+onintr(int sig) {
+ ns_need(MAIN_NEED_EXIT);
+}
+
+static SIG_FN
+setdumpflg(int sig) {
+ ns_need(MAIN_NEED_DUMP);
+}
+
+#ifdef DEBUG
+static SIG_FN
+setIncrDbgFlg(int sig) {
+ desired_debug++;
+ ns_need(MAIN_NEED_DEBUG);
+}
+
+static SIG_FN
+setNoDbgFlg(int sig) {
+ desired_debug = 0;
+ ns_need(MAIN_NEED_DEBUG);
+}
+#endif /*DEBUG*/
+
+#if defined(QRYLOG) && defined(SIGWINCH)
+static SIG_FN
+setQrylogFlg(int sig) {
+ ns_need(MAIN_NEED_QRYLOG);
+}
+#endif /*QRYLOG && SIGWINCH*/
+
+static SIG_FN
+setstatsflg(int sig) {
+ ns_need(MAIN_NEED_STATSDUMP);
+}
+
+static SIG_FN
+discard_pipe(int sig) {
+#ifdef SIGPIPE_ONE_SHOT
+ int saved_errno = errno;
+ set_signal_handler(SIGPIPE, discard_pipe);
+ errno = saved_errno;
+#endif
+}
+
+/*
+** Routines for managing stream queue
+*/
+
+static struct qstream *
+sq_add() {
+ struct qstream *sqp;
+
+ if (!(sqp = (struct qstream *)memget(sizeof *sqp))) {
+ ns_error(ns_log_default, "sq_add: memget: %s",
+ strerror(errno));
+ return (NULL);
+ }
+ memset(sqp, 0, sizeof *sqp);
+ ns_debug(ns_log_default, 3, "sq_add(%#lx)", (u_long)sqp);
+
+ sqp->flags = 0;
+ /* XXX should init other fields too? */
+ sqp->s_next = streamq;
+ streamq = sqp;
+ return (sqp);
+}
+
+/* sq_remove(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
+sq_remove(struct qstream *qp) {
+ struct qstream *qsp;
+
+ ns_debug(ns_log_default, 2, "sq_remove(%#lx, %d) rfcnt=%d",
+ (u_long)qp, qp->s_rfd, qp->s_refcnt);
+
+ if (qp->s_wbuf != NULL) {
+ memput(qp->s_wbuf, qp->s_wbuf_end - qp->s_wbuf);
+ qp->s_wbuf = NULL;
+ }
+ if (qp->flags & STREAM_MALLOC)
+ memput(qp->s_buf, qp->s_bufsize);
+ if (qp->flags & STREAM_READ_EV)
+ INSIST_ERR(evCancelRW(ev, qp->evID_r) != -1);
+ if (qp->flags & STREAM_WRITE_EV)
+ INSIST_ERR(evDeselectFD(ev, qp->evID_w) != -1);
+ if (qp->flags & STREAM_CONNECT_EV)
+ INSIST_ERR(evCancelConn(ev, qp->evID_c) != -1);
+ if (qp->flags & STREAM_AXFR)
+ ns_freexfr(qp);
+ (void) close(qp->s_rfd);
+ if (qp == streamq)
+ streamq = qp->s_next;
+ else {
+ for (qsp = streamq;
+ qsp && (qsp->s_next != qp);
+ qsp = qsp->s_next)
+ (void)NULL;
+ if (qsp)
+ qsp->s_next = qp->s_next;
+ }
+ memput(qp, sizeof *qp);
+}
+
+/* void
+ * sq_flush(allbut)
+ * call sq_remove() on all open streams except `allbut'
+ * side effects:
+ * global list `streamq' modified
+ * idiocy:
+ * is N^2 due to the scan inside of sq_remove()
+ */
+void
+sq_flush(struct qstream *allbut) {
+ struct qstream *sp, *spnext;
+
+ for (sp = streamq; sp != NULL; sp = spnext) {
+ spnext = sp->s_next;
+ if (sp != allbut)
+ sq_remove(sp);
+ }
+}
+
+/* int
+ * sq_openw(qs, buflen)
+ * add a write buffer to a stream
+ * return:
+ * 0 = success
+ * -1 = failure (check errno)
+ */
+int
+sq_openw(struct qstream *qs, int buflen) {
+#ifdef SO_LINGER /* XXX */
+ static const struct linger ll = { 1, 120 };
+#endif
+
+ INSIST(qs->s_wbuf == NULL);
+ qs->s_wbuf = (u_char *)memget(buflen);
+ if (qs->s_wbuf == NULL)
+ return (-1);
+ qs->s_wbuf_send = qs->s_wbuf;
+ qs->s_wbuf_free = qs->s_wbuf;
+ qs->s_wbuf_end = qs->s_wbuf + buflen;
+#ifdef SO_LINGER /* XXX */
+ /* 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(qs->s_rfd, SOL_SOCKET, SO_LINGER, (char *)&ll, sizeof ll);
+#endif
+ return (0);
+}
+
+/* static void
+ * sq_dowrite(qs)
+ * try to submit data to the system, remove it from our queue.
+ */
+static int
+sq_dowrite(struct qstream *qs) {
+ if (qs->s_wbuf_free > qs->s_wbuf_send) {
+ int n = write(qs->s_rfd, qs->s_wbuf_send,
+ qs->s_wbuf_free - qs->s_wbuf_send);
+ if (n < 0) {
+ if (errno != EINTR && errno != EAGAIN
+#if (EWOULDBLOCK != EAGAIN)
+ && errno != EWOULDBLOCK
+#endif
+ )
+ return (-1);
+ return (0);
+ }
+ qs->s_wbuf_send += n;
+ if (qs->s_wbuf_free > qs->s_wbuf_send) {
+ /* XXX: need some kind of delay here during which the
+ * socket will be deselected so we don't spin.
+ */
+ n = qs->s_wbuf_free - qs->s_wbuf_send;
+ memmove(qs->s_wbuf, qs->s_wbuf_send, n);
+ qs->s_wbuf_send = qs->s_wbuf;
+ qs->s_wbuf_free = qs->s_wbuf + n;
+ }
+ }
+ if (qs->s_wbuf_free == qs->s_wbuf_send)
+ qs->s_wbuf_free = qs->s_wbuf_send = qs->s_wbuf;
+ return (0);
+}
+
+/* void
+ * sq_flushw(qs)
+ * called when the socket becomes writable and we want to flush our
+ * buffers and the system's socket buffers. use as a closure with
+ * sq_writeh().
+ */
+void
+sq_flushw(struct qstream *qs) {
+ if (qs->s_wbuf_free == qs->s_wbuf_send) {
+ sq_writeh(qs, NULL);
+ sq_done(qs);
+ }
+}
+
+/* static void
+ * sq_writable(ctx, uap, fd, evmask)
+ * glue between eventlib closures and qstream closures
+ */
+static void
+sq_writable(evContext ctx, void *uap, int fd, int evmask) {
+ struct qstream *qs = uap;
+
+ INSIST(evmask & EV_WRITE);
+ INSIST(fd == qs->s_rfd);
+ if (sq_dowrite(qs) < 0) {
+ sq_remove(qs);
+ return;
+ }
+ if (qs->s_wbuf_closure
+ && qs->s_wbuf_end - qs->s_wbuf_free >= HFIXEDSZ+2) /* XXX guess */
+ (*qs->s_wbuf_closure)(qs);
+ if (sq_dowrite(qs) < 0) {
+ sq_remove(qs);
+ return;
+ }
+}
+
+/* int
+ * sq_writeh(qs, closure)
+ * register a closure to be called when a stream becomes writable
+ * return:
+ * 0 = success
+ * -1 = failure (check errno)
+ */
+int
+sq_writeh(struct qstream *qs, sq_closure c) {
+ if (c) {
+ if (!qs->s_wbuf_closure) {
+ if (evSelectFD(ev, qs->s_rfd, EV_WRITE,
+ sq_writable, qs, &qs->evID_w) < 0) {
+ return (-1);
+ }
+ qs->flags |= STREAM_WRITE_EV;
+ }
+ } else {
+ (void) evDeselectFD(ev, qs->evID_w);
+ qs->flags &= ~STREAM_WRITE_EV;
+ }
+ qs->s_wbuf_closure = c;
+ return (0);
+}
+
+/* int
+ * sq_write(qs, buf, len)
+ * queue a message onto the stream, prepended by a two byte length field
+ * return:
+ * 0 = success
+ * -1 = failure (check errno; E2BIG means we can't handle this right now)
+ */
+int
+sq_write(struct qstream *qs, const u_char *buf, int len) {
+ INSIST(qs->s_wbuf != NULL);
+ if (NS_INT16SZ + len > qs->s_wbuf_end - qs->s_wbuf_free) {
+ if (sq_dowrite(qs) < 0)
+ return (-1);
+ if (NS_INT16SZ + len > qs->s_wbuf_end - qs->s_wbuf_free) {
+ errno = E2BIG;
+ return (-1);
+ }
+ }
+ __putshort(len, qs->s_wbuf_free);
+ qs->s_wbuf_free += NS_INT16SZ;
+ memcpy(qs->s_wbuf_free, buf, len);
+ qs->s_wbuf_free += len;
+ return (0);
+}
+
+/* int
+ * sq_here(sp)
+ * determine whether stream 'sp' is still on the streamq
+ * return:
+ * boolean: is it here?
+ */
+static int
+sq_here(struct qstream *sp) {
+ 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(struct qstream *sp) {
+ sp->s_refcnt++;
+}
+
+/*
+ * Note that the current request on a stream has completed,
+ * and that we should continue looking for requests on the stream.
+ */
+void
+sq_done(struct qstream *sp) {
+ struct iovec iov;
+
+ if (sp->s_wbuf != NULL) {
+ memput(sp->s_wbuf, sp->s_wbuf_end - sp->s_wbuf);
+ sp->s_wbuf = NULL;
+ }
+ if (sp->flags & STREAM_AXFR)
+ ns_freexfr(sp);
+ sp->s_refcnt = 0;
+ sp->s_time = tt.tv_sec;
+ if (sp->flags & STREAM_DONE_CLOSE) {
+ /* XXX */
+ sq_remove(sp);
+ return;
+ }
+ iov = evConsIovec(sp->s_temp, INT16SZ);
+ if (evRead(ev, sp->s_rfd, &iov, 1, stream_getlen, sp, &sp->evID_r) ==
+ -1)
+ ns_panic(ns_log_default, 1, "evRead(fd %d): %s",
+ (void *)sp->s_rfd, strerror(errno));
+ sp->flags |= STREAM_READ_EV;
+}
+
+/* void
+ * dq_remove_gen(gen)
+ * close/deallocate all the udp sockets (except 0.0.0.0) which are
+ * not from the current generation.
+ * side effects:
+ * global list `iflist' is modified.
+ */
+void
+dq_remove_gen(time_t gen) {
+ interface *this, *next;
+
+ for (this = HEAD(iflist); this != NULL; this = next) {
+ next = NEXT(this, link);
+ if (this->gen != gen && ina_hlong(this->addr) != INADDR_ANY)
+ dq_remove(this);
+ }
+}
+
+/* void
+ * dq_remove_all()
+ * close/deallocate all interfaces.
+ * side effects:
+ * global list `iflist' is modified.
+ */
+void
+dq_remove_all() {
+ interface *this, *next;
+
+ for (this = HEAD(iflist); this != NULL; this = next) {
+ next = NEXT(this, link);
+ /*
+ * Clear the forwarding flag so we don't panic the server.
+ */
+ this->flags &= ~INTERFACE_FORWARDING;
+ dq_remove(this);
+ }
+}
+
+/* void
+ * dq_remove(interface *this)
+ * close/deallocate an interface's sockets. called on errors
+ * or if the interface disappears.
+ * side effects:
+ * global list `iflist' is modified.
+ */
+static void
+dq_remove(interface *this) {
+ ns_notice(ns_log_default, "deleting interface [%s].%u",
+ inet_ntoa(this->addr), ntohs(this->port));
+
+ if ((this->flags & INTERFACE_FORWARDING) != 0)
+ ns_panic(ns_log_default, 0,
+ "forwarding interface [%s].%u gone",
+ inet_ntoa(this->addr),
+ ntohs(this->port));
+
+ /* Deallocate fields. */
+ if ((this->flags & INTERFACE_FILE_VALID) != 0)
+ (void) evDeselectFD(ev, this->evID_d);
+ if (this->dfd >= 0)
+ (void) close(this->dfd);
+ if ((this->flags & INTERFACE_CONN_VALID) != 0)
+ (void) evCancelConn(ev, this->evID_s);
+ if (this->sfd >= 0)
+ (void) close(this->sfd);
+
+ UNLINK(iflist, this, link);
+ memput(this, sizeof *this);
+}
+
+/* struct in_addr
+ * net_mask(ina)
+ * makes a classful assumption in a classless world, and returns it.
+ */
+struct in_addr
+net_mask(struct in_addr ina) {
+ u_long hl = ina_hlong(ina);
+ struct in_addr ret;
+
+ if (IN_CLASSA(hl))
+ hl = IN_CLASSA_NET;
+ else if (IN_CLASSB(hl))
+ hl = IN_CLASSB_NET;
+ else if (IN_CLASSC(hl))
+ hl = IN_CLASSC_NET;
+ else
+ hl = INADDR_BROADCAST;
+ ina_ulong(ret) = htonl(hl);
+ return (ret);
+}
+
+/* aIsUs(addr)
+ * scan our list of interface addresses for "addr".
+ * returns:
+ * 0: address isn't one of our interfaces
+ * >0: address is one of our interfaces, or INADDR_ANY
+ */
+int
+aIsUs(struct in_addr addr) {
+ interface *ifp;
+
+ if (ina_hlong(addr) == INADDR_ANY || if_find(addr, 0) != NULL)
+ return (1);
+ return (0);
+}
+
+/* interface *
+ * if_find(addr, port)
+ * scan our list of interface addresses for "addr" and port.
+ * port == 0 means match any port
+ * returns:
+ * pointer to interface with this address/port, or NULL if there isn't
+ * one.
+ */
+static interface *
+if_find(struct in_addr addr, u_int16_t port) {
+ interface *ifp;
+
+ for (ifp = HEAD(iflist); ifp != NULL; ifp = NEXT(ifp, link))
+ if (ina_equal(addr, ifp->addr))
+ if (port == 0 || ifp->port == port)
+ break;
+ return (ifp);
+}
+
+/*
+ * 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);
+}
+
+static void
+deallocate_everything(void) {
+ FILE *f;
+
+ f = write_open(server_options->memstats_filename);
+
+ ns_freestats();
+ qflush();
+ sq_flush(NULL);
+ free_addinfo();
+ ns_shutdown();
+ dq_remove_all();
+ if (local_addresses != NULL)
+ free_ip_match_list(local_addresses);
+ if (local_networks != NULL)
+ free_ip_match_list(local_networks);
+ destroyservicelist();
+ destroyprotolist();
+ shutdown_logging();
+ evDestroy(ev);
+ if (conffile != NULL)
+ freestr(conffile);
+ if (user_name != NULL)
+ freestr(user_name);
+ if (group_name != NULL)
+ freestr(group_name);
+ if (chroot_dir != NULL)
+ freestr(chroot_dir);
+ if (f != NULL) {
+ memstats(f);
+ (void)fclose(f);
+ }
+}
+
+static void
+ns_exit(void) {
+ ns_info(ns_log_default, "named shutting down");
+#ifdef BIND_UPDATE
+ dynamic_about_to_exit();
+#endif
+ if (server_options && server_options->pid_filename)
+ (void)unlink(server_options->pid_filename);
+ ns_logstats(ev, NULL, evNowTime(), evConsTime(0, 0));
+ if (NS_OPTION_P(OPTION_DEALLOC_ON_EXIT))
+ deallocate_everything();
+ exit(0);
+}
+
+static void
+use_desired_debug(void) {
+#ifdef DEBUG
+ sigset_t set;
+ int bad;
+
+ /* protect against race conditions by blocking debugging signals */
+
+ if (sigemptyset(&set) < 0) {
+ ns_error(ns_log_os,
+ "sigemptyset failed in use_desired_debug: %s",
+ strerror(errno));
+ return;
+ }
+ if (sigaddset(&set, SIGUSR1) < 0) {
+ ns_error(ns_log_os,
+ "sigaddset SIGUSR1 failed in use_desired_debug: %s",
+ strerror(errno));
+ return;
+ }
+ if (sigaddset(&set, SIGUSR2) < 0) {
+ ns_error(ns_log_os,
+ "sigaddset SIGUSR2 failed in use_desired_debug: %s",
+ strerror(errno));
+ return;
+ }
+ if (sigprocmask(SIG_BLOCK, &set, NULL) < 0) {
+ ns_error(ns_log_os,
+ "sigprocmask to block USR1 and USR2 failed: %s",
+ strerror(errno));
+ return;
+ }
+ setdebug(desired_debug);
+ if (sigprocmask(SIG_UNBLOCK, &set, NULL) < 0)
+ ns_error(ns_log_os,
+ "sigprocmask to unblock USR1 and USR2 failed: %s",
+ strerror(errno));
+#endif
+}
+
+static void
+toggle_qrylog(void) {
+ qrylog = !qrylog;
+ ns_notice(ns_log_default, "query log %s\n", qrylog ?"on" :"off");
+}
+
+#ifdef BIND_NOTIFY
+static void
+do_notify_after_load(void) {
+ evDo(ev, (const void *)notify_after_load);
+}
+#endif
+
+/*
+ * This is a functional interface to the global needs and options.
+ */
+
+static const struct need_handler {
+ int need;
+ void (*handler)(void);
+ } need_handlers[] = {
+ { MAIN_NEED_RELOAD, ns_reload },
+ { MAIN_NEED_MAINT, ns_maint },
+ { MAIN_NEED_ENDXFER, endxfer },
+ { MAIN_NEED_ZONELOAD, loadxfer },
+ { MAIN_NEED_DUMP, doadump },
+ { MAIN_NEED_STATSDUMP, ns_stats },
+ { MAIN_NEED_EXIT, ns_exit },
+ { MAIN_NEED_QRYLOG, toggle_qrylog },
+ { MAIN_NEED_DEBUG, use_desired_debug },
+#ifdef BIND_NOTIFY
+ { MAIN_NEED_NOTIFY, do_notify_after_load },
+#endif
+ { 0, NULL }
+ };
+
+void
+ns_setoption(int option) {
+ ns_warning(ns_log_default, "used obsolete ns_setoption(%d)", option);
+}
+
+void
+ns_need(int need) {
+ needs |= need;
+}
+
+int
+ns_need_p(int need) {
+ return ((needs & need) != 0);
+}
+
+static void
+ns_handle_needs() {
+ const struct need_handler *nhp;
+
+ for (nhp = need_handlers; nhp->need && nhp->handler; nhp++) {
+ if ((needs & nhp->need) != 0) {
+ /*
+ * Turn off flag first, handler might turn it back on.
+ */
+ needs &= ~nhp->need;
+ (*nhp->handler)();
+ }
+ }
+}
+
+
+void
+writestream(struct qstream *sp, const u_char *msg, int msglen) {
+ if (sq_openw(sp, msglen + INT16SZ) == -1) {
+ sq_remove(sp);
+ return;
+ }
+ if (sq_write(sp, msg, msglen) == -1) {
+ sq_remove(sp);
+ return;
+ }
+ sq_writeh(sp, sq_flushw);
+}
+
+static void
+set_signal_handler(int sig, SIG_FN (*handler)()) {
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof sa);
+ sa.sa_handler = handler;
+ if (sigemptyset(&sa.sa_mask) < 0) {
+ ns_error(ns_log_os,
+ "sigemptyset failed in set_signal_handler(%d): %s",
+ sig, strerror(errno));
+ return;
+ }
+ if (sigaction(sig, &sa, NULL) < 0)
+ ns_error(ns_log_os,
+ "sigaction failed in set_signal_handler(%d): %s",
+ sig, strerror(errno));
+}
+
+static void
+init_signals() {
+ set_signal_handler(SIGINT, setdumpflg);
+ set_signal_handler(SIGILL, setstatsflg);
+#ifdef DEBUG
+ set_signal_handler(SIGUSR1, setIncrDbgFlg);
+ set_signal_handler(SIGUSR2, setNoDbgFlg);
+#endif
+ set_signal_handler(SIGHUP, onhup);
+#if defined(SIGWINCH) && defined(QRYLOG) /* XXX */
+ set_signal_handler(SIGWINCH, setQrylogFlg);
+#endif
+ set_signal_handler(SIGCHLD, reapchild);
+ set_signal_handler(SIGPIPE, discard_pipe);
+ set_signal_handler(SIGTERM, onintr);
+#if defined(SIGXFSZ) /* XXX */
+ /* Wierd DEC Hesiodism, harmless. */
+ set_signal_handler(SIGXFSZ, onhup);
+#endif
+}
+
+static int
+only_digits(const char *s) {
+ if (*s == '\0')
+ return (0);
+ while (*s != '\0') {
+ if (!isdigit(*s))
+ return (0);
+ s++;
+ }
+ return (1);
+}
diff --git a/contrib/bind/bin/named/ns_maint.c b/contrib/bind/bin/named/ns_maint.c
new file mode 100644
index 0000000..ad6e7f8
--- /dev/null
+++ b/contrib/bind/bin/named/ns_maint.c
@@ -0,0 +1,1210 @@
+#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.38 1998/03/16 19:40:25 halley Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+static int xfers_running, /* # of xfers running */
+ xfers_deferred, /* # of needed xfers not run yet */
+ qserials_running,
+ nxfers(struct zoneinfo *, int),
+ bottom_of_zone(struct databuf *, int);
+
+static void startxfer(struct zoneinfo *),
+ abortxfer(struct zoneinfo *),
+ addxfer(struct zoneinfo *),
+ tryxfer(void),
+ purge_z_2(struct hashbuf *, int);
+
+#define qserial_qfull() (qserials_running == MAXQSERIAL)
+
+static time_t stats_time;
+
+ /* State of all running zone transfers */
+static struct {
+ pid_t xfer_pid;
+ int xfer_state; /* see below */
+ WAIT_T xfer_status;
+} xferstatus[MAX_XFERS_RUNNING];
+
+#define XFER_IDLE 0
+#define XFER_RUNNING 1
+#define XFER_DONE 2
+
+
+/*
+ * Perform maintenance on all zones that need it.
+ */
+void
+ns_maint() {
+ struct zoneinfo *zp;
+ int zonenum, deleted;
+
+ gettime(&tt);
+
+ ns_debug(ns_log_maint, 1, "ns_maint()");
+
+ for (zp = zones, zonenum = 0; zp < &zones[nzones]; zp++, zonenum++)
+ zone_maint(zp);
+ ns_debug(ns_log_maint, 1, "exit ns_maint()");
+}
+
+/*
+ * Perform routine zone maintenance.
+ */
+void
+zone_maint(struct zoneinfo *zp) {
+ gettime(&tt);
+
+ ns_debug(ns_log_maint, 1, "zone_maint('%s'); now %lu",
+ zp->z_origin[0] == '\0' ? "." : zp->z_origin,
+ (u_long)tt.tv_sec);
+
+#ifdef DEBUG
+ if (debug >= 2)
+ printzoneinfo((zp - zones), ns_log_maint, 2);
+#endif
+
+ switch (zp->z_type) {
+
+ case Z_SECONDARY:
+ /*FALLTHROUGH*/
+#ifdef STUBS
+ case Z_STUB:
+#endif
+ if (zp->z_serial != 0 &&
+ ((zp->z_lastupdate+zp->z_expire) < (u_int32_t)tt.tv_sec)) {
+ zp->z_serial = 0;
+ }
+ if (zp->z_flags & (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL)) {
+ ns_retrytime(zp, tt.tv_sec);
+ break;
+ }
+ if (zp->z_flags & Z_XFER_RUNNING) {
+ abortxfer(zp);
+ /*
+ * Check again in 30 seconds in case the first
+ * abort doesn't work.
+ */
+ if (zp->z_time != 0 && zp->z_time <= tt.tv_sec)
+ zp->z_time = tt.tv_sec + 30;
+ break;
+ }
+ qserial_query(zp);
+ break;
+
+#ifdef BIND_UPDATE
+ case Z_PRIMARY:
+ if (! (zp->z_flags & Z_DYNAMIC))
+ break;
+ if (tt.tv_sec >= zp->z_soaincrtime &&
+ zp->z_soaincrintvl > 0 &&
+ zp->z_flags & Z_NEED_SOAUPDATE) {
+ if (incr_serial(zp) < 0) {
+ /* Try again later. */
+ ns_error(ns_log_maint,
+ "error updating serial number for %s from %d",
+ zp->z_origin,
+ zp->z_serial);
+ zp->z_soaincrtime = 0;
+ (void)schedule_soa_update(zp, 0);
+ }
+
+ }
+ if (tt.tv_sec >= zp->z_dumptime &&
+ zp->z_dumpintvl > 0 &&
+ zp->z_flags & Z_NEED_DUMP) {
+ if (zonedump(zp) < 0) {
+ /* Try again later. */
+ ns_error(ns_log_maint,
+ "zone dump for '%s' failed, rescheduling",
+ zp->z_origin);
+ zp->z_dumptime = 0;
+ (void)schedule_dump(zp);
+ }
+ }
+ break;
+#endif /* BIND_UPDATE */
+
+ default:
+ break;
+ }
+
+ /*
+ * It is essential that we never try to set a timer in the past
+ * or for now because doing so could cause an infinite loop.
+ */
+ INSIST(zp->z_time == 0 || zp->z_time > tt.tv_sec);
+
+ sched_zone_maint(zp);
+}
+
+static void
+do_zone_maint(evContext ctx, void *uap, struct timespec due,
+ struct timespec inter) {
+ ztimer_info zti = uap;
+ struct zoneinfo *zp;
+
+ INSIST(zti != NULL);
+
+ ns_debug(ns_log_maint, 1, "do_zone_maint for zone %s (class %s)",
+ zti->name, p_class(zti->class));
+ zp = find_zone(zti->name, zti->type, zti->class);
+ if (zp == NULL) {
+ ns_error(ns_log_maint,
+ "do_zone_maint: %s zone '%s' (class %s) is not authoritative",
+ zoneTypeString(zp), zti->name,
+ p_class(zti->class));
+ return;
+ }
+
+ free_zone_timerinfo(zp);
+
+ zp->z_flags &= ~Z_TIMER_SET;
+ zone_maint(zp);
+}
+
+/*
+ * Figure out the next maintenance time for the zone and set a timer.
+ */
+void
+sched_zone_maint(struct zoneinfo *zp) {
+ time_t next_maint = (time_t)0;
+ char *zone_name;
+ ztimer_info zti;
+
+ if (zp->z_time != 0)
+ next_maint = zp->z_time;
+#ifdef BIND_UPDATE
+ if (zp->z_type == z_master && (zp->z_flags & Z_DYNAMIC)) {
+ if (zp->z_soaincrintvl > 0 &&
+ (next_maint == 0 || next_maint > zp->z_soaincrtime))
+ next_maint = zp->z_soaincrtime;
+ if (zp->z_dumpintvl > 0 &&
+ (next_maint == 0 || next_maint > zp->z_dumptime))
+ next_maint = zp->z_dumptime;
+ }
+#endif
+
+ if (next_maint != 0) {
+ if (next_maint < tt.tv_sec)
+ next_maint = tt.tv_sec;
+
+ if (zp->z_flags & Z_TIMER_SET) {
+ if (next_maint == zp->z_nextmaint) {
+ ns_debug(ns_log_maint, 1,
+ "no schedule change for zone '%s'",
+ zp->z_origin[0] == '\0' ? "." :
+ zp->z_origin);
+ return;
+ }
+
+ if (evResetTimer(ev, zp->z_timer,
+ do_zone_maint, zp->z_timerinfo,
+ evConsTime(next_maint, 0),
+ evConsTime(0, 0)) < 0) {
+ ns_error(ns_log_maint,
+ "evChangeTimer failed in sched_zone_maint for zone '%s': %s",
+ zp->z_origin[0] == '\0' ? "." :
+ zp->z_origin,
+ strerror(errno));
+ return;
+ }
+ } else {
+ zti = (ztimer_info)memget(sizeof *zti);
+ if (zti == NULL)
+ ns_panic(ns_log_maint, 1,
+ "memget failed in sched_zone_maint");
+ zti->name = savestr(zp->z_origin, 1);
+ zti->class = zp->z_class;
+ zti->type = zp->z_type;
+ if (evSetTimer(ev, do_zone_maint, zti,
+ evConsTime(next_maint, 0),
+ evConsTime(0, 0), &zp->z_timer) < 0) {
+ ns_error(ns_log_maint,
+ "evSetTimer failed in sched_zone_maint for zone '%s': %s",
+ zp->z_origin[0] == '\0' ? "." :
+ zp->z_origin,
+ strerror(errno));
+ return;
+ }
+ zp->z_flags |= Z_TIMER_SET;
+ zp->z_timerinfo = zti;
+ }
+ ns_debug(ns_log_maint, 1,
+ "next maintenance for zone '%s' in %lu sec",
+ zp->z_origin[0] == '\0' ? "." : zp->z_origin,
+ (u_long)(next_maint - tt.tv_sec));
+ } else {
+ if (zp->z_flags & Z_TIMER_SET) {
+ free_zone_timerinfo(zp);
+ if (evClearTimer(ev, zp->z_timer) < 0)
+ ns_error(ns_log_maint,
+ "evClearTimer failed in sched_zone_maint for zone '%s': %s",
+ zp->z_origin[0] == '\0' ? "." :
+ zp->z_origin,
+ strerror(errno));
+ zp->z_flags &= ~Z_TIMER_SET;
+ }
+ ns_debug(ns_log_maint, 1,
+ "no scheduled maintenance for zone '%s'",
+ zp->z_origin[0] == '\0' ? "." : zp->z_origin);
+ }
+ zp->z_nextmaint = next_maint;
+}
+
+void
+ns_cleancache(evContext ctx, void *uap,
+ struct timespec due,
+ struct timespec inter)
+{
+ int deleted;
+
+ gettime(&tt);
+ INSIST(uap == NULL);
+ deleted = clean_cache(hashtab, 0);
+ ns_info(ns_log_maint, "Cleaned cache of %d RR%s",
+ deleted, (deleted==1) ? "" : "s");
+}
+
+/*
+ * Mark a zone "up to date" after named-xfer tells us this or we
+ * discover it through the qserial_*() logic.
+ * The caller is responsible for calling sched_zone_maint(zp).
+ */
+static void
+markUpToDate(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) {
+ struct timeval t[2];
+
+ t[0] = tt;
+ t[1] = tt;
+ (void) utimes(zp->z_source, t);
+ }
+ /* 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? */
+}
+
+void
+qserial_retrytime(struct zoneinfo *zp, time_t timebase) {
+ zp->z_time = timebase + 5 + (rand() % 25);
+}
+
+/*
+ * Query for the serial number of a zone, so that we can check to see if
+ * we need to transfer it. If there are too many outstanding serial
+ * number queries, we'll try again later.
+ * The caller is responsible for calling sched_zone_maint(zp).
+ */
+void
+qserial_query(struct zoneinfo *zp) {
+ struct qinfo *qp;
+
+ ns_debug(ns_log_default, 1, "qserial_query(%s)", zp->z_origin);
+
+ if (qserial_qfull()) {
+ qserial_retrytime(zp, tt.tv_sec);
+ return;
+ }
+
+ qp = sysquery(zp->z_origin, zp->z_class, T_SOA,
+ zp->z_addr, zp->z_addrcnt, QUERY);
+ if (!qp) {
+ ns_info(ns_log_default, "qserial_query(%s): sysquery FAILED",
+ zp->z_origin);
+ /* XXX - this is bad, we should do something */
+ qserial_retrytime(zp, tt.tv_sec);
+ return;
+ }
+ qp->q_flags |= Q_ZSERIAL;
+ qp->q_zquery = zp;
+ zp->z_flags |= Z_QSERIAL;
+ zp->z_xaddr = inaddr_any;
+ ns_refreshtime(zp, tt.tv_sec);
+ qserials_running++;
+ ns_debug(ns_log_default, 1, "qserial_query(%s) QUEUED", zp->z_origin);
+}
+
+void
+qserial_answer(struct qinfo *qp, u_int32_t serial, struct sockaddr_in from) {
+ struct zoneinfo *zp = qp->q_zquery;
+
+ ns_debug(ns_log_default, 1, "qserial_answer(%s, %u)", zp->z_origin,
+ serial);
+ zp->z_flags &= ~Z_QSERIAL;
+ qp->q_flags &= ~Q_ZSERIAL; /* keeps us from being called twice */
+ qserials_running--;
+ if (serial == 0) {
+ /* An error occurred, or the query timed out. */
+ ns_info(ns_log_default, "Err/TO getting serial# for \"%s\"",
+ zp->z_origin);
+ addxfer(zp);
+ } else if (SEQ_GT(serial, zp->z_serial) || !zp->z_serial) {
+ ns_debug(ns_log_default, 1,
+ "qserial_answer: zone is out of date");
+ zp->z_xaddr = from.sin_addr; /* don't use qp->q_from */
+ addxfer(zp);
+ } else if (SEQ_GT(zp->z_serial, serial)) {
+ if (!haveComplained((u_long)zp, (u_long)"went backward")) {
+ ns_notice(ns_log_default,
+ "Zone \"%s\" (class %d) SOA serial# (%u) rcvd from [%s] is < ours (%u)",
+ zp->z_origin, zp->z_class, serial,
+ inet_ntoa(from.sin_addr), zp->z_serial);
+ }
+ } else {
+ ns_debug(ns_log_default, 1,
+ "qserial_answer: zone serial is still OK");
+ markUpToDate(zp);
+ sched_zone_maint(zp);
+ }
+}
+
+/*
+ * Start an asynchronous zone transfer for a zone.
+ * Depends on current time being in tt.
+ * Caller must do sched_zone_maint(zp) after startxfer returns.
+ */
+static void
+startxfer(struct zoneinfo *zp) {
+ char *argv[NSMAX + 20], argv_ns[NSMAX][MAXDNAME];
+ int argc = 0, argc_ns = 0, pid, i;
+ u_int cnt;
+ char debug_str[10];
+ char serial_str[10];
+ char port_str[10];
+ char class_str[10];
+ char src_str[20];
+
+ ns_debug(ns_log_default, 1, "startxfer() %s", zp->z_origin);
+
+ argv[argc++] = server_options->named_xfer;
+ argv[argc++] = "-z";
+ argv[argc++] = zp->z_origin;
+ argv[argc++] = "-f";
+ argv[argc++] = zp->z_source;
+ argv[argc++] = "-s";
+ sprintf(serial_str, "%u", zp->z_serial);
+ argv[argc++] = serial_str;
+ if (zp->z_axfr_src.s_addr != 0) {
+ argv[argc++] = "-x";
+ argv[argc++] = strcpy(src_str, inet_ntoa(zp->z_axfr_src));
+ }
+ argv[argc++] = "-C";
+ sprintf(class_str, "%d", zp->z_class);
+ argv[argc++] = class_str;
+ 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 (ina_hlong(zp->z_xaddr) != INADDR_ANY) {
+ /*
+ * Address was specified by the qserial logic, use it
+ * first.
+ */
+ if (aIsUs(zp->z_xaddr) &&
+ !haveComplained((u_long)zp, (u_long)startxfer)) {
+ ns_notice(ns_log_default,
+ "attempted to fetch zone %s from self (%s)",
+ zp->z_origin, inet_ntoa(zp->z_xaddr));
+ } else
+ argv[argc++] = strcpy(argv_ns[argc_ns++],
+ inet_ntoa(zp->z_xaddr));
+ }
+ /*
+ * Copy the server ip addresses into argv, after converting
+ * to ascii and saving the static inet_ntoa result. Skip zp->z_xaddr
+ * if seen.
+ */
+ for (cnt = 0; cnt < zp->z_addrcnt; cnt++) {
+ struct in_addr a;
+
+ a = zp->z_addr[cnt];
+ if (ina_equal(a, zp->z_xaddr))
+ continue;
+ if (aIsUs(a) &&
+ !haveComplained((u_long)zp, (u_long)startxfer)) {
+ ns_notice(ns_log_default,
+ "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] = NULL;
+
+#ifdef DEBUG
+ if (debug >= 1) {
+ char buffer[1024];
+ char *curr, *last;
+ int len;
+
+ curr = buffer;
+ last = &buffer[sizeof buffer - 1]; /* leave room for \0 */
+ for (i = 0; i < argc; i++) {
+ len = strlen(argv[i]);
+ if (curr + len + 1 >= last) {
+ ns_debug(ns_log_xfer_in, 1,
+ "xfer args debug printout truncated");
+ break;
+ }
+ strncpy(curr, argv[i], len);
+ curr += len;
+ *curr = ' ';
+ curr++;
+ }
+ *curr = '\0';
+ ns_debug(ns_log_xfer_in, 1, buffer);
+ }
+#endif /* DEBUG */
+
+ gettime(&tt);
+ 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) {
+ ns_error(ns_log_default, "xfer vfork: %s", strerror(errno));
+ zp->z_time = tt.tv_sec + 10;
+ return;
+ }
+
+ if (pid == 0) {
+ /* Child. */
+ execv(server_options->named_xfer, argv);
+ ns_error(ns_log_default, "can't exec %s: %s",
+ server_options->named_xfer, strerror(errno));
+ _exit(XFER_FAIL); /* Avoid duplicate buffer flushes. */
+ }
+ /* Parent. */
+ xferstatus[i].xfer_pid = pid; /* XXX - small race condition here if we
+ * can't hold signals */
+ ns_debug(ns_log_default, 1, "started xfer child %d", pid);
+ zp->z_flags &= ~Z_NEED_XFER;
+ zp->z_flags |= Z_XFER_RUNNING;
+ zp->z_xferpid = pid;
+ xfers_running++;
+ if (zp->z_max_transfer_time_in)
+ zp->z_time = tt.tv_sec + zp->z_max_transfer_time_in;
+ else
+ zp->z_time = tt.tv_sec + server_options->max_transfer_time_in;
+}
+
+const char *
+zoneTypeString(const struct zoneinfo *zp) {
+ static char ret[sizeof "(4294967296?)"]; /* 2^32 */
+
+ switch (zp->z_type) {
+ case Z_MASTER: return ("master");
+ case Z_SLAVE: return ("slave");
+#ifdef STUBS
+ case Z_STUB: return ("stub");
+#endif
+ case Z_CACHE: return ("cache");
+ default:
+ sprintf(ret, "(%u?)", (u_int32_t)zp->z_type);
+ return (ret);
+ }
+}
+
+#ifdef DEBUG
+void
+printzoneinfo(int zonenum, int category, int level) {
+ struct timeval tt;
+ struct zoneinfo *zp = &zones[zonenum];
+
+ if (debug == 0)
+ return;
+
+ if (!zp->z_origin)
+ return;
+
+ gettime(&tt);
+
+ ns_debug(category, level, "zone %d: %s, class %s, type %s", zonenum,
+ zp->z_origin[0] ? zp->z_origin : ".",
+ p_class(zp->z_class), zoneTypeString(zp));
+ if (zp->z_source)
+ ns_debug(category, level, "\tsource %s", zp->z_source);
+ ns_debug(category, level, "\tflags %lx, serial %u, minimum %u",
+ (u_long)zp->z_flags, zp->z_serial, zp->z_minimum);
+ ns_debug(category, level, "\trefresh %u, retry %u, expire %u",
+ zp->z_refresh, zp->z_retry, zp->z_expire);
+ if (zp->z_time)
+ ns_debug(category, level, "\tz_time %lu (now %lu, left: %lu)",
+ zp->z_time, (u_long)tt.tv_sec,
+ (u_long)(zp->z_time - tt.tv_sec));
+ else
+ ns_debug(category, level, "\tz_time %lu", zp->z_time);
+#ifdef BIND_UPDATE
+ if (zp->z_type == z_master && zp->z_flags & Z_DYNAMIC) {
+ ns_debug(category, level,
+ "\tdumpintvl %lu, soaincrintvl %lu deferupdcnt %lu",
+ zp->z_dumpintvl, zp->z_soaincrintvl,
+ zp->z_deferupdcnt);
+ if (zp->z_soaincrtime)
+ ns_debug(category, level,
+ "\tz_soaincrtime %lu (now %lu, left: %lu)",
+ zp->z_soaincrtime, (u_long)tt.tv_sec,
+ (u_long)(zp->z_soaincrtime - tt.tv_sec));
+ else
+ ns_debug(category, level, "\tz_soaincrtime %lu",
+ zp->z_soaincrtime);
+ if (zp->z_dumptime)
+ ns_debug(category, level,
+ "\tz_dumptime %lu (now %lu, left: %lu)",
+ zp->z_dumptime, (u_long)tt.tv_sec,
+ (u_long)(zp->z_dumptime - tt.tv_sec));
+ else
+ ns_debug(category, level, "\tz_dumptime %lu",
+ zp->z_dumptime);
+ }
+#endif
+}
+#endif /* DEBUG */
+
+/* clean_cache(htp, all)
+ * Scan the entire cache looking for expired TTL's on nonauthoritative
+ * data, and remove it. if `all' is true, ignore TTL and rm everything.
+ * notes:
+ * this should be lazy and eventlib driven.
+ * return:
+ * number of deleted RRs.
+ */
+int
+clean_cache(struct hashbuf *htp, int all) {
+ struct databuf *dp, *pdp;
+ struct namebuf *np, *pnp, *npn;
+ struct namebuf **npp, **nppend;
+ int deleted = 0;
+
+ 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;
+ (void)NULL) {
+ if (dp->d_zone == DB_Z_CACHE &&
+ (stale(dp) || all)) {
+ dp = rm_datum(dp, np, pdp, NULL);
+ deleted++;
+ } else {
+ pdp = dp;
+ dp = dp->d_next;
+ }
+ } /*for(pdp)*/
+
+ if (np->n_hash) {
+ /* Call recursively to remove subdomains. */
+ deleted += clean_cache(np->n_hash, all);
+
+ /* If now empty, free it */
+ if (np->n_hash->h_cnt == 0) {
+ rm_hash(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)*/
+ return (deleted);
+}
+
+void
+purge_zone(const char *dname, struct hashbuf *htp, int class) {
+ const char *fname;
+ struct databuf *dp, *pdp;
+ struct namebuf *np;
+ struct hashbuf *phtp = htp;
+ int root_zone = 0;
+
+ ns_debug(ns_log_default, 1, "purge_zone(%s,%d)", dname, class);
+ if ((np = nlookup(dname, &phtp, &fname, 0)) && dname == fname &&
+ !ns_wildcard(NAME(*np))) {
+ for (pdp = NULL, dp = np->n_data; dp != NULL; (void)NULL) {
+ if (dp->d_class == class)
+ dp = rm_datum(dp, np, pdp, NULL);
+ else {
+ pdp = dp;
+ dp = dp->d_next;
+ }
+ }
+
+ if (*dname == '\0')
+ root_zone = 1;
+
+ if (np->n_hash != NULL || root_zone) {
+ struct hashbuf *h;
+
+ if (root_zone)
+ h = htp;
+ else
+ h = np->n_hash;
+
+ purge_z_2(h, class);
+ if (h->h_cnt == 0 && !root_zone) {
+ rm_hash(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;
+
+ ns_debug(ns_log_default, 3,
+ "purge_zone: cleaning cache");
+
+ /* 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) {
+ ns_debug(ns_log_default, 3,
+ "purge_zone: found our selves");
+ npn = rm_name(nnp,npp,pnp);
+ phtp->h_cnt--;
+ } else {
+ npn = nnp->n_next;
+ pnp = nnp;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void
+purge_z_2(htp, class)
+ struct hashbuf *htp;
+ int class;
+{
+ struct databuf *dp, *pdp;
+ 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;
+ (void)NULL) {
+ if (dp->d_class == class)
+ dp = rm_datum(dp, np, pdp,
+ NULL);
+ 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) {
+ rm_hash(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(struct databuf *dp, int class) {
+ int ret = 0;
+
+ for ((void)NULL; dp; dp = dp->d_next) {
+ if (dp->d_class != class)
+ continue;
+ if (dp->d_zone == DB_Z_CACHE)
+ continue;
+ if (dp->d_rcode) /* This should not occur. */
+ continue;
+ if (dp->d_type != T_SOA)
+ continue;
+ ret = 1;
+ break;
+ }
+ ns_debug(ns_log_default, 3, "bottom_of_zone() == %d", ret);
+ return (ret);
+}
+
+/*
+ * Handle XFER limit for a nameserver.
+ */
+static int
+nxfers(struct zoneinfo *zp, int delta) {
+ struct in_addr nsa;
+ struct nameser *nsp;
+ int ret;
+
+ if (ina_hlong(zp->z_xaddr) != INADDR_ANY)
+ 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(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)
+ ns_warning(ns_log_default,
+ "zone transfer timeout for \"%s\"; pid %lu missing",
+ zp->z_origin, (u_long)zp->z_xferpid);
+ else if (kill(zp->z_xferpid, SIGKILL) == -1)
+ ns_warning(ns_log_default,
+ "zone transfer timeout for \"%s\"; kill pid %lu: %s",
+ zp->z_origin, (u_long)zp->z_xferpid,
+ strerror(errno));
+ else
+ ns_warning(ns_log_default,
+"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, SIGTERM) == -1) {
+ if (errno == ESRCH)
+ /* No warning on first time, it may have just exited */
+ zp->z_flags |= Z_XFER_GONE;
+ else {
+ ns_warning(ns_log_default,
+ "zone transfer timeout for \"%s\"; pid %lu kill failed %s",
+ zp->z_origin, (u_long)zp->z_xferpid,
+ strerror(errno));
+ zp->z_flags |= Z_XFER_ABORTED;
+ }
+ } else {
+ ns_notice(ns_log_default,
+ "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.
+ */
+void
+reapchild(evContext ctx, void *uap, int sig) {
+ int pid, i;
+ WAIT_T status;
+ int saved_errno = errno;
+
+ gettime(&tt);
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ 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;
+ ns_need(MAIN_NEED_ENDXFER);
+ break;
+ }
+ }
+ }
+
+ errno = saved_errno;
+}
+
+/*
+ * Finish processing of of finished xfers
+ */
+void
+endxfer() {
+ struct zoneinfo *zp;
+ int exitstatus, pid, i;
+ WAIT_T status;
+
+ 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);
+ ns_debug(ns_log_default, 1,
+ "\nendxfer: child %d zone %s returned status=%d termsig=%d",
+ pid, zp->z_origin, exitstatus,
+ WIFSIGNALED(status) ? WTERMSIG(status) : -1);
+ if (WIFSIGNALED(status)) {
+ if (WTERMSIG(status) != SIGKILL) {
+ ns_notice(ns_log_default,
+ "named-xfer \"%s\" exited with signal %d",
+ zp->z_origin[0]?zp->z_origin:".",
+ WTERMSIG(status));
+ }
+ ns_retrytime(zp, tt.tv_sec);
+ sched_zone_maint(zp);
+ } else {
+ switch (exitstatus) {
+ case XFER_UPTODATE:
+ markUpToDate(zp);
+ sched_zone_maint(zp);
+ break;
+
+ case XFER_SUCCESS:
+ /* XXX should incorporate loadxfer() */
+ zp->z_flags |= Z_NEED_RELOAD;
+ zp->z_flags &= ~Z_SYSLOGGED;
+ ns_need(MAIN_NEED_ZONELOAD);
+ break;
+
+ case XFER_TIMEOUT:
+ if (!(zp->z_flags & Z_SYSLOGGED)) {
+ zp->z_flags |= Z_SYSLOGGED;
+ ns_notice(ns_log_default,
+ "zoneref: Masters for secondary zone \"%s\" unreachable",
+ zp->z_origin);
+ }
+ ns_retrytime(zp, tt.tv_sec);
+ sched_zone_maint(zp);
+ break;
+
+ default:
+ if (!(zp->z_flags & Z_SYSLOGGED)) {
+ zp->z_flags |= Z_SYSLOGGED;
+ ns_notice(ns_log_default,
+ "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);
+ sched_zone_maint(zp);
+ break;
+ }
+ break;
+ }
+ }
+ xferstatus[i].xfer_state = XFER_IDLE;
+ xferstatus[i].xfer_pid = 0;
+ }
+ tryxfer();
+}
+
+/*
+ * Try to start some xfers - new "fair scheduler" by Bob Halley @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)
+ ns_debug(ns_log_default, 3, "zones changed: %p != %p",
+ lastzones, zones);
+ lastzones = zones;
+ zp = zones;
+ }
+
+ /* did zones shrink? */
+ if (lastnzones > nzones) {
+ ns_debug(ns_log_default, 3, "zones shrunk");
+ zp = zones;
+ }
+ lastnzones = nzones;
+
+ if (zp == zones)
+ stopzp = &zones[nzones-1];
+ else
+ stopzp = zp - 1;
+
+ ns_debug(ns_log_default, 3,
+ "tryxfer start zp=%p stopzp=%p def=%d running=%d",
+ zp, stopzp, xfers_deferred, xfers_running);
+
+ startzp = zp;
+ for (;;) {
+ int xfers;
+
+ if (!xfers_deferred ||
+ xfers_running >= server_options->transfers_in)
+ break;
+
+ if ((xfers = nxfers(zp, 0)) != -1 &&
+ xfers < server_options->transfers_per_ns &&
+ (zp->z_flags & Z_NEED_XFER)) {
+ nxfers(zp, 1);
+ xfers_deferred--;
+ startxfer(zp);
+ sched_zone_maint(zp);
+ }
+
+ if (zp == stopzp) {
+ ns_debug(ns_log_default, 3, "tryxfer stop mark");
+ zp = startzp;
+ break;
+ }
+
+ zp++;
+ /* wrap around? */
+ if (zp == &zones[nzones])
+ zp = zones;
+ }
+ ns_debug(ns_log_default, 3, "tryxfer stop zp=%p", zp);
+}
+
+/*
+ * Reload zones whose transfers have completed.
+ */
+void
+loadxfer() {
+ struct zoneinfo *zp;
+
+ gettime(&tt);
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ if (zp->z_flags & Z_NEED_RELOAD) {
+ ns_debug(ns_log_default, 1, "loadxfer() \"%s\"",
+ zp->z_origin[0] ? zp->z_origin : ".");
+ zp->z_flags &= ~(Z_NEED_RELOAD|Z_AUTH);
+/* XXX this is bad, should be done in ns_reload() for primary changes. */
+ ns_stopxfrs(zp);
+ purge_zone(zp->z_origin, hashtab, zp->z_class);
+ 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);
+ sched_zone_maint(zp);
+ }
+ }
+}
+
+/*
+ * Add this zone to the set of those needing transfers.
+ */
+static void
+addxfer(struct zoneinfo *zp) {
+ if (!(zp->z_flags & Z_NEED_XFER)) {
+ zp->z_flags |= Z_NEED_XFER;
+ xfers_deferred++;
+ tryxfer();
+ }
+}
+
+/*
+ * Flush and reload data base.
+ */
+void
+ns_reload() {
+ ns_notice(ns_log_default, "reloading nameserver");
+
+ qflush();
+ sq_flush(NULL);
+#ifdef FORCED_RELOAD
+ reloading = 1; /* to force transfer if secondary and backing up */
+#endif
+ ns_init(conffile);
+ time(&resettime);
+#ifdef FORCED_RELOAD
+ reloading = 0;
+#endif /* FORCED_RELOAD */
+ ns_notice(ns_log_default, "Ready to answer queries.");
+}
diff --git a/contrib/bind/bin/named/ns_ncache.c b/contrib/bind/bin/named/ns_ncache.c
new file mode 100644
index 0000000..413ccc6
--- /dev/null
+++ b/contrib/bind/bin/named/ns_ncache.c
@@ -0,0 +1,226 @@
+#if !defined(lint) && !defined(SABER)
+static char rcsid[] = "$Id: ns_ncache.c,v 8.17 1998/03/20 01:12:01 halley Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#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 <errno.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+#define BOUNDS_CHECK(ptr, count) \
+ do { \
+ if ((ptr) + (count) > eom) { \
+ return; \
+ } \
+ } while (0)
+
+void
+cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from) {
+ struct databuf *dp;
+ HEADER *hp;
+ u_char *cp, *eom, *rdatap;
+ char dname[MAXDNAME];
+ int n;
+ int type, class;
+ int Vcode;
+ int flags;
+ u_int16_t ancount;
+ u_int dlen;
+
+ nameserIncr(from.sin_addr, nssRcvdNXD);
+
+ hp = (HEADER *)msg;
+ cp = msg+HFIXEDSZ;
+ eom = msg + msglen;
+
+ n = dn_expand(msg, eom, cp, dname, sizeof dname);
+ if (n < 0) {
+ ns_debug(ns_log_ncache, 1,
+ "Query expand name failed: cache_n_resp");
+ hp->rcode = FORMERR;
+ return;
+ }
+ cp += n;
+ BOUNDS_CHECK(cp, 2 * INT16SZ);
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ ns_debug(ns_log_ncache, 1, "ncache: dname %s, type %d, class %d",
+ dname, type, class);
+
+ ancount = ntohs(hp->ancount);
+
+ while (ancount--) {
+ u_int32_t ttl;
+ u_int16_t atype;
+ u_int16_t aclass;
+ n = dn_skipname(cp, eom);
+ if (n < 0) {
+ ns_debug(ns_log_ncache, 3, "ncache: form error");
+ return;
+ }
+ cp += n;
+ BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
+ GETSHORT(atype, cp);
+ GETSHORT(aclass, cp);
+ if (atype != T_CNAME || aclass != class) {
+ ns_debug(ns_log_ncache, 3, "ncache: form error");
+ return;
+ }
+ GETLONG(ttl, cp);
+ GETSHORT(dlen, cp);
+ BOUNDS_CHECK(cp, dlen);
+ rdatap = cp;
+ n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname);
+ if (n < 0) {
+ ns_debug(ns_log_ncache, 3, "ncache: form error");
+ return;
+ }
+ cp += n;
+ if (cp != rdatap + dlen) {
+ ns_debug(ns_log_ncache, 3, "ncache: form error");
+ return;
+ }
+ }
+
+#ifdef RETURNSOA
+ if (hp->nscount) {
+ u_int32_t ttl;
+ u_int16_t atype;
+ u_char *tp = cp;
+ u_char *cp1;
+ u_char data[MAXDATA];
+ size_t len = sizeof data;
+
+ /* we store NXDOMAIN as T_SOA regardless of the query type */
+ if (hp->rcode == NXDOMAIN)
+ type = T_SOA;
+
+ /* store ther SOA record */
+ n = dn_skipname(tp, msg + msglen);
+ if (n < 0) {
+ ns_debug(ns_log_ncache, 3, "ncache: form error");
+ return;
+ }
+ tp += n;
+
+ BOUNDS_CHECK(tp, 3 * INT16SZ + INT32SZ);
+ GETSHORT(atype, tp); /* type */
+ if (atype != T_SOA) {
+ ns_debug(ns_log_ncache, 3,
+ "ncache: type (%d) != T_SOA", atype);
+ goto no_soa;
+ }
+ tp += INT16SZ; /* class */
+ GETLONG(ttl, tp); /* ttl */
+ GETSHORT(dlen, tp); /* dlen */
+ BOUNDS_CHECK(tp, dlen);
+ rdatap = tp;
+
+ /* origin */
+ n = dn_expand(msg, msg + msglen, tp, (char*)data, len);
+ if (n < 0) {
+ ns_debug(ns_log_ncache, 3,
+ "ncache: origin form error");
+ return;
+ }
+ tp += n;
+ n = strlen((char*)data) + 1;
+ cp1 = data + n;
+ len -= n;
+ /* mail */
+ n = dn_expand(msg, msg + msglen, tp, (char*)cp1, len);
+ if (n < 0) {
+ ns_debug(ns_log_ncache, 3, "ncache: mail form error");
+ return;
+ }
+ tp += n;
+ n = strlen((char*)cp1) + 1;
+ cp1 += n;
+ len -= n;
+ n = 5 * INT32SZ;
+ BOUNDS_CHECK(tp, n);
+ memcpy(cp1, tp, n);
+ /* serial, refresh, retry, expire, min */
+ cp1 += n;
+ len -= n;
+ tp += n;
+ if (tp != rdatap + dlen) {
+ ns_debug(ns_log_ncache, 3, "ncache: form error");
+ return;
+ }
+ /* store the zone of the soa record */
+ n = dn_expand(msg, msg + msglen, cp, (char*)cp1, len);
+ if (n < 0) {
+ ns_debug(ns_log_ncache, 3, "ncache: form error 2");
+ return;
+ }
+ n = strlen((char*)cp1) + 1;
+ cp1 += n;
+
+ dp = savedata(class, type, MIN(ttl, NTTL) + tt.tv_sec, data,
+ cp1 - data);
+ } else {
+ no_soa:
+#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, NULL, flags, hashtab, from)) != OK) {
+ ns_debug(ns_log_ncache, 1,
+ "db_update failed (%d), cache_n_resp()", n);
+ db_freedata(dp);
+ return;
+ }
+ ns_debug(ns_log_ncache, 4,
+ "ncache succeeded: [%s %s %s] rcode:%d ttl:%ld",
+ dname, p_type(type), p_class(class),
+ dp->d_rcode, (long)(dp->d_ttl - tt.tv_sec));
+}
diff --git a/contrib/bind/bin/named/ns_parser.c b/contrib/bind/bin/named/ns_parser.c
new file mode 100644
index 0000000..47944ea
--- /dev/null
+++ b/contrib/bind/bin/named/ns_parser.c
@@ -0,0 +1,2376 @@
+#ifndef lint
+static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93 (BSDI)";
+#endif
+#include <stdlib.h>
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define YYEMPTY (-1)
+#define YYLEX yylex()
+#define yyclearin (yychar=YYEMPTY)
+#define yyerrok (yyerrflag=0)
+#define YYRECOVERING (yyerrflag!=0)
+#define YYPREFIX "yy"
+#line 2 "ns_parser.y"
+#if !defined(lint) && !defined(SABER)
+static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/* Global C stuff goes here. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+
+#include "port_after.h"
+
+#include "named.h"
+#include "ns_parseutil.h"
+#include "ns_lexer.h"
+
+#define SYM_ZONE 0x010000
+#define SYM_SERVER 0x020000
+#define SYM_KEY 0x030000
+#define SYM_ACL 0x040000
+#define SYM_CHANNEL 0x050000
+#define SYM_PORT 0x060000
+
+#define SYMBOL_TABLE_SIZE 29989 /* should always be prime */
+static symbol_table symtab;
+
+#define AUTH_TABLE_SIZE 397 /* should always be prime */
+static symbol_table authtab = NULL;
+
+static zone_config current_zone;
+static int seen_zone;
+
+static options current_options;
+static int seen_options;
+
+static topology_config current_topology;
+static int seen_topology;
+
+static server_config current_server;
+static int seen_server;
+
+static char *current_algorithm;
+static char *current_secret;
+
+static log_config current_logging;
+static int current_category;
+static int chan_type;
+static int chan_level;
+static u_int chan_flags;
+static int chan_facility;
+static char *chan_name;
+static int chan_versions;
+static u_long chan_max_size;
+
+static log_channel lookup_channel(char *);
+static void define_channel(char *, log_channel);
+static char *canonical_name(char *);
+
+int yyparse();
+
+#line 96 "ns_parser.y"
+typedef union {
+ char * cp;
+ int s_int;
+ long num;
+ u_long ul_int;
+ u_int16_t us_int;
+ struct in_addr ip_addr;
+ ip_match_element ime;
+ ip_match_list iml;
+ key_info keyi;
+ enum axfr_format axfr_fmt;
+} YYSTYPE;
+#line 121 "y.tab.c"
+#define L_EOS 257
+#define L_IPADDR 258
+#define L_NUMBER 259
+#define L_STRING 260
+#define L_QSTRING 261
+#define L_END_INCLUDE 262
+#define T_INCLUDE 263
+#define T_OPTIONS 264
+#define T_DIRECTORY 265
+#define T_PIDFILE 266
+#define T_NAMED_XFER 267
+#define T_DUMP_FILE 268
+#define T_STATS_FILE 269
+#define T_MEMSTATS_FILE 270
+#define T_FAKE_IQUERY 271
+#define T_RECURSION 272
+#define T_FETCH_GLUE 273
+#define T_QUERY_SOURCE 274
+#define T_LISTEN_ON 275
+#define T_PORT 276
+#define T_ADDRESS 277
+#define T_DATASIZE 278
+#define T_STACKSIZE 279
+#define T_CORESIZE 280
+#define T_DEFAULT 281
+#define T_UNLIMITED 282
+#define T_FILES 283
+#define T_HOSTSTATS 284
+#define T_DEALLOC_ON_EXIT 285
+#define T_TRANSFERS_IN 286
+#define T_TRANSFERS_OUT 287
+#define T_TRANSFERS_PER_NS 288
+#define T_TRANSFER_FORMAT 289
+#define T_MAX_TRANSFER_TIME_IN 290
+#define T_ONE_ANSWER 291
+#define T_MANY_ANSWERS 292
+#define T_NOTIFY 293
+#define T_AUTH_NXDOMAIN 294
+#define T_MULTIPLE_CNAMES 295
+#define T_CLEAN_INTERVAL 296
+#define T_INTERFACE_INTERVAL 297
+#define T_STATS_INTERVAL 298
+#define T_LOGGING 299
+#define T_CATEGORY 300
+#define T_CHANNEL 301
+#define T_SEVERITY 302
+#define T_DYNAMIC 303
+#define T_FILE 304
+#define T_VERSIONS 305
+#define T_SIZE 306
+#define T_SYSLOG 307
+#define T_DEBUG 308
+#define T_NULL_OUTPUT 309
+#define T_PRINT_TIME 310
+#define T_PRINT_CATEGORY 311
+#define T_PRINT_SEVERITY 312
+#define T_TOPOLOGY 313
+#define T_SERVER 314
+#define T_LONG_AXFR 315
+#define T_BOGUS 316
+#define T_TRANSFERS 317
+#define T_KEYS 318
+#define T_ZONE 319
+#define T_IN 320
+#define T_CHAOS 321
+#define T_HESIOD 322
+#define T_TYPE 323
+#define T_MASTER 324
+#define T_SLAVE 325
+#define T_STUB 326
+#define T_RESPONSE 327
+#define T_HINT 328
+#define T_MASTERS 329
+#define T_TRANSFER_SOURCE 330
+#define T_ALSO_NOTIFY 331
+#define T_ACL 332
+#define T_ALLOW_UPDATE 333
+#define T_ALLOW_QUERY 334
+#define T_ALLOW_TRANSFER 335
+#define T_SEC_KEY 336
+#define T_ALGID 337
+#define T_SECRET 338
+#define T_CHECK_NAMES 339
+#define T_WARN 340
+#define T_FAIL 341
+#define T_IGNORE 342
+#define T_FORWARD 343
+#define T_FORWARDERS 344
+#define T_ONLY 345
+#define T_FIRST 346
+#define T_IF_NO_ANSWER 347
+#define T_IF_NO_DOMAIN 348
+#define T_YES 349
+#define T_TRUE 350
+#define T_NO 351
+#define T_FALSE 352
+#define YYERRCODE 256
+short yylhs[] = { -1,
+ 0, 25, 25, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 27, 34, 28, 35, 35, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 38, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 5, 5, 4, 4, 3, 3, 43, 44, 40, 40,
+ 40, 40, 2, 2, 23, 23, 23, 23, 23, 21,
+ 21, 21, 22, 22, 22, 37, 37, 37, 37, 41,
+ 41, 41, 41, 20, 20, 20, 20, 42, 42, 42,
+ 39, 39, 45, 45, 46, 47, 29, 48, 48, 48,
+ 50, 49, 52, 49, 54, 54, 54, 54, 55, 55,
+ 56, 57, 57, 57, 57, 57, 58, 9, 9, 10,
+ 10, 59, 60, 60, 60, 60, 60, 60, 60, 53,
+ 53, 53, 8, 8, 61, 51, 51, 51, 7, 7,
+ 7, 6, 62, 30, 63, 63, 64, 64, 64, 64,
+ 64, 14, 14, 12, 12, 11, 11, 11, 11, 11,
+ 13, 17, 66, 65, 65, 65, 67, 33, 68, 68,
+ 68, 18, 19, 32, 70, 31, 69, 69, 15, 15,
+ 16, 16, 16, 16, 71, 71, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 73, 73,
+ 75, 74, 74, 76, 76, 77, 1, 24, 24,
+};
+short yylen[] = { 2,
+ 1, 1, 2, 1, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 3, 0, 5, 2, 3, 0, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 3, 5, 2, 0, 5, 2, 4,
+ 4, 4, 1, 1, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2, 1, 1,
+ 2, 2, 0, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 1, 1, 1, 1, 2, 2, 2,
+ 0, 1, 2, 3, 1, 0, 5, 2, 3, 1,
+ 0, 6, 0, 6, 1, 1, 2, 1, 2, 2,
+ 2, 0, 1, 1, 2, 2, 3, 1, 1, 0,
+ 1, 2, 1, 1, 1, 2, 2, 2, 2, 2,
+ 3, 1, 1, 1, 1, 2, 3, 1, 1, 1,
+ 1, 1, 0, 6, 2, 3, 2, 2, 2, 4,
+ 1, 2, 3, 1, 2, 1, 3, 3, 1, 3,
+ 1, 1, 1, 2, 3, 1, 0, 6, 2, 2,
+ 1, 3, 3, 5, 0, 5, 0, 3, 0, 1,
+ 1, 1, 1, 1, 2, 3, 2, 2, 4, 2,
+ 2, 4, 4, 4, 2, 2, 4, 1, 2, 3,
+ 1, 0, 1, 2, 3, 1, 1, 1, 1,
+};
+short yydefred[] = { 0,
+ 0, 11, 0, 15, 96, 0, 0, 0, 167, 0,
+ 0, 2, 4, 0, 0, 0, 0, 0, 0, 12,
+ 13, 0, 0, 0, 143, 0, 208, 209, 0, 0,
+ 3, 5, 6, 7, 8, 9, 10, 14, 0, 0,
+ 0, 175, 180, 0, 0, 50, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 37,
+ 0, 0, 43, 44, 100, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 154, 0, 159, 0, 161,
+ 0, 20, 22, 21, 25, 23, 24, 69, 65, 66,
+ 67, 68, 26, 27, 28, 0, 0, 39, 0, 0,
+ 0, 0, 85, 86, 87, 80, 84, 81, 82, 83,
+ 30, 31, 88, 89, 90, 51, 52, 45, 46, 29,
+ 32, 33, 47, 48, 49, 0, 0, 0, 70, 71,
+ 72, 0, 76, 77, 78, 79, 36, 0, 16, 0,
+ 17, 140, 141, 101, 142, 139, 134, 103, 133, 97,
+ 0, 98, 151, 0, 0, 0, 0, 0, 0, 0,
+ 176, 0, 0, 0, 155, 152, 174, 0, 171, 0,
+ 0, 0, 0, 0, 207, 56, 55, 58, 53, 54,
+ 57, 61, 62, 64, 0, 0, 0, 0, 73, 74,
+ 75, 34, 0, 18, 0, 0, 99, 149, 147, 148,
+ 0, 144, 0, 145, 198, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 157, 158,
+ 160, 153, 0, 0, 169, 170, 168, 0, 42, 40,
+ 41, 95, 0, 0, 0, 0, 0, 166, 163, 162,
+ 0, 0, 146, 195, 196, 188, 181, 182, 184, 183,
+ 187, 0, 190, 0, 0, 0, 0, 191, 178, 0,
+ 185, 172, 173, 35, 38, 0, 93, 138, 135, 0,
+ 0, 132, 0, 0, 0, 125, 0, 0, 0, 0,
+ 123, 124, 0, 150, 0, 164, 201, 0, 0, 206,
+ 0, 0, 0, 0, 0, 0, 186, 94, 102, 0,
+ 136, 108, 0, 105, 126, 0, 119, 121, 122, 118,
+ 127, 128, 129, 104, 0, 130, 165, 189, 0, 199,
+ 197, 0, 204, 192, 193, 194, 137, 107, 0, 0,
+ 0, 0, 117, 131, 200, 205, 109, 110, 111, 115,
+ 116,
+};
+short yydgoto[] = { 10,
+ 197, 122, 198, 201, 138, 164, 165, 289, 328, 329,
+ 96, 97, 98, 99, 42, 271, 259, 192, 193, 126,
+ 152, 212, 113, 100, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 23, 81, 82, 157, 158, 253, 118,
+ 83, 84, 119, 120, 254, 255, 24, 88, 89, 215,
+ 290, 216, 300, 325, 351, 352, 353, 301, 302, 303,
+ 291, 41, 178, 179, 261, 262, 30, 194, 181, 91,
+ 237, 238, 308, 311, 309, 312, 313,
+};
+short yysindex[] = { 122,
+ -200, 0, -238, 0, 0, -227, -228, -188, 0, 0,
+ 122, 0, 0, -220, -176, -164, -158, -155, -149, 0,
+ 0, -147, -88, -4, 0, -188, 0, 0, 4, -188,
+ 0, 0, 0, 0, 0, 0, 0, 0, 79, -240,
+ 11, 0, 0, 16, 20, 0, -218, -60, -40, -34,
+ -24, -14, -53, -53, -53, -193, -95, -190, -190, -190,
+ -190, -53, -53, -98, -56, -41, -162, -31, -53, -53,
+ -53, 6, 19, 22, 102, 161, 163, -204, -57, 0,
+ -120, 36, 0, 0, 0, -73, -205, -115, 38, -241,
+ 177, 257, 258, 16, -69, 0, 49, 0, -29, 0,
+ -226, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, -33, -36, 0, 31, 32,
+ 51, 185, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 16, 16, 16, 0, 0,
+ 0, -277, 0, 0, 0, 0, 0, 188, 0, 55,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 57, 0, 0, -162, -53, 56, 193, -118, 60, 104,
+ 0, 59, 63, -25, 0, 0, 0, 69, 0, -188,
+ -188, -11, -7, 203, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 16, -20, -16, -9, 0, 0,
+ 0, 0, 73, 0, 209, 210, 0, 0, 0, 0,
+ -143, 0, 77, 0, 0, 78, -53, 75, -184, 215,
+ -36, 216, 217, 218, 232, -277, -10, 99, 0, 0,
+ 0, 0, 113, 114, 0, 0, 0, -1, 0, 0,
+ 0, 0, 236, 73, 123, -214, -222, 0, 0, 0,
+ -81, 124, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 121, 0, 125, 16, 16, 16, 0, 0, 130,
+ 0, 0, 0, 0, 0, 131, 0, 0, 0, -104,
+ 132, 0, -202, 129, -221, 0, -53, -53, -53, -100,
+ 0, 0, 134, 0, 136, 0, 0, -96, 138, 0,
+ 271, 125, 141, 3, 8, 12, 0, 0, 0, 142,
+ 0, 0, 143, 0, 0, -89, 0, 0, 0, 0,
+ 0, 0, 0, 0, 144, 0, 0, 0, 146, 0,
+ 0, 147, 0, 0, 0, 0, 0, 0, -185, -190,
+ 76, 100, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+short yyrindex[] = { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 400, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, -85, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 149, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 284, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 149, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 155, 158, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 159, 160,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 294, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 295, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 299, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 168, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 301, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 171, 0, 0, 172, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 173, 174, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+short yygindex[] = { 0,
+ 311, 0, 0, 211, 266, 0, 0, 357, 0, 0,
+ 350, 95, 0, -80, 0, 0, 0, 253, 255, -58,
+ 0, 212, -43, -8, 0, 438, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 369, 0, 0, 0, 0,
+ 0, 0, 331, 333, 0, 199, 0, 0, 367, 0,
+ 0, 0, 0, 0, 105, 108, 0, 0, 0, 156,
+ 170, 0, 0, 283, 0, 201, 0, 0, 0, 0,
+ 0, 226, 0, 0, 157, 0, 152,
+};
+#define YYTABLESIZE 465
+short yytable[] = { 29,
+ 128, 129, 130, 95, 159, 200, 222, 95, 196, 170,
+ 114, 115, 95, 184, 173, 85, 95, 43, 131, 132,
+ 319, 45, 22, 95, 334, 140, 141, 142, 338, 189,
+ 25, 95, 26, 292, 39, 95, 32, 179, 27, 28,
+ 95, 288, 102, 304, 95, 27, 28, 174, 95, 127,
+ 127, 127, 127, 94, 27, 28, 20, 27, 28, 86,
+ 87, 21, 209, 210, 211, 206, 207, 208, 123, 27,
+ 28, 27, 28, 357, 175, 176, 177, 166, 169, 293,
+ 33, 294, 116, 117, 295, 327, 296, 297, 298, 299,
+ 124, 125, 34, 94, 167, 187, 358, 94, 35, 241,
+ 322, 36, 94, 167, 249, 323, 94, 37, 250, 38,
+ 190, 191, 258, 94, 279, 251, 27, 28, 40, 149,
+ 150, 94, 151, 284, 248, 94, 44, 344, 136, 137,
+ 94, 219, 345, 90, 94, 46, 346, 173, 94, 267,
+ 268, 269, 101, 270, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, 57, 27, 28, 58, 59, 60,
+ 133, 307, 61, 62, 63, 64, 65, 66, 67, 68,
+ 174, 179, 69, 70, 71, 72, 73, 74, 27, 28,
+ 121, 243, 244, 265, 86, 87, 27, 28, 92, 93,
+ 27, 28, 75, 188, 314, 315, 316, 175, 176, 177,
+ 103, 293, 134, 294, 167, 108, 295, 162, 296, 297,
+ 298, 299, 260, 76, 77, 349, 350, 135, 78, 163,
+ 104, 199, 79, 80, 146, 195, 105, 139, 92, 93,
+ 27, 28, 92, 93, 27, 28, 106, 92, 93, 27,
+ 28, 92, 93, 27, 28, 225, 107, 169, 92, 93,
+ 27, 28, 260, 331, 332, 333, 92, 93, 27, 28,
+ 92, 93, 27, 28, 143, 92, 93, 27, 28, 92,
+ 93, 27, 28, 92, 93, 27, 28, 144, 188, 226,
+ 145, 169, 227, 147, 324, 148, 330, 153, 154, 155,
+ 156, 359, 161, 228, 172, 109, 110, 111, 112, 180,
+ 188, 188, 188, 182, 183, 186, 116, 205, 117, 195,
+ 213, 214, 229, 217, 220, 221, 224, 239, 230, 231,
+ 232, 240, 233, 234, 235, 242, 191, 247, 236, 190,
+ 252, 256, 257, 263, 46, 266, 264, 272, 274, 275,
+ 276, 127, 188, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 277, 281, 58, 59, 60, 225,
+ 285, 61, 62, 63, 64, 65, 66, 67, 68, 282,
+ 283, 69, 70, 71, 72, 73, 74, 1, 307, 287,
+ 306, 350, 310, 2, 3, 4, 317, 318, 321, 326,
+ 336, 75, 337, 226, 340, 341, 227, 343, 347, 1,
+ 354, 348, 355, 356, 349, 19, 63, 228, 188, 188,
+ 188, 177, 76, 77, 156, 59, 60, 78, 91, 92,
+ 5, 79, 80, 202, 120, 203, 229, 106, 112, 113,
+ 114, 204, 230, 231, 232, 6, 233, 234, 235, 218,
+ 7, 273, 236, 168, 185, 246, 245, 278, 31, 160,
+ 203, 202, 286, 8, 171, 335, 361, 9, 360, 320,
+ 223, 305, 280, 342, 339,
+};
+short yycheck[] = { 8,
+ 59, 60, 61, 33, 125, 42, 125, 33, 42, 125,
+ 54, 55, 33, 94, 256, 256, 33, 26, 62, 63,
+ 125, 30, 261, 33, 125, 69, 70, 71, 125, 256,
+ 258, 33, 261, 256, 123, 33, 257, 123, 260, 261,
+ 33, 256, 261, 125, 33, 260, 261, 289, 33, 58,
+ 59, 60, 61, 123, 260, 261, 257, 260, 261, 300,
+ 301, 262, 340, 341, 342, 146, 147, 148, 259, 260,
+ 261, 260, 261, 259, 316, 317, 318, 86, 87, 302,
+ 257, 304, 276, 277, 307, 307, 309, 310, 311, 312,
+ 281, 282, 257, 123, 309, 125, 282, 123, 257, 125,
+ 303, 257, 123, 309, 125, 308, 123, 257, 125, 257,
+ 337, 338, 256, 123, 125, 125, 260, 261, 123, 324,
+ 325, 123, 327, 125, 205, 123, 123, 125, 291, 292,
+ 123, 175, 125, 123, 123, 256, 125, 256, 123, 324,
+ 325, 326, 123, 328, 265, 266, 267, 268, 269, 270,
+ 271, 272, 273, 274, 275, 260, 261, 278, 279, 280,
+ 259, 258, 283, 284, 285, 286, 287, 288, 289, 290,
+ 289, 257, 293, 294, 295, 296, 297, 298, 260, 261,
+ 276, 190, 191, 227, 300, 301, 260, 261, 258, 259,
+ 260, 261, 313, 99, 275, 276, 277, 316, 317, 318,
+ 261, 302, 259, 304, 309, 259, 307, 281, 309, 310,
+ 311, 312, 221, 334, 335, 305, 306, 259, 339, 293,
+ 261, 258, 343, 344, 123, 259, 261, 259, 258, 259,
+ 260, 261, 258, 259, 260, 261, 261, 258, 259, 260,
+ 261, 258, 259, 260, 261, 256, 261, 256, 258, 259,
+ 260, 261, 261, 297, 298, 299, 258, 259, 260, 261,
+ 258, 259, 260, 261, 259, 258, 259, 260, 261, 258,
+ 259, 260, 261, 258, 259, 260, 261, 259, 184, 290,
+ 259, 290, 293, 123, 293, 123, 295, 345, 346, 347,
+ 348, 350, 257, 304, 257, 349, 350, 351, 352, 123,
+ 206, 207, 208, 47, 47, 257, 276, 123, 277, 259,
+ 123, 257, 323, 257, 259, 123, 257, 259, 329, 330,
+ 331, 259, 333, 334, 335, 257, 338, 125, 339, 337,
+ 258, 123, 123, 257, 256, 261, 259, 123, 123, 123,
+ 123, 350, 248, 265, 266, 267, 268, 269, 270, 271,
+ 272, 273, 274, 275, 123, 257, 278, 279, 280, 256,
+ 125, 283, 284, 285, 286, 287, 288, 289, 290, 257,
+ 257, 293, 294, 295, 296, 297, 298, 256, 258, 257,
+ 257, 306, 258, 262, 263, 264, 257, 257, 257, 261,
+ 257, 313, 257, 290, 257, 125, 293, 257, 257, 0,
+ 257, 259, 257, 257, 305, 257, 123, 304, 314, 315,
+ 316, 257, 334, 335, 257, 257, 257, 339, 125, 125,
+ 299, 343, 344, 125, 257, 125, 323, 257, 257, 257,
+ 257, 121, 329, 330, 331, 314, 333, 334, 335, 174,
+ 319, 231, 339, 87, 95, 193, 192, 236, 11, 81,
+ 120, 119, 254, 332, 88, 300, 352, 336, 351, 290,
+ 178, 261, 237, 312, 308,
+};
+#define YYFINAL 10
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 352
+#if YYDEBUG
+char *yyname[] = {
+"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+"'!'",0,0,0,0,0,0,0,0,"'*'",0,0,0,0,"'/'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"L_EOS",
+"L_IPADDR","L_NUMBER","L_STRING","L_QSTRING","L_END_INCLUDE","T_INCLUDE",
+"T_OPTIONS","T_DIRECTORY","T_PIDFILE","T_NAMED_XFER","T_DUMP_FILE",
+"T_STATS_FILE","T_MEMSTATS_FILE","T_FAKE_IQUERY","T_RECURSION","T_FETCH_GLUE",
+"T_QUERY_SOURCE","T_LISTEN_ON","T_PORT","T_ADDRESS","T_DATASIZE","T_STACKSIZE",
+"T_CORESIZE","T_DEFAULT","T_UNLIMITED","T_FILES","T_HOSTSTATS",
+"T_DEALLOC_ON_EXIT","T_TRANSFERS_IN","T_TRANSFERS_OUT","T_TRANSFERS_PER_NS",
+"T_TRANSFER_FORMAT","T_MAX_TRANSFER_TIME_IN","T_ONE_ANSWER","T_MANY_ANSWERS",
+"T_NOTIFY","T_AUTH_NXDOMAIN","T_MULTIPLE_CNAMES","T_CLEAN_INTERVAL",
+"T_INTERFACE_INTERVAL","T_STATS_INTERVAL","T_LOGGING","T_CATEGORY","T_CHANNEL",
+"T_SEVERITY","T_DYNAMIC","T_FILE","T_VERSIONS","T_SIZE","T_SYSLOG","T_DEBUG",
+"T_NULL_OUTPUT","T_PRINT_TIME","T_PRINT_CATEGORY","T_PRINT_SEVERITY",
+"T_TOPOLOGY","T_SERVER","T_LONG_AXFR","T_BOGUS","T_TRANSFERS","T_KEYS","T_ZONE",
+"T_IN","T_CHAOS","T_HESIOD","T_TYPE","T_MASTER","T_SLAVE","T_STUB","T_RESPONSE",
+"T_HINT","T_MASTERS","T_TRANSFER_SOURCE","T_ALSO_NOTIFY","T_ACL",
+"T_ALLOW_UPDATE","T_ALLOW_QUERY","T_ALLOW_TRANSFER","T_SEC_KEY","T_ALGID",
+"T_SECRET","T_CHECK_NAMES","T_WARN","T_FAIL","T_IGNORE","T_FORWARD",
+"T_FORWARDERS","T_ONLY","T_FIRST","T_IF_NO_ANSWER","T_IF_NO_DOMAIN","T_YES",
+"T_TRUE","T_NO","T_FALSE",
+};
+char *yyrule[] = {
+"$accept : config_file",
+"config_file : statement_list",
+"statement_list : statement",
+"statement_list : statement_list statement",
+"statement : include_stmt",
+"statement : options_stmt L_EOS",
+"statement : logging_stmt L_EOS",
+"statement : server_stmt L_EOS",
+"statement : zone_stmt L_EOS",
+"statement : acl_stmt L_EOS",
+"statement : key_stmt L_EOS",
+"statement : L_END_INCLUDE",
+"statement : error L_EOS",
+"statement : error L_END_INCLUDE",
+"include_stmt : T_INCLUDE L_QSTRING L_EOS",
+"$$1 :",
+"options_stmt : T_OPTIONS $$1 '{' options '}'",
+"options : option L_EOS",
+"options : options option L_EOS",
+"option :",
+"option : T_DIRECTORY L_QSTRING",
+"option : T_NAMED_XFER L_QSTRING",
+"option : T_PIDFILE L_QSTRING",
+"option : T_STATS_FILE L_QSTRING",
+"option : T_MEMSTATS_FILE L_QSTRING",
+"option : T_DUMP_FILE L_QSTRING",
+"option : T_FAKE_IQUERY yea_or_nay",
+"option : T_RECURSION yea_or_nay",
+"option : T_FETCH_GLUE yea_or_nay",
+"option : T_NOTIFY yea_or_nay",
+"option : T_HOSTSTATS yea_or_nay",
+"option : T_DEALLOC_ON_EXIT yea_or_nay",
+"option : T_AUTH_NXDOMAIN yea_or_nay",
+"option : T_MULTIPLE_CNAMES yea_or_nay",
+"option : T_CHECK_NAMES check_names_type check_names_opt",
+"option : T_LISTEN_ON maybe_port '{' address_match_list '}'",
+"option : T_FORWARD forward_opt",
+"$$2 :",
+"option : T_FORWARDERS $$2 '{' opt_forwarders_list '}'",
+"option : T_QUERY_SOURCE query_source",
+"option : T_ALLOW_QUERY '{' address_match_list '}'",
+"option : T_ALLOW_TRANSFER '{' address_match_list '}'",
+"option : T_TOPOLOGY '{' address_match_list '}'",
+"option : size_clause",
+"option : transfer_clause",
+"option : T_TRANSFER_FORMAT transfer_format",
+"option : T_MAX_TRANSFER_TIME_IN L_NUMBER",
+"option : T_CLEAN_INTERVAL L_NUMBER",
+"option : T_INTERFACE_INTERVAL L_NUMBER",
+"option : T_STATS_INTERVAL L_NUMBER",
+"option : error",
+"transfer_format : T_ONE_ANSWER",
+"transfer_format : T_MANY_ANSWERS",
+"maybe_wild_addr : L_IPADDR",
+"maybe_wild_addr : '*'",
+"maybe_wild_port : in_port",
+"maybe_wild_port : '*'",
+"query_source_address : T_ADDRESS maybe_wild_addr",
+"query_source_port : T_PORT maybe_wild_port",
+"query_source : query_source_address",
+"query_source : query_source_port",
+"query_source : query_source_address query_source_port",
+"query_source : query_source_port query_source_address",
+"maybe_port :",
+"maybe_port : T_PORT in_port",
+"yea_or_nay : T_YES",
+"yea_or_nay : T_TRUE",
+"yea_or_nay : T_NO",
+"yea_or_nay : T_FALSE",
+"yea_or_nay : L_NUMBER",
+"check_names_type : T_MASTER",
+"check_names_type : T_SLAVE",
+"check_names_type : T_RESPONSE",
+"check_names_opt : T_WARN",
+"check_names_opt : T_FAIL",
+"check_names_opt : T_IGNORE",
+"forward_opt : T_ONLY",
+"forward_opt : T_FIRST",
+"forward_opt : T_IF_NO_ANSWER",
+"forward_opt : T_IF_NO_DOMAIN",
+"size_clause : T_DATASIZE size_spec",
+"size_clause : T_STACKSIZE size_spec",
+"size_clause : T_CORESIZE size_spec",
+"size_clause : T_FILES size_spec",
+"size_spec : any_string",
+"size_spec : L_NUMBER",
+"size_spec : T_DEFAULT",
+"size_spec : T_UNLIMITED",
+"transfer_clause : T_TRANSFERS_IN L_NUMBER",
+"transfer_clause : T_TRANSFERS_OUT L_NUMBER",
+"transfer_clause : T_TRANSFERS_PER_NS L_NUMBER",
+"opt_forwarders_list :",
+"opt_forwarders_list : forwarders_in_addr_list",
+"forwarders_in_addr_list : forwarders_in_addr L_EOS",
+"forwarders_in_addr_list : forwarders_in_addr_list forwarders_in_addr L_EOS",
+"forwarders_in_addr : L_IPADDR",
+"$$3 :",
+"logging_stmt : T_LOGGING $$3 '{' logging_opts_list '}'",
+"logging_opts_list : logging_opt L_EOS",
+"logging_opts_list : logging_opts_list logging_opt L_EOS",
+"logging_opts_list : error",
+"$$4 :",
+"logging_opt : T_CATEGORY category $$4 '{' channel_list '}'",
+"$$5 :",
+"logging_opt : T_CHANNEL channel_name $$5 '{' channel_opt_list '}'",
+"channel_severity : any_string",
+"channel_severity : T_DEBUG",
+"channel_severity : T_DEBUG L_NUMBER",
+"channel_severity : T_DYNAMIC",
+"version_modifier : T_VERSIONS L_NUMBER",
+"version_modifier : T_VERSIONS T_UNLIMITED",
+"size_modifier : T_SIZE size_spec",
+"maybe_file_modifiers :",
+"maybe_file_modifiers : version_modifier",
+"maybe_file_modifiers : size_modifier",
+"maybe_file_modifiers : version_modifier size_modifier",
+"maybe_file_modifiers : size_modifier version_modifier",
+"channel_file : T_FILE L_QSTRING maybe_file_modifiers",
+"facility_name : any_string",
+"facility_name : T_SYSLOG",
+"maybe_syslog_facility :",
+"maybe_syslog_facility : facility_name",
+"channel_syslog : T_SYSLOG maybe_syslog_facility",
+"channel_opt : channel_file",
+"channel_opt : channel_syslog",
+"channel_opt : T_NULL_OUTPUT",
+"channel_opt : T_SEVERITY channel_severity",
+"channel_opt : T_PRINT_TIME yea_or_nay",
+"channel_opt : T_PRINT_CATEGORY yea_or_nay",
+"channel_opt : T_PRINT_SEVERITY yea_or_nay",
+"channel_opt_list : channel_opt L_EOS",
+"channel_opt_list : channel_opt_list channel_opt L_EOS",
+"channel_opt_list : error",
+"channel_name : any_string",
+"channel_name : T_NULL_OUTPUT",
+"channel : channel_name",
+"channel_list : channel L_EOS",
+"channel_list : channel_list channel L_EOS",
+"channel_list : error",
+"category_name : any_string",
+"category_name : T_DEFAULT",
+"category_name : T_NOTIFY",
+"category : category_name",
+"$$6 :",
+"server_stmt : T_SERVER L_IPADDR $$6 '{' server_info_list '}'",
+"server_info_list : server_info L_EOS",
+"server_info_list : server_info_list server_info L_EOS",
+"server_info : T_BOGUS yea_or_nay",
+"server_info : T_TRANSFERS L_NUMBER",
+"server_info : T_TRANSFER_FORMAT transfer_format",
+"server_info : T_KEYS '{' key_list '}'",
+"server_info : error",
+"address_match_list : address_match_element L_EOS",
+"address_match_list : address_match_list address_match_element L_EOS",
+"address_match_element : address_match_simple",
+"address_match_element : '!' address_match_simple",
+"address_match_simple : L_IPADDR",
+"address_match_simple : L_IPADDR '/' L_NUMBER",
+"address_match_simple : L_NUMBER '/' L_NUMBER",
+"address_match_simple : address_name",
+"address_match_simple : '{' address_match_list '}'",
+"address_name : any_string",
+"key_ref : any_string",
+"key_list_element : key_ref",
+"key_list : key_list_element L_EOS",
+"key_list : key_list key_list_element L_EOS",
+"key_list : error",
+"$$7 :",
+"key_stmt : T_SEC_KEY $$7 any_string '{' key_definition '}'",
+"key_definition : algorithm_id secret",
+"key_definition : secret algorithm_id",
+"key_definition : error",
+"algorithm_id : T_ALGID any_string L_EOS",
+"secret : T_SECRET any_string L_EOS",
+"acl_stmt : T_ACL any_string '{' address_match_list '}'",
+"$$8 :",
+"zone_stmt : T_ZONE L_QSTRING optional_class $$8 optional_zone_options_list",
+"optional_zone_options_list :",
+"optional_zone_options_list : '{' zone_option_list '}'",
+"optional_class :",
+"optional_class : any_string",
+"zone_type : T_MASTER",
+"zone_type : T_SLAVE",
+"zone_type : T_HINT",
+"zone_type : T_STUB",
+"zone_option_list : zone_option L_EOS",
+"zone_option_list : zone_option_list zone_option L_EOS",
+"zone_option : T_TYPE zone_type",
+"zone_option : T_FILE L_QSTRING",
+"zone_option : T_MASTERS '{' master_in_addr_list '}'",
+"zone_option : T_TRANSFER_SOURCE maybe_wild_addr",
+"zone_option : T_CHECK_NAMES check_names_opt",
+"zone_option : T_ALLOW_UPDATE '{' address_match_list '}'",
+"zone_option : T_ALLOW_QUERY '{' address_match_list '}'",
+"zone_option : T_ALLOW_TRANSFER '{' address_match_list '}'",
+"zone_option : T_MAX_TRANSFER_TIME_IN L_NUMBER",
+"zone_option : T_NOTIFY yea_or_nay",
+"zone_option : T_ALSO_NOTIFY '{' opt_notify_in_addr_list '}'",
+"zone_option : error",
+"master_in_addr_list : master_in_addr L_EOS",
+"master_in_addr_list : master_in_addr_list master_in_addr L_EOS",
+"master_in_addr : L_IPADDR",
+"opt_notify_in_addr_list :",
+"opt_notify_in_addr_list : notify_in_addr_list",
+"notify_in_addr_list : notify_in_addr L_EOS",
+"notify_in_addr_list : notify_in_addr_list notify_in_addr L_EOS",
+"notify_in_addr : L_IPADDR",
+"in_port : L_NUMBER",
+"any_string : L_STRING",
+"any_string : L_QSTRING",
+};
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 10000
+#define YYMAXDEPTH 10000
+#endif
+#endif
+#define YYINITSTACKSIZE 200
+int yydebug;
+int yynerrs;
+struct yystack {
+ short *ssp;
+ YYSTYPE *vsp;
+ short *ss;
+ YYSTYPE *vs;
+ int stacksize;
+ short *sslim;
+};
+int yychar; /* some people use this, so we copy it in & out */
+int yyerrflag; /* must be global for yyerrok & YYRECOVERING */
+YYSTYPE yylval;
+#line 1282 "ns_parser.y"
+
+static char *
+canonical_name(char *name) {
+ char canonical[MAXDNAME];
+
+ if (strlen(name) >= MAXDNAME)
+ return (NULL);
+ strcpy(canonical, name);
+ if (makename(canonical, ".", sizeof canonical) < 0)
+ return (NULL);
+ return (savestr(canonical, 0));
+}
+
+static void
+init_acls() {
+ ip_match_element ime;
+ ip_match_list iml;
+ struct in_addr address;
+
+ /* Create the predefined ACLs */
+
+ address.s_addr = 0U;
+
+ /* ACL "any" */
+ ime = new_ip_match_pattern(address, 0);
+ iml = new_ip_match_list();
+ add_to_ip_match_list(iml, ime);
+ define_acl(savestr("any", 1), iml);
+
+ /* ACL "none" */
+ ime = new_ip_match_pattern(address, 0);
+ ip_match_negate(ime);
+ iml = new_ip_match_list();
+ add_to_ip_match_list(iml, ime);
+ define_acl(savestr("none", 1), iml);
+
+ /* ACL "localhost" */
+ ime = new_ip_match_localhost();
+ iml = new_ip_match_list();
+ add_to_ip_match_list(iml, ime);
+ define_acl(savestr("localhost", 1), iml);
+
+ /* ACL "localnets" */
+ ime = new_ip_match_localnets();
+ iml = new_ip_match_list();
+ add_to_ip_match_list(iml, ime);
+ define_acl(savestr("localnets", 1), iml);
+}
+
+static void
+free_sym_value(int type, void *value) {
+ ns_debug(ns_log_parser, 99, "free_sym_value: type %06x value %p",
+ type, value);
+ type &= ~0xffff;
+ switch (type) {
+ case SYM_ACL:
+ free_ip_match_list(value);
+ break;
+ case SYM_KEY:
+ free_key_info(value);
+ break;
+ default:
+ ns_panic(ns_log_parser, 1,
+ "unhandled case in free_sym_value()");
+ /* NOTREACHED */
+ break;
+ }
+}
+
+static log_channel
+lookup_channel(char *name) {
+ symbol_value value;
+
+ if (lookup_symbol(symtab, name, SYM_CHANNEL, &value))
+ return ((log_channel)(value.pointer));
+ return (NULL);
+}
+
+static void
+define_channel(char *name, log_channel channel) {
+ symbol_value value;
+
+ value.pointer = channel;
+ define_symbol(symtab, name, SYM_CHANNEL, value, SYMBOL_FREE_KEY);
+}
+
+static void
+define_builtin_channels() {
+ define_channel(savestr("default_syslog", 1), syslog_channel);
+ define_channel(savestr("default_debug", 1), debug_channel);
+ define_channel(savestr("default_stderr", 1), stderr_channel);
+ define_channel(savestr("null", 1), null_channel);
+}
+
+static void
+parser_setup() {
+ seen_options = 0;
+ seen_topology = 0;
+ symtab = new_symbol_table(SYMBOL_TABLE_SIZE, NULL);
+ if (authtab != NULL)
+ free_symbol_table(authtab);
+ authtab = new_symbol_table(AUTH_TABLE_SIZE, free_sym_value);
+ init_acls();
+ define_builtin_channels();
+}
+
+static void
+parser_cleanup() {
+ if (symtab != NULL)
+ free_symbol_table(symtab);
+ symtab = NULL;
+ /*
+ * We don't clean up authtab here because the ip_match_lists are in
+ * use.
+ */
+}
+
+/*
+ * Public Interface
+ */
+
+ip_match_list
+lookup_acl(char *name) {
+ symbol_value value;
+
+ if (lookup_symbol(authtab, name, SYM_ACL, &value))
+ return ((ip_match_list)(value.pointer));
+ return (NULL);
+}
+
+void
+define_acl(char *name, ip_match_list iml) {
+ symbol_value value;
+
+ INSIST(name != NULL);
+ INSIST(iml != NULL);
+
+ value.pointer = iml;
+ define_symbol(authtab, name, SYM_ACL, value,
+ SYMBOL_FREE_KEY|SYMBOL_FREE_VALUE);
+ ns_debug(ns_log_parser, 7, "acl %s", name);
+ dprint_ip_match_list(ns_log_parser, iml, 2, "allow ", "deny ");
+}
+
+key_info
+lookup_key(char *name) {
+ symbol_value value;
+
+ if (lookup_symbol(authtab, name, SYM_KEY, &value))
+ return ((key_info)(value.pointer));
+ return (NULL);
+}
+
+void
+define_key(char *name, key_info ki) {
+ symbol_value value;
+
+ INSIST(name != NULL);
+ INSIST(ki != NULL);
+
+ value.pointer = ki;
+ define_symbol(authtab, name, SYM_KEY, value, SYMBOL_FREE_VALUE);
+ dprint_key_info(ki);
+}
+
+void
+parse_configuration(const char *filename) {
+ FILE *config_stream;
+
+ config_stream = fopen(filename, "r");
+ if (config_stream == NULL)
+ ns_panic(ns_log_parser, 0, "can't open '%s'", filename);
+
+ lexer_setup();
+ parser_setup();
+ lexer_begin_file(filename, config_stream);
+ (void)yyparse();
+ lexer_end_file();
+ parser_cleanup();
+}
+
+void
+parser_initialize(void) {
+ lexer_initialize();
+}
+
+void
+parser_shutdown(void) {
+ if (authtab != NULL)
+ free_symbol_table(authtab);
+ lexer_shutdown();
+}
+#line 965 "y.tab.c"
+/* allocate initial stack */
+#if defined(__STDC__) || defined(__cplusplus)
+static int yyinitstack(struct yystack *sp)
+#else
+static int yyinitstack(sp)
+ struct yystack *sp;
+#endif
+{
+ int newsize;
+ short *newss;
+ YYSTYPE *newvs;
+
+ newsize = YYINITSTACKSIZE;
+ newss = (short *)malloc(newsize * sizeof *newss);
+ newvs = (YYSTYPE *)malloc(newsize * sizeof *newvs);
+ sp->ss = sp->ssp = newss;
+ sp->vs = sp->vsp = newvs;
+ if (newss == NULL || newvs == NULL) return -1;
+ sp->stacksize = newsize;
+ sp->sslim = newss + newsize - 1;
+ return 0;
+}
+
+/* double stack size, up to YYMAXDEPTH */
+#if defined(__STDC__) || defined(__cplusplus)
+static int yygrowstack(struct yystack *sp)
+#else
+static int yygrowstack(sp)
+ struct yystack *sp;
+#endif
+{
+ int newsize, i;
+ short *newss;
+ YYSTYPE *newvs;
+
+ if ((newsize = sp->stacksize) >= YYMAXDEPTH) return -1;
+ if ((newsize *= 2) > YYMAXDEPTH) newsize = YYMAXDEPTH;
+ i = sp->ssp - sp->ss;
+ if ((newss = (short *)realloc(sp->ss, newsize * sizeof *newss)) == NULL)
+ return -1;
+ sp->ss = newss;
+ sp->ssp = newss + i;
+ if ((newvs = (YYSTYPE *)realloc(sp->vs, newsize * sizeof *newvs)) == NULL)
+ return -1;
+ sp->vs = newvs;
+ sp->vsp = newvs + i;
+ sp->stacksize = newsize;
+ sp->sslim = newss + newsize - 1;
+ return 0;
+}
+
+#define YYFREESTACK(sp) { free((sp)->ss); free((sp)->vs); }
+
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+yyparse()
+{
+ register int yym, yyn, yystate, yych;
+ register YYSTYPE *yyvsp;
+ YYSTYPE yyval;
+ struct yystack yystk;
+#if YYDEBUG
+ register char *yys;
+ extern char *getenv();
+
+ if (yys = getenv("YYDEBUG"))
+ {
+ yyn = *yys;
+ if (yyn >= '0' && yyn <= '9')
+ yydebug = yyn - '0';
+ }
+#endif
+
+ yynerrs = 0;
+ yyerrflag = 0;
+ yychar = yych = YYEMPTY;
+
+ if (yyinitstack(&yystk)) goto yyoverflow;
+ *yystk.ssp = yystate = 0;
+
+yyloop:
+ if (yyn = yydefred[yystate]) goto yyreduce;
+ if (yych < 0)
+ {
+ if ((yych = YYLEX) < 0) yych = 0;
+ yychar = yych;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yych <= YYMAXTOKEN) yys = yyname[yych];
+ if (!yys) yys = "illegal-symbol";
+ printf("%sdebug: state %d, reading %d (%s)\n",
+ YYPREFIX, yystate, yych, yys);
+ }
+#endif
+ }
+ if ((yyn = yysindex[yystate]) && (yyn += yych) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yych)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, shifting to state %d\n",
+ YYPREFIX, yystate, yytable[yyn]);
+#endif
+ if (yystk.ssp >= yystk.sslim && yygrowstack(&yystk))
+ goto yyoverflow;
+ *++yystk.ssp = yystate = yytable[yyn];
+ *++yystk.vsp = yylval;
+ yychar = yych = YYEMPTY;
+ if (yyerrflag > 0) --yyerrflag;
+ goto yyloop;
+ }
+ if ((yyn = yyrindex[yystate]) && (yyn += yych) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yych)
+ {
+ yyn = yytable[yyn];
+ goto yyreduce;
+ }
+ if (yyerrflag) goto yyinrecovery;
+#ifdef lint
+ goto yynewerror;
+#endif
+yynewerror:
+ yyerror("syntax error");
+#ifdef lint
+ goto yyerrlab;
+#endif
+yyerrlab:
+ ++yynerrs;
+yyinrecovery:
+ if (yyerrflag < 3)
+ {
+ yyerrflag = 3;
+ for (;;)
+ {
+ if ((yyn = yysindex[*yystk.ssp]) &&
+ (yyn += YYERRCODE) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yystk.ssp, yytable[yyn]);
+#endif
+ if (yystk.ssp >= yystk.sslim && yygrowstack(&yystk))
+ goto yyoverflow;
+ *++yystk.ssp = yystate = yytable[yyn];
+ *++yystk.vsp = yylval;
+ goto yyloop;
+ }
+ else
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: error recovery discarding state %d\n",
+ YYPREFIX, *yystk.ssp);
+#endif
+ if (yystk.ssp <= yystk.ss) goto yyabort;
+ --yystk.ssp;
+ --yystk.vsp;
+ }
+ }
+ }
+ else
+ {
+ if (yych == 0) goto yyabort;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yych <= YYMAXTOKEN) yys = yyname[yych];
+ if (!yys) yys = "illegal-symbol";
+ printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+ YYPREFIX, yystate, yych, yys);
+ }
+#endif
+ yychar = yych = YYEMPTY;
+ goto yyloop;
+ }
+yyreduce:
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+ YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+ yym = yylen[yyn];
+ yyvsp = yystk.vsp; /* for speed in code under switch() */
+ yyval = yyvsp[1-yym];
+ switch (yyn)
+ {
+case 1:
+#line 206 "ns_parser.y"
+{
+ /* nothing */
+ }
+break;
+case 14:
+#line 227 "ns_parser.y"
+{ lexer_begin_file(yyvsp[-1].cp, NULL); }
+break;
+case 15:
+#line 235 "ns_parser.y"
+{
+ if (seen_options)
+ parser_error(0, "cannot redefine options");
+ current_options = new_options();
+ }
+break;
+case 16:
+#line 241 "ns_parser.y"
+{
+ if (!seen_options)
+ set_options(current_options, 0);
+ else
+ free_options(current_options);
+ current_options = NULL;
+ seen_options = 1;
+ }
+break;
+case 20:
+#line 257 "ns_parser.y"
+{
+ if (current_options->directory != NULL)
+ freestr(current_options->directory);
+ current_options->directory = yyvsp[0].cp;
+ }
+break;
+case 21:
+#line 263 "ns_parser.y"
+{
+ if (current_options->named_xfer != NULL)
+ freestr(current_options->named_xfer);
+ current_options->named_xfer = yyvsp[0].cp;
+ }
+break;
+case 22:
+#line 269 "ns_parser.y"
+{
+ if (current_options->pid_filename != NULL)
+ freestr(current_options->pid_filename);
+ current_options->pid_filename = yyvsp[0].cp;
+ }
+break;
+case 23:
+#line 275 "ns_parser.y"
+{
+ if (current_options->stats_filename != NULL)
+ freestr(current_options->stats_filename);
+ current_options->stats_filename = yyvsp[0].cp;
+ }
+break;
+case 24:
+#line 281 "ns_parser.y"
+{
+ if (current_options->memstats_filename != NULL)
+ freestr(current_options->memstats_filename);
+ current_options->memstats_filename = yyvsp[0].cp;
+ }
+break;
+case 25:
+#line 287 "ns_parser.y"
+{
+ if (current_options->dump_filename != NULL)
+ freestr(current_options->dump_filename);
+ current_options->dump_filename = yyvsp[0].cp;
+ }
+break;
+case 26:
+#line 293 "ns_parser.y"
+{
+ set_boolean_option(current_options, OPTION_FAKE_IQUERY, yyvsp[0].num);
+ }
+break;
+case 27:
+#line 297 "ns_parser.y"
+{
+ set_boolean_option(current_options, OPTION_NORECURSE, !yyvsp[0].num);
+ }
+break;
+case 28:
+#line 301 "ns_parser.y"
+{
+ set_boolean_option(current_options, OPTION_NOFETCHGLUE, !yyvsp[0].num);
+ }
+break;
+case 29:
+#line 305 "ns_parser.y"
+{
+ set_boolean_option(current_options, OPTION_NONOTIFY, !yyvsp[0].num);
+ }
+break;
+case 30:
+#line 309 "ns_parser.y"
+{
+ set_boolean_option(current_options, OPTION_HOSTSTATS, yyvsp[0].num);
+ }
+break;
+case 31:
+#line 313 "ns_parser.y"
+{
+ set_boolean_option(current_options, OPTION_DEALLOC_ON_EXIT,
+ yyvsp[0].num);
+ }
+break;
+case 32:
+#line 318 "ns_parser.y"
+{
+ set_boolean_option(current_options, OPTION_NONAUTH_NXDOMAIN,
+ !yyvsp[0].num);
+ }
+break;
+case 33:
+#line 323 "ns_parser.y"
+{
+ set_boolean_option(current_options, OPTION_MULTIPLE_CNAMES,
+ yyvsp[0].num);
+ }
+break;
+case 34:
+#line 328 "ns_parser.y"
+{
+ current_options->check_names[yyvsp[-1].s_int] = yyvsp[0].s_int;
+ }
+break;
+case 35:
+#line 332 "ns_parser.y"
+{
+ char port_string[10];
+ symbol_value value;
+
+ (void)sprintf(port_string, "%u", yyvsp[-3].us_int);
+ if (lookup_symbol(symtab, port_string, SYM_PORT, NULL))
+ parser_error(0,
+ "cannot redefine listen-on for port %u",
+ ntohs(yyvsp[-3].us_int));
+ else {
+ add_listen_on(current_options, yyvsp[-3].us_int, yyvsp[-1].iml);
+ value.pointer = NULL;
+ define_symbol(symtab, savestr(port_string, 1),
+ SYM_PORT, value, SYMBOL_FREE_KEY);
+ }
+
+ }
+break;
+case 37:
+#line 351 "ns_parser.y"
+{
+ if (current_options->fwdtab) {
+ free_forwarders(current_options->fwdtab);
+ current_options->fwdtab = NULL;
+ }
+ }
+break;
+case 40:
+#line 360 "ns_parser.y"
+{
+ if (current_options->query_acl)
+ free_ip_match_list(current_options->query_acl);
+ current_options->query_acl = yyvsp[-1].iml;
+ }
+break;
+case 41:
+#line 366 "ns_parser.y"
+{
+ if (current_options->transfer_acl)
+ free_ip_match_list(current_options->transfer_acl);
+ current_options->transfer_acl = yyvsp[-1].iml;
+ }
+break;
+case 42:
+#line 372 "ns_parser.y"
+{
+ if (current_options->topology)
+ free_ip_match_list(current_options->topology);
+ current_options->topology = yyvsp[-1].iml;
+ }
+break;
+case 43:
+#line 378 "ns_parser.y"
+{
+ /* To get around the $$ = $1 default rule. */
+ }
+break;
+case 45:
+#line 383 "ns_parser.y"
+{
+ current_options->transfer_format = yyvsp[0].axfr_fmt;
+ }
+break;
+case 46:
+#line 387 "ns_parser.y"
+{
+ current_options->max_transfer_time_in = yyvsp[0].num * 60;
+ }
+break;
+case 47:
+#line 391 "ns_parser.y"
+{
+ current_options->clean_interval = yyvsp[0].num * 60;
+ }
+break;
+case 48:
+#line 395 "ns_parser.y"
+{
+ current_options->interface_interval = yyvsp[0].num * 60;
+ }
+break;
+case 49:
+#line 399 "ns_parser.y"
+{
+ current_options->stats_interval = yyvsp[0].num * 60;
+ }
+break;
+case 51:
+#line 406 "ns_parser.y"
+{
+ yyval.axfr_fmt = axfr_one_answer;
+ }
+break;
+case 52:
+#line 410 "ns_parser.y"
+{
+ yyval.axfr_fmt = axfr_many_answers;
+ }
+break;
+case 53:
+#line 415 "ns_parser.y"
+{ yyval.ip_addr = yyvsp[0].ip_addr; }
+break;
+case 54:
+#line 416 "ns_parser.y"
+{ yyval.ip_addr.s_addr = htonl(INADDR_ANY); }
+break;
+case 55:
+#line 419 "ns_parser.y"
+{ yyval.us_int = yyvsp[0].us_int; }
+break;
+case 56:
+#line 420 "ns_parser.y"
+{ yyval.us_int = htons(0); }
+break;
+case 57:
+#line 424 "ns_parser.y"
+{
+ current_options->query_source.sin_addr = yyvsp[0].ip_addr;
+ }
+break;
+case 58:
+#line 430 "ns_parser.y"
+{
+ current_options->query_source.sin_port = yyvsp[0].us_int;
+ }
+break;
+case 63:
+#line 441 "ns_parser.y"
+{ yyval.us_int = htons(NS_DEFAULTPORT); }
+break;
+case 64:
+#line 442 "ns_parser.y"
+{ yyval.us_int = yyvsp[0].us_int; }
+break;
+case 65:
+#line 446 "ns_parser.y"
+{
+ yyval.num = 1;
+ }
+break;
+case 66:
+#line 450 "ns_parser.y"
+{
+ yyval.num = 1;
+ }
+break;
+case 67:
+#line 454 "ns_parser.y"
+{
+ yyval.num = 0;
+ }
+break;
+case 68:
+#line 458 "ns_parser.y"
+{
+ yyval.num = 0;
+ }
+break;
+case 69:
+#line 462 "ns_parser.y"
+{
+ if (yyvsp[0].num == 1 || yyvsp[0].num == 0) {
+ yyval.num = yyvsp[0].num;
+ } else {
+ parser_warning(0,
+ "number should be 0 or 1; assuming 1");
+ yyval.num = 1;
+ }
+ }
+break;
+case 70:
+#line 474 "ns_parser.y"
+{
+ yyval.s_int = primary_trans;
+ }
+break;
+case 71:
+#line 478 "ns_parser.y"
+{
+ yyval.s_int = secondary_trans;
+ }
+break;
+case 72:
+#line 482 "ns_parser.y"
+{
+ yyval.s_int = response_trans;
+ }
+break;
+case 73:
+#line 488 "ns_parser.y"
+{
+ yyval.s_int = warn;
+ }
+break;
+case 74:
+#line 492 "ns_parser.y"
+{
+ yyval.s_int = fail;
+ }
+break;
+case 75:
+#line 496 "ns_parser.y"
+{
+ yyval.s_int = ignore;
+ }
+break;
+case 76:
+#line 502 "ns_parser.y"
+{
+ set_boolean_option(current_options, OPTION_FORWARD_ONLY, 1);
+ }
+break;
+case 77:
+#line 506 "ns_parser.y"
+{
+ set_boolean_option(current_options, OPTION_FORWARD_ONLY, 0);
+ }
+break;
+case 78:
+#line 510 "ns_parser.y"
+{
+ parser_warning(0, "forward if-no-answer is unimplemented");
+ }
+break;
+case 79:
+#line 514 "ns_parser.y"
+{
+ parser_warning(0, "forward if-no-domain is unimplemented");
+ }
+break;
+case 80:
+#line 520 "ns_parser.y"
+{
+ current_options->data_size = yyvsp[0].ul_int;
+ }
+break;
+case 81:
+#line 524 "ns_parser.y"
+{
+ current_options->stack_size = yyvsp[0].ul_int;
+ }
+break;
+case 82:
+#line 528 "ns_parser.y"
+{
+ current_options->core_size = yyvsp[0].ul_int;
+ }
+break;
+case 83:
+#line 532 "ns_parser.y"
+{
+ current_options->files = yyvsp[0].ul_int;
+ }
+break;
+case 84:
+#line 538 "ns_parser.y"
+{
+ u_long result;
+
+ if (unit_to_ulong(yyvsp[0].cp, &result))
+ yyval.ul_int = result;
+ else {
+ parser_error(0, "invalid unit string '%s'", yyvsp[0].cp);
+ /* 0 means "use default" */
+ yyval.ul_int = 0;
+ }
+ freestr(yyvsp[0].cp);
+ }
+break;
+case 85:
+#line 551 "ns_parser.y"
+{
+ yyval.ul_int = (u_long)yyvsp[0].num;
+ }
+break;
+case 86:
+#line 555 "ns_parser.y"
+{
+ yyval.ul_int = 0;
+ }
+break;
+case 87:
+#line 559 "ns_parser.y"
+{
+ yyval.ul_int = ULONG_MAX;
+ }
+break;
+case 88:
+#line 565 "ns_parser.y"
+{
+ current_options->transfers_in = (u_long) yyvsp[0].num;
+ }
+break;
+case 89:
+#line 569 "ns_parser.y"
+{
+ current_options->transfers_out = (u_long) yyvsp[0].num;
+ }
+break;
+case 90:
+#line 573 "ns_parser.y"
+{
+ current_options->transfers_per_ns = (u_long) yyvsp[0].num;
+ }
+break;
+case 93:
+#line 583 "ns_parser.y"
+{
+ /* nothing */
+ }
+break;
+case 94:
+#line 587 "ns_parser.y"
+{
+ /* nothing */
+ }
+break;
+case 95:
+#line 593 "ns_parser.y"
+{
+ add_forwarder(current_options, yyvsp[0].ip_addr);
+ }
+break;
+case 96:
+#line 603 "ns_parser.y"
+{
+ current_logging = begin_logging();
+ }
+break;
+case 97:
+#line 607 "ns_parser.y"
+{
+ end_logging(current_logging, 1);
+ current_logging = NULL;
+ }
+break;
+case 101:
+#line 619 "ns_parser.y"
+{
+ current_category = yyvsp[0].s_int;
+ }
+break;
+case 103:
+#line 624 "ns_parser.y"
+{
+ chan_type = log_null;
+ chan_flags = 0;
+ chan_level = log_info;
+ }
+break;
+case 104:
+#line 630 "ns_parser.y"
+{
+ log_channel current_channel = NULL;
+
+ if (lookup_channel(yyvsp[-4].cp) != NULL) {
+ parser_error(0, "can't redefine channel '%s'", yyvsp[-4].cp);
+ freestr(yyvsp[-4].cp);
+ } else {
+ switch (chan_type) {
+ case log_file:
+ current_channel =
+ log_new_file_channel(chan_flags,
+ chan_level,
+ chan_name, NULL,
+ chan_versions,
+ chan_max_size);
+ freestr(chan_name);
+ chan_name = NULL;
+ break;
+ case log_syslog:
+ current_channel =
+ log_new_syslog_channel(chan_flags,
+ chan_level,
+ chan_facility);
+ break;
+ case log_null:
+ current_channel = log_new_null_channel();
+ break;
+ default:
+ ns_panic(ns_log_parser, 1,
+ "unknown channel type: %d",
+ chan_type);
+ }
+ if (current_channel == NULL)
+ ns_panic(ns_log_parser, 0,
+ "couldn't create channel");
+ define_channel(yyvsp[-4].cp, current_channel);
+ }
+ }
+break;
+case 105:
+#line 671 "ns_parser.y"
+{
+ symbol_value value;
+
+ if (lookup_symbol(constants, yyvsp[0].cp, SYM_LOGGING, &value)) {
+ chan_level = value.integer;
+ } else {
+ parser_error(0, "unknown severity '%s'", yyvsp[0].cp);
+ chan_level = log_debug(99);
+ }
+ freestr(yyvsp[0].cp);
+ }
+break;
+case 106:
+#line 683 "ns_parser.y"
+{
+ chan_level = log_debug(1);
+ }
+break;
+case 107:
+#line 687 "ns_parser.y"
+{
+ chan_level = yyvsp[0].num;
+ }
+break;
+case 108:
+#line 691 "ns_parser.y"
+{
+ chan_level = 0;
+ chan_flags |= LOG_USE_CONTEXT_LEVEL|LOG_REQUIRE_DEBUG;
+ }
+break;
+case 109:
+#line 698 "ns_parser.y"
+{
+ chan_versions = yyvsp[0].num;
+ chan_flags |= LOG_TRUNCATE;
+ }
+break;
+case 110:
+#line 703 "ns_parser.y"
+{
+ chan_versions = LOG_MAX_VERSIONS;
+ chan_flags |= LOG_TRUNCATE;
+ }
+break;
+case 111:
+#line 710 "ns_parser.y"
+{
+ chan_max_size = yyvsp[0].ul_int;
+ }
+break;
+case 112:
+#line 716 "ns_parser.y"
+{
+ chan_versions = 0;
+ chan_max_size = ULONG_MAX;
+ }
+break;
+case 113:
+#line 721 "ns_parser.y"
+{
+ chan_max_size = ULONG_MAX;
+ }
+break;
+case 114:
+#line 725 "ns_parser.y"
+{
+ chan_versions = 0;
+ }
+break;
+case 117:
+#line 733 "ns_parser.y"
+{
+ chan_flags |= LOG_CLOSE_STREAM;
+ chan_type = log_file;
+ chan_name = yyvsp[-1].cp;
+ }
+break;
+case 118:
+#line 741 "ns_parser.y"
+{ yyval.cp = yyvsp[0].cp; }
+break;
+case 119:
+#line 742 "ns_parser.y"
+{ yyval.cp = savestr("syslog", 1); }
+break;
+case 120:
+#line 745 "ns_parser.y"
+{ yyval.s_int = LOG_DAEMON; }
+break;
+case 121:
+#line 747 "ns_parser.y"
+{
+ symbol_value value;
+
+ if (lookup_symbol(constants, yyvsp[0].cp, SYM_SYSLOG, &value)) {
+ yyval.s_int = value.integer;
+ } else {
+ parser_error(0, "unknown facility '%s'", yyvsp[0].cp);
+ yyval.s_int = LOG_DAEMON;
+ }
+ freestr(yyvsp[0].cp);
+ }
+break;
+case 122:
+#line 761 "ns_parser.y"
+{
+ chan_type = log_syslog;
+ chan_facility = yyvsp[0].s_int;
+ }
+break;
+case 123:
+#line 767 "ns_parser.y"
+{ /* nothing to do */ }
+break;
+case 124:
+#line 768 "ns_parser.y"
+{ /* nothing to do */ }
+break;
+case 125:
+#line 770 "ns_parser.y"
+{
+ chan_type = log_null;
+ }
+break;
+case 126:
+#line 773 "ns_parser.y"
+{ /* nothing to do */ }
+break;
+case 127:
+#line 775 "ns_parser.y"
+{
+ if (yyvsp[0].num)
+ chan_flags |= LOG_TIMESTAMP;
+ else
+ chan_flags &= ~LOG_TIMESTAMP;
+ }
+break;
+case 128:
+#line 782 "ns_parser.y"
+{
+ if (yyvsp[0].num)
+ chan_flags |= LOG_PRINT_CATEGORY;
+ else
+ chan_flags &= ~LOG_PRINT_CATEGORY;
+ }
+break;
+case 129:
+#line 789 "ns_parser.y"
+{
+ if (yyvsp[0].num)
+ chan_flags |= LOG_PRINT_LEVEL;
+ else
+ chan_flags &= ~LOG_PRINT_LEVEL;
+ }
+break;
+case 134:
+#line 803 "ns_parser.y"
+{ yyval.cp = savestr("null", 1); }
+break;
+case 135:
+#line 807 "ns_parser.y"
+{
+ log_channel channel;
+ symbol_value value;
+
+ if (current_category >= 0) {
+ channel = lookup_channel(yyvsp[0].cp);
+ if (channel != NULL) {
+ add_log_channel(current_logging,
+ current_category, channel);
+ } else
+ parser_error(0, "unknown channel '%s'", yyvsp[0].cp);
+ }
+ freestr(yyvsp[0].cp);
+ }
+break;
+case 140:
+#line 829 "ns_parser.y"
+{ yyval.cp = savestr("default", 1); }
+break;
+case 141:
+#line 830 "ns_parser.y"
+{ yyval.cp = savestr("notify", 1); }
+break;
+case 142:
+#line 834 "ns_parser.y"
+{
+ symbol_value value;
+
+ if (lookup_symbol(constants, yyvsp[0].cp, SYM_CATEGORY, &value))
+ yyval.s_int = value.integer;
+ else {
+ parser_error(0, "invalid logging category '%s'",
+ yyvsp[0].cp);
+ yyval.s_int = -1;
+ }
+ freestr(yyvsp[0].cp);
+ }
+break;
+case 143:
+#line 853 "ns_parser.y"
+{
+ char *ip_printable;
+ symbol_value value;
+
+ ip_printable = inet_ntoa(yyvsp[0].ip_addr);
+ value.pointer = NULL;
+ if (lookup_symbol(symtab, ip_printable, SYM_SERVER, NULL))
+ seen_server = 1;
+ else
+ seen_server = 0;
+ if (seen_server)
+ parser_error(0, "cannot redefine server '%s'",
+ ip_printable);
+ else
+ define_symbol(symtab, savestr(ip_printable, 1),
+ SYM_SERVER, value,
+ SYMBOL_FREE_KEY);
+ current_server = begin_server(yyvsp[0].ip_addr);
+ }
+break;
+case 144:
+#line 873 "ns_parser.y"
+{
+ end_server(current_server, !seen_server);
+ }
+break;
+case 147:
+#line 883 "ns_parser.y"
+{
+ set_server_option(current_server, SERVER_INFO_BOGUS, yyvsp[0].num);
+ }
+break;
+case 148:
+#line 887 "ns_parser.y"
+{
+ set_server_transfers(current_server, (int)yyvsp[0].num);
+ }
+break;
+case 149:
+#line 891 "ns_parser.y"
+{
+ set_server_transfer_format(current_server, yyvsp[0].axfr_fmt);
+ }
+break;
+case 152:
+#line 903 "ns_parser.y"
+{
+ ip_match_list iml;
+
+ iml = new_ip_match_list();
+ if (yyvsp[-1].ime != NULL)
+ add_to_ip_match_list(iml, yyvsp[-1].ime);
+ yyval.iml = iml;
+ }
+break;
+case 153:
+#line 912 "ns_parser.y"
+{
+ if (yyvsp[-1].ime != NULL)
+ add_to_ip_match_list(yyvsp[-2].iml, yyvsp[-1].ime);
+ yyval.iml = yyvsp[-2].iml;
+ }
+break;
+case 155:
+#line 921 "ns_parser.y"
+{
+ if (yyvsp[0].ime != NULL)
+ ip_match_negate(yyvsp[0].ime);
+ yyval.ime = yyvsp[0].ime;
+ }
+break;
+case 156:
+#line 929 "ns_parser.y"
+{
+ yyval.ime = new_ip_match_pattern(yyvsp[0].ip_addr, 32);
+ }
+break;
+case 157:
+#line 933 "ns_parser.y"
+{
+ if (yyvsp[0].num < 0 || yyvsp[0].num > 32) {
+ parser_error(0, "mask bits out of range; skipping");
+ yyval.ime = NULL;
+ } else {
+ yyval.ime = new_ip_match_pattern(yyvsp[-2].ip_addr, yyvsp[0].num);
+ if (yyval.ime == NULL)
+ parser_error(0,
+ "address/mask mismatch; skipping");
+ }
+ }
+break;
+case 158:
+#line 945 "ns_parser.y"
+{
+ struct in_addr ia;
+
+ if (yyvsp[-2].num > 255) {
+ parser_error(0, "address out of range; skipping");
+ yyval.ime = NULL;
+ } else {
+ if (yyvsp[0].num < 0 || yyvsp[0].num > 32) {
+ parser_error(0,
+ "mask bits out of range; skipping");
+ yyval.ime = NULL;
+ } else {
+ ia.s_addr = htonl((yyvsp[-2].num & 0xff) << 24);
+ yyval.ime = new_ip_match_pattern(ia, yyvsp[0].num);
+ if (yyval.ime == NULL)
+ parser_error(0,
+ "address/mask mismatch; skipping");
+ }
+ }
+ }
+break;
+case 160:
+#line 967 "ns_parser.y"
+{
+ char name[256];
+
+ /*
+ * We want to be able to clean up this iml later so
+ * we give it a name and treat it like any other acl.
+ */
+ sprintf(name, "__internal_%p", yyvsp[-1].iml);
+ define_acl(savestr(name, 1), yyvsp[-1].iml);
+ yyval.ime = new_ip_match_indirect(yyvsp[-1].iml);
+ }
+break;
+case 161:
+#line 981 "ns_parser.y"
+{
+ ip_match_list iml;
+
+ iml = lookup_acl(yyvsp[0].cp);
+ if (iml == NULL) {
+ parser_error(0, "unknown ACL '%s'", yyvsp[0].cp);
+ yyval.ime = NULL;
+ } else
+ yyval.ime = new_ip_match_indirect(iml);
+ freestr(yyvsp[0].cp);
+ }
+break;
+case 162:
+#line 999 "ns_parser.y"
+{
+ key_info ki;
+
+ ki = lookup_key(yyvsp[0].cp);
+ if (ki == NULL) {
+ parser_error(0, "unknown key '%s'", yyvsp[0].cp);
+ yyval.keyi = NULL;
+ } else
+ yyval.keyi = ki;
+ freestr(yyvsp[0].cp);
+ }
+break;
+case 163:
+#line 1013 "ns_parser.y"
+{
+ if (yyvsp[0].keyi == NULL)
+ parser_error(0, "empty key not added to server list ");
+ else
+ add_server_key_info(current_server, yyvsp[0].keyi);
+ }
+break;
+case 167:
+#line 1027 "ns_parser.y"
+{
+ current_algorithm = NULL;
+ current_secret = NULL;
+ }
+break;
+case 168:
+#line 1032 "ns_parser.y"
+{
+ key_info ki;
+
+ if (lookup_key(yyvsp[-3].cp) != NULL) {
+ parser_error(0, "can't redefine key '%s'", yyvsp[-3].cp);
+ freestr(yyvsp[-3].cp);
+ } else {
+ if (current_algorithm == NULL ||
+ current_secret == NULL)
+ parser_error(0, "skipping bad key '%s'", yyvsp[-3].cp);
+ else {
+ ki = new_key_info(yyvsp[-3].cp, current_algorithm,
+ current_secret);
+ define_key(yyvsp[-3].cp, ki);
+ }
+ }
+ }
+break;
+case 169:
+#line 1052 "ns_parser.y"
+{
+ current_algorithm = yyvsp[-1].cp;
+ current_secret = yyvsp[0].cp;
+ }
+break;
+case 170:
+#line 1057 "ns_parser.y"
+{
+ current_algorithm = yyvsp[0].cp;
+ current_secret = yyvsp[-1].cp;
+ }
+break;
+case 171:
+#line 1062 "ns_parser.y"
+{
+ current_algorithm = NULL;
+ current_secret = NULL;
+ }
+break;
+case 172:
+#line 1068 "ns_parser.y"
+{ yyval.cp = yyvsp[-1].cp; }
+break;
+case 173:
+#line 1071 "ns_parser.y"
+{ yyval.cp = yyvsp[-1].cp; }
+break;
+case 174:
+#line 1079 "ns_parser.y"
+{
+ if (lookup_acl(yyvsp[-3].cp) != NULL) {
+ parser_error(0, "can't redefine ACL '%s'", yyvsp[-3].cp);
+ freestr(yyvsp[-3].cp);
+ } else
+ define_acl(yyvsp[-3].cp, yyvsp[-1].iml);
+ }
+break;
+case 175:
+#line 1093 "ns_parser.y"
+{
+ int sym_type;
+ symbol_value value;
+ char *zone_name;
+
+ if (!seen_options)
+ parser_error(0,
+ "no options statement before first zone; using previous/default");
+ sym_type = SYM_ZONE | (yyvsp[0].num & 0xffff);
+ value.pointer = NULL;
+ zone_name = canonical_name(yyvsp[-1].cp);
+ if (zone_name == NULL) {
+ parser_error(0, "can't make zone name '%s' canonical",
+ yyvsp[-1].cp);
+ seen_zone = 1;
+ zone_name = savestr("__bad_zone__", 1);
+ } else {
+ seen_zone = lookup_symbol(symtab, zone_name, sym_type,
+ NULL);
+ if (seen_zone) {
+ parser_error(0,
+ "cannot redefine zone '%s' class %d",
+ zone_name, yyvsp[0].num);
+ } else
+ define_symbol(symtab, zone_name, sym_type,
+ value, 0);
+ }
+ freestr(yyvsp[-1].cp);
+ current_zone = begin_zone(zone_name, yyvsp[0].num);
+ }
+break;
+case 176:
+#line 1124 "ns_parser.y"
+{ end_zone(current_zone, !seen_zone); }
+break;
+case 179:
+#line 1132 "ns_parser.y"
+{
+ yyval.num = C_IN;
+ }
+break;
+case 180:
+#line 1136 "ns_parser.y"
+{
+ symbol_value value;
+
+ if (lookup_symbol(constants, yyvsp[0].cp, SYM_CLASS, &value))
+ yyval.num = value.integer;
+ else {
+ /* the zone validator will give the error */
+ yyval.num = C_NONE;
+ }
+ freestr(yyvsp[0].cp);
+ }
+break;
+case 181:
+#line 1150 "ns_parser.y"
+{
+ yyval.s_int = Z_MASTER;
+ }
+break;
+case 182:
+#line 1154 "ns_parser.y"
+{
+ yyval.s_int = Z_SLAVE;
+ }
+break;
+case 183:
+#line 1158 "ns_parser.y"
+{
+ yyval.s_int = Z_HINT;
+ }
+break;
+case 184:
+#line 1162 "ns_parser.y"
+{
+ yyval.s_int = Z_STUB;
+ }
+break;
+case 187:
+#line 1172 "ns_parser.y"
+{
+ if (!set_zone_type(current_zone, yyvsp[0].s_int))
+ parser_warning(0, "zone type already set; skipping");
+ }
+break;
+case 188:
+#line 1177 "ns_parser.y"
+{
+ if (!set_zone_filename(current_zone, yyvsp[0].cp))
+ parser_warning(0,
+ "zone filename already set; skipping");
+ }
+break;
+case 190:
+#line 1184 "ns_parser.y"
+{
+ set_zone_transfer_source(current_zone, yyvsp[0].ip_addr);
+ }
+break;
+case 191:
+#line 1188 "ns_parser.y"
+{
+ if (!set_zone_checknames(current_zone, yyvsp[0].s_int))
+ parser_warning(0,
+ "zone checknames already set; skipping");
+ }
+break;
+case 192:
+#line 1194 "ns_parser.y"
+{
+ if (!set_zone_update_acl(current_zone, yyvsp[-1].iml))
+ parser_warning(0,
+ "zone update acl already set; skipping");
+ }
+break;
+case 193:
+#line 1200 "ns_parser.y"
+{
+ if (!set_zone_query_acl(current_zone, yyvsp[-1].iml))
+ parser_warning(0,
+ "zone query acl already set; skipping");
+ }
+break;
+case 194:
+#line 1206 "ns_parser.y"
+{
+ if (!set_zone_transfer_acl(current_zone, yyvsp[-1].iml))
+ parser_warning(0,
+ "zone transfer acl already set; skipping");
+ }
+break;
+case 195:
+#line 1212 "ns_parser.y"
+{
+ if (!set_zone_transfer_time_in(current_zone, yyvsp[0].num*60))
+ parser_warning(0,
+ "zone max transfer time (in) already set; skipping");
+ }
+break;
+case 196:
+#line 1218 "ns_parser.y"
+{
+ set_zone_notify(current_zone, yyvsp[0].num);
+ }
+break;
+case 199:
+#line 1226 "ns_parser.y"
+{
+ /* nothing */
+ }
+break;
+case 200:
+#line 1230 "ns_parser.y"
+{
+ /* nothing */
+ }
+break;
+case 201:
+#line 1236 "ns_parser.y"
+{
+ add_zone_master(current_zone, yyvsp[0].ip_addr);
+ }
+break;
+case 204:
+#line 1246 "ns_parser.y"
+{
+ /* nothing */
+ }
+break;
+case 205:
+#line 1250 "ns_parser.y"
+{
+ /* nothing */
+ }
+break;
+case 206:
+#line 1256 "ns_parser.y"
+{
+ add_zone_notify(current_zone, yyvsp[0].ip_addr);
+ }
+break;
+case 207:
+#line 1266 "ns_parser.y"
+{
+ if (yyvsp[0].num < 0 || yyvsp[0].num > 65535) {
+ parser_warning(0,
+ "invalid IP port number '%d'; setting port to 0",
+ yyvsp[0].num);
+ yyvsp[0].num = 0;
+ } else
+ yyval.us_int = htons(yyvsp[0].num);
+ }
+break;
+#line 2319 "y.tab.c"
+ }
+ yystk.ssp -= yym;
+ yystate = *yystk.ssp;
+ yystk.vsp -= yym;
+ yym = yylhs[yyn];
+ yych = yychar;
+ if (yystate == 0 && yym == 0)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+ yystate = YYFINAL;
+ *++yystk.ssp = YYFINAL;
+ *++yystk.vsp = yyval;
+ if (yych < 0)
+ {
+ if ((yych = YYLEX) < 0) yych = 0;
+ yychar = yych;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yych <= YYMAXTOKEN) yys = yyname[yych];
+ if (!yys) yys = "illegal-symbol";
+ printf("%sdebug: state %d, reading %d (%s)\n",
+ YYPREFIX, YYFINAL, yych, yys);
+ }
+#endif
+ }
+ if (yych == 0) goto yyaccept;
+ goto yyloop;
+ }
+ if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+ yystate = yytable[yyn];
+ else
+ yystate = yydgoto[yym];
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yystk.ssp, yystate);
+#endif
+ if (yystk.ssp >= yystk.sslim && yygrowstack(&yystk))
+ goto yyoverflow;
+ *++yystk.ssp = yystate;
+ *++yystk.vsp = yyval;
+ goto yyloop;
+yyoverflow:
+ yyerror("yacc stack overflow");
+yyabort:
+ YYFREESTACK(&yystk);
+ return (1);
+yyaccept:
+ YYFREESTACK(&yystk);
+ return (0);
+}
diff --git a/contrib/bind/bin/named/ns_parser.h b/contrib/bind/bin/named/ns_parser.h
new file mode 100644
index 0000000..1d23613
--- /dev/null
+++ b/contrib/bind/bin/named/ns_parser.h
@@ -0,0 +1,110 @@
+#define YYEMPTY (-1)
+#define L_EOS 257
+#define L_IPADDR 258
+#define L_NUMBER 259
+#define L_STRING 260
+#define L_QSTRING 261
+#define L_END_INCLUDE 262
+#define T_INCLUDE 263
+#define T_OPTIONS 264
+#define T_DIRECTORY 265
+#define T_PIDFILE 266
+#define T_NAMED_XFER 267
+#define T_DUMP_FILE 268
+#define T_STATS_FILE 269
+#define T_MEMSTATS_FILE 270
+#define T_FAKE_IQUERY 271
+#define T_RECURSION 272
+#define T_FETCH_GLUE 273
+#define T_QUERY_SOURCE 274
+#define T_LISTEN_ON 275
+#define T_PORT 276
+#define T_ADDRESS 277
+#define T_DATASIZE 278
+#define T_STACKSIZE 279
+#define T_CORESIZE 280
+#define T_DEFAULT 281
+#define T_UNLIMITED 282
+#define T_FILES 283
+#define T_HOSTSTATS 284
+#define T_DEALLOC_ON_EXIT 285
+#define T_TRANSFERS_IN 286
+#define T_TRANSFERS_OUT 287
+#define T_TRANSFERS_PER_NS 288
+#define T_TRANSFER_FORMAT 289
+#define T_MAX_TRANSFER_TIME_IN 290
+#define T_ONE_ANSWER 291
+#define T_MANY_ANSWERS 292
+#define T_NOTIFY 293
+#define T_AUTH_NXDOMAIN 294
+#define T_MULTIPLE_CNAMES 295
+#define T_CLEAN_INTERVAL 296
+#define T_INTERFACE_INTERVAL 297
+#define T_STATS_INTERVAL 298
+#define T_LOGGING 299
+#define T_CATEGORY 300
+#define T_CHANNEL 301
+#define T_SEVERITY 302
+#define T_DYNAMIC 303
+#define T_FILE 304
+#define T_VERSIONS 305
+#define T_SIZE 306
+#define T_SYSLOG 307
+#define T_DEBUG 308
+#define T_NULL_OUTPUT 309
+#define T_PRINT_TIME 310
+#define T_PRINT_CATEGORY 311
+#define T_PRINT_SEVERITY 312
+#define T_TOPOLOGY 313
+#define T_SERVER 314
+#define T_LONG_AXFR 315
+#define T_BOGUS 316
+#define T_TRANSFERS 317
+#define T_KEYS 318
+#define T_ZONE 319
+#define T_IN 320
+#define T_CHAOS 321
+#define T_HESIOD 322
+#define T_TYPE 323
+#define T_MASTER 324
+#define T_SLAVE 325
+#define T_STUB 326
+#define T_RESPONSE 327
+#define T_HINT 328
+#define T_MASTERS 329
+#define T_TRANSFER_SOURCE 330
+#define T_ALSO_NOTIFY 331
+#define T_ACL 332
+#define T_ALLOW_UPDATE 333
+#define T_ALLOW_QUERY 334
+#define T_ALLOW_TRANSFER 335
+#define T_SEC_KEY 336
+#define T_ALGID 337
+#define T_SECRET 338
+#define T_CHECK_NAMES 339
+#define T_WARN 340
+#define T_FAIL 341
+#define T_IGNORE 342
+#define T_FORWARD 343
+#define T_FORWARDERS 344
+#define T_ONLY 345
+#define T_FIRST 346
+#define T_IF_NO_ANSWER 347
+#define T_IF_NO_DOMAIN 348
+#define T_YES 349
+#define T_TRUE 350
+#define T_NO 351
+#define T_FALSE 352
+typedef union {
+ char * cp;
+ int s_int;
+ long num;
+ u_long ul_int;
+ u_int16_t us_int;
+ struct in_addr ip_addr;
+ ip_match_element ime;
+ ip_match_list iml;
+ key_info keyi;
+ enum axfr_format axfr_fmt;
+} YYSTYPE;
+extern YYSTYPE yylval;
diff --git a/contrib/bind/bin/named/ns_parser.y b/contrib/bind/bin/named/ns_parser.y
new file mode 100644
index 0000000..77dee0b
--- /dev/null
+++ b/contrib/bind/bin/named/ns_parser.y
@@ -0,0 +1,1473 @@
+%{
+#if !defined(lint) && !defined(SABER)
+static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/* Global C stuff goes here. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+
+#include "port_after.h"
+
+#include "named.h"
+#include "ns_parseutil.h"
+#include "ns_lexer.h"
+
+#define SYM_ZONE 0x010000
+#define SYM_SERVER 0x020000
+#define SYM_KEY 0x030000
+#define SYM_ACL 0x040000
+#define SYM_CHANNEL 0x050000
+#define SYM_PORT 0x060000
+
+#define SYMBOL_TABLE_SIZE 29989 /* should always be prime */
+static symbol_table symtab;
+
+#define AUTH_TABLE_SIZE 397 /* should always be prime */
+static symbol_table authtab = NULL;
+
+static zone_config current_zone;
+static int seen_zone;
+
+static options current_options;
+static int seen_options;
+
+static topology_config current_topology;
+static int seen_topology;
+
+static server_config current_server;
+static int seen_server;
+
+static char *current_algorithm;
+static char *current_secret;
+
+static log_config current_logging;
+static int current_category;
+static int chan_type;
+static int chan_level;
+static u_int chan_flags;
+static int chan_facility;
+static char *chan_name;
+static int chan_versions;
+static u_long chan_max_size;
+
+static log_channel lookup_channel(char *);
+static void define_channel(char *, log_channel);
+static char *canonical_name(char *);
+
+int yyparse();
+
+%}
+
+%union {
+ char * cp;
+ int s_int;
+ long num;
+ u_long ul_int;
+ u_int16_t us_int;
+ struct in_addr ip_addr;
+ ip_match_element ime;
+ ip_match_list iml;
+ key_info keyi;
+ enum axfr_format axfr_fmt;
+}
+
+/* Lexical analyzer return values. */
+%token L_EOS
+%token <ip_addr> L_IPADDR
+%token <num> L_NUMBER
+%token <cp> L_STRING
+%token <cp> L_QSTRING
+%token L_END_INCLUDE
+
+/* Include support */
+%token T_INCLUDE
+
+/* Items related to the "options" statement: */
+%token T_OPTIONS
+%token T_DIRECTORY T_PIDFILE T_NAMED_XFER
+%token T_DUMP_FILE T_STATS_FILE T_MEMSTATS_FILE
+%token T_FAKE_IQUERY T_RECURSION T_FETCH_GLUE
+%token T_QUERY_SOURCE T_LISTEN_ON T_PORT T_ADDRESS
+%type <us_int> in_port
+%type <us_int> maybe_port
+%type <us_int> maybe_wild_port
+%type <ip_addr> maybe_wild_addr
+%token T_DATASIZE T_STACKSIZE T_CORESIZE
+%token T_DEFAULT T_UNLIMITED
+%token T_FILES
+%token T_HOSTSTATS T_DEALLOC_ON_EXIT
+%token T_TRANSFERS_IN T_TRANSFERS_OUT T_TRANSFERS_PER_NS
+%token T_TRANSFER_FORMAT T_MAX_TRANSFER_TIME_IN
+%token T_ONE_ANSWER T_MANY_ANSWERS
+%type <axfr_fmt> transfer_format
+%token T_NOTIFY T_AUTH_NXDOMAIN T_MULTIPLE_CNAMES
+%token T_CLEAN_INTERVAL T_INTERFACE_INTERVAL T_STATS_INTERVAL
+
+/* Items used for the "logging" statement: */
+%token T_LOGGING T_CATEGORY T_CHANNEL T_SEVERITY T_DYNAMIC
+%token T_FILE T_VERSIONS T_SIZE
+%token T_SYSLOG T_DEBUG T_NULL_OUTPUT
+%token T_PRINT_TIME T_PRINT_CATEGORY T_PRINT_SEVERITY
+%type <s_int> category
+%type <cp> category_name channel_name facility_name
+%type <s_int> maybe_syslog_facility
+
+/* Items used for the "topology" statement: */
+%token T_TOPOLOGY
+
+/* ip_match_list */
+%type <ime> address_match_simple address_match_element address_name
+%type <iml> address_match_list
+
+/* Items used for "server" statements: */
+%token T_SERVER
+%token T_LONG_AXFR
+%token T_BOGUS
+%token T_TRANSFERS
+%token T_KEYS
+
+/* Items used for "zone" statements: */
+%token T_ZONE
+%type <num> optional_class
+%type <s_int> zone_type
+%token T_IN T_CHAOS T_HESIOD
+%token T_TYPE
+%token T_MASTER T_SLAVE T_STUB T_RESPONSE
+%token T_HINT
+%token T_MASTERS T_TRANSFER_SOURCE
+%token T_ALSO_NOTIFY
+
+/* Items used for access control lists and "allow" clauses: */
+%token T_ACL
+%token T_ALLOW_UPDATE T_ALLOW_QUERY T_ALLOW_TRANSFER
+
+/* Items related to the "key" statement: */
+%token T_SEC_KEY T_ALGID T_SECRET
+%type <keyi> key_ref
+%type <cp> algorithm_id secret
+
+/* Items used for "size_spec" clauses: */
+%type <ul_int> size_spec
+
+/* Items used for a "check-names" clause: */
+%token T_CHECK_NAMES
+%type <s_int> check_names_type
+%type <s_int> check_names_opt
+%token T_WARN T_FAIL T_IGNORE
+
+/* Items used for "forward" clauses: */
+%token T_FORWARD T_FORWARDERS
+%token T_ONLY T_FIRST T_IF_NO_ANSWER T_IF_NO_DOMAIN
+
+/* Items used for yes/no responses: */
+%type <num> yea_or_nay
+%token T_YES T_TRUE T_NO T_FALSE
+
+/* Miscellaneous items (used in several places): */
+%type <cp> any_string
+
+%%
+config_file: statement_list
+ {
+ /* nothing */
+ }
+ ;
+
+statement_list: statement
+ | statement_list statement
+ ;
+
+statement: include_stmt
+ | options_stmt L_EOS
+ | logging_stmt L_EOS
+ | server_stmt L_EOS
+ | zone_stmt L_EOS
+ | acl_stmt L_EOS
+ | key_stmt L_EOS
+ | L_END_INCLUDE
+ | error L_EOS
+ | error L_END_INCLUDE
+ ;
+
+include_stmt: T_INCLUDE L_QSTRING L_EOS { lexer_begin_file($2, NULL); }
+ ;
+
+/*
+ * Options
+ */
+
+options_stmt: T_OPTIONS
+ {
+ if (seen_options)
+ parser_error(0, "cannot redefine options");
+ current_options = new_options();
+ }
+ '{' options '}'
+ {
+ if (!seen_options)
+ set_options(current_options, 0);
+ else
+ free_options(current_options);
+ current_options = NULL;
+ seen_options = 1;
+ }
+ ;
+
+options: option L_EOS
+ | options option L_EOS
+ ;
+
+option: /* Empty */
+ | T_DIRECTORY L_QSTRING
+ {
+ if (current_options->directory != NULL)
+ freestr(current_options->directory);
+ current_options->directory = $2;
+ }
+ | T_NAMED_XFER L_QSTRING
+ {
+ if (current_options->named_xfer != NULL)
+ freestr(current_options->named_xfer);
+ current_options->named_xfer = $2;
+ }
+ | T_PIDFILE L_QSTRING
+ {
+ if (current_options->pid_filename != NULL)
+ freestr(current_options->pid_filename);
+ current_options->pid_filename = $2;
+ }
+ | T_STATS_FILE L_QSTRING
+ {
+ if (current_options->stats_filename != NULL)
+ freestr(current_options->stats_filename);
+ current_options->stats_filename = $2;
+ }
+ | T_MEMSTATS_FILE L_QSTRING
+ {
+ if (current_options->memstats_filename != NULL)
+ freestr(current_options->memstats_filename);
+ current_options->memstats_filename = $2;
+ }
+ | T_DUMP_FILE L_QSTRING
+ {
+ if (current_options->dump_filename != NULL)
+ freestr(current_options->dump_filename);
+ current_options->dump_filename = $2;
+ }
+ | T_FAKE_IQUERY yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_FAKE_IQUERY, $2);
+ }
+ | T_RECURSION yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_NORECURSE, !$2);
+ }
+ | T_FETCH_GLUE yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_NOFETCHGLUE, !$2);
+ }
+ | T_NOTIFY yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_NONOTIFY, !$2);
+ }
+ | T_HOSTSTATS yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_HOSTSTATS, $2);
+ }
+ | T_DEALLOC_ON_EXIT yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_DEALLOC_ON_EXIT,
+ $2);
+ }
+ | T_AUTH_NXDOMAIN yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_NONAUTH_NXDOMAIN,
+ !$2);
+ }
+ | T_MULTIPLE_CNAMES yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_MULTIPLE_CNAMES,
+ $2);
+ }
+ | T_CHECK_NAMES check_names_type check_names_opt
+ {
+ current_options->check_names[$2] = $3;
+ }
+ | T_LISTEN_ON maybe_port '{' address_match_list '}'
+ {
+ char port_string[10];
+ symbol_value value;
+
+ (void)sprintf(port_string, "%u", $2);
+ if (lookup_symbol(symtab, port_string, SYM_PORT, NULL))
+ parser_error(0,
+ "cannot redefine listen-on for port %u",
+ ntohs($2));
+ else {
+ add_listen_on(current_options, $2, $4);
+ value.pointer = NULL;
+ define_symbol(symtab, savestr(port_string, 1),
+ SYM_PORT, value, SYMBOL_FREE_KEY);
+ }
+
+ }
+ | T_FORWARD forward_opt
+ | T_FORWARDERS
+ {
+ if (current_options->fwdtab) {
+ free_forwarders(current_options->fwdtab);
+ current_options->fwdtab = NULL;
+ }
+ }
+ '{' opt_forwarders_list '}'
+ | T_QUERY_SOURCE query_source
+ | T_ALLOW_QUERY '{' address_match_list '}'
+ {
+ if (current_options->query_acl)
+ free_ip_match_list(current_options->query_acl);
+ current_options->query_acl = $3;
+ }
+ | T_ALLOW_TRANSFER '{' address_match_list '}'
+ {
+ if (current_options->transfer_acl)
+ free_ip_match_list(current_options->transfer_acl);
+ current_options->transfer_acl = $3;
+ }
+ | T_TOPOLOGY '{' address_match_list '}'
+ {
+ if (current_options->topology)
+ free_ip_match_list(current_options->topology);
+ current_options->topology = $3;
+ }
+ | size_clause
+ {
+ /* To get around the $$ = $1 default rule. */
+ }
+ | transfer_clause
+ | T_TRANSFER_FORMAT transfer_format
+ {
+ current_options->transfer_format = $2;
+ }
+ | T_MAX_TRANSFER_TIME_IN L_NUMBER
+ {
+ current_options->max_transfer_time_in = $2 * 60;
+ }
+ | T_CLEAN_INTERVAL L_NUMBER
+ {
+ current_options->clean_interval = $2 * 60;
+ }
+ | T_INTERFACE_INTERVAL L_NUMBER
+ {
+ current_options->interface_interval = $2 * 60;
+ }
+ | T_STATS_INTERVAL L_NUMBER
+ {
+ current_options->stats_interval = $2 * 60;
+ }
+ | error
+ ;
+
+transfer_format: T_ONE_ANSWER
+ {
+ $$ = axfr_one_answer;
+ }
+ | T_MANY_ANSWERS
+ {
+ $$ = axfr_many_answers;
+ }
+ ;
+
+maybe_wild_addr: L_IPADDR { $$ = $1; }
+ | '*' { $$.s_addr = htonl(INADDR_ANY); }
+ ;
+
+maybe_wild_port: in_port { $$ = $1; }
+ | '*' { $$ = htons(0); }
+ ;
+
+query_source_address: T_ADDRESS maybe_wild_addr
+ {
+ current_options->query_source.sin_addr = $2;
+ }
+ ;
+
+query_source_port: T_PORT maybe_wild_port
+ {
+ current_options->query_source.sin_port = $2;
+ }
+ ;
+
+query_source: query_source_address
+ | query_source_port
+ | query_source_address query_source_port
+ | query_source_port query_source_address
+ ;
+
+maybe_port: /* nothing */ { $$ = htons(NS_DEFAULTPORT); }
+ | T_PORT in_port { $$ = $2; }
+ ;
+
+yea_or_nay: T_YES
+ {
+ $$ = 1;
+ }
+ | T_TRUE
+ {
+ $$ = 1;
+ }
+ | T_NO
+ {
+ $$ = 0;
+ }
+ | T_FALSE
+ {
+ $$ = 0;
+ }
+ | L_NUMBER
+ {
+ if ($1 == 1 || $1 == 0) {
+ $$ = $1;
+ } else {
+ parser_warning(0,
+ "number should be 0 or 1; assuming 1");
+ $$ = 1;
+ }
+ }
+ ;
+
+check_names_type: T_MASTER
+ {
+ $$ = primary_trans;
+ }
+ | T_SLAVE
+ {
+ $$ = secondary_trans;
+ }
+ | T_RESPONSE
+ {
+ $$ = response_trans;
+ }
+ ;
+
+check_names_opt: T_WARN
+ {
+ $$ = warn;
+ }
+ | T_FAIL
+ {
+ $$ = fail;
+ }
+ | T_IGNORE
+ {
+ $$ = ignore;
+ }
+ ;
+
+forward_opt: T_ONLY
+ {
+ set_boolean_option(current_options, OPTION_FORWARD_ONLY, 1);
+ }
+ | T_FIRST
+ {
+ set_boolean_option(current_options, OPTION_FORWARD_ONLY, 0);
+ }
+ | T_IF_NO_ANSWER
+ {
+ parser_warning(0, "forward if-no-answer is unimplemented");
+ }
+ | T_IF_NO_DOMAIN
+ {
+ parser_warning(0, "forward if-no-domain is unimplemented");
+ }
+ ;
+
+size_clause: T_DATASIZE size_spec
+ {
+ current_options->data_size = $2;
+ }
+ | T_STACKSIZE size_spec
+ {
+ current_options->stack_size = $2;
+ }
+ | T_CORESIZE size_spec
+ {
+ current_options->core_size = $2;
+ }
+ | T_FILES size_spec
+ {
+ current_options->files = $2;
+ }
+ ;
+
+size_spec: any_string
+ {
+ u_long result;
+
+ if (unit_to_ulong($1, &result))
+ $$ = result;
+ else {
+ parser_error(0, "invalid unit string '%s'", $1);
+ /* 0 means "use default" */
+ $$ = 0;
+ }
+ freestr($1);
+ }
+ | L_NUMBER
+ {
+ $$ = (u_long)$1;
+ }
+ | T_DEFAULT
+ {
+ $$ = 0;
+ }
+ | T_UNLIMITED
+ {
+ $$ = ULONG_MAX;
+ }
+ ;
+
+transfer_clause: T_TRANSFERS_IN L_NUMBER
+ {
+ current_options->transfers_in = (u_long) $2;
+ }
+ | T_TRANSFERS_OUT L_NUMBER
+ {
+ current_options->transfers_out = (u_long) $2;
+ }
+ | T_TRANSFERS_PER_NS L_NUMBER
+ {
+ current_options->transfers_per_ns = (u_long) $2;
+ }
+ ;
+
+opt_forwarders_list: /* nothing */
+ | forwarders_in_addr_list
+ ;
+
+forwarders_in_addr_list: forwarders_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ | forwarders_in_addr_list forwarders_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ ;
+
+forwarders_in_addr: L_IPADDR
+ {
+ add_forwarder(current_options, $1);
+ }
+ ;
+
+/*
+ * Logging
+ */
+
+logging_stmt: T_LOGGING
+ {
+ current_logging = begin_logging();
+ }
+ '{' logging_opts_list '}'
+ {
+ end_logging(current_logging, 1);
+ current_logging = NULL;
+ }
+ ;
+
+logging_opts_list: logging_opt L_EOS
+ | logging_opts_list logging_opt L_EOS
+ | error
+ ;
+
+logging_opt: T_CATEGORY category
+ {
+ current_category = $2;
+ }
+ '{' channel_list '}'
+ | T_CHANNEL channel_name
+ {
+ chan_type = log_null;
+ chan_flags = 0;
+ chan_level = log_info;
+ }
+ '{' channel_opt_list '}'
+ {
+ log_channel current_channel = NULL;
+
+ if (lookup_channel($2) != NULL) {
+ parser_error(0, "can't redefine channel '%s'", $2);
+ freestr($2);
+ } else {
+ switch (chan_type) {
+ case log_file:
+ current_channel =
+ log_new_file_channel(chan_flags,
+ chan_level,
+ chan_name, NULL,
+ chan_versions,
+ chan_max_size);
+ freestr(chan_name);
+ chan_name = NULL;
+ break;
+ case log_syslog:
+ current_channel =
+ log_new_syslog_channel(chan_flags,
+ chan_level,
+ chan_facility);
+ break;
+ case log_null:
+ current_channel = log_new_null_channel();
+ break;
+ default:
+ ns_panic(ns_log_parser, 1,
+ "unknown channel type: %d",
+ chan_type);
+ }
+ if (current_channel == NULL)
+ ns_panic(ns_log_parser, 0,
+ "couldn't create channel");
+ define_channel($2, current_channel);
+ }
+ }
+ ;
+
+channel_severity: any_string
+ {
+ symbol_value value;
+
+ if (lookup_symbol(constants, $1, SYM_LOGGING, &value)) {
+ chan_level = value.integer;
+ } else {
+ parser_error(0, "unknown severity '%s'", $1);
+ chan_level = log_debug(99);
+ }
+ freestr($1);
+ }
+ | T_DEBUG
+ {
+ chan_level = log_debug(1);
+ }
+ | T_DEBUG L_NUMBER
+ {
+ chan_level = $2;
+ }
+ | T_DYNAMIC
+ {
+ chan_level = 0;
+ chan_flags |= LOG_USE_CONTEXT_LEVEL|LOG_REQUIRE_DEBUG;
+ }
+ ;
+
+version_modifier: T_VERSIONS L_NUMBER
+ {
+ chan_versions = $2;
+ chan_flags |= LOG_TRUNCATE;
+ }
+ | T_VERSIONS T_UNLIMITED
+ {
+ chan_versions = LOG_MAX_VERSIONS;
+ chan_flags |= LOG_TRUNCATE;
+ }
+ ;
+
+size_modifier: T_SIZE size_spec
+ {
+ chan_max_size = $2;
+ }
+ ;
+
+maybe_file_modifiers: /* nothing */
+ {
+ chan_versions = 0;
+ chan_max_size = ULONG_MAX;
+ }
+ | version_modifier
+ {
+ chan_max_size = ULONG_MAX;
+ }
+ | size_modifier
+ {
+ chan_versions = 0;
+ }
+ | version_modifier size_modifier
+ | size_modifier version_modifier
+ ;
+
+channel_file: T_FILE L_QSTRING maybe_file_modifiers
+ {
+ chan_flags |= LOG_CLOSE_STREAM;
+ chan_type = log_file;
+ chan_name = $2;
+ }
+ ;
+
+
+facility_name: any_string { $$ = $1; }
+ | T_SYSLOG { $$ = savestr("syslog", 1); }
+ ;
+
+maybe_syslog_facility: /* nothing */ { $$ = LOG_DAEMON; }
+ | facility_name
+ {
+ symbol_value value;
+
+ if (lookup_symbol(constants, $1, SYM_SYSLOG, &value)) {
+ $$ = value.integer;
+ } else {
+ parser_error(0, "unknown facility '%s'", $1);
+ $$ = LOG_DAEMON;
+ }
+ freestr($1);
+ }
+ ;
+
+channel_syslog: T_SYSLOG maybe_syslog_facility
+ {
+ chan_type = log_syslog;
+ chan_facility = $2;
+ }
+ ;
+
+channel_opt: channel_file { /* nothing to do */ }
+ | channel_syslog { /* nothing to do */ }
+ | T_NULL_OUTPUT
+ {
+ chan_type = log_null;
+ }
+ | T_SEVERITY channel_severity { /* nothing to do */ }
+ | T_PRINT_TIME yea_or_nay
+ {
+ if ($2)
+ chan_flags |= LOG_TIMESTAMP;
+ else
+ chan_flags &= ~LOG_TIMESTAMP;
+ }
+ | T_PRINT_CATEGORY yea_or_nay
+ {
+ if ($2)
+ chan_flags |= LOG_PRINT_CATEGORY;
+ else
+ chan_flags &= ~LOG_PRINT_CATEGORY;
+ }
+ | T_PRINT_SEVERITY yea_or_nay
+ {
+ if ($2)
+ chan_flags |= LOG_PRINT_LEVEL;
+ else
+ chan_flags &= ~LOG_PRINT_LEVEL;
+ }
+ ;
+
+channel_opt_list: channel_opt L_EOS
+ | channel_opt_list channel_opt L_EOS
+ | error
+ ;
+
+channel_name: any_string
+ | T_NULL_OUTPUT { $$ = savestr("null", 1); }
+ ;
+
+channel: channel_name
+ {
+ log_channel channel;
+ symbol_value value;
+
+ if (current_category >= 0) {
+ channel = lookup_channel($1);
+ if (channel != NULL) {
+ add_log_channel(current_logging,
+ current_category, channel);
+ } else
+ parser_error(0, "unknown channel '%s'", $1);
+ }
+ freestr($1);
+ }
+ ;
+
+channel_list: channel L_EOS
+ | channel_list channel L_EOS
+ | error
+ ;
+
+category_name: any_string
+ | T_DEFAULT { $$ = savestr("default", 1); }
+ | T_NOTIFY { $$ = savestr("notify", 1); }
+ ;
+
+category: category_name
+ {
+ symbol_value value;
+
+ if (lookup_symbol(constants, $1, SYM_CATEGORY, &value))
+ $$ = value.integer;
+ else {
+ parser_error(0, "invalid logging category '%s'",
+ $1);
+ $$ = -1;
+ }
+ freestr($1);
+ }
+ ;
+
+/*
+ * Server Information
+ */
+
+server_stmt: T_SERVER L_IPADDR
+ {
+ char *ip_printable;
+ symbol_value value;
+
+ ip_printable = inet_ntoa($2);
+ value.pointer = NULL;
+ if (lookup_symbol(symtab, ip_printable, SYM_SERVER, NULL))
+ seen_server = 1;
+ else
+ seen_server = 0;
+ if (seen_server)
+ parser_error(0, "cannot redefine server '%s'",
+ ip_printable);
+ else
+ define_symbol(symtab, savestr(ip_printable, 1),
+ SYM_SERVER, value,
+ SYMBOL_FREE_KEY);
+ current_server = begin_server($2);
+ }
+ '{' server_info_list '}'
+ {
+ end_server(current_server, !seen_server);
+ }
+ ;
+
+server_info_list: server_info L_EOS
+ | server_info_list server_info L_EOS
+ ;
+
+server_info: T_BOGUS yea_or_nay
+ {
+ set_server_option(current_server, SERVER_INFO_BOGUS, $2);
+ }
+ | T_TRANSFERS L_NUMBER
+ {
+ set_server_transfers(current_server, (int)$2);
+ }
+ | T_TRANSFER_FORMAT transfer_format
+ {
+ set_server_transfer_format(current_server, $2);
+ }
+ | T_KEYS '{' key_list '}'
+ | error
+ ;
+
+/*
+ * Address Matching
+ */
+
+address_match_list: address_match_element L_EOS
+ {
+ ip_match_list iml;
+
+ iml = new_ip_match_list();
+ if ($1 != NULL)
+ add_to_ip_match_list(iml, $1);
+ $$ = iml;
+ }
+ | address_match_list address_match_element L_EOS
+ {
+ if ($2 != NULL)
+ add_to_ip_match_list($1, $2);
+ $$ = $1;
+ }
+ ;
+
+address_match_element: address_match_simple
+ | '!' address_match_simple
+ {
+ if ($2 != NULL)
+ ip_match_negate($2);
+ $$ = $2;
+ }
+ ;
+
+address_match_simple: L_IPADDR
+ {
+ $$ = new_ip_match_pattern($1, 32);
+ }
+ | L_IPADDR '/' L_NUMBER
+ {
+ if ($3 < 0 || $3 > 32) {
+ parser_error(0, "mask bits out of range; skipping");
+ $$ = NULL;
+ } else {
+ $$ = new_ip_match_pattern($1, $3);
+ if ($$ == NULL)
+ parser_error(0,
+ "address/mask mismatch; skipping");
+ }
+ }
+ | L_NUMBER '/' L_NUMBER
+ {
+ struct in_addr ia;
+
+ if ($1 > 255) {
+ parser_error(0, "address out of range; skipping");
+ $$ = NULL;
+ } else {
+ if ($3 < 0 || $3 > 32) {
+ parser_error(0,
+ "mask bits out of range; skipping");
+ $$ = NULL;
+ } else {
+ ia.s_addr = htonl(($1 & 0xff) << 24);
+ $$ = new_ip_match_pattern(ia, $3);
+ if ($$ == NULL)
+ parser_error(0,
+ "address/mask mismatch; skipping");
+ }
+ }
+ }
+ | address_name
+ | '{' address_match_list '}'
+ {
+ char name[256];
+
+ /*
+ * We want to be able to clean up this iml later so
+ * we give it a name and treat it like any other acl.
+ */
+ sprintf(name, "__internal_%p", $2);
+ define_acl(savestr(name, 1), $2);
+ $$ = new_ip_match_indirect($2);
+ }
+ ;
+
+address_name: any_string
+ {
+ ip_match_list iml;
+
+ iml = lookup_acl($1);
+ if (iml == NULL) {
+ parser_error(0, "unknown ACL '%s'", $1);
+ $$ = NULL;
+ } else
+ $$ = new_ip_match_indirect(iml);
+ freestr($1);
+ }
+ ;
+
+/*
+ * Keys
+ */
+
+key_ref: any_string
+ {
+ key_info ki;
+
+ ki = lookup_key($1);
+ if (ki == NULL) {
+ parser_error(0, "unknown key '%s'", $1);
+ $$ = NULL;
+ } else
+ $$ = ki;
+ freestr($1);
+ }
+ ;
+
+key_list_element: key_ref
+ {
+ if ($1 == NULL)
+ parser_error(0, "empty key not added to server list ");
+ else
+ add_server_key_info(current_server, $1);
+ }
+ ;
+
+key_list: key_list_element L_EOS
+ | key_list key_list_element L_EOS
+ | error
+ ;
+
+key_stmt: T_SEC_KEY
+ {
+ current_algorithm = NULL;
+ current_secret = NULL;
+ }
+ any_string '{' key_definition '}'
+ {
+ key_info ki;
+
+ if (lookup_key($3) != NULL) {
+ parser_error(0, "can't redefine key '%s'", $3);
+ freestr($3);
+ } else {
+ if (current_algorithm == NULL ||
+ current_secret == NULL)
+ parser_error(0, "skipping bad key '%s'", $3);
+ else {
+ ki = new_key_info($3, current_algorithm,
+ current_secret);
+ define_key($3, ki);
+ }
+ }
+ }
+ ;
+
+key_definition: algorithm_id secret
+ {
+ current_algorithm = $1;
+ current_secret = $2;
+ }
+ | secret algorithm_id
+ {
+ current_algorithm = $2;
+ current_secret = $1;
+ }
+ | error
+ {
+ current_algorithm = NULL;
+ current_secret = NULL;
+ }
+ ;
+
+algorithm_id: T_ALGID any_string L_EOS { $$ = $2; }
+ ;
+
+secret: T_SECRET any_string L_EOS { $$ = $2; }
+ ;
+
+/*
+ * ACLs
+ */
+
+acl_stmt: T_ACL any_string '{' address_match_list '}'
+ {
+ if (lookup_acl($2) != NULL) {
+ parser_error(0, "can't redefine ACL '%s'", $2);
+ freestr($2);
+ } else
+ define_acl($2, $4);
+ }
+ ;
+
+/*
+ * Zones
+ */
+
+zone_stmt: T_ZONE L_QSTRING optional_class
+ {
+ int sym_type;
+ symbol_value value;
+ char *zone_name;
+
+ if (!seen_options)
+ parser_error(0,
+ "no options statement before first zone; using previous/default");
+ sym_type = SYM_ZONE | ($3 & 0xffff);
+ value.pointer = NULL;
+ zone_name = canonical_name($2);
+ if (zone_name == NULL) {
+ parser_error(0, "can't make zone name '%s' canonical",
+ $2);
+ seen_zone = 1;
+ zone_name = savestr("__bad_zone__", 1);
+ } else {
+ seen_zone = lookup_symbol(symtab, zone_name, sym_type,
+ NULL);
+ if (seen_zone) {
+ parser_error(0,
+ "cannot redefine zone '%s' class %d",
+ zone_name, $3);
+ } else
+ define_symbol(symtab, zone_name, sym_type,
+ value, 0);
+ }
+ freestr($2);
+ current_zone = begin_zone(zone_name, $3);
+ }
+ optional_zone_options_list
+ { end_zone(current_zone, !seen_zone); }
+ ;
+
+optional_zone_options_list: /* Empty */
+ | '{' zone_option_list '}'
+ ;
+
+optional_class: /* Empty */
+ {
+ $$ = C_IN;
+ }
+ | any_string
+ {
+ symbol_value value;
+
+ if (lookup_symbol(constants, $1, SYM_CLASS, &value))
+ $$ = value.integer;
+ else {
+ /* the zone validator will give the error */
+ $$ = C_NONE;
+ }
+ freestr($1);
+ }
+ ;
+
+zone_type: T_MASTER
+ {
+ $$ = Z_MASTER;
+ }
+ | T_SLAVE
+ {
+ $$ = Z_SLAVE;
+ }
+ | T_HINT
+ {
+ $$ = Z_HINT;
+ }
+ | T_STUB
+ {
+ $$ = Z_STUB;
+ }
+ ;
+
+zone_option_list: zone_option L_EOS
+ | zone_option_list zone_option L_EOS
+ ;
+
+zone_option: T_TYPE zone_type
+ {
+ if (!set_zone_type(current_zone, $2))
+ parser_warning(0, "zone type already set; skipping");
+ }
+ | T_FILE L_QSTRING
+ {
+ if (!set_zone_filename(current_zone, $2))
+ parser_warning(0,
+ "zone filename already set; skipping");
+ }
+ | T_MASTERS '{' master_in_addr_list '}'
+ | T_TRANSFER_SOURCE maybe_wild_addr
+ {
+ set_zone_transfer_source(current_zone, $2);
+ }
+ | T_CHECK_NAMES check_names_opt
+ {
+ if (!set_zone_checknames(current_zone, $2))
+ parser_warning(0,
+ "zone checknames already set; skipping");
+ }
+ | T_ALLOW_UPDATE '{' address_match_list '}'
+ {
+ if (!set_zone_update_acl(current_zone, $3))
+ parser_warning(0,
+ "zone update acl already set; skipping");
+ }
+ | T_ALLOW_QUERY '{' address_match_list '}'
+ {
+ if (!set_zone_query_acl(current_zone, $3))
+ parser_warning(0,
+ "zone query acl already set; skipping");
+ }
+ | T_ALLOW_TRANSFER '{' address_match_list '}'
+ {
+ if (!set_zone_transfer_acl(current_zone, $3))
+ parser_warning(0,
+ "zone transfer acl already set; skipping");
+ }
+ | T_MAX_TRANSFER_TIME_IN L_NUMBER
+ {
+ if (!set_zone_transfer_time_in(current_zone, $2*60))
+ parser_warning(0,
+ "zone max transfer time (in) already set; skipping");
+ }
+ | T_NOTIFY yea_or_nay
+ {
+ set_zone_notify(current_zone, $2);
+ }
+ | T_ALSO_NOTIFY '{' opt_notify_in_addr_list '}'
+ | error
+ ;
+
+master_in_addr_list: master_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ | master_in_addr_list master_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ ;
+
+master_in_addr: L_IPADDR
+ {
+ add_zone_master(current_zone, $1);
+ }
+ ;
+
+opt_notify_in_addr_list: /* nothing */
+ | notify_in_addr_list
+ ;
+
+notify_in_addr_list: notify_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ | notify_in_addr_list notify_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ ;
+
+notify_in_addr: L_IPADDR
+ {
+ add_zone_notify(current_zone, $1);
+ }
+ ;
+
+/*
+ * Misc.
+ */
+
+in_port: L_NUMBER
+ {
+ if ($1 < 0 || $1 > 65535) {
+ parser_warning(0,
+ "invalid IP port number '%d'; setting port to 0",
+ $1);
+ $1 = 0;
+ } else
+ $$ = htons($1);
+ }
+ ;
+
+any_string: L_STRING
+ | L_QSTRING
+ ;
+
+%%
+
+static char *
+canonical_name(char *name) {
+ char canonical[MAXDNAME];
+
+ if (strlen(name) >= MAXDNAME)
+ return (NULL);
+ strcpy(canonical, name);
+ if (makename(canonical, ".", sizeof canonical) < 0)
+ return (NULL);
+ return (savestr(canonical, 0));
+}
+
+static void
+init_acls() {
+ ip_match_element ime;
+ ip_match_list iml;
+ struct in_addr address;
+
+ /* Create the predefined ACLs */
+
+ address.s_addr = 0U;
+
+ /* ACL "any" */
+ ime = new_ip_match_pattern(address, 0);
+ iml = new_ip_match_list();
+ add_to_ip_match_list(iml, ime);
+ define_acl(savestr("any", 1), iml);
+
+ /* ACL "none" */
+ ime = new_ip_match_pattern(address, 0);
+ ip_match_negate(ime);
+ iml = new_ip_match_list();
+ add_to_ip_match_list(iml, ime);
+ define_acl(savestr("none", 1), iml);
+
+ /* ACL "localhost" */
+ ime = new_ip_match_localhost();
+ iml = new_ip_match_list();
+ add_to_ip_match_list(iml, ime);
+ define_acl(savestr("localhost", 1), iml);
+
+ /* ACL "localnets" */
+ ime = new_ip_match_localnets();
+ iml = new_ip_match_list();
+ add_to_ip_match_list(iml, ime);
+ define_acl(savestr("localnets", 1), iml);
+}
+
+static void
+free_sym_value(int type, void *value) {
+ ns_debug(ns_log_parser, 99, "free_sym_value: type %06x value %p",
+ type, value);
+ type &= ~0xffff;
+ switch (type) {
+ case SYM_ACL:
+ free_ip_match_list(value);
+ break;
+ case SYM_KEY:
+ free_key_info(value);
+ break;
+ default:
+ ns_panic(ns_log_parser, 1,
+ "unhandled case in free_sym_value()");
+ /* NOTREACHED */
+ break;
+ }
+}
+
+static log_channel
+lookup_channel(char *name) {
+ symbol_value value;
+
+ if (lookup_symbol(symtab, name, SYM_CHANNEL, &value))
+ return ((log_channel)(value.pointer));
+ return (NULL);
+}
+
+static void
+define_channel(char *name, log_channel channel) {
+ symbol_value value;
+
+ value.pointer = channel;
+ define_symbol(symtab, name, SYM_CHANNEL, value, SYMBOL_FREE_KEY);
+}
+
+static void
+define_builtin_channels() {
+ define_channel(savestr("default_syslog", 1), syslog_channel);
+ define_channel(savestr("default_debug", 1), debug_channel);
+ define_channel(savestr("default_stderr", 1), stderr_channel);
+ define_channel(savestr("null", 1), null_channel);
+}
+
+static void
+parser_setup() {
+ seen_options = 0;
+ seen_topology = 0;
+ symtab = new_symbol_table(SYMBOL_TABLE_SIZE, NULL);
+ if (authtab != NULL)
+ free_symbol_table(authtab);
+ authtab = new_symbol_table(AUTH_TABLE_SIZE, free_sym_value);
+ init_acls();
+ define_builtin_channels();
+}
+
+static void
+parser_cleanup() {
+ if (symtab != NULL)
+ free_symbol_table(symtab);
+ symtab = NULL;
+ /*
+ * We don't clean up authtab here because the ip_match_lists are in
+ * use.
+ */
+}
+
+/*
+ * Public Interface
+ */
+
+ip_match_list
+lookup_acl(char *name) {
+ symbol_value value;
+
+ if (lookup_symbol(authtab, name, SYM_ACL, &value))
+ return ((ip_match_list)(value.pointer));
+ return (NULL);
+}
+
+void
+define_acl(char *name, ip_match_list iml) {
+ symbol_value value;
+
+ INSIST(name != NULL);
+ INSIST(iml != NULL);
+
+ value.pointer = iml;
+ define_symbol(authtab, name, SYM_ACL, value,
+ SYMBOL_FREE_KEY|SYMBOL_FREE_VALUE);
+ ns_debug(ns_log_parser, 7, "acl %s", name);
+ dprint_ip_match_list(ns_log_parser, iml, 2, "allow ", "deny ");
+}
+
+key_info
+lookup_key(char *name) {
+ symbol_value value;
+
+ if (lookup_symbol(authtab, name, SYM_KEY, &value))
+ return ((key_info)(value.pointer));
+ return (NULL);
+}
+
+void
+define_key(char *name, key_info ki) {
+ symbol_value value;
+
+ INSIST(name != NULL);
+ INSIST(ki != NULL);
+
+ value.pointer = ki;
+ define_symbol(authtab, name, SYM_KEY, value, SYMBOL_FREE_VALUE);
+ dprint_key_info(ki);
+}
+
+void
+parse_configuration(const char *filename) {
+ FILE *config_stream;
+
+ config_stream = fopen(filename, "r");
+ if (config_stream == NULL)
+ ns_panic(ns_log_parser, 0, "can't open '%s'", filename);
+
+ lexer_setup();
+ parser_setup();
+ lexer_begin_file(filename, config_stream);
+ (void)yyparse();
+ lexer_end_file();
+ parser_cleanup();
+}
+
+void
+parser_initialize(void) {
+ lexer_initialize();
+}
+
+void
+parser_shutdown(void) {
+ if (authtab != NULL)
+ free_symbol_table(authtab);
+ lexer_shutdown();
+}
diff --git a/contrib/bind/bin/named/ns_parseutil.c b/contrib/bind/bin/named/ns_parseutil.c
new file mode 100644
index 0000000..aed15af
--- /dev/null
+++ b/contrib/bind/bin/named/ns_parseutil.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/* Global C stuff goes here. */
+
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "named.h"
+#include "ns_parseutil.h"
+
+
+/*
+ * Symbol Table
+ */
+
+symbol_table
+new_symbol_table(int size_guess, free_function free_value) {
+ symbol_table st;
+
+ st = (symbol_table)memget(sizeof (struct symbol_table));
+ if (st == NULL)
+ panic("memget failed in new_symbol_table()", NULL);
+ st->table = (symbol_entry *)memget(size_guess * sizeof *st->table);
+ if (st->table == NULL)
+ panic("memget failed in new_symbol_table()", NULL);
+ memset(st->table, 0, size_guess * sizeof (symbol_entry));
+ st->size = size_guess; /* size_guess should be prime */
+ st->free_value = free_value;
+ return (st);
+}
+
+void
+free_symbol(symbol_table st, symbol_entry ste) {
+ if (ste->flags & SYMBOL_FREE_KEY)
+ freestr(ste->key);
+ if (ste->flags & SYMBOL_FREE_VALUE)
+ (st->free_value)(ste->type, ste->value.pointer);
+}
+
+void
+free_symbol_table(symbol_table st) {
+ int i;
+ symbol_entry ste, ste_next;
+
+ for (i = 0; i < st->size; i++) {
+ for (ste = st->table[i]; ste != NULL; ste = ste_next) {
+ ste_next = ste->next;
+ free_symbol(st, ste);
+ memput(ste, sizeof *ste);
+ }
+ }
+ memput(st->table, st->size * sizeof (symbol_entry));
+ memput(st, sizeof *st);
+}
+
+void
+dprint_symbol_table(int level, symbol_table st) {
+ int i;
+ symbol_entry ste;
+
+ for (i = 0; i < st->size; i++) {
+ for (ste = st->table[i]; ste != NULL; ste = ste->next)
+ ns_debug(ns_log_parser, level,
+ "%7d: (%s: %d %p/%d %04x) ",
+ i, ste->key, ste->type, ste->value.pointer,
+ ste->value.integer, ste->flags);
+ }
+}
+
+/*
+ * P. J. Weinberger's hash function, adapted from p. 436 of
+ * _Compilers: Principles, Techniques, and Tools_, Aho, Sethi
+ * and Ullman, Addison-Wesley, 1986, ISBN 0-201-10088-6.
+ */
+static int
+symbol_hash(const char *key, int prime) {
+ const char *s;
+ unsigned int h = 0;
+ unsigned int g;
+ int c;
+
+ for (s = key; *s != '\0'; s++) {
+ c = *s;
+ if (isascii(c) && isupper(c))
+ c = tolower(c);
+ h = ( h << 4 ) + c;
+ if ((g = ( h & 0xf0000000 )) != 0) {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ return (h % prime);
+}
+
+int
+lookup_symbol(symbol_table st, const char *key, int type,
+ symbol_value *value) {
+ int hash;
+ symbol_entry ste;
+
+ hash = symbol_hash(key, st->size);
+ for (ste = st->table[hash]; ste != NULL; ste = ste->next)
+ if ((type == 0 || ste->type == type) &&
+ strcasecmp(ste->key, key) == 0)
+ break;
+ if (ste != NULL) {
+ if (value != NULL)
+ *value = ste->value;
+ return (1);
+ }
+ return (0);
+}
+
+void
+define_symbol(symbol_table st, char *key, int type, symbol_value value,
+ unsigned int flags) {
+ int hash;
+ symbol_entry ste;
+
+ hash = symbol_hash(key, st->size);
+ for (ste = st->table[hash]; ste != NULL; ste = ste->next)
+ if ((type == 0 || ste->type == type) &&
+ strcasecmp(ste->key, key) == 0)
+ break;
+ if (ste == NULL) {
+ ste = (symbol_entry)memget(sizeof *ste);
+ if (ste == NULL)
+ panic("memget failed in define_symbol()", NULL);
+ ste->key = key;
+ ste->type = type;
+ ste->value = value;
+ ste->flags = flags;
+ ste->next = st->table[hash];
+ st->table[hash] = ste;
+ } else {
+ ns_debug(ns_log_parser, 7, "redefined symbol %s type %d",
+ key, type);
+ free_symbol(st, ste);
+ ste->key = key;
+ ste->value = value;
+ ste->flags = flags;
+ }
+}
+
+void
+undefine_symbol(symbol_table st, char *key, int type) {
+ int hash;
+ symbol_entry prev_ste, ste, next_ste;
+
+ hash = symbol_hash(key, st->size);
+ for (prev_ste = NULL, ste = st->table[hash];
+ ste != NULL;
+ prev_ste = ste, ste = ste->next)
+ if ((type == 0 || ste->type == type) &&
+ strcasecmp(ste->key, key) == 0)
+ break;
+ if (ste != NULL) {
+ free_symbol(st, ste);
+ if (prev_ste != NULL)
+ prev_ste->next = ste->next;
+ else
+ st->table[hash] = ste->next;
+ memput(ste, sizeof *ste);
+ }
+}
+
+/*
+ * Conversion Routines
+ */
+
+int
+unit_to_ulong(char *in, u_long *out) {
+ int c, units_done = 0;
+ u_long result = 0L;
+
+ INSIST(in != NULL);
+
+ for (; (c = *in) != '\0'; in++) {
+ if (units_done)
+ return (0);
+ if (isdigit(c)) {
+ result *= 10;
+ result += (c - '0');
+ } else {
+ switch (c) {
+ case 'k':
+ case 'K':
+ result *= 1024;
+ units_done = 1;
+ break;
+ case 'm':
+ case 'M':
+ result *= (1024*1024);
+ units_done = 1;
+ break;
+ case 'g':
+ case 'G':
+ result *= (1024*1024*1024);
+ units_done = 1;
+ break;
+ default:
+ return (0);
+ }
+ }
+ }
+
+ *out = result;
+ return (1);
+}
diff --git a/contrib/bind/bin/named/ns_parseutil.h b/contrib/bind/bin/named/ns_parseutil.h
new file mode 100644
index 0000000..d241bea
--- /dev/null
+++ b/contrib/bind/bin/named/ns_parseutil.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#ifndef NS_PARSEUTIL_H
+#define NS_PARSEUTIL_H
+
+/*
+ * Symbol Table
+ */
+
+#define SYMBOL_FREE_KEY 0x01
+#define SYMBOL_FREE_VALUE 0x02
+
+typedef union symbol_value {
+ void *pointer;
+ int integer;
+} symbol_value;
+
+typedef void (*free_function)(int, void *);
+
+typedef struct symbol_entry {
+ char *key;
+ int type;
+ symbol_value value;
+ unsigned int flags;
+ struct symbol_entry *next;
+} *symbol_entry;
+
+typedef struct symbol_table {
+ int size;
+ symbol_entry *table;
+ free_function free_value;
+} *symbol_table;
+
+symbol_table new_symbol_table(int, free_function);
+void free_symbol(symbol_table, symbol_entry);
+void free_symbol_table(symbol_table);
+void dprint_symbol_table(int, symbol_table);
+int lookup_symbol(symbol_table, const char *, int,
+ symbol_value *);
+void define_symbol(symbol_table, char *, int, symbol_value,
+ unsigned int);
+void undefine_symbol(symbol_table, char *, int type);
+
+/*
+ * Conversion Routines
+ */
+
+int unit_to_ulong(char *, u_long *);
+
+#endif /* !NS_PARSEUTIL_H */
diff --git a/contrib/bind/bin/named/ns_req.c b/contrib/bind/bin/named/ns_req.c
new file mode 100644
index 0000000..ee60ce4
--- /dev/null
+++ b/contrib/bind/bin/named/ns_req.c
@@ -0,0 +1,1669 @@
+#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.46 1998/03/27 00:21:03 halley Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#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 <errno.h>
+#include <fcntl.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.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 */
+};
+
+#ifndef BIND_UPDATE
+enum req_action { Finish, Refuse, Return };
+#endif
+
+static struct addinfo addinfo[NADDRECS];
+static void addname(const char *, const char *,
+ u_int16_t, u_int16_t);
+static void copyCharString(u_char **, const char *);
+
+static enum req_action req_query(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(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(HEADER *hp, u_char **cpp, u_char *eom,
+ u_char *msg,struct sockaddr_in from);
+#endif
+
+/*
+ * Process request using database; assemble and send response.
+ */
+void
+ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
+ struct sockaddr_in from, int dfd)
+{
+ HEADER *hp = (HEADER *) msg;
+ u_char *cp, *eom;
+ enum req_action action;
+ int n;
+
+#ifdef DEBUG
+ if (debug > 3) {
+ ns_debug(ns_log_packet, 3, "ns_req(from %s)", sin_ntoa(from));
+ fp_nquery(msg, msglen, log_get_stream(packet_channel));
+ }
+#endif
+
+ /*
+ * 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 ns_o_query:
+ action = req_query(hp, &cp, eom, qsp,
+ &buflen, &msglen,
+ msg, dfd, from);
+ break;
+
+ case ns_o_iquery:
+ action = req_iquery(hp, &cp, eom, &buflen, msg, from);
+ break;
+
+#ifdef BIND_NOTIFY
+ case ns_o_notify:
+ action = req_notify(hp, &cp, eom, msg, from);
+ break;
+#endif
+
+#ifdef BIND_UPDATE
+ case ns_o_update:
+ action = req_update(hp, cp, eom, msg, qsp, dfd, from);
+ break;
+#endif /* BIND_UPDATE */
+
+ default:
+ ns_debug(ns_log_default, 1,
+ "ns_req: Opcode %d not implemented", 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;
+ cp = eom;
+ /*FALLTHROUGH*/
+ case Finish:
+ /* rest of the function handles this case */
+ break;
+ default:
+ panic("ns_req: bad action variable", NULL);
+ /*NOTREACHED*/
+ }
+
+ /*
+ * apply final polish
+ */
+ hp->qr = 1; /* set Response flag */
+ hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0);
+
+ n = doaddinfo(hp, cp, buflen);
+ cp += n;
+ buflen -= n;
+
+#ifdef DEBUG
+ ns_debug(ns_log_default, 1,
+ "ns_req: answer -> %s fd=%d id=%d size=%d",
+ sin_ntoa(from), (qsp == NULL) ? dfd : qsp->s_rfd,
+ ntohs(hp->id), cp - msg);
+ if (debug >= 10)
+ fp_nquery(msg, cp - msg, log_get_stream(packet_channel));
+#endif /*DEBUG*/
+ if (qsp == NULL) {
+ if (sendto(dfd, (char*)msg, cp - msg, 0,
+ (struct sockaddr *)&from,
+ sizeof(from)) < 0) {
+ if (!haveComplained(ina_ulong(from.sin_addr),
+ (u_long)sendtoStr))
+ ns_info(ns_log_default,
+ "ns_req: sendto(%s): %s",
+ sin_ntoa(from), strerror(errno));
+ nameserIncr(from.sin_addr, nssSendtoErr);
+ }
+ nameserIncr(from.sin_addr, nssSentAns);
+ if (hp->rcode == NXDOMAIN)
+ nameserIncr(from.sin_addr, nssSentNXD);
+ if (!hp->aa)
+ nameserIncr(from.sin_addr, nssSentNaAns);
+ } else
+ writestream(qsp, msg, cp - msg);
+
+ /* Is now a safe time? */
+ if (needs_prime_cache)
+ prime_cache();
+}
+
+#ifdef BIND_NOTIFY
+int
+findZonePri(const struct zoneinfo *zp, const struct sockaddr_in from) {
+ struct in_addr ina;
+ int i;
+
+ ina = from.sin_addr;
+ for (i = 0; (u_int)i < zp->z_addrcnt; i++)
+ if (ina_equal(zp->z_addr[i], ina))
+ return (i);
+ return (-1);
+}
+
+static enum req_action
+req_notify(HEADER *hp, u_char **cpp, u_char *eom, u_char *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) {
+ ns_debug(ns_log_notify, 1,
+ "FORMERR Notify header counts wrong");
+ 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) {
+ ns_debug(ns_log_notify, 1,
+ "FORMERR Query expand name failed");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ *cpp += n;
+ if (*cpp + 2 * INT16SZ > eom) {
+ ns_debug(ns_log_notify, 1,
+ "FORMERR notify too short");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ GETSHORT(type, *cpp);
+ GETSHORT(class, *cpp);
+ ns_info(ns_log_notify, "rcvd NOTIFY(%s, %s, %s) from %s",
+ dnbuf, p_class(class), p_type(type), sin_ntoa(from));
+ /* 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) {
+ ns_info(ns_log_notify,
+ "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_slave) {
+ /* 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.
+ */
+ ns_info(ns_log_notify,
+ "NOTIFY for non-secondary name (%s), from %s",
+ dnbuf, sin_ntoa(from));
+ goto refuse;
+ }
+ if (findZonePri(&zones[zn], from) == -1) {
+ ns_info(ns_log_notify,
+ "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) {
+ ns_info(ns_log_notify,
+ "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)) {
+ ns_info(ns_log_notify,
+ "NOTIFY(SOA) for zone already xferring (%s)",
+ dnbuf);
+ goto noerror;
+ }
+ zones[zn].z_time = tt.tv_sec;
+ qserial_query(&zones[zn]);
+ sched_zone_maint(&zones[zn]);
+ 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(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
+ int *buflenp, int *msglenp, u_char *msg, int dfd,
+ struct sockaddr_in from)
+{
+ int n, class, type, count, zone, 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 zoneinfo *zp;
+ struct databuf *dp;
+
+ nameserIncr(from.sin_addr, nssRcvdQ);
+
+ nsp[0] = NULL;
+ dpp = dnptrs;
+ *dpp++ = msg;
+ *dpp = NULL;
+ /*
+ * Make gcc happy.
+ */
+ omsglen = 0;
+ omsg = NULL;
+ id = 0;
+
+ /* 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) {
+ ns_debug(ns_log_default, 1,
+ "FORMERR Query header counts wrong");
+ 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) {
+ ns_debug(ns_log_default, 1,
+ "FORMERR Query expand name failed");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ *cpp += n;
+ if (*cpp + 2 * INT16SZ > eom) {
+ ns_debug(ns_log_default, 1,
+ "FORMERR Query message length short");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ GETSHORT(type, *cpp);
+ GETSHORT(class, *cpp);
+ if (*cpp < eom) {
+ ns_debug(ns_log_default, 6,
+ "message length > received message");
+ *msglenp = *cpp - msg;
+ }
+
+ qtypeIncr(type);
+
+ /*
+ * Process query.
+ */
+ if (type == T_AXFR) {
+ /* Refuse request if not a TCP connection. */
+ if (qsp == NULL) {
+ ns_info(ns_log_default,
+ "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);
+ hp->rd = 0; /* Recursion not possible. */
+ }
+ *buflenp -= *msglenp;
+ count = 0;
+ founddata = 0;
+ dname = dnbuf;
+ cname = 0;
+
+#ifdef QRYLOG
+ if (qrylog) {
+ ns_info(ns_log_queries, "XX /%s/%s/%s",
+ inet_ntoa(from.sin_addr),
+ (dname[0] == '\0') ? "." : dname,
+ p_type(type));
+ }
+#endif /*QRYLOG*/
+
+ try_again:
+ foundname = 0;
+ ns_debug(ns_log_default, 1, "req: nlookup(%s) id %d type=%d class=%d",
+ dname, ntohs(hp->id), type, class);
+ htp = hashtab; /* lookup relative to root */
+ if ((anp = np = nlookup(dname, &htp, &fname, 0)) == NULL)
+ fname = "";
+ ns_debug(ns_log_default, 1, "req: %s '%s' as '%s' (cname=%d)",
+ np == NULL ? "missed" : "found",
+ dname, fname, cname);
+
+#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;
+ ns_debug(ns_log_default, 3,
+ "ypkludge: hit as '%s'", dname);
+ return (Finish);
+ }
+ }
+#endif /*YPKLUDGE*/
+
+ /*
+ * Begin Access Control Point
+ */
+
+ zone = DB_Z_CACHE;
+ if (np) {
+ struct namebuf *access_np;
+
+ /*
+ * Find out which zone this will be answered from. Note
+ * that we look for a zone with the same class as ours.
+ * The np that we found in the database might not be the
+ * one we asked for (i.e. dname might not equal fname). This
+ * is OK, since if a name doesn't exist, we need to go up
+ * the tree until we find the closest enclosing zone that
+ * is of the same class.
+ */
+ for (access_np = np; access_np != NULL;
+ access_np = np_parent(access_np)) {
+ dp = access_np->n_data;
+ while (dp && dp->d_class != class)
+ dp = dp->d_next;
+ if (dp != NULL) {
+ zone = dp->d_zone;
+ break;
+ }
+ }
+ }
+
+ zp = &zones[zone];
+
+ /*
+ * Are queries allowed from this host?
+ */
+ if (type != T_AXFR) {
+ ip_match_list query_acl;
+
+ if (zp->z_query_acl != NULL)
+ query_acl = zp->z_query_acl;
+ else
+ query_acl = server_options->query_acl;
+
+ if (query_acl != NULL
+ && !ip_address_allowed(query_acl, from.sin_addr)) {
+ ns_notice(ns_log_security,
+ "unapproved query from %s for \"%s\"",
+ sin_ntoa(from), *dname ? dname : ".");
+ return (Refuse);
+ }
+ } else {
+ ip_match_list transfer_acl;
+
+ /* Do they have permission to do a zone transfer? */
+
+ if (zp->z_transfer_acl != NULL)
+ transfer_acl = zp->z_transfer_acl;
+ else
+ transfer_acl = server_options->transfer_acl;
+
+ if (transfer_acl != NULL
+ && !ip_address_allowed(transfer_acl, from.sin_addr)) {
+ ns_notice(ns_log_security,
+ "unapproved AXFR from %s for \"%s\" (acl)",
+ sin_ntoa(from), *dname ? dname : ".");
+ return (Refuse);
+ }
+
+ /* Are we authoritative? */
+
+ if ((zp->z_flags & Z_AUTH) == 0) {
+ ns_notice(ns_log_security,
+ "unapproved AXFR from %s for \"%s\" (not auth)",
+ sin_ntoa(from), *dname ? dname : ".");
+ return (Refuse);
+ }
+
+ /* Is the name at a zone cut? */
+
+ if (strcasecmp(zp->z_origin, dname) != 0) {
+ ns_notice(ns_log_security,
+ "unapproved AXFR from %s for \"%s\" (not zone top)",
+ sin_ntoa(from), *dname ? dname : ".");
+ return (Refuse);
+ }
+
+ ns_info(ns_log_security, "approved AXFR from %s for \"%s\"",
+ sin_ntoa(from), *dname ? dname : ".");
+ }
+
+ /*
+ * End Access Control Point
+ */
+
+ /*
+ * Yow!
+ */
+ if (!strcasecmp(dnbuf, "VERSION.BIND") &&
+ class == C_CHAOS && type == T_TXT) {
+ u_char *tp;
+
+ hp->ancount = htons(1);
+ hp->nscount = htons(0);
+ hp->arcount = htons(0);
+ hp->rcode = NOERROR;
+ hp->aa = 1;
+ hp->ra = 0;
+ copyCharString(cpp, "VERSION"); /* Name */
+ copyCharString(cpp, "BIND");
+ *(*cpp)++ = 0x00;
+ PUTSHORT(T_TXT, *cpp); /* Type */
+ PUTSHORT(C_CHAOS, *cpp); /* Class */
+ PUTLONG(0, *cpp); /* TTL */
+ tp = *cpp; /* Temp RdLength */
+ PUTSHORT(0, *cpp);
+ copyCharString(cpp, ShortVersion);
+ PUTSHORT((*cpp) - (tp + INT16SZ), tp); /* Real RdLength */
+ *msglenp = *cpp - msg; /* Total message length */
+ return (Finish);
+ }
+
+ /*
+ * If we don't know anything about the requested name,
+ * go look for nameservers.
+ */
+ if (!np || fname != dname)
+ goto fetchns;
+
+ foundname++;
+ answers = *cpp;
+ count = *cpp - msg;
+
+ /* 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 (count) {
+ *cpp += n;
+ *buflenp -= n;
+ *msglenp += n;
+ hp->nscount = htons((u_int16_t)count);
+ }
+ if (hp->rcode == NOERROR_NODATA) {
+ /* this should not occur */
+ hp->rcode = NOERROR;
+ return (Finish);
+ }
+ }
+#endif
+ hp->rcode = NXDOMAIN;
+ /*
+ * XXX forcing AA all the time isn't right, but
+ * we have to work that way by default
+ * for compatibility with older servers.
+ */
+ if (!NS_OPTION_P(OPTION_NONAUTH_NXDOMAIN))
+ hp->aa = 1;
+ ns_debug(ns_log_default, 3, "NXDOMAIN aa = %d",
+ hp->aa);
+ return (Finish);
+ }
+ }
+
+ /*
+ * If not NXDOMAIN, the NOERROR_NODATA record might be
+ * anywhere in the chain. Have to go through the grind.
+ */
+
+ 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) {
+ ns_debug(ns_log_default, 1,
+ "T_AXFR refused: no data");
+ return (Refuse);
+ }
+ goto fetchns;
+ }
+
+ if (hp->rcode == NOERROR_NODATA) {
+ hp->rcode = NOERROR;
+#ifdef RETURNSOA
+ if (count) {
+ *cpp += n;
+ *buflenp -= n;
+ *msglenp += n;
+ hp->nscount = htons(count);
+ }
+#endif
+ founddata = 1;
+ return (Finish);
+ }
+
+ *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) {
+ ns_debug(ns_log_default, 3,
+ "resp: leaving, MAXCNAMES exceeded");
+ hp->rcode = SERVFAIL;
+ return (Finish);
+ }
+ goto try_again;
+ }
+ founddata = 1;
+ ns_debug(ns_log_default, 3,
+ "req: foundname=%d, count=%d, founddata=%d, cname=%d",
+ foundname, count, founddata, cname);
+
+ if (type == T_AXFR) {
+ ns_xfr(qsp, np, zone, class, type, hp->opcode, ntohs(hp->id));
+ return (Return);
+ }
+
+ 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).
+ */
+ free_nsp(nsp);
+ 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;
+ ns_debug(ns_log_default, 3, "req: leaving (%s, rcode %d)",
+ dname, hp->rcode);
+ if (class != C_ANY) {
+ hp->aa = 1;
+ if (np && (!foundname || !founddata)) {
+ 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 */
+ free_nsp(nsp);
+ 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*/
+ }
+ }
+ free_nsp(nsp);
+ return (Finish);
+
+ case SERVFAIL:
+ /* We're authoritative but the zone isn't loaded. */
+ if (!founddata &&
+ !(NS_OPTION_P(OPTION_FORWARD_ONLY) &&
+ server_options->fwdtab)) {
+ hp->rcode = SERVFAIL;
+ free_nsp(nsp);
+ 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 || NS_OPTION_P(OPTION_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);
+ }
+ free_nsp(nsp);
+
+ /* 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 *)memget((unsigned) *msglenp);
+ if (omsg == NULL) {
+ ns_info(ns_log_default, "ns_req: Out Of Memory");
+ hp->rcode = SERVFAIL;
+ free_nsp(nsp);
+ return (Finish);
+ }
+ id = hp->id;
+ omsglen = *msglenp;
+ memcpy(omsg, msg, omsglen);
+ n = res_mkquery(QUERY, dname, class, type,
+ NULL, 0, NULL, msg,
+ *msglenp + *buflenp);
+ if (n < 0) {
+ ns_info(ns_log_default, "res_mkquery(%s) failed",
+ dname);
+ hp->rcode = SERVFAIL;
+ free_nsp(nsp);
+ return (Finish);
+ }
+ *msglenp = n;
+ }
+ n = ns_forw(nsp, msg, *msglenp, from, qsp, dfd, &qp,
+ dname, class, type, np, 0);
+ if (n != FW_OK && cname)
+ memput(omsg, omsglen);
+ 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') {
+ ns_notice(ns_log_default,
+ "ns_req: no address for root server");
+ hp->rcode = SERVFAIL;
+ free_nsp(nsp);
+ return (Finish);
+ }
+ 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;
+ free_nsp(nsp);
+ return (Finish);
+ }
+ free_nsp(nsp);
+ return (Return);
+}
+
+static enum req_action
+req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp,
+ u_char *msg, struct sockaddr_in from)
+{
+ int dlen, alen, n, type, class, count;
+ char dnbuf[MAXDNAME], anbuf[PACKETSZ], *data, *fname;
+
+ nameserIncr(from.sin_addr, nssRcvdIQ);
+
+ if (ntohs(hp->ancount) != 1
+ || ntohs(hp->qdcount) != 0
+ || ntohs(hp->nscount) != 0
+ || ntohs(hp->arcount) != 0) {
+ ns_debug(ns_log_default, 1,
+ "FORMERR IQuery header counts wrong");
+ 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) {
+ ns_debug(ns_log_default, 1,
+ "FORMERR IQuery packet name problem");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ *cpp += n;
+ if (*cpp + 3 * INT16SZ + INT32SZ > eom) {
+ ns_debug(ns_log_default, 1,
+ "FORMERR IQuery message too short");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ GETSHORT(type, *cpp);
+ GETSHORT(class, *cpp);
+ *cpp += INT32SZ; /* ttl */
+ GETSHORT(dlen, *cpp);
+ *cpp += dlen;
+ if (*cpp != eom) {
+ ns_debug(ns_log_default, 1,
+ "FORMERR IQuery message length off");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+
+ /*
+ * not all inverse queries are handled.
+ */
+ switch (type) {
+ case T_A:
+ if (!NS_OPTION_P(OPTION_FAKE_IQUERY) || dlen != INT32SZ)
+ return (Refuse);
+ break;
+ default:
+ return (Refuse);
+ }
+ ns_debug(ns_log_default, 1,
+ "req: IQuery class %d type %d", class, type);
+
+ fname = (char *)msg + HFIXEDSZ;
+ alen = (char *)*cpp - fname;
+ if ((size_t)alen > sizeof anbuf)
+ return (Refuse);
+ memcpy(anbuf, fname, alen);
+ data = anbuf + alen - dlen;
+ *cpp = (u_char *)fname;
+ *buflenp -= HFIXEDSZ;
+ count = 0;
+
+#ifdef QRYLOG
+ if (qrylog) {
+ char tmp[sizeof "255.255.255.255"];
+
+ strcpy(tmp, inet_ntoa(from.sin_addr));
+ ns_info(ns_log_queries, "XX /%s/%s/-%s",
+ tmp, inet_ntoa(ina_get((u_char *)data)),
+ p_type(type));
+ }
+#endif /*QRYLOG*/
+
+ /*
+ * We can only get here if 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(ina_get((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++;
+
+ ns_debug(ns_log_default, 1, "req: IQuery %d records", count);
+ hp->qdcount = htons((u_int16_t)count);
+ if (alen > *buflenp) {
+ hp->tc = 1;
+ return (Finish);
+ }
+ memcpy(*cpp, anbuf, alen);
+ *cpp += alen;
+ return (Finish);
+}
+
+/*
+ * Test a datum for validity and return non-zero if it is out of date.
+ */
+int
+stale(struct databuf *dp) {
+ struct zoneinfo *zp = &zones[dp->d_zone];
+
+ switch (zp->z_type) {
+
+ case z_master:
+ 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_slave:
+ /*
+ * Check to see whether a secondary zone has expired or
+ * time warped; if so clear authority flag for zone,
+ * schedule the zone for immediate maintenance, and
+ * return true.
+ */
+ if ((int32_t)(tt.tv_sec - zp->z_lastupdate)
+ > (int32_t)zp->z_expire) {
+ ns_debug(ns_log_default, 1,
+ "stale: secondary zone %s expired",
+ zp->z_origin);
+ if (!haveComplained((u_long)zp, (u_long)stale)) {
+ ns_notice(ns_log_default,
+ "secondary zone \"%s\" expired",
+ zp->z_origin);
+ }
+ zp->z_flags &= ~Z_AUTH;
+ if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))) {
+ zp->z_time = tt.tv_sec;
+ sched_zone_maint(zp);
+ }
+ return (1);
+ }
+ if (zp->z_lastupdate > tt.tv_sec) {
+ if (!haveComplained((u_long)zp, (u_long)stale)) {
+ ns_notice(ns_log_default,
+ "secondary zone \"%s\" time warp",
+ zp->z_origin);
+ }
+ zp->z_flags &= ~Z_AUTH;
+ if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))) {
+ zp->z_time = tt.tv_sec;
+ sched_zone_maint(zp);
+ }
+ return (1);
+ }
+ return (0);
+
+ case z_hint:
+ if (dp->d_flags & DB_F_HINT ||
+ dp->d_ttl >= (u_int32_t)tt.tv_sec)
+ return (0);
+ ns_debug(ns_log_default, 3, "stale: ttl %d %ld (x%lx)",
+ dp->d_ttl, (long)(dp->d_ttl - tt.tv_sec),
+ (u_long)dp->d_flags);
+ return (1);
+
+ default:
+ /* FALLTHROUGH */ ;
+
+ }
+ panic("stale: impossible condition", NULL);
+ /* NOTREACHED */
+ return (0); /* Make gcc happy. */
+}
+
+/*
+ * Copy databuf into a resource record for replies.
+ * Return size of RR if OK, -1 if buffer is full.
+ */
+int
+make_rr(const char *name, struct databuf *dp, u_char *buf,
+ int buflen, int doadd, u_char **comp_ptrs, u_char **edp)
+{
+ u_char *cp;
+ u_char *cp1, *sp;
+ struct zoneinfo *zp;
+ int32_t n;
+ int16_t type = dp->d_type;
+ u_int32_t ttl;
+#ifdef BIND_UPDATE
+ u_int32_t serial;
+#endif
+
+ ns_debug(ns_log_default, 5,
+ "make_rr(%s, %lx, %lx, %d, %d) %d zone %d ttl %lu",
+ name, (u_long)dp, (u_long)buf,
+ buflen, doadd, dp->d_size, dp->d_zone, (u_long)dp->d_ttl);
+
+ if (dp->d_rcode
+#ifdef RETURNSOA
+ && dp->d_size == 0
+#endif
+ )
+ panic("make_rr: impossible d_rcode value", NULL);
+
+ zp = &zones[dp->d_zone];
+ /* check for outdated RR before updating comp_ptrs[] 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 */
+ }
+
+ buflen -= RRFIXEDSZ;
+ if (buflen < 0)
+ return (-1);
+#ifdef RETURNSOA
+ if (dp->d_rcode) {
+ name = (char *)dp->d_data;
+ name += strlen(name) +1;
+ name += strlen(name) +1;
+ name += 5 * INT32SZ;
+ type = T_SOA;
+ }
+#endif
+ if ((n = dn_comp(name, buf, buflen, comp_ptrs, edp)) < 0)
+ return (-1);
+ cp = buf + n;
+ buflen -= n;
+ if (buflen < 0)
+ return (-1);
+ PUTSHORT((u_int16_t)type, cp);
+ PUTSHORT((u_int16_t)dp->d_class, cp);
+ PUTLONG(ttl, cp);
+ sp = cp;
+ cp += INT16SZ;
+ switch (type) {
+ case T_CNAME:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ n = dn_comp((char *)dp->d_data, cp, buflen, comp_ptrs, 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, comp_ptrs, edp);
+ if (n < 0)
+ return (-1);
+ PUTSHORT((u_int16_t)n, sp);
+ cp += n;
+ if (doadd)
+ addname((char*)dp->d_data, name,
+ 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, comp_ptrs, edp);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ buflen -= type == T_SOA ? n + 5 * INT32SZ : n;
+ if (buflen < 0)
+ return (-1);
+ cp1 += strlen((char *)cp1) + 1;
+ n = dn_comp((char *)cp1, cp, buflen, comp_ptrs, edp);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ if (type == T_SOA) {
+ cp1 += strlen((char *)cp1) + 1;
+#ifdef BIND_UPDATE
+ if (zp->z_flags & Z_NEED_SOAUPDATE)
+ if (incr_serial(zp) < 0)
+ ns_error(ns_log_default,
+ "error updating serial number for %s from %d",
+ zp->z_origin, zp->z_serial);
+#endif
+ n = 5 * INT32SZ;
+ memcpy(cp, cp1, n);
+ cp += n;
+ }
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ PUTSHORT((u_int16_t)n, sp);
+ break;
+
+ case T_NAPTR:
+ /* cp1 == our data/ cp == data of RR */
+ cp1 = dp->d_data;
+
+ /* copy order */
+ buflen -= INT16SZ;
+ if (buflen < 0)
+ return (-1);
+ memcpy(cp, cp1, INT16SZ);
+ cp += INT16SZ;
+ cp1 += INT16SZ;
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ ns_debug(ns_log_default, 1, "current size n = %u", n);
+
+ /* copy preference */
+ buflen -= INT16SZ;
+ if (buflen < 0)
+ return (-1);
+ memcpy(cp, cp1, INT16SZ);
+ cp += INT16SZ;
+ cp1 += INT16SZ;
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ ns_debug(ns_log_default, 1, "current size n = %u", n);
+
+ /* Flags */
+ n = *cp1++;
+ ns_debug(ns_log_default, 1, "size of n at flags = %d", n);
+ buflen -= n + 1;
+ if (buflen < 0)
+ return (-1);
+ *cp++ = n;
+ memcpy(cp, cp1, n);
+ cp += n;
+ cp1 += n;
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ ns_debug(ns_log_default, 1, "current size n = %u", n);
+
+ /* Service */
+ n = *cp1++;
+ buflen -= n + 1;
+ if (buflen < 0)
+ return (-1);
+ *cp++ = n;
+ memcpy(cp, cp1, n);
+ cp += n;
+ cp1 += n;
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ ns_debug(ns_log_default, 1, "current size n = %u", n);
+
+ /* Regexp */
+ n = *cp1++;
+ buflen -= n + 1;
+ if (buflen < 0)
+ return (-1);
+ *cp++ = n;
+ memcpy(cp, cp1, n);
+ cp += n;
+ cp1 += n;
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ ns_debug(ns_log_default, 1, "current size n = %u", n);
+
+ /* Replacement */
+ ns_debug(ns_log_default, 1, "Replacement = %s", cp1);
+ n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp);
+ ns_debug(ns_log_default, 1, "dn_comp's n = %u", n);
+ if (n < 0)
+ return (-1);
+ cp += n;
+
+ /* save data length */
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ ns_debug(ns_log_default, 1, "saved size n = %u", n);
+ PUTSHORT((u_int16_t)n, sp);
+
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ case T_SRV:
+ /* cp1 == our data/ cp == data of RR */
+ cp1 = dp->d_data;
+
+ if ((buflen -= INT16SZ) < 0)
+ return (-1);
+
+ /* copy preference */
+ memcpy(cp, cp1, INT16SZ);
+ cp += INT16SZ;
+ cp1 += INT16SZ;
+
+ if (type == T_SRV) {
+ buflen -= INT16SZ*2;
+ if (buflen < 0)
+ return (-1);
+ memcpy(cp, cp1, INT16SZ*2);
+ cp += INT16SZ*2;
+ cp1 += INT16SZ*2;
+ }
+
+ n = dn_comp((char *)cp1, cp, buflen, comp_ptrs, 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, type, dp->d_class);
+ break;
+
+ case T_PX:
+ cp1 = dp->d_data;
+
+ if ((buflen -= INT16SZ) < 0)
+ return (-1);
+
+ /* copy preference */
+ memcpy(cp, cp1, INT16SZ);
+ cp += INT16SZ;
+ cp1 += INT16SZ;
+
+ n = dn_comp((char *)cp1, cp, buflen, comp_ptrs, edp);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ buflen -= n;
+ cp1 += strlen((char *)cp1) + 1;
+ n = dn_comp((char *)cp1, cp, buflen, comp_ptrs, 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;
+
+ case T_SIG:
+ /* cp1 == our data; cp == data of target RR */
+ cp1 = dp->d_data;
+
+ /* first just copy over the type_covered, algorithm, */
+ /* labels, orig ttl, two timestamps, and the footprint */
+ if ((dp->d_size - 18) > buflen)
+ return (-1); /* out of room! */
+ memcpy(cp, cp1, 18);
+ cp += 18;
+ cp1 += 18;
+ buflen -= 18;
+
+ /* then the signer's name */
+ n = dn_comp((char *)cp1, cp, buflen, NULL, NULL);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ buflen -= n;
+ cp1 += strlen((char*)cp1)+1;
+
+ /* finally, we copy over the variable-length signature */
+ n = dp->d_size - (u_int16_t)((cp1 - dp->d_data));
+ if (n > buflen)
+ return (-1); /* out of room! */
+ memcpy(cp, cp1, n);
+ cp += n;
+
+ /* save data length & return */
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ PUTSHORT((u_int16_t)n, sp);
+ break;
+
+ default:
+ if (dp->d_size > buflen)
+ return (-1);
+ memcpy(cp, dp->d_data, dp->d_size);
+ PUTSHORT((u_int16_t)dp->d_size, sp);
+ cp += dp->d_size;
+ }
+ return (cp - buf);
+}
+
+static void
+addname(const char *dname, const char *rname,
+ u_int16_t rtype, u_int16_t class)
+{
+ struct addinfo *ap;
+ 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, 1);
+ ap->a_rname = savestr(rname, 1);
+ ap->a_rtype = rtype;
+ ap->a_class = class;
+ }
+}
+
+/*
+ * Lookup addresses for names in addinfo and put into the message's
+ * additional section.
+ */
+int
+doaddinfo(HEADER *hp, u_char *msg, int msglen) {
+ struct namebuf *np;
+ struct databuf *dp;
+ struct addinfo *ap;
+ u_char *cp;
+ struct hashbuf *htp;
+ const char *fname;
+ int n, count;
+
+ if (!addcount)
+ return (0);
+
+ ns_debug(ns_log_default, 3, "doaddinfo() addcount = %d", addcount);
+
+ if (hp->tc) {
+ ns_debug(ns_log_default, 4,
+ "doaddinfo(): tc already set, bailing");
+ return (0);
+ }
+
+ count = 0;
+ cp = msg;
+ for (ap = addinfo; --addcount >= 0; ap++) {
+ int foundany = 0,
+ foundcname = 0,
+ save_count = count,
+ save_msglen = msglen;
+ u_char *save_cp = cp;
+
+ ns_debug(ns_log_default, 3,
+ "do additional \"%s\" (from \"%s\")",
+ 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;
+ ns_debug(ns_log_default, 3, "found it");
+ /* look for the data */
+ delete_stale(np);
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (dp->d_rcode)
+ continue;
+ 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++;
+ /*
+ * Should be smart and eliminate duplicate
+ * data here. XXX
+ */
+ if ((n = make_rr(ap->a_dname, dp, cp, msglen, 0,
+ dnptrs, dnptrs_end)) < 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
+ */
+ ns_debug(ns_log_default, 5,
+ "addinfo: not enough room, remaining msglen = %d",
+ save_msglen);
+ cp = save_cp;
+ msglen = save_msglen;
+ count = save_count;
+ break;
+ }
+ ns_debug(ns_log_default, 5,
+ "addinfo: adding address data n = %d", n);
+ cp += n;
+ msglen -= n;
+ count++;
+ }
+ next_rr:
+ if (!NS_OPTION_P(OPTION_NOFETCHGLUE) &&
+ !foundcname && !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(nhash(ap->a_dname),
+ nhash(ap->a_rname))) {
+ ns_info(ns_log_cname,
+ "\"%s %s %s\" points to a CNAME (%s)",
+ ap->a_rname, p_class(ap->a_class),
+ p_type(ap->a_rtype), ap->a_dname);
+ }
+ }
+ freestr(ap->a_dname);
+ freestr(ap->a_rname);
+ }
+ hp->arcount = htons((u_int16_t)count);
+ return (cp - msg);
+}
+
+int
+doaddauth(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)) {
+ ns_debug(ns_log_default, 1,
+ "doaddauth: can't add stale '%s' (%d)",
+ dnbuf, buflen);
+ return (0);
+ }
+ n = make_rr(dnbuf, dp, cp, buflen, 1, dnptrs, dnptrs_end);
+ if (n <= 0) {
+ ns_debug(ns_log_default, 1,
+ "doaddauth: can't add oversize '%s' (%d) (n=%d)",
+ dnbuf, buflen, n);
+ if (n < 0) {
+ hp->tc = 1;
+ }
+ return (0);
+ }
+ hp->nscount = htons(ntohs(hp->nscount) + 1);
+ return (n);
+}
+
+void
+free_addinfo() {
+ struct addinfo *ap;
+
+ for (ap = addinfo; --addcount >= 0; ap++) {
+ freestr(ap->a_dname);
+ freestr(ap->a_rname);
+ }
+ addcount = 0;
+}
+
+void
+free_nsp(struct databuf **nsp) {
+ while (*nsp) {
+ DRCNTDEC(*nsp);
+ if ((*nsp)->d_rcnt)
+ ns_debug(ns_log_default, 3, "free_nsp: %s rcnt %d",
+ (*nsp)->d_data, (*nsp)->d_rcnt);
+ else {
+ ns_debug(ns_log_default, 3,
+ "free_nsp: %s rcnt %d delayed",
+ (*nsp)->d_data, (*nsp)->d_rcnt);
+ db_freedata(*nsp); /* delayed free */
+ }
+ *nsp++ = NULL;
+ }
+}
+
+static void
+copyCharString(u_char **dst, const char *src) {
+ size_t len = strlen(src) & 0xff;
+ *(*dst)++ = (u_char) len;
+ memcpy(*dst, src, len);
+ *dst += len;
+}
diff --git a/contrib/bind/bin/named/ns_resp.c b/contrib/bind/bin/named/ns_resp.c
new file mode 100644
index 0000000..012f89e
--- /dev/null
+++ b/contrib/bind/bin/named/ns_resp.c
@@ -0,0 +1,3298 @@
+#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.56 1998/03/16 19:40:07 halley Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#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 <errno.h>
+#include <limits.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+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",
+ wrongQuestion[] = "answer to wrong question",
+ danglingCname[] = "dangling CNAME pointer";
+
+struct db_list {
+ struct db_list *db_next;
+ struct databuf *db_dp;
+};
+
+struct flush_set {
+ char * fs_name;
+ int fs_type;
+ int fs_class;
+ u_int fs_cred;
+ struct db_list *fs_list;
+ struct db_list *fs_last;
+};
+
+static void rrsetadd(struct flush_set *, const char *,
+ struct databuf *),
+ rrsetupdate(struct flush_set *, int flags,
+ struct sockaddr_in),
+ flushrrset(struct flush_set *, struct sockaddr_in),
+ free_flushset(struct flush_set *, int);
+static int rrsetcmp(char *, struct db_list *),
+ check_root(void),
+ check_ns(void),
+ rrextract(u_char *, int, u_char *,
+ struct databuf **, char *, int,
+ struct sockaddr_in, char **);
+static void sysnotify_slaves(const char *, const char *,
+ int, int, int *, int *);
+static void sysnotify_ns(const char *, const char *,
+ int, int, int *, int *);
+static void add_related_additional(char *);
+static void free_related_additional(void);
+static int related_additional(char *);
+static void freestr_maybe(char **);
+
+#define MAX_RELATED 100
+
+static int num_related = 0;
+static char *related[MAX_RELATED];
+
+static char *
+learntFrom(struct qinfo *qp, struct sockaddr_in *server) {
+ static char *buf = NULL;
+ char *a, *ns, *na;
+ struct databuf *db;
+ int i;
+
+ a = ns = na = "<Not Available>";
+
+ for (i = 0; (u_int)i < qp->q_naddr; i++) {
+ if (ina_equal(qp->q_addr[i].ns_addr.sin_addr,
+ server->sin_addr)) {
+ db = qp->q_addr[i].ns;
+ if (db != NULL) {
+ if (NS_OPTION_P(OPTION_HOSTSTATS)) {
+ char nsbuf[20];
+
+ if (db->d_ns != NULL) {
+ strcpy(nsbuf,
+ inet_ntoa(db->d_ns->addr));
+ ns = nsbuf;
+ } else {
+ ns = zones[db->d_zone]
+ .z_origin;
+ }
+ }
+ if (db->d_rcode == 0)
+ na = (char*)qp->q_addr[i].ns->d_data;
+ }
+
+ if (NS_OPTION_P(OPTION_HOSTSTATS)) {
+ char abuf[20];
+
+ db = qp->q_addr[i].nsdata;
+ if (db != NULL) {
+ if (db->d_ns != NULL) {
+ strcpy(abuf,
+ inet_ntoa(db->d_ns->addr));
+ a = abuf;
+ } else {
+ a = zones[db->d_zone].z_origin;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (a == ns && ns == na) /* all "UNKNOWN" */
+ return (NULL);
+
+ if (*a == '\0')
+ a = "\".\"";
+ if (*ns == '\0')
+ ns = "\".\"";
+ if (*na == '\0')
+ na = "\".\"";
+
+ if (NS_OPTION_P(OPTION_HOSTSTATS)) {
+ static const char fmt[] = " '%s': learnt (A=%s,NS=%s)";
+
+ buf = newstr(sizeof fmt + strlen(na) + strlen(a) + strlen(ns),
+ 0);
+ if (buf == NULL)
+ return (NULL);
+ sprintf(buf, fmt, na, a, ns);
+ } else {
+ static const char fmt[] = " '%s'";
+
+ buf = newstr(sizeof fmt + strlen(na), 0);
+ if (buf == NULL)
+ return (NULL);
+ sprintf(buf, fmt, na);
+ }
+
+ return (buf);
+}
+
+void
+ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
+ struct qinfo *qp;
+ HEADER *hp;
+ struct qserv *qs;
+ struct databuf *ns, *ns2;
+ u_char *cp;
+ u_char *eom = msg + msglen;
+ struct flush_set *flushset = NULL;
+ int flushset_size = 0;
+ struct sockaddr_in *nsa;
+ struct databuf *nsp[NSMAX];
+ int i, c, n, qdcount, ancount, aucount, nscount, arcount, arfirst;
+ u_int qtype, qclass;
+ int restart; /* flag for processing cname response */
+ int validanswer, dbflags;
+ int cname, lastwascname, externalcname;
+ int count, founddata, foundname;
+ int buflen;
+ int newmsglen;
+ char name[MAXDNAME], qname[MAXDNAME], aname[MAXDNAME];
+ char msgbuf[MAXDNAME];
+ char *dname, tmpdomain[MAXDNAME];
+ 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 fwdinfo *fwd;
+ struct databuf *dp;
+ int forcecmsg = 0;
+ char *tname = NULL;
+
+ nameserIncr(from.sin_addr, nssRcvdR);
+ nsp[0] = NULL;
+ hp = (HEADER *) msg;
+ if ((qp = qfindid(hp->id)) == NULL ) {
+ ns_debug(ns_log_default, 1, "DUP? dropped (id %d)",
+ ntohs(hp->id));
+ nameserIncr(from.sin_addr, nssRcvdDupR);
+ return;
+ }
+
+ ns_debug(ns_log_default, 2, "Response (%s %s %s) nsid=%d id=%d",
+ (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;
+ if (cp + 2 * INT16SZ > eom) {
+ formerrmsg = outofDataQuery;
+ goto formerr;
+ }
+ GETSHORT(qtype, cp);
+ GETSHORT(qclass, cp);
+ if (!ns_nameok(qname, qclass, NULL, response_trans,
+ ns_ownercontext(qtype, response_trans),
+ qname, from.sin_addr)) {
+ formerrmsg = badNameFound;
+ goto refused;
+ }
+ 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;
+ }
+ if (strcasecmp(qp->q_name, qname) != 0 ||
+ qp->q_class != qclass ||
+ qp->q_type != qtype) {
+ formerrmsg = wrongQuestion;
+ goto formerr;
+ }
+ } else {
+ strcpy(qname, qp->q_name);
+ qclass = qp->q_class;
+ qtype = qp->q_type;
+ }
+
+ /* 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
+ )) {
+ ns_debug(ns_log_default, 2,
+ "resp: error (ret %d, op %d), dropped",
+ hp->rcode, hp->opcode);
+ switch (hp->rcode) {
+ case SERVFAIL:
+ nameserIncr(from.sin_addr, nssRcvdFail);
+ break;
+ case FORMERR:
+ nameserIncr(from.sin_addr, nssRcvdFErr);
+ break;
+ default:
+ nameserIncr(from.sin_addr, nssRcvdErr);
+ break;
+ }
+ /* mark server as bad */
+ if (!qp->q_fwd)
+ for (i = 0; i < (int)qp->q_naddr; i++)
+ if (ina_equal(qp->q_addr[i].ns_addr.sin_addr,
+ from.sin_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 ||
+ ina_equal(qp->q_addr[qp->q_curaddr].ns_addr.sin_addr,
+ from.sin_addr))
+ retry(qp);
+ return;
+ }
+
+ if (qdcount != 1) {
+ /* We don't generate or forward these (yet). */
+ formerrmsg = notSingleQuery;
+ goto formerr;
+ }
+
+ /*
+ * 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.
+ * XXX - should put this in STATS somewhere.
+ */
+ for (fwd = server_options->fwdtab; fwd; fwd = fwd->next)
+ if (ina_equal(fwd->fwdaddr.sin_addr, from.sin_addr))
+ 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 == NULL) {
+ struct timeval *stp;
+
+ for (n = 0, qs = qp->q_addr;
+ (u_int)n < qp->q_naddr;
+ n++, qs++)
+ if (ina_equal(qs->ns_addr.sin_addr, from.sin_addr))
+ break;
+ if ((u_int)n >= qp->q_naddr) {
+ if (!haveComplained(ina_ulong(from.sin_addr),
+ (u_long)"unexpected source")) {
+ ns_info(ns_log_default,
+ "Response from unexpected source (%s)",
+ sin_ntoa(from));
+ }
+ /*
+ * 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?
+ */
+ /* 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);
+ }
+
+ ns_debug(ns_log_default, 3,
+ "stime %lu/%lu now %lu/%lu rtt %ld",
+ (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) {
+ u_long t;
+
+ if (ns->d_nstime == 0)
+ t = rtrip;
+ else
+ t = ns->d_nstime * ALPHA
+ +
+ (1 - ALPHA) * rtrip;
+ if (t > 65535)
+ t = 65535;
+ ns->d_nstime = (u_int16_t)t;
+ }
+
+ /*
+ * 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;
+ ns_debug(ns_log_default, 2,
+ "NS #%d addr %s used, rtt %d",
+ 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++) {
+ u_long t;
+
+ 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)
+ t = (rtrip * BETA);
+ else
+ t = ns2->d_nstime * BETA
+ +
+ (1 - ALPHA) * rtrip;
+ } else
+ t = ns2->d_nstime * GAMMA;
+ if (t > 65535)
+ t = 65535;
+ ns2->d_nstime = (u_int16_t)t;
+ ns_debug(ns_log_default, 2, "NS #%d %s rtt now %d", 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
+
+ /*
+ * Non-authoritative, no answer, no error, with referral.
+ */
+ if (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, log_get_stream(packet_channel));
+#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;
+ if (tp + 2 * INT16SZ > eom) {
+ formerrmsg = outofDataAuth;
+ goto formerr;
+ }
+ GETSHORT(type, tp);
+ GETSHORT(class, tp);
+ if (!ns_nameok(name, class, NULL, response_trans,
+ ns_ownercontext(type, response_trans),
+ name, from.sin_addr)) {
+ formerrmsg = badNameFound;
+ goto refused;
+ }
+
+ /*
+ * 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.sin_addr, nssRcvdLDel);
+ /* mark server as bad */
+ if (!qp->q_fwd)
+ for (i = 0; i < (int)qp->q_naddr; i++)
+ if (ina_equal(qp->q_addr[i].ns_addr.sin_addr,
+ from.sin_addr))
+ qp->q_addr[i].nretry = MAXRETRY;
+ if (class == C_IN &&
+ !haveComplained(ina_ulong(from.sin_addr),
+ nhash(qp->q_domain))) {
+ char *learnt_from = learntFrom(qp, &from);
+
+ ns_info(ns_log_lame_servers,
+ "Lame server on '%s' (in '%s'?): %s%s",
+ qname, qp->q_domain,
+ sin_ntoa(from),
+ (learnt_from == NULL) ? "" :
+ learnt_from);
+ if (learnt_from != NULL)
+ freestr(learnt_from);
+ }
+
+ /* XXX - doesn't handle responses sent from the wrong
+ * interface on a multihomed server
+ */
+ if (qp->q_fwd ||
+ ina_equal(qp->q_addr[qp->q_curaddr].ns_addr.sin_addr,
+ from.sin_addr))
+ retry(qp);
+ return;
+ }
+ }
+
+ 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_int type, class, dlen;
+ u_int32_t serial;
+ u_char *tp = cp;
+ u_char *rdatap;
+
+ n = dn_expand(msg, eom, tp, name, sizeof name);
+ if (n < 0) {
+ formerrmsg = expandFailedAnswer;
+ goto formerr;
+ }
+ tp += n; /* name */
+ if (tp + 3 * INT16SZ + INT32SZ > eom) {
+ formerrmsg = outofDataAnswer;
+ goto formerr;
+ }
+ GETSHORT(type, tp); /* type */
+ GETSHORT(class, tp); /* class */
+ tp += INT32SZ; /* ttl */
+ GETSHORT(dlen, tp); /* dlen */
+ rdatap = tp; /* start of rdata */
+ if (!ns_nameok(name, class, NULL, response_trans,
+ ns_ownercontext(type, response_trans),
+ name, from.sin_addr)) {
+ formerrmsg = badNameFound;
+ goto refused;
+ }
+ 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 (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 */
+ if (tp + 5 * INT32SZ > eom) {
+ formerrmsg = dlenUnderrunAnswer;
+ goto formerr;
+ }
+ GETLONG(serial, tp);
+ tp += 4 * INT32SZ; /* Skip rest of SOA. */
+ if ((u_int)(tp - rdatap) != dlen) {
+ formerrmsg = dlenOverrunAnswer;
+ goto formerr;
+ }
+
+ qserial_answer(qp, serial, from);
+ qremove(qp);
+ } else {
+ retry(qp);
+ }
+ return;
+ }
+
+ /*
+ * Add the info received in the response to the data base.
+ */
+ arfirst = ancount + aucount;
+ c = arfirst + 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;
+
+ 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 */
+ }
+
+ /* retry using tcp provided this was not a tcp query */
+ if (!(qp->q_flags & Q_USEVC)) {
+ qp->q_flags |= Q_USEVC;
+ unsched(qp);
+ schedretry(qp, 60);
+ if (tcp_send(qp) != NOERROR)
+ /*
+ * We're probably in trouble if tcp_send
+ * failed, but we'll try to press on because
+ * there isn't anything else to do.
+ */
+ retry(qp);
+ return;
+ } else if (!qsp) {
+ /* outstanding udp response */
+ return;
+ }
+
+ /* XXX truncated tcp response */
+ ns_error(ns_log_default,
+ "ns_resp: TCP truncated: \"%s\" %s %s",
+ qname, p_class(qclass), p_type(qtype));
+ /* mark this server as bad */
+ if (!qp->q_fwd)
+ for (i = 0; i < (int)qp->q_naddr; i++)
+ if (ina_equal(qp->q_addr[i].ns_addr.sin_addr,
+ from.sin_addr))
+ qp->q_addr[i].nretry = MAXRETRY;
+
+ /* try another server, it may have a bigger write buffer */
+ retry(qp);
+ return;
+ }
+
+ tp = cp;
+
+ restart = 0;
+ validanswer = 0;
+ nscount = 0;
+ cname = 0;
+ lastwascname = 0;
+ externalcname = 0;
+ strcpy(aname, qname);
+
+ if (count) {
+ /* allocate 1 extra record for end of set detection */
+ flushset_size = (count + 1) * sizeof *flushset;
+ flushset = memget(flushset_size);
+ if (flushset == NULL)
+ panic("flushset: out of memory", NULL);
+ memset(flushset, 0, flushset_size);
+ } else
+ flushset = NULL;
+
+ for (i = 0; i < count; i++) {
+ struct databuf *dp;
+ int type;
+
+ freestr_maybe(&tname);
+ if (cp >= eom) {
+ free_related_additional();
+ if (flushset != NULL)
+ free_flushset(flushset, flushset_size);
+ formerrmsg = outofDataFinal;
+ goto formerr;
+ }
+ n = rrextract(msg, msglen, cp, &dp, name, sizeof name, from,
+ &tname);
+ if (n < 0) {
+ free_related_additional();
+ freestr_maybe(&tname);
+ if (flushset != NULL)
+ free_flushset(flushset, flushset_size);
+ formerrmsg = outofDataFinal;
+ if (hp->rcode == REFUSED)
+ goto refused;
+ else
+ goto formerr;
+ }
+ cp += n;
+ if (!dp)
+ continue;
+ type = dp->d_type;
+ if (i < ancount) {
+ /* Answer section. */
+ if (externalcname || strcasecmp(name, aname) != 0) {
+ if (!externalcname)
+ ns_info(ns_log_resp_checks,
+ "wrong ans. name (%s != %s)",
+ name[0] ? name : ".",
+ aname[0] ? aname : ".");
+ else
+ ns_debug(ns_log_resp_checks, 3,
+ "ignoring answer '%s' after external cname",
+ name);
+ db_freedata(dp);
+ continue;
+ }
+ if (type == T_CNAME &&
+ qtype != T_CNAME && qtype != T_ANY) {
+ strcpy(aname, (char *)dp->d_data);
+ if (!samedomain(aname, qp->q_domain))
+ externalcname = 1;
+ cname++;
+ lastwascname = 1;
+ } else {
+ validanswer = 1;
+ lastwascname = 0;
+ }
+
+ if (tname != NULL) {
+ add_related_additional(tname);
+ tname = NULL;
+ }
+
+ dp->d_cred = (hp->aa && !strcasecmp(name, qname))
+ ? DB_C_AUTH
+ : DB_C_ANSWER;
+ } else {
+ /* After answer section. */
+ if (lastwascname) {
+ ns_debug(ns_log_resp_checks, 3,
+ "last was cname, ignoring auth. and add.");
+ db_freedata(dp);
+ break;
+ }
+ if (i < arfirst) {
+ /* Authority section. */
+ switch (type) {
+ case T_NS:
+ case T_SOA:
+ if (!samedomain(aname, name)){
+ ns_info(ns_log_resp_checks,
+ "bad referral (%s !< %s)",
+ aname[0] ? aname : ".",
+ name[0] ? name : ".");
+ db_freedata(dp);
+ continue;
+ } else if (!samedomain(name,
+ qp->q_domain)) {
+ if (!externalcname)
+ ns_info(ns_log_resp_checks,
+ "bad referral (%s !< %s)",
+ name[0] ? name : ".",
+ qp->q_domain[0] ?
+ qp->q_domain : ".");
+ db_freedata(dp);
+ continue;
+ }
+ if (type == T_NS) {
+ nscount++;
+ add_related_additional(tname);
+ tname = NULL;
+ }
+ break;
+ case T_NXT:
+ /* XXX check */
+ break;
+ case T_SIG:
+ /* XXX check that it relates to an
+ NS or SOA or NXT */
+ break;
+ default:
+ ns_info(ns_log_resp_checks,
+ "invalid RR type '%s' in authority section (name = '%s') from %s",
+ p_type(type), name,
+ sin_ntoa(from));
+ db_freedata(dp);
+ continue;
+ }
+ } else {
+ /* Additional section. */
+ switch (type) {
+ case T_A:
+ case T_AAAA:
+ if (externalcname ||
+ !samedomain(name, qp->q_domain)) {
+ ns_debug(ns_log_resp_checks, 3,
+ "ignoring additional info '%s' type %s",
+ name, p_type(type));
+ db_freedata(dp);
+ continue;
+ }
+ if (!related_additional(name)) {
+ ns_info(ns_log_resp_checks,
+ "unrelated additional info '%s' type %s from %s",
+ name, p_type(type),
+ sin_ntoa(from));
+ db_freedata(dp);
+ continue;
+ }
+ break;
+ case T_KEY:
+ /* XXX check? */
+ break;
+ case T_SIG:
+ /*
+ * XXX a SIG RR should relate
+ * to some other RR in this section,
+ * although if it's the last RR
+ * it might be a transaction signature.
+ */
+ break;
+ default:
+ ns_info(ns_log_resp_checks,
+ "invalid RR type '%s' in additional section (name = '%s') from %s",
+ p_type(type), name,
+ sin_ntoa(from));
+ db_freedata(dp);
+ continue;
+ }
+ }
+ dp->d_cred = (qp->q_flags & Q_PRIMING)
+ ? DB_C_ANSWER
+ : DB_C_ADDITIONAL;
+ }
+ rrsetadd(flushset, name, dp);
+ }
+ free_related_additional();
+ freestr_maybe(&tname);
+ if (flushset != NULL) {
+ rrsetupdate(flushset, dbflags, from);
+ free_flushset(flushset, flushset_size);
+ }
+ if (lastwascname && !externalcname)
+ ns_info(ns_log_cname, "%s (%s)", danglingCname, aname);
+
+ if (cp > eom) {
+ formerrmsg = outofDataAFinal;
+ goto formerr;
+ }
+
+ if ((qp->q_flags & Q_SYSTEM) && ancount) {
+ if ((qp->q_flags & Q_PRIMING) && !check_root()) {
+ /* mark server as bad */
+ if (!qp->q_fwd)
+ for (i = 0; i < (int)qp->q_naddr; i++)
+ if (ina_equal(qp->q_addr[i].ns_addr.sin_addr,
+ from.sin_addr))
+ qp->q_addr[i].nretry = MAXRETRY;
+ /* XXX - doesn't handle responses sent from
+ * the wronginterface on a multihomed server
+ */
+ if (qp->q_fwd ||
+ qp->q_addr[qp->q_curaddr].ns_addr.sin_addr.s_addr
+ == from.sin_addr.s_addr)
+ retry(qp);
+ return;
+ }
+ ns_debug(ns_log_default, 3,
+ "resp: leaving, SYSQUERY ancount %d", 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, ns_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;
+ }
+
+ /*
+ * 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)) {
+ ns_debug(ns_log_default, 3,
+ "resp: got as much answer as there is");
+ goto return_msg;
+ }
+
+ /*
+ * We might want to cache this negative answer.
+ *
+ * if ancount != 0 and rcode == NOERROR we cannot determine if the
+ * CNAME chain has been processed to completion or not, so just
+ * restart the query. DNS needs a NODATA return code!
+ */
+ if (((hp->rcode == NXDOMAIN) && (cname == ancount)) ||
+ ((hp->rcode == NOERROR) && (ancount == 0) && (nscount == 0)))
+ {
+ cache_n_resp(msg, msglen, from);
+
+ if (!qp->q_cmsglen) {
+ ns_debug(ns_log_default, 3,
+ "resp: leaving NO: auth = %d", hp->aa);
+ goto return_msg;
+ }
+ forcecmsg = 1;
+ }
+
+ /*
+ * All messages in here need further processing. i.e. they
+ * are either CNAMEs or we got referred again.
+ */
+ count = 0;
+ founddata = 0;
+ dname = name;
+ /*
+ * 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 ((forcecmsg && qp->q_cmsglen) ||
+ ((!restart || !cname) && qp->q_cmsglen && ancount)) {
+ ns_debug(ns_log_default, 1, "Cname second pass");
+ newmsglen = MIN(PACKETSZ, qp->q_cmsglen);
+ memcpy(newmsg, qp->q_cmsg, newmsglen);
+ } else {
+ newmsglen = MIN(PACKETSZ, msglen);
+ memcpy(newmsg, msg, newmsglen);
+ }
+ hp = (HEADER *) newmsg;
+ hp->ancount = htons(0);
+ hp->nscount = htons(0);
+ hp->arcount = htons(0);
+ hp->rcode = NOERROR;
+ 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) {
+ ns_debug(ns_log_default, 1, "dn_expand failed");
+ goto servfail;
+ }
+ if (!res_dnok(dname)) {
+ ns_debug(ns_log_default, 1, "bad name (%s)", dname);
+ goto servfail;
+ }
+ cp += n + QFIXEDSZ;
+ buflen = sizeof(newmsg) - (cp - newmsg);
+
+ cname = 0;
+
+ try_again:
+ ns_debug(ns_log_default, 1, "resp: nlookup(%s) qtype=%d", dname,
+ qtype);
+ foundname = 0;
+ fname = "";
+ htp = hashtab; /* lookup relative to root */
+ np = nlookup(dname, &htp, &fname, 0);
+ ns_debug(ns_log_default, 1, "resp: %s '%s' as '%s' (cname=%d)",
+ np == NULL ? "missed" : "found", dname, fname, cname);
+ if (np == NULL || fname != dname)
+ goto fetch_ns;
+
+ foundname++;
+ count = cp - newmsg;
+ /*
+ * Look for NXDOMAIN record.
+ */
+ for (dp = np->n_data; dp; dp = dp->d_next) {
+ if (!stale(dp) && (dp->d_rcode == NXDOMAIN) &&
+ (dp->d_class == (int)qclass)) {
+#ifdef RETURNSOA
+ n = finddata(np, qclass, T_SOA, hp, &dname,
+ &buflen, &count);
+ if ( n != 0) {
+ if (count) {
+ cp += n;
+ buflen -= n;
+ newmsglen += n;
+ hp->nscount = htons((u_int16_t)count);
+ }
+ if (hp->rcode == NOERROR_NODATA) {
+ hp->rcode = NOERROR;
+ goto return_newmsg;
+ }
+ }
+#endif
+ hp->rcode = NXDOMAIN;
+ /*
+ * XXX forcing AA all the time isn't right, but
+ * we have to work that way by default
+ * for compatibility with older servers.
+ */
+ if (!NS_OPTION_P(OPTION_NONAUTH_NXDOMAIN))
+ hp->aa = 1;
+ ns_debug(ns_log_default, 3, "resp: NXDOMAIN aa = %d",
+ hp->aa);
+ goto return_newmsg;
+ }
+ }
+ n = finddata(np, qclass, qtype, hp, &dname, &buflen, &count);
+ if (n == 0)
+ goto fetch_ns; /* NO data available */
+ if (hp->rcode) {
+ if (hp->rcode == NOERROR_NODATA)
+ hp->rcode = NOERROR;
+#ifdef RETURNSOA
+ if (count) {
+ cp += n;
+ buflen -= n;
+ hp->nscount = htons((u_int16_t)count);
+ }
+#endif
+ goto return_newmsg;
+ }
+ 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;
+
+ ns_debug(ns_log_default, 3,
+ "resp: foundname=%d, count=%d, founddata=%d, cname=%d",
+ 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).
+ */
+ free_nsp(nsp);
+ switch (findns(&np, qclass, nsp, &count, 0)) {
+ case NXDOMAIN: /* shouldn't happen */
+ ns_debug(ns_log_default, 3, "req: leaving (%s, rcode %d)",
+ dname, hp->rcode);
+ if (!foundname)
+ hp->rcode = NXDOMAIN;
+ if (qclass != C_ANY) {
+ hp->aa = 1;
+ if (np && (!foundname || !founddata)) {
+ 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) {
+ ns_debug(ns_log_default, 1,
+ "resp: MAXQUERIES exceeded (%s %s %s)",
+ dname, p_class(qclass), p_type(qtype));
+ ns_info(ns_log_default,
+ "MAXQUERIES exceeded, possible data loop in resolving (%s)",
+ dname);
+ goto servfail;
+ }
+
+ /* Reset the query control structure */
+
+ ns_freeqns(qp, "ns_resp");
+ qp->q_naddr = 0;
+ qp->q_curaddr = 0;
+ qp->q_fwd = server_options->fwdtab;
+
+ if (qp->q_domain != NULL)
+ freestr(qp->q_domain);
+ getname(np, tmpdomain, sizeof tmpdomain);
+ qp->q_domain = savestr(tmpdomain, 1);
+
+ if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) {
+ if (n < 0) {
+ ns_debug(ns_log_default, 3,
+ "resp: nslookup reports danger");
+ if (cname) /* a remote CNAME that does not have data */
+ goto return_newmsg;
+ goto servfail;
+ } else {
+ ns_debug(ns_log_default, 3,
+ "resp: no addrs found for NS's");
+ /*
+ * 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) {
+ ns_debug(ns_log_default, 3,
+ "resp: leaving, MAXCNAMES exceeded");
+ goto servfail;
+ }
+ ns_debug(ns_log_default, 1, "q_cname = %d", qp->q_cname);
+ ns_debug(ns_log_default, 3,
+ "resp: building recursive query; nslookup");
+ if (qp->q_cmsg == NULL) {
+ qp->q_cmsg = qp->q_msg;
+ qp->q_cmsglen = qp->q_msglen;
+ qp->q_cmsgsize = qp->q_msgsize;
+ } else if (qp->q_msg != NULL)
+ memput(qp->q_msg, qp->q_msgsize);
+ qp->q_msg = (u_char *)memget(PACKETSZ);
+ if (qp->q_msg == NULL) {
+ ns_notice(ns_log_default, "resp: memget error");
+ goto servfail;
+ }
+ qp->q_msgsize = PACKETSZ;
+ n = res_mkquery(QUERY, dname, qclass, qtype,
+ NULL, 0, NULL, qp->q_msg, PACKETSZ);
+ if (n < 0) {
+ ns_info(ns_log_default, "resp: res_mkquery(%s) failed",
+ dname);
+ goto servfail;
+ }
+ if (qp->q_name != NULL)
+ freestr(qp->q_name);
+ qp->q_name = savestr(dname, 1);
+ 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);
+ ns_debug(ns_log_default, 1,
+ "resp: forw -> %s ds=%d nsid=%d id=%d %dms",
+ 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,
+ log_get_stream(packet_channel));
+#endif
+ if (qp->q_flags & Q_USEVC) {
+ if (tcp_send(qp) != NOERROR) {
+ if (!haveComplained(ina_ulong(nsa->sin_addr),
+ (u_long)tcpsendStr))
+ ns_info(ns_log_default,
+ "ns_forw: tcp_send(%s) failed: %s",
+ sin_ntoa(*nsa), strerror(errno));
+ }
+ } else if (sendto(ds, (char*)qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0)
+ {
+ if (!haveComplained(ina_ulong(nsa->sin_addr),
+ (u_long)sendtoStr))
+ ns_info(ns_log_default, "ns_resp: sendto(%s): %s",
+ sin_ntoa(*nsa), strerror(errno));
+ nameserIncr(nsa->sin_addr, nssSendtoErr);
+ }
+ hp->rd = 0; /* leave set to 0 for dup detection */
+ nameserIncr(nsa->sin_addr, nssSentFwdR);
+ nameserIncr(qp->q_from.sin_addr, nssRcvdFwdR);
+ ns_debug(ns_log_default, 3, "resp: Query sent.");
+ free_nsp(nsp);
+ return;
+
+ formerr:
+ if (!haveComplained(ina_ulong(from.sin_addr), (u_long)formerrmsg))
+ ns_info(ns_log_resp_checks, "Malformed response from %s (%s)",
+ sin_ntoa(from), formerrmsg);
+ free_nsp(nsp);
+ return;
+
+ return_msg:
+ nameserIncr(from.sin_addr, nssRcvdFwdR);
+ nameserIncr(qp->q_from.sin_addr, nssSentFwdR);
+ /* The "standard" return code */
+ hp->qr = 1;
+ hp->id = qp->q_id;
+ hp->rd = 1;
+ hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0);
+ (void) send_msg(msg, msglen, qp);
+ qremove(qp);
+ free_nsp(nsp);
+ return;
+
+ return_newmsg:
+ nameserIncr(qp->q_from.sin_addr, nssSentAns);
+
+ if (!hp->aa)
+ nameserIncr(qp->q_from.sin_addr, nssSentNaAns);
+ if (hp->rcode == NXDOMAIN)
+ nameserIncr(qp->q_from.sin_addr, nssSentNXD);
+ n = doaddinfo(hp, cp, buflen);
+ cp += n;
+ buflen -= n;
+ hp->qr = 1;
+ hp->id = qp->q_id;
+ hp->rd = 1;
+ hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0);
+ (void) send_msg(newmsg, cp - newmsg, qp);
+ qremove(qp);
+ free_nsp(nsp);
+ return;
+
+ refused:
+ hp = (HEADER *)(qp->q_cmsglen ? qp->q_cmsg : qp->q_msg);
+ hp->rcode = REFUSED;
+ hp->qr = 1;
+ hp->id = qp->q_id;
+ hp->rd = 1;
+ hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0);
+ (void) send_msg((u_char *)hp,
+ (qp->q_cmsglen ? qp->q_cmsglen : qp->q_msglen),
+ qp);
+ qremove(qp);
+ free_nsp(nsp);
+ return;
+
+ servfail:
+ nameserIncr(qp->q_from.sin_addr, nssSentFail);
+ 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 = (NS_OPTION_P(OPTION_NORECURSE) == 0);
+ (void) send_msg((u_char *)hp,
+ (qp->q_cmsglen ? qp->q_cmsglen : qp->q_msglen),
+ qp);
+ qremove(qp);
+ free_nsp(nsp);
+ return;
+
+ timeout:
+ if (qp->q_stream)
+ sq_remove(qp->q_stream);
+ qremove(qp);
+ free_nsp(nsp);
+ return;
+}
+
+#define BOUNDS_CHECK(ptr, count) \
+ do { \
+ if ((ptr) + (count) > eom) { \
+ hp->rcode = FORMERR; \
+ return (-1); \
+ } \
+ } while (0)
+
+static int
+rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
+ char *dname, int namelen, struct sockaddr_in from, char **tnamep)
+{
+ u_char *cp, *eom, *rdatap;
+ u_int class, type, dlen;
+ int n, n1;
+ u_int32_t ttl;
+ u_char *cp1, data[MAXDATA*2];
+ HEADER *hp = (HEADER *)msg;
+ enum context context;
+
+ if (tnamep != NULL)
+ *tnamep = NULL;
+
+ *dpp = NULL;
+ cp = rrp;
+ eom = msg + msglen;
+ if ((n = dn_expand(msg, eom, cp, dname, namelen)) < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ if (ttl > MAXIMUM_TTL) {
+ ns_debug(ns_log_default, 5, "%s: converted TTL > %u to 0",
+ dname, MAXIMUM_TTL);
+ ttl = 0;
+ }
+ GETSHORT(dlen, cp);
+ BOUNDS_CHECK(cp, dlen);
+ rdatap = cp;
+ if (!ns_nameok(dname, class, NULL, response_trans,
+ ns_ownercontext(type, response_trans),
+ dname, from.sin_addr)) {
+ hp->rcode = REFUSED;
+ return (-1);
+ }
+ ns_debug(ns_log_default, 3,
+ "rrextract: dname %s type %d class %d ttl %d",
+ dname, type, class, ttl);
+ /*
+ * Convert the resource record data into the internal
+ * database format.
+ *
+ * On entry to the switch:
+ * CP points to the RDATA section of the wire-format RR.
+ * DLEN is its length.
+ * The memory area at DATA is available for processing.
+ *
+ * On exit from the switch:
+ * CP has been incremented past the RR.
+ * CP1 points to the RDATA section of the database-format RR.
+ * N contains the length of the RDATA section of the dbase-format RR.
+ *
+ * The new data at CP1 for length N will be copied into the database,
+ * so it need not be in any particular storage location.
+ */
+ switch (type) {
+ case T_A:
+ if (dlen != INT32SZ) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ /*FALLTHROUGH*/
+ case T_WKS:
+ case T_HINFO:
+ case T_TXT:
+ case T_X25:
+ case T_ISDN:
+ case T_NSAP:
+ case T_AAAA:
+ case T_LOC:
+ case T_KEY:
+ 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, eom, cp, (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if (!ns_nameok((char *)data, class, NULL, response_trans,
+ type == T_PTR ?ns_ptrcontext(dname) :domain_ctx,
+ dname, from.sin_addr)) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = data;
+ n = strlen((char *)data) + 1;
+ if (tnamep != NULL && (type == T_NS || type == T_MB))
+ *tnamep = savestr((char *)cp1, 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, eom, cp, (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if (!ns_nameok((char *)data, class, NULL, response_trans,
+ context, dname, from.sin_addr)) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ /*
+ * The next use of 'cp' is dn_expand(), so we don't have
+ * to BOUNDS_CHECK() here.
+ */
+ cp1 = data + (n = strlen((char *)data) + 1);
+ n1 = sizeof(data) - n;
+ if (type == T_SOA)
+ n1 -= 5 * INT32SZ;
+ n = dn_expand(msg, eom, 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, NULL, response_trans,
+ context, dname, from.sin_addr)) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += strlen((char *)cp1) + 1;
+ if (type == T_SOA) {
+ n = 5 * INT32SZ;
+ BOUNDS_CHECK(cp, n);
+ memcpy(cp1, cp, n);
+ cp += n;
+ cp1 += n;
+ }
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ case T_NAPTR:
+ /* Grab weight and port. */
+ BOUNDS_CHECK(cp, INT16SZ*2);
+ memcpy(data, cp, INT16SZ*2);
+ cp1 = data + INT16SZ*2;
+ cp += INT16SZ*2;
+
+ /* Flags */
+ BOUNDS_CHECK(cp, 1);
+ n = *cp++;
+ BOUNDS_CHECK(cp, n);
+ *cp1++ = n;
+ memcpy(cp1, cp, n);
+ cp += n; cp1 += n;
+
+ /* Service */
+ BOUNDS_CHECK(cp, 1);
+ n = *cp++;
+ BOUNDS_CHECK(cp, n);
+ *cp1++ = n;
+ memcpy(cp1, cp, n);
+ cp += n; cp1 += n;
+
+ /* Regexp */
+ BOUNDS_CHECK(cp, 1);
+ n = *cp++;
+ BOUNDS_CHECK(cp, n);
+ *cp1++ = n;
+ memcpy(cp1, cp, n);
+ cp += n; cp1 += n;
+
+ /* Replacement */
+ n = dn_expand(msg, eom, cp, (char *)cp1,
+ sizeof data - (cp1 - data));
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if (!ns_nameok((char *)cp1, class, NULL, response_trans,
+ hostname_ctx, dname, from.sin_addr)) {
+ 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_MX:
+ case T_AFSDB:
+ case T_RT:
+ case T_SRV:
+ /* grab preference */
+ BOUNDS_CHECK(cp, INT16SZ);
+ memcpy(data, cp, INT16SZ);
+ cp1 = data + INT16SZ;
+ cp += INT16SZ;
+
+ if (type == T_SRV) {
+ /* Grab weight and port. */
+ BOUNDS_CHECK(cp, INT16SZ*2);
+ memcpy(cp1, cp, INT16SZ*2);
+ cp1 += INT16SZ*2;
+ cp += INT16SZ*2;
+ }
+
+ /* get name */
+ n = dn_expand(msg, eom, cp, (char *)cp1,
+ sizeof data - (cp1 - data));
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if (!ns_nameok((char *)cp1, class, NULL, response_trans,
+ hostname_ctx, dname, from.sin_addr)) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+
+ if (tnamep != NULL)
+ *tnamep = savestr((char *)cp1, 1);
+
+ /* compute end of data */
+ cp1 += strlen((char *)cp1) + 1;
+ /* compute size of data */
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ case T_PX:
+ /* grab preference */
+ BOUNDS_CHECK(cp, INT16SZ);
+ memcpy(data, cp, INT16SZ);
+ cp1 = data + INT16SZ;
+ cp += INT16SZ;
+
+ /* get MAP822 name */
+ n = dn_expand(msg, eom, cp, (char *)cp1,
+ sizeof data - INT16SZ);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if (!ns_nameok((char *)cp1, class, NULL, response_trans,
+ domain_ctx, dname, from.sin_addr)) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ /*
+ * The next use of 'cp' is dn_expand(), so we don't have
+ * to BOUNDS_CHECK() here.
+ */
+ cp1 += (n = strlen((char *)cp1) + 1);
+ n1 = sizeof(data) - n;
+ n = dn_expand(msg, eom, cp, (char *)cp1, n1);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if (!ns_nameok((char *)cp1, class, NULL, response_trans,
+ domain_ctx, dname, from.sin_addr)) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += strlen((char *)cp1) + 1;
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ case T_SIG: {
+ u_long origTTL, exptime, signtime, timetilexp, now;
+
+ /* Check signature time, expiration, and adjust TTL. */
+ /* This code is similar to that in db_load.c. */
+
+ /* Skip coveredType, alg, labels */
+ BOUNDS_CHECK(cp, INT16SZ + 1 + 1 + 3*INT32SZ);
+ cp1 = cp + INT16SZ + 1 + 1;
+ GETLONG(origTTL, cp1);
+ GETLONG(exptime, cp1);
+ GETLONG(signtime, cp1);
+ now = time(NULL); /* Get current time in GMT/UTC */
+
+ /* Don't let bogus name servers increase the signed TTL */
+ if (ttl > origTTL) {
+ ns_debug(ns_log_default, 3,
+ "shrinking SIG TTL from %d to origTTL %d",
+ ttl, origTTL);
+ ttl = origTTL;
+ }
+
+ /* Don't let bogus signers "sign" in the future. */
+ if (signtime > now) {
+ ns_debug(ns_log_default, 3,
+ "ignoring SIG: signature date %s is in the future",
+ p_secstodate (signtime));
+ return ((cp - rrp) + dlen);
+ }
+
+ /* Ignore received SIG RR's that are already expired. */
+ if (exptime <= now) {
+ ns_debug(ns_log_default, 3,
+ "ignoring SIG: expiration %s is in the past",
+ p_secstodate (exptime));
+ return ((cp - rrp) + dlen);
+ }
+
+ /* Lop off the TTL at the expiration time. */
+ timetilexp = exptime - now;
+ if (timetilexp < ttl) {
+ ns_debug(ns_log_default, 3,
+ "shrinking expiring %s SIG TTL from %d to %d",
+ p_secstodate (exptime), ttl, timetilexp);
+ ttl = timetilexp;
+ }
+
+ /* The following code is copied from named-xfer.c. */
+ cp1 = (u_char *)data;
+
+ /* first just copy over the type_covered, algorithm, */
+ /* labels, orig ttl, two timestamps, and the footprint */
+ BOUNDS_CHECK(cp, 18);
+ memcpy(cp1, cp, 18);
+ cp += 18;
+ cp1 += 18;
+
+ /* then the signer's name */
+ n = dn_expand(msg, eom, cp, (char *)cp1, (sizeof data) - 18);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += strlen((char*)cp1)+1;
+
+ /* finally, we copy over the variable-length signature.
+ Its size is the total data length, minus what we copied. */
+ if (18 + (u_int)n > dlen) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ n = dlen - (18 + n);
+ if (n > ((int)(sizeof data) - (int)(cp1 - (u_char *)data))) {
+ hp->rcode = FORMERR;
+ return (-1); /* out of room! */
+ }
+ memcpy(cp1, cp, n);
+ cp += n;
+ cp1 += n;
+
+ /* compute size of data */
+ n = cp1 - (u_char *)data;
+ cp1 = (u_char *)data;
+ break;
+ }
+
+ default:
+ ns_debug(ns_log_default, 3, "unknown type %d", type);
+ return ((cp - rrp) + dlen);
+ }
+
+ if (cp > eom) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if ((u_int)(cp - rdatap) != dlen) {
+ ns_debug(ns_log_default, 3,
+ "encoded rdata length is %u, but actual length was %u",
+ dlen, (u_int)(cp - rdatap));
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if (n > MAXDATA) {
+ ns_debug(ns_log_default, 1,
+ "update type %d: %d bytes is too much data",
+ type, n);
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+
+ ttl += tt.tv_sec;
+ *dpp = savedata(class, type, ttl, cp1, n);
+ return (cp - rrp);
+}
+
+int
+send_msg(u_char *msg, int msglen, struct qinfo *qp) {
+ if (qp->q_flags & Q_SYSTEM)
+ return (1);
+ if (!qp->q_stream && (msglen > PACKETSZ))
+ msglen = trunc_adjust(msg, msglen, PACKETSZ);
+ ns_debug(ns_log_default, 1, "send_msg -> %s (%s %d) id=%d",
+ sin_ntoa(qp->q_from),
+ qp->q_stream == NULL ? "UDP" : "TCP",
+ qp->q_stream == NULL ? qp->q_dfd : qp->q_stream->s_rfd,
+ ntohs(qp->q_id));
+#ifdef DEBUG
+ if (debug > 4) {
+ struct qinfo *tqp;
+
+ for (tqp = nsqhead; tqp != NULL; tqp = tqp->q_link) {
+ ns_debug(ns_log_default, 4,
+ "qp %#lx q_id: %d q_nsid: %d q_msglen: %d",
+ (u_long)tqp, tqp->q_id,
+ tqp->q_nsid, tqp->q_msglen);
+ ns_debug(ns_log_default, 4,
+ "\tq_naddr: %d q_curaddr: %d",
+ tqp->q_naddr, tqp->q_curaddr);
+ ns_debug(ns_log_default, 4,
+ "\tq_next: %#lx q_link: %#lx",
+ (u_long)qp->q_next, (u_long)qp->q_link);
+ }
+ }
+ if (debug >= 6)
+ fp_nquery(msg, msglen, log_get_stream(packet_channel));
+#endif /* DEBUG */
+ if (qp->q_stream == NULL) {
+ if (sendto(qp->q_dfd, (char*)msg, msglen, 0,
+ (struct sockaddr *)&qp->q_from,
+ sizeof(qp->q_from)) < 0) {
+ if (!haveComplained(ina_ulong(qp->q_from.sin_addr),
+ (u_long)sendtoStr))
+#if defined(SPURIOUS_ECONNREFUSED)
+ if (errno != ECONNREFUSED)
+#endif
+ ns_info(ns_log_default,
+ "send_msg: sendto(%s): %s",
+ sin_ntoa(qp->q_from),
+ strerror(errno));
+ nameserIncr(qp->q_from.sin_addr, nssSendtoErr);
+ return (1);
+ }
+ } else
+ writestream(qp->q_stream, (u_char*)msg, msglen);
+ 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;
+ struct qinfo *oqp;
+{
+ char dname[MAXDNAME];
+
+ 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;
+ ns_debug(ns_log_default, 2, "prime: %s", dname);
+ (void) sysquery(dname, class, type, NULL, 0, QUERY);
+}
+#endif
+
+void
+prime_cache() {
+ struct qinfo *qp;
+
+ /*
+ * XXX - should this always be skipped if OPTION_FORWARD_ONLY
+ * or should it be another option? What about when we are
+ * doing selective forwarding?
+ */
+ if (!NS_OPTION_P(OPTION_FORWARD_ONLY)) {
+ ns_debug(ns_log_default, 1, "prime_cache: priming = %d",
+ priming);
+ if (!priming && fcachetab->h_tab[0] != NULL) {
+ 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
+/*
+ * 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(const char *dname, int class, int type) {
+ const char *zname, *fname;
+ int nns, na, zn, n;
+ struct zoneinfo *zp;
+ struct hashbuf *htp;
+ struct namebuf *np;
+ struct databuf *dp;
+
+ ns_debug(ns_log_notify, 3, "sysnotify(%s, %s, %s)",
+ dname, p_class(class), p_type(type));
+ htp = hashtab;
+ np = nlookup(dname, &htp, &fname, 0);
+ if (np == NULL) {
+ ns_warning(ns_log_notify, "sysnotify: can't find \"%s\"",
+ dname);
+ return;
+ }
+ zn = findMyZone(np, class);
+ if (zn == DB_Z_CACHE) {
+ ns_warning(ns_log_notify, "sysnotify: not auth for zone %s",
+ dname);
+ return;
+ }
+ zp = &zones[zn];
+ if (zp->z_notify == znotify_no ||
+ (zp->z_notify == znotify_use_default &&
+ NS_OPTION_P(OPTION_NONOTIFY)))
+ return;
+ if (zp->z_type != z_master && zp->z_type != z_slave) {
+ ns_warning(ns_log_notify, "sysnotify: %s not master or slave",
+ dname);
+ return;
+ }
+ zname = zp->z_origin;
+ nns = na = 0;
+ if (zp->z_type == z_master)
+ sysnotify_slaves(dname, zname, class, zn, &nns, &na);
+ if (zp->z_notify_count != 0) {
+ struct in_addr *also_addr = zp->z_also_notify;
+ int i;
+
+ for (i = 0; i < zp->z_notify_count; i++) {
+ sysquery(dname, class, T_SOA, also_addr, 1,
+ NS_NOTIFY_OP);
+ also_addr++;
+ }
+ nns += zp->z_notify_count;
+ na += zp->z_notify_count;
+ }
+ if (nns != 0 || na != 0)
+ ns_info(ns_log_notify,
+ "Sent NOTIFY for \"%s %s %s\" (%s); %d NS, %d A",
+ dname, p_class(class), p_type(type), zname, nns, na);
+}
+
+static void
+sysnotify_slaves(const char *dname, const char *zname, int class, int zn,
+ int *nns, int *na)
+{
+ const char *mname, *fname;
+ struct hashbuf *htp;
+ struct namebuf *np;
+ struct databuf *dp;
+
+ /*
+ * Master.
+ */
+ htp = hashtab;
+ np = nlookup(zname, &htp, &fname, 0);
+ if (!np) {
+ ns_warning(ns_log_notify,
+ "sysnotify: found name \"%s\" but not zone",
+ dname);
+ return;
+ }
+ mname = NULL;
+ for (dp = np->n_data; dp; dp = dp->d_next) {
+ if (dp->d_zone == DB_Z_CACHE || !match(dp, class, T_SOA))
+ continue;
+ if (mname) {
+ ns_notice(ns_log_notify,
+ "multiple SOA's for zone \"%s\"?",
+ zname);
+ return;
+ }
+ mname = (char *) dp->d_data;
+ }
+ if (mname == NULL) {
+ ns_notice(ns_log_notify, "no SOA found for zone \"%s\"",
+ zname);
+ return;
+ }
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (dp->d_zone == DB_Z_CACHE || !match(dp, class, T_NS))
+ continue;
+ if (strcasecmp((char*)dp->d_data, mname) == 0)
+ continue;
+ sysnotify_ns(dname, (char *)dp->d_data, class, zn, nns, na);
+ }
+}
+
+static void
+sysnotify_ns(const char *dname, const char *aname,
+ int class, int zn, int *nns, int *na)
+{
+ struct databuf *adp;
+ struct namebuf *anp;
+ const char *fname;
+ struct in_addr nss[NSMAX];
+ struct hashbuf *htp;
+ int is_us, nsc;
+
+ htp = hashtab;
+ anp = nlookup(aname, &htp, &fname, 0);
+ nsc = 0;
+ is_us = 0;
+ if (anp != NULL)
+ for (adp = anp->n_data; adp; adp = adp->d_next) {
+ struct in_addr ina;
+
+ if (!match(adp, class, T_A))
+ continue;
+ ina = ina_get(adp->d_data);
+ if (aIsUs(ina)) {
+ is_us = 1;
+ continue;
+ }
+ if (nsc < NSMAX)
+ nss[nsc++] = ina;
+ } /*next A*/
+ if (nsc == 0) {
+ if (!is_us) {
+ struct qinfo *qp;
+
+ qp = sysquery(aname, class, T_A, 0, 0, QUERY);
+ if (qp != NULL)
+ qp->q_notifyzone = zn;
+ }
+ return;
+ }
+ (void) sysquery(dname, class, T_SOA, nss, nsc, NS_NOTIFY_OP);
+ (*nns)++;
+ *na += nsc;
+}
+#endif /*BIND_NOTIFY*/
+
+struct qinfo *
+sysquery(const char *dname, int class, int type,
+ struct in_addr *nss, int nsc, int opcode)
+{
+ struct qinfo *qp, *oqp;
+ HEADER *hp;
+ char tmpdomain[MAXDNAME];
+ struct namebuf *np;
+ struct databuf *nsp[NSMAX];
+ struct hashbuf *htp;
+ struct sockaddr_in *nsa;
+ const char *fname;
+ int n, count;
+
+ nsp[0] = NULL;
+ ns_debug(ns_log_default, 3, "sysquery(%s, %d, %d, %#x, %d)",
+ dname, class, type, nss, nsc);
+ qp = qnew(dname, class, type);
+
+ if (nss && nsc)
+ np = NULL;
+ else {
+ htp = hashtab;
+ if (priming && dname[0] == '\0') {
+ np = NULL;
+ } else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) {
+ ns_info(ns_log_default,
+ "sysquery: nlookup error on %s?",
+ dname);
+ err1:
+ ns_freeqry(qp);
+ return (NULL);
+ }
+
+ n = findns(&np, class, nsp, &count, 0);
+ switch (n) {
+ case NXDOMAIN:
+ case SERVFAIL:
+ ns_info(ns_log_default,
+ "sysquery: findns error (%s) on %s?",
+ n == NXDOMAIN ? "NXDOMAIN" : "SERVFAIL",
+ dname);
+ err2:
+ free_nsp(nsp);
+ 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 = server_options->fwdtab;
+ qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2;
+ qp->q_flags |= Q_SYSTEM;
+
+ getname(np, tmpdomain, sizeof tmpdomain);
+ qp->q_domain = savestr(tmpdomain, 1);
+
+ if ((qp->q_msg = (u_char *)memget(PACKETSZ)) == NULL) {
+ ns_notice(ns_log_default, "sysquery: memget failed");
+ goto err2;
+ }
+ qp->q_msgsize = PACKETSZ;
+ n = res_mkquery(opcode, dname, class,
+ type, NULL, 0, NULL,
+ qp->q_msg, PACKETSZ);
+ if (n < 0) {
+ ns_info(ns_log_default,
+ "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 != NULL; oqp = oqp->q_link) {
+ if ((oqp != qp)
+ && (oqp->q_msglen == qp->q_msglen)
+ && memcmp(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*/
+ {
+ ns_debug(ns_log_default, 3,
+ "sysquery: duplicate");
+ 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) {
+ ns_info(ns_log_default,
+ "sysquery: nslookup reports danger (%s)",
+ dname);
+ goto err2;
+ } else if (np && NAME(*np)[0] == '\0') {
+ /*
+ * It's not too serious if we don't have
+ * the root server addresses if we have to
+ * go through a forwarder anyway. Don't
+ * bother to log it, since prime_cache()
+ * won't do anything about it as currently
+ * implemented.
+ *
+ * XXX - should we skip setting
+ * needs_prime_cache as well?
+ *
+ * XXX - what happens when we implement
+ * selective forwarding?
+ */
+ if (!NS_OPTION_P(OPTION_FORWARD_ONLY))
+ ns_warning(ns_log_default,
+ "sysquery: no addrs found for root NS (%s)",
+ dname);
+ if (class == C_IN && !priming)
+ needs_prime_cache = 1;
+ goto err2;
+ }
+ if (np) {
+ free_nsp(nsp);
+ nsp[0] = NULL;
+ np = np_parent(np);
+ n = findns(&np, class, nsp, &count, 0);
+ switch (n) {
+ case NXDOMAIN: /*FALLTHROUGH*/
+ case SERVFAIL:
+ ns_info(ns_log_default,
+ "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);
+
+ ns_debug(ns_log_default, 1,
+ "sysquery: send -> %s dfd=%d nsid=%d id=%d retry=%ld",
+ 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,
+ log_get_stream(packet_channel));
+#endif
+ if (sendto(qp->q_dfd, (char*)qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0) {
+ if (!haveComplained(ina_ulong(nsa->sin_addr),
+ (u_long)sendtoStr))
+ ns_info(ns_log_default, "sysquery: sendto(%s): %s",
+ sin_ntoa(*nsa), strerror(errno));
+ nameserIncr(nsa->sin_addr, nssSendtoErr);
+ }
+ nameserIncr(nsa->sin_addr, nssSentSysQ);
+ free_nsp(nsp);
+ return (qp);
+}
+
+/*
+ * Check the list of root servers after receiving a response
+ * to a query for the root servers.
+ */
+static int
+check_root() {
+ struct databuf *dp, *pdp;
+ 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) {
+ ns_notice(ns_log_default, "check_root: Can't find root!");
+ return (0);
+ }
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next)
+ if (dp->d_type == T_NS)
+ count++;
+ ns_debug(ns_log_default, 1, "%d root servers", count);
+ if (count < MINROOTS) {
+ ns_notice(ns_log_default,
+ "check_root: %d root servers after query to root server < min",
+ count);
+ return (0);
+ }
+ pdp = NULL;
+ dp = np->n_data;
+ while (dp != NULL) {
+ if (dp->d_type == T_NS && dp->d_zone == DB_Z_CACHE &&
+ dp->d_ttl < (u_int32_t)tt.tv_sec) {
+ ns_debug(ns_log_default, 1,
+ "deleting old root server '%s'",
+ dp->d_data);
+ dp = rm_datum(dp, np, pdp, NULL);
+ /* SHOULD DELETE FROM HINTS ALSO */
+ continue;
+ }
+ pdp = dp;
+ dp = dp->d_next;
+ }
+ if (check_ns())
+ return (1);
+ else {
+ priming = 1;
+ return (0);
+ }
+}
+
+/*
+ * Check the root to make sure that for each NS record we have a A RR
+ */
+static int
+check_ns() {
+ struct databuf *dp, *tdp;
+ struct namebuf *np, *tnp;
+ struct hashbuf *htp;
+ char *dname;
+ int found_arr;
+ const char *fname;
+ time_t curtime;
+ int servers = 0, rrsets = 0;
+
+ ns_debug(ns_log_default, 2, "check_ns()");
+
+ 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) {
+ int cnames = 0;
+
+ if (dp->d_rcode)
+ continue;
+
+ if (dp->d_type != T_NS)
+ continue;
+
+ servers++;
+
+ /* look for A records */
+ dname = (caddr_t) dp->d_data;
+ htp = hashtab;
+ tnp = nlookup(dname, &htp, &fname, 0);
+ if (tnp == NULL || fname != dname) {
+ ns_debug(ns_log_default, 3,
+ "check_ns: %s: not found %s %#lx",
+ dname, fname, (u_long)tnp);
+ sysquery(dname, dp->d_class, T_A, NULL,
+ 0, QUERY);
+ continue;
+ }
+ /* look for name server addresses */
+ found_arr = 0;
+ delete_stale(tnp);
+ for (tdp = tnp->n_data;
+ tdp != NULL;
+ tdp = tdp->d_next) {
+ if (tdp->d_rcode)
+ continue;
+ if (tdp->d_type == T_CNAME)
+ cnames++;
+ if (tdp->d_type != T_A ||
+ tdp->d_class != dp->d_class)
+ continue;
+ if ((tdp->d_zone == DB_Z_CACHE) &&
+ (tdp->d_ttl < (u_int32_t)curtime)) {
+ ns_debug(ns_log_default, 3,
+ "check_ns: stale entry '%s'",
+ NAME(*tnp));
+ found_arr = 0;
+ break;
+ }
+ found_arr++;
+ }
+ if (found_arr)
+ rrsets++;
+ else if (cnames > 0)
+ ns_info(ns_log_default,
+ "Root NS %s -> CNAME %s",
+ NAME(*np), NAME(*tnp));
+ else
+ sysquery(dname, dp->d_class, T_A, NULL,
+ 0, QUERY);
+ }
+ }
+
+ ns_debug(ns_log_default, 2, "check_ns: %d %d", servers, rrsets);
+ return ((servers <= 2)
+ ? (rrsets == servers)
+ : ((rrsets * 2) >= servers)
+ );
+}
+
+/* int findns(npp, class, nsp, countp, flag)
+ * Find NS's 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}
+ * *countp is bogus, but nsp[] has a single SOA returned in it.
+ * SERVFAIL: we are auth but zone isn't loaded; or, no root servers found
+ * *countp and nsp[] are bogus.
+ * OK: we are not authoritative, and here are the NS records we found.
+ * *countp and nsp[] return NS records of interest.
+ */
+int
+findns(struct namebuf **npp, int class,
+ struct databuf **nsp, int *countp, int flag)
+{
+ struct namebuf *np = *npp;
+ struct databuf *dp;
+ struct databuf **nspp;
+ struct hashbuf *htp;
+
+ nsp[0] = NULL;
+
+ if (priming && (np == NULL || NAME(*np)[0] == '\0'))
+ htp = fcachetab;
+ else
+ htp = hashtab;
+
+ try_again:
+ if (htp == fcachetab && class == C_IN && !priming)
+ /*
+ * XXX - do we want to set needs_prime_cache if
+ * OPTION_FORWARD_ONLY?
+ */
+ 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) {
+ ns_debug(ns_log_default, 5, "findns: np %#x '%s'", 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 != DB_Z_CACHE &&
+ ((zones[dp->d_zone].z_type == Z_PRIMARY) ||
+ (zones[dp->d_zone].z_type == Z_SECONDARY)) &&
+ match(dp, class, T_SOA)) {
+ ns_debug(ns_log_default, 3,
+ "findns: SOA found");
+ if (zones[dp->d_zone].z_flags & Z_AUTH) {
+ *npp = np;
+ nsp[0] = dp;
+ nsp[1] = NULL;
+ DRCNTINC(dp);
+ 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;
+ delete_stale(np);
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!match(dp, class, T_NS))
+ continue;
+ if (dp->d_rcode)
+ continue;
+ /*
+ * Don't use records that may become invalid to
+ * reference later when we do the rtt computation.
+ * Never delete our safety-belt information!
+ *
+ * XXX: this is horribly bogus.
+ */
+ if ((dp->d_zone == DB_Z_CACHE) &&
+ (dp->d_ttl < (u_int32_t)tt.tv_sec) &&
+ !(dp->d_flags & DB_F_HINT)) {
+ ns_debug(ns_log_default, 1,
+ "findns: stale entry '%s'",
+ NAME(*np));
+ /*
+ * We may have already added NS databufs
+ * and are going to throw them away. Fix
+ * reference counts. We don't need to free
+ * them here as we just got them from the
+ * cache.
+ */
+ while (nspp > &nsp[0]) {
+ nspp--;
+ DRCNTDEC(*nspp);
+ }
+ nsp[0] = NULL;
+ goto try_parent;
+ }
+ if (nspp < &nsp[NSMAX-1]) {
+ *nspp++ = dp;
+ DRCNTINC(dp);
+ }
+ }
+
+ *countp = nspp - nsp;
+ if (*countp > 0) {
+ ns_debug(ns_log_default, 3,
+ "findns: %d NS's added for '%s'",
+ *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;
+ }
+ ns_debug(ns_log_default, 1,
+ "findns: No root nameservers for class %s?", p_class(class));
+ if ((unsigned)class < MAXCLASS && norootlogged[class] == 0) {
+ norootlogged[class] = 1;
+ ns_info(ns_log_default, "No root nameservers for class %s",
+ 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(struct namebuf *np, int class, int type,
+ HEADER *hp, char **dnamep, int *lenp, int *countp)
+{
+ struct databuf *dp;
+ char *cp;
+ int buflen, n, count = 0;
+
+ delete_stale(np);
+
+#ifdef ROUND_ROBIN
+ if (type != T_ANY && type != T_PTR) {
+ /* cycle order of RRs, for a load balancing effect... */
+
+ struct databuf **dpp;
+
+ for (dpp = &np->n_data; (dp = *dpp) != NULL;
+ dpp = &dp->d_next) {
+ if (dp->d_next && wanted(dp, class, type)) {
+ 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)
+ ns_debug(ns_log_default, 1, "finddata(): buflen=%d", buflen);
+#endif
+ cp = ((char *)hp) + *countp;
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!wanted(dp, class, type)) {
+ if (type == T_CNAME && class == dp->d_class) {
+ /* any data means no CNAME exists */
+ *countp = 0;
+ return 0;
+ }
+ continue;
+ }
+ if (dp->d_cred == DB_C_ADDITIONAL) {
+#ifdef NOADDITIONAL
+ continue;
+#else
+ /* 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 earlier when this datum is
+ * used often.
+ */
+ dp->d_ttl = tt.tv_sec
+ +
+ 0.95 * (int) (dp->d_ttl - tt.tv_sec);
+#endif
+ }
+ /* -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...
+ */
+ ns_info(ns_log_default,
+ "NODATA & data for \"%s\" type %d class %d",
+ *dnamep, type, class);
+ continue;
+ }
+ if (type == T_ANY)
+ continue;
+ hp->rcode = NOERROR_NODATA;
+ if (dp->d_size == 0) { /* !RETURNSOA */
+ *countp = 0;
+ return 1; /* XXX - we have to report success */
+ }
+ }
+ if (dp->d_rcode == NXDOMAIN) {
+ if (count != 0) {
+ /*
+ * This should not happen, yet it might...
+ */
+ ns_info(ns_log_default,
+ "NXDOMAIN & data for \"%s\" type %d class %d",
+ *dnamep, type, class);
+ continue;
+ }
+ hp->rcode = NXDOMAIN;
+ if (dp->d_size == 0) { /* !RETURNSOA */
+ *countp = 0;
+ return 1; /* XXX - we have to report success */
+ }
+ }
+
+ /* Don't put anything but key or sig RR's in response to
+ requests for key or sig */
+ if (((type == T_SIG) || (type == T_KEY)) &&
+ (!((dp->d_type == T_SIG) || (dp->d_type == T_KEY))) )
+ continue;
+
+ if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1,
+ dnptrs, dnptrs_end)) < 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 != DB_Z_CACHE &&
+ (zones[dp->d_zone].z_flags & Z_AUTH) != 0 &&
+ class != C_ANY)
+ hp->aa = 1; /* XXX */
+#endif
+ if (dp->d_type == T_CNAME) {
+ /* don't alias if querying for key, sig, nxt, or any */
+ if ((type != T_KEY) &&
+ (type != T_SIG) &&
+ (type != T_NXT) &&
+ (type != T_ANY)) { /* or T_NS? */
+ *dnamep = (caddr_t) dp->d_data;
+ }
+ break;
+ }
+ }
+ /*
+ * Cache invalidate the other RR's of same type
+ * if some have timed out
+ */
+ ns_debug(ns_log_default, 3, "finddata: added %d class %d type %d RRs",
+ count, class, type);
+ *countp = count;
+ return (*lenp - buflen);
+}
+
+/*
+ * Do we want this data record based on the class and type?
+ * (We always return found unexpired SIG RR's that cover the wanted rrtype.)
+ */
+int
+wanted(const struct databuf *dp, int class, int type) {
+ const u_char *cp;
+ int coveredType;
+ time_t expiration;
+#ifdef DEBUG
+ char pclass[15], ptype[15];
+#endif
+
+#ifdef DEBUG
+ strcpy(pclass, p_class(class));
+ strcpy(ptype, p_type(type));
+ ns_debug(ns_log_default, 3, "wanted(%#x, %s %s) [%s %s]",
+ dp, pclass, ptype,
+ p_class(dp->d_class), p_type(dp->d_type));
+#endif
+
+ if (dp->d_class != class && class != C_ANY)
+ return (0);
+ /*
+ * Must check SIG for expiration below, other matches
+ * return OK here.
+ */
+ if (type == dp->d_type && (type != T_SIG))
+ return (1);
+ /* 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);
+
+ /* First, look at the type of RR. */
+ switch (dp->d_type) {
+
+ /* Cases to deal with:
+ T_ANY search, return all unexpired SIGs.
+ T_SIG search, return all unexpired SIGs.
+ T_<foo> search, return all unexp SIG <FOO>s.
+ */
+ case T_SIG:
+ cp = dp->d_data;
+ GETSHORT(coveredType, cp);
+ cp += INT16SZ + INT32SZ; /* skip alg, labels, & orig TTL */
+ GETLONG(expiration,cp);
+
+ if (type == T_ANY || type == T_SIG || type == coveredType) {
+ if (expiration > time(0))
+ return (1); /* Unexpired matching SIG */
+ }
+ return (0); /* We don't return this SIG. */
+
+ case T_ANY:
+ return (1);
+ case T_CNAME:
+ if (dp->d_rcode != NOERROR_NODATA)
+ return (1);
+ else
+ break;
+ }
+ /* OK, now look at the type of query. */
+ 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 != DB_Z_CACHE
+ && (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(struct namebuf *np, struct databuf **dpp,
+ u_char *cp, int buflen, int *countp)
+{
+ struct databuf *dp;
+ char dname[MAXDNAME];
+ 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 */
+ if (dp->d_rcode)
+ continue;
+ if ((n = make_rr(dname, dp, cp, buflen, 1,
+ dnptrs, dnptrs_end)) < 0)
+ return (-bytes); /* Truncation */
+ cp += n;
+ buflen -= n;
+ bytes += n;
+ (*countp)++;
+ }
+ return (bytes);
+}
+
+static void
+rrsetadd(struct flush_set *flushset, const char *name, struct databuf *dp) {
+ struct flush_set *fs = flushset;
+ struct db_list *dbl;
+
+ while (fs->fs_name && (
+ strcasecmp(fs->fs_name,name) ||
+ (fs->fs_class != dp->d_class) ||
+ (fs->fs_type != dp->d_type) ||
+ (fs->fs_cred != dp->d_cred))) {
+ fs++;
+ }
+ if (!fs->fs_name) {
+ fs->fs_name = savestr(name, 1);
+ fs->fs_class = dp->d_class;
+ fs->fs_type = dp->d_type;
+ fs->fs_cred = dp->d_cred;
+ fs->fs_list = NULL;
+ fs->fs_last = NULL;
+ }
+ dbl = (struct db_list *)memget(sizeof(struct db_list));
+ if (!dbl)
+ panic("rrsetadd: out of memory", NULL);
+ dbl->db_next = NULL;
+ dbl->db_dp = dp;
+ if (fs->fs_last == NULL)
+ fs->fs_list = dbl;
+ else
+ fs->fs_last->db_next = dbl;
+ fs->fs_last = dbl;
+}
+
+static int
+ttlcheck(const char *name, struct db_list *dbl, int update) {
+ int type = dbl->db_dp->d_type;
+ int class = dbl->db_dp->d_class;
+ struct hashbuf *htp = hashtab;
+ const char *fname;
+ struct namebuf *np;
+ struct db_list *dbp = dbl;
+ struct databuf *dp;
+ u_int32_t ttl = 0; /* Make gcc happy. */
+ int first;
+
+
+ np = nlookup(name, &htp, &fname, 0);
+ if (np == NULL || fname != name || ns_wildcard(NAME(*np)))
+ return (1);
+
+ /* check that all the ttl's we have are the same, if not return 1 */
+ first = 1;
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!match(dp, class, type))
+ continue;
+ if (first) {
+ /* we can't update zone data so return early */
+ if (dp->d_zone != DB_Z_CACHE)
+ return (0);
+ ttl = dp->d_ttl;
+ first = 0;
+ } else if (ttl != dp->d_ttl)
+ return (1);
+ }
+
+ /* there are no records of this type in the cache */
+ if (first)
+ return(1);
+
+ /*
+ * the ttls of all records we have in the cache are the same
+ * if the ttls differ in the new set we don't want it.
+ */
+
+ /* check that all the ttl's we have are the same, if not return 0 */
+ first = 1;
+ while (dbp) {
+ if (first) {
+ ttl = dbp->db_dp->d_ttl;
+ first = 0;
+ } else if (ttl != dbp->db_dp->d_ttl) {
+ return(0);
+ }
+ dbp = dbp->db_next;
+ }
+
+ /* update ttl if required */
+ if (update) {
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!match(dp, class, type))
+ continue;
+ if (dp->d_ttl > ttl)
+ break;
+ dp->d_ttl = ttl;
+ fixttl(dp);
+ }
+ }
+
+ return(1);
+}
+
+static int
+rrsetcmp(name, dbl)
+ char *name;
+ struct db_list *dbl;
+{
+ int type = dbl->db_dp->d_type;
+ int class = dbl->db_dp->d_class;
+ struct hashbuf *htp = hashtab;
+ const char *fname;
+ struct namebuf *np;
+ struct db_list *dbp = dbl;
+ struct databuf *dp;
+ int exists = 0;
+
+
+ np = nlookup(name, &htp, &fname, 0);
+ if (np == NULL || fname != name || ns_wildcard(NAME(*np))) {
+ ns_debug(ns_log_default, 3, "rrsetcmp: name not in database");
+ return (-1);
+ }
+
+ /* check that all entries in dbl are in the cache */
+ while (dbp) {
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (match(dp, class, type))
+ exists++;
+ if (!db_cmp(dp, dbp->db_dp)
+#ifdef NOADDITIONAL
+ && ((dp->d_cred == dbp->db_dp->d_cred) ||
+ (dp->d_cred != DB_C_ADDITIONAL))
+#endif
+ )
+ break;
+ }
+ if (!dp) {
+ ns_debug(ns_log_default, 3,
+ "rrsetcmp: %srecord%s in database",
+ exists ? "" : "no ", exists ? " not" : "s");
+ return (exists ? 1 : -1);
+ }
+ dbp = dbp->db_next;
+ }
+
+ /* Check that all cache entries are in the list. */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!match(dp, class, type))
+ continue;
+#ifdef NCACHE
+ if (dp->d_rcode)
+ return (1);
+#endif
+ dbp = dbl;
+ while (dbp) {
+ if (!db_cmp(dp, dbp->db_dp))
+ break;
+ dbp = dbp->db_next;
+ }
+ if (!dbp) {
+ ns_debug(ns_log_default, 3,
+ "rrsetcmp: record not in rrset");
+ return (1);
+ }
+ }
+ ns_debug(ns_log_default, 3, "rrsetcmp: rrsets matched");
+ return (0);
+}
+
+static void
+rrsetupdate(struct flush_set * flushset, int flags, struct sockaddr_in from) {
+ struct flush_set *fs = flushset;
+ struct db_list *dbp, *odbp;
+ int n;
+
+ while (fs->fs_name) {
+ ns_debug(ns_log_default, 2, "rrsetupdate: %s",
+ fs->fs_name[0] ? fs->fs_name : ".");
+ if ((n = rrsetcmp(fs->fs_name, fs->fs_list)) &&
+ ttlcheck(fs->fs_name, fs->fs_list, 0)) {
+ if (n > 0)
+ flushrrset(fs, from);
+
+ dbp = fs->fs_list;
+ while (dbp) {
+ n = db_update(fs->fs_name, dbp->db_dp,
+ dbp->db_dp, NULL, flags,
+ hashtab, from);
+ ns_debug(ns_log_default, 3,
+ "rrsetupdate: %s %d",
+ fs->fs_name[0] ? fs->fs_name : ".",
+ n);
+ if (n != OK)
+ db_freedata(dbp->db_dp);
+ odbp = dbp;
+ dbp = dbp->db_next;
+ memput(odbp, sizeof *odbp);
+ }
+ } else {
+ if (n == 0)
+ (void)ttlcheck(fs->fs_name,fs->fs_list, 1);
+ dbp = fs->fs_list;
+ while (dbp) {
+ db_freedata(dbp->db_dp);
+ odbp = dbp;
+ dbp = dbp->db_next;
+ memput(odbp, sizeof *odbp);
+ }
+ }
+ fs->fs_list = NULL;
+ fs++;
+ }
+}
+
+static void
+flushrrset(struct flush_set * fs, struct sockaddr_in from) {
+ struct databuf *dp;
+ int n;
+
+ ns_debug(ns_log_default, 2, "flushrrset(%s, %s, %s, %d)",
+ fs->fs_name[0]?fs->fs_name:".", p_type(fs->fs_type),
+ p_class(fs->fs_class), fs->fs_cred);
+ dp = savedata(fs->fs_class, fs->fs_type, 0, NULL, 0);
+ dp->d_zone = DB_Z_CACHE;
+ dp->d_cred = fs->fs_cred;
+ dp->d_clev = 0;
+ do {
+ n = db_update(fs->fs_name, dp, NULL, NULL, DB_DELETE, hashtab,
+ from);
+ ns_debug(ns_log_default, 3, "flushrrset: %d", n);
+ } while (n == OK);
+ db_freedata(dp);
+}
+
+static void
+free_flushset(struct flush_set *flushset, int flushset_size) {
+ struct flush_set *fs;
+
+ for (fs = flushset; fs->fs_name != NULL; fs++)
+ freestr(fs->fs_name);
+ memput(flushset, flushset_size);
+}
+
+/*
+ * 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(struct namebuf *np, int class, int type) {
+ struct databuf *dp, *pdp;
+
+ ns_debug(ns_log_default, 3, "delete_all(%#x:\"%s\" %s %s)",
+ np, NAME(*np), p_class(class), p_type(type));
+ pdp = NULL;
+ dp = np->n_data;
+ while (dp != NULL) {
+ if (dp->d_zone == DB_Z_CACHE && (dp->d_flags & DB_F_HINT) == 0
+ && match(dp, class, type)) {
+ dp = rm_datum(dp, np, pdp, NULL);
+ continue;
+ }
+ pdp = dp;
+ dp = dp->d_next;
+ }
+}
+
+/* delete_stale(np)
+ * for all RRs associated with this name, check for staleness (& delete)
+ * arguments:
+ * np = pointer to namebuf to be cleaned.
+ * returns:
+ * void.
+ * side effects:
+ * delete_all() can be called, freeing memory and relinking chains.
+ */
+void
+delete_stale(np)
+ struct namebuf *np;
+{
+ struct databuf *dp;
+ again:
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (dp->d_zone == DB_Z_CACHE && stale(dp)) {
+ delete_all(np, dp->d_class, dp->d_type);
+ goto again;
+ }
+ }
+}
+
+
+/*
+ * Adjust answer message so that it fits in outlen. Set tc if required.
+ *
+ * If outlen = msglen, can be used to verify qdcount, ancount, nscount
+ * and arcount.
+ *
+ * return new length
+ */
+
+int
+trunc_adjust(u_char *msg, int msglen, int outlen) {
+ register HEADER *hp;
+ u_int qdcount, ancount, nscount, arcount, dlen;
+ u_char *cp = msg, *cp1, *eom_in, *eom_out;
+ int n;
+
+ eom_in = msg + msglen;
+ eom_out = msg + outlen;
+
+ hp = (HEADER *)msg;
+ qdcount = ntohs(hp->qdcount);
+ ancount = ntohs(hp->ancount);
+ nscount = ntohs(hp->nscount);
+ arcount = ntohs(hp->arcount);
+ cp += HFIXEDSZ;
+
+ while ((qdcount || ancount || nscount || arcount) &&
+ cp < eom_in && cp < eom_out) {
+
+ cp1 = cp; /* use temporary in case we break */
+
+ n = dn_skipname(cp1, eom_in);
+ if (n < 0)
+ break;
+ cp1 += n + 2 * INT16SZ; /* type, class */
+
+ if (!qdcount) {
+ cp1 += INT32SZ; /* ttl */
+ if (cp1 + INT16SZ > eom_in)
+ break;
+ GETSHORT(dlen, cp1);
+ cp1 += dlen;
+ }
+
+ if (cp1 > eom_in || cp1 > eom_out)
+ break;
+
+ cp = cp1;
+
+ if (qdcount)
+ qdcount--;
+ else if (ancount)
+ ancount--;
+ else if (nscount)
+ nscount--;
+ else
+ arcount--;
+ }
+
+ if (qdcount || ancount || nscount || arcount) {
+ ns_debug(ns_log_default, 1,
+ "trunc_adjust:%s %d %d %d %d %d, %d %d %d %d %d",
+ hp->tc?" tc":"", msglen,
+ ntohs(hp->qdcount), ntohs(hp->ancount),
+ ntohs(hp->nscount), ntohs(hp->arcount),
+ cp-msg, qdcount, ancount, nscount, arcount);
+ hp->tc = 1;
+ hp->qdcount = htons(ntohs(hp->qdcount) - qdcount);
+ hp->ancount = htons(ntohs(hp->ancount) - ancount);
+ hp->nscount = htons(ntohs(hp->nscount) - nscount);
+ hp->arcount = htons(ntohs(hp->arcount) - arcount);
+ }
+ ENSURE(cp <= eom_out);
+ return (cp - msg);
+}
+
+static void
+add_related_additional(char *name) {
+ int i;
+
+ if (num_related >= MAX_RELATED - 1)
+ return;
+ for (i = 0; i < num_related; i++)
+ if (strcasecmp(name, related[i]) == 0) {
+ freestr(name);
+ return;
+ }
+ related[num_related++] = name;
+}
+
+static void
+free_related_additional() {
+ int i;
+
+ for (i = 0; i < num_related; i++)
+ freestr(related[i]);
+ num_related = 0;
+}
+
+static int
+related_additional(char *name) {
+ int i;
+
+ for (i = 0; i < num_related; i++)
+ if (strcasecmp(name, related[i]) == 0)
+ return (1);
+ return (0);
+}
+
+static void
+freestr_maybe(char **tname) {
+ if (tname == NULL || *tname == NULL)
+ return;
+ freestr(*tname);
+ *tname = NULL;
+}
diff --git a/contrib/bind/bin/named/ns_stats.c b/contrib/bind/bin/named/ns_stats.c
new file mode 100644
index 0000000..5be0257
--- /dev/null
+++ b/contrib/bind/bin/named/ns_stats.c
@@ -0,0 +1,415 @@
+#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.18 1998/02/13 19:50:24 halley Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/*
+ * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+#include <isc/tree.h>
+
+#include "port_after.h"
+
+#ifdef HAVE_GETRUSAGE /* XXX */
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+#include "named.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(FILE *);
+
+void
+ns_stats() {
+ time_t timenow = time(NULL);
+ FILE *f;
+ int i;
+
+ ns_notice(ns_log_statistics, "dumping nameserver stats");
+
+ if (!(f = fopen(server_options->stats_filename, "a"))) {
+ ns_notice(ns_log_statistics, "cannot open stat file, \"%s\"",
+ server_options->stats_filename);
+ return;
+ }
+
+ fprintf(f, "+++ Statistics Dump +++ (%ld) %s",
+ (long)timenow, checked_ctime(&timenow));
+ fprintf(f, "%ld\ttime since boot (secs)\n",
+ (long)(timenow - boottime));
+ fprintf(f, "%ld\ttime since reset (secs)\n",
+ (long)(timenow - resettime));
+
+ /* 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] != NULL)
+ 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, "++ Memory Statistics ++\n");
+ memstats(f);
+ fprintf(f, "-- Memory Statistics --\n");
+ fprintf(f, "--- Statistics Dump --- (%ld) %s",
+ (long)timenow, checked_ctime(&timenow));
+ (void) my_fclose(f);
+ ns_notice(ns_log_statistics, "done dumping nameserver stats");
+}
+
+void
+qtypeIncr(qtype)
+ int qtype;
+{
+ if (qtype < T_A || qtype > T_ANY)
+ qtype = 0; /* bad type */
+ typestats[qtype]++;
+}
+
+static tree *nameserTree;
+static int nameserInit;
+
+static FILE *nameserStatsFile;
+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) */
+ "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 */
+ };
+
+/*
+ * Note that addresses in network byte order always have the high byte first.
+ * XXX - this is horribly IPv4 dependent, but it's performance critical.
+ */
+static int
+nameserCompar(const tree_t t1, const tree_t t2) {
+ u_char *p1 = (u_char *)t1, *p2 = (u_char *)t2;
+ int i;
+
+ for (i = INADDRSZ; i > 0; i--) {
+ u_char c1 = *p1++, c2 = *p2++;
+
+ if (c1 < c2)
+ return (-1);
+ if (c1 > c2)
+ return (1);
+ }
+ 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 == NULL && (flags & NS_F_INSERT) != 0) {
+ ns = (struct nameser *)memget(sizeof(struct nameser));
+ if (ns == NULL) {
+ nomem: if (!haveComplained((u_long)nameserFind, 0))
+ ns_notice(ns_log_statistics,
+ "nameserFind: memget failed; %s",
+ strerror(errno));
+ return (NULL);
+ }
+ memset(ns, 0, sizeof *ns);
+ ns->addr = addr;
+ if (!tree_add(&nameserTree, nameserCompar, (tree_t)ns, NULL)) {
+ int save = errno;
+ memput(ns, sizeof *ns);
+ errno = save;
+ goto nomem;
+ }
+ }
+ return (ns);
+}
+
+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);
+}
+
+static void
+nameserStats(f)
+ FILE *f;
+{
+ nameserStatsFile = f;
+ fprintf(f, "++ Name Server Statistics ++\n");
+ nameserStatsHdr(f);
+ fprintf(f, "(Global)\n");
+ nameserStatsOut(f, globalStats);
+ if (NS_OPTION_P(OPTION_HOSTSTATS))
+ tree_trav(&nameserTree, nameserStatsTravUAR);
+ fprintf(f, "-- Name Server Statistics --\n");
+ nameserStatsFile = NULL;
+}
+
+void
+ns_logstats(evContext ctx, void *uap, struct timespec due,
+ struct timespec inter)
+{
+ char buffer[1024];
+ char buffer2[32], header[64];
+ time_t timenow = time(NULL);
+ int i;
+#ifdef HAVE_GETRUSAGE
+ struct rusage usage, childu;
+#endif /*HAVE_GETRUSAGE*/
+
+#ifdef HAVE_GETRUSAGE
+# define tv_float(tv) ((tv).tv_sec + ((tv).tv_usec / 1000000.0))
+
+ 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));
+ ns_info(ns_log_statistics, "USAGE %lu %lu %s", (u_long)timenow,
+ (u_long)boottime, buffer);
+# undef tv_float
+#endif /*HAVE_GETRUSAGE*/
+
+ 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) {
+ ns_info(ns_log_statistics, buffer);
+ strcpy(buffer, header);
+ }
+ strcat(buffer, buffer2);
+ }
+ }
+ ns_info(ns_log_statistics, 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) {
+ ns_info(ns_log_statistics, buffer);
+ strcpy(buffer, header);
+ }
+ strcat(buffer, buffer2);
+ }
+ ns_info(ns_log_statistics, buffer);
+}
+
+static void
+nameserFree(void *uap) {
+ struct nameser *ns = uap;
+
+ memput(ns, sizeof *ns);
+}
+
+void
+ns_freestats(void) {
+ if (nameserTree == NULL)
+ return;
+ tree_mung(&nameserTree, nameserFree);
+ nameserInit = 0;
+}
diff --git a/contrib/bind/bin/named/ns_udp.c b/contrib/bind/bin/named/ns_udp.c
new file mode 100644
index 0000000..8b1af5e
--- /dev/null
+++ b/contrib/bind/bin/named/ns_udp.c
@@ -0,0 +1,123 @@
+#if !defined(lint) && !defined(SABER)
+static char rcsid[] = "$Id: ns_udp.c,v 8.5 1997/05/21 19:52:26 halley Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <nlist.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+void
+ns_udp() {
+#if defined(CHECK_UDP_SUM) || defined(FIX_UDP_SUM)
+ struct nlist nl[2];
+ int fd;
+ int sum;
+ u_long res, offset;
+
+ nl[0].n_name = UDPSUM;
+ nl[1].n_name = 0;
+
+ if (nlist(KSYMS, nl)) {
+ ns_debug(ns_log_default, 1, "ns_udp: nlist (%s,%s) failed",
+ KSYMS, UDPSUM);
+ return;
+ }
+
+ ns_debug(ns_log_default, 1, "ns_udp: %s %d %lu (%ld)",
+ nl[0].n_name, nl[0].n_type, nl[0].n_value, nl[0].n_value);
+
+ if (!nl[0].n_type)
+ return;
+
+ if ((fd = open(KMEM, O_RDWR, 0)) < 0) {
+ ns_debug(ns_log_default, 1, "ns_udp: open %s failed: %s", KMEM,
+ strerror(errno));
+ return;
+ }
+
+ offset = nl[0].n_value;
+#ifdef KMAP
+ offset &= ((~0UL)>>1);
+#endif
+
+ res = lseek(fd, offset, SEEK_SET);
+ if (res != offset) {
+ ns_debug(ns_log_default, 1, "ns_udp: lseek %lu failed %lu: %s",
+ offset, res, strerror(errno));
+ goto cleanup;
+ }
+
+ if (read(fd, &sum, sizeof(sum)) != sizeof(sum)) {
+ ns_debug(ns_log_default, 1, "ns_udp: read failed: %s",
+ strerror(errno));
+ goto cleanup;
+ }
+
+ ns_debug(ns_log_default, 1, "ns_udp: %d", sum);
+ if (sum == 0) {
+#ifdef FIX_UDP_SUM
+ sum = 1;
+ lseek(fd, offset, SEEK_SET);
+ if (res != offset) {
+ ns_debug(ns_log_default, 1,
+ "ns_udp: lseek %lu failed %lu: %s",
+ offset, res, strerror(errno));
+ goto cleanup;
+ }
+ if (write(fd, &sum, sizeof(sum)) != sizeof(sum)) {
+ ns_debug(ns_log_default, 1, "ns_udp: write failed: %s",
+ strerror(errno));
+ goto cleanup;
+ }
+ ns_warning(ns_log_default, "ns_udp: check sums turned on");
+#else
+ ns_panic(ns_log_default, 0,
+ "ns_udp: checksums NOT turned on, exiting");
+#endif
+ }
+cleanup:
+ close(fd);
+#endif
+}
diff --git a/contrib/bind/bin/named/ns_update.c b/contrib/bind/bin/named/ns_update.c
new file mode 100644
index 0000000..e6fdd8d
--- /dev/null
+++ b/contrib/bind/bin/named/ns_update.c
@@ -0,0 +1,2393 @@
+#if !defined(lint) && !defined(SABER)
+static char rcsid[] = "$Id: ns_update.c,v 8.24 1998/03/20 00:49:16 halley Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/*
+ * Based on the Dynamic DNS reference implementation by Viraj Bais
+ * <viraj_bais@ccm.fm.intel.com>
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+#define WRITEABLE_MASK (S_IWUSR | S_IWGRP | S_IWOTH)
+
+/* XXXRTH almost all funcs. in here should be static!
+ map rdata_dump to db_to_textual
+ map rdata_expand to wire_to_db
+ make a textual_to_db and use it in merge_logs?
+ replace all this "map" stuff with the new routines (from 4.9.5 I think)
+ */
+
+/* from ns_req.c */
+
+static struct map m_opcode[] = {
+ { "nxdomain", NXDOMAIN },
+ { "yxdomain", YXDOMAIN },
+ { "nxrrset", NXRRSET },
+ { "yxrrset", YXRRSET },
+ { "delete", DELETE },
+ { "add", ADD },
+};
+#define M_OPCODE_CNT (sizeof(m_opcode) / sizeof(struct map))
+
+/* XXXRTH workaround map difficulties */
+#define M_CLASS_CNT m_class_cnt
+#define M_TYPE_CNT m_type_cnt
+
+static char *opcodes[] = {
+ "delete",
+ "add",
+ "",
+ "nxdomain",
+ "",
+ "",
+ "yxdomain",
+ "yxrrset",
+ "nxrrset",
+ "",
+ "",
+};
+
+
+/* from db_load.c */
+
+static struct map m_section[] = {
+ { "zone", S_ZONE },
+ { "prereq", S_PREREQ },
+ { "update", S_UPDATE },
+ { "reserved", S_ADDT },
+};
+#define M_SECTION_CNT (sizeof(m_section) / sizeof(struct map))
+
+
+/* from ns_req.c */
+
+static ns_updrec *rrecp_start = NULL, *rrecp_last = NULL;
+
+
+/* forward */
+static int findzone(const char *, int, int, int *, int);
+static int rdata_expand(const u_char *, const u_char *, const u_char *,
+ u_int, size_t, u_char *, size_t);
+
+
+static FILE *
+open_transaction_log(struct zoneinfo *zp) {
+ FILE *fp;
+
+ fp = fopen(zp->z_updatelog, "a+");
+ if (fp == NULL) {
+ ns_error(ns_log_update, "can't open %s: %s", zp->z_updatelog,
+ strerror(errno));
+ return (NULL);
+ }
+ if (ftell(fp) == 0L) {
+ fprintf(fp, "%s", LogSignature);
+ }
+ return (fp);
+}
+
+
+static int
+close_transaction_log(struct zoneinfo *zp, FILE *fp) {
+ if (fflush(fp) == EOF) {
+ ns_error(ns_log_update, "fflush() of %s failed: %s",
+ zp->z_updatelog, strerror(errno));
+ return (-1);
+ }
+ if (fsync(fileno(fp)) < 0) {
+ ns_error(ns_log_update, "fsync() of %s failed: %s",
+ zp->z_updatelog, strerror(errno));
+ return (-1);
+ }
+ if (fclose(fp) == EOF) {
+ ns_error(ns_log_update, "fclose() of %s failed: %s",
+ zp->z_updatelog, strerror(errno));
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * printupdatelog(srcaddr, firstp, hp, zp, old_serial)
+ * append an ascii form to the zone's transaction log file.
+ */
+static void
+printupdatelog(struct sockaddr_in srcaddr,
+ ns_updrec *firstp,
+ HEADER *hp,
+ struct zoneinfo *zp,
+ u_int32_t old_serial)
+{
+ struct databuf *dp;
+ struct map *mp;
+ ns_updrec *rrecp;
+ int opcode;
+ char time[25];
+ FILE *fp;
+
+ if (!firstp)
+ return;
+
+ fp = open_transaction_log(zp);
+ if (fp == NULL)
+ return;
+
+ sprintf(time, "at %lu", (u_long)tt.tv_sec);
+ fprintf(fp, "[DYNAMIC_UPDATE] id %u from %s %s (named pid %ld):\n",
+ hp->id, sin_ntoa(srcaddr), time, (long)getpid());
+ for (rrecp = firstp; rrecp; rrecp = rrecp->r_next) {
+ INSIST(zp == &zones[rrecp->r_zone]);
+ switch (rrecp->r_section) {
+ case S_ZONE:
+ fprintf(fp, "zone:\torigin %s class %s serial %u\n",
+ zp->z_origin, p_class(zp->z_class),
+ old_serial);
+ break;
+ case S_PREREQ:
+ opcode = rrecp->r_opcode;
+ fprintf(fp, "prereq:\t{%s} %s. %s ",
+ opcodes[opcode], rrecp->r_dname,
+ p_class(zp->z_class));
+ if (opcode == NXRRSET || opcode == YXRRSET) {
+ fprintf(fp, "%s ", p_type(rrecp->r_type));
+ if ((dp = rrecp->r_dp) && dp->d_size > 0) {
+ dp->d_class = zp->z_class;
+ (void) rdata_dump(dp, fp);
+ }
+ }
+ fprintf(fp, "\n");
+ break;
+ case S_UPDATE:
+ opcode = rrecp->r_opcode;
+ fprintf(fp, "update:\t{%s} %s. ",
+ opcodes[opcode], rrecp->r_dname);
+ if (opcode == ADD)
+ fprintf(fp, "%u ", rrecp->r_ttl);
+ fprintf(fp, "%s ", p_class(zp->z_class));
+ if (rrecp->r_type != T_ANY)
+ fprintf(fp, "%s ", p_type(rrecp->r_type));
+ if ((dp = rrecp->r_dp) && dp->d_size > 0) {
+ dp->d_class = zp->z_class;
+ (void) rdata_dump(dp, fp);
+ }
+ fprintf(fp, "\n");
+ break;
+ case S_ADDT:
+ break;
+ default:
+ ns_panic(ns_log_update, 1,
+ "printupdatelog - impossible condition");
+ /*NOTREACHED*/
+ }
+ }
+ fprintf(fp, "\n");
+ (void) close_transaction_log(zp, fp);
+}
+
+static void
+cancel_soa_update(struct zoneinfo *zp) {
+ ns_debug(ns_log_update, 3, "cancel_soa_update for %s", zp->z_origin);
+ zp->z_flags &= ~Z_NEED_SOAUPDATE;
+ zp->z_soaincrtime = 0;
+ zp->z_updatecnt = 0;
+}
+
+/*
+ * Figure out when a SOA serial number update should happen.
+ * Returns non-zero if the caller should call sched_zone_maint(zp).
+ */
+int
+schedule_soa_update(struct zoneinfo *zp, int numupdated) {
+ (void) gettime(&tt);
+
+ zp->z_flags |= Z_NEED_SOAUPDATE;
+
+ /*
+ * Only z_deferupdcnt updates are allowed before we force
+ * a serial update.
+ */
+ zp->z_updatecnt += numupdated;
+ if (zp->z_updatecnt >= zp->z_deferupdcnt) {
+ if (incr_serial(zp) < 0) {
+ ns_error(ns_log_update,
+ "error updating serial number for %s from %d",
+ zp->z_origin, zp->z_serial);
+ } else
+ return (0);
+ /*
+ * Note we continue scheduling if for some reason
+ * incr_serial fails.
+ */
+ }
+
+ if (zp->z_soaincrintvl > 0) {
+ /* We want automatic updates in this zone. */
+ if (zp->z_soaincrtime > 0) {
+ /* Already scheduled. */
+ ns_debug(ns_log_update, 3,
+ "schedule_soa_update('%s'): already scheduled",
+ zp->z_origin);
+ return (0);
+ } else {
+ /* First update since the soa was last incremented. */
+ zp->z_updatecnt = numupdated;
+ zp->z_soaincrtime = tt.tv_sec + zp->z_soaincrintvl;
+ /*
+ * Never schedule soaincrtime to occur after
+ * dumptime.
+ */
+ if (zp->z_soaincrtime > zp->z_dumptime)
+ zp->z_soaincrtime = zp->z_dumptime;
+ ns_debug(ns_log_update, 3,
+ "schedule_soa_update('%s'): scheduled for %lu",
+ zp->z_origin, (u_long)zp->z_soaincrtime);
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Figure out when a zone dump should happen.
+ * Returns non-zero if the caller should call sched_zone_maint(zp).
+ */
+int
+schedule_dump(struct zoneinfo *zp) {
+ time_t half;
+
+ (void) gettime(&tt);
+
+ zp->z_flags |= Z_NEED_DUMP;
+
+ if (zp->z_dumpintvl > 0) {
+ /* We want automatic dumping in this zone. */
+ if (zp->z_dumptime > 0) {
+ /* Already scheduled. */
+ ns_debug(ns_log_update, 3,
+ "schedule_dump('%s'): already scheduled",
+ zp->z_origin);
+ return (0);
+ } else {
+ /*
+ * Set new dump time for dynamic zone. Use a random
+ * number in the last half of the dump limit; we want
+ * it to be substantially correct while still
+ * preventing dump synchronization among various
+ * dynamic zones.
+ */
+ half = (zp->z_dumpintvl + 1) / 2;
+ zp->z_dumptime = tt.tv_sec + half + (rand() % half);
+ /*
+ * Never schedule soaincrtime to occur after
+ * dumptime.
+ */
+ if (zp->z_soaincrtime > zp->z_dumptime)
+ zp->z_soaincrtime = zp->z_dumptime;
+ ns_debug(ns_log_update, 3,
+ "schedule_dump('%s'): scheduled for %lu",
+ zp->z_origin, (u_long)zp->z_dumptime);
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * int
+ * process_prereq(rec, rcodep)
+ * Process one prerequisite.
+ * returns:
+ * >0 prerequisite was satisfied.
+ * =0 prerequisite was not satisfied, or an error occurred.
+ * side effects:
+ * sets *rcodep if an error occurs or prerequisite isn't satisfied.
+ */
+static int
+process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) {
+ const char *dname = ur->r_dname;
+ u_int16_t class = ur->r_class;
+ u_int16_t type = ur->r_type;
+ u_int32_t ttl = ur->r_ttl;
+ struct databuf *rdp = ur->r_dp;
+ const char *fname;
+ struct hashbuf *htp;
+ struct namebuf *np;
+ struct databuf *dp;
+
+ /*
+ * An element in the list might have already been
+ * processed if it is in the same RRset as a previous
+ * RRset Exists (value dependent) prerequisite.
+ */
+ if (rdp && (rdp->d_mark & D_MARK_FOUND) != 0) {
+ /* Already processed. */
+ return (1);
+ }
+ if (ttl != 0) {
+ ns_debug(ns_log_update, 1,
+ "process_prereq: ttl!=0 in prereq section");
+ *rcodep = FORMERR;
+ return (0);
+ }
+ htp = hashtab;
+ np = nlookup(dname, &htp, &fname, 0);
+ if (fname != dname)
+ np = NULL; /* Matching by wildcard not allowed here. */
+ if (class == C_ANY) {
+ if (rdp->d_size) {
+ ns_debug(ns_log_update, 1,
+ "process_prereq: empty rdata required in prereq section with class=ANY");
+ *rcodep = FORMERR;
+ return (0);
+ }
+ if (type == T_ANY) {
+ /* Name is in use. */
+ ur->r_opcode = YXDOMAIN;
+ if (np == NULL || np->n_data == NULL) {
+ /*
+ * Name does not exist or is
+ * an empty nonterminal.
+ */
+ ns_debug(ns_log_update, 1,
+ "process_prereq: %s not in use",
+ dname);
+ *rcodep = NXDOMAIN;
+ return (0);
+ }
+ } else {
+ /* RRset exists (value independent). */
+ int found = 0;
+
+ ur->r_opcode = YXRRSET;
+ if (np != NULL)
+ for (dp = np->n_data;
+ dp && !found;
+ dp = dp->d_next)
+ if (match(dp, class, type))
+ found = 1;
+ if (!found) {
+ ns_debug(ns_log_update, 1,
+ "process_prereq: RRset (%s,%s,%s) does not exist",
+ dname, p_type(type), p_class(zclass));
+ *rcodep = NXRRSET;
+ return (0);
+ }
+ }
+ } else if (class == C_NONE) {
+ if (rdp->d_size) {
+ ns_debug(ns_log_update, 1,
+ "process_prereq: empty rdata required in prereq section with class=NONE");
+ *rcodep = FORMERR;
+ return (0);
+ }
+ if (type == T_ANY) {
+ /* Name is not in use. */
+ ur->r_opcode = NXDOMAIN;
+ if (np != NULL && np->n_data != NULL) {
+ /*
+ * Name exists and is not an
+ * empty nonterminal.
+ */
+ ns_debug(ns_log_update, 1,
+ "process_prereq: %s exists",
+ dname);
+ *rcodep = YXDOMAIN;
+ return (0);
+ }
+ } else {
+ /* RRset does not exist. */
+ int found = 0;
+
+ ur->r_opcode = NXRRSET;
+ class = zclass;
+ if (np != NULL)
+ for (dp = np->n_data;
+ dp && !found;
+ dp = dp->d_next)
+ if (match(dp, class, type))
+ found = 1;
+ if (found) {
+ ns_debug(ns_log_update, 1,
+ "process_prereq: RRset (%s,%s) exists",
+ dname, p_type(type));
+ *rcodep = YXRRSET;
+ return (0);
+ }
+ }
+ } else if (class == zclass) {
+ /*
+ * RRset exists (value dependent).
+ *
+ * Check for RRset equality also.
+ */
+ ns_updrec *tmp;
+
+ ur->r_opcode = YXRRSET;
+ if (!rdp) {
+ ns_debug(ns_log_update, 1,
+ "process_prereq: nonempty rdata required in prereq section with class=%s",
+ p_class(class));
+ *rcodep = FORMERR;
+ return (0);
+ }
+ htp = hashtab;
+ np = nlookup(dname, &htp, &fname, 0);
+ if (np == NULL || fname != dname) {
+ *rcodep = NXRRSET;
+ return (0);
+ }
+ for (dp = np->n_data; dp; dp = dp->d_next) {
+ if (match(dp, class, type)) {
+ int found = 0;
+
+ for (tmp = ur;
+ tmp && !found;
+ tmp = tmp->r_next) {
+ if (tmp->r_section != S_PREREQ)
+ break;
+ if (!db_cmp(dp, tmp->r_dp)) {
+ tmp->r_dp->d_mark |=
+ D_MARK_FOUND;
+ found = 1;
+ }
+ }
+ if (!found) {
+ *rcodep = NXRRSET;
+ return (0);
+ }
+ }
+ }
+ for (tmp = ur; tmp; tmp = tmp->r_next)
+ if (tmp->r_section == S_PREREQ &&
+ !strcasecmp(dname, tmp->r_dname) &&
+ tmp->r_class == class &&
+ tmp->r_type == type &&
+ (ur->r_dp->d_mark & D_MARK_FOUND) == 0) {
+ *rcodep = NXRRSET;
+ return (0);
+ } else {
+ tmp->r_opcode = YXRRSET;
+ }
+ } else {
+ ns_debug(ns_log_update, 1,
+ "process_prereq: incorrect class %s",
+ p_class(class));
+ *rcodep = FORMERR;
+ return (0);
+ }
+ /* Through the gauntlet, and out. */
+ return (1);
+}
+
+/*
+ * int
+ * prescan_update(ur, rcodep)
+ * Process one prerequisite.
+ * returns:
+ * >0 update looks OK (format wise; who knows if it will succeed?)
+ * =0 update has something wrong with it.
+ * side effects:
+ * sets *rcodep if an error occurs or prerequisite isn't satisfied.
+ */
+static int
+prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) {
+ const char *dname = ur->r_dname;
+ u_int16_t class = ur->r_class;
+ u_int16_t type = ur->r_type;
+ u_int32_t ttl = ur->r_ttl;
+ struct databuf *rdp = ur->r_dp;
+ const char *fname;
+ struct hashbuf *htp;
+ struct namebuf *np;
+
+ if (class == zclass) {
+ if (type == T_ANY ||
+ type == T_AXFR || type == T_IXFR ||
+ type == T_MAILA || type == T_MAILB) {
+ ns_debug(ns_log_update, 1,
+ "prescan_update: invalid type (%s)",
+ p_type(type));
+ *rcodep = FORMERR;
+ return (0);
+ }
+ } else if (class == C_ANY) {
+ if (ttl != 0 || rdp->d_size ||
+ type == T_AXFR || type == T_IXFR ||
+ type == T_MAILA || type == T_MAILB) {
+ ns_debug(ns_log_update, 1,
+ "prescan_update: formerr(#2)");
+ *rcodep = FORMERR;
+ return (0);
+ }
+ } else if (class == C_NONE) {
+ if (ttl != 0 || type == T_ANY ||
+ type == T_AXFR || type == T_IXFR ||
+ type == T_MAILA || type == T_MAILB) {
+ ns_debug(ns_log_update, 1,
+ "prescan_update: formerr(#3)");
+ *rcodep = FORMERR;
+ return (0);
+ }
+ } else {
+ ns_debug(ns_log_update, 1,
+ "prescan_update: invalid class (%s)",
+ p_class(class));
+ *rcodep = FORMERR;
+ return (0);
+ }
+ /* No format errors found. */
+ return (1);
+}
+
+/*
+ * int
+ * process_updates(firstp, rcodep, from)
+ * Process prerequisites and apply updates from the list to the database.
+ * returns:
+ * number of successful updates, 0 if none were successful.
+ * side effects:
+ * *rcodep gets the transaction return code.
+ * can schedule maintainance for zone dumps and soa.serial# increments.
+ */
+static int
+process_updates(ns_updrec *firstp, int *rcodep, struct sockaddr_in from) {
+ int i, j, n, dbflags, matches, zonenum;
+ int numupdated = 0, soaupdated = 0, schedmaint = 0;
+ u_int16_t zclass;
+ ns_updrec *ur;
+ const char *fname;
+ struct databuf *dp, *savedp;
+ struct zoneinfo *zp;
+ int zonelist[MAXDNAME];
+
+ *rcodep = SERVFAIL;
+ if (!firstp)
+ return (0);
+ if (firstp->r_section == S_ZONE) {
+ zclass = firstp->r_class;
+ zonenum = firstp->r_zone;
+ zp = &zones[zonenum];
+ } else {
+ ns_debug(ns_log_update, 1,
+ "process_updates: missing zone record");
+ return (0);
+ }
+
+ /* Process prereq records and prescan update records. */
+ for (ur = firstp; ur != NULL; ur = ur->r_next) {
+ const char * dname = ur->r_dname;
+ u_int16_t class = ur->r_class;
+ u_int16_t type = ur->r_type;
+ u_int32_t ttl = ur->r_ttl;
+ struct databuf *rdp = ur->r_dp;
+ u_int section = ur->r_section;
+
+ ns_debug(ns_log_update, 3,
+"process_update: record section=%s, dname=%s, \
+class=%s, type=%s, ttl=%d, dp=0x%0x",
+ p_section(section, ns_o_update), dname,
+ p_class(class), p_type(type), ttl, rdp);
+
+ matches = findzone(dname, zclass, MAXDNAME,
+ zonelist, MAXDNAME);
+ ur->r_zone = 0;
+ for (j = 0; j < matches && !ur->r_zone; j++)
+ if (zonelist[j] == zonenum)
+ ur->r_zone = zonelist[j];
+ if (!ur->r_zone) {
+ ns_debug(ns_log_update, 1,
+ "process_updates: record does not belong to the zone %s",
+ zones[zonenum].z_origin);
+ *rcodep = NOTZONE;
+ return (0);
+ }
+
+ switch (section) {
+ case S_ZONE:
+ break;
+ case S_PREREQ:
+ if (!process_prereq(ur, rcodep, zclass))
+ return (0); /* *rcodep has been set. */
+ ns_debug(ns_log_update, 3, "prerequisite satisfied");
+ break;
+ case S_UPDATE:
+ if (!prescan_update(ur, rcodep, zclass))
+ return (0); /* *rcodep has been set. */
+ ns_debug(ns_log_update, 3, "update prescan succeeded");
+ break;
+ case S_ADDT:
+ break;
+ default:
+ ns_panic(ns_log_update, 1,
+ "process_updates: impossible section");
+ /* NOTREACHED */
+ }
+ }
+
+ /* Now process the records in update section. */
+ for (ur = firstp; ur != NULL; ur = ur->r_next) {
+ const char * dname = ur->r_dname;
+ u_int16_t class = ur->r_class;
+
+ if (ur->r_section != S_UPDATE)
+ continue;
+ dbflags = 0;
+ savedp = NULL;
+ dp = ur->r_dp;
+ if (class == zp->z_class) {
+ /* ADD databuf dp to hash table */
+ /*
+ * Handling of various SOA/WKS/CNAME scenarios
+ * is done in db_update().
+ */
+ ur->r_opcode = ADD;
+ dbflags |= DB_NODATA;
+ n = db_update(dname, dp, dp, &savedp,
+ dbflags, hashtab, from);
+ if (n != OK) {
+ ns_debug(ns_log_update, 3,
+ "process_updates: failed to add databuf (%d)",
+ n);
+ } else {
+ ns_debug(ns_log_update, 3,
+ "process_updates: added databuf 0x%0x",
+ dp);
+ dp->d_mark = D_MARK_ADDED;
+ numupdated++;
+ if (dp->d_type == T_SOA)
+ soaupdated = 1;
+ }
+ } else if (class == C_ANY || class == C_NONE) {
+ /*
+ * DELETE databuf's matching dp from the hash table.
+ *
+ * handling of various SOA/NS scenarios done
+ * in db_update().
+ */
+ ur->r_opcode = DELETE;
+ /*
+ * we know we're deleting now, and db_update won't
+ * match with class==C_NONE, so we use the zone's
+ * class.
+ */
+ if (class == C_NONE)
+ ur->r_dp->d_class = zp->z_class;
+ dbflags |= DB_DELETE;
+ n = db_update(dname, dp, NULL, &savedp,
+ dbflags, hashtab, from);
+ if (n != OK)
+ ns_debug(ns_log_update, 3,
+ "process_updates: delete failed");
+ else {
+ ns_debug(ns_log_update, 3,
+ "process_updates: delete succeeded");
+ numupdated++;
+ }
+ }
+ /*
+ * Even an addition could have caused some deletions like
+ * replacing old SOA or CNAME or WKS record or records of
+ * lower cred/clev.
+ *
+ * We need to save the deleted databuf's in case we wish to
+ * abort this update transaction and roll back all updates
+ * applied from this packet.
+ */
+ ur->r_deldp = savedp;
+ }
+
+ /*
+ * If we got here, things are OK, so set rcodep to indicate so.
+ */
+ *rcodep = NOERROR;
+
+ if (!numupdated)
+ return (0);
+
+ /*
+ * schedule maintenance for dumps and SOA.serial# increment
+ * (this also sets Z_NEED_DUMP and Z_NEED_SOAUPDATE appropriately)
+ */
+ schedmaint = 0;
+ if (schedule_dump(zp))
+ schedmaint = 1;
+ if (soaupdated) {
+ /*
+ * SOA updated by this update transaction, so
+ * we need to set the zone serial number, stop any
+ * automatic updates that may be pending, and send out
+ * a NOTIFY message.
+ */
+ zp->z_serial = get_serial_unchecked(zp);
+ cancel_soa_update(zp);
+ schedmaint = 1;
+#ifdef BIND_NOTIFY
+ sysnotify(zp->z_origin, zp->z_class, T_SOA);
+#endif
+ } else {
+ if (schedule_soa_update(zp, numupdated))
+ schedmaint = 1;
+ }
+ if (schedmaint)
+ sched_zone_maint(zp);
+ return (numupdated);
+}
+
+static enum req_action
+req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg,
+ struct qstream *qsp, int dfd, struct sockaddr_in from)
+{
+ char dnbuf[MAXDNAME], *dname;
+ u_int zocount, prcount, upcount, adcount, class, type, dlen;
+ u_int32_t ttl;
+ int i, n, cnt, found, matches, zonenum, numupdated = 0;
+ int rcode = NOERROR;
+ u_int c, section;
+ u_char rdata[MAXDATA];
+ struct qinfo *qp;
+ struct databuf *dp, *nsp[NSMAX];
+ struct databuf **nspp = &nsp[0];
+ struct zoneinfo *zp;
+ ns_updrec *rrecp;
+ int zonelist[MAXDNAME];
+ int should_use_tcp;
+ u_int32_t old_serial;
+
+ nsp[0] = NULL;
+
+ zocount = ntohs(hp->qdcount);
+ prcount = ntohs(hp->ancount);
+ upcount = ntohs(hp->nscount);
+ adcount = ntohs(hp->arcount);
+
+ /* Process zone section. */
+ ns_debug(ns_log_update, 3, "req_update: section ZONE, count %d",
+ zocount);
+ if ((n = dn_expand(msg, eom, cp, dnbuf, sizeof(dnbuf))) < 0) {
+ ns_debug(ns_log_update, 1, "req_update: expand name failed");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ dname = dnbuf;
+ cp += n;
+ if (cp + 2 * INT16SZ > eom) {
+ ns_debug(ns_log_update, 1, "req_update: too short");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ if (zocount != 1 || type != T_SOA) {
+ ns_debug(ns_log_update, 1,
+ "req_update: incorrect count or type for zone section: %d",
+ zocount);
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+
+ matches = findzone(dname, class, 0, zonelist, MAXDNAME);
+ if (matches == 1) {
+ zonenum = zonelist[0];
+ zp = &zones[zonenum];
+ old_serial = get_serial(zp);
+ if (zp->z_class != (int)class ||
+ (zp->z_type != z_master && zp->z_type != z_slave))
+ matches = 0;
+ }
+ if (matches != 1) {
+ ns_debug(ns_log_update, 1,
+ "req_update: non-authoritative server for %s",
+ dname);
+ hp->rcode = NOTAUTH;
+ return (Finish);
+ }
+
+ /*
+ * Begin Access Control Point
+ */
+
+ if (!ip_address_allowed(zp->z_update_acl, from.sin_addr)) {
+ ns_notice(ns_log_security, "unapproved update from %s for %s",
+ sin_ntoa(from), *dname ? dname : ".");
+ return (Refuse);
+ }
+
+ /*
+ * End Access Control Point
+ */
+
+ /* XXXVIX should check update key when we have one. */
+
+ /* we should be authoritative */
+ if (!(zp->z_flags & Z_AUTH)) {
+ ns_debug(ns_log_update, 1,
+ "req_update: zone %s: Z_AUTH not set",
+ dname);
+ hp->rcode = NOTAUTH;
+ return (Finish);
+ }
+
+ if (zp->z_type == Z_SECONDARY) {
+ /*
+ * XXX the code below is broken. Until fixed, we just
+ * refuse.
+ */
+ return (Refuse);
+
+ /* We are a slave for this zone, forward it to the master. */
+ for (cnt = 0; cnt < zp->z_addrcnt; cnt++)
+ *nspp++ = savedata(zp->z_class, T_A, USE_MINIMUM,
+ (u_char *)&zp->z_addr[cnt].s_addr,
+ INT32SZ);
+ *nspp = NULL;
+ /*
+ * If the request came in over TCP, forward it over TCP
+ */
+ should_use_tcp = (qsp != NULL);
+ n = ns_forw(nsp, msg, eom-msg, from, qsp, dfd, &qp,
+ dname, class, type, NULL, should_use_tcp);
+ free_nsp(nsp);
+ switch (n) {
+ case FW_OK:
+ case FW_DUP:
+ return (Return);
+ case FW_NOSERVER:
+ /* should not happen */
+ case FW_SERVFAIL:
+ hp->rcode = SERVFAIL;
+ return (Finish);
+ }
+ }
+ /*
+ * We are the primary master server for this zone,
+ * proceed further and process update packet
+ */
+ if (!(zp->z_flags & Z_DYNAMIC)) {
+ ns_debug(ns_log_update, 1,
+ "req_update: dynamic flag not set for zone %s",
+ dname);
+ return (Refuse);
+ }
+ ns_debug(ns_log_update, 3,
+ "req_update: update request for zone %s, class %s",
+ zp->z_origin, p_class(class));
+ rrecp_start = res_mkupdrec(S_ZONE, dname, class, type, 0);
+ rrecp_start->r_zone = zonenum;
+ rrecp_start->r_prev = NULL;
+ rrecp_start->r_next = NULL;
+ rrecp_last = rrecp_start;
+
+ /*
+ * Parse the prerequisite and update sections for format errors.
+ */
+ for (i = 0; (u_int)i < prcount + upcount; i++) {
+ if ((n = dn_expand(msg, eom, cp, dnbuf, sizeof(dnbuf))) < 0) {
+ ns_debug(ns_log_update, 1,
+ "req_update: expand name failed");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ dname = dnbuf;
+ cp += n;
+ if (cp + RRFIXEDSZ > eom) {
+ ns_debug(ns_log_update, 1,
+ "req_update: overrun in answer");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ GETSHORT(dlen, cp);
+ n = 0;
+ dp = NULL;
+ if (dlen > 0) {
+ if (cp + dlen > eom) {
+ ns_debug(ns_log_update, 1,
+ "req_update: bad dlen");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ n = rdata_expand(msg, eom, cp, type, dlen,
+ rdata, sizeof rdata);
+ if (n == 0 || n > MAXDATA) {
+ ns_debug(ns_log_update, 1,
+ "req_update: failed to expand record");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ cp += dlen;
+ }
+ section = ((u_int)i < prcount) ? S_PREREQ : S_UPDATE;
+ rrecp = res_mkupdrec(section, dname, class, type, ttl);
+ dp = savedata(class, type, ttl, rdata, n);
+ dp->d_zone = zonenum;
+ dp->d_cred = DB_C_ZONE;
+ dp->d_clev = nlabels(zp->z_origin);
+ /* XXX - also record in dp->d_ns, which host this came from */
+ rrecp->r_dp = dp;
+ /* Append the current record to the end of list of records. */
+ rrecp_last->r_next = rrecp;
+ rrecp->r_prev = rrecp_last;
+ rrecp->r_next = NULL;
+ rrecp_last = rrecp;
+ if (cp > eom) {
+ ns_info(ns_log_update,
+ "Malformed response from %s (overrun)",
+ inet_ntoa(from.sin_addr));
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ }
+
+ /* Now process all parsed records in the prereq and update sections. */
+ numupdated = process_updates(rrecp_start, &rcode, from);
+ hp->rcode = rcode;
+ if (numupdated <= 0) {
+ ns_error(ns_log_update,
+ "error processing update packet id %d from %s",
+ hp->id, sin_ntoa(from));
+ return (Finish);
+ }
+
+ /* Make a log of the update. */
+ (void) printupdatelog(from, rrecp_start, hp, zp, old_serial);
+
+ return (Finish);
+}
+
+static void
+free_rrecp(ns_updrec **startpp, ns_updrec **lastpp, int rcode,
+ struct sockaddr_in from)
+{
+ ns_updrec *rrecp, *first_rrecp, *next_rrecp;
+ struct databuf *dp, *tmpdp;
+ char *dname, *msg;
+
+ REQUIRE(startpp != NULL && lastpp != NULL);
+
+ if (rcode == NOERROR) {
+ first_rrecp = *startpp;
+ msg = "free_rrecp: update transaction succeeded, cleaning up";
+ } else {
+ first_rrecp = *lastpp;
+ msg = "free_rrecp: update transaction aborted, rolling back";
+ }
+ ns_debug(ns_log_update, 1, msg);
+ for (rrecp = first_rrecp; rrecp != NULL; rrecp = next_rrecp) {
+ if (rcode == NOERROR)
+ next_rrecp = rrecp->r_next;
+ else
+ next_rrecp = rrecp->r_prev;
+ if (rrecp->r_section != S_UPDATE) {
+ if (rrecp->r_dp)
+ db_freedata(rrecp->r_dp);
+ res_freeupdrec(rrecp);
+ continue;
+ }
+ dname = rrecp->r_dname;
+ dp = rrecp->r_dp;
+ if ((dp->d_mark & D_MARK_ADDED) != 0) {
+ if (rcode == NOERROR) {
+ /*
+ * This databuf is now a part of hashtab,
+ * or has been deleted by a subsequent update.
+ * Either way, we must not free it.
+ */
+ dp->d_mark &= ~D_MARK_ADDED;
+ } else {
+ /* Delete the databuf. */
+ if (db_update(dname, dp, NULL, NULL,
+ DB_DELETE, hashtab, from)
+ != OK) {
+ ns_error(ns_log_update,
+ "free_rrecp: failed to delete databuf: dname=%s, type=%s",
+ dname, p_type(dp->d_type));
+ } else {
+ ns_debug(ns_log_update, 3,
+ "free_rrecp: deleted databuf 0x%0x",
+ dp);
+ /*
+ * XXXRTH
+ *
+ * We used to db_freedata() here,
+ * but I removed it because 'dp' was
+ * part of a hashtab before we called
+ * db_update(), and since our delete
+ * has succeeded, it should have been
+ * freed.
+ */
+ }
+ }
+ } else {
+ /*
+ * Databuf's matching this were deleted by this
+ * update, or were never executed (because we bailed
+ * out early).
+ */
+ db_freedata(dp);
+ }
+
+ /* Process deleted databuf's. */
+ dp = rrecp->r_deldp;
+ while (dp != NULL) {
+ tmpdp = dp;
+ dp = dp->d_next;
+ if (rcode == NOERROR) {
+ if (tmpdp->d_rcnt)
+ ns_debug(ns_log_update, 1,
+ "free_rrecp: type = %d, rcnt = %d",
+ p_type(tmpdp->d_type),
+ tmpdp->d_rcnt);
+ else {
+ tmpdp->d_next = NULL;
+ db_freedata(tmpdp);
+ }
+ } else {
+ /* Add the databuf back. */
+ tmpdp->d_mark &= ~D_MARK_DELETED;
+ if (db_update(dname, tmpdp, tmpdp, NULL,
+ 0, hashtab, from) != OK) {
+ ns_error(ns_log_update,
+ "free_rrecp: failed to add back databuf: dname=%s, type=%s",
+ dname, p_type(tmpdp->d_type));
+ } else {
+ ns_debug(ns_log_update, 3,
+ "free_rrecp: added back databuf 0x%0x",
+ tmpdp);
+ }
+ }
+ }
+ res_freeupdrec(rrecp);
+ }
+ *startpp = NULL;
+ *lastpp = NULL;
+}
+
+enum req_action
+req_update(HEADER *hp, u_char *cp, u_char *eom, u_char *msg,
+ struct qstream *qsp, int dfd, struct sockaddr_in from)
+{
+ enum req_action ret;
+
+ ret = req_update_private(hp, cp, eom, msg, qsp, dfd, from);
+ free_rrecp(&rrecp_start, &rrecp_last, hp->rcode, from);
+ if (ret == Finish) {
+ hp->qdcount = hp->ancount = hp->nscount = hp->arcount = 0;
+ memset(msg + HFIXEDSZ, 0, (eom - msg) - HFIXEDSZ);
+ }
+ return (ret);
+}
+
+/*
+ * expand rdata portion of a compressed resource record at cp into cp1
+ * and return the length of the expanded rdata (length of the compressed
+ * rdata is "dlen").
+ */
+static int
+rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp,
+ u_int type, size_t dlen, u_char *cp1, size_t size)
+{
+ const u_char *cpinit = cp;
+ const u_char *cp1init = cp1;
+ int n, i;
+
+ switch (type) {
+ case T_A:
+ if (dlen != INT32SZ)
+ return (0);
+ /*FALLTHROUGH*/
+ case T_WKS:
+ case T_HINFO:
+ case T_TXT:
+ case T_X25:
+ case T_ISDN:
+ case T_NSAP:
+ case T_LOC:
+ if (size < dlen)
+ return (0);
+ memcpy(cp1, cp, dlen);
+ return (dlen);
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_NS:
+ case T_PTR:
+ n = dn_expand(msg, eom, cp, (char *)cp1, size);
+ if (n < 0 || (u_int)n != dlen)
+ return (0);
+ return (strlen((char *)cp1) + 1);
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ /* Get two compressed domain names. */
+ for (i = 0; i < 2; i++) {
+ n = dn_expand(msg, eom, cp, (char *)cp1, size);
+ if (n < 0)
+ return (0);
+ cp += n;
+ n = strlen((char *)cp1) + 1;
+ cp1 += n;
+ size -= n;
+ }
+ if (type == T_SOA) {
+ n = 5 * INT32SZ;
+ if (size < (size_t)n || cp + n > eom)
+ return(0);
+ size -= n;
+ memcpy(cp1, cp, n);
+ cp += n;
+ cp1 += n;
+ }
+ if (cp != cpinit + dlen)
+ return (0);
+ return (cp1 - cp1init);
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ case T_SRV:
+ /* Grab preference. */
+ if (size < INT16SZ || cp + INT16SZ > eom)
+ return (0);
+ size -= INT16SZ;
+ memcpy(cp1, cp, INT16SZ);
+ cp += INT16SZ;
+ cp1 += INT16SZ;
+
+ if (type == T_SRV) {
+ if (size < INT16SZ*2 || cp + INT16SZ*2 > eom)
+ return (0);
+ size -= INT16SZ*2;
+ /* Grab weight and port. */
+ memcpy(cp1, cp, INT16SZ*2);
+ cp1 += INT16SZ*2;
+ cp += INT16SZ*2;
+ }
+
+ /* Get name. */
+ n = dn_expand(msg, eom, cp, (char *)cp1, size);
+ if (n < 0)
+ return (0);
+ cp += n;
+ n = strlen((char *)cp1) + 1;
+ cp1 += n;
+ if (cp != cpinit + dlen)
+ return (0);
+ return (cp1 - cp1init);
+ case T_PX:
+ /* Grab preference. */
+ if (size < INT16SZ || cp + INT16SZ > eom)
+ return (0);
+ size -= INT16SZ;
+ memcpy(cp1, cp, INT16SZ);
+ cp += INT16SZ;
+ cp1 += INT16SZ;
+ /* Get MAP822 name. */
+ n = dn_expand(msg, eom, cp, (char *)cp1, size);
+ if (n < 0)
+ return (0);
+ cp += n;
+ n = strlen((char *)cp1) + 1;
+ cp1 += n;
+ size -= n;
+ n = dn_expand(msg, eom, cp, (char *)cp1, size);
+ if (n < 0)
+ return (0);
+ cp += n;
+ n = strlen((char *)cp1) + 1;
+ cp1 += n;
+ if (cp != cpinit + dlen)
+ return (0);
+ return (cp1 - cp1init);
+ default:
+ ns_debug(ns_log_update, 3, "unknown type %d", type);
+ return (0);
+ }
+}
+
+/*
+ * Print out rdata portion of a resource record from a databuf into a file.
+ *
+ * XXX - similar code in db_dump() should be replaced by a call to this
+ * function.
+ */
+void
+rdata_dump(struct databuf *dp, FILE *fp) {
+ u_int32_t n, addr;
+ u_char *cp, *end;
+ int i, j;
+ const char *proto;
+
+ cp = (u_char *)dp->d_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, ";\tNT=%d", dp->d_nstime);
+ 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. ( ", cp);
+#if defined(RETURNSOA) && defined(NCACHE)
+ if (dp->d_rcode == NXDOMAIN)
+ fputs(";", fp);
+#endif
+ cp += strlen((char *)cp) + 1;
+ GETLONG(n, cp);
+ fprintf(fp, "%u", n);
+ GETLONG(n, cp);
+ fprintf(fp, " %u", n);
+ GETLONG(n, cp);
+ fprintf(fp, " %u", n);
+ GETLONG(n, cp);
+ fprintf(fp, " %u", n);
+ GETLONG(n, cp);
+ fprintf(fp, " %u )", n);
+#if defined(RETURNSOA) && defined(NCACHE)
+ if (dp->d_rcode == NXDOMAIN)
+ fprintf(fp, ";%s.;NXDOMAIN;\t-$", cp);
+#endif
+ break;
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ GETSHORT(n, cp);
+ fprintf(fp, "%u", n);
+ fprintf(fp, " %s.", cp);
+ break;
+ case T_PX:
+ GETSHORT(n, cp);
+ fprintf(fp, "%u", 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);
+ }
+ }
+ /* XXXVIX need to keep the segmentation (see 4.9.5). */
+ (void) fputs("\"", fp);
+ break;
+ case T_NSAP:
+ (void) fputs(inet_nsap_ntoa(dp->d_size, dp->d_data, NULL), fp);
+ break;
+ case T_LOC:
+ (void) fputs(loc_ntoa(dp->d_data, NULL), fp);
+ break;
+ case T_WKS:
+ GETLONG(addr, cp);
+ addr = htonl(addr);
+ fputs(inet_ntoa(*(struct in_addr *)&addr), fp);
+ proto = protocolname((u_char)*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;
+ default:
+ fprintf(fp, "\t;?d_type=%d?", dp->d_type);
+ }
+}
+
+/*
+ * Return the number of authoritative zones that "dname" could belong to by
+ * stripping up to "depth" labels from dname. Up to the first "maxzones"
+ * authoritative zone numbers will be stored in "zonelist", ordered
+ * deepest match first.
+ */
+static int
+findzone(const char *dname, int class, int depth, int *zonelist, int maxzones){
+ char *tmpdname;
+ char tmpdnamebuf[MAXDNAME];
+ char *zonename, *cp;
+ int tmpdnamelen, zonenamelen, zonenum, i, j, c;
+ int matches = 0;
+ int escaped, found, done;
+
+ ns_debug(ns_log_update, 4, "findzone(dname=%s, class=%d, depth=%d, \
+zonelist=0x%x, maxzones=%d)",
+ dname, class, depth, zonelist, maxzones);
+#ifdef DEBUG
+ if (debug >= 5) {
+ ns_debug(ns_log_update, 5, "zone dump:");
+ for (zonenum = 1; zonenum < nzones; zonenum++)
+ printzoneinfo(zonenum, ns_log_update, 5);
+ }
+#endif
+
+ strcpy(tmpdnamebuf, dname);
+ tmpdname = tmpdnamebuf;
+ /*
+ * The code to handle trailing dots and escapes is adapted
+ * from samedomain().
+ */
+ tmpdnamelen = strlen(tmpdname);
+ /*
+ * Ignore a trailing label separator (i.e. an unescaped dot)
+ * in 'tmpdname'.
+ */
+ if (tmpdnamelen && tmpdname[tmpdnamelen-1] == '.') {
+ escaped = 0;
+ /* note this loop doesn't get executed if tmpdnamelen==1 */
+ for (j = tmpdnamelen - 2; j >= 0; j--)
+ if (tmpdname[j] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else {
+ break;
+ }
+ if (!escaped) {
+ tmpdnamelen--;
+ tmpdname[tmpdnamelen] = '\0';
+ }
+ }
+
+ for (done = i = 0; i <= depth && !done; i++) {
+ for (zonenum = 1; zonenum < nzones; zonenum++) {
+ if (zones[zonenum].z_type == z_nil)
+ continue;
+ if (zones[zonenum].z_class != class)
+ continue;
+ zonename = zones[zonenum].z_origin;
+ zonenamelen = strlen(zonename);
+ /*
+ * Ignore a trailing label separator
+ * (i.e. an unescaped dot) in 'zonename'.
+ */
+ if (zonenamelen && zonename[zonenamelen-1] == '.') {
+ escaped = 0;
+ for (j = zonenamelen - 2; j >= 0; j--)
+ if (zonename[j] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else {
+ break;
+ }
+ if (!escaped)
+ zonenamelen--;
+ }
+
+ if (tmpdnamelen != zonenamelen)
+ continue;
+ ns_debug(ns_log_update, 5,
+ "about to strncasecmp('%s', '%s', %d)",
+ tmpdname, zonename, tmpdnamelen);
+ /* XXXRTH I'm doing a special test for zonenamelen == 0
+ because I worry that some implementations of
+ strncasecmp might not handle comparisions where
+ n==0 correctly */
+ if (zonenamelen == 0 ||
+ !strncasecmp(tmpdname, zonename, tmpdnamelen)) {
+ ns_debug(ns_log_update, 5, "match");
+ zonelist[matches++] = zonenum;
+ if (matches == maxzones) {
+ /* XXX should signal error */
+ return (matches);
+ }
+ }
+ }
+
+ /*
+ * Strip off the first label if we're not already at
+ * the root label.
+ */
+ if (*tmpdname != '\0') {
+ for (escaped = found = 0;
+ (c = *tmpdname) && !found;
+ tmpdname++) {
+ if (!escaped && (c == '.'))
+ /*
+ * Note the loop increment will
+ * make tmpdname point past the '.'
+ * before the '!found' test causes
+ * us to exit the loop.
+ */
+ found = 1;
+
+ if (escaped)
+ escaped = 0;
+ else if (c == '\\')
+ escaped = 1;
+ }
+ } else
+ done = 1;
+
+ tmpdnamelen = strlen(tmpdname);
+ }
+ ns_debug(ns_log_update, 4,
+ "findzone: returning %d match(es)", matches);
+ return (matches);
+}
+
+/*
+ * reapply lost updates from log file for the zone to the zone
+ *
+ * returns -1 on error, 0 on success, 1 if dump reload needed
+ */
+int
+merge_logs(struct zoneinfo *zp) {
+ char origin[MAXDNAME], data[MAXDATA], dnbuf[MAXDNAME], sclass[3];
+ char buf[BUFSIZ], buf2[100];
+ FILE *fp;
+ u_int32_t serial, ttl, old_serial, new_serial;
+ char *dname, *cp, *cp1;
+ int type, class;
+ int i, c, section, opcode, matches, zonenum, err, multiline;
+ int nonempty_lineno = -1, prev_pktdone = 0, cont = 0, inside_next = 0;
+ int id, rcode = NOERROR;
+ u_int32_t n;
+ struct map *mp;
+ ns_updrec *rrecp;
+ struct databuf *dp;
+ struct in_addr ina;
+ int zonelist[MAXDNAME];
+ struct stat st;
+ u_char *serialp;
+ struct sockaddr_in empty_from;
+ int datasize;
+
+ empty_from.sin_family = AF_INET;
+ empty_from.sin_addr.s_addr = htonl(INADDR_ANY);
+ empty_from.sin_port = htons(0);
+
+ /* XXX - much of this stuff is similar to that in nsupdate.c
+ * getword_str() was used in nsupdate.c for reasons described there
+ * getword() is used here just to be consistent with db_load()
+ */
+
+ /* If there is no log file, just return. */
+ if (stat(zp->z_updatelog, &st) < 0) {
+ if (errno != ENOENT)
+ ns_error(ns_log_update,
+ "unexpected stat(%s) failure: %s",
+ zp->z_updatelog, strerror(errno));
+ return (-1);
+ }
+ fp = fopen(zp->z_updatelog, "r");
+ if (fp == NULL) {
+ ns_error(ns_log_update, "fopen(%s) failed: %s",
+ zp->z_updatelog, strerror(errno));
+ return (-1);
+ }
+
+ /*
+ * See if we really have a log file -- it might be a zone dump
+ * that was in the process of being renamed, or it might
+ * be garbage!
+ */
+
+ if (fgets(buf, sizeof(buf), fp)==NULL) {
+ ns_error(ns_log_update, "fgets() from %s failed: %s",
+ zp->z_updatelog, strerror(errno));
+ fclose(fp);
+ return (-1);
+ }
+ if (strcmp(buf, DumpSignature) == 0) {
+ /* It's a dump; finish rename that was interrupted. */
+ ns_info(ns_log_update,
+ "completing interrupted dump rename for %s",
+ zp->z_source);
+ if (rename(zp->z_updatelog, zp->z_source) < 0) {
+ ns_error(ns_log_update, "rename(%s,%s) failed: %s",
+ zp->z_updatelog, zp->z_source,
+ strerror(errno));
+ return (-1);
+ }
+ fclose(fp);
+ /* Finally, tell caller to reload zone. */
+ return (1);
+ }
+ if (strcmp(buf, LogSignature) != 0) {
+ /* Not a dump and not a log; complain and then bail out. */
+ ns_error(ns_log_update, "invalid log file %s",
+ zp->z_updatelog);
+ fclose(fp);
+ return (-1);
+ }
+
+ ns_debug(ns_log_update, 3, "merging logs for %s from %s",
+ zp->z_origin, zp->z_updatelog);
+ lineno = 1;
+ rrecp_start = NULL;
+ rrecp_last = NULL;
+ for (;;) {
+ if (!getword(buf, sizeof buf, fp, 0)) {
+ if (lineno == (nonempty_lineno + 1)) {
+ /*
+ * End of a nonempty line inside an update
+ * packet or not inside an update packet.
+ */
+ continue;
+ }
+ /*
+ * Empty line or EOF.
+ *
+ * Marks completion of current update packet.
+ */
+ inside_next = 0;
+ prev_pktdone = 1;
+ cont = 1;
+ } else {
+ nonempty_lineno = lineno;
+ }
+
+ if (!strcasecmp(buf, "[DYNAMIC_UPDATE]")) {
+ err = 0;
+ rcode = NOERROR;
+ cp = fgets(buf, sizeof buf, fp);
+ if (cp != NULL)
+ lineno++;
+ if (cp == NULL || !sscanf((char *)cp, "id %d", &id))
+ id = -1;
+ inside_next = 1;
+ prev_pktdone = 1;
+ cont = 1;
+ } else if (!strcasecmp(buf, "[INCR_SERIAL]")) {
+ /* XXXRTH not enough error checking here */
+ cp = fgets(buf, sizeof buf, fp);
+ if (cp != NULL)
+ lineno++;
+ if (cp == NULL ||
+ !sscanf((char *)cp, "from %u to %u",
+ &old_serial, &new_serial)) {
+ ns_error(ns_log_update,
+ "incr_serial problem with %s",
+ zp->z_updatelog);
+ } else {
+ serial = get_serial(zp);
+ if (serial != old_serial) {
+ ns_error(ns_log_update,
+ "serial number mismatch (log=%u, zone=%u) in %s", old_serial,
+ serial, zp->z_updatelog);
+ } else {
+ set_serial(zp, new_serial);
+ /*
+ * The zone has changed; make sure
+ * a dump is scheduled.
+ */
+ (void)schedule_dump(zp);
+ sched_zone_maint(zp);
+ ns_info(ns_log_update,
+ "set serial to %u (log file %s)",
+ new_serial, zp->z_updatelog);
+ }
+ }
+ prev_pktdone = 1;
+ cont = 1;
+ }
+ if (prev_pktdone) {
+ if (rrecp_start) {
+ n = process_updates(rrecp_start, &rcode,
+ empty_from);
+ if (n > 0)
+ ns_info(ns_log_update,
+ "successfully merged update id %d from log file %s",
+ id, zp->z_updatelog);
+ else
+ ns_error(ns_log_update,
+ "error merging update id %d from log file %s",
+ id, zp->z_updatelog);
+ free_rrecp(&rrecp_start, &rrecp_last, rcode,
+ empty_from);
+ }
+ prev_pktdone = 0;
+ if (feof(fp))
+ break;
+ }
+ if (cont) {
+ cont = 0;
+ continue;
+ }
+ if (!inside_next)
+ continue;
+ /*
+ * inside the same update packet,
+ * continue accumulating records.
+ */
+ section = -1;
+ n = strlen(buf);
+ if (buf[n-1] == ':')
+ buf[--n] = '\0';
+ for (mp = m_section; mp < m_section+M_SECTION_CNT; mp++)
+ if (!strcasecmp(buf, mp->token)) {
+ section = mp->val;
+ break;
+ }
+ ttl = 0;
+ type = -1;
+ class = zp->z_class;
+ n = 0;
+ data[0] = '\0';
+ switch (section) {
+ case S_ZONE:
+ cp = fgets(buf, sizeof buf, fp);
+ if (!cp)
+ *buf = '\0';
+ n = sscanf(cp, "origin %s class %s serial %ul",
+ origin, sclass, &serial);
+ if (n != 3 || strcasecmp(origin, zp->z_origin))
+ err++;
+ if (cp)
+ lineno++;
+ if (!err && serial != zp->z_serial) {
+ ns_error(ns_log_update,
+ "serial number mismatch in update id %d (log=%u, zone=%u) in %s",
+ id, serial, zp->z_serial,
+ zp->z_updatelog);
+ inside_next = 0;
+ err++;
+ }
+ if (!err && inside_next) {
+ int success;
+
+ dname = origin;
+ type = T_SOA;
+ class = sym_ston(__p_class_syms, sclass,
+ &success);
+ if (!success) {
+ err++;
+ break;
+ }
+ matches = findzone(dname, class, 0,
+ zonelist, MAXDNAME);
+ if (matches)
+ zonenum = zonelist[0];
+ else
+ err++;
+ }
+ break;
+ case S_PREREQ:
+ case S_UPDATE:
+ /* Operation code. */
+ if (!getword(buf, sizeof buf, fp, 0)) {
+ err++;
+ break;
+ }
+ opcode = -1;
+ if (buf[0] == '{') {
+ n = strlen(buf);
+ for (i = 0; (u_int32_t)i < n; i++)
+ buf[i] = buf[i+1];
+ if (buf[n-2] == '}')
+ buf[n-2] = '\0';
+ }
+ for (mp = m_opcode; mp < m_opcode+M_OPCODE_CNT; mp++)
+ if (!strcasecmp(buf, mp->token)) {
+ opcode = mp->val;
+ break;
+ }
+ if (opcode == -1) {
+ err++;
+ break;
+ }
+ /* Owner's domain name. */
+ if (!getword((char *)dnbuf, sizeof dnbuf, fp, 0)) {
+ err++;
+ break;
+ }
+ n = strlen((char *)dnbuf) - 1;
+ if (dnbuf[n] == '.')
+ dnbuf[n] = '\0';
+ dname = dnbuf;
+ ttl = 0;
+ type = -1;
+ class = zp->z_class;
+ n = 0;
+ data[0] = '\0';
+ (void) getword(buf, sizeof buf, fp, 1);
+ if (isdigit(buf[0])) { /* ttl */
+ ttl = strtoul(buf, 0, 10);
+ if (errno == ERANGE && ttl == ULONG_MAX) {
+ err++;
+ break;
+ }
+ (void) getword(buf, sizeof buf, fp, 1);
+ }
+
+ /* possibly class */
+ if (buf[0] != '\0') {
+ int success;
+ int maybe_class;
+
+ maybe_class = sym_ston(__p_class_syms,
+ buf,
+ &success);
+ if (success) {
+ class = maybe_class;
+ (void) getword(buf,
+ sizeof buf,
+ fp, 1);
+ }
+ }
+ /* possibly type */
+ if (buf[0] != '\0') {
+ int success;
+ int maybe_type;
+
+ maybe_type = sym_ston(__p_type_syms,
+ buf,
+ &success);
+
+ if (success) {
+ type = maybe_type;
+ (void) getword(buf,
+ sizeof buf,
+ fp, 1);
+ }
+ }
+ if (buf[0] != '\0') /* possibly rdata */
+ /*
+ * Convert the ascii data 'buf' to the proper
+ * format based on the type and pack into
+ * 'data'.
+ *
+ * XXX - same as in db_load(),
+ * consolidation needed
+ */
+ switch (type) {
+ case T_A:
+ if (!inet_aton(buf, &ina)) {
+ err++;
+ break;
+ }
+ n = ntohl(ina.s_addr);
+ cp = data;
+ PUTLONG(n, cp);
+ n = INT32SZ;
+ break;
+ case T_HINFO:
+ case T_ISDN:
+ n = strlen(buf);
+ data[0] = n;
+ memcpy(data+1, buf, n);
+ n++;
+ if (!getword(buf, sizeof buf,
+ fp, 0)) {
+ i = 0;
+ } else {
+ endline(fp);
+ i = strlen(buf);
+ }
+ data[n] = i;
+ memcpy(data+n+1, buf, i);
+ break;
+ case T_SOA:
+ case T_MINFO:
+ case T_RP:
+ (void) strcpy(data, buf);
+ cp = data + strlen(data) + 1;
+ if (!getword((char *)cp,
+ sizeof data - (cp - data),
+ fp, 1)) {
+ err++;
+ break;
+ }
+ cp += strlen((char *)cp) + 1;
+ if (type != T_SOA) {
+ n = cp - data;
+ break;
+ }
+ if (class != zp->z_class ||
+ strcasecmp(dname, zp->z_origin)) {
+ err++;
+ break;
+ }
+ c = getnonblank(fp, zp->z_updatelog);
+ if (c == '(') {
+ multiline = 1;
+ } else {
+ multiline = 0;
+ ungetc(c, fp);
+ }
+ for (i = 0; i < 5; i++) {
+ n = getnum(fp, zp->z_updatelog,
+ GETNUM_SERIAL);
+ if (getnum_error) {
+ err++;
+ break;
+ }
+ PUTLONG(n, cp);
+ }
+ if (multiline &&
+ getnonblank(fp, zp->z_updatelog)
+ != ')') {
+ err++;
+ break;
+ }
+ endline(fp);
+ break;
+ case T_WKS:
+ if (!inet_aton(buf, &ina)) {
+ err++;
+ break;
+ }
+ n = ntohl(ina.s_addr);
+ cp = data;
+ PUTLONG(n, cp);
+ *cp = (char)getprotocol(fp,
+ zp->z_updatelog
+ );
+ n = INT32SZ + sizeof(char);
+ n = getservices((int)n, data,
+ fp, zp->z_updatelog);
+ break;
+ case T_NS:
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ (void) strcpy(data, buf);
+ if (makename(data, origin,
+ sizeof(data)) == -1) {
+ err++;
+ break;
+ }
+ n = strlen(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 */
+ cp = data;
+ PUTSHORT((u_int16_t)n, cp);
+ if (!getword(buf, sizeof(buf),
+ fp, 1)) {
+ err++;
+ break;
+ }
+ (void) strcpy((char *)cp, buf);
+ if (makename((char *)cp, origin,
+ sizeof(data) - (cp-data))
+ == -1) {
+ err++;
+ break;
+ }
+ /* advance pointer to end of data */
+ cp += strlen((char *)cp) +1;
+ /* now save length */
+ n = (cp - data);
+ break;
+ case T_PX:
+ n = 0;
+ data[0] = '\0';
+ cp = buf;
+ while (isdigit(*cp))
+ n = n * 10 + (*cp++ - '0');
+ cp = data;
+ PUTSHORT((u_int16_t)n, cp);
+ for (i = 0; i < 2; i++) {
+ if (!getword(buf,
+ sizeof(buf),
+ fp, 0)) {
+ err++;
+ break;
+ }
+ (void) strcpy((char *)cp,
+ buf);
+ cp += strlen((char *)cp) + 1;
+ }
+ n = cp - data;
+ break;
+ case T_TXT:
+ case T_X25:
+ i = strlen(buf);
+ cp = data;
+ datasize = sizeof data;
+ cp1 = buf;
+ while (i > 255) {
+ if (datasize < 256) {
+ ns_error(ns_log_update,
+ "record too big");
+ return (-1);
+ }
+ datasize -= 255;
+ *cp++ = 255;
+ memcpy(cp, cp1, 255);
+ cp += 255;
+ cp1 += 255;
+ i -= 255;
+ }
+ if (datasize < i + 1) {
+ ns_error(ns_log_update,
+ "record too big");
+ return (-1);
+ }
+ *cp++ = i;
+ memcpy(cp, cp1, i);
+ cp += i;
+ n = cp - data;
+ endline(fp);
+ /* XXXVIX: segmented texts 4.9.5 */
+ break;
+ case T_NSAP:
+ n = inet_nsap_addr(buf,
+ (u_char *)data,
+ sizeof data);
+ endline(fp);
+ break;
+ 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')
+ ungetc(*cp, fp);
+ *cp = '\0';
+ n = loc_aton(buf, (u_char *)data);
+ if (n == 0) {
+ err++;
+ break;
+ }
+ endline(fp);
+ break;
+ default:
+ err++;
+ }
+ if (section == S_PREREQ) {
+ ttl = 0;
+ if (opcode == NXDOMAIN) {
+ class = C_NONE;
+ type = T_ANY;
+ n = 0;
+ } else if (opcode == YXDOMAIN) {
+ class = C_ANY;
+ type = T_ANY;
+ n = 0;
+ } else if (opcode == NXRRSET) {
+ class = C_NONE;
+ n = 0;
+ } else if (opcode == YXRRSET) {
+ if (n == 0)
+ class = C_ANY;
+ }
+ } else { /* section == S_UPDATE */
+ if (opcode == DELETE) {
+ if (n == 0) {
+ class = C_ANY;
+ if (type == -1)
+ type = T_ANY;
+ } else {
+ class = C_NONE;
+ }
+ }
+ }
+ break;
+ case S_ADDT:
+ default:
+ ns_debug(ns_log_update, 1,
+ "cannot interpret section: %d", section);
+ inside_next = 0;
+ err++;
+ }
+ if (err) {
+ inside_next = 0;
+ ns_debug(ns_log_update, 1,
+ "merge of update id %d failed due to error at line %d",
+ id, lineno);
+ free_rrecp(&rrecp_start, &rrecp_last, rcode,
+ empty_from);
+ continue;
+ }
+ rrecp = res_mkupdrec(section, dname, class, type, ttl);
+ if (section != S_ZONE) {
+ dp = savedata(class, type, ttl, (u_char *)data, n);
+ dp->d_zone = zonenum;
+ dp->d_cred = DB_C_ZONE;
+ dp->d_clev = nlabels(zp->z_origin);
+ rrecp->r_dp = dp;
+ } else {
+ rrecp->r_zone = zonenum;
+ }
+ if (rrecp_start == NULL) {
+ rrecp_start = rrecp;
+ rrecp_last = rrecp;
+ rrecp->r_prev = NULL;
+ rrecp->r_next = NULL;
+ } else {
+ rrecp_last->r_next = rrecp;
+ rrecp->r_prev = rrecp_last;
+ rrecp->r_next = NULL;
+ rrecp_last = rrecp;
+ }
+ } /* for (;;) */
+
+ fclose(fp);
+ return (0);
+}
+
+
+/*
+ * Create a disk database to back up zones
+ */
+int
+zonedump(zp)
+ struct zoneinfo *zp;
+{
+ FILE *fp;
+ const char *fname;
+ struct hashbuf *htp;
+ char *op;
+ struct stat st;
+ char tmp_name[MAXPATHLEN];
+ int escaped;
+ char c;
+
+ /*
+ * We must check to see if Z_NEED_SOAUPDATE is set, and if so
+ * we must do it. This won't be the case normally
+ * (when called from ns_maint()), but it is possible if we're
+ * exiting named.
+ */
+
+ if (zp->z_flags & Z_NEED_SOAUPDATE) {
+ u_int32_t serial, old_serial;
+
+ old_serial = get_serial(zp);
+ serial = old_serial + 1;
+ if (serial == 0)
+ serial = 1;
+ set_serial(zp, serial);
+ }
+
+ /* Only dump zone if there is a cache specified */
+ if (zp->z_source && *(zp->z_source)) {
+ ns_debug(ns_log_update, 1, "zonedump(%s)", zp->z_source);
+
+ if (strlen(zp->z_source)+strlen(DumpSuffix) >= MAXPATHLEN) {
+ ns_error(ns_log_update,
+ "filename %s too long in zonedump",
+ zp->z_source);
+ /*
+ * This problem won't ever get better, so we
+ * clear the "need dump" flag.
+ */
+ zp->z_flags &= ~Z_NEED_DUMP;
+ return (-1);
+ }
+ (void)sprintf(tmp_name, "%s%s", zp->z_source, DumpSuffix);
+ if ((fp = write_open(tmp_name)) == NULL) {
+ ns_error(ns_log_update, "fopen() of %s failed: %s",
+ tmp_name, strerror(errno));
+ return (-1);
+ }
+ fprintf(fp, "%s", DumpSignature);
+ op = zp->z_origin;
+ escaped = 0;
+ while (*op && (((c = *op++) != '.') || escaped))
+ escaped = (c == '\\') && !escaped;
+ gettime(&tt);
+ htp = hashtab;
+ if (nlookup(zp->z_origin, &htp, &fname, 0) != NULL) {
+ if (db_dump(htp, fp, zp-zones, op) != OK) {
+ ns_error(ns_log_update,
+ "error dumping zone file %s",
+ zp->z_source);
+ (void)fclose(fp);
+ return (-1);
+ }
+ }
+ if (fflush(fp) == EOF) {
+ ns_error(ns_log_update, "fflush() of %s failed: %s",
+ tmp_name, strerror(errno));
+ return (-1);
+ }
+ if (fsync(fileno(fp)) < 0) {
+ ns_error(ns_log_update, "fsync() of %s failed: %s",
+ tmp_name, strerror(errno));
+ return (-1);
+ }
+ if (fclose(fp) == EOF) {
+ ns_error(ns_log_update, "fclose() of %s failed: %s",
+ tmp_name, strerror(errno));
+ return (-1);
+ }
+ /*
+ * Try to make read only, so people will be less likely to
+ * edit dynamic domains.
+ */
+ if (stat(tmp_name, &st) < 0) {
+ ns_error(ns_log_update,
+ "stat(%s) failed, pressing on: %s",
+ tmp_name, strerror(errno));
+ } else {
+ zp->z_ftime = st.st_mtime;
+ st.st_mode &= ~WRITEABLE_MASK;
+ if (chmod(tmp_name, st.st_mode) < 0)
+ ns_error(ns_log_update,
+ "chmod(%s,%o) failed, pressing on: %s",
+ tmp_name, st.st_mode,
+ strerror(errno));
+ }
+ if (rename(tmp_name, zp->z_updatelog) < 0) {
+ ns_error(ns_log_update, "rename(%s,%s) failed: %s",
+ tmp_name, zp->z_updatelog, strerror(errno));
+ return (-1);
+ }
+ if (rename(zp->z_updatelog, zp->z_source) < 0) {
+ ns_error(ns_log_update, "rename(%s,%s) failed: %s",
+ zp->z_updatelog, zp->z_source,
+ strerror(errno));
+ return (-1);
+ }
+ } else
+ ns_debug(ns_log_update, 1, "zonedump: no zone to dump");
+
+ zp->z_flags &= ~Z_NEED_DUMP;
+ zp->z_dumptime = 0;
+ return (0);
+}
+
+struct databuf *
+findzonesoa(struct zoneinfo *zp) {
+ struct hashbuf *htp;
+ struct namebuf *np;
+ struct databuf *dp;
+ const char *fname;
+
+ htp = hashtab;
+ np = nlookup(zp->z_origin, &htp, &fname, 0);
+ if (np == NULL || fname != zp->z_origin)
+ return (NULL);
+ foreach_rr(dp, np, T_SOA, zp->z_class, zp - zones)
+ return (dp);
+ return (NULL);
+}
+
+u_char *
+findsoaserial(u_char *data) {
+ char *cp = (char *)data;
+
+ cp += strlen(cp) + 1; /* Nameserver. */
+ cp += strlen(cp) + 1; /* Mailbox. */
+ return ((u_char *)cp);
+}
+
+u_int32_t
+get_serial_unchecked(struct zoneinfo *zp) {
+ struct databuf *dp;
+ u_char *cp;
+ u_int32_t ret;
+
+ dp = findzonesoa(zp);
+ if (!dp)
+ ns_panic(ns_log_update, 1,
+ "get_serial_unchecked(%s): can't locate zone SOA",
+ zp->z_origin);
+ cp = findsoaserial(dp->d_data);
+ GETLONG(ret, cp);
+ return (ret);
+}
+
+u_int32_t
+get_serial(struct zoneinfo *zp) {
+ u_int32_t ret;
+
+ ret = get_serial_unchecked(zp);
+ if (ret != zp->z_serial)
+ ns_panic(ns_log_update, 1,
+ "get_serial(%s): db and zone serial numbers differ",
+ zp->z_origin);
+ return (ret);
+}
+
+void
+set_serial(struct zoneinfo *zp, u_int32_t serial) {
+ struct databuf *dp;
+ u_char *cp;
+
+ dp = findzonesoa(zp);
+ if (!dp)
+ ns_panic(ns_log_update, 1,
+ "set_serial(%s): can't locate zone SOA",
+ zp->z_origin);
+ cp = findsoaserial(dp->d_data);
+ PUTLONG(serial, cp);
+ zp->z_serial = serial;
+ zp->z_flags &= ~Z_NEED_SOAUPDATE;
+ zp->z_soaincrtime = 0;
+ zp->z_updatecnt = 0;
+#ifdef BIND_NOTIFY
+ sysnotify(zp->z_origin, zp->z_class, T_SOA);
+#endif
+ /*
+ * Note: caller is responsible for scheduling a dump
+ */
+}
+
+/*
+ * Increment serial number in zoneinfo structure and hash table SOA databuf
+ */
+
+int
+incr_serial(struct zoneinfo *zp) {
+ u_int32_t serial, old_serial;
+ FILE *fp;
+ time_t t;
+
+ old_serial = get_serial(zp);
+ serial = old_serial + 1;
+ if (serial == 0)
+ serial = 1;
+ set_serial(zp, serial);
+
+ (void) gettime(&tt);
+ t = (time_t)tt.tv_sec;
+ fp = open_transaction_log(zp);
+ if (fp == NULL)
+ return (-1);
+ fprintf(fp, "[INCR_SERIAL] from %u to %u %s\n",
+ old_serial, serial, checked_ctime(&t));
+ if (close_transaction_log(zp, fp)<0)
+ return (-1);
+
+ /*
+ * This shouldn't happen, but we check to be sure.
+ */
+ if (!(zp->z_flags & Z_NEED_DUMP)) {
+ ns_warning(ns_log_update,
+ "incr_serial: Z_NEED_DUMP not set for zone '%s'",
+ zp->z_origin);
+ (void)schedule_dump(zp);
+ }
+
+ sched_zone_maint(zp);
+
+ return (0);
+}
+
+void
+dynamic_about_to_exit(void) {
+ struct zoneinfo *zp;
+
+ ns_debug(ns_log_update, 1,
+ "shutting down; dumping zones that need it");
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ if ((zp->z_flags & Z_DYNAMIC) &&
+ ((zp->z_flags & Z_NEED_SOAUPDATE) ||
+ (zp->z_flags & Z_NEED_DUMP)))
+ (void)zonedump(zp);
+ }
+}
diff --git a/contrib/bind/bin/named/ns_xfr.c b/contrib/bind/bin/named/ns_xfr.c
new file mode 100644
index 0000000..52d3464
--- /dev/null
+++ b/contrib/bind/bin/named/ns_xfr.c
@@ -0,0 +1,642 @@
+#if !defined(lint) && !defined(SABER)
+static char rcsid[] = "$Id: ns_xfr.c,v 8.25 1998/03/25 18:47:34 halley Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+static struct qs_x_lev *sx_freelev(struct qs_x_lev *lev);
+
+static void sx_newmsg(struct qstream *qsp),
+ sx_sendlev(struct qstream *qsp),
+ sx_sendsoa(struct qstream *qsp);
+
+static int sx_flush(struct qstream *qsp),
+ sx_addrr(struct qstream *qsp,
+ const char *dname,
+ struct databuf *dp),
+ sx_nsrrs(struct qstream *qsp),
+ sx_allrrs(struct qstream *qsp),
+ sx_pushlev(struct qstream *qsp, struct namebuf *np);
+
+/*
+ * void
+ * ns_xfr(qsp, znp, zone, class, type, opcode, id)
+ * Initiate a concurrent (event driven) outgoing zone transfer.
+ */
+void
+ns_xfr(struct qstream *qsp, struct namebuf *znp,
+ int zone, int class, int type,
+ int opcode, int id)
+{
+ FILE *rfp;
+ int fdstat;
+ pid_t pid;
+ server_info si;
+#ifdef SO_SNDBUF
+ static const int sndbuf = XFER_BUFSIZE * 2;
+#endif
+#ifdef SO_SNDLOWAT
+ static const int sndlowat = XFER_BUFSIZE;
+#endif
+
+ ns_info(ns_log_xfer_out, "zone transfer of \"%s\" (%s) to %s",
+ zones[zone].z_origin, p_class(class), sin_ntoa(qsp->s_from));
+
+#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
+#ifdef SO_SNDLOWAT
+ /*
+ * We don't want select() to show writability 'til we can write
+ * an XFER_BUFSIZE block of data.
+ */
+ (void) setsockopt(qsp->s_rfd, SOL_SOCKET, SO_SNDLOWAT,
+ (char *)&sndlowat, sizeof sndlowat);
+#endif
+ if (sq_openw(qsp, 64*1024) == -1)
+ goto abort;
+ memset(&qsp->xfr, 0, sizeof qsp->xfr);
+ qsp->xfr.top = znp;
+ qsp->xfr.zone = zone;
+ qsp->xfr.class = class;
+ qsp->xfr.id = id;
+ qsp->xfr.opcode = opcode;
+ qsp->xfr.msg = memget(XFER_BUFSIZE);
+ if (!qsp->xfr.msg)
+ goto abort;
+ qsp->xfr.eom = qsp->xfr.msg + XFER_BUFSIZE;
+ qsp->xfr.cp = NULL;
+ qsp->xfr.state = s_x_firstsoa;
+ zones[zone].z_numxfrs++;
+ qsp->flags |= STREAM_AXFR;
+
+ si = find_server(qsp->s_from.sin_addr);
+ if (si != NULL && si->transfer_format != axfr_use_default)
+ qsp->xfr.transfer_format = si->transfer_format;
+ else
+ qsp->xfr.transfer_format = server_options->transfer_format;
+
+ if (sx_pushlev(qsp, znp) < 0) {
+ abort:
+ (void) shutdown(qsp->s_rfd, 2);
+ sq_remove(qsp);
+ return;
+ }
+ (void) sq_writeh(qsp, sx_sendsoa);
+}
+
+/*
+ * void
+ * ns_stopxfrs(zp)
+ * Stop (abort, reset) all transfers of the zone specified by 'zp'.
+ */
+void
+ns_stopxfrs(struct zoneinfo *zp) {
+ struct qstream *this, *next;
+ u_int zone = (u_int)(zp - zones);
+
+ for (this = streamq; this; this = next) {
+ next = this->s_next;
+ if (this->xfr.zone == zone) {
+ (void) shutdown(this->s_rfd, 2);
+ sq_remove(this);
+ }
+ }
+ INSIST(zp->z_numxfrs == 0);
+}
+
+/*
+ * void
+ * ns_freexfr(qsp)
+ * Free all xfr-related dynamic data associated with qsp.
+ */
+void
+ns_freexfr(struct qstream *qsp) {
+ if (qsp->xfr.msg != NULL) {
+ memput(qsp->xfr.msg, XFER_BUFSIZE);
+ qsp->xfr.msg = NULL;
+ }
+ while (qsp->xfr.lev)
+ qsp->xfr.lev = sx_freelev(qsp->xfr.lev);
+ zones[qsp->xfr.zone].z_numxfrs--;
+ qsp->flags &= ~STREAM_AXFR;
+}
+
+/*
+ * u_char *
+ * renew_msg(msg)
+ * init the header of a message, reset the compression pointers, and
+ * reset the write pointer to the first byte following the header.
+ */
+static void
+sx_newmsg(struct qstream *qsp) {
+ HEADER *hp = (HEADER *)qsp->xfr.msg;
+
+ memset(hp, 0, HFIXEDSZ);
+ hp->id = htons(qsp->xfr.id);
+ hp->opcode = qsp->xfr.opcode;
+ hp->qr = 1;
+ hp->rcode = NOERROR;
+
+ qsp->xfr.ptrs[0] = qsp->xfr.msg;
+ qsp->xfr.ptrs[1] = NULL;
+
+ qsp->xfr.cp = qsp->xfr.msg + HFIXEDSZ;
+}
+
+/*
+ * int
+ * sx_flush(qsp)
+ * flush the intermediate buffer out to the stream IO system.
+ * return:
+ * passed through from sq_write().
+ */
+static int
+sx_flush(struct qstream *qsp) {
+ int ret;
+
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_nquery(qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg,
+ log_get_stream(packet_channel));
+#endif
+ ret = sq_write(qsp, qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg);
+ if (ret >= 0)
+ qsp->xfr.cp = NULL;
+ return (ret);
+}
+
+/*
+ * int
+ * sx_addrr(qsp, name, dp)
+ * add name/dp's RR to the current assembly message. if it won't fit,
+ * write current message out, renew the message, and then RR should fit.
+ * return:
+ * -1 = the sx_flush() failed so we could not queue the full message.
+ * 0 = one way or another, everything is fine.
+ * side effects:
+ * on success, the ANCOUNT is incremented and the pointers are advanced.
+ */
+static int
+sx_addrr(struct qstream *qsp, const char *dname, struct databuf *dp) {
+ HEADER *hp = (HEADER *)qsp->xfr.msg;
+ u_char **edp = qsp->xfr.ptrs + sizeof qsp->xfr.ptrs / sizeof(u_char*);
+ int n;
+
+ if (qsp->xfr.cp != NULL) {
+ if (qsp->xfr.transfer_format == axfr_one_answer &&
+ sx_flush(qsp) < 0)
+ return (-1);
+ }
+ if (qsp->xfr.cp == NULL)
+ sx_newmsg(qsp);
+ n = make_rr(dname, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp,
+ 0, qsp->xfr.ptrs, edp);
+ if (n < 0) {
+ if (sx_flush(qsp) < 0)
+ return (-1);
+ if (qsp->xfr.cp == NULL)
+ sx_newmsg(qsp);
+ n = make_rr(dname, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp,
+ 0, qsp->xfr.ptrs, edp);
+ INSIST(n >= 0);
+ }
+ hp->ancount = htons(ntohs(hp->ancount) + 1);
+ qsp->xfr.cp += n;
+ return (0);
+}
+
+/*
+ * int
+ * sx_soarr(qsp)
+ * add the SOA RR's at the current level's top np to the assembly message.
+ * return:
+ * 0 = success
+ * -1 = write buffer full, cannot continue at this time
+ * side effects:
+ * if progress was made, header and pointers will be advanced.
+ */
+static int
+sx_soarr(struct qstream *qsp) {
+ struct databuf *dp;
+
+ foreach_rr(dp, qsp->xfr.top, T_SOA, qsp->xfr.class, qsp->xfr.zone) {
+ if (sx_addrr(qsp, zones[qsp->xfr.zone].z_origin, dp) < 0) {
+ /* RR wouldn't fit. Bail out. */
+ return (-1);
+ }
+ return (0);
+ }
+ ns_panic(ns_log_xfer_out, 1, "no SOA at zone top");
+}
+
+/*
+ * int
+ * sx_nsrrs(qsp)
+ * add the NS RR's at the current level's current np,
+ * to the assembly message
+ * return:
+ * >1 = number of NS RRs added, note that there may be more
+ * 0 = success, there are no more NS RRs at this level
+ * -1 = write buffer full, cannot continue at this time
+ * side effects:
+ * if progress was made, header and pointers will be advanced.
+ * note:
+ * this is meant for AXFR, which includes glue as part of the answer
+ * sections. this is different from and incompatible with the additional
+ * data of a referral response.
+ */
+static int
+sx_nsrrs(struct qstream *qsp) {
+ struct databuf *dp, *tdp, *gdp;
+ struct namebuf *gnp, *tnp, *top;
+ struct hashbuf *htp;
+ const char *fname;
+ int rrcount, class;
+
+ class = qsp->xfr.class;
+ top = qsp->xfr.top;
+ rrcount = 0;
+ for ((void)NULL;
+ (dp = qsp->xfr.lev->dp) != NULL;
+ qsp->xfr.lev->dp = dp->d_next) {
+ /* XYZZY foreach_rr? */
+ if (dp->d_class != class && class != C_ANY)
+ continue;
+ if (dp->d_rcode)
+ continue;
+ /*
+ * It might not be in the same zone, if we are authoritative
+ * for both parent and child, but it does have to be a zone.
+ *
+ * XXX: this is sort of a bug, since it means we merge the
+ * @ NS RRset into our parent's zone. But that is what
+ * db_load() does, so for now we have no choice.
+ */
+ if (dp->d_zone == DB_Z_CACHE)
+ continue;
+ if (dp->d_type != T_NS)
+ continue;
+ if (!(qsp->xfr.lev->flags & SXL_GLUING)) {
+ if (sx_addrr(qsp, qsp->xfr.lev->dname, dp) < 0) {
+ /* RR wouldn't fit. Bail out. */
+ return (-1);
+ }
+ rrcount++;
+ }
+
+ /*
+ * 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;
+ gnp = nlookup((char *)dp->d_data, &htp, &fname, 0);
+ if (gnp == NULL || fname != (char *)dp->d_data)
+ continue;
+ for (tnp = gnp;
+ tnp != NULL && tnp != top;
+ tnp = tnp->n_parent)
+ (void)NULL;
+ 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) {
+ foreach_rr(tdp, tnp, T_NS, class, DB_Z_CACHE)
+ break;
+ /* If we found a zone cut, we're outta here. */
+ if (tdp != NULL)
+ break;
+ }
+ /* If name server is not in a delegated zone, skip it. */
+ if (tnp == top || (tnp == NULL && NAME(*top)[0] == '\0'))
+ continue;
+ /* Now we know glue records are needed. Send them. */
+ qsp->xfr.lev->flags |= SXL_GLUING;
+ foreach_rr(gdp, gnp, T_A, class, DB_Z_CACHE)
+ if (sx_addrr(qsp, fname, gdp) < 0) {
+ /*
+ * Rats. We already sent the NS RR, too.
+ * Note that SXL_GLUING is being left on.
+ */
+ return (-1);
+ }
+ qsp->xfr.lev->flags &= ~SXL_GLUING;
+ }
+ return (rrcount);
+}
+
+/*
+ * int
+ * sx_allrrs(qsp)
+ * add the non-(SOA,NS) RR's at the current level's current np,
+ * to the assembly message
+ * return:
+ * >0 = number of RR's added, note that there may be more
+ * 0 = success, there are no more RRs at this level
+ * -1 = write buffer full, cannot continue at this time
+ * side effects:
+ * if progress was made, header and pointers will be advanced.
+ * note:
+ * this is meant for AXFR, which includes glue as part of the answer
+ * sections. this is different from and incompatible with the additional
+ * data of a referral response.
+ */
+static int
+sx_allrrs(struct qstream *qsp) {
+ struct databuf *dp, *tdp, *gdp;
+ struct namebuf *gnp, *tnp, *top;
+ struct hashbuf *htp;
+ const char *fname;
+ int rrcount, class;
+ u_int zone;
+
+ class = qsp->xfr.class;
+ top = qsp->xfr.top;
+ zone = qsp->xfr.zone;
+ rrcount = 0;
+ for ((void)NULL;
+ (dp = qsp->xfr.lev->dp) != NULL;
+ qsp->xfr.lev->dp = dp->d_next) {
+ /* XYZZY foreach_rr? */
+ if (dp->d_class != class && class != C_ANY)
+ continue;
+ if (dp->d_rcode)
+ continue;
+ if (dp->d_zone != zone || stale(dp))
+ continue;
+ if (dp->d_type == T_SOA || dp->d_type == T_NS)
+ continue;
+ /* XXXRTH I presume this is still relevant and that
+ this is the right place... */
+#if 0 /* Not yet implemented. Only a SHOULD in the I-D. -gnu@toad.com */
+ /* skip the SIG AXFR record because we did it first too. */
+ if (dp->d_type == T_SIG) {
+ int sig_rrtype = GETSHORT (dp->d_data);
+ if (sig_rrtype == T_AXFR)
+ continue;
+ }
+#endif /* 0 */
+ INSIST(!(qsp->xfr.lev->flags & SXL_GLUING));
+
+ if (sx_addrr(qsp, qsp->xfr.lev->dname, dp) < 0) {
+ /* RR wouldn't fit. Bail out. */
+ return (-1);
+ }
+ rrcount++;
+ }
+ return (rrcount);
+}
+
+/*
+ * void
+ * sx_sendlev(qsp)
+ * send all the RRs at the current level (really a domain name), and
+ * do a decomposed recursion to get all subdomains up to and including
+ * but not exceeding bottom zone cuts.
+ * side effects:
+ * advances qsp->xfr pointers. changes qsp->xfr.lev quite often.
+ * causes messages to be sent to a remote TCP client. changes the
+ * qsp->xfr.state at the end of the topmost level. changes the
+ * qsp->xfr.lev->state several times per domain name.
+ */
+static void
+sx_sendlev(struct qstream *qsp) {
+ struct qs_x_lev *lev;
+ int rrcount;
+
+ again:
+ lev = qsp->xfr.lev;
+ switch (lev->state) {
+ case sxl_ns: {
+ while (lev->dp) {
+ rrcount = sx_nsrrs(qsp);
+ /* If we can't pack this one in, come back later. */
+ if (rrcount < 0)
+ return;
+ /*
+ * NS RRs other than those at the
+ * zone top are zone cuts.
+ */
+ if (rrcount > 0 && qsp->xfr.top != lev->np)
+ lev->flags |= SXL_ZONECUT;
+ }
+ /* No more DP's for the NS RR pass on this NP. */
+ if (lev->flags & SXL_ZONECUT) {
+ /* Zone cut, so go directly to end of level. */
+ break;
+ }
+ /* No NS RR's, so it's safe to send other types. */
+ lev->state = sxl_all;
+ lev->dp = lev->np->n_data;
+ goto again;
+ }
+ case sxl_all: {
+ while (lev->dp) {
+ /* If we can't pack this one in, come back later. */
+ if (sx_allrrs(qsp) < 0)
+ return;
+ }
+ /* No more non-NS DP's for this NP, do subdomains. */
+ lev->state = sxl_sub;
+ goto again;
+ }
+ case sxl_sub: {
+ struct namebuf *np;
+
+ /* Get next in-use hash chain if we're not following one. */
+ while (lev->nnp == NULL) {
+ /* If no, or no more subdomains, end of level. */
+ if (lev->npp == NULL || lev->npp == lev->npe)
+ break;
+ lev->nnp = *lev->npp++;
+ }
+ /* If we encountered the end of the level, we're outta here. */
+ if ((np = lev->nnp) == NULL)
+ break;
+ /* Next time, we'll do the following NP, or the next chain. */
+ lev->nnp = np->n_next;
+ /* Skip our own NP if it appears as a subdom (as in root). */
+ if (np != lev->np)
+ sx_pushlev(qsp, np);
+ goto again;
+ }
+ default:
+ abort();
+ }
+
+ /* End of level. Pop it off the stack. */
+
+ if ((qsp->xfr.lev = sx_freelev(lev)) == NULL) {
+ /* End of topmost level. */
+ qsp->xfr.state = s_x_lastsoa;
+ sq_writeh(qsp, sx_sendsoa);
+ return;
+ }
+ goto again;
+}
+
+/*
+ * void
+ * sx_sendsoa(qsp)
+ * send either the first or last SOA needed for an AXFR.
+ * side effects:
+ * changes qsp->xfr.state. adds RR to output buffer.
+ */
+static void
+sx_sendsoa(struct qstream *qsp) {
+ if (sx_soarr(qsp) == -1)
+ return; /* No state change, come back here later. */
+
+ switch (qsp->xfr.state) {
+ case s_x_firstsoa: {
+ /* Next thing to do is send the zone. */
+ qsp->xfr.state = s_x_zone;
+ sq_writeh(qsp, sx_sendlev);
+ break;
+ }
+ case s_x_lastsoa: {
+ /* Next thing to do is go back and wait for another query. */
+ (void)sx_flush(qsp);
+ qsp->xfr.state = s_x_done;
+ sq_writeh(qsp, sq_flushw);
+ break;
+ }
+ default: {
+ ns_panic(ns_log_xfer_out, 1,
+ "unexpected state %d in sx_sendsoa", qsp->xfr.state);
+ }
+ }
+}
+
+/* int
+ * sx_pushlev(qsp, np)
+ * manage the decomposed recursion. set up for a new level (domain).
+ * returns:
+ * 0 = success
+ * -1 = failure (check errno)
+ */
+static int
+sx_pushlev(struct qstream *qsp, struct namebuf *np) {
+ struct qs_x_lev *new = memget(sizeof *new);
+ struct hashbuf *htp;
+
+ if (!new) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ memset(new, 0, sizeof *new);
+ new->state = sxl_ns;
+ new->np = np;
+ new->dp = np->n_data;
+ getname(np, new->dname, sizeof new->dname);
+ /*
+ * 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 = ((new->dname[0] == '\0') ? hashtab : np->n_hash);
+ if (htp) {
+ new->npp = htp->h_tab;
+ new->npe = htp->h_tab + htp->h_size;
+ } else {
+ new->npp = NULL;
+ new->npe = NULL;
+ }
+ new->nnp = NULL;
+ new->next = qsp->xfr.lev;
+ qsp->xfr.lev = new;
+ return (0);
+}
+
+/*
+ * qs_x_lev *
+ * sx_freelev(lev)
+ * free the memory occupied by a level descriptor
+ * return:
+ * pointer to "next" level descriptor
+ */
+static struct qs_x_lev *
+sx_freelev(struct qs_x_lev *lev) {
+ struct qs_x_lev *next = lev->next;
+
+ memput(lev, sizeof *lev);
+ return (next);
+}
diff --git a/contrib/bind/bin/named/pathnames.c b/contrib/bind/bin/named/pathnames.c
new file mode 100644
index 0000000..2ba2415
--- /dev/null
+++ b/contrib/bind/bin/named/pathnames.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/*
+ * $Id: pathnames.c,v 8.5 1997/05/21 19:52:28 halley Exp $
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+int
+main(int argc, char *argv[], char *envp[]) {
+ char *arg;
+
+ argc--, argv++;
+ while (argc-- && (arg = *argv++) != NULL)
+ if (!strcasecmp("_PATH_XFER", arg))
+ puts(_PATH_XFER);
+ else if (!strcasecmp("_PATH_PIDFILE", arg))
+ puts(_PATH_PIDFILE);
+ else if (!strcasecmp("_PATH_NAMED", arg))
+ puts(_PATH_NAMED);
+ else
+ exit(1);
+ exit(0);
+}
diff --git a/contrib/bind/bin/named/pathtemplate.h b/contrib/bind/bin/named/pathtemplate.h
new file mode 100644
index 0000000..d339ef8
--- /dev/null
+++ b/contrib/bind/bin/named/pathtemplate.h
@@ -0,0 +1,70 @@
+/*
+ * $Id: pathtemplate.h,v 8.1 1998/03/19 19:53:21 halley Exp $
+ */
+
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#include <paths.h>
+
+#ifndef _PATH_CONF
+#define _PATH_CONF "%DESTETC%/named.conf"
+#endif
+
+#ifndef _PATH_DEBUG
+#define _PATH_DEBUG "named.run"
+#endif
+
+#ifndef _PATH_DUMPFILE
+#define _PATH_DUMPFILE "named_dump.db"
+#endif
+
+#ifndef _PATH_NAMED
+#define _PATH_NAMED "%DESTSBIN%/named"
+#endif
+
+#ifndef _PATH_PIDFILE
+#define _PATH_PIDFILE "%DESTRUN%/named.pid"
+#endif
+
+#ifndef _PATH_STATS
+#define _PATH_STATS "named.stats"
+#endif
+
+#ifndef _PATH_MEMSTATS
+#define _PATH_MEMSTATS "named.memstats"
+#endif
+
+#ifndef _PATH_TMPXFER
+#define _PATH_TMPXFER "xfer.ddt.XXXXXX"
+#endif
+
+#ifndef _PATH_XFER
+#define _PATH_XFER "%DESTEXEC%/named-xfer"
+#endif
+
+#ifndef _PATH_XFERTRACE
+#define _PATH_XFERTRACE "xfer.trace"
+#endif
+
+#ifndef _PATH_XFERDDT
+#define _PATH_XFERDDT "xfer.ddt"
+#endif
+
+#ifndef _PATH_DEVNULL
+#define _PATH_DEVNULL "/dev/null"
+#endif
diff --git a/contrib/bind/bin/named/test/127.0.0.zone b/contrib/bind/bin/named/test/127.0.0.zone
new file mode 100644
index 0000000..b9b7bf5
--- /dev/null
+++ b/contrib/bind/bin/named/test/127.0.0.zone
@@ -0,0 +1,11 @@
+$ORIGIN 0.0.127.in-addr.arpa.
+
+@ 1D IN SOA localhost. root.localhost. (
+ 42 ; serial (d. adams)
+ 3H ; refresh
+ 15M ; retry
+ 1W ; expiry
+ 1D ) ; minimum
+
+ 1D IN NS localhost.
+1 1D IN PTR localhost.
diff --git a/contrib/bind/bin/named/test/localhost.zone b/contrib/bind/bin/named/test/localhost.zone
new file mode 100644
index 0000000..ad5e68e
--- /dev/null
+++ b/contrib/bind/bin/named/test/localhost.zone
@@ -0,0 +1,10 @@
+$ORIGIN localhost.
+@ 1D IN SOA @ root (
+ 42 ; serial (d. adams)
+ 3H ; refresh
+ 15M ; retry
+ 1W ; expiry
+ 1D ) ; minimum
+
+ 1D IN NS @
+ 1D IN A 127.0.0.1
diff --git a/contrib/bind/bin/named/test/named.conf b/contrib/bind/bin/named/test/named.conf
new file mode 100644
index 0000000..b852604
--- /dev/null
+++ b/contrib/bind/bin/named/test/named.conf
@@ -0,0 +1,29 @@
+// This is a configuration file for named (from BIND 8.1 or later).
+// It would normally be installed as /etc/named.conf.
+
+options {
+// directory "/var/named";
+ check-names master warn; /* default. */
+ datasize 20M;
+};
+
+zone "localhost" IN {
+ type master;
+ file "localhost.zone";
+ check-names fail;
+ allow-update { none; };
+ allow-transfer { any; };
+};
+
+zone "0.0.127.in-addr.arpa" IN {
+ type master;
+ file "127.0.0.zone";
+ check-names fail;
+ allow-update { none; };
+ allow-transfer { any; };
+};
+
+zone "." IN {
+ type hint;
+ file "root.hint";
+};
diff --git a/contrib/bind/bin/named/test/root.hint b/contrib/bind/bin/named/test/root.hint
new file mode 100644
index 0000000..0b8f372
--- /dev/null
+++ b/contrib/bind/bin/named/test/root.hint
@@ -0,0 +1,37 @@
+
+; <<>> DiG 2.2 <<>> @192.5.5.241
+; (1 server found)
+;; res options: init recurs defnam dnsrch
+;; got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10
+;; flags: qr aa rd; QUERY: 1, ANSWER: 9, AUTHORITY: 0, ADDITIONAL: 9
+;; QUERY SECTION:
+;; ., type = NS, class = IN
+
+;; ANSWER SECTION:
+. 6D IN NS C.ROOT-SERVERS.NET.
+. 6D IN NS D.ROOT-SERVERS.NET.
+. 6D IN NS E.ROOT-SERVERS.NET.
+. 6D IN NS I.ROOT-SERVERS.NET.
+. 6D IN NS F.ROOT-SERVERS.NET.
+. 6D IN NS G.ROOT-SERVERS.NET.
+. 6D IN NS A.ROOT-SERVERS.NET.
+. 6D IN NS H.ROOT-SERVERS.NET.
+. 6D IN NS B.ROOT-SERVERS.NET.
+
+;; ADDITIONAL SECTION:
+C.ROOT-SERVERS.NET. 5w6d16h IN A 192.33.4.12
+D.ROOT-SERVERS.NET. 5w6d16h IN A 128.8.10.90
+E.ROOT-SERVERS.NET. 5w6d16h IN A 192.203.230.10
+I.ROOT-SERVERS.NET. 5w6d16h IN A 192.36.148.17
+F.ROOT-SERVERS.NET. 5w6d16h IN A 192.5.5.241
+G.ROOT-SERVERS.NET. 5w6d16h IN A 192.112.36.4
+A.ROOT-SERVERS.NET. 5w6d16h IN A 198.41.0.4
+H.ROOT-SERVERS.NET. 5w6d16h IN A 128.63.2.53
+B.ROOT-SERVERS.NET. 5w6d16h IN A 128.9.0.107
+
+;; Total query time: 8 msec
+;; FROM: wisdom.home.vix.com to SERVER: 192.5.5.241
+;; WHEN: Fri Nov 22 00:08:05 1996
+;; MSG SIZE sent: 17 rcvd: 312
+
diff --git a/contrib/bind/bin/named/version.c b/contrib/bind/bin/named/version.c
new file mode 100644
index 0000000..9468be2
--- /dev/null
+++ b/contrib/bind/bin/named/version.c
@@ -0,0 +1,89 @@
+/*
+ * @(#)Version.c 4.9 (Berkeley) 7/21/90
+ * $Id: version.c,v 8.2 1997/04/24 23:59:02 vixie Exp $
+ */
+
+#ifndef lint
+char sccsid[] = "@(#)named %VERSION% %WHEN% %WHOANDWHERE%";
+char rcsid[] = "$Id: version.c,v 8.2 1997/04/24 23:59:02 vixie Exp $";
+#endif /* not lint */
+
+char Version[] = "named %VERSION% %WHEN%\n\t%WHOANDWHERE%";
+char ShortVersion[] = "%VERSION%";
+
+#ifdef COMMENT
+
+SCCS/s.Version.c:
+
+D 4.8.3 90/06/27 17:05:21 bloom 37 35 00031/00028/00079
+Version distributed with 4.3 Reno tape (June 1990)
+
+D 4.8.2 89/09/18 13:57:11 bloom 35 34 00020/00014/00087
+Interim fixes release
+
+D 4.8.1 89/02/08 17:12:15 karels 34 33 00026/00017/00075
+branch for 4.8.1
+
+D 4.8 88/07/09 14:27:00 karels 33 28 00043/00031/00049
+4.8 is here!
+
+D 4.7 87/11/20 13:15:52 karels 25 24 00000/00000/00062
+4.7.3 beta
+
+D 4.6 87/07/21 12:15:52 karels 25 24 00000/00000/00062
+4.6 declared stillborn
+
+D 4.5 87/02/10 12:33:25 kjd 24 18 00000/00000/00062
+February 1987, Network Release. Child (bind) grows up, parent (kevin) leaves home.
+
+D 4.4 86/10/01 10:06:26 kjd 18 12 00020/00017/00042
+October 1, 1986 Network Distribution
+
+D 4.3 86/06/04 12:12:18 kjd 12 7 00015/00028/00044
+Version distributed with 4.3BSD
+
+D 4.2 86/04/30 20:57:16 kjd 7 1 00056/00000/00016
+Network distribution Freeze and one more version until 4.3BSD
+
+D 1.1 86/04/30 19:30:00 kjd 1 0 00016/00000/00000
+date and time created 86/04/30 19:30:00 by kjd
+
+code versions:
+
+Makefile
+ Makefile 4.14 (Berkeley) 2/28/88
+db.h
+ db.h 4.13 (Berkeley) 2/17/88
+db_dump.c
+ db_dump.c 4.20 (Berkeley) 2/17/88
+db_load.c
+ db_load.c 4.26 (Berkeley) 2/28/88
+db_lookup.c
+ db_lookup.c 4.14 (Berkeley) 2/17/88
+db_reload.c
+ db_reload.c 4.15 (Berkeley) 2/28/88
+db_save.c
+ db_save.c 4.13 (Berkeley) 2/17/88
+db_update.c
+ db_update.c 4.16 (Berkeley) 2/28/88
+ns_forw.c
+ ns_forw.c 4.26 (Berkeley) 3/28/88
+ns_init.c
+ ns_init.c 4.23 (Berkeley) 2/28/88
+ns_main.c
+ Copyright (c) 1986 Regents of the University of California.\n\
+ ns_main.c 4.30 (Berkeley) 3/7/88
+ns_maint.c
+ ns_maint.c 4.23 (Berkeley) 2/28/88
+ns_req.c
+ ns_req.c 4.32 (Berkeley) 3/31/88
+ns_resp.c
+ ns_resp.c 4.50 (Berkeley) 4/7/88
+ns_sort.c
+ ns_sort.c 4.3 (Berkeley) 2/17/88
+ns_stats.c
+ ns_stats.c 4.3 (Berkeley) 2/17/88
+newvers.sh
+ newvers.sh 4.4 (Berkeley) 3/28/88
+
+#endif /* COMMENT */
OpenPOWER on IntegriCloud