summaryrefslogtreecommitdiffstats
path: root/contrib/bind/bin
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1999-11-30 02:43:11 +0000
committerpeter <peter@FreeBSD.org>1999-11-30 02:43:11 +0000
commit9716636318d4160418baceabe7ba05ce065692fc (patch)
tree486664278b935f789477f5f876359d7b1f743529 /contrib/bind/bin
parentdc618593bdb400692edd72ab5a4296a7e33ed5e2 (diff)
parent4ef23ce6957fc75fc005885496d605fed48213e1 (diff)
downloadFreeBSD-src-9716636318d4160418baceabe7ba05ce065692fc.zip
FreeBSD-src-9716636318d4160418baceabe7ba05ce065692fc.tar.gz
This commit was generated by cvs2svn to compensate for changes in r53910,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'contrib/bind/bin')
-rw-r--r--contrib/bind/bin/Makefile19
-rw-r--r--contrib/bind/bin/addr/Makefile25
-rw-r--r--contrib/bind/bin/addr/addr.c11
-rw-r--r--contrib/bind/bin/dig/Makefile27
-rw-r--r--contrib/bind/bin/dig/dig.c707
-rw-r--r--contrib/bind/bin/dnskeygen/Makefile85
-rw-r--r--contrib/bind/bin/dnskeygen/dnskeygen.c318
-rw-r--r--contrib/bind/bin/dnsquery/Makefile25
-rw-r--r--contrib/bind/bin/dnsquery/dnsquery.c56
-rw-r--r--contrib/bind/bin/host/Makefile25
-rw-r--r--contrib/bind/bin/host/host.c867
-rw-r--r--contrib/bind/bin/irpd/Makefile98
-rw-r--r--contrib/bind/bin/irpd/irpd.c2252
-rw-r--r--contrib/bind/bin/irpd/irs-irpd.conf11
-rw-r--r--contrib/bind/bin/irpd/version.c25
-rw-r--r--contrib/bind/bin/mkservdb/Makefile83
-rw-r--r--contrib/bind/bin/mkservdb/mkservdb.c169
-rw-r--r--contrib/bind/bin/named-bootconf/Grot/named-bootconf.pl324
-rw-r--r--contrib/bind/bin/named-bootconf/Makefile76
-rw-r--r--contrib/bind/bin/named-bootconf/named-bootconf.sh306
-rw-r--r--contrib/bind/bin/named-xfer/Makefile31
-rw-r--r--contrib/bind/bin/named/db_defs.h108
-rw-r--r--contrib/bind/bin/named/db_dump.c64
-rw-r--r--contrib/bind/bin/named/db_func.h98
-rw-r--r--contrib/bind/bin/named/db_glob.h33
-rw-r--r--contrib/bind/bin/named/db_glue.c318
-rw-r--r--contrib/bind/bin/named/db_ixfr.c861
-rw-r--r--contrib/bind/bin/named/db_load.c1750
-rw-r--r--contrib/bind/bin/named/db_lookup.c106
-rw-r--r--contrib/bind/bin/named/db_save.c26
-rw-r--r--contrib/bind/bin/named/db_sec.c1097
-rw-r--r--contrib/bind/bin/named/db_tsig.c158
-rw-r--r--contrib/bind/bin/named/db_update.c141
-rw-r--r--contrib/bind/bin/named/named.conf41
-rw-r--r--contrib/bind/bin/named/named.h24
-rw-r--r--contrib/bind/bin/named/ns_config.c1153
-rw-r--r--contrib/bind/bin/named/ns_ctl.c866
-rw-r--r--contrib/bind/bin/named/ns_defs.h272
-rw-r--r--contrib/bind/bin/named/ns_forw.c367
-rw-r--r--contrib/bind/bin/named/ns_func.h214
-rw-r--r--contrib/bind/bin/named/ns_glob.h41
-rw-r--r--contrib/bind/bin/named/ns_glue.c58
-rw-r--r--contrib/bind/bin/named/ns_init.c240
-rw-r--r--contrib/bind/bin/named/ns_ixfr.c563
-rw-r--r--contrib/bind/bin/named/ns_lexer.c95
-rw-r--r--contrib/bind/bin/named/ns_lexer.h8
-rw-r--r--contrib/bind/bin/named/ns_main.c1027
-rw-r--r--contrib/bind/bin/named/ns_maint.c901
-rw-r--r--contrib/bind/bin/named/ns_ncache.c156
-rw-r--r--contrib/bind/bin/named/ns_notify.c379
-rw-r--r--contrib/bind/bin/named/ns_parser.y637
-rw-r--r--contrib/bind/bin/named/ns_parseutil.c6
-rw-r--r--contrib/bind/bin/named/ns_parseutil.h8
-rw-r--r--contrib/bind/bin/named/ns_req.c843
-rw-r--r--contrib/bind/bin/named/ns_resp.c1749
-rw-r--r--contrib/bind/bin/named/ns_signal.c264
-rw-r--r--contrib/bind/bin/named/ns_sort.c410
-rw-r--r--contrib/bind/bin/named/ns_stats.c83
-rw-r--r--contrib/bind/bin/named/ns_udp.c5
-rw-r--r--contrib/bind/bin/named/ns_update.c959
-rw-r--r--contrib/bind/bin/named/ns_xfr.c302
-rw-r--r--contrib/bind/bin/named/pathtemplate.h8
-rw-r--r--contrib/bind/bin/named/test/named.conf16
-rw-r--r--contrib/bind/bin/named/version.c4
-rw-r--r--contrib/bind/bin/ndc/Makefile50
-rw-r--r--contrib/bind/bin/ndc/ndc.c698
-rw-r--r--contrib/bind/bin/nslookup/Makefile27
-rw-r--r--contrib/bind/bin/nslookup/list.c127
-rw-r--r--contrib/bind/bin/nslookup/res.h7
-rw-r--r--contrib/bind/bin/nslookup/send.c62
-rw-r--r--contrib/bind/bin/nslookup/skip.c4
-rw-r--r--contrib/bind/bin/nslookup/subr.c136
-rw-r--r--contrib/bind/bin/nsupdate/Makefile25
-rw-r--r--contrib/bind/bin/nsupdate/nsupdate.c282
74 files changed, 19661 insertions, 3756 deletions
diff --git a/contrib/bind/bin/Makefile b/contrib/bind/bin/Makefile
index b330286..ffe01a3 100644
--- a/contrib/bind/bin/Makefile
+++ b/contrib/bind/bin/Makefile
@@ -1,4 +1,4 @@
-## Copyright (c) 1996 by Internet Software Consortium
+## Copyright (c) 1996,1999 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
@@ -13,7 +13,7 @@
## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
## SOFTWARE.
-# $Id: Makefile,v 8.17 1998/03/20 00:40:13 halley Exp $
+# $Id: Makefile,v 8.27 1999/08/08 17:13:24 vixie Exp $
DESTDIR=
CC= cc
@@ -33,32 +33,35 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include
LEX = lex -I
YACC = yacc
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
+AR= ar cru
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
LDFLAGS=
MARGS = "SYSTYPE=${SYSTYPE}" "SHELL=${SHELL}" "A=${A}" "O=${O}" \
"CC=${CC}" "LEX=${LEX}" "YACC=${YACC}" "CDEBUG=${CDEBUG}" \
"SYSLIBS=${SYSLIBS}" "LDFLAGS=${LDFLAGS}" \
- "DESTDIR=${DESTDIR}" "PIDDIR=${PIDDIR}" "DESTMAN=${DESTMAN}" \
+ "DESTDIR=${DESTDIR}" "DESTMAN=${DESTMAN}" \
"DESTBIN=${DESTBIN}" "DESTSBIN=${DESTSBIN}" "DESTEXEC=${DESTEXEC}" \
"DESTLIB=${DESTLIB}" "DESTINC=${DESTINC}" "DESTETC=${DESTETC}" \
"DESTRUN=${DESTRUN}" "DESTHELP=${DESTHELP}" \
"RANLIB=${RANLIB}" "AR=${AR}" "ARPREF=${ARPREF}" "ARSUFF=${ARSUFF}" \
- "INCL=../${INCL}" "PORTINCL=../${PORTINCL}" \
+ "INCL=../${INCL}" "PORTINCL=../${PORTINCL}" "EXE=${EXE}" \
"LIBBIND=../${LIBBIND}" "LIBPORT=../${LIBPORT}" \
"INSTALL=${INSTALL}" "CPPFLAGS=${CPPFLAGS}" "TOP=../${TOP}" \
- "VER=${VER}" "STRIP=${STRIP}" "PS=${PS}"
+ "VER=${VER}" "STRIP=${STRIP}" "PS=${PS}" "INSTALL_LIB=${INSTALL_LIB}" \
+ "INSTALL_EXEC=${INSTALL_EXEC}" "BOUNDS=${BOUNDS}"
CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL}
-SUBDIRS = addr nslookup dig dnsquery host named named-xfer ndc nsupdate
+SUBDIRS = addr nslookup dig dnsquery host named named-xfer ndc nsupdate \
+ mkservdb irpd dnskeygen named-bootconf
all: ${SUBDIRS}
diff --git a/contrib/bind/bin/addr/Makefile b/contrib/bind/bin/addr/Makefile
index 0e8b2ec..18dd281 100644
--- a/contrib/bind/bin/addr/Makefile
+++ b/contrib/bind/bin/addr/Makefile
@@ -1,4 +1,4 @@
-## Copyright (c) 1996 by Internet Software Consortium
+## Copyright (c) 1996,1999 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
@@ -13,7 +13,7 @@
## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
## SOFTWARE.
-# $Id: Makefile,v 8.19 1997/06/19 03:22:06 halley Exp $
+# $Id: Makefile,v 8.25 1999/08/08 17:51:00 vixie Exp $
DESTDIR=
CC= cc
@@ -29,15 +29,17 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include
LIBBIND = ${TOP}/lib/libbind.a
A=a
O=o
+EXE=
LEX = lex -I
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
STRIP=-s
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
LDFLAGS=
CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL}
@@ -46,26 +48,29 @@ PROG= addr
SRCS= ${PROG}.c
OBJS= ${PROG}.${O}
-all: ${PROG}
+all: ${PROG}${EXE}
-${PROG}: ${OBJS} ${LIBBIND} Makefile
- ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} \
+${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile
+ ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \
${LIBBIND} ${SYSLIBS}
+.c.${O}:
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c
+
distclean: clean
clean: FRC
- rm -f ${PROG} ${OBJS} core .depend
+ rm -f ${PROG}${EXE} ${OBJS} core .depend
rm -f *.BAK *.CKP *~ *.orig
depend: ${SRCS}
- mkdep -p ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
+ mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
${DESTDIR}${DESTBIN}:
mkdir -p ${DESTDIR}${DESTBIN}
-install: ${DESTDIR}${DESTBIN} ${PROG}
- ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTBIN}/${PROG}
+install: ${DESTDIR}${DESTBIN} ${PROG}${EXE}
+ ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE}
links: FRC
@set -e; ln -s SRC/*.[ch] .
diff --git a/contrib/bind/bin/addr/addr.c b/contrib/bind/bin/addr/addr.c
index 535033a..a693391 100644
--- a/contrib/bind/bin/addr/addr.c
+++ b/contrib/bind/bin/addr/addr.c
@@ -1,9 +1,9 @@
#if !defined(lint) && !defined(SABER)
-static char rcsid[] = "$Id: addr.c,v 8.5 1997/04/25 00:00:29 vixie Exp $";
+static const char rcsid[] = "$Id: addr.c,v 8.8 1999/10/13 16:38:55 vixie Exp $";
#endif /* not lint */
/*
- * Copyright (c) 1996 by Internet Software Consortium.
+ * Copyright (c) 1996,1999 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
@@ -129,11 +129,12 @@ main(argc, argv)
char *argv[];
{
u_char addr[BIGGEST_ADDRESS];
- int optchr, af, len;
+ int optchr, af, len, some;
prog = argv[0];
af = AF_INET;
len = INADDRSZ;
+ some = 0;
while ((optchr = getopt(argc, argv, "46n:p:")) != -1) {
switch (optchr) {
case '4':
@@ -152,6 +153,7 @@ main(argc, argv)
/* NOTREACHED */
}
display(optarg, af, addr, len);
+ some++;
break;
case 'p':
if (inet_pton(af, optarg, addr) <= 0) {
@@ -161,12 +163,15 @@ main(argc, argv)
/* NOTREACHED */
}
display(optarg, af, addr, len);
+ some++;
break;
default:
usage();
/* NOTREACHED */
}
}
+ if (!some)
+ usage();
exit(0);
/* NOTREACHED */
}
diff --git a/contrib/bind/bin/dig/Makefile b/contrib/bind/bin/dig/Makefile
index dbbc00f..250df96 100644
--- a/contrib/bind/bin/dig/Makefile
+++ b/contrib/bind/bin/dig/Makefile
@@ -1,4 +1,4 @@
-## Copyright (c) 1996 by Internet Software Consortium
+## Copyright (c) 1996,1999 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
@@ -13,7 +13,7 @@
## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
## SOFTWARE.
-# $Id: Makefile,v 8.19 1997/06/19 03:22:07 halley Exp $
+# $Id: Makefile,v 8.25 1999/08/08 17:51:01 vixie Exp $
DESTDIR=
CC= cc
@@ -29,15 +29,17 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include
LIBBIND = ${TOP}/lib/libbind.a
A=a
O=o
+EXE=
LEX = lex -I
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
STRIP=-s
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
LDFLAGS=
CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL}
@@ -50,26 +52,29 @@ PROG= dig
SRCS= ${PROG}.c
OBJS= ${PROG}.${O}
-all: ${PROG}
+all: ${PROG}${EXE}
-${PROG}: ${OBJS} ${NSLOOKUP_OBJS} ${LIBBIND} Makefile
- ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} ${NSLOOKUP_OBJS} \
- ${LIBBIND} ${SYSLIBS}
+${PROG}${EXE}: ${OBJS} ${NSLOOKUP_OBJS} ${LIBBIND} Makefile
+ ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \
+ ${NSLOOKUP_OBJS} ${LIBBIND} ${SYSLIBS}
+
+.c.${O}:
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c
distclean: clean
clean: FRC
- rm -f ${PROG} ${OBJS} core .depend
+ rm -f ${PROG}${EXE} ${OBJS} core .depend
rm -f *.BAK *.CKP *~ *.orig
depend: ${SRCS}
- mkdep -p ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
+ mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
${DESTDIR}${DESTBIN}:
mkdir -p ${DESTDIR}${DESTBIN}
-install: ${DESTDIR}${DESTBIN} ${PROG}
- ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTBIN}/${PROG}
+install: ${DESTDIR}${DESTBIN} ${PROG}${EXE}
+ ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE}
links: FRC
@set -e; ln -s SRC/*.[ch] .
diff --git a/contrib/bind/bin/dig/dig.c b/contrib/bind/bin/dig/dig.c
index 7db8ba0..4e75c13 100644
--- a/contrib/bind/bin/dig/dig.c
+++ b/contrib/bind/bin/dig/dig.c
@@ -1,5 +1,5 @@
#ifndef lint
-static char rcsid[] = "$Id: dig.c,v 8.19 1998/03/19 19:30:18 halley Exp $";
+static const char rcsid[] = "$Id: dig.c,v 8.36 1999/11/05 05:05:14 vixie Exp $";
#endif
/*
@@ -56,7 +56,7 @@ static char rcsid[] = "$Id: dig.c,v 8.19 1998/03/19 19:30:18 halley Exp $";
*/
/*
- * Copyright (c) 1996 by Internet Software Consortium
+ * Portions Copyright (c) 1996-1999 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
@@ -159,11 +159,14 @@ static char rcsid[] = "$Id: dig.c,v 8.19 1998/03/19 19:30:18 halley Exp $";
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
+#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
+#include <isc/dst.h>
+
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -179,12 +182,10 @@ static char rcsid[] = "$Id: dig.c,v 8.19 1998/03/19 19:30:18 halley Exp $";
#include "../nslookup/res.h"
-extern char *_res_resultcodes[]; /* res_debug.c */
-
/* Global. */
-#define VERSION 81
-#define VSTRING "8.1"
+#define VERSION 82
+#define VSTRING "8.2"
#define PRF_DEF 0x2ff9
#define PRF_MIN 0xA930
@@ -194,20 +195,21 @@ extern char *_res_resultcodes[]; /* res_debug.c */
#define MAXHOSTNAMELEN 256
#endif
-int eecode = 0;
-
-FILE *qfp;
-int sockFD;
-
#define SAVEENV "DiG.env"
#define DIG_MAXARGS 30
+static int eecode = 0;
+static FILE * qfp;
+static int sockFD;
static char *defsrv, *srvmsg;
static char defbuf[40] = "default -- ";
static char srvbuf[60];
static char myhostname[MAXHOSTNAMELEN];
+static struct sockaddr_in myaddress;
+static u_int32_t ixfr_serial;
/* stuff for nslookup modules */
+struct __res_state res;
FILE *filePtr;
jmp_buf env;
HostInfo *defaultPtr = NULL;
@@ -228,7 +230,8 @@ static void Usage(void);
static int SetOption(const char *);
static void res_re_init(void);
static int xstrtonum(char *);
-static int printZone(const char *, const struct sockaddr_in *);
+static int printZone(ns_type, const char *,
+ const struct sockaddr_in *, ns_tsig_key *);
static int print_axfr(FILE *output, const u_char *msg,
size_t msglen);
static struct timeval difftv(struct timeval, struct timeval);
@@ -246,15 +249,17 @@ main(int argc, char **argv) {
HEADER header_;
u_char packet_[PACKETSZ];
} packet_;
-#define packet (packet_.packet_)
- u_char answer[8*1024];
+#define header (packet_.header_)
+#define packet (packet_.packet_)
+ u_char answer[64*1024];
int n;
char doping[90];
char pingstr[50];
char *afile;
char *addrc, *addrend, *addrbegin;
- struct timeval exectime, tv1, tv2, start_time, end_time, query_time;
+ time_t exectime;
+ struct timeval tv1, tv2, start_time, end_time, query_time;
char *srv;
int anyflag = 0;
@@ -262,7 +267,7 @@ main(int argc, char **argv) {
int tmp;
int qtypeSet;
int addrflag = 0;
- int zone = 0;
+ ns_type xfr = ns_t_invalid;
int bytes_out, bytes_in;
char cmd[256];
@@ -279,13 +284,22 @@ main(int argc, char **argv) {
struct __res_state res_x, res_t;
char *pp;
- res_init();
- _res.pfcode = PRF_DEF;
+ ns_tsig_key key;
+ char *keyfile = NULL, *keyname = NULL;
+
+ res_ninit(&res);
+ res.pfcode = PRF_DEF;
qtypeSet = 0;
memset(domain, 0, sizeof domain);
gethostname(myhostname, (sizeof myhostname));
- defsrv = strcat(defbuf, inet_ntoa(_res.nsaddr.sin_addr));
- res_x = _res;
+#ifdef HAVE_SA_LEN
+ myaddress.sin_len = sizeof(struct sockaddr_in);
+#endif
+ myaddress.sin_family = AF_INET;
+ myaddress.sin_addr.s_addr = INADDR_ANY;
+ myaddress.sin_port = 0; /*INPORT_ANY*/;
+ defsrv = strcat(defbuf, inet_ntoa(res.nsaddr.sin_addr));
+ res_x = res;
/*
* If LOCALDEF in environment, should point to file
@@ -298,7 +312,7 @@ main(int argc, char **argv) {
((fp = open(SAVEENV, O_RDONLY)) > 0)) {
read(fp, (char *)&res_x, (sizeof res_x));
close(fp);
- _res = res_x;
+ res = res_x;
}
/*
* Check for batch-mode DiG; also pre-scan for 'help'.
@@ -332,7 +346,7 @@ main(int argc, char **argv) {
vtmp++;
}
- _res.id = 1;
+ res.id = 1;
gettimeofday(&tv1, NULL);
/*
@@ -352,7 +366,7 @@ main(int argc, char **argv) {
*/
if (sticky) {
printf(";; (using sticky settings)\n");
- _res = res_x;
+ res = res_x;
}
/*
@@ -363,7 +377,7 @@ main(int argc, char **argv) {
/* defaults */
queryType = ns_t_ns;
queryClass = ns_c_in;
- zone = 0;
+ xfr = ns_t_invalid;
*pingstr = 0;
srv = NULL;
@@ -387,7 +401,10 @@ main(int argc, char **argv) {
SetOption(*argv+1);
continue;
}
-
+ if (**argv == '=') {
+ ixfr_serial = strtoul(*argv+1, NULL, 0);
+ continue;
+ }
if (strncmp(*argv, "-nost", 5) == 0) {
sticky = 0;
continue;
@@ -460,15 +477,57 @@ main(int argc, char **argv) {
strcat(domain, addrc);
strcat(domain, ".in-addr.arpa.");
break;
- case 'p': port = htons(atoi(*++argv)); break;
+ case 'p':
+ if (argv[0][2] != '\0')
+ port = ntohs(atoi(argv[0]+2));
+ else
+ port = htons(atoi(*++argv));
+ break;
case 'P':
if (argv[0][2] != '\0')
- strcpy(pingstr,&argv[0][2]);
+ strcpy(pingstr, argv[0]+2);
else
- strcpy(pingstr,"ping -s");
+ strcpy(pingstr, "ping -s");
break;
case 'n':
- _res.ndots = atoi(&argv[0][2]);
+ if (argv[0][2] != '\0')
+ res.ndots = atoi(argv[0]+2);
+ else
+ res.ndots = atoi(*++argv);
+ break;
+ case 'b': {
+ char *a, *p;
+
+ if (argv[0][2] != '\0')
+ a = argv[0]+2;
+ else
+ a = *++argv;
+ if ((p = strchr(a, ':')) != NULL) {
+ *p++ = '\0';
+ myaddress.sin_port =
+ ntohs(atoi(p));
+ }
+ if (!inet_aton(a,&myaddress.sin_addr)){
+ fprintf(stderr,
+ ";; bad -b addr\n");
+ exit(1);
+ }
+ }
+ case 'k':
+ /* -k keydir:keyname */
+
+ if (argv[0][2] != '\0')
+ keyfile = argv[0]+2;
+ else
+ keyfile = *++argv;
+
+ keyname = strchr(keyfile, ':');
+ if (keyname == NULL) {
+ fprintf(stderr,
+ "key option argument should be keydir:keyname\n");
+ exit(1);
+ }
+ *keyname++='\0';
break;
} /* switch - */
continue;
@@ -479,9 +538,12 @@ main(int argc, char **argv) {
queryClass = C_ANY;
continue;
}
- if (T_AXFR == tmp) {
- _res.pfcode = PRF_ZONE;
- zone++;
+ if (ns_t_xfr_p(tmp) &&
+ (tmp == ns_t_axfr ||
+ (res.options & RES_USEVC) != 0)
+ ) {
+ res.pfcode = PRF_ZONE;
+ xfr = (ns_type)tmp;
} else {
queryType = tmp;
qtypeSet++;
@@ -495,16 +557,127 @@ main(int argc, char **argv) {
}
} /* while argv remains */
- if (_res.pfcode & 0x80000)
+ /* process key options */
+ if (keyfile) {
+#ifdef PARSE_KEYFILE
+ int i, n1;
+ char buf[BUFSIZ], *p;
+ FILE *fp = NULL;
+ int file_major, file_minor, alg;
+
+ fp = fopen(keyfile, "r");
+ if (fp == NULL) {
+ perror(keyfile);
+ exit(1);
+ }
+ /* Now read the header info from the file. */
+ i = fread(buf, 1, BUFSIZ, fp);
+ if (i < 5) {
+ fclose(fp);
+ exit(1);
+ }
+ fclose(fp);
+
+ p = buf;
+
+ n=strlen(p); /* get length of strings */
+ n1=strlen("Private-key-format: v");
+ if (n1 > n ||
+ strncmp(buf, "Private-key-format: v", n1)) {
+ fprintf(stderr, "Invalid key file format\n");
+ exit(1); /* not a match */
+ }
+ p+=n1; /* advance pointer */
+ sscanf((char *)p, "%d.%d", &file_major, &file_minor);
+ /* should do some error checking with these someday */
+ while (*p++!='\n'); /* skip to end of line */
+
+ n=strlen(p); /* get length of strings */
+ n1=strlen("Algorithm: ");
+ if (n1 > n || strncmp(p, "Algorithm: ", n1)) {
+ fprintf(stderr, "Invalid key file format\n");
+ exit(1); /* not a match */
+ }
+ p+=n1; /* advance pointer */
+ if (sscanf((char *)p, "%d", &alg)!=1) {
+ fprintf(stderr, "Invalid key file format\n");
+ exit(1);
+ }
+ while (*p++!='\n'); /* skip to end of line */
+
+ n=strlen(p); /* get length of strings */
+ n1=strlen("Key: ");
+ if (n1 > n || strncmp(p, "Key: ", n1)) {
+ fprintf(stderr, "Invalid key file format\n");
+ exit(1); /* not a match */
+ }
+ p+=n1; /* advance pointer */
+ pp=p;
+ while (*pp++!='\n'); /* skip to end of line,
+ * terminate it */
+ *--pp='\0';
+
+ key.data=malloc(1024*sizeof(char));
+ key.len=b64_pton(p, key.data, 1024);
+
+ strcpy(key.name, keyname);
+ strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT");
+#else
+ /* use the dst* routines to parse the key files
+ *
+ * This requires that both the .key and the .private
+ * files exist in your cwd, so the keyfile parmeter
+ * here is assumed to be a path in which the
+ * K*.{key,private} files exist.
+ */
+ DST_KEY *dst_key;
+ char cwd[PATH_MAX+1];
+
+ if (getcwd(cwd, PATH_MAX)==NULL) {
+ perror("unable to get current directory");
+ exit(1);
+ }
+ if (chdir(keyfile)<0) {
+ fprintf(stderr,
+ "unable to chdir to %s: %s\n", keyfile,
+ strerror(errno));
+ exit(1);
+ }
+
+ dst_init();
+ dst_key = dst_read_key(keyname,
+ 0 /* not used for priv keys */,
+ KEY_HMAC_MD5, DST_PRIVATE);
+ if (!dst_key) {
+ fprintf(stderr,
+ "dst_read_key: error reading key\n");
+ exit(1);
+ }
+ key.data=malloc(1024*sizeof(char));
+ dst_key_to_buffer(dst_key, key.data, 1024);
+ key.len=dst_key->dk_key_size;
+
+ strcpy(key.name, keyname);
+ strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT");
+
+ if (chdir(cwd)<0) {
+ fprintf(stderr, "unable to chdir to %s: %s\n",
+ cwd, strerror(errno));
+ exit(1);
+ }
+#endif
+ }
+
+ if (res.pfcode & 0x80000)
printf("; pfcode: %08lx, options: %08lx\n",
- _res.pfcode, _res.options);
+ res.pfcode, res.options);
/*
* Current env. (after this parse) is to become the
* new "working" environmnet. Used in conj. with sticky.
*/
if (envset) {
- res_x = _res;
+ res_x = res;
envset = 0;
}
@@ -523,13 +696,13 @@ main(int argc, char **argv) {
((fp = open(SAVEENV,
O_WRONLY|O_CREAT|O_TRUNC,
S_IREAD|S_IWRITE)) > 0)) {
- write(fp, (char *)&_res, (sizeof _res));
+ write(fp, (char *)&res, (sizeof res));
close(fp);
}
envsave = 0;
}
- if (_res.pfcode & RES_PRF_CMD)
+ if (res.pfcode & RES_PRF_CMD)
printf("%s\n", cmd);
addrflag = anyflag = 0;
@@ -549,16 +722,16 @@ main(int argc, char **argv) {
struct in_addr addr;
if (inet_aton(srv, &addr)) {
- _res.nscount = 1;
- _res.nsaddr.sin_addr = addr;
+ res.nscount = 1;
+ res.nsaddr.sin_addr = addr;
srvmsg = strcat(srvbuf, srv);
} else {
- res_t = _res;
- _res.pfcode = 0;
- _res.options = RES_DEFAULT;
- res_init();
+ res_t = res;
+ res_ninit(&res);
+ res.pfcode = 0;
+ res.options = RES_DEFAULT;
hp = gethostbyname(srv);
- _res = res_t;
+ res = res_t;
if (hp == NULL
|| hp->h_addr_list == NULL
|| *hp->h_addr_list == NULL) {
@@ -572,54 +745,57 @@ main(int argc, char **argv) {
} else {
u_int32_t **addr;
- _res.nscount = 0;
+ res.nscount = 0;
for (addr = (u_int32_t**)hp->h_addr_list;
- *addr && (_res.nscount < MAXNS);
+ *addr && (res.nscount < MAXNS);
addr++) {
- _res.nsaddr_list[
- _res.nscount++
+ res.nsaddr_list[
+ res.nscount++
].sin_addr.s_addr = **addr;
}
srvmsg = strcat(srvbuf,srv);
strcat(srvbuf, " ");
strcat(srvmsg,
- inet_ntoa(_res.nsaddr.sin_addr)
- );
+ inet_ntoa(res.nsaddr.sin_addr));
}
}
printf("; (%d server%s found)\n",
- _res.nscount, (_res.nscount==1)?"":"s");
- _res.id += _res.retry;
+ res.nscount, (res.nscount==1)?"":"s");
+ res.id += res.retry;
}
{
int i;
- for (i = 0; i < _res.nscount; i++) {
- _res.nsaddr_list[i].sin_family = AF_INET;
- _res.nsaddr_list[i].sin_port = port;
+ for (i = 0; i < res.nscount; i++) {
+ res.nsaddr_list[i].sin_family = AF_INET;
+ res.nsaddr_list[i].sin_port = port;
}
- _res.id += _res.retry;
+ res.id += res.retry;
}
- if (zone) {
+ if (ns_t_xfr_p(xfr)) {
int i;
- for (i = 0; i < _res.nscount; i++) {
- int x = printZone(domain,
- &_res.nsaddr_list[i]);
- if (_res.pfcode & RES_PRF_STATS) {
- struct timeval exectime;
- time_t t;
+ for (i = 0; i < res.nscount; i++) {
+ int x;
+ if (keyfile)
+ x = printZone(xfr, domain,
+ &res.nsaddr_list[i],
+ &key);
+ else
+ x = printZone(xfr, domain,
+ &res.nsaddr_list[i],
+ NULL);
+ if (res.pfcode & RES_PRF_STATS) {
+ exectime = time(NULL);
printf(";; FROM: %s to SERVER: %s\n",
myhostname,
- inet_ntoa(_res.nsaddr_list[i]
+ inet_ntoa(res.nsaddr_list[i]
.sin_addr));
- gettimeofday(&exectime, NULL);
- t = (time_t)exectime.tv_sec;
- printf(";; WHEN: %s", ctime(&t));
+ printf(";; WHEN: %s", ctime(&exectime));
}
if (!x)
break; /* success */
@@ -633,25 +809,54 @@ main(int argc, char **argv) {
qtypeSet++;
}
- bytes_out = n = res_mkquery(QUERY, domain,
- queryClass, queryType,
- NULL, 0, NULL,
- packet, sizeof packet);
+ bytes_out = n = res_nmkquery(&res, QUERY, domain,
+ queryClass, queryType,
+ NULL, 0, NULL,
+ packet, sizeof packet);
if (n < 0) {
fflush(stderr);
- printf(";; res_mkquery: buffer too small\n\n");
+ printf(";; res_nmkquery: buffer too small\n\n");
continue;
}
+ if (queryType == T_IXFR) {
+ HEADER *hp = (HEADER *) packet;
+ u_char *cpp = packet + bytes_out;
+
+ hp->nscount = htons(1+ntohs(hp->nscount));
+ n = dn_comp(domain, cpp,
+ (sizeof packet) - (cpp - packet),
+ NULL, NULL);
+ cpp += n;
+ PUTSHORT(T_SOA, cpp); /* type */
+ PUTSHORT(C_IN, cpp); /* class */
+ PUTLONG(0, cpp); /* ttl */
+ PUTSHORT(22, cpp); /* dlen */
+ *cpp++ = 0; /* mname */
+ *cpp++ = 0; /* rname */
+ PUTLONG(ixfr_serial, cpp);
+ PUTLONG(0xDEAD, cpp); /* Refresh */
+ PUTLONG(0xBEEF, cpp); /* Retry */
+ PUTLONG(0xABCD, cpp); /* Expire */
+ PUTLONG(0x1776, cpp); /* Min TTL */
+ bytes_out = n = cpp - packet;
+ };
+
eecode = 0;
- if (_res.pfcode & RES_PRF_HEAD1)
- __fp_resstat(NULL, stdout);
+ if (res.pfcode & RES_PRF_HEAD1)
+ fp_resstat(&res, stdout);
(void) gettimeofday(&start_time, NULL);
- if ((bytes_in = n = res_send(packet, n,
- answer, sizeof answer)) < 0) {
+ if (keyfile)
+ n = res_nsendsigned(&res, packet, n, &key, answer, sizeof answer);
+ else
+ n = res_nsend(&res, packet, n, answer, sizeof answer);
+ if ((bytes_in = n) < 0) {
fflush(stdout);
n = 0 - n;
msg[0]=0;
- strcat(msg,";; res_send to server ");
+ if (keyfile)
+ strcat(msg,";; res_nsendsigned to server ");
+ else
+ strcat(msg,";; res_nsend to server ");
strcat(msg,srvmsg);
perror(msg);
fflush(stderr);
@@ -665,18 +870,17 @@ main(int argc, char **argv) {
}
(void) gettimeofday(&end_time, NULL);
- if (_res.pfcode & RES_PRF_STATS) {
+ if (res.pfcode & RES_PRF_STATS) {
time_t t;
query_time = difftv(start_time, end_time);
printf(";; Total query time: ");
prnttime(query_time);
putchar('\n');
+ exectime = time(NULL);
printf(";; FROM: %s to SERVER: %s\n",
myhostname, srvmsg);
- gettimeofday(&exectime,NULL);
- t = (time_t)exectime.tv_sec;
- printf(";; WHEN: %s", ctime(&t));
+ printf(";; WHEN: %s", ctime(&exectime));
printf(";; MSG SIZE sent: %d rcvd: %d\n",
bytes_out, bytes_in);
}
@@ -723,9 +927,11 @@ where: server,\n\
-f file (batch mode input file name)\n\
-T time (batch mode time delay, per query)\n\
-p port (nameserver is on this port) [53]\n\
- -Pping-string (see man page)\n\
+ -b addr[:port] (bind to this tcp address) [*]\n\
+ -P[ping-string] (see man page)\n\
-t query-type (synonym for q-type)\n\
-c query-class (synonym for q-class)\n\
+ -k keydir:keyname (sign the query with this TSIG key)\n\
-envsav,-envset (see man page)\n\
-[no]stick (see man page)\n\
", stderr);
@@ -739,6 +945,8 @@ where: server,\n\
", stderr);
fputs("\
notes: defname and search don't work; use fully-qualified names.\n\
+ this is DiG version " VSTRING "\n\
+ $Id: dig.c,v 8.36 1999/11/05 05:05:14 vixie Exp $\n\
", stderr);
}
@@ -747,128 +955,139 @@ SetOption(const char *string) {
char option[NAME_LEN], type[NAME_LEN], *ptr;
int i;
- i = sscanf(string, " %s", option);
- if (i != 1) {
- fprintf(stderr, ";*** Invalid option: %s\n", option);
- return (ERROR);
+ i = pickString(string, option, sizeof option);
+ if (i == 0) {
+ fprintf(stderr, ";*** Invalid option: %s\n", string);
+
+ /* this is ugly, but fixing the caller to behave
+ properly with an error return value would require a major
+ cleanup. */
+ exit(9);
}
if (strncmp(option, "aa", 2) == 0) { /* aaonly */
- _res.options |= RES_AAONLY;
+ res.options |= RES_AAONLY;
} else if (strncmp(option, "noaa", 4) == 0) {
- _res.options &= ~RES_AAONLY;
+ res.options &= ~RES_AAONLY;
} else if (strncmp(option, "deb", 3) == 0) { /* debug */
- _res.options |= RES_DEBUG;
+ res.options |= RES_DEBUG;
} else if (strncmp(option, "nodeb", 5) == 0) {
- _res.options &= ~(RES_DEBUG | RES_DEBUG2);
+ res.options &= ~(RES_DEBUG | RES_DEBUG2);
} else if (strncmp(option, "ko", 2) == 0) { /* keepopen */
- _res.options |= (RES_STAYOPEN | RES_USEVC);
+ res.options |= (RES_STAYOPEN | RES_USEVC);
} else if (strncmp(option, "noko", 4) == 0) {
- _res.options &= ~RES_STAYOPEN;
+ res.options &= ~RES_STAYOPEN;
} else if (strncmp(option, "d2", 2) == 0) { /* d2 (more debug) */
- _res.options |= (RES_DEBUG | RES_DEBUG2);
+ res.options |= (RES_DEBUG | RES_DEBUG2);
} else if (strncmp(option, "nod2", 4) == 0) {
- _res.options &= ~RES_DEBUG2;
+ res.options &= ~RES_DEBUG2;
} else if (strncmp(option, "def", 3) == 0) { /* defname */
- _res.options |= RES_DEFNAMES;
+ res.options |= RES_DEFNAMES;
} else if (strncmp(option, "nodef", 5) == 0) {
- _res.options &= ~RES_DEFNAMES;
+ res.options &= ~RES_DEFNAMES;
} else if (strncmp(option, "sea", 3) == 0) { /* search list */
- _res.options |= RES_DNSRCH;
+ res.options |= RES_DNSRCH;
} else if (strncmp(option, "nosea", 5) == 0) {
- _res.options &= ~RES_DNSRCH;
+ res.options &= ~RES_DNSRCH;
} else if (strncmp(option, "do", 2) == 0) { /* domain */
ptr = strchr(option, '=');
- if (ptr != NULL)
- sscanf(++ptr, "%s", _res.defdname);
+ if (ptr != NULL) {
+ i = pickString(++ptr, res.defdname, sizeof res.defdname);
+ if (i == 0) { /* value's too long or non-existant. This actually
+ shouldn't happen due to pickString()
+ above */
+ fprintf(stderr, "*** Invalid domain: %s\n", ptr) ;
+ exit(9); /* see comment at previous call to exit()*/
+ }
+ }
} else if (strncmp(option, "ti", 2) == 0) { /* timeout */
ptr = strchr(option, '=');
if (ptr != NULL)
- sscanf(++ptr, "%d", &_res.retrans);
+ sscanf(++ptr, "%d", &res.retrans);
} else if (strncmp(option, "ret", 3) == 0) { /* retry */
ptr = strchr(option, '=');
if (ptr != NULL)
- sscanf(++ptr, "%d", &_res.retry);
+ sscanf(++ptr, "%d", &res.retry);
} else if (strncmp(option, "i", 1) == 0) { /* ignore */
- _res.options |= RES_IGNTC;
+ res.options |= RES_IGNTC;
} else if (strncmp(option, "noi", 3) == 0) {
- _res.options &= ~RES_IGNTC;
+ res.options &= ~RES_IGNTC;
} else if (strncmp(option, "pr", 2) == 0) { /* primary */
- _res.options |= RES_PRIMARY;
+ res.options |= RES_PRIMARY;
} else if (strncmp(option, "nop", 3) == 0) {
- _res.options &= ~RES_PRIMARY;
+ res.options &= ~RES_PRIMARY;
} else if (strncmp(option, "rec", 3) == 0) { /* recurse */
- _res.options |= RES_RECURSE;
+ res.options |= RES_RECURSE;
} else if (strncmp(option, "norec", 5) == 0) {
- _res.options &= ~RES_RECURSE;
+ res.options &= ~RES_RECURSE;
} else if (strncmp(option, "v", 1) == 0) { /* vc */
- _res.options |= RES_USEVC;
+ res.options |= RES_USEVC;
} else if (strncmp(option, "nov", 3) == 0) {
- _res.options &= ~RES_USEVC;
+ res.options &= ~RES_USEVC;
} else if (strncmp(option, "pfset", 5) == 0) {
ptr = strchr(option, '=');
if (ptr != NULL)
- _res.pfcode = xstrtonum(++ptr);
+ res.pfcode = xstrtonum(++ptr);
} else if (strncmp(option, "pfand", 5) == 0) {
ptr = strchr(option, '=');
if (ptr != NULL)
- _res.pfcode = _res.pfcode & xstrtonum(++ptr);
+ res.pfcode = res.pfcode & xstrtonum(++ptr);
} else if (strncmp(option, "pfor", 4) == 0) {
ptr = strchr(option, '=');
if (ptr != NULL)
- _res.pfcode |= xstrtonum(++ptr);
+ res.pfcode |= xstrtonum(++ptr);
} else if (strncmp(option, "pfmin", 5) == 0) {
- _res.pfcode = PRF_MIN;
+ res.pfcode = PRF_MIN;
} else if (strncmp(option, "pfdef", 5) == 0) {
- _res.pfcode = PRF_DEF;
+ res.pfcode = PRF_DEF;
} else if (strncmp(option, "an", 2) == 0) { /* answer section */
- _res.pfcode |= RES_PRF_ANS;
+ res.pfcode |= RES_PRF_ANS;
} else if (strncmp(option, "noan", 4) == 0) {
- _res.pfcode &= ~RES_PRF_ANS;
+ res.pfcode &= ~RES_PRF_ANS;
} else if (strncmp(option, "qu", 2) == 0) { /* question section */
- _res.pfcode |= RES_PRF_QUES;
+ res.pfcode |= RES_PRF_QUES;
} else if (strncmp(option, "noqu", 4) == 0) {
- _res.pfcode &= ~RES_PRF_QUES;
+ res.pfcode &= ~RES_PRF_QUES;
} else if (strncmp(option, "au", 2) == 0) { /* authority section */
- _res.pfcode |= RES_PRF_AUTH;
+ res.pfcode |= RES_PRF_AUTH;
} else if (strncmp(option, "noau", 4) == 0) {
- _res.pfcode &= ~RES_PRF_AUTH;
+ res.pfcode &= ~RES_PRF_AUTH;
} else if (strncmp(option, "ad", 2) == 0) { /* addition section */
- _res.pfcode |= RES_PRF_ADD;
+ res.pfcode |= RES_PRF_ADD;
} else if (strncmp(option, "noad", 4) == 0) {
- _res.pfcode &= ~RES_PRF_ADD;
+ res.pfcode &= ~RES_PRF_ADD;
} else if (strncmp(option, "tt", 2) == 0) { /* TTL & ID */
- _res.pfcode |= RES_PRF_TTLID;
+ res.pfcode |= RES_PRF_TTLID;
} else if (strncmp(option, "nott", 4) == 0) {
- _res.pfcode &= ~RES_PRF_TTLID;
+ res.pfcode &= ~RES_PRF_TTLID;
} else if (strncmp(option, "he", 2) == 0) { /* head flags stats */
- _res.pfcode |= RES_PRF_HEAD2;
+ res.pfcode |= RES_PRF_HEAD2;
} else if (strncmp(option, "nohe", 4) == 0) {
- _res.pfcode &= ~RES_PRF_HEAD2;
+ res.pfcode &= ~RES_PRF_HEAD2;
} else if (strncmp(option, "H", 1) == 0) { /* header all */
- _res.pfcode |= RES_PRF_HEADX;
+ res.pfcode |= RES_PRF_HEADX;
} else if (strncmp(option, "noH", 3) == 0) {
- _res.pfcode &= ~(RES_PRF_HEADX);
+ res.pfcode &= ~(RES_PRF_HEADX);
} else if (strncmp(option, "qr", 2) == 0) { /* query */
- _res.pfcode |= RES_PRF_QUERY;
+ res.pfcode |= RES_PRF_QUERY;
} else if (strncmp(option, "noqr", 4) == 0) {
- _res.pfcode &= ~RES_PRF_QUERY;
+ res.pfcode &= ~RES_PRF_QUERY;
} else if (strncmp(option, "rep", 3) == 0) { /* reply */
- _res.pfcode |= RES_PRF_REPLY;
+ res.pfcode |= RES_PRF_REPLY;
} else if (strncmp(option, "norep", 5) == 0) {
- _res.pfcode &= ~RES_PRF_REPLY;
+ res.pfcode &= ~RES_PRF_REPLY;
} else if (strncmp(option, "cm", 2) == 0) { /* command line */
- _res.pfcode |= RES_PRF_CMD;
+ res.pfcode |= RES_PRF_CMD;
} else if (strncmp(option, "nocm", 4) == 0) {
- _res.pfcode &= ~RES_PRF_CMD;
+ res.pfcode &= ~RES_PRF_CMD;
} else if (strncmp(option, "cl", 2) == 0) { /* class mnemonic */
- _res.pfcode |= RES_PRF_CLASS;
+ res.pfcode |= RES_PRF_CLASS;
} else if (strncmp(option, "nocl", 4) == 0) {
- _res.pfcode &= ~RES_PRF_CLASS;
+ res.pfcode &= ~RES_PRF_CLASS;
} else if (strncmp(option, "st", 2) == 0) { /* stats*/
- _res.pfcode |= RES_PRF_STATS;
+ res.pfcode |= RES_PRF_STATS;
} else if (strncmp(option, "nost", 4) == 0) {
- _res.pfcode &= ~RES_PRF_STATS;
+ res.pfcode &= ~RES_PRF_STATS;
} else {
fprintf(stderr, "; *** Invalid option: %s\n", option);
return (ERROR);
@@ -881,22 +1100,22 @@ SetOption(const char *string) {
* Force a reinitialization when the domain is changed.
*/
static void
-res_re_init()
-{
+res_re_init() {
static char localdomain[] = "LOCALDOMAIN";
- long pfcode = _res.pfcode;
- long ndots = _res.ndots;
+ u_long pfcode = res.pfcode, options = res.options;
+ unsigned ndots = res.ndots;
char *buf;
/*
* This is ugly but putenv() is more portable than setenv().
*/
- buf = malloc((sizeof localdomain) + strlen(_res.defdname) +10/*fuzz*/);
- sprintf(buf, "%s=%s", localdomain, _res.defdname);
+ buf = malloc((sizeof localdomain) + strlen(res.defdname) +10/*fuzz*/);
+ sprintf(buf, "%s=%s", localdomain, res.defdname);
putenv(buf); /* keeps the argument, so we won't free it */
- res_init();
- _res.pfcode = pfcode;
- _res.ndots = ndots;
+ res_ninit(&res);
+ res.pfcode = pfcode;
+ res.options = options;
+ res.ndots = ndots;
}
/*
@@ -947,7 +1166,9 @@ typedef union {
} querybuf;
static int
-printZone(const char *zone, const struct sockaddr_in *sin) {
+printZone(ns_type xfr, const char *zone, const struct sockaddr_in *sin,
+ ns_tsig_key *key)
+{
static u_char *answer = NULL;
static int answerLen = 0;
@@ -960,19 +1181,91 @@ printZone(const char *zone, const struct sockaddr_in *sin) {
char dname[2][NS_MAXDNAME], file[NAME_LEN];
enum { NO_ERRORS, ERR_READING_LEN, ERR_READING_MSG, ERR_PRINTING }
error = NO_ERRORS;
+ pid_t zpid;
+ u_char *newmsg;
+ int newmsglen;
+ ns_tcp_tsig_state tsig_state;
+ int tsig_ret;
+
+ switch (xfr) {
+ case ns_t_axfr:
+ case ns_t_zxfr:
+ break;
+ default:
+ fprintf(stderr, ";; %s - transfer type not supported\n",
+ p_type(xfr));
+ return (ERROR);
+ }
/*
* Create a query packet for the requested zone name.
*/
- msglen = res_mkquery(ns_o_query, zone, queryClass, ns_t_axfr, NULL,
- 0, 0, buf.qb2, sizeof buf);
+ msglen = res_nmkquery(&res, ns_o_query, zone,
+ queryClass, ns_t_axfr, NULL,
+ 0, 0, buf.qb2, sizeof buf);
if (msglen < 0) {
- if (_res.options & RES_DEBUG)
- fprintf(stderr, ";; res_mkquery failed\n");
+ if (res.options & RES_DEBUG)
+ fprintf(stderr, ";; res_nmkquery failed\n");
return (ERROR);
}
/*
+ * Sign the message if a key was sent
+ */
+ if (key == NULL) {
+ newmsg = (u_char *)&buf;
+ newmsglen = msglen;
+ } else {
+ DST_KEY *dstkey;
+ int bufsize, siglen;
+ u_char sig[64];
+ int ret;
+
+ /* ns_sign() also calls dst_init(), but there is no harm
+ * doing it twice
+ */
+ dst_init();
+
+ bufsize = msglen + 1024;
+ newmsg = (u_char *) malloc(bufsize);
+ if (newmsg == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ memcpy(newmsg, (u_char *)&buf, msglen);
+ newmsglen = msglen;
+
+ if (strcmp(key->alg, NS_TSIG_ALG_HMAC_MD5) != 0)
+ dstkey = NULL;
+ else
+ dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
+ NS_KEY_TYPE_AUTH_ONLY,
+ NS_KEY_PROT_ANY,
+ key->data, key->len);
+ if (dstkey == NULL) {
+ errno = EINVAL;
+ if (key)
+ free(newmsg);
+ return (-1);
+ }
+
+ siglen = sizeof(sig);
+/* newmsglen++; */
+ ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0,
+ sig, &siglen, 0);
+ if (ret < 0) {
+ if (key)
+ free (newmsg);
+ if (ret == NS_TSIG_ERROR_NO_SPACE)
+ errno = EMSGSIZE;
+ else if (ret == -1)
+ errno = EINVAL;
+ return (ret);
+ }
+ ns_verify_tcp_init(dstkey, sig, siglen, &tsig_state);
+ }
+
+ /*
* Set up a virtual circuit to the server.
*/
if ((sockFD = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) {
@@ -981,29 +1274,86 @@ printZone(const char *zone, const struct sockaddr_in *sin) {
perror(";; socket");
return (e);
}
+ if (bind(sockFD, (struct sockaddr *)&myaddress, sizeof myaddress) < 0){
+ int e = errno;
+
+ fprintf(stderr, ";; bind(%s:%u): %s\n",
+ inet_ntoa(myaddress.sin_addr),
+ ntohs(myaddress.sin_port),
+ strerror(e));
+ (void) close(sockFD);
+ sockFD = -1;
+ return (e);
+ }
if (connect(sockFD, (struct sockaddr *)sin, sizeof *sin) < 0) {
int e = errno;
perror(";; connect");
(void) close(sockFD);
sockFD = -1;
- return e;
+ return (e);
}
/*
* Send length & message for zone transfer
*/
- ns_put16(msglen, tmp);
+ ns_put16(newmsglen, tmp);
if (write(sockFD, (char *)tmp, NS_INT16SZ) != NS_INT16SZ ||
- write(sockFD, (char *)&buf, msglen) != msglen) {
+ write(sockFD, (char *)newmsg, newmsglen) != newmsglen) {
int e = errno;
+ if (key)
+ free (newmsg);
perror(";; write");
(void) close(sockFD);
sockFD = -1;
return (e);
}
+ /*
+ * If we're compressing, push a gzip into the pipeline.
+ */
+ if (xfr == ns_t_zxfr) {
+ enum { rd = 0, wr = 1 };
+ int z[2];
+
+ if (pipe(z) < 0) {
+ int e = errno;
+ if (key)
+ free (newmsg);
+
+ perror(";; pipe");
+ (void) close(sockFD);
+ sockFD = -1;
+ return (e);
+ }
+ zpid = vfork();
+ if (zpid < 0) {
+ int e = errno;
+ if (key)
+ free (newmsg);
+
+ perror(";; fork");
+ (void) close(sockFD);
+ sockFD = -1;
+ return (e);
+ } else if (zpid == 0) {
+ /* Child. */
+ (void) close(z[rd]);
+ (void) dup2(sockFD, STDIN_FILENO);
+ (void) close(sockFD);
+ (void) dup2(z[wr], STDOUT_FILENO);
+ (void) close(z[wr]);
+ execlp("gzip", "gzip", "-d", "-v", NULL);
+ perror(";; child: execlp(gunzip)");
+ _exit(1);
+ }
+ /* Parent. */
+ (void) close(z[wr]);
+ (void) dup2(z[rd], sockFD);
+ (void) close(z[rd]);
+ }
+
dname[0][0] = '\0';
for (done = 0; !done; (void)NULL) {
/*
@@ -1053,7 +1403,19 @@ printZone(const char *zone, const struct sockaddr_in *sin) {
break;
}
- result = print_axfr(stdout, answer, cp - answer);
+ /*
+ * Verify the TSIG
+ */
+
+ if (key) {
+ tsig_ret = ns_verify_tcp(answer, &len, &tsig_state, 1);
+ if (tsig_ret == 0)
+ printf("; TSIG ok\n");
+ else
+ printf("; TSIG invalid\n");
+ }
+
+ result = print_axfr(stdout, answer, len);
if (result != 0) {
error = ERR_PRINTING;
break;
@@ -1108,7 +1470,7 @@ printZone(const char *zone, const struct sockaddr_in *sin) {
break;
}
if (type == T_SOA && soacnt++ &&
- !strcasecmp(dname[0], dname[1])) {
+ ns_samename(dname[0], dname[1]) == 1) {
done++;
break;
}
@@ -1122,6 +1484,35 @@ printZone(const char *zone, const struct sockaddr_in *sin) {
(void) close(sockFD);
sockFD = -1;
+ /*
+ * If we were uncompressing, reap the uncompressor.
+ */
+ if (xfr == ns_t_zxfr) {
+ pid_t pid;
+ int status;
+
+ pid = wait(&status);
+ if (pid < 0) {
+ int e = errno;
+
+ perror(";; wait");
+ return (e);
+ }
+ if (pid != zpid) {
+ fprintf(stderr, ";; wrong pid (%lu != %lu)\n",
+ (u_long)pid, (u_long)zpid);
+ return (ERROR);
+ }
+ printf(";; pid %lu: exit %d, signal %d, core %c\n",
+ pid, WEXITSTATUS(status),
+ WIFSIGNALED(status) ? WTERMSIG(status) : 0,
+ WCOREDUMP(status) ? 't' : 'f');
+ }
+
+ /* XXX This should probably happen sooner than here */
+ if (key)
+ free (newmsg);
+
switch (error) {
case NO_ERRORS:
return (0);
diff --git a/contrib/bind/bin/dnskeygen/Makefile b/contrib/bind/bin/dnskeygen/Makefile
new file mode 100644
index 0000000..bea8511
--- /dev/null
+++ b/contrib/bind/bin/dnskeygen/Makefile
@@ -0,0 +1,85 @@
+## Copyright (c) 1996,1999 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 1.5 1999/08/08 17:51:01 vixie 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
+SYSLIBS = -ll -lutil
+DESTBIN = /usr/local/bin
+DESTSBIN = /usr/local/sbin
+DESTEXEC = /usr/local/libexec
+DESTMAN = /usr/share/man
+DESTHELP= /usr/share/misc
+AR= ar cru
+INSTALL= install
+STRIP=-s
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
+
+PS=ps
+LDFLAGS=
+CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL}
+
+PROG= dnskeygen
+SRCS= dnskeygen.c
+OBJS= dnskeygen.${O}
+
+all: ${PROG}${EXE}
+
+${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile
+ ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \
+ ${LIBBIND} ${SYSLIBS}
+.c.${O}:
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c
+
+distclean: clean
+
+clean: FRC
+ rm -f ${PROG}${EXE} ${OBJS} core .depend
+ rm -f *.BAK *.CKP *~ *.orig
+
+depend: ${SRCS}
+ mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
+
+${DESTDIR}${DESTEXEC}:
+ mkdir -p ${DESTDIR}${DESTEXEC}
+
+install: ${DESTDIR}${DESTEXEC} ${PROG}${EXE}
+ ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTEXEC}/${PROG}${EXE}
+
+links: FRC
+ @set -e; ln -s SRC/*.[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/dnskeygen/dnskeygen.c b/contrib/bind/bin/dnskeygen/dnskeygen.c
new file mode 100644
index 0000000..c30eae7
--- /dev/null
+++ b/contrib/bind/bin/dnskeygen/dnskeygen.c
@@ -0,0 +1,318 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: dnskeygen.c,v 1.9 1999/10/13 16:38:59 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * Portions Copyright (c) 1995-1999 by TISLabs at Network Associates, Inc.
+ *
+ * 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 NETWORK ASSOCIATES
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE.
+ */
+
+#include "port_before.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "arpa/nameser.h"
+
+#include <isc/dst.h>
+
+#include "port_after.h"
+
+#define PRINT_SUPPORTED 2
+
+static void usage(char *str, int full);
+
+static short dsa_sizes[] = {512, 576, 640, 704, 768, 832, 896, 960, 1024, 0};
+static char *prog;
+
+int
+main(int argc, char **argv) {
+ DST_KEY *pubkey;
+ char *name=NULL;
+ int ch;
+ char str[128];
+ int alg = 0;
+ int zone_key = 0, user_key = 0, end_key = 0, key_type = 0;
+ int size = -1, exp = 0;
+ int no_auth = 0, no_conf = 0;
+ int sign_val = 0, flags = 0, protocol = -1;
+ int i, err = 0, n;
+ extern char *optarg;
+ char array[1024];
+
+ dst_init();
+ if ((prog = strrchr(argv[0],'/')) == NULL)
+ prog = strdup(argv[0]);
+ else
+ prog = strdup(++prog);
+
+/* process input arguments */
+ while ((ch = getopt(argc, argv, "achiuzn:s:p:D:H:R:F"))!= -1) {
+ switch (ch) {
+ case 'a':
+ no_auth = NS_KEY_NO_AUTH;
+ break;
+ case 'c':
+ no_conf = NS_KEY_NO_CONF;
+ break;
+ case 'F':
+ exp=1;
+ break;
+ case 'n':
+ if (optarg)
+ name = strdup(optarg);
+ else
+ usage("-n not followed by name", 0);
+ i = strlen(name);
+ if (name[i-1] != '.') {
+ printf("** Adding dot to the name to make it"
+ " fully qualified domain name**\n");
+ free(name);
+ name = malloc(i+2);
+ strcpy(name, optarg);
+ strcat(name, ".");
+ }
+ break;
+ case 'p':
+ if (optarg && isdigit(optarg[0]))
+ protocol = atoi(optarg);
+ else
+ usage("-p flag not followed by a number", 0);
+ break;
+ case 's':
+ /* Default: not signatory key */
+ if (optarg && isdigit(optarg[0]))
+ sign_val = (int) atoi(optarg);
+ else
+ usage("-s flag requires a value",0);
+ break;
+ case 'h':
+ end_key = NS_KEY_NAME_ENTITY;
+ key_type++;
+ break;
+ case 'u' :
+ user_key = NS_KEY_NAME_USER;
+ key_type++;
+ break ;
+ case 'z':
+ zone_key = NS_KEY_NAME_ZONE;
+ key_type++;
+ break;
+ case 'H':
+ if (optarg && isdigit(optarg[0]))
+ size = (int) atoi(optarg);
+ else
+ usage("-H flag requires a size",0);
+ if (alg != 0)
+ usage("Only ONE alg can be specified", 1);
+ alg = KEY_HMAC_MD5;
+ if (!dst_check_algorithm(alg))
+ usage("Algorithm HMAC-MD5 not available",
+ PRINT_SUPPORTED);
+ break;
+ case 'R':
+ if (optarg && isdigit(optarg[0]))
+ size = (int) atoi(optarg);
+ else
+ usage("-R flag requires a size",0);
+ if (alg != 0)
+ usage("Only ONE alg can be specified", 1);
+ alg = NS_ALG_MD5RSA;
+ if (!dst_check_algorithm(alg))
+ usage("Algorithm RSA not available",
+ PRINT_SUPPORTED);
+ break;
+ case 'D':
+ if (optarg && isdigit(optarg[0]))
+ size = (int) atoi(optarg);
+ else
+ usage("-D flag requires a size", 0);
+ if (alg != 0)
+ usage("Only ONE alg can be specified", 1);
+ alg = NS_ALG_DSS;
+ if (dst_check_algorithm(alg) == 0)
+ usage("Algorithm DSS not available",
+ PRINT_SUPPORTED);
+ break;
+ default:
+ err++;
+ } /* switch */
+ } /* while (getopt) */
+
+ /*
+ * Command line parsed make sure required parameters are present
+ */
+ if (name == NULL)
+ usage("No key name specified -n <name>", 1);
+
+ if (alg == 0)
+ usage("No algorithm specififed -{DHR}", 1);
+
+ if (key_type == 0)
+ usage("Key type -{zhu} must be specified", 1);
+ else if (key_type > 1)
+ usage("Only one key type -{zhu} must be specified", 1);
+
+ if (alg == NS_ALG_DSS)
+ no_conf = NS_KEY_NO_CONF; /* dss keys can not encrypt */
+
+ if (protocol == -1) {
+ if (zone_key || end_key)
+ protocol = NS_KEY_PROT_DNSSEC;
+ else
+ protocol = NS_KEY_PROT_EMAIL;
+ }
+ if (protocol < 0 || protocol > 255)
+ usage("Protocol value out of range [0..255]", 0);
+
+ if (sign_val < 0 || sign_val > 15) {
+ sprintf(str, "%s: Signatory value %d out of range[0..15]\n",
+ prog, sign_val);
+ usage(str, 0);
+ }
+ /* if any of bits 321 is set bit 0 can not be set*/
+ if (sign_val & 0xe)
+ sign_val &= 0xe;
+
+ /* if a zone key make sure at least one of the signer flags is set */
+ if ((protocol == NS_KEY_PROT_DNSSEC) && (sign_val == 0))
+ sign_val = 0x01;
+
+ if (no_auth && no_conf) { /* null key specified */
+ if (sign_val > 0)
+ sign_val = 0x0; /* null key can not sign */
+ if (size > 0)
+ size = 0; /* null key must have size 0 */
+ }
+
+ if (size > 0) {
+ if (alg == NS_ALG_MD5RSA){
+ if (size < 512 || size > 4096)
+ usage("Size out of range", 1);
+ }
+ else if (exp)
+ usage("-F can only be specified with -R", 0);
+ if (alg == NS_ALG_DSS) {
+ for (i = 0; dsa_sizes[i]; i++)
+ if (size <= dsa_sizes[i])
+ break;
+ if (size != dsa_sizes[i])
+ usage("Invalid DSS key size", 1);
+ }
+ }
+ else if (size < 0)
+ usage("No size specified", 0);
+
+ if (err)
+ usage("errors encountered/unknown flag", 1);
+
+ flags = no_conf | no_auth | end_key | user_key | zone_key | sign_val;
+
+/* process defaults */
+#ifdef WARN_NONZONE_SIGNER
+ if (signer && (user_key | end_key))
+ printf("Warning: User/End key is allowed to sign\n");
+#endif
+
+ /* create a public/private key pair */
+ if (alg == NS_ALG_MD5RSA)
+ printf("Generating %d bit RSA Key for %s\n\n",size, name);
+ else if (alg == NS_ALG_DSS)
+ printf("Generating %d bit DSS Key for %s\n\n",size, name);
+ else if (alg == KEY_HMAC_MD5)
+ printf("Generating %d bit HMAC-MD5 Key for %s\n\n",
+ size, name);
+
+ /* Make the key
+ * dst_generate_key_pair will place result in files that it
+ * knows about K<name><foot>.public and K<name><foot>.private
+ */
+ pubkey = dst_generate_key(name, size, exp, flags, protocol, alg);
+
+ if (pubkey == NULL) {
+ printf("Failed generating key for %s\n", name);
+ exit(12);
+ }
+
+ if (dst_write_key(pubkey, DST_PRIVATE) < 0) {
+ printf ("Failed to write private key for %s %d %d\n",
+ name, pubkey->dk_id, pubkey->dk_alg);
+ exit(12);
+ }
+
+ if (dst_write_key(pubkey, DST_PUBLIC) <= 0) {
+ if (access(name, F_OK))
+ printf("Not allowed to overwrite existing file\n");
+ else
+ printf("Failed to write public key for %s %d %d\n",
+ name, pubkey->dk_id, pubkey->dk_alg);
+ exit(12);
+ }
+
+ printf("Generated %d bit Key for %s id=%d alg=%d flags=%d\n\n",
+ size, name, pubkey->dk_id, pubkey->dk_alg,
+ pubkey->dk_flags);
+ exit(0);
+}
+
+static void
+usage(char *str, int flag){
+ int i;
+ printf ("\nNo key generated\n");
+ if (*str != '\0')
+ printf("Usage:%s: %s\n",prog, str);
+ printf("Usage:%s -{DHR} <size> [-F] -{zhu} [-ac] [-p <no>]"
+ " [-s <no>] -n name\n", prog);
+ if (flag == 0)
+ exit(2);
+ printf("\t-D generate DSA/DSS KEY: size must be one of following:\n");
+ printf("\t\t");
+ for(i = 0; dsa_sizes[i] > 0; i++)
+ printf(" %d,", dsa_sizes[i]);
+ printf("\n");
+ printf("\t-H generate HMAC-MD5 KEY: size in the range [1..512]:\n");
+ printf("\t-R generate RSA KEY: size in the range [512..4096]\n");
+ printf("\t-F RSA KEYS only: use large exponent\n");
+
+ printf("\t-z Zone key \n");
+ printf("\t-h Host/Entity key \n");
+ printf("\t-u User key \n");
+
+ printf("\t-a Key CANNOT be used for authentication\n");
+ printf("\t-c Key CANNOT be used for encryption\n");
+
+ printf("\t-p Set protocol field to <no>\n");
+ printf("\t\t default: 2 (email) for Host keys, 3 (dnssec) for all others\n");
+ printf("\t-s Strength value this key signs DNS records with\n");
+ printf("\t\t default: 1 for Zone keys, 0 for all others\n");
+ printf("\t-n name: the owner of the key\n");
+
+ if (flag == PRINT_SUPPORTED) {
+ printf("Available algorithms are:");
+ if (dst_check_algorithm(NS_ALG_MD5RSA) == 1)
+ printf(" RSA");
+ if (dst_check_algorithm(NS_ALG_DSS) == 1)
+ printf(" DSS");
+ if (dst_check_algorithm(KEY_HMAC_MD5) == 1)
+ printf(" HMAC-MD5");
+ printf("\n");
+ }
+
+ exit (-3);
+}
+
+
diff --git a/contrib/bind/bin/dnsquery/Makefile b/contrib/bind/bin/dnsquery/Makefile
index 95d557d..a643702 100644
--- a/contrib/bind/bin/dnsquery/Makefile
+++ b/contrib/bind/bin/dnsquery/Makefile
@@ -1,4 +1,4 @@
-## Copyright (c) 1996 by Internet Software Consortium
+## Copyright (c) 1996,1999 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
@@ -13,7 +13,7 @@
## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
## SOFTWARE.
-# $Id: Makefile,v 8.18 1997/06/19 03:22:08 halley Exp $
+# $Id: Makefile,v 8.24 1999/08/08 17:51:01 vixie Exp $
DESTDIR=
CC= cc
@@ -29,15 +29,17 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include
LIBBIND = ${TOP}/lib/libbind.a
A=a
O=o
+EXE=
LEX = lex -I
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
STRIP=-s
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
LDFLAGS=
CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL}
@@ -46,26 +48,29 @@ PROG= dnsquery
SRCS= ${PROG}.c
OBJS= ${PROG}.${O}
-all: ${PROG}
+all: ${PROG}${EXE}
-${PROG}: ${OBJS} ${LIBBIND} Makefile
- ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} \
+${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile
+ ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \
${LIBBIND} ${SYSLIBS}
+.c.${O}:
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c
+
distclean: clean
clean: FRC
- rm -f ${PROG} ${OBJS} core .depend
+ rm -f ${PROG}${EXE} ${OBJS} core .depend
rm -f *.BAK *.CKP *~ *.orig
depend: ${SRCS}
- mkdep -p ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
+ mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
${DESTDIR}${DESTBIN}:
mkdir -p ${DESTDIR}${DESTBIN}
-install: ${DESTDIR}${DESTBIN} ${PROG}
- ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTBIN}/${PROG}
+install: ${DESTDIR}${DESTBIN} ${PROG}${EXE}
+ ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE}
links: FRC
@set -e; ln -s SRC/*.[ch] .
diff --git a/contrib/bind/bin/dnsquery/dnsquery.c b/contrib/bind/bin/dnsquery/dnsquery.c
index 790e0cc..218c8a8 100644
--- a/contrib/bind/bin/dnsquery/dnsquery.c
+++ b/contrib/bind/bin/dnsquery/dnsquery.c
@@ -1,9 +1,9 @@
#if !defined(lint) && !defined(SABER)
-static char rcsid[] = "$Id: dnsquery.c,v 8.7 1997/05/21 19:51:22 halley Exp $";
+static const char rcsid[] = "$Id: dnsquery.c,v 8.13 1999/10/13 16:38:59 vixie Exp $";
#endif /* not lint */
/*
- * Copyright (c) 1996 by Internet Software Consortium.
+ * Copyright (c) 1996,1999 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
@@ -33,6 +33,7 @@ static char rcsid[] = "$Id: dnsquery.c,v 8.7 1997/05/21 19:51:22 halley Exp $";
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include "port_after.h"
@@ -41,6 +42,8 @@ extern int errno;
extern int h_errno;
extern char *h_errlist[];
+struct __res_state res;
+
int
main(int argc, char *argv[]) {
char name[MAXDNAME];
@@ -68,13 +71,13 @@ main(int argc, char *argv[]) {
}
/* handle args */
- while ((c = getopt(argc, argv, "c:dh:n:p:r:st:u:v")) != EOF) {
+ while ((c = getopt(argc, argv, "c:dh:n:p:r:st:u:v")) != -1) {
switch (c) {
- case 'r' : _res.retry = atoi(optarg);
+ case 'r' : res.retry = atoi(optarg);
break;
- case 'p' : _res.retrans = atoi(optarg);
+ case 'p' : res.retrans = atoi(optarg);
break;
case 'h' : strcpy(name, optarg);
@@ -123,10 +126,11 @@ main(int argc, char *argv[]) {
* So, we must init the resolver before any
* of this.
*/
- if (!(_res.options & RES_INIT))
- if (res_init() == -1) {
+ if (!(res.options & RES_INIT))
+ if (res_ninit(&res) == -1) {
fprintf(stderr,
- "res_init() failed\n");
+ "res_ninit() failed\n"
+ );
exit(-1);
}
if (nameservers >= MAXNS) break;
@@ -158,29 +162,28 @@ main(int argc, char *argv[]) {
len = sizeof(answer);
+ if (!(res.options & RES_INIT))
+ if (res_ninit(&res) == -1) {
+ fprintf(stderr, "res_ninit() failed\n");
+ exit(-1);
+ }
+
/*
* set these here so they aren't set for a possible call to
* gethostbyname above
*/
- if (debug || stream) {
- if (!(_res.options & RES_INIT))
- if (res_init() == -1) {
- fprintf(stderr, "res_init() failed\n");
- exit(-1);
- }
- if (debug)
- _res.options |= RES_DEBUG;
- if (stream)
- _res.options |= RES_USEVC;
- }
+ if (debug)
+ res.options |= RES_DEBUG;
+ if (stream)
+ res.options |= RES_USEVC;
/* if the -n flag was used, add them to the resolver's list */
if (nameservers != 0) {
- _res.nscount = nameservers;
+ res.nscount = nameservers;
for (i = nameservers - 1; i >= 0; i--) {
- _res.nsaddr_list[i].sin_addr.s_addr = q_nsaddr[i].s_addr;
- _res.nsaddr_list[i].sin_family = AF_INET;
- _res.nsaddr_list[i].sin_port = htons(NAMESERVER_PORT);
+ res.nsaddr_list[i].sin_addr.s_addr = q_nsaddr[i].s_addr;
+ res.nsaddr_list[i].sin_family = AF_INET;
+ res.nsaddr_list[i].sin_port = htons(NAMESERVER_PORT);
}
}
@@ -190,17 +193,18 @@ main(int argc, char *argv[]) {
* which will strip the trailing dot
*/
if (name[strlen(name) - 1] == '.') {
- n = res_query(name, class, type, answer, len);
+ n = res_nquery(&res, name, class, type, answer, len);
if (n < 0) {
fprintf(stderr, "Query failed (h_errno = %d) : %s\n",
h_errno, h_errlist[h_errno]);
exit(-1);
}
- } else if ((n = res_search(name, class, type, answer, len)) < 0) {
+ } else if ((n = res_nsearch(&res, name, class, type,
+ answer, len)) < 0) {
fprintf(stderr, "Query failed (h_errno = %d) : %s\n",
h_errno, h_errlist[h_errno]);
exit(-1);
}
- fp_nquery(answer, n, stdout);
+ res_pquery(&res, answer, n, stdout);
exit(0);
}
diff --git a/contrib/bind/bin/host/Makefile b/contrib/bind/bin/host/Makefile
index c1090d4..f121ab7 100644
--- a/contrib/bind/bin/host/Makefile
+++ b/contrib/bind/bin/host/Makefile
@@ -1,4 +1,4 @@
-## Copyright (c) 1996 by Internet Software Consortium
+## Copyright (c) 1996,1999 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
@@ -13,7 +13,7 @@
## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
## SOFTWARE.
-# $Id: Makefile,v 8.18 1997/06/19 03:22:08 halley Exp $
+# $Id: Makefile,v 8.24 1999/08/08 17:51:01 vixie Exp $
DESTDIR=
CC= cc
@@ -29,15 +29,17 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include
LIBBIND = ${TOP}/lib/libbind.a
A=a
O=o
+EXE=
LEX = lex -I
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
STRIP=-s
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
LDFLAGS=
CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL}
@@ -46,26 +48,29 @@ PROG= host
SRCS= ${PROG}.c
OBJS= ${PROG}.${O}
-all: ${PROG}
+all: ${PROG}${EXE}
-${PROG}: ${OBJS} ${LIBBIND} Makefile
- ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} \
+${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile
+ ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \
${LIBBIND} ${SYSLIBS}
+.c.${O}:
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c
+
distclean: clean
clean: FRC
- rm -f ${PROG} ${OBJS} core .depend
+ rm -f ${PROG}${EXE} ${OBJS} core .depend
rm -f *.BAK *.CKP *~ *.orig
depend: ${SRCS}
- mkdep -p ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
+ mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
${DESTDIR}${DESTBIN}:
mkdir -p ${DESTDIR}${DESTBIN}
-install: ${DESTDIR}${DESTBIN} ${PROG}
- ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTBIN}/${PROG}
+install: ${DESTDIR}${DESTBIN} ${PROG}${EXE}
+ ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE}
links: FRC
@set -e; ln -s SRC/*.[ch] .
diff --git a/contrib/bind/bin/host/host.c b/contrib/bind/bin/host/host.c
index 78eb48b..bcfbe02 100644
--- a/contrib/bind/bin/host/host.c
+++ b/contrib/bind/bin/host/host.c
@@ -1,5 +1,5 @@
#ifndef lint
-static char rcsid[] = "$Id: host.c,v 8.21 1998/03/19 19:31:25 halley Exp $";
+static const char rcsid[] = "$Id: host.c,v 8.34 1999/11/11 19:39:10 cyarnell Exp $";
#endif /* not lint */
/*
@@ -56,7 +56,7 @@ static char rcsid[] = "$Id: host.c,v 8.21 1998/03/19 19:31:25 halley Exp $";
*/
/*
- * Portions Copyright (c) 1996 by Internet Software Consortium
+ * Portions Copyright (c) 1996-1999 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
@@ -76,7 +76,7 @@ static char rcsid[] = "$Id: host.c,v 8.21 1998/03/19 19:31:25 halley Exp $";
static const char copyright[] =
"@(#) Copyright (c) 1986 Regents of the University of California.\n\
Portions Copyright (c) 1993 Digital Equipment Corporation.\n\
- Portions Copyright (c) 1996 Internet Software Consortium.\n\
+ Portions Copyright (c) 1996-1999 Internet Software Consortium.\n\
All rights reserved.\n";
#endif /* not lint */
@@ -106,16 +106,22 @@ static const char copyright[] =
#include <string.h>
#include <unistd.h>
-#include "port_after.h"
+#include <memory.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <isc/dst.h>
-extern int h_errno;
-extern char *_res_resultcodes[];
+#include "port_after.h"
/* Global. */
+#define SIG_RDATA_BY_NAME 18
+#define NS_HEADERDATA_SIZE 10
+
#define NUMNS 8
#define NUMNSADDR 16
#define NUMMX 50
+#define NUMRR 127 /* max rr's per node to verify signatures for */
#define SUCCESS 0
#define TIME_OUT -1
@@ -123,22 +129,50 @@ extern char *_res_resultcodes[];
#define ERROR -3
#define NONAUTH -4
+#define MY_PACKETSZ 64*1024 /* need this to hold tcp answers */
+
typedef union {
HEADER qb1;
- u_char qb2[NS_PACKETSZ];
+ u_char qb2[MY_PACKETSZ];
} querybuf;
+#define SD_RR 1
+#define SD_SIG 2
+#define SD_BADSIG 4
+
+typedef struct {
+ u_char data[MY_PACKETSZ];
+ size_t len;
+} rrstruct;
+
+static char chase_domain[NS_MAXDNAME];
+static int chase_class;
+static int chase_type;
+static char chase_sigorigttl[NS_INT32SZ];
+static rrstruct chase_rr[NUMRR];
+static int chase_rr_num;
+static char chase_lastgoodkey[NS_MAXDNAME];
+static char chase_signer[NS_MAXDNAME];
+static u_char chase_sigrdata[MY_PACKETSZ];
+static size_t chase_sigrdata_len;
+static u_char chase_signature[MY_PACKETSZ];
+static size_t chase_signature_len;
+static int chase_step;
+static int sigchase;
+
static char cnamebuf[NS_MAXDNAME];
static u_char hostbuf[NS_MAXDNAME];
static int sockFD;
static FILE *filePtr;
-static struct __res_state orig;
+static struct __res_state res, orig;
static char *cname = NULL;
+static const char *progname = "amnesia";
static int getclass = ns_c_in, verbose = 0, list = 0;
static int server_specified = 0;
static int gettype;
+static char getdomain[NS_MAXDNAME];
/* Forward. */
@@ -146,7 +180,7 @@ static int parsetype(const char *s);
static int parseclass(const char *s);
static void printanswer(const struct hostent *hp);
static void hperror(int errnum);
-static int getaddrinfo(struct in_addr addr);
+static int addrinfo(struct in_addr addr);
static int gethostinfo(char *name);
static int getdomaininfo(const char *name, const char *domain);
static int getinfo(const char *name, const char *domain,
@@ -162,74 +196,97 @@ static const u_char * pr_cdname(const u_char *cp, const u_char *msg,
static int ListHosts(char *namePtr, int queryType);
static const char * DecodeError(int result);
+static void
+usage(const char *msg) {
+ fprintf(stderr, "%s: usage error (%s)\n", progname, msg);
+ fprintf(stderr, "\
+Usage: %s [-adlrwv] [-t querytype] [-c class] host [server]\n\
+\t-a is equivalent to '-v -t *'\n\
+\t-c class to look for non-Internet data\n\
+\t-d to turn on debugging output\n\
+\t-l to turn on 'list mode'\n\
+\t-r to disable recursive processing\n\
+\t-s recursively chase signature found in answers\n\
+\t-t querytype to look for a specific type of information\n\
+\t-v for verbose output\n\
+\t-w to wait forever until reply\n\
+", progname);
+ exit(1);
+}
+
/* Public. */
int
-main(int c, char **v) {
+main(int argc, char **argv) {
struct in_addr addr;
struct hostent *hp;
- char *s, *oldcname;
+ char *s;
int inverse = 0, waitmode = 0;
- int ncnames;
+ int ncnames, ch;
+ int nkeychains, i;
- res_init();
- _res.retrans = 5;
+ dst_init();
- if (c < 2) {
- fprintf(stderr, "Usage: host [-w] [-v] [-r] [-d] [-t querytype] [-c class] [-a] host [server]\n -w to wait forever until reply\n -v for verbose output\n -r to disable recursive processing\n -d to turn on debugging output\n -t querytype to look for a specific type of information\n -c class to look for non-Internet data\n -a is equivalent to '-v -t *'\n");
- exit(1);
- }
- while (c > 2 && v[1][0] == '-') {
- if (strcmp (v[1], "-w") == 0) {
- _res.retry = 1;
- _res.retrans = 15;
- waitmode = 1;
- v++;
- c--;
- }
- else if (strcmp (v[1], "-r") == 0) {
- _res.options &= ~RES_RECURSE;
- v++;
- c--;
- }
- else if (strcmp (v[1], "-d") == 0) {
- _res.options |= RES_DEBUG;
- v++;
- c--;
- }
- else if (strcmp (v[1], "-v") == 0) {
+ if ((progname = strrchr(argv[0], '/')) == NULL)
+ progname = argv[0];
+ else
+ progname++;
+ res_ninit(&res);
+ res.retrans = 5;
+ while ((ch = getopt(argc, argv, "ac:dlrst:vw")) != -1) {
+ switch (ch) {
+ case 'a':
verbose = 1;
- v++;
- c--;
- }
- else if (strcmp (v[1], "-l") == 0) {
+ gettype = ns_t_any;
+ break;
+ case 'c':
+ getclass = parseclass(optarg);
+ break;
+ case 'd':
+ res.options |= RES_DEBUG;
+ break;
+ case 'l':
list = 1;
- v++;
- c--;
- }
- else if (strncmp (v[1], "-t", 2) == 0) {
- v++;
- c--;
- gettype = parsetype(v[1]);
- v++;
- c--;
- }
- else if (strncmp (v[1], "-c", 2) == 0) {
- v++;
- c--;
- getclass = parseclass(v[1]);
- v++;
- c--;
- }
- else if (strcmp (v[1], "-a") == 0) {
+ break;
+ case 'r':
+ res.options &= ~RES_RECURSE;
+ break;
+ case 's':
+ sigchase = 1;
+ break;
+ case 't':
+ gettype = parsetype(optarg);
+ break;
+ case 'v':
verbose = 1;
- gettype = ns_t_any;
- v++;
- c--;
- }
- }
- if (c > 2) {
- s = v[2];
+ break;
+ case 'w':
+ res.retry = 1;
+ res.retrans = 15;
+ waitmode = 1;
+ break;
+ default:
+ usage("unrecogized switch");
+ /*NOTREACHED*/
+ }
+ }
+ if (gettype == 0) {
+ if (verbose)
+ printf ("Forcing `-t a' for signature trace.\n");
+ gettype = ns_t_a;
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc < 1)
+ usage("missing host argument");
+ strncpy(getdomain, *argv++, NS_MAXDNAME);
+ getdomain[NS_MAXDNAME-1] = 0;
+ argc--;
+ if (argc > 1)
+ usage("extra undefined arguments");
+ if (argc == 1) {
+ s = *argv++;
+ argc--;
server_specified++;
if (!inet_aton(s, &addr)) {
@@ -237,55 +294,85 @@ main(int c, char **v) {
if (hp == NULL) {
fprintf(stderr,
"Error in looking up server name:\n");
- hperror(h_errno);
+ hperror(res.res_h_errno);
exit(1);
}
- memcpy(&_res.nsaddr.sin_addr, hp->h_addr, NS_INADDRSZ);
+ memcpy(&res.nsaddr.sin_addr, hp->h_addr, NS_INADDRSZ);
printf("Using domain server:\n");
printanswer(hp);
} else {
- _res.nsaddr.sin_family = AF_INET;
- _res.nsaddr.sin_addr = addr;
- _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
+ res.nsaddr.sin_family = AF_INET;
+ res.nsaddr.sin_addr = addr;
+ res.nsaddr.sin_port = htons(NAMESERVER_PORT);
printf("Using domain server %s:\n",
- inet_ntoa(_res.nsaddr.sin_addr));
+ inet_ntoa(res.nsaddr.sin_addr));
}
- _res.nscount = 1;
- _res.retry = 2;
+ res.nscount = 1;
+ res.retry = 2;
}
- if (strcmp(v[1], ".") == 0 || !inet_aton(v[1], &addr))
+ if (strcmp(getdomain, ".") == 0 || !inet_aton(getdomain, &addr))
addr.s_addr = INADDR_NONE;
hp = NULL;
- h_errno = TRY_AGAIN;
+ res.res_h_errno = TRY_AGAIN;
/*
* We handle default domains ourselves, thank you.
*/
- _res.options &= ~RES_DEFNAMES;
+ res.options &= ~RES_DEFNAMES;
if (list)
- exit(ListHosts(v[1], gettype ? gettype : ns_t_a));
- oldcname = NULL;
- ncnames = 5;
- while (hp == NULL && h_errno == TRY_AGAIN) {
+ exit(ListHosts(getdomain, gettype ? gettype : ns_t_a));
+ ncnames = 5; nkeychains = 18;
+ while (hp == NULL && res.res_h_errno == TRY_AGAIN) {
if (addr.s_addr == INADDR_NONE) {
cname = NULL;
- if (oldcname == NULL)
- hp = (struct hostent *)gethostinfo(v[1]);
- else
- hp = (struct hostent *)gethostinfo(oldcname);
- if (cname) {
+ hp = (struct hostent *)gethostinfo(getdomain);
+ getdomain[0] = 0; /* clear this query */
+ if (sigchase && (chase_step & SD_RR)) {
+ if (nkeychains-- == 0) {
+ printf("Too many sig/key chains. Loop?\n");
+ exit(1);
+ }
+ if (chase_step & SD_SIG) {
+ /* start new query, for KEY */
+ strcpy (getdomain, chase_signer);
+ strcat (getdomain, ".");
+ gettype = ns_t_key;
+ } else if (!(chase_step & SD_BADSIG)) {
+ /* start new query, for SIG */
+ strcpy (getdomain, chase_domain);
+ strcat (getdomain, ".");
+ gettype = ns_t_sig;
+ } else if (hp && !(chase_step & SD_SIG) &&
+ (chase_step & SD_BADSIG)) {
+ printf ("%s for %s not found, last verified key %s\n",
+ chase_step & SD_SIG ? "Key" : "Signature",
+ chase_step & SD_SIG ? chase_signer : chase_domain,
+ chase_domain,
+ chase_lastgoodkey ? chase_lastgoodkey : "None");
+ }
+ }
+ if (!getdomain[0] && cname) {
if (ncnames-- == 0) {
printf("Too many cnames. Loop?\n");
exit(1);
}
- strcat(cname, ".");
- oldcname = cname;
+ strcpy(getdomain, cname);
+ strcat(getdomain, ".");
+ }
+ if (getdomain[0]) {
+ if (chase_step & SD_SIG) {
+ printf ("Locating key for %s\n", getdomain);
+ } else if (chase_step & SD_SIG) {
+ printf ("Locating signature for %s record(s) on %s\n",
+ sym_ntos(__p_type_syms, chase_type, NULL),
+ getdomain);
+ }
hp = NULL;
- h_errno = TRY_AGAIN;
+ res.res_h_errno = TRY_AGAIN;
continue;
}
} else {
- if (getaddrinfo(addr) == 0)
+ if (addrinfo(addr) == 0)
hp = NULL;
else
hp = (struct hostent *)1; /* XXX */
@@ -295,7 +382,7 @@ main(int c, char **v) {
}
if (hp == NULL) {
- hperror(h_errno);
+ hperror(res.res_h_errno);
exit(1);
}
@@ -317,6 +404,7 @@ parsetype(const char *s) {
return (atoi(s));
fprintf(stderr, "Invalid query type: %s\n", s);
exit(2);
+ /*NOTREACHED*/
}
static int
@@ -330,6 +418,7 @@ parseclass(const char *s) {
return (atoi(s));
fprintf(stderr, "Invalid query class: %s\n", s);
exit(2);
+ /*NOTREACHED*/
}
static void
@@ -430,7 +519,7 @@ hperror(int errnum) {
}
static int
-getaddrinfo(struct in_addr addr) {
+addrinfo(struct in_addr addr) {
u_int32_t ha = ntohl(addr.s_addr);
char name[NS_MAXDNAME];
@@ -445,6 +534,7 @@ getaddrinfo(struct in_addr addr) {
static int
gethostinfo(char *name) {
char *cp, **domain;
+ char tmp[NS_MAXDNAME];
const char *tp;
int hp, nDomain;
int asis = 0;
@@ -463,13 +553,13 @@ gethostinfo(char *name) {
cp[-1] = '.';
return (hp);
}
- if (n == 0 && (tp = hostalias(name))) {
+ if (n == 0 && (tp = res_hostalias(&res, name, tmp, sizeof tmp))) {
if (verbose)
printf("Aliased to \"%s\"\n", tp);
- _res.options |= RES_DEFNAMES;
+ res.options |= RES_DEFNAMES;
return (getdomaininfo(tp, (char *)NULL));
}
- if (n >= _res.ndots) {
+ if (n >= res.ndots) {
asis = 1;
if (verbose)
printf("Trying null domain\n");
@@ -477,14 +567,14 @@ gethostinfo(char *name) {
if (hp)
return (hp);
}
- for (domain = _res.dnsrch; *domain; domain++) {
+ for (domain = res.dnsrch; *domain; domain++) {
if (verbose)
printf("Trying domain \"%s\"\n", *domain);
hp = getdomaininfo(name, *domain);
if (hp)
return (hp);
}
- if (h_errno != HOST_NOT_FOUND || (_res.options & RES_DNSRCH) == 0)
+ if (res.res_h_errno != HOST_NOT_FOUND || (res.options & RES_DNSRCH) == 0)
return (0);
if (!asis)
return (0);
@@ -500,10 +590,10 @@ getdomaininfo(const char *name, const char *domain) {
if (gettype)
return (getinfo(name, domain, gettype));
else {
- val1 = getinfo(name, domain, ns_t_a);
+ val1 = getinfo(name, domain, gettype=ns_t_a);
if (cname || verbose)
return (val1);
- val2 = getinfo(name, domain, ns_t_mx);
+ val2 = getinfo(name, domain, gettype=ns_t_mx);
return (val1 || val2);
}
}
@@ -523,19 +613,19 @@ getinfo(const char *name, const char *domain, int type) {
sprintf(host, "%.*s.%.*s",
NS_MAXDNAME, name, NS_MAXDNAME, domain);
- n = res_mkquery(QUERY, host, getclass, type, NULL, 0, NULL,
- buf.qb2, sizeof buf);
+ n = res_nmkquery(&res, QUERY, host, getclass, type, NULL, 0, NULL,
+ buf.qb2, sizeof buf);
if (n < 0) {
- if (_res.options & RES_DEBUG)
- printf("res_mkquery failed\n");
- h_errno = NO_RECOVERY;
+ if (res.options & RES_DEBUG)
+ printf("res_nmkquery failed\n");
+ res.res_h_errno = NO_RECOVERY;
return (0);
}
- n = res_send(buf.qb2, n, answer.qb2, sizeof answer);
+ n = res_nsend(&res, buf.qb2, n, answer.qb2, sizeof answer);
if (n < 0) {
- if (_res.options & RES_DEBUG)
- printf("res_send failed\n");
- h_errno = TRY_AGAIN;
+ if (res.options & RES_DEBUG)
+ printf("res_nsend failed\n");
+ res.res_h_errno = TRY_AGAIN;
return (0);
}
eom = answer.qb2 + n;
@@ -544,7 +634,7 @@ getinfo(const char *name, const char *domain, int type) {
static int
printinfo(const querybuf *answer, const u_char *eom, int filter, int isls) {
- int n, n1, i, j, nmx, ancount, nscount, arcount, qdcount, buflen;
+ int n, n1, i, j, nmx, ancount, nscount, arcount, qdcount, buflen, savesigchase;
u_short pref, class;
const u_char *bp, *cp;
const HEADER *hp;
@@ -557,24 +647,24 @@ printinfo(const querybuf *answer, const u_char *eom, int filter, int isls) {
qdcount = ntohs(hp->qdcount);
nscount = ntohs(hp->nscount);
arcount = ntohs(hp->arcount);
- if (_res.options & RES_DEBUG || (verbose && isls == 0))
+ if (res.options & RES_DEBUG || (verbose && isls == 0))
printf("rcode = %d (%s), ancount=%d\n",
hp->rcode, DecodeError(hp->rcode), ancount);
if (hp->rcode != NOERROR || (ancount+nscount+arcount) == 0) {
switch (hp->rcode) {
case NXDOMAIN:
- h_errno = HOST_NOT_FOUND;
+ res.res_h_errno = HOST_NOT_FOUND;
return (0);
case SERVFAIL:
- h_errno = TRY_AGAIN;
+ res.res_h_errno = TRY_AGAIN;
return (0);
case NOERROR:
- h_errno = NO_DATA;
+ res.res_h_errno = NO_DATA;
return (0);
case FORMERR:
case NOTIMP:
case REFUSED:
- h_errno = NO_RECOVERY;
+ res.res_h_errno = NO_RECOVERY;
return (0);
}
return (0);
@@ -603,21 +693,20 @@ printinfo(const querybuf *answer, const u_char *eom, int filter, int isls) {
printf(
"The following answer is not authoritative:\n"
);
- while (--ancount >= 0 && cp && cp < eom) {
+ if (!hp->ad)
+ if (verbose && isls == 0)
+ printf("The following answer is not verified as authentic by the server:\n");
+ while (--ancount >= 0 && cp && cp < eom)
cp = pr_rr(cp, answer->qb2, stdout, filter);
- /*
- * When we ask for address and there is a CNAME, it
- * seems to return both the CNAME and the address.
- * Since we trace down the CNAME chain ourselves, we
- * don't really want to print the address at this
- * point.
- */
- if (cname && ! verbose)
- return (1);
- }
}
if (!verbose)
return (1);
+
+ /* don't chase signatures for non-answer stuff */
+
+ savesigchase = sigchase;
+ sigchase = 0;
+
if (nscount) {
printf("For authoritative answers, see:\n");
while (--nscount >= 0 && cp && cp < eom)
@@ -628,9 +717,80 @@ printinfo(const querybuf *answer, const u_char *eom, int filter, int isls) {
while (--arcount >= 0 && cp && cp < eom)
cp = (u_char *)pr_rr(cp, answer->qb2, stdout, filter);
}
+
+ /* restore sigchase value */
+
+ sigchase = savesigchase;
+
return (1);
}
+void print_hex_field (u_int8_t field[], int length, int width, char *pref)
+{
+ /* Prints an arbitrary bit field, from one address for some number of
+ bytes. Output is formatted via the width, and includes the raw
+ hex value and (if printable) the printed value underneath. "pref"
+ is a string used to start each line, e.g., " " to indent.
+
+ This is very useful in gdb to see what's in a memory field.
+ */
+ int i, start, stop;
+
+ start=0;
+ do
+ {
+ stop=(start+width)<length?(start+width):length;
+ printf (pref);
+ for (i = start; i < stop; i++)
+ printf ("%02x ", (u_char) field[i]);
+ printf ("\n");
+
+ printf (pref);
+ for (i = start; i < stop; i++)
+ if (isprint(field[i]))
+ printf (" %c ", (u_char) field[i]);
+ else
+ printf (" ");
+ printf ("\n");
+
+ start = stop;
+ } while (start < length);
+}
+
+void memswap (void *s1, void *s2, size_t n)
+{
+ void *tmp;
+
+ tmp = malloc(n);
+ if (!tmp) {
+ printf ("Out of memory\n");
+ exit (1);
+ }
+
+ memcpy(tmp, s1, n);
+ memcpy(s1, s2, n);
+ memcpy(s2, tmp, n);
+
+ free (tmp);
+}
+
+void print_hex (u_int8_t field[], int length)
+{
+ /* Prints the hex values of a field...not as pretty as the print_hex_field.
+ */
+ int i, start, stop;
+
+ start=0;
+ do
+ {
+ stop=length;
+ for (i = start; i < stop; i++)
+ printf ("%02x ", (u_char) field[i]);
+ start = stop;
+ if (start < length) printf ("\n");
+ } while (start < length);
+}
+
/*
* Print resource record fields in human readable form.
*/
@@ -639,16 +799,21 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) {
int type, class, dlen, n, c, proto, ttl;
struct in_addr inaddr;
u_char in6addr[NS_IN6ADDRSZ];
+ const u_char *savecp = cp;
const u_char *cp1;
struct protoent *protop;
struct servent *servp;
char punc = ' ';
int doprint;
char name[NS_MAXDNAME];
+ char thisdomain[NS_MAXDNAME];
char tmpbuf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+ u_char canonrr[MY_PACKETSZ];
+ size_t canonrr_len = 0;
if ((cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name))) == NULL)
return (NULL); /* compression error */
+ strcpy(thisdomain, name);
type = ns_get16(cp);
cp += INT16SZ;
@@ -711,10 +876,31 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) {
case ns_t_mr:
case ns_t_ns:
case ns_t_ptr:
- cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
+ {
+ const u_char *startrdata = cp;
+ u_char cdname[NS_MAXCDNAME];
+
+ cp = (u_char *)pr_cdname(cp, msg, name, sizeof name);
if (doprint)
- fprintf(file,"%c%s",punc, name);
+ fprintf(file, "%c%s", punc, name);
+
+ /* Extract DNSSEC canonical RR. */
+
+ n = ns_name_unpack(msg, msg+MY_PACKETSZ, startrdata,
+ cdname, sizeof cdname);
+ if (n >= 0)
+ n = ns_name_ntol(cdname, cdname, sizeof cdname);
+ if (n >= 0) {
+ /* Copy header. */
+ memcpy(canonrr, cp1 - NS_HEADERDATA_SIZE, NS_HEADERDATA_SIZE);
+ /* Overwrite length field. */
+ ns_put16(n, canonrr + NS_HEADERDATA_SIZE - NS_INT16SZ);
+ /* Copy unpacked name. */
+ memcpy(canonrr + NS_HEADERDATA_SIZE, cdname, n);
+ canonrr_len = NS_HEADERDATA_SIZE + n;
+ }
break;
+ }
case ns_t_hinfo:
case ns_t_isdn:
@@ -739,12 +925,47 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) {
break;
case ns_t_soa:
- cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
+ {
+ const u_char *startname = cp;
+ u_char cdname[NS_MAXCDNAME];
+
+ cp = (u_char *)pr_cdname(cp, msg, name, sizeof name);
if (doprint)
fprintf(file, "\t%s", name);
- cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
+
+ n = ns_name_unpack(msg, msg + 512, startname,
+ cdname, sizeof cdname);
+ if (n >= 0)
+ n = ns_name_ntol(cdname, cdname, sizeof cdname);
+ if (n >= 0) {
+ /* Copy header. */
+ memcpy(canonrr, cp1 - NS_HEADERDATA_SIZE, NS_HEADERDATA_SIZE);
+ /* Copy expanded name. */
+ memcpy(canonrr + NS_HEADERDATA_SIZE, cdname, n);
+ canonrr_len = NS_HEADERDATA_SIZE + n;
+ }
+
+ startname = cp;
+ cp = (u_char *)pr_cdname(cp, msg, name, sizeof name);
if (doprint)
fprintf(file, " %s", name);
+
+ n = ns_name_unpack(msg, msg + 512, startname,
+ cdname, sizeof cdname);
+ if (n >= 0)
+ n = ns_name_ntol(cdname, cdname, sizeof cdname);
+ if (n >= 0) {
+ /* Copy expanded name. */
+ memcpy(canonrr + canonrr_len, cdname, n);
+ canonrr_len += n;
+ /* Copy rest of SOA. */
+ memcpy(canonrr + canonrr_len, cp, 5 * INT32SZ);
+ canonrr_len += 5 * INT32SZ;
+ /* Overwrite length field. */
+ ns_put16(canonrr_len - NS_HEADERDATA_SIZE,
+ canonrr + NS_HEADERDATA_SIZE - NS_INT16SZ);
+ }
+
if (doprint)
fprintf(file, "(\n\t\t\t%ld\t;serial (version)",
ns_get32(cp));
@@ -767,10 +988,14 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) {
ns_get32(cp));
cp += INT32SZ;
break;
-
+ }
case ns_t_mx:
case ns_t_afsdb:
case ns_t_rt:
+ {
+ const u_char *startrdata = cp;
+ u_char cdname[NS_MAXCDNAME];
+
if (doprint) {
if (type == ns_t_mx && !verbose)
fprintf(file," (pri=%d) by ", ns_get16(cp));
@@ -783,7 +1008,28 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) {
cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
if (doprint)
fprintf(file, "%s", name);
+
+ n = ns_name_unpack(msg, msg+512, startrdata + sizeof(u_short),
+ cdname, sizeof cdname);
+ if (n >= 0)
+ n = ns_name_ntol(cdname, cdname, sizeof cdname);
+ if (n >= 0) {
+ /* Copy header. */
+ memcpy(canonrr, cp1 - NS_HEADERDATA_SIZE,
+ NS_HEADERDATA_SIZE);
+ /* Overwrite length field. */
+ ns_put16(sizeof(u_short) + n,
+ canonrr + NS_HEADERDATA_SIZE - NS_INT16SZ);
+ /* Copy u_short. */
+ memcpy(canonrr + NS_HEADERDATA_SIZE, startrdata,
+ sizeof(u_short));
+ /* Copy expanded name. */
+ memcpy(canonrr + NS_HEADERDATA_SIZE + sizeof(u_short),
+ cdname, n);
+ canonrr_len = NS_HEADERDATA_SIZE + sizeof(u_short) + n;
+ }
break;
+ }
case ns_t_srv:
if (doprint)
@@ -934,6 +1180,260 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) {
} while (++n & 07);
}
break;
+ case ns_t_nxt:
+ {
+ const u_char *startrdata = cp;
+ u_char cdname[NS_MAXCDNAME];
+ size_t bitmaplen;
+
+ cp = (u_char *) pr_cdname(cp, msg, name, sizeof name);
+ if (doprint)
+ fprintf(file, "%c%s", punc, name);
+ bitmaplen = dlen - (cp - startrdata);
+
+ /* extract dnssec canonical rr */
+
+ n = ns_name_unpack(msg, msg+MY_PACKETSZ, startrdata,
+ cdname, sizeof cdname);
+ if (n >= 0)
+ n = ns_name_ntol(cdname, cdname, sizeof cdname);
+ if (n >= 0) {
+ /* Copy header. */
+ memcpy(canonrr, cp1 - NS_HEADERDATA_SIZE,
+ NS_HEADERDATA_SIZE);
+ /* Overwrite length field. */
+ ns_put16(n + bitmaplen,
+ canonrr + NS_HEADERDATA_SIZE - NS_INT16SZ);
+ /* Copy expanded name. */
+ memcpy(canonrr + NS_HEADERDATA_SIZE, cdname, n);
+ /* Copy type bit map. */
+ memcpy(canonrr + NS_HEADERDATA_SIZE + n, cp,
+ bitmaplen);
+ canonrr_len = NS_HEADERDATA_SIZE + n + bitmaplen;
+ }
+ cp += bitmaplen;
+ break;
+ }
+ case ns_t_sig:
+ {
+ int tc;
+ const u_char *origttl;
+
+ /* type covered */
+ tc = ns_get16(cp);
+ if (doprint && verbose)
+ fprintf(file, "%c%s", punc, sym_ntos(__p_type_syms, tc, NULL));
+ cp += sizeof(u_short);
+ /* algorithm */
+ if (doprint && verbose)
+ fprintf(file, " %d", *cp);
+ cp++;
+ /* labels */
+ if (doprint && verbose)
+ fprintf(file, " %d", *cp);
+ cp++;
+ /* original ttl */
+ origttl = cp;
+ if (doprint && verbose)
+ fprintf(file, " %d", ns_get32(cp));
+ cp += INT32SZ;
+ /* signature expiration */
+ if (doprint && verbose)
+ fprintf(file, " %d", ns_get32(cp));
+ cp += INT32SZ;
+ /* time signed */
+ if (doprint && verbose)
+ fprintf(file, " %d", ns_get32(cp));
+ cp += INT32SZ;
+ /* key footprint */
+ if (doprint && verbose)
+ fprintf(file, " %d", ns_get16(cp));
+ cp += sizeof(u_short);
+ /* signer's name */
+ cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name));
+ if (doprint && verbose)
+ fprintf(file, " %s", name);
+ else if (doprint && !verbose)
+ fprintf (file, " %s for type %s", name,
+ sym_ntos(__p_type_syms, tc, NULL));
+ /* signature */
+ {
+ char str[MY_PACKETSZ];
+ size_t len = cp1-cp+dlen;
+
+ b64_ntop (cp, len, str, MY_PACKETSZ-1);
+
+ if (sigchase && !(chase_step & SD_SIG) &&
+ strcmp (chase_domain, thisdomain) == 0 &&
+ chase_class == class & chase_type == tc)
+ {
+ u_char cdname[NS_MAXCDNAME];
+
+ if (doprint && !verbose)
+ fprintf(file, " (chasing key)");
+
+ strcpy(chase_signer, name);
+
+ memcpy(&chase_sigorigttl[0], origttl,
+ NS_INT32SZ);
+
+ n = ns_name_ntol(cp1 + SIG_RDATA_BY_NAME,
+ cdname, sizeof cdname);
+ if (n >= 0) {
+ memcpy(chase_sigrdata, cp1,
+ SIG_RDATA_BY_NAME);
+ memcpy(chase_sigrdata + SIG_RDATA_BY_NAME,
+ cdname, n);
+ chase_sigrdata_len += SIG_RDATA_BY_NAME + n;
+ memcpy(chase_signature, cp, len);
+ chase_signature_len = len;
+
+ chase_step |= SD_SIG;
+ }
+ } else if (sigchase) {
+ chase_step |= SD_BADSIG;
+ }
+
+ cp += len;
+ if (doprint && verbose)
+ fprintf (file, " %s", str);
+ }
+ break;
+ }
+ case ns_t_key:
+ /* flags */
+ if (doprint && verbose)
+ fprintf(file, "%c%d", punc, ns_get16(cp));
+ cp += sizeof(u_short);
+ /* protocol */
+ if (doprint && verbose)
+ fprintf(file, " %d", *cp);
+ cp++;
+ /* algorithm */
+ n = *cp;
+ if (doprint && verbose)
+ fprintf(file, " %d", *cp);
+ cp++;
+ switch (n) {
+ case 1: /* MD5/RSA */
+ {
+ char str[MY_PACKETSZ];
+ size_t len = cp1-cp+dlen;
+
+ b64_ntop (cp, len, str, MY_PACKETSZ-1);
+ cp += len;
+
+ if (doprint && verbose)
+ fprintf (file, " %s", str);
+ break;
+ }
+
+ default:
+ fprintf (stderr, "Unknown algorithm %d\n", n);
+ cp = cp1 + dlen;
+ break;
+ }
+
+ if (sigchase && (chase_step & (SD_SIG|SD_RR)) &&
+ strcmp (getdomain, name) == 0 &&
+ getclass == class & gettype == type)
+ {
+ DST_KEY *dstkey;
+ int rc, len, i, j;
+
+ /* convert dnskey to dstkey */
+
+ dstkey = dst_dnskey_to_key (name, cp1, dlen);
+
+ /* fix ttl in rr */
+
+ for (i = 0; i < NUMRR && chase_rr[i].len; i++)
+ {
+ len = dn_skipname(chase_rr[i].data,
+ chase_rr[i].data +
+ chase_rr[i].len);
+ if (len>=0)
+ memcpy(chase_rr[i].data + len + NS_INT16SZ +
+ NS_INT16SZ,
+ &chase_sigorigttl, INT32SZ);
+ }
+
+ /* sort rr's (qsort() is too slow) */
+
+ for (i = 0; i < NUMRR && chase_rr[i].len; i++)
+ for (j = i + 1; i < NUMRR && chase_rr[j].len; j++)
+ if (memcmp(chase_rr[i].data, chase_rr[j].data, MY_PACKETSZ) > 0)
+ memswap(&chase_rr[i], &chase_rr[j], sizeof(rrstruct));
+
+ /* append rr's to sigrdata */
+
+ for (i = 0; i < NUMRR && chase_rr[i].len; i++)
+ {
+ memcpy (chase_sigrdata + chase_sigrdata_len,
+ chase_rr[i].data, chase_rr[i].len);
+ chase_sigrdata_len += chase_rr[i].len;
+ }
+
+ /* print rr-data and signature */
+
+ if (verbose) {
+ print_hex_field(chase_sigrdata,
+ chase_sigrdata_len,
+ 21,"DATA: ");
+ print_hex_field(chase_signature,
+ chase_signature_len,
+ 21,"SIG: ");
+ }
+
+ /* do the works */
+
+ if (dstkey)
+ rc = dst_verify_data(SIG_MODE_ALL, dstkey, NULL,
+ chase_sigrdata,
+ chase_sigrdata_len,
+ chase_signature,
+ chase_signature_len);
+ else
+ rc = 1;
+
+ dst_free_key(dstkey);
+
+ if (verbose)
+ {
+ fprintf(file, "\nVerification %s", rc == 0 ?
+ "was SUCCESSFULL" :
+ "FAILED");
+ }
+ else
+ {
+ fprintf (file,
+ " that %s verify our %s "
+ "record(s) on %s",
+ rc == 0 ? "successfully" :
+ "DOES NOT",
+ sym_ntos(__p_type_syms, chase_type,
+ NULL),
+ chase_domain);
+ }
+
+ if (rc == 0)
+ {
+ strcpy (chase_lastgoodkey, name);
+ }
+ else
+ {
+ /* don't trace further after a failure */
+ sigchase = 0;
+ }
+
+ chase_step = 0;
+ chase_signature_len = 0;
+ chase_sigrdata_len = 0;
+ memset(chase_sigorigttl, 0, NS_INT32SZ);
+ memset(chase_rr, 0, sizeof(chase_rr));
+ chase_rr_num = 0;
+ }
+ break;
default:
if (doprint)
@@ -944,8 +1444,42 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) {
if (cp != cp1 + dlen)
fprintf(file, "packet size error (%p != %p)\n",
cp, cp1 + dlen);
+
+ if (sigchase && !(chase_step & SD_SIG) &&
+ strcmp (getdomain, thisdomain) == 0 && getclass == class &&
+ gettype == type && type != ns_t_sig)
+ {
+ u_char cdname[NS_MAXCDNAME];
+
+ if (doprint && !verbose)
+ fprintf (file, " (chasing signature)", sigchase-1);
+
+ /* unpack rr */
+
+ n = ns_name_unpack(msg, msg + MY_PACKETSZ, savecp,
+ cdname, sizeof cdname);
+ if (n >= 0)
+ n = ns_name_ntol(cdname, cdname, sizeof cdname);
+ if (n >= 0) {
+ memcpy(chase_rr[chase_rr_num].data, cdname, n);
+ memcpy(chase_rr[chase_rr_num].data + n,
+ canonrr_len ? canonrr : cp1 - NS_HEADERDATA_SIZE,
+ canonrr_len ? canonrr_len : dlen + NS_HEADERDATA_SIZE);
+ chase_rr[chase_rr_num].len =
+ n + (canonrr_len != 0 ? canonrr_len :
+ dlen + NS_HEADERDATA_SIZE);
+
+ strcpy(chase_domain, getdomain);
+ chase_class = class;
+ chase_type = type;
+ chase_step |= SD_RR;
+ chase_rr_num++;
+ }
+ }
+
if (doprint)
fprintf(file, "\n");
+
return (cp);
}
@@ -965,6 +1499,12 @@ pr_type(int type) {
return ("mail is handled");
case ns_t_txt:
return ("descriptive text");
+ case ns_t_sig:
+ return ("has a signature signed by");
+ case ns_t_key:
+ return ("has a key");
+ case ns_t_nxt:
+ return ("next valid name");
case ns_t_afsdb:
return ("DCE or AFS service from");
}
@@ -995,7 +1535,7 @@ pr_class(int class) {
static const u_char *
pr_cdname(const u_char *cp, const u_char *msg, char *name, int namelen) {
- int n = dn_expand(msg, msg + 512, cp, name, namelen - 2);
+ int n = dn_expand(msg, msg + MY_PACKETSZ, cp, name, namelen - 2);
if (n < 0)
return (NULL);
@@ -1036,7 +1576,7 @@ ListHosts(char *namePtr, int queryType) {
namePtr[i-1] = 0;
if (server_specified) {
- memcpy(&nsipaddr[0], &_res.nsaddr.sin_addr, NS_INADDRSZ);
+ memcpy(&nsipaddr[0], &res.nsaddr.sin_addr, NS_INADDRSZ);
numnsaddr = 1;
} else {
/*
@@ -1044,19 +1584,22 @@ ListHosts(char *namePtr, int queryType) {
* query, possibly followed by looking up addresses for some
* of the names.
*/
- msglen = res_mkquery(ns_o_query, namePtr, ns_c_in, ns_t_ns,
- NULL, 0, NULL, buf.qb2, sizeof buf);
+ msglen = res_nmkquery(&res, ns_o_query, namePtr,
+ ns_c_in, ns_t_ns,
+ NULL, 0, NULL,
+ buf.qb2, sizeof buf);
if (msglen < 0) {
- printf("res_mkquery failed\n");
+ printf("res_nmkquery failed\n");
return (ERROR);
}
- msglen = res_send(buf.qb2, msglen, answer.qb2, sizeof answer);
+ msglen = res_nsend(&res, buf.qb2, msglen,
+ answer.qb2, sizeof answer);
if (msglen < 0) {
printf("Cannot find nameserver -- try again later\n");
return (ERROR);
}
- if (_res.options & RES_DEBUG || verbose)
+ if (res.options & RES_DEBUG || verbose)
printf("rcode = %d (%s), ancount=%d\n",
answer.qb1.rcode, DecodeError(answer.qb1.rcode),
ntohs(answer.qb1.ancount));
@@ -1134,13 +1677,13 @@ ListHosts(char *namePtr, int queryType) {
if (dn_expand(answer.qb2, eom,
cp, name, sizeof(name)) >= 0) {
if (numns < NUMNS &&
- strcasecmp((char *)domain,
- namePtr) == 0) {
+ ns_samename((char *)domain,
+ namePtr) == 1) {
for (i = 0; i < numns; i++)
- if (strcasecmp(
+ if (ns_samename(
nsname[i],
(char *)name
- ) == 0)
+ ) == 1)
/* duplicate */
break;
if (i >= numns) {
@@ -1155,9 +1698,9 @@ ListHosts(char *namePtr, int queryType) {
} else if (type == ns_t_a) {
if (numnsaddr < NUMNSADDR)
for (i = 0; i < numns; i++) {
- if (strcasecmp(nsname[i],
+ if (ns_samename(nsname[i],
(char *)domain)
- == 0) {
+ == 1) {
nshaveaddr[i]++;
memcpy(
&nsipaddr[numnsaddr],
@@ -1195,11 +1738,11 @@ ListHosts(char *namePtr, int queryType) {
numaddrs++;
}
}
- if (_res.options & RES_DEBUG || verbose)
+ if (res.options & RES_DEBUG || verbose)
printf(
"Found %d addresses for %s by extra query\n",
numaddrs, nsname[i]);
- } else if (_res.options & RES_DEBUG || verbose)
+ } else if (res.options & RES_DEBUG || verbose)
printf("Found %d addresses for %s\n",
nshaveaddr[i], nsname[i]);
}
@@ -1218,10 +1761,10 @@ ListHosts(char *namePtr, int queryType) {
/*
* Create a query packet for the requested domain name.
*/
- msglen = res_mkquery(QUERY, namePtr, getclass, ns_t_axfr, NULL,
- 0, NULL, buf.qb2, sizeof buf);
+ msglen = res_nmkquery(&res, QUERY, namePtr, getclass, ns_t_axfr, NULL,
+ 0, NULL, buf.qb2, sizeof buf);
if (msglen < 0) {
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
fprintf(stderr, "ListHosts: Res_mkquery failed\n");
return (ERROR);
}
@@ -1240,7 +1783,7 @@ ListHosts(char *namePtr, int queryType) {
return (ERROR);
}
memcpy(&sin.sin_addr, &nsipaddr[thisns], NS_INADDRSZ);
- if (_res.options & RES_DEBUG || verbose)
+ if (res.options & RES_DEBUG || verbose)
printf("Trying %s\n", inet_ntoa(sin.sin_addr));
if (connect(sockFD, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
break;
@@ -1310,7 +1853,7 @@ ListHosts(char *namePtr, int queryType) {
if (i != NOERROR || ntohs(buf.qb1.ancount) == 0) {
if (thisns + 1 < numnsaddr &&
(i == SERVFAIL || i == NOTIMP || i == REFUSED)) {
- if (_res.options & RES_DEBUG || verbose)
+ if (res.options & RES_DEBUG || verbose)
printf(
"Server failed, trying next server: %s\n",
i != NOERROR
@@ -1356,7 +1899,7 @@ ListHosts(char *namePtr, int queryType) {
(void) dn_expand(buf.qb2, buf.qb2 + len, nmp,
dname[soacnt], sizeof dname[0]);
if (soacnt) {
- if (strcmp(dname[0], dname[1]) == 0)
+ if (ns_samename(dname[0], dname[1]) == 1)
break;
} else
soacnt++;
@@ -1383,7 +1926,7 @@ ListHosts(char *namePtr, int queryType) {
fprintf(stderr,"ListHosts: error receiving zone transfer:\n");
fprintf(stderr,
" result: %s, answers = %d, authority = %d, additional = %d\n",
- _res_resultcodes[headerPtr->rcode],
+ p_rcode(headerPtr->rcode),
ntohs(headerPtr->ancount), ntohs(headerPtr->nscount),
ntohs(headerPtr->arcount));
return (ERROR);
@@ -1395,16 +1938,16 @@ ListHosts(char *namePtr, int queryType) {
static const char *
DecodeError(int result) {
switch(result) {
- case NOERROR: return ("Success"); break;
- case FORMERR: return ("Format error"); break;
- case SERVFAIL: return ("Server failed"); break;
- case NXDOMAIN: return ("Non-existent domain"); break;
- case NOTIMP: return ("Not implemented"); break;
- case REFUSED: return ("Query refused"); break;
- case NO_INFO: return ("No information"); break;
- case ERROR: return ("Unspecified error"); break;
- case TIME_OUT: return ("Timed out"); break;
- case NONAUTH: return ("Non-authoritative answer"); break;
+ case NOERROR: return ("Success");
+ case FORMERR: return ("Format error");
+ case SERVFAIL: return ("Server failed");
+ case NXDOMAIN: return ("Non-existent domain");
+ case NOTIMP: return ("Not implemented");
+ case REFUSED: return ("Query refused");
+ case NO_INFO: return ("No information");
+ case ERROR: return ("Unspecified error");
+ case TIME_OUT: return ("Timed out");
+ case NONAUTH: return ("Non-authoritative answer");
default: return ("BAD ERROR VALUE");
}
/* NOTREACHED */
diff --git a/contrib/bind/bin/irpd/Makefile b/contrib/bind/bin/irpd/Makefile
new file mode 100644
index 0000000..6f94d63
--- /dev/null
+++ b/contrib/bind/bin/irpd/Makefile
@@ -0,0 +1,98 @@
+## 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 1.3 1999/02/22 02:47:55 vixie 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
+EXE=
+LEX = lex -I
+YACC = yacc -d
+SYSLIBS = -ll -lutil
+DESTBIN = /usr/local/bin
+DESTSBIN = /usr/local/sbin
+DESTEXEC = /usr/local/libexec
+DESTMAN = /usr/share/man
+DESTHELP= /usr/share/misc
+DESTETC= /etc
+DESTRUN= /var/run
+AR= ar cru
+INSTALL= install
+STRIP=-s
+
+PS=ps
+LDFLAGS=
+CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} -I${TOP}/lib/irs ${DEFS}
+
+VER= LOCAL-`date +%y%m%d.%H%M%S`
+HOSTNAMECMD= hostname || uname -n
+
+PROG= irpd
+HDRS=
+SRCS= irpd.c
+OBJS= irpd.${O}
+
+all: ${PROG}${EXE}
+
+${PROG}${EXE}: irpd.${O} tmp_version.${O} ${LIBBIND}
+ ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG}${EXE} ${OBJS} tmp_version.${O} \
+ ${LIBBIND} ${SYSLIBS}
+
+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)
+
+distclean: clean
+
+clean: FRC
+ rm -f ${PROG}${EXE} ${OBJS} core .depend
+ rm -f *.BAK *.CKP *~ *.orig
+ rm -f tmp_version.c tmp_version.${O}
+
+depend: ${SRCS}
+ mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} -I${TOP}/lib/irs ${DEFS} ${SRCS}
+
+${DESTDIR}${DESTSBIN}:
+ mkdir -p ${DESTDIR}${DESTSBIN}
+
+install: ${DESTDIR}${DESTSBIN} ${PROG}${EXE}
+ ${INSTALL} ${STRIP} -c -m 755 ${PROG}${EXE} ${DESTDIR}${DESTSBIN}/${PROG}${EXE}
+
+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/irpd/irpd.c b/contrib/bind/bin/irpd/irpd.c
new file mode 100644
index 0000000..a2b13cb
--- /dev/null
+++ b/contrib/bind/bin/irpd/irpd.c
@@ -0,0 +1,2252 @@
+/*
+ * Copyright(c) 1999 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.
+ */
+
+/* Notes. */
+
+#if 0
+
+I have to use an AF_INET. Ctl_server should probably take a AF arugment.
+
+The server has no way to issue any other greeting than HELLO. E.g., would
+like to be able to drop connection on greeting if client is not comming
+from 127.0.0.1.
+
+Need to fix client to handle response with body.
+
+should add iovec with body to the struct ctl_sess?
+
+should we close connections on some errors (like marshalling errors)?
+
+getnetbyname falls back to /etc/networks when named not running. Does not
+seem to be so for getnetbyaddr
+
+#endif
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irpd.c,v 1.7 1999/10/13 16:26:23 vixie Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <ctype.h>
+#include <errno.h>
+#include <grp.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <pwd.h>
+#include <resolv.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <utmp.h>
+
+#ifdef EMPTY
+/* Digital UNIX utmp.h defines this. */
+#undef EMPTY
+#endif
+
+#include <isc/ctl.h>
+#include <isc/assertions.h>
+#include <isc/list.h>
+#include <isc/memcluster.h>
+#include <isc/logging.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/irpmarshall.h>
+#include <irs_data.h>
+
+#include "port_after.h"
+
+/* Macros. */
+
+#define ALLDIGITS(s) (strspn((s), "0123456789") == strlen((s)))
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+#define MAXNETNAMELEN 256
+
+#if !defined(SUN_LEN)
+#define SUN_LEN(su) \
+ (sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path))
+#endif
+
+/*
+ * This macro is used to initialize a specified field of a net_data struct.
+ * If the initialization fails then an error response code is sent with a
+ * description of which field failed to be initialized.
+ *
+ * This is only meant for use at the start of the various verb functions.
+ */
+
+#define ND_INIT(nd, field, sess, respcode) \
+ do{ if ((nd)->field == 0) { \
+ (nd)->field = (*(nd)->irs->field ## _map)(nd->irs); \
+ if ((nd)->field == 0) { \
+ char *msg = "net_data " #field " initialization failed"; \
+ ctl_response(sess, respcode, msg, CTL_EXIT, NULL, \
+ NULL, NULL, NULL, 0); \
+ return; \
+ } \
+ } \
+ } while (0)
+
+/* Data structures. */
+
+struct arg_s {
+ struct iovec * iov;
+ int iovlen;
+};
+
+struct response_buff {
+ char * buff;
+ size_t bufflen;
+};
+
+struct client_ctx {
+ struct net_data * net_data;
+};
+
+/* Forwards. */
+
+static struct response_buff *newbuffer(u_int length);
+static void release_buffer(struct response_buff *b);
+static struct arg_s *split_string(const char *string);
+static void free_args(struct arg_s *args);
+static int is_all_digits(char *p);
+static struct client_ctx *make_cli_ctx(void);
+static struct net_data *get_net_data(struct ctl_sess *sess);
+
+static void irpd_gethostbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_gethostbyname2(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_gethostbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_gethostent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_sethostent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getpwnam(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getpwuid(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getpwent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_setpwent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getnetbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getnetbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getnetent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_setnetent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getgrnam(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getgrgid(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_setgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getservbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getservbyport(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getservent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_setservent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getprotobyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getprotobynumber(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_setprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_innetgr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_setnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_endnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_quit(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_help(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_accept(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_abort(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+
+static void irpd_done(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ void *param);
+static void response_done(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ void *uap);
+static void logger(enum ctl_severity, const char *fmt, ...);
+
+/* Constants. */
+
+static const u_int hello_code = IRPD_WELCOME_CODE;
+static const char hello_msg[] = "Welcome to IRPD (v 1)";
+static const u_int unkncode = 500;
+static const u_int timeoutcode = 501;
+static const u_int irpd_quit_ok = 201;
+static const u_int timeout = IRPD_TIMEOUT;
+
+/* Globals. */
+
+static int main_needs_exit = 0;
+static evContext ev;
+
+struct ctl_verb verbs [] = {
+ { "gethostbyname", irpd_gethostbyname },
+ { "gethostbyname2", irpd_gethostbyname2 },
+ { "gethostbyaddr", irpd_gethostbyaddr },
+ { "gethostent", irpd_gethostent },
+ { "sethostent", irpd_sethostent },
+#ifdef WANT_IRS_PW
+ { "getpwnam", irpd_getpwnam },
+ { "getpwuid", irpd_getpwuid },
+ { "getpwent", irpd_getpwent },
+ { "setpwent", irpd_setpwent },
+#endif
+ { "getnetbyname", irpd_getnetbyname },
+ { "getnetbyaddr", irpd_getnetbyaddr },
+ { "getnetent", irpd_getnetent },
+ { "setnetent", irpd_setnetent },
+#ifdef WANT_IRS_GR
+ { "getgrnam", irpd_getgrnam },
+ { "getgrgid", irpd_getgrgid },
+ { "getgrent", irpd_getgrent },
+ { "setgrent", irpd_setgrent },
+#endif
+ { "getservbyname", irpd_getservbyname },
+ { "getservbyport", irpd_getservbyport },
+ { "getservent", irpd_getservent },
+ { "setservent", irpd_setservent },
+
+ { "getprotobyname", irpd_getprotobyname },
+ { "getprotobynumber", irpd_getprotobynumber },
+ { "getprotoent", irpd_getprotoent },
+ { "setprotoent", irpd_setprotoent },
+
+ { "getnetgrent", irpd_getnetgrent },
+ { "innetgr", irpd_innetgr },
+ { "setnetgrent", irpd_setnetgrent },
+ { "endnetgrent", irpd_endnetgrent },
+ { "quit", irpd_quit },
+ { "help", irpd_help },
+
+ { "", irpd_accept }, /* For connection setups. */
+
+ /* abort is a verb expected by the ctl library. Is called when the
+ * client drops the connection unexpectedly.
+ */
+ { "abort", irpd_abort },
+
+ { NULL, NULL }
+};
+
+/*
+ * An empty string causes the library to use the compiled in
+ * defaults and to ignore any external files.
+ */
+char *conffile = "";
+
+/* Public. */
+
+int
+main(int argc, char **argv) {
+ struct ctl_sctx *ctx;
+ struct sockaddr *addr;
+ struct sockaddr_un uaddr;
+ struct sockaddr_in iaddr;
+ log_channel chan;
+ short port = IRPD_PORT;
+ char *prog = argv[0];
+ char *sockname = IRPD_PATH;
+ char *p;
+ int ch;
+ size_t socksize;
+
+ addr = (struct sockaddr *)&iaddr;
+ socksize = sizeof iaddr;
+
+ openlog("iprd", LOG_CONS|LOG_PID, LOG_DAEMON);
+ while ((ch = getopt(argc, argv, "u:p:c:")) != -1) {
+ switch(ch) {
+ case 'c':
+ conffile = optarg;
+ break;
+
+ case 'p':
+ port = strtol(optarg, &p, 10);
+ if (*p != '\0') {
+ /* junk in argument */
+ syslog(LOG_ERR, "port option not a number");
+ exit(1);
+ }
+ break;
+
+ case 'u':
+ sockname = optarg;
+ addr = (struct sockaddr *)&uaddr;
+ socksize = sizeof uaddr;
+ break;
+
+ case 'h':
+ case '?':
+ default:
+ fprintf(stderr, "%s [ -c config-file ]\n", prog);
+ exit(1);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ memset(&uaddr, 0, sizeof uaddr);
+ memset(&iaddr, 0, sizeof iaddr);
+
+#ifdef HAVE_SA_LEN
+ iaddr.sin_len = sizeof iaddr;
+#endif
+ iaddr.sin_family = AF_INET;
+ iaddr.sin_port = htons(IRPD_PORT);
+ iaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ uaddr.sun_family = AF_UNIX;
+ strncpy(uaddr.sun_path, sockname, sizeof uaddr.sun_path);
+#ifdef HAVE_SA_LEN
+ uaddr.sun_len = SUN_LEN(&uaddr);
+#endif
+
+ if (addr == (struct sockaddr *)&uaddr)
+ socksize = SUN_LEN(&uaddr);
+
+ /* XXX what if this file is not currently a socket? */
+ unlink(sockname);
+
+ evCreate(&ev);
+
+ ctx = ctl_server(ev, addr, socksize, verbs,
+ unkncode, timeoutcode, /* IRPD_TIMEOUT */ 30, 5,
+ IRPD_MAXSESS, logger, NULL);
+
+ INSIST(ctx != NULL);
+
+ while (!main_needs_exit) {
+ evEvent event;
+
+ INSIST_ERR(evGetNext(ev, &event, EV_WAIT) != -1);
+ INSIST_ERR(evDispatch(ev, event) != -1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * static void
+ * simple_response(struct ctl_sess *sess, u_int code, char *msg);
+ * Send back a simple, one-line response to the client.
+ */
+static void
+simple_response(struct ctl_sess *sess, u_int code, char *msg) {
+ struct response_buff *b = newbuffer(strlen(msg) + 1);
+
+ if (b == 0)
+ return;
+ strcpy(b->buff, msg);
+ ctl_response(sess, code, b->buff, 0, 0, response_done, b, NULL, 0);
+}
+
+/*
+ * static void
+ * send_hostent(struct ctl_sess *sess, struct hostent *ho);
+ * Send a hostent struct over the wire. If HO is NULL, then
+ * a "No such host" is sent instead.
+ */
+static void
+send_hostent(struct ctl_sess *sess, struct hostent *ho) {
+ if (ho == NULL)
+ simple_response(sess, IRPD_GETHOST_NONE, "No such host");
+ else {
+ size_t need;
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_ho(ho, &b->buff, &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Internal error");
+ logger(ctl_warning,
+ "Cannot marshall host data for %s\n",
+ ho->h_name);
+ release_buffer(b);
+ } else {
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETHOST_OK, "Host found",
+ 0, 0, response_done,
+ b, b->buff, strlen(b->buff));
+ }
+ }
+}
+
+/*
+ * static void
+ * do_gethostbyname2(struct ctl_sess *sess, struct net_data *nd,
+ * const char *hostname, int af);
+ * Look up the given HOSTNAME by Address-Family
+ * and then send the results to the client connected to
+ * SESS.
+ */
+static void
+do_gethostbyname2(struct ctl_sess *sess, struct net_data *nd,
+ const char *hostname, int af)
+{
+ struct hostent *ho;
+
+ ho = gethostbyname2_p(hostname, af, nd);
+ send_hostent(sess, ho);
+}
+
+/*
+ * static void
+ * irpd_gethostbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETHOSTBYNAME verb.
+ */
+static void
+irpd_gethostbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ char hname[MAXHOSTNAMELEN];
+ struct arg_s *args;
+ int i;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Incorrect usage: GETHOSTBYNAME hostname");
+ } else {
+ if (args->iov[0].iov_len >= sizeof hname) {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "GETHOSTBYNAME: name too long");
+ } else {
+ strncpy(hname, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ hname[args->iov[0].iov_len] = '\0';
+ do_gethostbyname2(sess, netdata, hname, AF_INET);
+ }
+ }
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_gethostbyname2(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETHOSTBYNAME2 verb.
+ */
+static void
+irpd_gethostbyname2(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ char hname[MAXHOSTNAMELEN];
+ struct arg_s *args;
+ int i;
+ int af;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 3) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Incorrect usage: GETHOSTBYNAME2 hostname AF");
+ } else if (args->iov[0].iov_len >= sizeof hname) {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "GETHOSTBYNAME2: name too long");
+ } else {
+ if (strncasecmp(args->iov[1].iov_base, "af_inet6", 8) == 0)
+ af = AF_INET6;
+ else if (strncasecmp(args->iov[1].iov_base, "af_inet", 7) == 0)
+ af = AF_INET;
+ else {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Unknown address family");
+ goto untimely;
+ }
+
+ strncpy(hname, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ hname[args->iov[0].iov_len] = '\0';
+ do_gethostbyname2(sess, netdata, hname, af);
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_gethostbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETHOSTBYADDR verb.
+ */
+static void
+irpd_gethostbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct hostent *ho;
+ char haddr[MAXHOSTNAMELEN];
+ char tmpaddr[NS_IN6ADDRSZ];
+ struct arg_s *args;
+ int i;
+ int af;
+ int addrlen;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 3) {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "GETHOSTBYADDR addr afamily");
+ } else {
+ if (args->iov[0].iov_len >= sizeof haddr) {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Address too long");
+ } else {
+ strncpy(haddr, args->iov[1].iov_base,
+ args->iov[1].iov_len);
+ haddr[args->iov[1].iov_len] = '\0';
+ if (strcasecmp(haddr, "af_inet") == 0) {
+ af = AF_INET;
+ addrlen = NS_INADDRSZ;
+ } else if (strcasecmp(haddr, "af_inet6") == 0) {
+ af = AF_INET6;
+ addrlen = NS_IN6ADDRSZ;
+ } else {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Unknown address family");
+ goto untimely;
+ }
+
+ strncpy(haddr, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ haddr[args->iov[0].iov_len] = '\0';
+
+ if (inet_pton(af, haddr, tmpaddr) != 1) {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Invalid address");
+ goto untimely;
+ }
+
+ ho = gethostbyaddr_p(tmpaddr, addrlen, af, netdata);
+ send_hostent(sess, ho);
+ }
+ }
+
+ untimely:
+ free_args(args);
+}
+
+
+/*
+ * static void
+ * irpd_gethostent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETHOSTENT verb
+ */
+static void
+irpd_gethostent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct hostent *ho;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR);
+
+ ho = gethostent_p(netdata);
+
+ send_hostent(sess, ho);
+}
+
+/*
+ * static void
+ * irpd_sethostent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the SETHOSTENT verb
+ */
+static void
+irpd_sethostent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct hostent *ho;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR);
+
+ sethostent_p(1, netdata); /* always stayopen */
+ simple_response(sess, IRPD_GETHOST_SETOK, "ok");
+}
+
+#ifdef WANT_IRS_PW
+/*
+ * static void
+ * send_pwent(struct ctl_sess *sess, struct passwd *pw);
+ * Send PW over the wire, or, if PW is NULL, a "No such
+ * user" response.
+ */
+static void
+send_pwent(struct ctl_sess *sess, struct passwd *pw) {
+ if (pw == NULL) {
+ simple_response(sess, IRPD_GETUSER_NONE,
+ "No such user");
+ } else {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_pw(pw, &b->buff,
+ &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETUSER_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall pw\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETUSER_OK, "User found", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+ }
+}
+
+/*
+ * static void
+ * irpd_getpwnam(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETPWNAM verb
+ */
+static void
+irpd_getpwnam(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct passwd *pw;
+ char username[64];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pw, sess, IRPD_GETUSER_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETUSER_ERROR,
+ "GETPWNAM username");
+ } else {
+ if (args->iov[0].iov_len >= sizeof username) {
+ simple_response(sess, IRPD_GETUSER_ERROR,
+ "Name too long");
+ } else {
+ strncpy(username, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ username[args->iov[0].iov_len] = '\0';
+
+ pw = getpwnam_p(username, netdata);
+ send_pwent(sess, pw);
+ }
+ }
+
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getpwuid(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETPWUID verb.
+ */
+static void
+irpd_getpwuid(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct passwd *pw;
+ char userid[64];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pw, sess, IRPD_GETUSER_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETUSER_ERROR,
+ "GETPWUID uid");
+ } else {
+ if (args->iov[0].iov_len >= sizeof userid) {
+ simple_response(sess, IRPD_GETUSER_ERROR,
+ "Name too long");
+ } else {
+ strncpy(userid, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ userid[args->iov[0].iov_len] = '\0';
+
+ if (!ALLDIGITS(userid)) {
+ simple_response(sess, IRPD_GETUSER_ERROR,
+ "Not a uid");
+ } else {
+ uid_t uid;
+ long lval;
+
+ lval = strtol(userid, 0, 10);
+ uid = (uid_t)lval;
+ if ((long)uid != lval) {
+ /* value was too big */
+ simple_response(sess,
+ IRPD_GETUSER_ERROR,
+ "Not a valid uid");
+ goto untimely;
+ }
+
+ pw = getpwuid_p(uid, netdata);
+ send_pwent(sess, pw);
+ }
+ }
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getpwent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implemtnation of the GETPWENT verb.
+ */
+static void
+irpd_getpwent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct passwd *pw;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pw, sess, IRPD_GETUSER_ERROR);
+
+ pw = getpwent_p(netdata);
+ send_pwent(sess, pw);
+}
+
+/*
+ * static void
+ * irpd_setpwent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implemtnation of the SETPWENT verb.
+ */
+static void
+irpd_setpwent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct passwd *pw;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pw, sess, IRPD_GETUSER_ERROR);
+
+ setpwent_p(netdata);
+ simple_response(sess, IRPD_GETUSER_SETOK, "ok");
+}
+#endif /* WANT_IRS_PW */
+
+/*
+ * static void
+ * send_nwent(struct ctl_sess *sess, struct nwent *ne);
+ * Sends a nwent structure over the wire, or "No such
+ * network" if NE is NULL.
+ */
+static void
+send_nwent(struct ctl_sess *sess, struct nwent *nw) {
+ if (nw == NULL) {
+ simple_response(sess, IRPD_GETNET_NONE, "No such net");
+ } else {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_nw(nw, &b->buff,
+ &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall nw\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETNET_OK, "Network found", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+ }
+}
+
+/*
+ * static void
+ * send_netent(struct ctl_sess *sess, struct netent *ne);
+ * Sends a NETENT structure over the wire, or "No such
+ * Network" error if NE is NULL.
+ */
+static void
+send_netent(struct ctl_sess *sess, struct netent *ne) {
+ if (ne == NULL) {
+ simple_response(sess, IRPD_GETNET_NONE, "No such net");
+ } else {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_ne(ne, &b->buff,
+ &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall ne\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETNET_OK, "Network found", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+ }
+}
+
+/*
+ * static void
+ * irpd_getnetbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of GETNETBYNAME verb.
+ */
+static void
+irpd_getnetbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct netent *ne;
+ struct nwent *nw;
+ char netname[MAXNETNAMELEN];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, nw, sess, IRPD_GETNET_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "GETNETBYNAME name");
+ } else {
+ if (args->iov[0].iov_len >= sizeof netname) {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "Name too long");
+ } else {
+ strncpy(netname, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ netname[args->iov[0].iov_len] = '\0';
+
+ ne = getnetbyname_p(netname, netdata);
+
+ /* The public interface only gives us a struct
+ netent, and we need a struct nwent that irs uses
+ internally, so we go dig it out ourselves. Yuk
+ */
+ nw = NULL;
+ if (ne != NULL) {
+ /* Puke. */
+ INSIST(netdata->nw_last == ne);
+ nw = netdata->nww_last;
+ }
+
+ send_nwent(sess, nw);
+ }
+ }
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getnetbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ */
+static void
+irpd_getnetbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct netent *ne;
+ struct nwent *nw;
+ char haddr[MAXHOSTNAMELEN];
+ long tmpaddr;
+ struct arg_s *args;
+ int i;
+ int af;
+ int addrlen;
+ int bits;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, nw, sess, IRPD_GETUSER_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 3) {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "GETNETBYADDR addr afamily");
+ } else {
+ if (args->iov[0].iov_len >= sizeof haddr) {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "Address too long");
+ } else {
+ strncpy(haddr, args->iov[1].iov_base,
+ args->iov[1].iov_len);
+ haddr[args->iov[1].iov_len] = '\0';
+ if (strcasecmp(haddr, "af_inet") == 0) {
+ af = AF_INET;
+ addrlen = NS_INADDRSZ;
+ } else if (strcasecmp(haddr, "af_inet6") == 0) {
+ af = AF_INET6;
+ addrlen = NS_IN6ADDRSZ;
+
+ /* XXX the interface we use(getnetbyaddr)
+ * can't handle AF_INET6, so for now we
+ * bail.
+ */
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "AF_INET6 unsupported");
+ goto untimely;
+ } else {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "Unknown address family");
+ goto untimely;
+ }
+
+ strncpy(haddr, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ haddr[args->iov[0].iov_len] = '\0';
+
+ bits = inet_net_pton(af, haddr,
+ &tmpaddr, sizeof tmpaddr);
+ if (bits < 0) {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "Invalid address");
+ goto untimely;
+ }
+
+ ne = getnetbyaddr_p(tmpaddr, af, netdata);
+
+ /* The public interface only gives us a struct
+ netent, and we need a struct nwent that irs uses
+ internally, so we go dig it out ourselves. Yuk
+ */
+ nw = NULL;
+ if (ne != NULL) {
+ /* Puke puke */
+ INSIST(netdata->nw_last == ne);
+ nw = netdata->nww_last;
+ }
+
+ send_nwent(sess, nw);
+ }
+ }
+
+ untimely:
+ free_args(args);
+}
+
+
+/*
+ * static void
+ * irpd_getnetent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETNETENT verb.
+ */
+static void
+irpd_getnetent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct netent *ne;
+ struct nwent *nw;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, nw, sess, IRPD_GETNET_ERROR);
+
+ ne = getnetent_p(netdata);
+ nw = NULL;
+ if (ne != NULL) {
+ /* triple puke */
+ INSIST(netdata->nw_last == ne);
+ nw = netdata->nww_last;
+ }
+ send_nwent(sess, nw);
+}
+
+/*
+ * static void
+ * irpd_setnetent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the SETNETENT verb.
+ */
+static void
+irpd_setnetent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct netent *ne;
+ struct nwent *nw;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, nw, sess, IRPD_GETNET_ERROR);
+
+ setnetent_p(1, netdata); /* always stayopen */
+ simple_response(sess, IRPD_GETNET_SETOK, "ok");
+}
+
+#ifdef WANT_IRS_GR
+/*
+ * static void
+ * send_grent(struct ctl_sess *sess, struct group *gr);
+ * Marshall GR and send as body of response. If GR is NULL
+ * then a "No such group" response is sent instead.
+ */
+static void
+send_grent(struct ctl_sess *sess, struct group *gr) {
+ if (gr == NULL) {
+ simple_response(sess, IRPD_GETGROUP_NONE,
+ "No such user");
+ } else {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_gr(gr, &b->buff, &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall gr\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETGROUP_OK, "Group found", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+ }
+}
+
+/*
+ * static void
+ * irpd_getgrnam(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETGRNAM verb.
+ */
+static void
+irpd_getgrnam(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct group *gr;
+ char groupname[64];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, gr, sess, IRPD_GETGROUP_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "GETGRNAM groupname");
+ } else {
+ if (args->iov[0].iov_len >= sizeof groupname) {
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "Name too long");
+ } else {
+ strncpy(groupname, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ groupname[args->iov[0].iov_len] = '\0';
+
+ gr = getgrnam_p(groupname, netdata);
+ send_grent(sess, gr);
+ }
+ }
+
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getgrgid(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implentation of the GETGRGID verb.
+ */
+static void
+irpd_getgrgid(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct group *gr;
+ char groupid[64];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, gr, sess, IRPD_GETGROUP_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "GETGRUID gid");
+ } else {
+ if (args->iov[0].iov_len >= sizeof groupid) {
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "Name too long");
+ } else {
+ strncpy(groupid, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ groupid[args->iov[0].iov_len] = '\0';
+
+ if (!ALLDIGITS(groupid)) {
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "Not a gid");
+ } else {
+ gid_t gid;
+ long lval;
+
+ lval = strtol(groupid, 0, 10);
+ gid = (gid_t)lval;
+ if ((long)gid != lval) {
+ /* value was too big */
+ simple_response(sess,
+ IRPD_GETGROUP_ERROR,
+ "Not a valid gid");
+ goto untimely;
+ }
+
+ gr = getgrgid_p(gid, netdata);
+ send_grent(sess, gr);
+ }
+ }
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETGRENT verb.
+ */
+static void
+irpd_getgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct group *gr;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, gr, sess, IRPD_GETGROUP_ERROR);
+
+ gr = getgrent_p(netdata);
+ send_grent(sess, gr);
+}
+
+/*
+ * static void
+ * irpd_setgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the SETGRENT verb.
+ */
+static void
+irpd_setgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct group *gr;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, gr, sess, IRPD_GETGROUP_ERROR);
+
+ setgrent_p(netdata);
+ simple_response(sess, IRPD_GETGROUP_SETOK, "ok");
+}
+#endif /* WANT_IRS_GR */
+
+static void
+send_servent(struct ctl_sess *sess, struct servent *serv) {
+ if (serv == NULL) {
+ simple_response(sess, IRPD_GETSERVICE_NONE,
+ "No such service");
+ } else {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_sv(serv, &b->buff,
+ &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall servent\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETSERVICE_OK, "Service found", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+ }
+}
+
+static void
+irpd_getservbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct servent *serv;
+ char servicename[64];
+ char protoname[10];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, sv, sess, IRPD_GETSERVICE_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 3) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "GETSERVNAM servicename protocol");
+ } else {
+ if (args->iov[0].iov_len >= sizeof servicename) {
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "Invalid service name");
+ } else if (args->iov[1].iov_len >= sizeof protoname) {
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "Invalid protocol name");
+ } else {
+ strncpy(servicename, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ servicename[args->iov[0].iov_len] = '\0';
+
+ strncpy(protoname, args->iov[1].iov_base,
+ args->iov[1].iov_len);
+ protoname[args->iov[1].iov_len] = '\0';
+
+ serv = getservbyname_p(servicename, protoname,
+ netdata);
+ send_servent(sess, serv);
+ }
+ }
+
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getservbyport(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the GETSERVBYPORT verb.
+ */
+static void
+irpd_getservbyport(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct servent *sv;
+ char portnum[64];
+ char protoname[10];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, sv, sess, IRPD_GETSERVICE_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 3) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "GETSERVBYPORT port protocol");
+ } else {
+ if (args->iov[0].iov_len >= sizeof portnum) {
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "Invalid port");
+ } else if (args->iov[1].iov_len > sizeof protoname - 1) {
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "Invalid protocol");
+ } else {
+ strncpy(portnum, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ portnum[args->iov[0].iov_len] = '\0';
+
+ strncpy(protoname, args->iov[1].iov_base,
+ args->iov[1].iov_len);
+ protoname[args->iov[1].iov_len] = '\0';
+
+ if (!ALLDIGITS(portnum)) {
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "Not a port number");
+ } else {
+ short port;
+ long lval;
+
+ lval = strtol(portnum, 0, 10);
+ port = (short)lval;
+ if ((long)port != lval) {
+ /* value was too big */
+ simple_response(sess,
+ IRPD_GETSERVICE_ERROR,
+ "Not a valid port");
+ goto untimely;
+ }
+ port = htons(port);
+
+ sv = getservbyport_p(port, protoname, netdata);
+ send_servent(sess, sv);
+ }
+ }
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getservent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the GETSERVENT verb.
+ */
+static void
+irpd_getservent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct servent *sv;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, sv, sess, IRPD_GETSERVICE_ERROR);
+
+ sv = getservent_p(netdata);
+ send_servent(sess, sv);
+}
+
+/*
+ * static void
+ * irpd_setservent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the SETSERVENT verb.
+ */
+static void
+irpd_setservent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct servent *sv;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, sv, sess, IRPD_GETSERVICE_ERROR);
+
+ setservent_p(1, netdata); /* always stay open */
+ simple_response(sess, IRPD_GETSERVICE_SETOK, "ok");
+}
+
+/*
+ * static void
+ * send_prent(struct ctl_sess *sess, struct protoent *pr);
+ * Send the PR structure over the wire. If PR is NULL, then
+ * the response "No such protocol" is sent instead.
+ */
+static void
+send_prent(struct ctl_sess *sess, struct protoent *pr) {
+ if (pr == NULL) {
+ simple_response(sess, IRPD_GETPROTO_NONE,
+ "No such protocol");
+ } else {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_pr(pr, &b->buff,
+ &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETPROTO_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall pr\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETPROTO_OK, "Protocol found", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+ }
+}
+
+/*
+ * static void
+ * irpd_getprotobyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the GETPROTOBYNAME verb.
+ */
+static void
+irpd_getprotobyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct protoent *pr;
+ char protoname[64];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pr, sess, IRPD_GETPROTO_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETPROTO_ERROR,
+ "GETPROTOBYNAME protocol");
+ } else {
+ if (args->iov[0].iov_len >= sizeof protoname) {
+ simple_response(sess, IRPD_GETPROTO_ERROR,
+ "Name too long");
+ } else {
+ strncpy(protoname, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ protoname[args->iov[0].iov_len] = '\0';
+
+ pr = getprotobyname_p(protoname, netdata);
+ send_prent(sess, pr);
+ }
+ }
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getprotobynumber(struct ctl_sctx *ctx,
+ * struct ctl_sess *sess, const struct ctl_verb *verb,
+ * const char *rest, u_int respflags, void *respctx,
+ * void *uctx);
+ * Handle the GETPROTOBYNUMBER verb.
+ */
+static void
+irpd_getprotobynumber(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct protoent *pr;
+ char protonum[64];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pr, sess, IRPD_GETPROTO_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETPROTO_ERROR,
+ "GETPROTOBYNUMBER protocol");
+ } else {
+ if (args->iov[0].iov_len >= sizeof protonum) {
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "Name too long");
+ } else {
+ strncpy(protonum, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ protonum[args->iov[0].iov_len] = '\0';
+
+ if (!ALLDIGITS(protonum)) {
+ simple_response(sess, IRPD_GETPROTO_ERROR,
+ "Not a protocol number");
+ } else {
+ int proto;
+ long lval;
+
+ lval = strtol(protonum, 0, 10);
+ proto = (int)lval;
+ if ((long)proto != lval) {
+ /* value was too big */
+ simple_response(sess,
+ IRPD_GETPROTO_ERROR,
+ "Not a valid proto");
+ goto untimely;
+ }
+
+ pr = getprotobynumber_p(proto, netdata);
+ send_prent(sess, pr);
+ }
+ }
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the GETPROTOENT verb.
+ */
+static void
+irpd_getprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct protoent *pr;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pr, sess, IRPD_GETPROTO_ERROR);
+
+ pr = getprotoent_p(netdata);
+ send_prent(sess, pr);
+}
+
+/*
+ * static void
+ * irpd_setprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the SETPROTOENT verb.
+ */
+static void
+irpd_setprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct protoent *pr;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pr, sess, IRPD_GETPROTO_ERROR);
+
+ setprotoent_p(1, netdata); /* always stay open */
+ simple_response(sess, IRPD_GETPROTO_SETOK, "ok");
+}
+
+/*
+ * static void
+ * send_pwent(struct ctl_sess *sess, struct passwd *pw);
+ * Send PW over the wire, or, if PW is NULL, a "No such
+ * user" response.
+ */
+static void
+send_ngent(struct ctl_sess *sess, char *host, char *user, char *domain) {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_ng(host, user, domain, &b->buff,
+ &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETNETGR_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall ng\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETNETGR_OK, "Netgroup entry", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+}
+
+/*
+ * static void
+ * irpd_getnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the GETNETGRENT verb.
+ */
+static void
+irpd_getnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ char netgroupname[64];
+ struct response_buff *b = NULL;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ng, sess, IRPD_GETNETGR_ERROR);
+
+ if (rest != NULL && strlen(rest) > 0) {
+ simple_response(sess, IRPD_GETNETGR_ERROR,
+ "GETNETGRENT");
+ } else {
+ char *host, *user, *domain;
+
+ if (getnetgrent_p(&host, &user, &domain, netdata) == 1) {
+ send_ngent(sess, host, user, domain);
+ } else {
+ simple_response(sess, IRPD_GETNETGR_NOMORE,
+ "No more");
+ }
+ }
+}
+
+/*
+ * static void
+ * irpd_innetgr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the INNETGR verb.
+ */
+static void
+irpd_innetgr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+ char *host;
+ char *user;
+ char *domain;
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ng, sess, IRPD_GETNETGR_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 3) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETNETGR_ERROR,
+ "INNETGR netgroup ngentry");
+ } else {
+ char *grptmp = memget(args->iov[0].iov_len + 1);
+ char *ngtmp = memget(args->iov[1].iov_len + 1);
+
+ strncpy(grptmp, args->iov[0].iov_base, args->iov[0].iov_len);
+ strncpy(ngtmp, args->iov[1].iov_base, args->iov[1].iov_len);
+
+ grptmp[args->iov[0].iov_len] = '\0';
+ ngtmp[args->iov[1].iov_len] = '\0';
+
+ if (irp_unmarshall_ng(&host, &user, &domain, ngtmp) != 0) {
+ simple_response(sess, IRPD_GETNETGR_ERROR,
+ "ngentry must be (host,user,domain)");
+ } else {
+ if (innetgr_p(grptmp, host, user, domain,
+ netdata) == 1) {
+ simple_response(sess, IRPD_GETNETGR_MATCHES,
+ "INNETGR matches");
+ } else {
+ simple_response(sess, IRPD_GETNETGR_NOMATCH,
+ "INNETGR does not match");
+ }
+ }
+
+ memput(grptmp, args->iov[0].iov_len + 1);
+ memput(ngtmp, args->iov[1].iov_len + 1);
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_setnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the SETNETGRENT verb.
+ */
+static void
+irpd_setnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ng, sess, IRPD_GETNETGR_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETNETGR_ERROR,
+ "setnetgrent netgroup");
+ } else {
+ setnetgrent_p(rest, netdata);
+ simple_response(sess, IRPD_GETNETGR_SETOK,
+ "setnetgrent ok");
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_endnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the ENDNETGRENT verb.
+ */
+static void
+irpd_endnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ng, sess, IRPD_GETNETGR_ERROR);
+
+ if (rest != NULL && strlen (rest) > 0) {
+ simple_response(sess, IRPD_GETNETGR_ERROR,
+ "endnetgrent netgroup");
+ } else {
+ endnetgrent_p(netdata);
+ simple_response(sess, IRPD_GETNETGR_SETOK,
+ "endnetgrent ok");
+ }
+}
+
+/*
+ * static void
+ * irpd_done(struct ctl_sctx *ctx, struct ctl_sess *sess, void *param)
+ * Callback for when QUIT respnse is sent out.
+ */
+static void
+irpd_done(struct ctl_sctx *ctx, struct ctl_sess *sess, void *param) {
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ net_data_destroy(netdata);
+}
+
+/*
+ * static void
+ * irpd_quit(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the QUIT verb.
+ */
+static void
+irpd_quit(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ ctl_response(sess, irpd_quit_ok, "See ya!", CTL_EXIT, NULL,
+ 0 , NULL, NULL, 0);
+}
+
+/*
+ * static void
+ * irpd_help(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the HELP verb.
+ */
+static void
+irpd_help(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ /* XXX should make this do something better (like include required
+ * arguments.
+ */
+ ctl_sendhelp(sess, 231);
+}
+
+/*
+ * static void
+ * irpd_accept(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle a new connection.
+ */
+static void
+irpd_accept(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct sockaddr *sa = respctx;
+ char raddr[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+ int reject = 1;
+ int response;
+ char *respmsg = NULL;
+
+ if (sa->sa_family == AF_UNIX) {
+ syslog (LOG_INFO, "New AF_UNIX connection");
+ reject = 0;
+ } else if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *sin = respctx;
+ static long localhost;
+ static long zero;
+
+ if (localhost == 0) {
+ /* yes, this could be done with simple arithmetic... */
+ inet_pton(AF_INET, "127.0.0.1", &localhost);
+ }
+
+ inet_ntop(AF_INET, &sin->sin_addr, raddr, sizeof raddr);
+
+ /* we reject INET connections that are not from the local
+ * machine.
+ */
+ if (sin->sin_addr.s_addr == zero ||
+ sin->sin_addr.s_addr == localhost) {
+ reject = 0;
+ syslog(LOG_INFO, "New connection from %s", raddr);
+ } else {
+ syslog(LOG_INFO, "New connection from %s (reject)",
+ raddr);
+ respmsg = "Connections from off host not permitted";
+ }
+ } else if (sa->sa_family == AF_INET6) {
+ /* XXX should do something intelligent here. */
+ respmsg = "IPv6 connections not implemented yet.";
+ syslog(LOG_ERR, "Cannot handle AF_INET6 connections yet");
+ } else {
+ syslog (LOG_ERR, "Unknown peer type: %d", sa->sa_family);
+ respmsg = "What are you???";
+ }
+
+ if (reject) {
+ response = IRPD_NOT_WELCOME_CODE;
+ if (respmsg == NULL) {
+ respmsg = "Go away!";
+ }
+ /* XXX can we be sure that stacked up commands will not be
+ * processed before the control connection is closed???
+ */
+ } else {
+ void *ctx = make_cli_ctx();
+
+ if (ctx == NULL) {
+ response = IRPD_NOT_WELCOME_CODE;
+ respmsg = "Internal error (client context)";
+ } else {
+ response = IRPD_WELCOME_CODE;
+ if (respmsg == NULL) {
+ respmsg = "Welcome to IRPD (v 1)";
+ }
+ ctl_setcsctx(sess, ctx);
+ }
+ }
+ ctl_response(sess, response, respmsg, (reject ? CTL_EXIT : 0), NULL,
+ 0, NULL, NULL, 0);
+}
+
+/*
+ * static void
+ * irpd_abort(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle a dropped connection.
+ */
+static void
+irpd_abort(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct net_data *netdata = get_net_data(sess);
+
+ if (netdata != NULL)
+ net_data_destroy(netdata);
+}
+
+/*
+ * void
+ * response_done(struct ctl_sctx *ctx, struct ctl_sess *sess, void *uap)
+ * UAP is the response_buffer passed through to
+ * ctl_response.
+ */
+static void
+response_done(struct ctl_sctx *ctx, struct ctl_sess *sess, void *uap) {
+ release_buffer(uap);
+}
+
+/*
+ * static void
+ * logger(enum ctl_severity sev, const char *fmt, ...);
+ * Logging routine called by the ctl_* functions. For now we
+ * just spit everything to stderr.
+ */
+
+static void
+logger(enum ctl_severity sev, const char *fmt, ...) {
+ char buffer[1024];
+ va_list ap;
+ int level;
+
+ if (sev == ctl_debug)
+ return;
+
+ if (sev == ctl_warning)
+ level = LOG_WARNING;
+ else if (sev == ctl_error)
+ level = LOG_ERR;
+ else {
+ syslog(LOG_CRIT, "Invalid severity: %d", (int)sev);
+ exit(1);
+ }
+
+ va_start(ap, fmt);
+
+#if 0
+ fprintf(stderr, "irpd: ");
+ vfprintf(stderr, fmt, ap);
+#else
+ if (vsprintf(buffer, fmt, ap) > (sizeof (buffer) - 1)) {
+ syslog(LOG_CRIT, "Buffer overrun in logger");
+ abort();
+ }
+ syslog(level, "%s", buffer);
+#endif
+ va_end(ap);
+}
+
+/*
+ * static struct response_buff *
+ * newbuffer(u_int length);
+ * Create a structure to hold an allocated buffer. We do
+ * this so we can get the size to deallocate later.
+ * Returns:
+ * Pointer to the structure
+ */
+static struct response_buff *
+newbuffer(u_int length) {
+ struct response_buff *h;
+
+ h = memget(sizeof *h);
+ if (h == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ h->buff = NULL;
+ h->bufflen = length;
+
+ if (length > 0) {
+ h->buff = memget(h->bufflen);
+ if (h->buff == NULL) {
+ memput(h, sizeof *h);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(h->buff, 0, h->bufflen);
+ }
+
+ return (h);
+}
+
+/*
+ * static void
+ * release_buffer(struct response_buff *b);
+ * Free up a buffer allocated with newbuffer.
+ */
+static void
+release_buffer(struct response_buff *b) {
+ memset(b->buff, 0, b->bufflen);
+ memput(b->buff, b->bufflen);
+
+ memset(b, 0, sizeof *b);
+ memput(b, sizeof *b);
+}
+
+/*
+ * static struct arg_s *
+ * split_string(const char *string);
+ * Create an array of iovecs(last one having NULL fields)
+ * pointing into STRING at the non-whitespace sections. The
+ * iovecs are stashed inside a structure so we can get the
+ * size back later at deallocation time. Iovecs are used to avoid
+ * modifying the argument with added nulls.
+ * Returns:
+ * Pointer to the wrapper structure. Must be given to free_args()
+ * when done
+ */
+static struct arg_s *
+split_string(const char *string) {
+ struct iovec *iovs;
+ const char *p;
+ int i, c, iswh;
+ struct arg_s *a;
+
+ /* count + 1 of the number of runs of non-whitespace. */
+ for (iswh = 1, i = 1, p = string ; p != NULL && *p ; p++) {
+ if (iswh && !isspace(*p)) {
+ iswh = 0;
+ i++;
+ } else if (!iswh && isspace(*p)) {
+ iswh = 1;
+ }
+ }
+
+ iovs = memget(sizeof (struct iovec) * i);
+ if (iovs == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ a = memget(sizeof *a);
+ if (a == NULL) {
+ errno = ENOMEM;
+ memput(iovs, sizeof (struct iovec) * i);
+ return (NULL);
+ }
+ a->iov = iovs;
+ a->iovlen = i;
+
+ for (c = 0, p = string ; p != NULL && *p ; c++) {
+ while (isspace(*p)) {
+ p++;
+ }
+
+ if (*p == '\0')
+ break;
+
+ iovs[c].iov_base = (void *)p;
+
+ while (*p && !isspace(*p)) {
+ p++;
+ }
+ iovs[c].iov_len = p - (char *)iovs[c].iov_base;
+ }
+ INSIST(c == i - 1);
+ iovs[c].iov_base = NULL;
+ iovs[c].iov_len = 0;
+
+ return (a);
+}
+
+/*
+ * static void
+ * free_args(struct arg_s *args);
+ * Free up the argument structure created with
+ * split_string().
+ */
+
+static void
+free_args(struct arg_s *args) {
+ memput(args->iov, sizeof (struct iovec) * args->iovlen);
+ memput(args, sizeof *args);
+}
+
+static struct client_ctx *
+make_cli_ctx(void) {
+ struct client_ctx *p = memget (sizeof *p);
+
+ if (p == NULL)
+ return (NULL);
+
+ p->net_data = net_data_create(conffile);
+
+ return (p);
+}
+
+static void
+release_cli_ctx(struct client_ctx *ctx) {
+ INSIST(ctx != NULL);
+ INSIST(ctx->net_data != NULL);
+
+ net_data_destroy(ctx->net_data);
+ memput(ctx, sizeof *ctx);
+}
+
+static struct net_data *
+get_net_data(struct ctl_sess *sess) {
+ struct client_ctx *ctx = ctl_getcsctx(sess);
+
+ INSIST(ctx != NULL);
+ INSIST(ctx->net_data != NULL);
+
+ return (ctx->net_data);
+}
diff --git a/contrib/bind/bin/irpd/irs-irpd.conf b/contrib/bind/bin/irpd/irs-irpd.conf
new file mode 100644
index 0000000..07385d3
--- /dev/null
+++ b/contrib/bind/bin/irpd/irs-irpd.conf
@@ -0,0 +1,11 @@
+# Private irs config file for irpd so that it doesn't get configured to
+# talk to itself.
+passwd local
+group local
+services local
+protocols local
+hosts dns continue
+hosts local
+networks dns continue
+networks local
+netgroup local
diff --git a/contrib/bind/bin/irpd/version.c b/contrib/bind/bin/irpd/version.c
new file mode 100644
index 0000000..cc42c0b
--- /dev/null
+++ b/contrib/bind/bin/irpd/version.c
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+char sccsid[] = "@(#)named %VERSION% %WHEN% %WHOANDWHERE%";
+char rcsid[] = "$Id: version.c,v 1.1 1999/01/18 07:47:17 vixie Exp $";
+#endif /* not lint */
+
+char Version[] = "named %VERSION% %WHEN%\n\t%WHOANDWHERE%";
+char ShortVersion[] = "%VERSION%";
+
diff --git a/contrib/bind/bin/mkservdb/Makefile b/contrib/bind/bin/mkservdb/Makefile
new file mode 100644
index 0000000..47af236
--- /dev/null
+++ b/contrib/bind/bin/mkservdb/Makefile
@@ -0,0 +1,83 @@
+## Copyright (c) 1998,1999 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 1.6 1999/08/08 17:51:01 vixie 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
+SYSLIBS = -ll -lutil
+DESTBIN = /usr/local/bin
+DESTSBIN = /usr/local/sbin
+DESTEXEC = /usr/local/libexec
+DESTMAN = /usr/share/man
+DESTHELP= /usr/share/misc
+STRIP=-s
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
+
+LDFLAGS=
+CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL}
+
+PROG= mkservdb
+SRCS= ${PROG}.c
+OBJS= ${PROG}.${O}
+
+all: ${PROG}${EXE}
+
+${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile
+ ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \
+ ${LIBBIND} ${SYSLIBS}
+
+.c.${O}:
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c
+
+distclean: clean
+
+clean: FRC
+ rm -f ${PROG}${EXE} ${OBJS} core .depend
+ rm -f *.BAK *.CKP *~ *.orig
+
+depend: ${SRCS}
+ mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
+
+${DESTDIR}${DESTBIN}:
+ mkdir -p ${DESTDIR}${DESTBIN}
+
+install: ${DESTDIR}${DESTBIN} ${PROG}${EXE}
+ ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE}
+
+links: FRC
+ @set -e; ln -s SRC/*.[ch] .
+
+tags: FRC
+ ctags *.[ch]
+
+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/mkservdb/mkservdb.c b/contrib/bind/bin/mkservdb/mkservdb.c
new file mode 100644
index 0000000..5647ec7
--- /dev/null
+++ b/contrib/bind/bin/mkservdb/mkservdb.c
@@ -0,0 +1,169 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: mkservdb.c,v 1.6 1999/10/13 16:39:00 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1998,1999 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 <resolv.h>
+
+#include <ctype.h>
+#ifdef IRS_LCL_SV_DB
+#include <db.h>
+#endif
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../include/irs.h"
+#include "../../lib/irs/irs_p.h"
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+#ifndef IRS_LCL_SV_DB
+main(int argc, char **argv) {
+ fprintf(stderr, "%s: not supported on this architecture\n", argv[0]);
+ exit(1);
+}
+
+#else
+
+#define _PATH_SERVICES_DB_TMP _PATH_SERVICES_DB ".new"
+
+struct servent *getnextent(FILE *);
+
+main(int argc, char **argv) {
+ DB *db;
+ DBT key;
+ DBT data;
+ char *filename = _PATH_SERVICES;
+ char *tmpdatabase = _PATH_SERVICES_DB_TMP;
+ char *database = _PATH_SERVICES_DB;
+ char dbuf[1024];
+ char kbuf[512];
+ u_short *ports;
+ struct lcl_sv lcl_sv;
+ struct servent *sv;
+ int n, r;
+ char *p;
+
+ unlink(tmpdatabase);
+
+ if (argc > 1)
+ filename = argv[1];
+
+ lcl_sv.fp = fopen(filename, "r");
+ if (lcl_sv.fp == NULL)
+ err(1, "%s", filename);
+
+ db = dbopen(tmpdatabase, O_CREAT|O_RDWR, 0444, DB_BTREE, NULL);
+ if (db == NULL)
+ err(1, "%s", tmpdatabase);
+
+ while ((sv = irs_lclsv_fnxt(&lcl_sv)) != NULL) {
+ if (sv->s_proto == NULL)
+ continue;
+
+ key.data = kbuf;
+ data.data = dbuf;
+
+ /* Note that (sizeof "/") == 2. */
+ if (strlen(sv->s_name) + sizeof "/" + strlen(sv->s_proto)
+ > sizeof kbuf)
+ continue;
+ key.size = SPRINTF((kbuf, "%s/%s", sv->s_name, sv->s_proto))+1;
+
+ ((u_short *)dbuf)[0] = sv->s_port;
+ p = dbuf;
+ p += sizeof(u_short);
+ if (sv->s_aliases)
+ for (n = 0; sv->s_aliases[n]; ++n) {
+ strcpy(p, sv->s_aliases[n]);
+ p += strlen(p) + 1;
+ }
+ data.size = p - dbuf;
+
+ if ((r = db->put(db, &key, &data, R_NOOVERWRITE)))
+ if (r < 0)
+ errx(1, "failed to write %s", key.data);
+ else
+ warnx("will not overwrite %s", key.data);
+ for (n = 0; sv->s_aliases[n]; ++n) {
+ if (strlen(sv->s_aliases[n]) + sizeof "/"
+ + strlen(sv->s_proto) > sizeof kbuf)
+ continue;
+ key.size = SPRINTF((kbuf, "%s/%s",
+ sv->s_aliases[n], sv->s_proto))+1;
+ if ((r = db->put(db, &key, &data, R_NOOVERWRITE)))
+ if (r < 0)
+ errx(1, "failed to write %s",
+ key.data);
+ else
+ warnx("will not overwrite %s",
+ key.data);
+ }
+
+ ports = (u_short *)kbuf;
+ ports[0] = 0;
+ ports[1] = sv->s_port;
+ strcpy((char *)(ports+2), sv->s_proto);
+ key.size = sizeof(u_short) * 2 + strlen((char *)(ports+2)) + 1;
+
+ if (strlen(sv->s_name) + sizeof "/" + strlen(sv->s_proto)
+ > sizeof dbuf)
+ continue;
+ p = dbuf;
+ p += SPRINTF((p, "%s/%s", sv->s_name, sv->s_proto)) + 1;
+ if (sv->s_aliases != NULL)
+ for (n = 0; sv->s_aliases[n] != NULL; n++)
+ if ((p + strlen(sv->s_aliases[n]) + 1) - dbuf
+ <= sizeof dbuf) {
+ strcpy(p, sv->s_aliases[n]);
+ p += strlen(p) + 1;
+ }
+ data.size = p - dbuf;
+
+ if ((r = db->put(db, &key, &data, R_NOOVERWRITE)))
+ if (r < 0)
+ errx(1, "failed to write %d/%s",
+ ntohs(sv->s_port), sv->s_proto);
+ else
+ warnx("will not overwrite %d/%s",
+ ntohs(sv->s_port), sv->s_proto);
+ }
+ db->close(db);
+ if (rename(tmpdatabase, database))
+ err(1, "rename %s -> %s", tmpdatabase, database);
+ exit(0);
+}
+
+#endif
diff --git a/contrib/bind/bin/named-bootconf/Grot/named-bootconf.pl b/contrib/bind/bin/named-bootconf/Grot/named-bootconf.pl
new file mode 100644
index 0000000..ce1b368
--- /dev/null
+++ b/contrib/bind/bin/named-bootconf/Grot/named-bootconf.pl
@@ -0,0 +1,324 @@
+#!/usr/bin/perl
+
+## Copyright (c) 1996-1999 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 1.2 1999/01/08 19:27:35 vixie 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-bootconf/Makefile b/contrib/bind/bin/named-bootconf/Makefile
new file mode 100644
index 0000000..4c1a0df
--- /dev/null
+++ b/contrib/bind/bin/named-bootconf/Makefile
@@ -0,0 +1,76 @@
+## Copyright (c) 1999 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 1.1 1999/01/07 02:09:37 vixie 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
+SYSLIBS = -ll -lutil
+DESTBIN = /usr/local/bin
+DESTSBIN = /usr/local/sbin
+DESTEXEC = /usr/local/libexec
+DESTMAN = /usr/share/man
+DESTHELP= /usr/share/misc
+STRIP=-s
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
+
+LDFLAGS=
+CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL}
+
+PROG= named-bootconf
+
+all: ${PROG}
+
+${PROG}: ${PROG}.sh Makefile
+ cp ${PROG}.sh ${PROG}
+ chmod +x ${PROG}
+
+distclean: clean
+
+clean: FRC
+ rm -f ${PROG}
+ rm -f *.BAK *.CKP *~ *.orig
+
+depend:
+
+${DESTDIR}${DESTSBIN}:
+ mkdir -p ${DESTDIR}${DESTSBIN}
+
+install: ${DESTDIR}${DESTSBIN} ${PROG}
+ ${INSTALL} -c -m 755 ${PROG} ${DESTDIR}${DESTSBIN}/${PROG}
+
+links: FRC
+ @set -e; ln -s SRC/*.sh .
+
+tags:
+
+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-bootconf/named-bootconf.sh b/contrib/bind/bin/named-bootconf/named-bootconf.sh
new file mode 100644
index 0000000..c1dfaad
--- /dev/null
+++ b/contrib/bind/bin/named-bootconf/named-bootconf.sh
@@ -0,0 +1,306 @@
+#!/bin/sh
+#
+# $NetBSD: named-bootconf.sh,v 1.5 1998/12/15 01:00:53 tron Exp $
+#
+# Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by Matthias Scheler.
+#
+# 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 NetBSD
+# Foundation, Inc. and its contributors.
+# 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+
+## Copyright (c) 1999 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 [ ${OPTIONFILE-X} = X ]; then
+ OPTIONFILE=/tmp/.options.`date +%s`.$$
+ ZONEFILE=/tmp/.zones.`date +%s`.$$
+ COMMENTFILE=/tmp/.comments.`date +%s`.$$
+ export OPTIONFILE ZONEFILE COMMENTFILE
+ touch $OPTIONFILE $ZONEFILE $COMMENTFILE
+ DUMP=1
+else
+ DUMP=0
+fi
+
+while read CMD ARGS; do
+ class=
+ CMD=`echo "${CMD}" | tr '[A-Z]' '[a-z]'`
+ case $CMD in
+ \; )
+ echo \# $ARGS >>$COMMENTFILE
+ ;;
+ cache )
+ set - X $ARGS
+ shift
+ if [ $# -eq 2 ]; then
+ (echo ""
+ cat $COMMENTFILE
+ echo "zone \"$1\" {"
+ echo " type hint;"
+ echo " file \"$2\";"
+ echo "};") >>$ZONEFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ fi
+ ;;
+ directory )
+ set - X $ARGS
+ shift
+ if [ $# -eq 1 ]; then
+ (cat $COMMENTFILE
+ echo " directory \"$1\";") >>$OPTIONFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+
+ DIRECTORY=$1
+ export DIRECTORY
+ fi
+ ;;
+ forwarders )
+ (cat $COMMENTFILE
+ echo " forwarders {"
+ for ARG in $ARGS; do
+ echo " $ARG;"
+ done
+ echo " };") >>$OPTIONFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ ;;
+ include )
+ if [ "$ARGS" != "" ]; then
+ (cd ${DIRECTORY-.}; cat $ARGS) | $0
+ fi
+ ;;
+ limit )
+ ARGS=`echo "${ARGS}" | tr '[A-Z]' '[a-z]'`
+ set - X $ARGS
+ shift
+ if [ $# -eq 2 ]; then
+ cat $COMMENTFILE >>$OPTIONFILE
+ case $1 in
+ datasize | files | transfers-in | transfers-per-ns )
+ echo " $1 $2;" >>$OPTIONFILE
+ ;;
+ esac
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ fi
+ ;;
+ options )
+ ARGS=`echo "${ARGS}" | tr '[A-Z]' '[a-z]'`
+ cat $COMMENTFILE >>$OPTIONFILE
+ for ARG in $ARGS; do
+ case $ARG in
+ fake-iquery )
+ echo " fake-iquery yes;" >>$OPTIONFILE
+ ;;
+ forward-only )
+ echo " forward only;" >>$OPTIONFILE
+ ;;
+ no-fetch-glue )
+ echo " fetch-glue no;" >>$OPTIONFILE
+ ;;
+ no-recursion )
+ echo " recursion no;" >>$OPTIONFILE
+ ;;
+ esac
+ done
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ ;;
+ primary|primary/* )
+ case $CMD in
+ primary/chaos )
+ class="chaos "
+ ;;
+ primary/hs )
+ class="hesiod "
+ ;;
+ esac
+ set - X $ARGS
+ shift
+ if [ $# -eq 2 ]; then
+ (echo ""
+ cat $COMMENTFILE
+ echo "zone \"$1\" ${class}{"
+ echo " type master;"
+ echo " file \"$2\";"
+ echo "};") >>$ZONEFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ fi
+ ;;
+ secondary|secondary/* )
+ case $CMD in
+ secondary/chaos )
+ class="chaos "
+ ;;
+ secondary/hs )
+ class="hesiod "
+ ;;
+ esac
+ set - X $ARGS
+ shift
+ if [ $# -gt 2 ]; then
+ ZONE=$1
+ shift
+ PRIMARIES=$1
+ while [ $# -gt 2 ]; do
+ shift
+ PRIMARIES="$PRIMARIES $1"
+ done
+ (echo ""
+ cat $COMMENTFILE
+ echo "zone \"$ZONE\" ${class}{"
+ echo " type slave;"
+ echo " file \"$2\";"
+ echo " masters {"
+ for PRIMARY in $PRIMARIES; do
+ echo " $PRIMARY;"
+ done
+ echo " };"
+ echo "};") >>$ZONEFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ fi
+ ;;
+ stub|stub/* )
+ case $CMD in
+ stub/chaos )
+ class="chaos "
+ ;;
+ stub/hs )
+ class="hesiod "
+ ;;
+ esac
+ set - X $ARGS
+ shift
+ if [ $# -gt 2 ]; then
+ ZONE=$1
+ shift
+ PRIMARIES=$1
+ while [ $# -gt 2 ]; do
+ shift
+ PRIMARIES="$PRIMARIES $1"
+ done
+ (echo ""
+ cat $COMMENTFILE
+ echo "zone \"$ZONE\" ${class}{"
+ echo " type stub;"
+ echo " file \"$2\";"
+ echo " masters {"
+ for PRIMARY in $PRIMARIES; do
+ echo " $PRIMARY;"
+ done
+ echo " };"
+ echo "};") >>$ZONEFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ fi
+ ;;
+ slave )
+ cat $COMMENTFILE >>$OPTIONFILE
+ echo " forward only;" >>$OPTIONFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ ;;
+ sortlist )
+ (cat $COMMENTFILE
+ echo " topology {"
+ for ARG in $ARGS; do
+ case $ARG in
+ *.0.0.0 )
+ echo " $ARG/8;"
+ ;;
+ *.0.0 )
+ echo " $ARG/16;"
+ ;;
+ *.0 )
+ echo " $ARG/24;"
+ ;;
+ * )
+ echo " $ARG;"
+ ;;
+ esac
+ done
+ echo " };") >>$OPTIONFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ ;;
+ tcplist | xfrnets )
+ (cat $COMMENTFILE
+ echo " allow-transfer {"
+ for ARG in $ARGS; do
+ case $ARG in
+ *.0.0.0 )
+ echo " $ARG/8;"
+ ;;
+ *.0.0 )
+ echo " $ARG/16;"
+ ;;
+ *.0 )
+ echo " $ARG/24;"
+ ;;
+ * )
+ echo " $ARG;"
+ ;;
+ esac
+ done
+ echo " };") >>$OPTIONFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ ;;
+ esac
+done
+
+if [ $DUMP -eq 1 ]; then
+ echo ""
+ echo "options {"
+ cat $OPTIONFILE
+ echo "};"
+ cat $ZONEFILE $COMMENTFILE
+
+ rm -f $OPTIONFILE $ZONEFILE $COMMENTFILE
+fi
+
+exit 0
diff --git a/contrib/bind/bin/named-xfer/Makefile b/contrib/bind/bin/named-xfer/Makefile
index 8db8b6e..76d9684 100644
--- a/contrib/bind/bin/named-xfer/Makefile
+++ b/contrib/bind/bin/named-xfer/Makefile
@@ -1,4 +1,4 @@
-## Copyright (c) 1996 by Internet Software Consortium
+## Copyright (c) 1996,1999 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
@@ -13,7 +13,7 @@
## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
## SOFTWARE.
-# $Id: Makefile,v 8.21 1998/04/14 00:39:03 halley Exp $
+# $Id: Makefile,v 8.29 1999/08/08 17:51:02 vixie Exp $
DESTDIR=
CC= cc
@@ -29,17 +29,19 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include
LIBBIND = ${TOP}/lib/libbind.a
A=a
O=o
+EXE=
LEX = lex -I
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
+AR= ar cru
INSTALL= install
STRIP=-s
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
PS=ps
LDFLAGS=
@@ -52,26 +54,28 @@ PROG= named-xfer
SRCS= ${PROG}.c
OBJS= ${PROG}.${O}
-all: ${PROG}
+all: ${PROG}${EXE}
-${PROG}: ${OBJS} ${NAMED_OBJS} ${LIBBIND} Makefile
- ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} ${NAMED_OBJS} \
+${PROG}${EXE}: ${OBJS} ${NAMED_OBJS} ${LIBBIND} Makefile
+ ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} ${NAMED_OBJS} \
${LIBBIND} ${SYSLIBS}
+.c.${O}:
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c
distclean: clean
clean: FRC
- rm -f ${PROG} core .depend
- rm -f *.BAK *.CKP *~ *.${O} *.orig
+ rm -f ${PROG}${EXE} ${OBJS} core .depend
+ rm -f *.BAK *.CKP *~ *.orig
depend: ${SRCS}
- mkdep -p ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
+ mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
${DESTDIR}${DESTEXEC}:
mkdir -p ${DESTDIR}${DESTEXEC}
-install: ${DESTDIR}${DESTEXEC} ${PROG}
- ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTEXEC}/${PROG}
+install: ${DESTDIR}${DESTEXEC} ${PROG}${EXE}
+ ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTEXEC}/${PROG}${EXE}
links: FRC
@set -e; ln -s SRC/*.[ch] .
@@ -79,9 +83,6 @@ links: FRC
tags: FRC
ctags ${SRCS} *.h
-commands.c: commands.l
- ${LEX} -t $< > $@ || rm $@
-
FRC:
# DO NOT DELETE THIS LINE -- mkdep uses it.
diff --git a/contrib/bind/bin/named/db_defs.h b/contrib/bind/bin/named/db_defs.h
index ab93480..9fe2021 100644
--- a/contrib/bind/bin/named/db_defs.h
+++ b/contrib/bind/bin/named/db_defs.h
@@ -1,9 +1,10 @@
/*
* from db.h 4.16 (Berkeley) 6/1/90
- * $Id: db_defs.h,v 8.17 1998/02/17 17:17:43 vixie Exp $
+ * $Id: db_defs.h,v 8.36 1999/08/26 18:42:32 vixie Exp $
*/
-/* Copyright (c) 1985, 1990
+/*
+ * Copyright (c) 1985, 1990
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,7 +36,8 @@
* SUCH DAMAGE.
*/
-/* Portions Copyright (c) 1993 by Digital Equipment Corporation.
+/*
+ * 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
@@ -54,7 +56,8 @@
* SOFTWARE.
*/
-/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+/*
+ * Portions Copyright (c) 1996-1999 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
@@ -74,12 +77,12 @@
* 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)
+ /* max length of data in a TXT RR segment */
+#define MAXCHARSTRING 255
+
#define DB_ROOT_TIMBUF 3600
#define TIMBUF 300
@@ -87,6 +90,16 @@
#define DICT_MAXLENGTH 127
#define DICT_INSERT_P 0x0001
+/* Average hash chain depths. */
+#define AVGCH_MARSHAL 5
+#define AVGCH_NLOOKUP 3
+
+/* Nonstandard maximum class to force better packing. */
+#define ZONE_BITS 24
+#define CLASS_BITS 8
+#define ZONE_MAX ((1<<ZONE_BITS)-1)
+#define CLASS_MAX ((1<<CLASS_BITS)-1)
+
/*
* Hash table structures.
*/
@@ -101,17 +114,18 @@ struct databuf {
* primary and secondary zones),
* d_ttl is the time to live.
*/
- unsigned d_flags :7; /* see below */
+ unsigned d_zone :ZONE_BITS; /* zone number or 0 for the cache */
+ unsigned d_class :CLASS_BITS; /* class number (nonstandard limit) */
+ unsigned d_flags :4; /* DB_F_{??????} */
+ unsigned d_secure :2; /* DB_S_{??????} */
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 */
+ unsigned d_rcode :4; /* rcode for negative caching */
+ unsigned d_mark :3; /* place to mark data */
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_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)
@@ -131,6 +145,7 @@ struct databuf {
#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 */
+#define DB_F_LAME 0x08 /* databuf may refer to lame server */
/*
* d_cred definitions
@@ -141,6 +156,13 @@ struct databuf {
#define DB_C_ADDITIONAL 1 /* additional data */
#define DB_C_CACHE 0 /* cache - worst */
+/*
+ * d_secure definitions
+ */
+#define DB_S_SECURE 2 /* secure (verified) data */
+#define DB_S_INSECURE 1 /* insecure data */
+#define DB_S_FAILED 0 /* data that failed a security check */
+
struct namebuf {
u_int n_hashval; /* hash value of _n_name */
struct namebuf *n_next; /* linked list */
@@ -162,6 +184,51 @@ struct hashbuf {
#define HASHSHIFT 3
#define HASHMASK 0x1f
+#define HASHROTATE(v) \
+ (((v) << HASHSHIFT) | ((v) >> ((sizeof(v) * 8) - HASHSHIFT)))
+#define HASHLOWER(c) ((isascii(c) && isupper(c)) ? tolower(c) : (c))
+#define HASHIMILATE(v,c) ((v) = (HASHROTATE(v)) + (HASHLOWER(c) & HASHMASK))
+
+#define TSIG_BUF_SIZE 640
+#define TSIG_SIG_SIZE 20
+
+struct tsig_record {
+ u_int8_t sig[TSIG_SIG_SIZE];
+ struct dst_key *key;
+ int siglen;
+};
+
+struct sig_record {
+ u_int16_t sig_type_n;
+ u_int8_t sig_alg_n, sig_labels_n;
+ u_int32_t sig_ottl_n, sig_exp_n, sig_time_n;
+ u_int16_t sig_keyid_n;
+};
+
+/* This is the wire format size of "struct sig_record", i.e., no padding. */
+#define SIG_HDR_SIZE 18
+
+struct dnode {
+ struct databuf *dp;
+ struct dnode *dn_next;
+ int line;
+ char *file;
+};
+
+typedef struct dnode * dlist;
+
+struct db_rrset {
+ dlist rr_list;
+ dlist rr_sigs;
+ char *rr_name;
+ int16_t rr_class;
+ int16_t rr_type;
+ struct db_rrset *rr_next;
+};
+#define DBHASHSIZE(s) (sizeof(struct hashbuf) + \
+ (s-1) * sizeof(struct db_rrset *))
+
+#define SIG_COVERS(dp) (ns_get16(dp->d_data))
/*
* Flags to updatedb
@@ -172,6 +239,8 @@ struct hashbuf {
#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_MERGE 0x40 /* make no control on rr in db_update (for ixfr) */
+#define DB_REPLACE 0x80 /* replace data if it exists */
#define DB_Z_CACHE 0 /* cache-zone-only db_dump() */
#define DB_Z_ALL 65535 /* normal db_dump() */
@@ -194,6 +263,8 @@ struct hashbuf {
#ifdef BIND_UPDATE
#define SERIAL (-11)
#endif
+#define CNAMEANDOTHER (-12)
+#define DNSSECFAIL (-13) /* db_set_update */
/*
* getnum() options
@@ -203,13 +274,18 @@ struct hashbuf {
#define GETNUM_SCALED 0x02 /* permit "k", "m" suffixes, scale result */
/*
+ * db_load() options
+ */
+#define ISNOTIXFR 0
+#define ISIXFR 1
+#define ISAXFRIXFR 2
+
+/*
* 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) \
+ if (!match(dp, (cl), (ty))) \
continue; \
else if (((zn) == DB_Z_CACHE) \
? stale(dp) \
diff --git a/contrib/bind/bin/named/db_dump.c b/contrib/bind/bin/named/db_dump.c
index 9c15af3..75a59b7 100644
--- a/contrib/bind/bin/named/db_dump.c
+++ b/contrib/bind/bin/named/db_dump.c
@@ -1,6 +1,6 @@
#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 $";
+static const char sccsid[] = "@(#)db_dump.c 4.33 (Berkeley) 3/3/91";
+static const char rcsid[] = "$Id: db_dump.c,v 8.40 1999/10/13 16:39:01 vixie Exp $";
#endif /* not lint */
/*
@@ -82,7 +82,7 @@ static char rcsid[] = "$Id: db_dump.c,v 8.24 1998/02/13 19:49:09 halley Exp $";
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -104,6 +104,7 @@ static char rcsid[] = "$Id: db_dump.c,v 8.24 1998/02/13 19:49:09 halley Exp $";
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -141,7 +142,7 @@ doadump()
return;
gettime(&tt);
fprintf(fp, "; Dumped at %s", ctimel(tt.tv_sec));
- if (zones && nzones)
+ if (zones != NULL && nzones != 0)
zt_dump(fp);
fputs(
"; Note: Cr=(auth,answer,addtnl,cache) tag only shown for non-auth RR's\n",
@@ -164,7 +165,7 @@ zt_dump(FILE *fp) {
struct zoneinfo *zp;
fprintf(fp, ";; ++zone table++\n");
- for (zp = &zones[1]; zp < &zones[nzones]; zp++) {
+ for (zp = &zones[0]; zp < &zones[nzones]; zp++) {
char *pre, buf[64];
u_int cnt;
@@ -183,8 +184,8 @@ zt_dump(FILE *fp) {
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),
+ fprintf(fp, ";\tftime=%lu, xaddrcnt=%d, state=%04x, pid=%d\n",
+ (u_long)zp->z_ftime, zp->z_xaddrcnt,
zp->z_flags, (int)zp->z_xferpid);
sprintf(buf, ";\tz_addr[%d]: ", zp->z_addrcnt);
pre = buf;
@@ -195,7 +196,7 @@ zt_dump(FILE *fp) {
if (zp->z_addrcnt)
fputc('\n', fp);
if (zp->z_axfr_src.s_addr != 0)
- fprintf(fp, "; update source [%s]\n",
+ fprintf(fp, ";\tupdate source [%s]\n",
inet_ntoa(zp->z_axfr_src));
}
fprintf(fp, ";; --zone table--\n");
@@ -209,13 +210,12 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) {
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 *sigdata, *certdata;
u_char *savecp;
char temp_base64[NS_MD5RSA_MAX_BASE64];
@@ -275,11 +275,11 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) {
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)
+ } else if (dp->d_ttl != USE_MINIMUM)
fprintf(fp, "%d\t", (int)dp->d_ttl);
- else if (tab)
- (void) putc('\t', fp);
+ else
+ fprintf(fp, "%d\t",
+ zones[dp->d_zone].z_minimum);
fprintf(fp, "%s\t%s\t",
p_class(dp->d_class),
p_type(dp->d_type));
@@ -538,9 +538,8 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) {
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++;
+ /* Labels (8-bit decimal) */
+ fprintf(fp, "%d ", *cp++);
/* OTTL (u_long) */
NS_GET32(n, cp);
fprintf(fp, "%u ", n);
@@ -573,10 +572,28 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) {
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));
+ fprintf(fp," %s", p_type(n));
}
break;
+ case ns_t_cert:
+ certdata = cp;
+ NS_GET16(n,cp);
+ fprintf(fp, "%d ", n); /* cert type */
+
+ NS_GET16(n,cp);
+ fprintf(fp, "%d %d ", n, *cp++); /* tag & alg */
+
+ /* Certificate (base64 of any length) */
+ i = b64_ntop(cp,
+ dp->d_size - (cp - certdata),
+ temp_base64, sizeof(temp_base64));
+ if (i < 0)
+ fprintf(fp, "; BAD BASE64");
+ else
+ fprintf(fp, "%s", temp_base64);
+ break;
+
default:
fprintf(fp, "%s?d_type=%d?",
sep, dp->d_type);
@@ -591,6 +608,17 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) {
sep, dp->d_clev);
sep = " ";
}
+ if ((dp->d_flags & DB_F_LAME) != 0) {
+ time_t when;
+ getname(np, dname, sizeof(dname));
+ when = db_lame_find(dname, dp);
+ if (when != 0 && when > tt.tv_sec) {
+ fprintf(fp, "%sLAME=%d",
+ sep, when - tt.tv_sec);
+ sep = " ";
+ }
+ }
+
eoln:
if (dp->d_ns != NULL){
fprintf(fp, "%s[%s]",
diff --git a/contrib/bind/bin/named/db_func.h b/contrib/bind/bin/named/db_func.h
index 2d4c05b..9ba5299 100644
--- a/contrib/bind/bin/named/db_func.h
+++ b/contrib/bind/bin/named/db_func.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 1985, 1990
+/*
+ * Copyright (c) 1985, 1990
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +31,8 @@
* SUCH DAMAGE.
*/
-/* Portions Copyright (c) 1993 by Digital Equipment Corporation.
+/*
+ * 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
@@ -49,7 +51,8 @@
* SOFTWARE.
*/
-/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+/*
+ * Portions Copyright (c) 1996-1999 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
@@ -65,9 +68,29 @@
* SOFTWARE.
*/
+/*
+ * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc.
+ *
+ * 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 Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES
+ * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED
+ * 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 $
+ * $Id: db_func.h,v 8.40 1999/10/07 08:24:06 vixie Exp $
*/
/* ++from db_update.c++ */
@@ -96,19 +119,30 @@ extern void doadump(void);
/* --from db_dump.c-- */
/* ++from db_load.c++ */
+extern 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);
extern void endline(FILE *);
extern int getword(char *, size_t, FILE *, int),
+ getttl(FILE *, const char *, int, u_int32_t *, int *),
getnum(FILE *, const char *, int),
- db_load(const char *, const char *,
- struct zoneinfo *, const char *);
+ db_load(const char *, const char *, struct zoneinfo *,
+ const char *, int);
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
+extern void db_err(int, char *, int, const char *, int);
+extern int parse_sec_rdata(char *inp, int inp_len, int inp_full,
+ u_char *data, int data_len,
+ FILE *fp, struct zoneinfo *zp,
+ char *domain, u_int32_t ttl,
+ int type, enum context context,
+ enum transport transport,
+ char **errmsg);
/* --from db_load.c-- */
/* ++from db_glue.c++ */
@@ -119,10 +153,8 @@ extern void buildservicelist(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 *);
+ get_class(const char *);
+extern u_int nhash(const char *);
extern const char *protocolname(int),
*servicename(u_int16_t, const char *);
#ifndef BSD
@@ -137,15 +169,45 @@ extern struct namebuf *rm_name(struct namebuf *,
struct namebuf *);
extern void rm_hash(struct hashbuf *);
extern void db_freedata(struct databuf *);
+extern void db_lame_add(char *zone, char *server, time_t when);
+extern time_t db_lame_find(char *zone, struct databuf *dp);
+extern void db_lame_clean(void);
+extern void db_lame_destroy(void);
/* --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);
+extern int match(struct databuf *, int, int),
+ nxtmatch(const char *, struct databuf *,
+ struct databuf *),
+ rrmatch(const char *, struct databuf *,
+ struct databuf *);
/* --from db_lookup.c-- */
-/* ++from db_dict.c++ */
-int dict_lookup(const char *, int, int);
-/* --from db_dict.c-- */
+/* ++from db_ixfr.c++ */
+struct ns_updrec * ixfr_get_change_list(struct zoneinfo *, u_int32_t,
+ u_int32_t);
+int ixfr_have_log(struct zoneinfo *, u_int32_t,
+ u_int32_t);
+/* --from db_ixfr.c++ */
+
+/* ++from db_sec.c++ */
+int add_trusted_key(const char *name, const int flags,
+ const int proto, const int alg,
+ const char *str);
+int db_set_update(char *name, struct databuf *dp,
+ void **state, int flags,
+ struct hashbuf **htp,
+ struct sockaddr_in from,
+ int *rrcount, int line,
+ const char *file);
+/* --from db_sec.c-- */
+/* ++from db_tsig.c++ */
+char * tsig_alg_name(int value);
+int tsig_alg_value(char *name);
+struct dst_key * tsig_key_from_addr(struct in_addr addr);
+struct tsig_record * new_tsig(struct dst_key *key, u_char *sig, int siglen);
+void free_tsig(struct tsig_record *tsig);
+/* --from db_tsig.c-- */
diff --git a/contrib/bind/bin/named/db_glob.h b/contrib/bind/bin/named/db_glob.h
index 79d915d..3d11739 100644
--- a/contrib/bind/bin/named/db_glob.h
+++ b/contrib/bind/bin/named/db_glob.h
@@ -1,9 +1,10 @@
/*
* from db.h 4.16 (Berkeley) 6/1/90
- * $Id: db_glob.h,v 8.8 1997/06/09 17:46:51 halley Exp $
+ * $Id: db_glob.h,v 8.12 1999/08/08 21:10:01 vixie Exp $
*/
-/* Copyright (c) 1985, 1990
+/*
+ * Copyright (c) 1985, 1990
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,7 +36,8 @@
* SUCH DAMAGE.
*/
-/* Portions Copyright (c) 1993 by Digital Equipment Corporation.
+/*
+ * 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
@@ -54,7 +56,8 @@
* SOFTWARE.
*/
-/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+/*
+ * Portions Copyright (c) 1996-1999 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
@@ -75,20 +78,26 @@
*/
/* ONE_WEEK maximum ttl */
-DECL u_int max_cache_ttl INIT(7*24*60*60);
+DECL u_int max_cache_ttl INIT(7*24*60*60);
/* no minimum ttl */
-DECL u_int min_cache_ttl INIT(0);
+DECL u_int min_cache_ttl INIT(0);
/* current line number */
-DECL int lineno;
+DECL int lineno INIT(0);
/* root hash table */
-DECL struct hashbuf *hashtab INIT(NULL);
+DECL struct hashbuf *hashtab INIT(NULL);
/* hash table of cache read from file */
-DECL struct hashbuf *fcachetab INIT(NULL);
+DECL struct hashbuf *fcachetab INIT(NULL);
+
+ /* state of ns_reload() and ns_reconfig(). */
+DECL int reloading INIT(0);
+DECL int reconfiging INIT(0);
-#ifdef FORCED_RELOAD
-DECL int reloading INIT(0);
-#endif /* FORCED_RELOAD */
+DECL const int hashsizes[]
+#ifdef MAIN_PROGRAM
+ = { 2, 11, 113, 337, 977, 2053, 4073, 8011, 16001, 99887, 0 }
+#endif
+ ;
diff --git a/contrib/bind/bin/named/db_glue.c b/contrib/bind/bin/named/db_glue.c
index bc6aed4..f1fae69 100644
--- a/contrib/bind/bin/named/db_glue.c
+++ b/contrib/bind/bin/named/db_glue.c
@@ -1,6 +1,6 @@
#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 $";
+static const char sccsid[] = "@(#)db_glue.c 4.4 (Berkeley) 6/1/90";
+static const char rcsid[] = "$Id: db_glue.c,v 8.39 1999/10/15 19:48:57 vixie Exp $";
#endif /* not lint */
/*
@@ -57,7 +57,7 @@ static char rcsid[] = "$Id: db_glue.c,v 8.27 1998/02/14 00:41:39 halley Exp $";
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -79,6 +79,8 @@ static char rcsid[] = "$Id: db_glue.c,v 8.27 1998/02/14 00:41:39 halley Exp $";
#include <sys/uio.h>
#include <sys/param.h>
#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -147,6 +149,7 @@ destroyservicelist() {
freestr(slp->proto);
memput(slp, sizeof *slp);
}
+ servicelist = NULL;
}
void
@@ -183,6 +186,7 @@ destroyprotolist() {
freestr(plp->name);
memput(plp, sizeof *plp);
}
+ protolist = NULL;
}
static int
@@ -451,29 +455,11 @@ getname(struct namebuf *np, char *buf, int buflen) {
*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
+ * note:
+ * this logic is intended to produce the same result as nlookup()'s.
*/
u_int
nhash(const char *name) {
@@ -481,136 +467,190 @@ nhash(const char *name) {
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);
+ while ((ch = (u_char)*name++) != (u_char)'\0')
+ HASHIMILATE(hval, ch);
+ return (hval);
}
-/*
-** 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"
-*/
+void
+db_freedata(struct databuf *dp) {
+ int bytes = DATASIZE(dp->d_size);
-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--;
- }
+ 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);
+}
- /* lb==0 means 'b' is the root domain, so 'a' must be in 'b'. */
- if (lb == 0)
- return (1);
+struct lame_hash {
+ struct lame_hash *next;
+ char *zone;
+ char *server;
+ time_t when;
+ unsigned int hval;
+} **lame_hash = NULL;
- /* 'b' longer than 'a' means 'a' can't be in 'b'. */
- if (lb > la)
- return (0);
+static int lame_hash_size = 0;
+static int lame_hash_cnt = 0;
- /* We use strncasecmp because we might be trying to
- * ignore a trailing dot. */
- if (lb == la)
- return (strncasecmp(a, b, lb) == 0);
+void
+db_lame_add(char *zone, char *server, time_t when) {
+ unsigned int hval = nhash(zone);
+ struct lame_hash *last, *this;
+ struct lame_hash **new;
+ int n;
+ int newsize;
+
+ db_lame_clean();
+
+ /* grow / initalise hash table */
+ if (lame_hash_cnt >= lame_hash_size) {
+ if (lame_hash_size == 0)
+ newsize = hashsizes[0];
+ else {
+ for (n = 0; (newsize = hashsizes[n++]) != 0; (void)NULL)
+ if (lame_hash_size == newsize) {
+ newsize = hashsizes[n];
+ break;
+ }
+ if (newsize == 0)
+ newsize = lame_hash_size * 2 + 1;
+ }
+ new = memget(newsize * sizeof this);
+ if (new == NULL)
+ return;
+ memset(new, 0, newsize * sizeof this);
+ for (n = 0 ; n < lame_hash_size; n++) {
+ this = lame_hash[n];
+ while (this) {
+ last = this;
+ this = this->next;
+ last->next = new[hval%newsize];
+ new[hval%newsize] = last;
+ }
+ }
+ if (lame_hash != NULL)
+ memput(lame_hash, lame_hash_size * sizeof this);
+ lame_hash = new;
+ lame_hash_size = newsize;
+ }
- /* Ok, we know la > lb. */
+ last = NULL;
+ this = lame_hash[hval%lame_hash_size];
+ while (this) {
+ if ((ns_samename(this->server, server) == 1) &&
+ (ns_samename(this->zone, zone) == 1)) {
+ this->when = when;
+ return;
+ }
+ last = this;
+ this = this->next;
+ }
+ this = memget(sizeof *this);
+ if (this == NULL)
+ return;
+ this->server = savestr(server, 0);
+ this->zone = savestr(zone, 0);
+ if (this->server == NULL || this->zone == NULL) {
+ if (this->server != NULL)
+ freestr(this->server);
+ if (this->zone != NULL)
+ freestr(this->zone);
+ memput(this, sizeof *this);
+ return;
+ }
+ this->when = when;
+ this->hval = hval;
+ this->next = NULL;
+ if (last != NULL)
+ last->next = this;
+ else
+ lame_hash[hval%lame_hash_size] = this;
+ lame_hash_cnt++;
+}
- diff = la - lb;
+time_t
+db_lame_find(char *zone, struct databuf *dp) {
+ unsigned int hval = nhash(zone);
+ struct lame_hash *this;
- /* 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)
+ if (lame_hash_size == 0) {
+ /* db_lame_destroy() must have been called. */
+ dp->d_flags &= ~DB_F_LAME;
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);
+ db_lame_clean(); /* Remove expired record so that we can
+ * clear DB_F_LAME when there are no
+ * additions. */
- /* 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);
+ this = lame_hash[hval % lame_hash_size];
+ while (this) {
+ if ((ns_samename(this->server, (char*)dp->d_data) == 1) &&
+ (ns_samename(this->zone, zone) == 1))
+ return (this->when);
+ this = this->next;
+ }
+ dp->d_flags &= ~DB_F_LAME;
+ return (0);
}
void
-db_freedata(struct databuf *dp) {
- int bytes = (dp->d_type == T_NS) ?
- DATASIZE(dp->d_size)+INT32SZ : DATASIZE(dp->d_size);
+db_lame_clean(void) {
+ int i;
+ struct lame_hash *last, *this;
+
+ for (i = 0 ; i < lame_hash_size; i++) {
+ last = NULL;
+ this = lame_hash[i];
+ while (this != NULL) {
+ if (this->when < tt.tv_sec) {
+ freestr(this->zone);
+ freestr(this->server);
+ if (last != NULL) {
+ last->next = this->next;
+ memput(this, sizeof *this);
+ this = last->next;
+ } else {
+ lame_hash[i] = this->next;
+ memput(this, sizeof *this);
+ this = lame_hash[i];
+ }
+ lame_hash_cnt--;
+ } else {
+ last = this;
+ this = this->next;
+ }
+ }
+ }
+}
- 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);
+void
+db_lame_destroy(void) {
+ int i;
+ struct lame_hash *last, *this;
+
+ if (lame_hash_size == 0)
+ return;
+
+ for (i = 0 ; i < lame_hash_size; i++) {
+ this = lame_hash[i];
+ while (this != NULL) {
+ last = this;
+ this = this->next;
+ freestr(last->zone);
+ freestr(last->server);
+ memput(last, sizeof *this);
+ }
+ }
+ memput(lame_hash, lame_hash_size * sizeof this);
+ lame_hash_cnt = 0;
+ lame_hash_size = 0;
+ lame_hash = NULL;
}
diff --git a/contrib/bind/bin/named/db_ixfr.c b/contrib/bind/bin/named/db_ixfr.c
new file mode 100644
index 0000000..a009f4d
--- /dev/null
+++ b/contrib/bind/bin/named/db_ixfr.c
@@ -0,0 +1,861 @@
+#if !defined(lint) && !defined(SABER)
+static char rcsid[] = "$Id: db_ixfr.c,v 8.18 1999/10/15 19:48:57 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc.
+ *
+ * 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 Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES
+ * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED
+ * 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.
+ */
+
+/*
+ * Manage ixfr transaction log
+ */
+
+#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 <res_update.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 "port_after.h"
+
+#include "named.h"
+
+#define DBIXFR_ERROR -1
+#define DBIXFR_FOUND_RR 2
+#define DBIXFR_END 3
+
+static int ixfr_getrr(struct zoneinfo *, FILE *, const char *, char *,
+ ns_updrec **, u_int32_t *, u_int32_t *);
+
+ns_updrec *
+ixfr_get_change_list(struct zoneinfo *zp,
+ u_int32_t from_serial, u_int32_t to_serial)
+{
+ FILE * fp;
+ u_int32_t old_serial, new_serial;
+ char origin[MAXDNAME];
+ struct namebuf *np, *listnp, *finlistnp;
+ LIST(ns_updrec) listuprec;
+ int ret, mode;
+ ns_updrec *uprec;
+
+ if (SEQ_GT(from_serial, to_serial))
+ return (NULL);
+ listnp = finlistnp = NULL;
+ INIT_LIST(listuprec);
+ if ((fp = fopen(zp->z_ixfr_base, "r")) == NULL) {
+ ns_warning(ns_log_db, "%s: %s",
+ zp->z_ixfr_base, strerror(errno));
+ return (NULL);
+ }
+ strcpy(origin, zp->z_origin);
+ lineno = 1;
+ np = NULL;
+ mode = 0;
+ old_serial = new_serial = 0;
+ for (;;) {
+ ret = ixfr_getrr(zp, fp, zp->z_ixfr_base, origin, &uprec,
+ &old_serial, &new_serial);
+ switch (ret) {
+ case DBIXFR_ERROR:
+ (void) my_fclose(fp);
+ ns_warning(ns_log_db, "Logical error in %s line %d",
+ zp->z_ixfr_base, lineno);
+ return (NULL);
+ case DBIXFR_FOUND_RR:
+ if (EMPTY(listuprec)) {
+ /* skip updates prior to the one we want */
+ if (uprec->r_zone != from_serial) {
+ while (uprec != NULL) {
+ ns_updrec *prev;
+
+ if (uprec->r_dp != NULL)
+ db_freedata(uprec->r_dp);
+ uprec->r_dp = NULL;
+ prev = PREV(uprec, r_link);
+ res_freeupdrec(uprec);
+ uprec = prev;
+ }
+ break;
+ }
+ }
+ APPEND(listuprec, uprec, r_link);
+ /* continue; */
+ break;
+ case DBIXFR_END:
+ (void) my_fclose(fp);
+ return (HEAD(listuprec));
+ default:
+ (void) my_fclose(fp);
+ return (NULL);
+ }
+ }
+}
+
+/*
+ * int ixfr_have_log(struct zoneinfo *zp,u_int32_t from_serial,
+ * u_int32_t to_serial)
+ *
+ * verify that ixfr transaction log contains changes
+ * from from_serial to to_serial
+ *
+ * returns:
+ * 0 = serial number is up to date
+ * 1 = transision is possible
+ * -1 = error while opening the ixfr transaction log
+ * -2 = error in parameters
+ * -3 = logical error in the history file
+ */
+int
+ixfr_have_log(struct zoneinfo *zp, u_int32_t from_serial, u_int32_t to_serial)
+{
+ FILE *fp;
+ u_int32_t old_serial = 0, new_serial = 0;
+ char buf[BUFSIZ];
+ char *cp;
+ struct stat st;
+ int nonempty_lineno = -1, prev_pktdone = 0, cont = 0,
+ inside_next = 0;
+ int err;
+ int id, rcode = NOERROR;
+
+ if (SEQ_GT(from_serial, to_serial))
+ return (-2);
+ if (from_serial == to_serial)
+ return (0);
+ /* If there is no log file, just return. */
+ if (zp->z_ixfr_base == NULL || zp->z_updatelog == NULL)
+ return (-1);
+ if (stat(zp->z_ixfr_base, &st) < 0) {
+ if (errno != ENOENT)
+ ns_error(ns_log_db,
+ "unexpected stat(%s) failure: %s",
+ zp->z_ixfr_base, strerror(errno));
+ return (-1);
+ }
+ if ((fp = fopen(zp->z_ixfr_base, "r")) == NULL) {
+ ns_warning(ns_log_db, "%s: %s",
+ zp->z_ixfr_base, strerror(errno));
+ return (-1);
+ }
+ 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, LogSignature) != 0) {
+ ns_error(ns_log_update, "invalid log file %s",
+ zp->z_updatelog);
+ fclose(fp);
+ return (-3);
+ }
+ lineno = 1;
+ for (;;) {
+ if (getword(buf, sizeof buf, fp, 0)) {
+ nonempty_lineno = lineno;
+ } else {
+ if (lineno == (nonempty_lineno + 1))
+ continue;
+ inside_next = 0;
+ prev_pktdone = 1;
+ cont = 1;
+ }
+ if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") ||
+ !strcasecmp(buf, "[IXFR_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, "serial")) {
+ cp = fgets(buf, sizeof buf, fp);
+ if (cp != NULL)
+ lineno++;
+ if (sscanf((char *) cp, "%u", &old_serial)) {
+ if (from_serial >= old_serial) {
+ fclose(fp);
+ return (1);
+ } else {
+ fclose(fp);
+ return (-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) != 2) {
+ fclose(fp);
+ return (-3);
+ } else if (from_serial >= old_serial) {
+ fclose(fp);
+ return (1);
+ }
+ fclose(fp);
+ return (-1);
+ }
+ if (prev_pktdone) {
+ prev_pktdone = 0;
+ if (feof(fp))
+ break;
+ }
+ }
+ fclose(fp);
+ return (0);
+}
+
+/* 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 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
+
+/*
+ * int
+ * ixfr_getrr(struct zoneinfo *zp, FILE *fp,
+ * const char *filename, char *origin, struct namebuf **np,
+ * u_int32_t *old_serial, u_int32_t *new_serial)
+ *
+ * read a line from the historic of a zone.
+ *
+ * returns:
+ *
+ * DBIXFR_ERROR = an error occured
+ * DBIXFR_FOUND_RR = a rr encountered
+ * DBIXFR_END = end of file
+ */
+static int
+ixfr_getrr(struct zoneinfo *zp, FILE *fp, const char *filename, char *origin,
+ ns_updrec **uprec, u_int32_t *old_serial,
+ u_int32_t *new_serial)
+{
+ static int read_soa, read_ns, rrcount;
+
+ char data[MAXDATA], dnbuf[MAXDNAME], sclass[3];
+ const char *errtype = "Database";
+ char *dname, *cp, *cp1;
+ char buf[MAXDATA];
+ u_int32_t serial, ttl;
+ int nonempty_lineno = -1, prev_pktdone = 0, cont = 0,
+ inside_next = 0;
+ int id, rcode = NOERROR;
+ int i, c, section, opcode, matches, zonenum, err, multiline;
+ int type, class;
+ u_int32_t n;
+ enum transport transport;
+ struct map *mp;
+ int zonelist[MAXDNAME];
+ struct databuf *dp;
+ struct in_addr ina;
+ struct sockaddr_in empty_from;
+ int datasize;
+ ns_updque listuprec;
+ ns_updrec * rrecp;
+ u_long l;
+
+#define ERRTO(msg) if (1) { errtype = msg; goto err; } else (void)NULL
+
+ err = 0;
+ transport = primary_trans;
+ lineno = 1;
+ INIT_LIST(listuprec);
+ for (;;) {
+ if (!getword(buf, sizeof buf, fp, 0)) {
+ if (lineno == (nonempty_lineno + 1) && !(feof(fp))) {
+ /*
+ * 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]") ||
+ !strcasecmp(buf, "[IXFR_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) != 2) {
+ ns_error(ns_log_update,
+ "incr_serial problem with %s",
+ zp->z_updatelog);
+ } else {
+ serial = get_serial(zp);
+ }
+ cont = 1;
+ } else if (!strcasecmp(buf, "[END_DELTA]")) {
+ prev_pktdone = 1;
+ cont = 1;
+ lineno++;
+ }
+ if (prev_pktdone) {
+ if (!EMPTY(listuprec)) {
+ n++;
+ *uprec = TAIL(listuprec);
+ return (DBIXFR_FOUND_RR);
+ }
+ 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 || ns_samename(origin, zp->z_origin) != 1)
+ err++;
+ if (cp)
+ lineno++;
+ 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 */
+ if (ns_parse_ttl(buf, &l) < 0) {
+ err++;
+ break;
+ }
+ ttl = l;
+ (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;
+ n++;
+ memcpy(data + n + 1, buf, i);
+ n += 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 ||
+ ns_samename(dname, zp->z_origin) != 1) {
+ err++;
+ break;
+ }
+ c = getnonblank(fp, zp->z_updatelog);
+ if (c == '(') {
+ multiline = 1;
+ } else {
+ multiline = 0;
+ ungetc(c, fp);
+ }
+ n = getnum(fp, zp->z_updatelog, GETNUM_SERIAL);
+ if (getnum_error) {
+ err++;
+ break;
+ }
+ if (opcode == ADD && i == 0)
+ *new_serial = n;
+ PUTLONG(n, cp);
+ for (i = 0; i < 4; i++) {
+ if (!getword(buf, sizeof buf, fp, 1)) {
+ err++;
+ break;
+ }
+ if (ns_parse_ttl(buf, &l) < 0) {
+ err++;
+ break;
+ }
+ n = l;
+ PUTLONG(n, cp);
+ }
+ if (multiline &&
+ getnonblank(fp, zp->z_updatelog) != ')')
+ {
+ err++;
+ break;
+ }
+ endline(fp);
+ n = cp - data;
+ 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 > MAXCHARSTRING) {
+ if (datasize <= MAXCHARSTRING) {
+ ns_error(ns_log_update,
+ "record too big");
+ return (-1);
+ }
+ datasize -= MAXCHARSTRING;
+ *cp++ = (char)MAXCHARSTRING;
+ memcpy(cp, cp1, MAXCHARSTRING);
+ cp += MAXCHARSTRING;
+ cp1 += MAXCHARSTRING;
+ i -= MAXCHARSTRING;
+ }
+ 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;
+ case ns_t_sig:
+ case ns_t_nxt:
+ case ns_t_key:
+ case ns_t_cert:{
+ char *errmsg = NULL;
+
+ n = parse_sec_rdata(buf, sizeof(buf), 1,
+ (u_char *) data,
+ sizeof(data),
+ fp, zp, dname, ttl,
+ type, domain_ctx,
+ transport, &errmsg);
+ if (errmsg) {
+ err++;
+ endline(fp);
+ n = 0;
+ }
+ 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 = zp->z_class;
+ }
+ }
+ }
+ 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);
+ memset(&empty_from, 0, sizeof empty_from);
+ free_rrecp(&listuprec, 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;
+ rrecp->r_opcode = opcode;
+ } else {
+ rrecp->r_zone = zonenum;
+ rrecp->r_opcode = opcode;
+ }
+
+ /* remove add/delete pairs */
+ if (section == S_UPDATE) {
+ ns_updrec *arp;
+ int foundmatch;
+
+ arp = TAIL(listuprec);
+ foundmatch = 0;
+ while (arp) {
+ if (arp->r_section == S_UPDATE &&
+ ((arp->r_opcode == DELETE &&
+ opcode == ADD) ||
+ (opcode == DELETE &&
+ arp->r_opcode == ADD)) &&
+ arp->r_dp->d_type == dp->d_type &&
+ arp->r_dp->d_class == dp->d_class &&
+ arp->r_dp->d_ttl == dp->d_ttl &&
+ ns_samename(arp->r_dname, dname) == 1 &&
+ db_cmp(arp->r_dp, dp) == 0) {
+ db_freedata(dp);
+ db_freedata(arp->r_dp);
+ UNLINK(listuprec, arp, r_link);
+ res_freeupdrec(arp);
+ res_freeupdrec(rrecp);
+ foundmatch = 1;
+ break;
+ }
+ arp = PREV(arp, r_link);
+ }
+ if (foundmatch)
+ continue;
+ }
+
+ APPEND(listuprec, rrecp, r_link);
+ /* Override zone number with current zone serial number */
+ rrecp->r_zone = serial;
+ }
+
+ if (err)
+ return (DBIXFR_ERROR);
+
+ return (DBIXFR_END);
+}
diff --git a/contrib/bind/bin/named/db_load.c b/contrib/bind/bin/named/db_load.c
index d05a969..9b6fedb 100644
--- a/contrib/bind/bin/named/db_load.c
+++ b/contrib/bind/bin/named/db_load.c
@@ -1,6 +1,6 @@
#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 $";
+static const char sccsid[] = "@(#)db_load.c 4.38 (Berkeley) 3/2/91";
+static const char rcsid[] = "$Id: db_load.c,v 8.97 1999/10/30 03:21:35 vixie Exp $";
#endif /* not lint */
/*
@@ -82,7 +82,7 @@ static char rcsid[] = "$Id: db_load.c,v 8.41 1998/02/13 20:02:28 halley Exp $";
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -110,6 +110,7 @@ static char rcsid[] = "$Id: db_load.c,v 8.41 1998/02/13 20:02:28 halley Exp $";
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -137,27 +138,28 @@ static char rcsid[] = "$Id: db_load.c,v 8.41 1998/02/13 20:02:28 halley Exp $";
/* 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 genname(char *, int, const char *, char *, int);
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 get_nxt_types(u_char *, FILE *, const char *);
+
+static int parse_sig_rr(char *, int, u_char *, int, FILE *,
+ struct zoneinfo *, char *, u_int32_t ,
+ enum context , enum transport , char **);
+static int parse_key_rr(char *, int, u_char *, int, FILE *,
+ struct zoneinfo *, char *, enum context,
+ enum transport, char **);
+
+static int parse_cert_rr(char *, int, u_char *, int, FILE *, char **);
+static int parse_nxt_rr(char *, int, u_char *, int, FILE *,
+ struct zoneinfo *, char *, enum context,
+ enum transport, char **);
+
+
static int wordtouint32_error = 0;
static int empty_token = 0;
static int getmlword_nesting = 0;
@@ -166,37 +168,50 @@ static int getmlword_nesting = 0;
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 CURRENT 1
+#define DOT 2
+#define AT 3
+#define DNAME 4
+#define INCLUDE 5
+#define ORIGIN 6
+#define GENERATE 7
+#define DEFAULTTTL 8
+#define ERRTOK 9
#define MAKENAME_OK(N) \
do { \
if (!makename_ok(N, origin, class, zp, \
- transport, context, \
+ transport, context, \
domain, filename, lineno, \
- sizeof(data) - ((u_char*)N - data))) { \
+ data_size - ((u_char*)N - data))) { \
+ errs++; \
+ sprintf(buf, "bad name \"%s\"", N); \
+ goto err; \
+ } \
+ } while (0)
+
+#define MAKENAME_OKZP(N, SI) \
+ do { \
+ if (!makename_ok(N, zp->z_origin, zp->z_class, zp, \
+ transport, context, \
+ domain, zp->z_source, lineno, \
+ SI - ((u_char*)N - data))) { \
errs++; \
sprintf(buf, "bad name \"%s\"", N); \
goto err; \
} \
} while (0)
+#define RANGE(x, min, max) \
+ (((x) > (max)) ? (max) : (((x) < (min)) ? (min) : (x)))
+
/* Public. */
/* int
- * db_load(filename, in_origin, zp, def_domain)
+ * db_load(filename, in_origin, zp, def_domain, isixfr)
* 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.
@@ -207,18 +222,24 @@ static notify_info_list pending_notifies;
*/
int
db_load(const char *filename, const char *in_origin,
- struct zoneinfo *zp, const char *def_domain)
+ struct zoneinfo *zp, const char *def_domain, int isixfr)
{
static int read_soa, read_ns, rrcount;
+ static u_int32_t default_ttl, default_warn;
+ static struct filenames {
+ struct filenames *next;
+ char *name;
+ } *filenames, *fn;
const char *errtype = "Database";
char *cp;
char domain[MAXDNAME], origin[MAXDNAME], tmporigin[MAXDNAME];
char buf[MAXDATA];
+ char genlhs[MAXDNAME], genrhs[MAXDNAME];
u_char data[MAXDATA];
- const char *op;
- int c, someclass, class, type, dbflags, dataflags, multiline;
- int slineno, i, errs, didinclude, escape, success, dateerror;
+ int data_size = sizeof(data);
+ int c, someclass, class, type, dbflags, dataflags, multiline = 0;
+ int slineno, i, errs, didinclude, ininclude, escape, success;
u_int32_t ttl, n, serial;
u_long tmplong;
struct databuf *dp;
@@ -227,9 +248,10 @@ db_load(const char *filename, const char *in_origin,
struct in_addr ina;
enum transport transport;
enum context context;
- u_int32_t sig_type;
- u_int32_t keyflags;
struct sockaddr_in empty_from;
+ int genstart, genend, genstep;
+ char *thisfile;
+ void *state = NULL;
empty_from.sin_family = AF_INET;
empty_from.sin_addr.s_addr = htonl(INADDR_ANY);
@@ -241,40 +263,57 @@ db_load(const char *filename, const char *in_origin,
* and complains.
*/
#define ERRTO(msg) do { if (1) { errtype = msg; goto err; } } while (0)
+#define ERRTOZ(msg) do { if (1) { errtype = msg; buf[0] = '\0'; goto err; } } while (0)
switch (zp->z_type) {
case Z_PRIMARY:
- case Z_CACHE:
+ case Z_HINT:
transport = primary_trans;
break;
case Z_SECONDARY:
case Z_STUB:
transport = secondary_trans;
break;
+ case Z_CACHE:
+ transport = response_trans;
+ break;
default:
transport = response_trans; /*guessing*/
break;
}
errs = 0;
didinclude = 0;
- if (!def_domain) {
- /* This is not the result of a $INCLUDE. */
+ ininclude = (def_domain != NULL);
+ if (!ininclude) {
rrcount = 0;
read_soa = 0;
read_ns = 0;
+ default_ttl = USE_MINIMUM;
+ default_warn = 1;
clev = nlabels(in_origin);
+ filenames = NULL;
}
+ ttl = default_ttl;
- ns_debug(ns_log_load, 1, "db_load(%s, %s, %d, %s)",
+ ns_debug(ns_log_load, 1, "db_load(%s, %s, %d, %s, %s)",
filename, in_origin, zp - zones,
- def_domain ? def_domain : "Nil");
+ def_domain ? def_domain : "Nil", isixfr ? "IXFR" : "Normal");
+
+ fn = (struct filenames *)memget(sizeof *filenames);
+ if (fn == NULL)
+ ns_panic(ns_log_db, 0, "db_load: memget failed");
+ thisfile = fn->name = savestr(filename, 1);
+ fn->next = filenames;
+ filenames = fn;
strcpy(origin, in_origin);
if ((fp = fopen(filename, "r")) == NULL) {
- ns_warning(ns_log_load, "%s: %s", filename, strerror(errno));
+ ns_warning(ns_log_load, "db_load could not open: %s: %s",
+ filename, strerror(errno));
+ zp->z_ftime = 0;
return (-1);
}
- if (zp->z_type == Z_CACHE) {
+ if (zp->z_type == Z_HINT) {
dbflags = DB_NODATA | DB_NOHINTS;
dataflags = DB_F_HINT;
#ifdef STUBS
@@ -288,7 +327,8 @@ db_load(const char *filename, const char *in_origin,
}
gettime(&tt);
if (fstat(fileno(fp), &sb) < 0) {
- ns_warning(ns_log_load, "%s: %s", filename, strerror(errno));
+ ns_warning(ns_log_load, "fstat failed: %s: %s",
+ filename, strerror(errno));
sb.st_mtime = (int)tt.tv_sec;
}
slineno = lineno;
@@ -302,6 +342,10 @@ db_load(const char *filename, const char *in_origin,
while ((c = gettoken(fp, filename)) != EOF) {
switch (c) {
case INCLUDE:
+ if (isixfr) {
+ c = ERRTOK;
+ break;
+ }
if (!getword(buf, sizeof buf, fp, 0))
/* file name*/
break;
@@ -309,12 +353,12 @@ db_load(const char *filename, const char *in_origin,
strcpy(tmporigin, origin);
else {
if (makename(tmporigin, origin,
- sizeof(tmporigin)) == -1)
+ sizeof(tmporigin)) == -1)
ERRTO("$INCLUDE makename failed");
endline(fp);
}
didinclude = 1;
- errs += db_load(buf, tmporigin, zp, domain);
+ errs += db_load(buf, tmporigin, zp, domain, ISNOTIXFR);
continue;
case ORIGIN:
@@ -329,6 +373,123 @@ db_load(const char *filename, const char *in_origin,
origin);
continue;
+ case GENERATE:
+ if (!getword(buf, sizeof(buf), fp, 0))
+ ERRTOZ("$GENERATE missing RANGE");
+ n = sscanf(buf, "%d-%d/%d", &genstart, &genend,
+ &genstep);
+ if (n != 2 && n != 3)
+ ERRTO("$GENERATE invalid range");
+ if (n == 2)
+ genstep = 1;
+ if ((genend < genstart) || (genstart < 0) ||
+ (genstep < 0))
+ ERRTO("$GENERATE invalid range");
+ if (!getword(genlhs, sizeof(genlhs), fp, 2))
+ ERRTOZ("$GENERATE missing LHS");
+ if (!getword(buf, sizeof(buf), fp, 0))
+ ERRTOZ("GENERATE missing TYPE");
+ type = sym_ston(__p_type_syms, buf, &success);
+ if (success == 0 || type == ns_t_any) {
+ ns_info(ns_log_load,
+ "%s: Line %d: $GENERATE unknown type: %s.",
+ filename, lineno, buf);
+ errs++;
+ endline(fp);
+ continue;
+ }
+ switch (type) {
+ case ns_t_ns:
+ case ns_t_ptr:
+ case ns_t_cname:
+ case ns_t_a:
+ case ns_t_aaaa:
+ break;
+ default:
+ ERRTO("$GENERATE unsupported type");
+ }
+ if (!getword(genrhs, sizeof(genrhs), fp, 2))
+ ERRTOZ("$GENERATE missing RHS");
+ for (i = genstart; i <= genend; i += genstep) {
+ if (genname(genlhs, i, origin, domain,
+ sizeof domain) == -1)
+ ERRTOZ("$GENERATE genname LHS failed");
+ context = ns_ownercontext(type, transport);
+ if (!ns_nameok(NULL, domain, class, zp, transport,
+ context, domain, inaddr_any)) {
+ strcpy(buf, domain);
+ ERRTO("$GENERATE owner name error");
+ }
+ switch (type) {
+ case ns_t_ns:
+ case ns_t_ptr:
+ case ns_t_cname:
+ if (genname(genrhs, i, origin, (char *)data,
+ sizeof data) == -1)
+ ERRTOZ("$GENERATE genname RHS failed");
+ switch (type) {
+ case ns_t_ns:
+ context = hostname_ctx;
+ break;
+ case ns_t_ptr:
+ context = ns_ptrcontext(domain);
+ break;
+ case ns_t_cname:
+ context = domain_ctx;
+ break;
+ }
+ if (!ns_nameok(NULL, (char *)data, class, zp,
+ transport, context,
+ domain, inaddr_any)) {
+ strncpy(buf, domain, sizeof(buf));
+ buf[sizeof(buf)-1] = '\0';
+ ERRTO("$GENERATE name error");
+ }
+ n = strlen((char *)data) + 1;
+ break;
+ case ns_t_a:
+ case ns_t_aaaa:
+ if (genname(genrhs, i, NULL, (char *)data,
+ sizeof data) == -1)
+ ERRTOZ("$GENERATE genname RHS failed");
+ strncpy(buf, (char*)data, sizeof(buf));
+ buf[sizeof(buf)-1] = '\0';
+ 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_aaaa:
+ if (inet_pton(AF_INET6, buf, data) <= 0)
+ ERRTO("IPv6 Address");
+ n = NS_IN6ADDRSZ;
+ break;
+ }
+ break;
+ default:
+ ERRTOZ("$GENERATE unsupported context");
+ }
+ 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;
+ c = db_set_update(domain, dp, &state, dbflags,
+ (dataflags & DB_F_HINT) != 0 ?
+ &fcachetab : &hashtab,
+ empty_from, &rrcount, lineno,
+ filename);
+ if (c != OK) {
+ if (c == CNAMEANDOTHER)
+ errs++;
+ }
+ }
+ endline(fp);
+ continue;
+
case DNAME:
if (!getword(domain, sizeof(domain), fp, 1))
break;
@@ -336,6 +497,14 @@ db_load(const char *filename, const char *in_origin,
ERRTO("ownername makename failed");
goto gotdomain;
+ case DEFAULTTTL:
+ if (getttl(fp, filename, lineno, &n,
+ &multiline) <= 0 || n > MAXIMUM_TTL) {
+ ERRTO("$TTL bad TTL value");
+ }
+ ttl = default_ttl = n;
+ continue;
+
case AT:
(void) strcpy(domain, origin);
goto gotdomain;
@@ -350,10 +519,19 @@ db_load(const char *filename, const char *in_origin,
continue;
break;
}
- if (ns_parse_ttl(buf, &tmplong) < 0)
- ttl = USE_MINIMUM;
- else {
- ttl = (u_int32_t)tmplong;
+ if (ns_parse_ttl(buf, &tmplong) < 0) {
+ if (zp->z_type == z_master &&
+ default_warn &&
+ (default_ttl == USE_MINIMUM)) {
+ ns_warning(ns_log_load,
+ "Zone \"%s\" (file %s): %s",
+ zp->z_origin, filename,
+ "No default TTL set using SOA minimum instead");
+ default_warn = 0;
+ }
+ ttl = (u_int32_t)default_ttl;
+ } else {
+ ttl = tmplong;
if (ttl > MAXIMUM_TTL) {
ns_info(ns_log_load,
"%s: Line %d: TTL > %u; converted to 0",
@@ -375,6 +553,14 @@ db_load(const char *filename, const char *in_origin,
/* Parse class (IN, etc) */
someclass = sym_ston(__p_class_syms, buf, &success);
+ if (success && someclass != zp->z_class) {
+ ns_info(ns_log_load,
+ "%s: Line %d: wrong class: %s.",
+ filename, lineno,
+ p_class(someclass));
+ errs++;
+ break;
+ }
if (success && someclass != C_ANY) {
class = someclass;
(void) getword(buf, sizeof buf, fp, 0);
@@ -389,9 +575,10 @@ db_load(const char *filename, const char *in_origin,
errs++;
break;
}
-
+ if (ttl == USE_MINIMUM)
+ ttl = zp->z_minimum;
context = ns_ownercontext(type, transport);
- if (!ns_nameok(domain, class, zp, transport, context,
+ if (!ns_nameok(NULL, domain, class, zp, transport, context,
domain, inaddr_any)) {
errs++;
ns_notice(ns_log_load,
@@ -404,6 +591,7 @@ db_load(const char *filename, const char *in_origin,
case ns_t_key:
case ns_t_sig:
case ns_t_nxt:
+ case ns_t_cert:
/*
* Don't do anything here for these types --
* they read their own input separately later.
@@ -451,7 +639,7 @@ db_load(const char *filename, const char *in_origin,
/* FALLTHROUGH */
soa_rp_minfo:
(void) strcpy((char *)data, buf);
-
+
MAKENAME_OK((char *)data);
cp = (char *)(data + strlen((char *)data) + 1);
if (!getword(cp,
@@ -469,13 +657,7 @@ db_load(const char *filename, const char *in_origin,
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) {
+ if (ns_samename(zp->z_origin, domain) != 1) {
errs++;
ns_error(ns_log_load,
"%s:%d: SOA for \"%s\" not at zone top \"%s\"",
@@ -509,9 +691,10 @@ db_load(const char *filename, const char *in_origin,
n = INIT_REFRESH;
}
PUTLONG(n, cp);
- zp->z_refresh = MAX(n, MIN_REFRESH);
+ zp->z_refresh = RANGE(n, MIN_REFRESH,
+ MAX_REFRESH);
if (zp->z_type == Z_SECONDARY
-#if defined(STUBS)
+#if defined(STUBS)
|| zp->z_type == Z_STUB
#endif
) {
@@ -520,7 +703,7 @@ db_load(const char *filename, const char *in_origin,
sched_zone_maint(zp);
}
#ifdef BIND_UPDATE
- if ((zp->z_type == Z_PRIMARY) &&
+ if ((zp->z_type == Z_PRIMARY) &&
(zp->z_flags & Z_DYNAMIC))
if ((u_int32_t)zp->z_soaincrintvl >
zp->z_refresh/3) {
@@ -537,14 +720,15 @@ db_load(const char *filename, const char *in_origin,
n = INIT_REFRESH;
}
PUTLONG(n, cp);
- zp->z_retry = MAX(n, MIN_RETRY);
+ zp->z_retry = RANGE(n, MIN_RETRY, MAX_RETRY);
if (getttl(fp, filename, lineno,
- &zp->z_expire, &multiline) <= 0) {
+ &n, &multiline) <= 0) {
errs++;
- zp->z_expire = INIT_REFRESH;
+ n = INIT_REFRESH;
}
- n = zp->z_expire;
PUTLONG(n, cp);
+ zp->z_expire = RANGE(n, zp->z_refresh,
+ MAX_EXPIRE);
if (getttl(fp, filename, lineno, &n,
&multiline) <= 0) {
errs++;
@@ -556,8 +740,10 @@ db_load(const char *filename, const char *in_origin,
"%s: Line %d: SOA minimum TTL > %u; converted to 0",
filename, lineno, MAXIMUM_TTL);
zp->z_minimum = 0;
- } else
+ } else
zp->z_minimum = n;
+ if (default_ttl == USE_MINIMUM)
+ ttl = n;
n = cp - (char *)data;
if (multiline) {
buf[0] = getnonblank(fp, filename);
@@ -584,7 +770,7 @@ db_load(const char *filename, const char *in_origin,
break;
case ns_t_ns:
- if (strcasecmp(zp->z_origin, domain) == 0)
+ if (ns_samename(zp->z_origin, domain) == 1)
read_ns++;
context = hostname_ctx;
goto cname_etc;
@@ -625,22 +811,28 @@ db_load(const char *filename, const char *in_origin,
if (!getword(buf, sizeof buf, fp, 0))
ERRTO("NAPTR Flags");
n = strlen(buf);
+ if (n > 255)
+ ERRTO("NAPTR Flags too big");
*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);
+ if (n > 255)
+ ERRTO("NAPTR Service Classes too big");
*cp++ = n;
memcpy(cp, buf, (int)n);
cp += n;
-
+
/* Pattern */
if (!getword(buf, sizeof buf, fp, 0))
ERRTO("NAPTR Pattern");
n = strlen(buf);
+ if (n > 255)
+ ERRTO("NAPTR Pattern too big");
*cp++ = n;
memcpy(cp, buf, (int)n);
cp += n;
@@ -648,6 +840,9 @@ db_load(const char *filename, const char *in_origin,
/* Replacement */
if (!getword(buf, sizeof buf, fp, 1))
ERRTO("NAPTR Replacement");
+ n = strlen(buf);
+ if (n > data_size - ((u_char *)cp - data))
+ ERRTO("NAPTR Replacement too big");
(void) strcpy((char *)cp, buf);
context = domain_ctx;
MAKENAME_OK(cp);
@@ -771,422 +966,31 @@ db_load(const char *filename, const char *in_origin,
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)
+ case ns_t_nxt:
+ case ns_t_key:
+ case ns_t_cert:
+ case ns_t_sig: {
+ char *errmsg = NULL;
+ int ret = parse_sec_rdata(buf, sizeof(buf), 0,
+ data, sizeof(data),
+ fp, zp, domain, ttl,
+ type, domain_ctx,
+ transport, &errmsg);
+ if (ret < 0) {
+ errtype = errmsg;
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 */
+ n = ret;
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++;
+ n++;
while ((i = getc(fp), *cp = i, i != EOF)
&& *cp != '\n'
&& (n < MAXDATA)) {
@@ -1202,6 +1006,7 @@ db_load(const char *filename, const char *in_origin,
endline(fp);
break;
+
default:
goto err;
}
@@ -1209,7 +1014,7 @@ db_load(const char *filename, const char *in_origin,
* Ignore data outside the zone.
*/
if (zp->z_type != Z_CACHE &&
- !samedomain(domain, zp->z_origin))
+ !ns_samedomain(domain, zp->z_origin))
{
ns_info(ns_log_load,
"%s:%d: data \"%s\" outside zone \"%s\" (ignored)",
@@ -1223,42 +1028,44 @@ db_load(const char *filename, const char *in_origin,
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++;
- }
+ c = db_set_update(domain, dp, &state, dbflags,
+ (dataflags & DB_F_HINT) != 0 ?
+ &fcachetab : &hashtab,
+ empty_from, &rrcount, lineno,
+ filename);
+ if (c == CNAMEANDOTHER)
+ errs++;
continue;
- case ERROR:
+ case ERRTOK:
break;
}
err:
errs++;
- ns_notice(ns_log_load, "%s:%d: %s error (%s)",
+ ns_notice(ns_log_load, "%s:%d: %s error near (%s)",
filename, empty_token ? (lineno - 1) : lineno,
errtype, buf);
if (!empty_token)
endline(fp);
}
+ c = db_set_update(NULL, NULL, &state, dbflags,
+ (dataflags & DB_F_HINT) ? &fcachetab : &hashtab,
+ empty_from, &rrcount, lineno, filename);
+ if (c != OK) {
+ if (c == CNAMEANDOTHER)
+ errs++;
+ }
+
(void) my_fclose(fp);
lineno = slineno;
- if (!def_domain) {
+ if (!ininclude) {
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) {
+ if (zp->z_type != Z_CACHE && zp->z_type != Z_HINT) {
const char *msg = NULL;
if (read_soa == 0)
@@ -1276,62 +1083,45 @@ db_load(const char *filename, const char *in_origin,
zp->z_origin, filename, msg);
}
}
- }
- if (!def_domain) {
- if (errs)
+ while (filenames) {
+ fn = filenames;
+ filenames = filenames->next;
+ freestr(fn->name);
+ memput(fn, sizeof *fn);
+ }
+ if (errs != 0)
ns_warning(ns_log_load,
"%s zone \"%s\" (%s) rejected due to errors (serial %u)",
- zoneTypeString(zp), zp->z_origin,
+ zoneTypeString(zp->z_type), 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,
+ zoneTypeString(zp->z_type), zp->z_origin,
p_class(zp->z_class), zp->z_serial);
}
- if (errs) {
+ if (errs != 0) {
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);
- }
- }
- }
- }
+ if (errs == 0 && (!ininclude) &&
+ (zp->z_type == z_master || zp->z_type == z_slave))
+ ns_notify(zp->z_origin, zp->z_class, ns_t_soa);
#endif
return (errs);
}
+void
+db_err(int err, char *domain, int type, const char *filename, int lineno) {
+ if (filename != NULL && err == CNAMEANDOTHER)
+ ns_notice(ns_log_load, "%s:%d:%s: CNAME and OTHER data error",
+ filename, lineno, domain);
+ if (err != DATAEXISTS)
+ ns_debug(ns_log_load, 1, "update failed %s %d",
+ domain, type);
+}
+
static int
gettoken(FILE *fp, const char *src) {
int c;
@@ -1350,11 +1140,15 @@ gettoken(FILE *fp, const char *src) {
return (INCLUDE);
if (!strcasecmp("origin", op))
return (ORIGIN);
+ if (!strcasecmp("generate", op))
+ return (GENERATE);
+ if (!strcasecmp("ttl", op))
+ return (DEFAULTTTL);
}
ns_notice(ns_log_db,
"%s:%d: Unknown $ option: $%s",
src, lineno, op);
- return (ERROR);
+ return (ERRTOK);
case ';':
while ((c = getc(fp)) != EOF && c != '\n')
@@ -1375,6 +1169,10 @@ gettoken(FILE *fp, const char *src) {
lineno++;
continue;
+ case '\r':
+ if (NS_OPTION_P(OPTION_TREAT_CR_AS_SPACE) != 0)
+ return (CURRENT);
+
default:
(void) ungetc(c, fp);
return (DNAME);
@@ -1391,6 +1189,7 @@ gettoken(FILE *fp, const char *src) {
* size - of destination
* fp - file to read from
* preserve - should we preserve \ before \\ and \.?
+ * if preserve == 2, then keep all \
* return value:
* 0 = no word; perhaps EOL or EOF; lineno was incremented.
* 1 = word was read
@@ -1398,10 +1197,12 @@ gettoken(FILE *fp, const char *src) {
int
getword(char *buf, size_t size, FILE *fp, int preserve) {
char *cp = buf;
- int c, spaceok;
+ int c, spaceok, once;
empty_token = 0; /* XXX global side effect. */
+ once = 0;
while ((c = getc(fp)) != EOF) {
+ once++;
if (c == ';') {
/* Comment. Skip to end of line. */
while ((c = getc(fp)) != EOF && c != '\n')
@@ -1427,6 +1228,9 @@ getword(char *buf, size_t size, FILE *fp, int preserve) {
c = '\\';
if (preserve)
switch (c) {
+ default:
+ if (preserve == 1)
+ break;
case '\\':
case '.':
case '0':
@@ -1474,6 +1278,9 @@ getword(char *buf, size_t size, FILE *fp, int preserve) {
c = '\\';
if (preserve)
switch (c) {
+ default:
+ if (preserve == 1)
+ break;
case '\\':
case '.':
case '0':
@@ -1510,6 +1317,8 @@ getword(char *buf, size_t size, FILE *fp, int preserve) {
*cp = '\0';
if (cp == buf)
empty_token = 1;
+ if (!once)
+ lineno++;
return (cp != buf);
}
@@ -1524,7 +1333,7 @@ getword(char *buf, size_t size, FILE *fp, int preserve) {
* side effects:
* *ttl is written if the return value is to be 1.
*/
-static int
+int
getttl(FILE *fp, const char *fn, int lineno, u_int32_t *ttl, int *multiline) {
char buf[MAXDATA];
u_long tmp;
@@ -1748,6 +1557,103 @@ getnonblank(FILE *fp, const char *src) {
}
/*
+ * Replace all single "$"'s in "name" with "it".
+ * ${delta} will add delta to "it" before printing.
+ * ${delta,width} will change print width as well, zero fill is implied
+ * ${delta,width,radix} will change radix as well, can be d, o, x, X.
+ * i.e. ${0,2,X} will produce a two digit hex (upper case) with zero fill.
+ * Append "origin" to name if required and validate result with makename.
+ * To get a "$" or "{" in the output use \ before it.
+ * Return 0 on no error or -1 on error.
+ * Resulting name stored in "buf".
+ */
+
+static int
+genname(char *name, int it, const char *origin, char *buf, int size) {
+ char *bp = buf;
+ char *eom = buf + size;
+ char *cp;
+ char numbuf[32];
+ char fmt[32];
+ int delta = 0;
+ int width;
+
+ while (*name) {
+ if (*name == '$') {
+ if (*(++name) == '$') {
+ /* should be deprecated. how? */
+ if (bp >= eom)
+ return (-1);
+ *bp++ = *name++;
+ } else {
+ strcpy(fmt, "%d");
+ if (*name == '{') {
+ switch (sscanf(name, "{%d,%d,%1[doxX]}", &delta, &width, numbuf)) {
+ case 1:
+ break;
+ case 2:
+ sprintf(fmt, "%%0%dd", width);
+ break;
+ case 3:
+ sprintf(fmt, "%%0%d%c", width, numbuf[0]);
+ break;
+ default:
+ return (-1);
+ }
+ while (*name && *name++ != '}') {
+ continue;
+ }
+ }
+ sprintf(numbuf, fmt, it + delta);
+ cp = numbuf;
+ while (*cp) {
+ if (bp >= eom)
+ return (-1);
+ *bp++ = *cp++;
+ }
+ }
+ } else if (*name == '\\') {
+ if (*(++name) == '\0') {
+ if (bp >= eom)
+ return (-1);
+ *bp++ = '\\';
+ } else {
+ switch (*name) {
+ case '\\':
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (bp >= eom)
+ return (-1);
+ *bp++ = '\\';
+ default:
+ if (bp >= eom)
+ return (-1);
+ *bp++ = *name++;
+ }
+ }
+ } else {
+ if (bp >= eom)
+ return (-1);
+ *bp++ = *name++;
+ }
+ }
+ if (bp >= eom)
+ return (-1);
+ *bp = '\0';
+ return (origin == NULL ? 0 : makename(buf, origin, size));
+}
+
+
+/*
* Take name and fix it according to following rules:
* "." means root.
* "@" means current origin.
@@ -1786,7 +1692,7 @@ makename(char *name, const char *origin, int size) {
return (0);
}
-static int
+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)
@@ -1798,7 +1704,7 @@ makename_ok(char *name, const char *origin, int class, struct zoneinfo *zp,
filename, lineno);
return (0);
}
- if (!ns_nameok(name, class, zp, transport, context, owner,
+ if (!ns_nameok(NULL, name, class, zp, transport, context, owner,
inaddr_any)) {
ns_info(ns_log_db, "%s:%d: database naming error",
filename, lineno);
@@ -1928,91 +1834,6 @@ wordtouint32(buf)
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,
@@ -2029,7 +1850,7 @@ getcharstring(char *buf, char *data, int type,
if (type == ns_t_txt || type == ns_t_x25) {
while (i > MAXCHARSTRING
&& n + MAXCHARSTRING + 1 < MAXDATA) {
- data[n] = MAXCHARSTRING;
+ data[n] = (char)MAXCHARSTRING;
memmove(data + n + 1, b, MAXCHARSTRING);
n += MAXCHARSTRING + 1;
b += MAXCHARSTRING;
@@ -2040,13 +1861,13 @@ getcharstring(char *buf, char *data, int type,
if (i > MAXCHARSTRING) {
ns_info(ns_log_db,
"%s:%d: RDATA field %d too long",
- src, lineno, nfield);
+ src, lineno -1, nfield);
return (0);
}
if (n + i + 1 > MAXDATA) {
ns_info(ns_log_db,
"%s:%d: total RDATA too long",
- src, lineno);
+ src, lineno -1);
return (0);
}
data[n] = i;
@@ -2058,7 +1879,7 @@ getcharstring(char *buf, char *data, int type,
if (nfield < minfields) {
ns_info(ns_log_db,
"%s:%d: expected %d RDATA fields, only saw %d",
- src, lineno, minfields, nfield);
+ src, lineno -1, minfields, nfield);
return (0);
}
@@ -2083,18 +1904,18 @@ getcharstring(char *buf, char *data, int type,
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 maxtype=0;
int success;
int type;
int errs = 0;
- memset(data, 0, ns_t_any/NS_NXT_BITS+1);
+ memset(data, 0, NS_NXT_MAX/NS_NXT_BITS+1);
while (getmlword(b, sizeof(b), fp, 0)) {
if (feof(fp) || ferror(fp))
- break;
+ break;
if (strlen(b) == 0 || b[0] == '\n')
- continue;
+ continue;
/* Parse RR type (A, MX, etc) */
type = sym_ston(__p_type_syms, (char *)b, &success);
@@ -2106,7 +1927,7 @@ get_nxt_types(u_char *data, FILE *fp, const char *filename) {
continue;
}
NS_NXT_BIT_SET(type, data);
- if (type > maxtype)
+ if (type > maxtype)
maxtype = type;
}
if (errs)
@@ -2157,62 +1978,623 @@ fixup_soa(const char *fn, struct zoneinfo *zp) {
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);
-}
+/* this function reads in the sig record rdata from the input file and
+ * returns the following codes
+ * > 0 length of the recrod
+ * ERR_EOF end of file
+ *
+ */
-void
-notify_after_load(evContext ctx, void *uap, const void *tag) {
- int delay, max_delay;
- notify_info ni = uap;
+static int
+parse_sig_rr(char *buf, int buf_len, u_char *data, int data_size,
+ FILE *fp, struct zoneinfo *zp, char *domain, u_int32_t ttl,
+ enum context domain_ctx, enum transport transport, char **errmsg)
+{
+/* 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
+ Labels 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.
+*/
+ u_int32_t sig_type;
+ int dateerror;
+ int siglen, success;
+ u_char *cp;
+ u_int32_t al, la, n;
+ u_int32_t signtime, exptime, timetilexp;
+ u_int32_t origTTL;
+ enum context context;
+ time_t now;
+ char *errtype = "SIG error";
+ int i, my_buf_size = MAXDATA, errs = 0;
+
+
+ /* 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 */
- 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);
+ /* RRtype (char *)
+ * if old style inp will contain the next token
+ *copy that into buffer, otherwise read from file
+ */
+ if (buf && buf_len == 0)
+ if (!getmlword((char*)buf, my_buf_size, 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 = &data[i];
+ PUTSHORT((u_int16_t)sig_type, cp);
+ i += 2;
+
+ /* Algorithm id (8-bit decimal) */
+ if (!getmlword(buf, my_buf_size, fp, 0))
+ ERRTO("Missing algorithm ID");
+ al = wordtouint32(buf);
+ if (0 == al || wordtouint32_error || 255 <= al)
+ ERRTO("Bad algorithm number");
+ data[i] = (u_char) al;
+ i++;
+
+ /*
+ * Labels (8-bit decimal)
+ */
+ if (!getmlword(buf, my_buf_size, fp, 0))
+ ERRTO("Missing label count");
+ la = wordtouint32(buf);
+ if (0 == la || wordtouint32_error || 255 <= la)
+ ERRTO("Bad label count number");
+ data[i] = (u_char) la;
+ i++;
+
+ /*
+ * OTTL (optional u_int32_t) and
+ * Texp (u_int32_t date)
+ */
+ if (!getmlword(buf, my_buf_size, 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 ns_datetosecs.
+ */
+ exptime = ns_datetosecs(buf, &dateerror);
+ if (!dateerror) {
+ /* Output TTL as OTTL */
+ origTTL = ttl;
+ cp = &data[i];
+ PUTLONG (origTTL, cp);
+ i += 4;
+ } else {
+ /* Parse and output OTTL; scan TEXP */
+ origTTL = wordtouint32(buf);
+ if (0 >= origTTL || wordtouint32_error ||
+ (origTTL > 0x7fffffff))
+ ERRTO("Original TTL value bad");
+ cp = &data[i];
+ PUTLONG(origTTL, cp);
+ i += 4;
+ if (!getmlword(buf, my_buf_size, fp, 0))
+ ERRTO("Expiration time missing");
+ exptime = ns_datetosecs(buf, &dateerror);
}
- ni->state = notify_info_delay;
+ if (dateerror || exptime > 0x7fffffff || exptime <= 0)
+ ERRTO("Invalid expiration time");
+ cp = &data[i];
+ PUTLONG(exptime, cp);
+ i += 4;
+
+ /* Tsig (u_int32_t) */
+ if (!getmlword(buf, my_buf_size, fp, 0))
+ ERRTO("Missing signature time");
+ signtime = ns_datetosecs(buf, &dateerror);
+ if (0 == signtime || dateerror)
+ ERRTO("Invalid signature time");
+ cp = &data[i];
+ PUTLONG(signtime, cp);
+ i += 4;
+
+ /* Kfootprint (unsigned_16) */
+ if (!getmlword(buf, my_buf_size, fp, 0))
+ ERRTO("Missing key footprint");
+ n = wordtouint32(buf);
+ if (wordtouint32_error || n >= 0x0ffff)
+ ERRTO("Invalid key footprint");
+ cp = &data[i];
+ PUTSHORT((u_int16_t)n, cp);
+ i += 2;
+
+ /* Signer's Name */
+ if (!getmlword((char*)buf, my_buf_size, fp, 0))
+ ERRTO("Missing signer's name");
+ cp = &data[i];
+ strcpy((char *)cp, buf);
+ context = domain_ctx;
+ MAKENAME_OKZP((char *)cp, data_size);
+ i += strlen((char *)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, my_buf_size, fp, 0)) {
+ siglen = 0;
+ } else {
+ cp = &data[i];
+ siglen = b64_pton(buf, (u_char*)cp, data_size - i);
+ if (siglen < 0)
+ ERRTO("Signature block bad");
+ }
+
+ /* 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); /* need to find a better place for this XXX ogud */
+ /* 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");
+ break;
+
+ case NS_ALG_DH:
+ if (siglen < 1)
+ ERRTO("DH Signature too short");
+ break; /* need more tests here */
+
+ case NS_ALG_DSA:
+ if (siglen < NS_DSA_SIG_SIZE)
+ ERRTO("DSS Signature too short");
+ else if (siglen > NS_DSA_SIG_SIZE)
+ ERRTO("DSS Signature too long ");
+ break; /* need more tests here */
+
+ 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;
+ default:
+ ERRTO("UNKOWN SIG algorithm");
+ }
+
+ /* 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 */
+
+ return (n);
+ err:
+ *errmsg = errtype;
+ return (-1);
}
-static void
-notify_after_delay(evContext ctx, void *uap,
- struct timespec due,
- struct timespec inter)
+static int
+parse_nxt_rr(char *buf, int buf_len, u_char *data, int data_size,
+ FILE *fp, struct zoneinfo *zp, char *domain, enum context context,
+ enum transport transport, char **errmsg)
{
- notify_info ni = uap;
+
+ /* 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).
+ */
+ int n, errs = 0, i;
+ u_char *cp;
+/* char *origin = zp->z_origin;
+ int class = zp->z_class; */
+ *errmsg = "NXT name error";
+
+ (void) strcpy((char *)data, buf);
+ MAKENAME_OKZP((char *)data, data_size);
+ n = strlen((char *)data) + 1;
+ cp = n + data;
+ i = get_nxt_types(cp, fp, zp->z_source);
+ if( i > 0)
+ return (n + i);
+ *errmsg = "NXT type error";
+ err:
+ return (-1);
+}
- UNLINK(pending_notifies, ni, link);
- ni->state = notify_info_done;
- sysnotify(ni->name, ni->class, ns_t_soa);
- free_notify_info(ni);
+
+static int
+parse_cert_rr(char *buf, int buf_len, u_char *data, int data_size,
+ FILE *fp, char **errmsg)
+{
+ /* Cert record looks like:
+ * Type Key_tag Alg Cert
+ * Type: certification type number (16)
+ * Key_tag: tag of corresponding KEY RR (16)
+ * Alg: algorithm of the KEY RR (8)
+ * Cert: base64 enocded block
+ */
+ u_char *cp;
+ u_int32_t cert_type, key_tag, alg;
+ char *errtype = "CERT parse error";
+ int certlen, i, n, success;
+
+ i = 0;
+ cp = &data[i];
+ cert_type = sym_ston(__p_cert_syms, buf, &success);
+ if (!success) {
+ cert_type = wordtouint32(buf);
+ if (wordtouint32_error || cert_type > 0xFFFF)
+ ERRTO("CERT type out of range");
+ }
+ PUTSHORT((u_int16_t)cert_type, cp);
+ i += INT16SZ;
+
+ if (!getmlword((char*)buf, buf_len, fp, 0))
+ ERRTO("CERT doesn't specify type");
+
+ key_tag = wordtouint32(buf);
+ if (wordtouint32_error || key_tag > 0xFFFF)
+ ERRTO("CERT KEY tag out of range");
+
+ PUTSHORT((u_int16_t)key_tag, cp);
+ i += INT16SZ;
+
+ if (!getmlword(buf, buf_len, fp, 0))
+ ERRTO("CERT missing algorithm ID");
+
+ alg = sym_ston(__p_key_syms, buf, &success);
+ if (!success) {
+ alg = wordtouint32(buf);
+ if (wordtouint32_error || alg > 0xFF)
+ ERRTO("CERT KEY alg out of range");
+ }
+
+ data[i++] = (u_char)alg;
+
+ if (!getallwords(buf, buf_len, fp, 0)) {
+ certlen = 0;
+ }
+ else {
+ cp = &data[i];
+ certlen = b64_pton(buf, (u_char*)cp, sizeof(data) - i);
+ if (certlen < 0)
+ ERRTO("CERT blob has encoding error");
+ }
+ /* set total length */
+ n = i + certlen;
+ return (n);
+ err:
+ *errmsg = errtype;
+ return (-1);
+
}
-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);
+static int
+parse_key_rr(char *buf, int buf_len, u_char *data, int data_size,
+ FILE *fp, struct zoneinfo *zp, char *domain, enum context context,
+ enum transport transport, char **errmsg)
+{
+ /* 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,i, n;
+ u_int32_t keyflags;
+ char *errtype = "KEY error";
+ u_char *cp, *expstart;
+ u_int expbytes, modbytes;
+
+ i = n = 0;
+ data[i] = '\0';
+ cp = data;
+ getmlword_nesting = 0; /* KLUDGE err recov. */
+
+ /*>>> Flags (unsigned_16) */
+ keyflags = wordtouint32(buf);
+ if (wordtouint32_error || 0xFFFF < keyflags)
+ ERRTO("KEY flags error");
+ if (keyflags & NS_KEY_RESERVED_BITMASK)
+ ERRTO("KEY Reserved Flag Bit");
+ PUTSHORT(keyflags, cp);
+
+ /*>>> Protocol (8-bit decimal) */
+ if (!getmlword((char*)buf, buf_len, 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, buf_len, 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;
+
+ /*>>> Extended KEY flag field in bytes 5 and 6 */
+ if (NS_KEY_EXTENDED_FLAGS & keyflags) {
+ u_int32_t keyflags2;
+
+ if (!getmlword((char*)buf, buf_len, fp, 0))
+ ERRTO("KEY Flags Field");
+ keyflags2 = wordtouint32(buf);
+ if (wordtouint32_error || 0xFFFF < keyflags2)
+ ERRTO("Extended key flags error");
+ if (keyflags2 & NS_KEY_RESERVED_BITMASK2)
+ ERRTO("KEY Reserved Flag2 Bit");
+ PUTSHORT(keyflags2, cp);
+ }
+
+ /*>>> 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,
+ data_size - (cp - data));
+ if (klen < 0)
+ ERRTO("KEY Public Key");
+ }
+
+ /* set total length */
+ n = klen + (cp - data);
+
+ /*
+ * Now check for valid key flags & algs & etc, from the RFC.
+ */
+
+ if (NS_KEY_TYPE_NO_KEY == (keyflags & NS_KEY_TYPEMASK))
+ nk = 1; /* No-key */
+ else
+ nk = 0; /* have a key */
+
+ if ((keyflags & (NS_KEY_NAME_TYPE | NS_KEY_TYPEMASK)) ==
+ (NS_KEY_NAME_ZONE | NS_KEY_TYPE_CONF_ONLY))
+ /* 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_DH: {
+ u_char *dh_cp;
+ u_int16_t dh_len, plen, glen, ulen;
+
+ dh_cp = (u_char *)cp;
+ GETSHORT(plen, dh_cp);
+ if(plen < 16)
+ ERRTO("DH short plen");
+ dh_len = 2 + plen;
+ if(dh_len > klen)
+ ERRTO("DH plen > klen");
+
+ GETSHORT(glen, dh_cp);
+ if(glen <= 0 || glen > plen)
+ ERRTO("DH glen bad");
+ dh_len = 2 + glen;
+ if(dh_len > klen)
+ ERRTO("DH glen > klen");
+
+ GETSHORT(ulen, dh_cp);
+ if(ulen <= 0 || ulen > plen)
+ ERRTO("DH ulen bad");
+ dh_len = 2 + ulen;
+ if(dh_len > klen)
+ ERRTO("DH ulen > klen");
+ else if (dh_len < klen)
+ ERRTO("DH *len < klen");
+ break;
}
- INIT_LIST(pending_notifies);
+
+ case NS_ALG_DSA: {
+ u_int8_t t;
+
+ if ( klen == 0)
+ break;
+ t = *cp;
+ if (t > 8)
+ ERRTO("DSA T value");
+ if (klen != (1 + 20 + 3 *(64+8*t)))
+ ERRTO("DSA length");
+ break;
+ }
+
+ case NS_ALG_PRIVATE_OID:
+ if (klen == 0)
+ ERRTO("No ObjectID in key");
+ break;
+ default:
+ ERRTO("Unknown Key algorithm");
+ }
+
+ endline(fp); /* flush the rest of the line */
+ return (n);
+ err:
+ *errmsg = errtype;
+ return (-1);
+} /*T_KEY*/
+
+/*
+ * function to invoke DNSSEC specific parsing routines.
+ * this is simpler than copying these complicated blocks into the
+ * multiple souce files that read files (ixfr, nsupdate etc..).
+ * this code should be in a library rather than in this file but
+ * what the heck for now (ogud@tislabs.com)
+ */
+int
+parse_sec_rdata(char *buf, int buf_len, int buf_full, u_char *data,
+ int data_size, FILE *fp, struct zoneinfo *zp,
+ char *domain, u_int32_t ttl, int type, enum context context,
+ enum transport transport, char **errmsg)
+{
+ int ret = -1;
+
+ getmlword_nesting = 0; /* KLUDGE err recov. */
+ if (!buf_full && buf && buf_len != 0) /* check if any data in buf */
+ if (!getmlword(buf, buf_len, fp, 1)) {
+ *errmsg = "unexpected end of input";
+ goto err;
+ }
+
+ switch (type) {
+ case ns_t_sig:
+ ret = parse_sig_rr(buf, buf_len, data, data_size, fp, zp,
+ domain, ttl, context, transport, errmsg);
+ break;
+ case ns_t_key:
+ ret = parse_key_rr(buf, buf_len, data, data_size, fp, zp,
+ domain, context, transport, errmsg);
+ break;
+ case ns_t_nxt:
+ ret = parse_nxt_rr(buf, buf_len, data, data_size, fp, zp,
+ domain, context, transport, errmsg);
+ break;
+ case ns_t_cert:
+ ret = parse_cert_rr(buf, buf_len, data, data_size, fp, errmsg);
+ break;
+ default:
+ ret = -1;
+ *errmsg = "parse_sec_rdata():Unsupported SEC type type";
+ goto err;
+ }
+ return (ret);
+ err:
+ endline(fp);
+ return (ret);
}
-#endif
+
diff --git a/contrib/bind/bin/named/db_lookup.c b/contrib/bind/bin/named/db_lookup.c
index ddf17ad..400523e 100644
--- a/contrib/bind/bin/named/db_lookup.c
+++ b/contrib/bind/bin/named/db_lookup.c
@@ -1,6 +1,6 @@
#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 $";
+static const char sccsid[] = "@(#)db_lookup.c 4.18 (Berkeley) 3/21/91";
+static const char rcsid[] = "$Id: db_lookup.c,v 8.24 1999/10/15 19:48:58 vixie Exp $";
#endif /* not lint */
/*
@@ -57,7 +57,7 @@ static char rcsid[] = "$Id: db_lookup.c,v 8.13 1998/02/13 19:52:54 halley Exp $"
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -82,6 +82,7 @@ static char rcsid[] = "$Id: db_lookup.c,v 8.13 1998/02/13 19:52:54 halley Exp $"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -139,11 +140,7 @@ nlookup(const char *name, struct hashbuf **htpp,
break;
}
- /* rotate left HASHSHIFT */
- hval = (hval << HASHSHIFT) |
- (hval>>((sizeof(hval)*8)-HASHSHIFT));
- hval += ((isascii(c) && isupper(c)) ? tolower(c) : c)
- & HASHMASK;
+ HASHIMILATE(hval, c);
if (escaped)
escaped = 0;
else if (c == '\\')
@@ -186,7 +183,7 @@ nlookup(const char *name, struct hashbuf **htpp,
np->n_next = htp->h_tab[hval];
htp->h_tab[hval] = np;
/* Increase hash table size. */
- if (++htp->h_cnt > htp->h_size * 2) {
+ if (++htp->h_cnt > (htp->h_size * AVGCH_NLOOKUP)) {
*htpp = savehash(htp);
if (parent == NULL) {
if (htp == hashtab) {
@@ -209,12 +206,10 @@ nlookup(const char *name, struct hashbuf **htpp,
* 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
+ * the AXFR wart description in ns_axfr.c
*/
struct namebuf *
-np_parent(np)
- struct namebuf *np;
-{
+np_parent(struct namebuf *np) {
struct hashbuf *htp;
struct namebuf *np2;
@@ -228,19 +223,17 @@ np_parent(np)
/* 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) {
-
+ 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) {
+ for (np = htp->h_tab[0]; np != NULL; 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 */
+ /* there are no RR's with a owner name of "." yet */
+ return (NULL);
}
}
/* Try the hints. */
@@ -248,7 +241,7 @@ np_parent(np)
htp = fcachetab;
goto try_again;
}
- ns_debug(ns_log_db, 1, "np_parent(0x%lx) couldn't namebuf",
+ ns_debug(ns_log_db, 1, "np_parent(0x%lx) couldn't find namebuf",
(u_long)np);
return (NULL); /* XXX shouldn't happen */
}
@@ -263,7 +256,76 @@ 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)
+ if (dp->d_type != type && dp->d_type != T_SIG && type != T_ANY)
+ return (0);
+ if (type != T_SIG && dp->d_type == T_SIG && SIG_COVERS(dp) != type)
return (0);
return (1);
}
+
+/* static int
+ * nxtlower(name, dp)
+ * Is the NXT/SIG NXT record 'lower'?
+ * return value:
+ * boolean
+ */
+static int
+nxtlower(const char *name, struct databuf *dp) {
+ /* An NXT is a lower NXT iff the SOA bit is set in the bitmap */
+ if (dp->d_type == T_NXT) {
+ u_char *nxtbitmap = dp->d_data + strlen((char *)dp->d_data) + 1;
+ return (NS_NXT_BIT_ISSET(T_SOA, nxtbitmap) ? 1 : 0);
+ }
+ /* If it's not an NXT, it's a SIG NXT. An NXT record must be signed
+ * by the zone, so the signer name must be the same as the owner.
+ */
+ return (ns_samename(name, (char *)dp->d_data + SIG_HDR_SIZE) != 1 ? 0 : 1);
+}
+
+/* int
+ * nxtmatch(name, dp1, dp2)
+ * Do NXT/SIG NXT records `dp1' and `dp2' belong to the same NXT set?
+ * return value:
+ * boolean
+ */
+int
+nxtmatch(const char *name, struct databuf *dp1, struct databuf *dp2) {
+ int dp1_lower, dp2_lower;
+
+ if (dp1->d_type != ns_t_nxt || dp2->d_type != ns_t_nxt)
+ return (0);
+ dp1_lower = nxtlower(name, dp1);
+ dp2_lower = nxtlower(name, dp2);
+ return (dp1_lower == dp2_lower);
+}
+
+/* int
+ * rrmatch(name, dp1, dp2)
+ * Do data records `dp1' and `dp2' match in class and type?
+ * If both are NXTs, do they belong in the same NXT set?
+ * If both are SIGs, do the covered types match?
+ * If both are SIG NXTs, do the covered NXTs belong in the same set?
+ * Why is DNSSEC so confusing?
+ * return value:
+ * boolean
+ */
+int
+rrmatch(const char *name, struct databuf *dp1, struct databuf *dp2) {
+ if (dp1->d_class != dp2->d_class &&
+ dp1->d_class != C_ANY && dp2->d_class != C_ANY)
+ return(0);
+ if (dp1->d_type != dp2->d_type &&
+ dp1->d_type != T_ANY && dp2->d_type != T_ANY)
+ return(0);
+ if (dp1->d_type == T_NXT)
+ return(nxtmatch(name, dp1, dp2));
+ if (dp1->d_type != T_SIG)
+ return(1);
+ if (SIG_COVERS(dp1) == SIG_COVERS(dp2)) {
+ if (SIG_COVERS(dp1) == ns_t_nxt)
+ return(nxtmatch(name, dp1, dp2));
+ else
+ return(1);
+ }
+ return(0);
+}
diff --git a/contrib/bind/bin/named/db_save.c b/contrib/bind/bin/named/db_save.c
index a05c40f..c4db46a 100644
--- a/contrib/bind/bin/named/db_save.c
+++ b/contrib/bind/bin/named/db_save.c
@@ -1,6 +1,6 @@
#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 $";
+static const char sccsid[] = "@(#)db_save.c 4.16 (Berkeley) 3/21/91";
+static const char rcsid[] = "$Id: db_save.c,v 8.26 1999/10/13 16:39:02 vixie Exp $";
#endif /* not lint */
/*
@@ -57,7 +57,7 @@ static char rcsid[] = "$Id: db_save.c,v 8.15 1998/01/26 22:40:08 halley Exp $";
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -82,6 +82,7 @@ static char rcsid[] = "$Id: db_save.c,v 8.15 1998/01/26 22:40:08 halley Exp $";
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -136,11 +137,13 @@ savedata(class, type, ttl, data, size)
int size;
{
struct databuf *dp;
- int bytes = (type == T_NS) ? DATASIZE(size)+INT32SZ : DATASIZE(size);
+ int bytes = DATASIZE(size);
dp = (struct databuf *)memget(bytes);
if (dp == NULL)
panic("savedata: memget", NULL);
+ if (class > CLASS_MAX)
+ panic("savedata: bad class", NULL);
memset(dp, 0, bytes);
dp->d_next = NULL;
dp->d_type = type;
@@ -151,6 +154,7 @@ savedata(class, type, ttl, data, size)
dp->d_flags = 0;
dp->d_cred = 0;
dp->d_clev = 0;
+ dp->d_secure = DB_S_INSECURE;
dp->d_rcode = NOERROR;
dp->d_ns = NULL;
dp->d_nstime = 0;
@@ -158,20 +162,6 @@ savedata(class, type, ttl, data, size)
return (dp);
}
-int hashsizes[] = { /* hashtable sizes */
- 2,
- 11,
- 113,
- 337,
- 977,
- 2053,
- 4073,
- 8011,
- 16001,
- 99887,
- 0
-};
-
/*
* Allocate a data buffer & save data.
*/
diff --git a/contrib/bind/bin/named/db_sec.c b/contrib/bind/bin/named/db_sec.c
new file mode 100644
index 0000000..bb31fae
--- /dev/null
+++ b/contrib/bind/bin/named/db_sec.c
@@ -0,0 +1,1097 @@
+
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: db_sec.c,v 8.30 1999/10/15 21:06:49 vixie 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-1999 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/un.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.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 <isc/memcluster.h>
+#include <isc/tree.h>
+
+#include <isc/dst.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+struct zpubkey {
+ struct dst_key *zpk_key; /* Should be DST_KEY */
+ char *zpk_name;
+ struct zpubkey *zpk_next;
+};
+
+typedef struct zpubkey *zpubkey_list;
+
+static int nxt_match_rrset(struct databuf *dp, struct db_rrset *rrset);
+
+/*
+ * A converted databuf is a stripped down databuf after converting the
+ * data to wire format.
+ */
+struct converted_databuf {
+ struct converted_databuf *cd_next;
+ u_char *cd_data;
+ int cd_size, cd_alloc;
+};
+
+/* All of the trusted keys and zone keys */
+static tree *trusted_keys = NULL;
+
+static int
+compare_pubkey (struct zpubkey *zpk1, struct zpubkey *zpk2) {
+ char ta[NS_MAXDNAME], tb[NS_MAXDNAME];
+
+ if (ns_makecanon(zpk1->zpk_name, ta, sizeof ta) < 0 ||
+ ns_makecanon(zpk2->zpk_name, tb, sizeof tb) < 0)
+ return (-1);
+ return (strcasecmp(ta, tb));
+}
+
+static struct zpubkey *
+tree_srch_pubkey (const char *name) {
+ struct zpubkey tkey, *key;
+
+ tkey.zpk_name = (char *) name;
+ if (trusted_keys == NULL) {
+ tree_init(&trusted_keys);
+ return (NULL);
+ }
+ key = (struct zpubkey *)tree_srch(&trusted_keys, compare_pubkey,
+ &tkey);
+ return (key);
+}
+
+static DST_KEY *
+find_public_key (const char *name, u_int16_t key_id) {
+ struct namebuf *knp;
+ struct hashbuf *htp;
+ struct databuf *dp;
+ const char *fname;
+ DST_KEY *key;
+
+ ns_debug(ns_log_default, 5, "find_public_key(%s, %d)", name, key_id);
+
+ htp = hashtab;
+ knp = nlookup (name, &htp, &fname, 0);
+ if (fname != name)
+ /* The name doesn't exist, so there's no key */
+ return (NULL);
+
+ for (dp = knp->n_data; dp != NULL; dp = dp->d_next) {
+ if (dp->d_type != ns_t_key || dp->d_secure < DB_S_SECURE)
+ continue;
+ key = dst_dnskey_to_key(name, dp->d_data, dp->d_size);
+ /* XXX what about multiple keys with same footprint? */
+ if (key) {
+ if (key->dk_id == ntohs(key_id))
+ return (key);
+ else
+ dst_free_key(key);
+ }
+ }
+ return (NULL);
+}
+
+
+static DST_KEY *
+find_trusted_key (const char *name, u_int16_t key_id) {
+ struct zpubkey *zpk;
+ zpubkey_list keylist = tree_srch_pubkey (name);
+
+ ns_debug(ns_log_default, 5, "find_trusted_key(%s, %d)", name, key_id);
+
+ for (zpk = keylist; zpk; zpk = zpk->zpk_next)
+ if (zpk->zpk_key->dk_id == ntohs(key_id))
+ return (zpk->zpk_key);
+
+ return (NULL);
+}
+
+int
+add_trusted_key (const char *name, const int flags, const int proto,
+ const int alg, const char *str)
+{
+ zpubkey_list keylist;
+ struct zpubkey *zpk;
+ u_char buf[1024];
+ int n;
+
+ keylist = tree_srch_pubkey (name);
+
+ zpk = (struct zpubkey *) memget (sizeof (struct zpubkey));
+ if (zpk == NULL)
+ ns_panic(ns_log_default, 1,
+ "add_trusted_key: memget failed(%s)", name);
+ n = b64_pton(str, buf, sizeof(buf));
+ if (n < 0)
+ goto failure;
+ zpk->zpk_key = dst_buffer_to_key(name, alg, flags, proto, buf, n);
+ if (zpk->zpk_key == NULL) {
+ ns_warning(ns_log_default,
+ "add_trusted_key: dst_buffer_to_key(%s) failed",
+ name);
+ goto failure;
+ }
+ zpk->zpk_name = zpk->zpk_key->dk_key_name;
+ zpk->zpk_next = NULL;
+
+ if (keylist == NULL) {
+ if (tree_add (&trusted_keys, compare_pubkey, zpk, NULL) == NULL)
+ goto failure;
+ }
+ else {
+ struct zpubkey *tkey = keylist;
+ while (tkey->zpk_next)
+ tkey = tkey->zpk_next;
+ tkey->zpk_next = zpk;
+ }
+
+ return (1);
+ failure:
+ memput(zpk, sizeof (struct zpubkey));
+ return (0);
+}
+
+/* Can the signer sign records for this name? This is a heuristic. */
+static int
+can_sign(const char *name, const char *signer) {
+ return (ns_samedomain(name, signer) &&
+ dn_count_labels(name) - dn_count_labels(signer) <= 2);
+}
+
+static int
+rrset_set_security(struct db_rrset *rrset, int slev) {
+ struct dnode *dnp;
+
+ for (dnp = rrset->rr_list; dnp != NULL; dnp = dnp->dn_next)
+ dnp->dp->d_secure = slev;
+ for (dnp = rrset->rr_sigs; dnp != NULL; dnp = dnp->dn_next)
+ dnp->dp->d_secure = slev;
+ return (slev);
+}
+
+static int
+convert_databuf(struct databuf *dp, struct converted_databuf *cdp) {
+ u_char *bp = cdp->cd_data;
+ u_char *cp = dp->d_data;
+ u_char *eob = cdp->cd_data + cdp->cd_alloc;
+ int len;
+ u_char buf[MAXDNAME];
+
+ switch (dp->d_type) {
+ case ns_t_soa:
+ case ns_t_minfo:
+ case ns_t_rp:
+ if (eob - bp < strlen((char *)cp) + 1)
+ return (-1);
+ if (ns_name_pton((char *)cp, buf, sizeof buf) < 0)
+ return (-1);
+ len = ns_name_ntol(buf, bp, eob - bp);
+ if (len < 0)
+ return (-1);
+ bp += len;
+ cp += strlen((char *)cp) + 1;
+
+ if (eob - bp < strlen((char *)cp) + 1)
+ return (-1);
+ if (ns_name_pton((char *)cp, buf, sizeof buf) < 0)
+ return (-1);
+ len = ns_name_ntol(buf, bp, eob - bp);
+ if (len < 0)
+ return (-1);
+ bp += len;
+ cp += strlen((char *)cp) + 1;
+
+ if (dp->d_type == ns_t_soa) {
+ if (eob - bp < 5 * INT32SZ)
+ return (-1);
+ memcpy(bp, cp, 5 * INT32SZ);
+ bp += (5 * INT32SZ);
+ cp += (5 * INT32SZ);
+ }
+
+ break;
+
+ case ns_t_ns:
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_ptr:
+ case ns_t_nxt:
+ if (eob - bp < strlen((char *)cp) + 1)
+ return (-1);
+ if (ns_name_pton((char *)cp, buf, sizeof buf) < 0)
+ return (-1);
+ len = ns_name_ntol(buf, bp, eob - bp);
+ if (len < 0)
+ return (-1);
+ bp += len;
+ cp += (len = strlen((char *)cp) + 1);
+
+ if (dp->d_type == ns_t_nxt) {
+ if (eob - bp < dp->d_size - len)
+ return (-1);
+ memcpy(bp, cp, dp->d_size - len);
+ bp += (dp->d_size - len);
+ cp += (dp->d_size - len);
+ }
+ break;
+
+ case ns_t_srv:
+ if (eob - bp < 2 * INT16SZ)
+ return (-1);
+ memcpy(bp, cp, 2 * INT16SZ);
+ bp += (2 * INT16SZ);
+ cp += (2 * INT16SZ);
+ /* no break */
+ case ns_t_rt:
+ case ns_t_mx:
+ case ns_t_afsdb:
+ case ns_t_px:
+ if (eob - bp < INT16SZ)
+ return (-1);
+ memcpy (bp, cp, INT16SZ);
+ bp += INT16SZ;
+ cp += INT16SZ;
+
+ if (eob - bp < strlen((char *)cp) + 1)
+ return (-1);
+ if (ns_name_pton((char *)cp, buf, sizeof buf) < 0)
+ return (-1);
+ len = ns_name_ntol(buf, bp, eob - bp);
+ if (len < 0)
+ return (-1);
+ bp += len;
+ cp += strlen((char *)cp) + 1;
+
+ if (dp->d_type == ns_t_px) {
+ if (eob - bp < strlen((char *)cp) + 1)
+ return (-1);
+ if (ns_name_pton((char *)cp, buf, sizeof buf) < 0)
+ return (-1);
+ len = ns_name_ntol(buf, bp, eob - bp);
+ if (len < 0)
+ return (-1);
+ bp += len;
+ cp += strlen((char *)cp) + 1;
+ }
+ break;
+
+ default:
+ if (eob - bp < dp->d_size)
+ return (-1);
+ memcpy(bp, cp, dp->d_size);
+ bp += dp->d_size;
+ }
+ cdp->cd_size = bp - cdp->cd_data;
+ return (cdp->cd_size);
+}
+
+static int
+digest_rr(char *envelope, int elen, struct converted_databuf *cdp,
+ char *buffer, int blen)
+{
+ char *bp = buffer, *eob = buffer + blen;
+
+ if (eob - bp < elen)
+ return (-1);
+ memcpy (bp, envelope, elen);
+ bp += elen;
+
+ if (eob - bp < INT16SZ)
+ return (-1);
+ PUTSHORT(cdp->cd_size, bp);
+
+ if (eob - bp < cdp->cd_size)
+ return (-1);
+ memcpy (bp, cdp->cd_data, cdp->cd_size);
+ bp += cdp->cd_size;
+
+ return (bp - buffer);
+}
+
+/* Sorts the converted databuf in the list */
+static void
+insert_converted_databuf(struct converted_databuf *cdp,
+ struct converted_databuf **clist)
+{
+ struct converted_databuf *tcdp, *next;
+ int t;
+
+#define compare_cdatabuf(c1, c2, t) \
+ (t = memcmp(c1->cd_data, c2->cd_data, MIN(c1->cd_size, c2->cd_size)), \
+ t == 0 ? c1->cd_size - c2->cd_size : t)
+
+ if (*clist == NULL) {
+ *clist = cdp;
+ return;
+ }
+
+ tcdp = *clist;
+ if (compare_cdatabuf(cdp, tcdp, t) < 0) {
+ cdp->cd_next = tcdp;
+ *clist = cdp;
+ return;
+ }
+
+ next = tcdp->cd_next;
+ while (next) {
+ if (compare_cdatabuf(cdp, next, t) < 0) {
+ cdp->cd_next = next;
+ tcdp->cd_next = cdp;
+ return;
+ }
+ tcdp = next;
+ next = next->cd_next;
+ }
+ tcdp->cd_next = cdp;
+#undef compare_cdatabuf
+}
+
+static void
+free_clist(struct converted_databuf *clist) {
+ struct converted_databuf *cdp;
+
+ while (clist != NULL) {
+ cdp = clist;
+ clist = clist->cd_next;
+ memput(cdp->cd_data, cdp->cd_alloc);
+ memput(cdp, sizeof(struct converted_databuf));
+ }
+}
+
+/* Removes all empty nodes from an rrset's SIG list. */
+static void
+rrset_trim_sigs(struct db_rrset *rrset) {
+ struct dnode *dnp, *odnp, *ndnp;
+
+ odnp = NULL;
+ dnp = rrset->rr_sigs;
+ while (dnp != NULL) {
+ if (dnp->dp != NULL) {
+ odnp = dnp;
+ dnp = dnp->dn_next;
+ }
+ else {
+ if (odnp != NULL)
+ odnp->dn_next = dnp->dn_next;
+ else
+ rrset->rr_sigs = dnp->dn_next;
+ ndnp = dnp->dn_next;
+ memput(dnp, sizeof(struct dnode));
+ dnp = ndnp;
+ }
+ }
+}
+
+int
+verify_set(struct db_rrset *rrset) {
+ DST_KEY *key = NULL;
+ struct sig_record *sigdata;
+ struct dnode *sigdn;
+ struct databuf *sigdp;
+ time_t now;
+ char *signer;
+ u_char name_n[MAXDNAME];
+ u_char *sig, *eom;
+ int trustedkey = 0, siglen, labels, len = 0, ret;
+ u_char *buffer = NULL, *bp;
+ u_char envelope[MAXDNAME+32], *ep;
+ struct dnode *dnp;
+ int bufsize = 2048; /* Large enough for MAXDNAME + SIG_HDR_SIZE */
+ struct converted_databuf *clist = NULL, *cdp;
+ int dnssec_failed = 0, dnssec_succeeded = 0;
+ int return_value;
+ int i;
+
+ if (rrset == NULL || rrset->rr_name == NULL) {
+ ns_warning (ns_log_default, "verify_set: missing rrset/name");
+ return (rrset_set_security(rrset, DB_S_FAILED));
+ }
+
+ if (rrset->rr_sigs == NULL)
+ return (rrset_set_security(rrset, DB_S_INSECURE));
+
+ ns_debug(ns_log_default, 5, "verify_set(%s, %s, %s)", rrset->rr_name,
+ p_type(rrset->rr_type), p_class(rrset->rr_class));
+
+ now = time(NULL);
+
+ for (sigdn = rrset->rr_sigs; sigdn != NULL; sigdn = sigdn->dn_next) {
+ u_int32_t namefield;
+ struct sig_record sigrec;
+
+ sigdp = sigdn->dp;
+
+ eom = sigdp->d_data + sigdp->d_size;
+ if (sigdp->d_size < SIG_HDR_SIZE) {
+ return_value = DB_S_FAILED;
+ goto end;
+ }
+ memcpy(&sigrec, sigdp->d_data, SIG_HDR_SIZE);
+ sigdata = &sigrec;
+ signer = (char *)sigdp->d_data + SIG_HDR_SIZE;
+ sig = (u_char *)signer + strlen(signer) + 1;
+ siglen = eom - sig;
+
+ /*
+ * Don't verify a set if the SIG inception time is in
+ * the future. This should be fixed before 2038 (BEW)
+ */
+ if (ntohl(sigdata->sig_time_n) > now)
+ continue;
+
+ /* An expired set is dropped, but the data is not. */
+ if (ntohl(sigdata->sig_exp_n) < now) {
+ db_freedata(sigdp);
+ sigdn->dp = NULL;
+ continue;
+ }
+
+ /* Cleanup from the last iteration if we continue'd */
+ if (trustedkey == 0 && key != NULL)
+ dst_free_key(key);
+
+ key = find_trusted_key(signer, sigdata->sig_keyid_n);
+
+ if (key == NULL) {
+ trustedkey = 0;
+ key = find_public_key(signer, sigdata->sig_keyid_n);
+ }
+ else
+ trustedkey = 1;
+
+ /* if we don't have the key, either
+ * - the data should be considered insecure
+ * - the sig is not a dnssec signature
+ */
+ if (key == NULL)
+ continue;
+
+ /* Can a key with this name sign the data? */
+ if (!can_sign(rrset->rr_name, signer))
+ continue;
+
+ /* Check the protocol and flags of the key */
+ if (key->dk_proto != NS_KEY_PROT_DNSSEC &&
+ key->dk_proto != NS_KEY_PROT_ANY)
+ continue;
+ if (key->dk_flags & NS_KEY_NO_AUTH)
+ continue;
+ namefield = key->dk_flags & NS_KEY_NAME_TYPE;
+ if (namefield == NS_KEY_NAME_USER ||
+ namefield == NS_KEY_NAME_RESERVED)
+ continue;
+ if (namefield == NS_KEY_NAME_ENTITY &&
+ (key->dk_flags & NS_KEY_SIGNATORYMASK == 0))
+ continue;
+
+ /*
+ * If we're still here, we have a non-null key that's either
+ * a zone key or an entity key with signing authority.
+ */
+
+ if (buffer == NULL) {
+ bp = buffer = memget(bufsize);
+ if (bp == NULL) {
+ return_value = DB_S_FAILED;
+ goto end;
+ }
+ }
+ else
+ bp = buffer;
+
+
+ /* Digest the fixed portion of the SIG record */
+ memcpy(bp, (char *) sigdata, SIG_HDR_SIZE);
+ bp += SIG_HDR_SIZE;
+
+ /* Digest the signer's name, canonicalized */
+ if (ns_name_pton(signer, name_n, sizeof name_n) < 0) {
+ return_value = DB_S_FAILED;
+ goto end;
+ }
+ i = ns_name_ntol(name_n, (u_char *)bp, bufsize - SIG_HDR_SIZE);
+ if (i < 0) {
+ return_value = DB_S_FAILED;
+ goto end;
+ }
+ bp += i;
+
+ /* create the dns record envelope:
+ * <name><type><class><Original TTL>
+ */
+ if (ns_name_pton(rrset->rr_name, name_n, sizeof name_n) < 0 ||
+ ns_name_ntol(name_n, (u_char *)envelope, sizeof envelope) < 0) {
+ return_value = DB_S_FAILED;
+ goto end;
+ }
+
+ labels = dn_count_labels(rrset->rr_name);
+ if (labels > sigdata->sig_labels_n) {
+ ep = envelope;
+ for (i=0; i < (labels - 1 - sigdata->sig_labels_n); i++)
+ ep += (*ep+1);
+ i = dn_skipname(ep, envelope + sizeof envelope);
+ if (i < 0) {
+ return_value = DB_S_FAILED;
+ goto end;
+ }
+ envelope[0] = '\001';
+ envelope[1] = '*';
+ memmove(envelope + 2, ep, i);
+ }
+ i = dn_skipname(envelope, envelope + sizeof envelope);
+ if (i < 0) {
+ return_value = DB_S_FAILED;
+ goto end;
+ }
+ ep = envelope + i;
+ PUTSHORT (rrset->rr_type, ep);
+ PUTSHORT (rrset->rr_class, ep);
+ if (envelope + sizeof(envelope) - ep < INT32SZ) {
+ return_value = DB_S_FAILED;
+ goto end;
+ }
+ memcpy (ep, &sigdata->sig_ottl_n, INT32SZ);
+ ep += INT32SZ;
+
+ if (clist == NULL) {
+ for (dnp = rrset->rr_list;
+ dnp != NULL;
+ dnp = dnp->dn_next)
+ {
+ struct databuf *dp = dnp->dp;
+
+ cdp = memget(sizeof(struct converted_databuf));
+ if (cdp == NULL) {
+ return_value = DB_S_FAILED;
+ goto end;
+ }
+ memset(cdp, 0, sizeof(*cdp));
+ /* Should be large enough... */
+ cdp->cd_alloc = dp->d_size + 8;
+ cdp->cd_data = memget(cdp->cd_alloc);
+ if (cdp->cd_data == NULL) {
+ memput(cdp, sizeof(*cdp));
+ return_value = DB_S_FAILED;
+ goto end;
+ }
+ while (convert_databuf(dp, cdp) < 0) {
+ memput(cdp->cd_data, cdp->cd_alloc);
+ cdp->cd_alloc *= 2;
+ cdp->cd_data = memget(cdp->cd_alloc);
+ if (cdp->cd_data == NULL) {
+ memput(cdp, sizeof(*cdp));
+ return_value = DB_S_FAILED;
+ goto end;
+ }
+ }
+ insert_converted_databuf(cdp, &clist);
+ }
+ }
+
+ for (cdp = clist; cdp != NULL; cdp = cdp->cd_next) {
+ len = digest_rr((char *)envelope, ep-envelope, cdp,
+ (char *)bp, bufsize - (bp - buffer));
+ while (len < 0) {
+ u_char *newbuf;
+
+ /* Double the buffer size */
+ newbuf = memget(bufsize*2);
+ if (newbuf == NULL) {
+ return_value = DB_S_FAILED;
+ goto end;
+ }
+ memcpy(newbuf, buffer, bp - buffer);
+ bp = (bp - buffer) + newbuf;
+ memput(buffer, bufsize);
+ buffer = newbuf;
+ bufsize *= 2;
+
+ len = digest_rr((char *)envelope, ep-envelope,
+ cdp, (char *)bp,
+ bufsize - (bp - buffer));
+ }
+ bp += len;
+ }
+
+ if (len < 0) {
+ return_value = DB_S_FAILED;
+ goto end;
+ }
+
+ ret = dst_verify_data(SIG_MODE_ALL, key, NULL, buffer,
+ bp - buffer, sig, siglen);
+
+ if (ret < 0) {
+ dnssec_failed++;
+ db_freedata(sigdp);
+ sigdn->dp = NULL;
+ }
+ else
+ dnssec_succeeded++;
+ }
+
+end:
+ if (dnssec_failed > 0)
+ rrset_trim_sigs(rrset);
+ if (trustedkey == 0 && key != NULL)
+ dst_free_key(key);
+
+ if (dnssec_failed > 0 && dnssec_succeeded == 0) {
+ ns_warning (ns_log_default,
+ "verify_set(%s, %s, %s) failed",
+ rrset->rr_name, p_type(rrset->rr_type),
+ p_class(rrset->rr_class));
+ return_value = DB_S_FAILED;
+ }
+ else if (dnssec_succeeded > 0)
+ return_value = DB_S_SECURE;
+ else
+ return_value = DB_S_INSECURE;
+ free_clist(clist);
+ if (buffer != NULL)
+ memput(buffer, bufsize);
+ return (rrset_set_security(rrset, return_value));
+}
+
+static void
+rrset_free_partial(struct db_rrset *rrset, int free_data, struct dnode *start) {
+ struct dnode *dnp;
+ int found_start = 0;
+
+ ns_debug(ns_log_default, 5, "rrset_free(%s)", rrset->rr_name);
+
+ if (start == NULL)
+ found_start = 1;
+
+ while (rrset->rr_list) {
+ dnp = rrset->rr_list;
+ if (dnp == start)
+ found_start = 1;
+ rrset->rr_list = rrset->rr_list->dn_next;
+ if (dnp->dp != NULL && free_data == 1 && found_start == 1)
+ db_freedata(dnp->dp);
+ memput(dnp, sizeof(struct dnode));
+ }
+ while (rrset->rr_sigs) {
+ dnp = rrset->rr_sigs;
+ if (dnp == start)
+ found_start = 1;
+ rrset->rr_sigs = rrset->rr_sigs->dn_next;
+ if (dnp->dp != NULL && free_data == 1 && found_start == 1)
+ db_freedata(dnp->dp);
+ memput(dnp, sizeof(struct dnode));
+ }
+}
+
+static void
+rrset_free(struct db_rrset *rrset, int free_data) {
+ rrset_free_partial(rrset, free_data, NULL);
+}
+
+/*
+ * This is called when we have an rrset with SIGs and no other data.
+ * Returns 1 if we either found the necessary data or if the SIG can be added
+ * with no other data. 0 indicates that the SIG cannot be added.
+ */
+static int
+attach_data(struct db_rrset *rrset) {
+ int type, class;
+ struct databuf *dp, *newdp, *sigdp;
+ struct dnode *dnp;
+ struct namebuf *np;
+ struct hashbuf *htp;
+ char *signer;
+ const char *fname;
+ char *name = rrset->rr_name;
+
+ sigdp = rrset->rr_sigs->dp;
+
+ type = SIG_COVERS(sigdp);
+ class = sigdp->d_class;
+ signer = (char *)(sigdp + SIG_HDR_SIZE);
+
+ /* First, see if the signer can sign data for the name. If not,
+ * it's not a DNSSEC signature, so we can insert it with no
+ * corresponding data.
+ */
+ if (!can_sign(name, signer))
+ return (1);
+
+ htp = hashtab;
+ np = nlookup (name, &htp, &fname, 0);
+ if (fname != name)
+ return (0);
+
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (dp->d_type == type && dp->d_class == class) {
+ newdp = savedata(class, type, dp->d_ttl, dp->d_data,
+ dp->d_size);
+ dnp = (struct dnode *) memget (sizeof (struct dnode));
+ if (dnp == NULL)
+ ns_panic(ns_log_default, 1,
+ "attach_data: memget failed");
+ dnp->dp = newdp;
+ dnp->dn_next = rrset->rr_list;
+ rrset->rr_list = dnp;
+ }
+ }
+ if (rrset->rr_list != NULL)
+ return (1);
+ else
+ return (0);
+}
+
+static int
+rrset_db_update(struct db_rrset *rrset, int flags, struct hashbuf **htpp,
+ struct sockaddr_in from, int *rrcount)
+{
+ struct dnode *dnp;
+ struct databuf *dp;
+ int ret;
+
+ /* If we have any unattached SIG records that are DNSSEC signatures,
+ * don't cache them unless we already have the corresponding data.
+ * If we do cache unattached SIGs, we run into problems later if we
+ * have a SIG X and get a query for type X.
+ */
+ if (rrset->rr_list == NULL) {
+ if (attach_data(rrset) == 0) {
+ rrset_free(rrset, 1);
+ return (OK);
+ }
+
+ if (rrset->rr_list != NULL &&
+ verify_set(rrset) == DB_S_FAILED)
+ {
+ rrset_free(rrset, 1);
+ return (OK);
+ }
+ }
+
+ for (dnp = rrset->rr_list; dnp != NULL; dnp = dnp->dn_next) {
+ dp = dnp->dp;
+ ret = db_update(rrset->rr_name, dp, dp, NULL,
+ flags, (*htpp), from);
+ if (ret != OK) {
+ /* XXX Probably should do rollback. */
+ db_err(ret, rrset->rr_name, dp->d_type,
+ dnp->file, dnp->line);
+ if (ret != DATAEXISTS) {
+ rrset_free_partial(rrset, 1, dnp);
+ return (ret);
+ }
+ db_freedata(dp);
+ }
+ if (rrcount != NULL)
+ (*rrcount)++;
+ dnp->dp = NULL;
+ }
+ for (dnp = rrset->rr_sigs; dnp != NULL; dnp = dnp->dn_next) {
+ dp = dnp->dp;
+ if (dp == NULL) /* verifyset() can remove sigs */
+ continue;
+ ret = db_update(rrset->rr_name, dp, dp, NULL,
+ flags, (*htpp), from);
+ if (ret != OK) {
+ /* XXX Probably should do rollback. */
+ db_err(ret, rrset->rr_name, dp->d_type,
+ dnp->file, dnp->line);
+ if (ret != DATAEXISTS) {
+ rrset_free_partial(rrset, 1, dnp);
+ return (ret);
+ }
+ db_freedata(dp);
+ }
+ if (rrcount != NULL)
+ (*rrcount)++;
+ dnp->dp = NULL;
+ }
+ rrset_free(rrset, 0);
+ return (OK);
+}
+
+static int
+rr_in_set(struct databuf *rr, struct dnode *set) {
+ struct dnode *dnp;
+
+ if (set == NULL)
+ return (0);
+
+ for(dnp = set; dnp != NULL; dnp = dnp->dn_next) {
+ if (dnp->dp->d_size == rr->d_size &&
+ memcmp(dnp->dp->d_data, rr->d_data, dnp->dp->d_size) == 0)
+ return (1);
+ }
+ return (0);
+}
+
+static int
+add_to_rrset_list(struct db_rrset **rrsets, char *name, struct databuf *dp,
+ int line, const char *file)
+{
+ struct db_rrset *rrset = *rrsets;
+ struct dnode *dnp;
+
+ while (rrset != NULL) {
+ if (rrset->rr_type != ns_t_nxt || dp->d_type != ns_t_nxt) {
+ if (dp->d_type == ns_t_sig) {
+ if (SIG_COVERS(dp) == rrset->rr_type)
+ break;
+ } else {
+ if (dp->d_type == rrset->rr_type)
+ break;
+ }
+ }
+ else if (nxt_match_rrset(dp, rrset))
+ break;
+ rrset = rrset->rr_next;
+ }
+
+ if (rrset != NULL) {
+ if ((dp->d_type == ns_t_sig && rr_in_set(dp, rrset->rr_sigs)) ||
+ (dp->d_type != ns_t_sig && rr_in_set(dp, rrset->rr_list)))
+ {
+ db_freedata(dp);
+ return (DATAEXISTS);
+ }
+ } else {
+ rrset = (struct db_rrset *) memget(sizeof(struct db_rrset));
+ if (rrset == NULL)
+ ns_panic(ns_log_default, 1,
+ "add_to_rrset_list: memget failed(%s)", name);
+ memset(rrset, 0, sizeof(struct db_rrset));
+ rrset->rr_name = savestr(name, 1);
+ rrset->rr_class = dp->d_class;
+ if (dp->d_type == ns_t_sig)
+ rrset->rr_type = SIG_COVERS(dp);
+ else
+ rrset->rr_type = dp->d_type;
+ rrset->rr_next = *rrsets;
+ *rrsets = rrset;
+ }
+
+ dnp = (struct dnode *) memget(sizeof(struct dnode));
+ if (dnp == NULL)
+ ns_panic(ns_log_default, 1,
+ "add_to_rrset_list: memget failed(%s)", name);
+ memset(dnp, 0, sizeof(struct dnode));
+ dnp->dp = dp;
+ if (dp->d_type == ns_t_sig) {
+ if (rrset->rr_sigs != NULL) {
+ struct dnode *fdnp;
+
+ /* Preserve the order of the RRs */
+ /* Add this one to the end of the list */
+ for (fdnp = rrset->rr_sigs;
+ fdnp->dn_next != NULL;
+ fdnp = fdnp->dn_next)
+ /* NULL */ ;
+ fdnp->dn_next = dnp;
+ } else
+ rrset->rr_sigs = dnp;
+ } else {
+ if (rrset->rr_list != NULL) {
+ struct dnode *fdnp;
+
+ /* Preserve the order of the RRs */
+ /* Add this one to the end of the list */
+ for (fdnp = rrset->rr_list;
+ fdnp->dn_next != NULL;
+ fdnp = fdnp->dn_next)
+ /* NULL */ ;
+ fdnp->dn_next = dnp;
+ } else
+ rrset->rr_list = dnp;
+ }
+ dnp->file = (char *) file;
+ dnp->line = line;
+ return (0);
+}
+
+static int
+update_rrset_list(struct db_rrset **rrsets, int flags, struct hashbuf **htpp,
+ struct sockaddr_in from, int *rrcount)
+{
+ struct db_rrset *rrset = *rrsets, *next = NULL, *last = NULL;
+ int result = 0, tresult, cnameandother = 0;
+
+ while (rrset != NULL) {
+ if (rrset->rr_type == ns_t_key)
+ break;
+ last = rrset;
+ rrset = rrset->rr_next;
+ }
+
+ if (rrset != NULL && last != NULL) {
+ last->rr_next = rrset->rr_next;
+ rrset->rr_next = *rrsets;
+ *rrsets = rrset;
+ }
+
+ rrset = *rrsets;
+
+ while (rrset != NULL) {
+ if (verify_set(rrset) > DB_S_FAILED) {
+ ns_debug(ns_log_default, 10,
+ "update_rrset_list(%s, %s): set verified",
+ rrset->rr_name, p_type(rrset->rr_type));
+ tresult = rrset_db_update(rrset, flags, htpp,
+ from, rrcount);
+ if (tresult == CNAMEANDOTHER)
+ cnameandother++;
+ if (tresult != OK)
+ result = tresult;
+ }
+ else {
+ rrset_free(rrset, 1);
+ result = DNSSECFAIL;
+ }
+ freestr(rrset->rr_name);
+ next = rrset->rr_next;
+ memput(rrset, sizeof(struct db_rrset));
+ rrset = next;
+ }
+ *rrsets = NULL;
+ if (cnameandother != 0)
+ return (CNAMEANDOTHER);
+ return (result);
+}
+
+int
+db_set_update(char *name, struct databuf *dp, void **state,
+ int flags, struct hashbuf **htpp, struct sockaddr_in from,
+ int *rrcount, int line, const char *file)
+{
+ struct db_rrset **rrsets;
+ struct db_rrset *rrset;
+ int result = 0;
+
+ ns_debug(ns_log_default, 5, "db_set_update(%s)",
+ (name == NULL) ? "<NULL>" : (*name == 0) ? "." : name);
+
+ if (state == NULL)
+ ns_panic(ns_log_default, 1,
+ "Called db_set_update with state == NULL");
+
+ rrsets = (struct db_rrset **) state;
+
+ if (*rrsets != NULL) {
+ rrset = *rrsets;
+ if (rrset->rr_name != NULL && dp != NULL &&
+ name != NULL && ns_samename(name, rrset->rr_name) == 1 &&
+ dp->d_class == rrset->rr_class)
+ return (add_to_rrset_list(rrsets, name, dp,
+ line, file));
+ }
+
+ if (*rrsets != NULL)
+ result = update_rrset_list(rrsets, flags, htpp, from, rrcount);
+
+ if (dp != NULL) {
+ ns_debug(ns_log_default, 10,
+ "db_set_update(%s), creating new list", name);
+
+ (void) add_to_rrset_list(rrsets, name, dp, line, file);
+ }
+ return (result);
+}
+
+static int
+nxt_match_rrset(struct databuf *dp, struct db_rrset *rrset) {
+ if (rrset->rr_list != NULL)
+ return (nxtmatch(rrset->rr_name, dp, rrset->rr_list->dp));
+ else
+ return (nxtmatch(rrset->rr_name, dp, rrset->rr_sigs->dp));
+}
diff --git a/contrib/bind/bin/named/db_tsig.c b/contrib/bind/bin/named/db_tsig.c
new file mode 100644
index 0000000..d95031d
--- /dev/null
+++ b/contrib/bind/bin/named/db_tsig.c
@@ -0,0 +1,158 @@
+
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: db_tsig.c,v 8.5 1999/10/15 19:48:59 vixie 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-1999 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/un.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.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 <isc/memcluster.h>
+#include <isc/tree.h>
+
+#include <isc/dst.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+typedef struct {
+ DST_KEY *key;
+ void *ctx;
+} tsig_axfr_state;
+
+#define TSIG_ALG_MD5 "HMAC-MD5.SIG-ALG.REG.INT"
+#define TSIG_ALG_MD5_SHORT "hmac-md5"
+
+char *
+tsig_alg_name(int value) {
+ if (value == KEY_HMAC_MD5)
+ return(TSIG_ALG_MD5);
+ else
+ return(NULL);
+}
+
+int
+tsig_alg_value(char *name) {
+ if (ns_samename(name, TSIG_ALG_MD5) == 1 ||
+ strcasecmp(name, TSIG_ALG_MD5_SHORT) == 0)
+ return (KEY_HMAC_MD5);
+ else
+ return (-1);
+}
+
+DST_KEY *
+tsig_key_from_addr(struct in_addr addr) {
+ server_info si = si = find_server(addr);
+ if (si == NULL || si->key_list == NULL || si->key_list->first == NULL)
+ return(NULL);
+ return(si->key_list->first->key);
+}
+
+struct tsig_record *
+new_tsig(DST_KEY *key, u_char *sig, int siglen) {
+ struct tsig_record *tsig;
+
+ if (siglen > TSIG_SIG_SIZE)
+ return(NULL);
+ tsig = memget(sizeof(struct tsig_record));
+ if (tsig == NULL)
+ return(NULL);
+ tsig->key = key;
+ tsig->siglen = siglen;
+ memcpy(tsig->sig, sig, siglen);
+ return(tsig);
+}
+
+void
+free_tsig(struct tsig_record *tsig) {
+ if (tsig == NULL)
+ return;
+ memput(tsig, sizeof(struct tsig_record));
+}
diff --git a/contrib/bind/bin/named/db_update.c b/contrib/bind/bin/named/db_update.c
index ab70663..ea0176e 100644
--- a/contrib/bind/bin/named/db_update.c
+++ b/contrib/bind/bin/named/db_update.c
@@ -1,6 +1,6 @@
#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 $";
+static const char sccsid[] = "@(#)db_update.c 4.28 (Berkeley) 3/21/91";
+static const char rcsid[] = "$Id: db_update.c,v 8.39 1999/10/15 19:48:59 vixie Exp $";
#endif /* not lint */
/*
@@ -57,7 +57,7 @@ static char rcsid[] = "$Id: db_update.c,v 8.23 1998/02/13 20:01:38 halley Exp $"
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -78,6 +78,7 @@ static char rcsid[] = "$Id: db_update.c,v 8.23 1998/02/13 20:01:38 halley Exp $"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -116,7 +117,7 @@ isRefByNS(const char *name, struct hashbuf *htp) {
dp->d_class == C_HS) &&
dp->d_type == T_NS &&
!dp->d_rcode &&
- !strcasecmp(name, (char *)dp->d_data)) {
+ ns_samename(name, (char *)dp->d_data) == 1) {
return (1);
}
}
@@ -153,21 +154,18 @@ findMyZone(struct namebuf *np, int class) {
* the cache or an authoritative zone, depending).
*/
for (dp = np->n_data; dp; dp = dp->d_next)
- if (match(dp, class, T_SOA))
+ if (match(dp, class, T_SOA) && dp->d_type == 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))
+ if (match(dp, class, T_NS) && dp->d_type == 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?)
- */
+ /* The cache has not yet been primed. */
return (DB_Z_CACHE);
}
@@ -226,12 +224,11 @@ db_update(const char *name,
struct namebuf *np;
int zn, isHintNS;
int check_ttl = 0;
+ int deleted_something = 0;
const char *fname;
#ifdef BIND_UPDATE
- int i, found_other_ns = 0;
+ int 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",
@@ -320,6 +317,7 @@ db_update(const char *name,
dp->d_zone = DB_Z_CACHE;
dp->d_flags = DB_F_HINT;
dp->d_cred = DB_C_CACHE;
+ dp->d_secure = odp->d_secure; /* BEW - this should be ok */
dp->d_clev = 0;
if (db_update(name,
dp, dp, NULL,
@@ -337,7 +335,7 @@ db_update(const char *name,
pdp = NULL;
for (dp = np->n_data; dp != NULL; ) {
- if (!match(dp, odp->d_class, odp->d_type)) {
+ if (!rrmatch(name, dp, odp)) {
/* {class,type} doesn't match. these are
* the aggregation cases.
*/
@@ -368,6 +366,9 @@ db_update(const char *name,
ns_info(ns_log_db,
"%s has CNAME and other data (invalid)",
name);
+ if (zones[odp->d_zone].z_type ==
+ Z_PRIMARY)
+ return (CNAMEANDOTHER);
goto skip;
}
if (!newdp || newdp->d_class != dp->d_class)
@@ -394,7 +395,7 @@ db_update(const char *name,
return (AUTH);
#endif
- /* if the new data is authoritative but
+ /* if the new data is authoritative
* but isn't as credible, reject it.
*/
if (newdp->d_cred == DB_C_ZONE &&
@@ -406,6 +407,11 @@ db_update(const char *name,
* upper zone's file and is therefore
* glue.
*/
+
+ /* BEW/OG: we see no reason to override
+ * these rules with new security based
+ * rules.
+ */
if (newdp->d_clev < dp->d_clev) {
if (!ISVALIDGLUE(newdp)) {
ns_info(ns_log_db,
@@ -431,7 +437,8 @@ db_update(const char *name,
/* process NXDOMAIN */
/* policy */
if (newdp->d_rcode == NXDOMAIN) {
- if (dp->d_cred < DB_C_AUTH)
+ if (dp->d_cred < DB_C_AUTH &&
+ newdp->d_secure >= dp->d_secure)
goto delete;
else
return (DATAEXISTS);
@@ -455,24 +462,37 @@ db_update(const char *name,
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",
+"credibility for %s is %d(%d)(sec %d) from [%s].%d, is %d(%d)(sec %d) in cache",
*name ? name : ".",
newdp->d_cred,
newdp->d_clev,
+ newdp->d_secure,
inet_ntoa(from.sin_addr),
ntohs(from.sin_port),
dp->d_cred,
+ dp->d_secure,
dp->d_clev);
- if (newdp->d_cred > dp->d_cred) {
- /* better credibility.
+ if ((newdp->d_secure > dp->d_secure) ||
+ (newdp->d_secure == dp->d_secure &&
+ (newdp->d_cred > dp->d_cred)))
+ {
+ /* better credibility / security.
* remove the old datum.
*/
goto delete;
}
- if (newdp->d_cred < dp->d_cred) {
- /* credibility is worse. ignore it. */
+ if ((newdp->d_secure < dp->d_secure) ||
+ (newdp->d_secure == dp->d_secure &&
+ (newdp->d_cred < dp->d_cred)))
+ {
+ /* credibility / security is worse.
+ * ignore it.
+ */
return (AUTH);
}
+ /* BEW/OG: from above, we know the security
+ * levels are the same.
+ */
if (newdp->d_cred == DB_C_ZONE &&
dp->d_cred == DB_C_ZONE ) {
/* Both records are from a zone file.
@@ -566,8 +586,19 @@ db_update(const char *name,
INT32SZ + sizeof(u_char)))
goto delete;
if (dp->d_type == T_CNAME &&
- !NS_OPTION_P(OPTION_MULTIPLE_CNAMES))
- goto delete;
+ !NS_OPTION_P(OPTION_MULTIPLE_CNAMES) &&
+ db_cmp(dp, odp) != 0)
+ if ((flags & DB_REPLACE) == 0 &&
+ zones[dp->d_zone].z_type ==
+ Z_PRIMARY) {
+ ns_info(ns_log_db,
+ "%s has multiple CNAMES",
+ name);
+ return (CNAMEANDOTHER);
+ } else
+ goto delete;
+#if 0
+/* BEW - this _seriously_ breaks DNSSEC. Is it necessary for dynamic update? */
#ifdef BIND_UPDATE
if (dp->d_type == T_SIG)
/*
@@ -576,6 +607,20 @@ db_update(const char *name,
*/
goto delete;
#endif
+#endif
+ if (dp->d_type == T_NXT) {
+ goto delete;
+ }
+ if (dp->d_type == T_SIG &&
+ SIG_COVERS(dp) == T_NXT) {
+ struct sig_record *sr1, *sr2;
+
+ sr1 = (struct sig_record *) dp->d_data;
+ sr2 = (struct sig_record *)
+ newdp->d_data;
+ if (sr1->sig_alg_n == sr2->sig_alg_n)
+ goto delete;
+ }
if (check_ttl) {
if (newdp->d_ttl != dp->d_ttl)
ns_warning(ns_log_db,
@@ -621,11 +666,13 @@ db_update(const char *name,
goto skip;
if (odp->d_clev < dp->d_clev)
goto skip;
- if (odp->d_cred < dp->d_cred)
+ if ((odp->d_secure < dp->d_secure) ||
+ ((odp->d_secure == dp->d_secure) &&
+ (odp->d_cred < dp->d_cred)))
goto skip;
#ifdef BIND_UPDATE
- if (!strcasecmp(name, zones[dp->d_zone].z_origin) &&
- !newdp) {
+ if (ns_samename(name, zones[dp->d_zone].z_origin) == 1
+ && newdp == NULL) {
/* do not delete SOA or NS records as a set */
/* XXXRTH isn't testing d_size unnecessary? */
if ((odp->d_size == 0) &&
@@ -677,6 +724,7 @@ db_update(const char *name,
if (savedpp != NULL)
foundRR = 1;
#endif
+ deleted_something = 1;
dp = rm_datum(dp, np, pdp, savedpp);
} else {
skip: pdp = dp;
@@ -690,10 +738,16 @@ db_update(const char *name,
return (NODATA);
}
}
- /* XXX: delete a terminal namebuf also if all databuf's
- * underneath of it have been deleted) */
- if (newdp == NULL)
+ if (newdp == NULL) {
+ if (deleted_something) {
+ while (np->n_data == NULL && np->n_hash == NULL) {
+ np = purge_node(htp, np);
+ if (np == NULL)
+ break;
+ }
+ }
return (OK);
+ }
/* XXX: empty nodes bypass credibility checks above; should check
* response source address here if flags&NOTAUTH.
*/
@@ -790,7 +844,10 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) {
case T_MG:
case T_MR:
/* Only a domain name */
- return (strcasecmp((char *)dp1->d_data, (char *)dp2->d_data));
+ if (ns_samename((char *)dp1->d_data, (char *)dp2->d_data) == 1)
+ return (0);
+ else
+ return (1);
case T_SIG:
/* Binary data, a domain name, more binary data */
@@ -800,8 +857,8 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) {
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))
+ if (ns_samename((char *)dp1->d_data + NS_SIG_SIGNER,
+ (char *)dp2->d_data + NS_SIG_SIGNER) != 1)
return (1);
return (memcmp(dp1->d_data + len,
dp2->d_data + len,
@@ -809,7 +866,7 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) {
case T_NXT:
/* First a domain name, then binary data */
- if (strcasecmp((char *)dp1->d_data, (char *)dp2->d_data))
+ if (ns_samename((char *)dp1->d_data, (char *)dp2->d_data) != 1)
return (1);
len = strlen((char *)dp1->d_data)+1;
return (memcmp(dp1->d_data + len,
@@ -837,14 +894,14 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) {
case T_SOA:
case T_MINFO:
case T_RP:
- if (strcasecmp((char *)dp1->d_data, (char *)dp2->d_data))
+ if (ns_samename((char *)dp1->d_data, (char *)dp2->d_data) != 1)
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))
+ if (ns_samename((char *)cp1, (char *)cp2) != 1)
return (1);
+ if (dp1->d_type != T_SOA)
+ return (0);
cp1 += strlen((char *)cp1) + 1;
cp2 += strlen((char *)cp2) + 1;
return (memcmp(cp1, cp2, INT32SZ * 5));
@@ -907,18 +964,22 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) {
if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* port */
return (1);
}
- return (strcasecmp((char *)cp1, (char *)cp2));
+ if (ns_samename((char *)cp1, (char *)cp2) != 1)
+ return (1);
+ return (0);
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))
+ if (ns_samename((char *)cp1, (char *)cp2) != 1)
return (1);
cp1 += strlen((char *)cp1) + 1;
cp2 += strlen((char *)cp2) + 1;
- return (strcasecmp((char *)cp1, (char *)cp2));
+ if (ns_samename((char *)cp1, (char *)cp2) != 1)
+ return (1);
+ return (0);
case T_TXT:
case T_X25:
diff --git a/contrib/bind/bin/named/named.conf b/contrib/bind/bin/named/named.conf
index ab96666..d423b34 100644
--- a/contrib/bind/bin/named/named.conf
+++ b/contrib/bind/bin/named/named.conf
@@ -42,6 +42,9 @@ options {
// notify on a zone-by-zone
// basis in the "zone" statement
// see (below)
+ max-serial-queries 4; // number of parallel SOA queries
+ // we can have outstanding for master
+ // zone change testing purposes
auth-nxdomain yes; // always set AA on NXDOMAIN.
// don't set this to 'no' unless
// you know what you're doing -- older
@@ -153,6 +156,20 @@ options {
// every 'interface-interval' minutes
statistics-interval 60; // log statistics every
// 'statistics-interval' minutes
+ /*
+ * IXFR options
+ */
+ maintain-ixfr-base no; // If yes, keep transaction log file for IXFR
+ max-ixfr-log-size 20; // Not implemented, maximum size the
+ // IXFR transaction log file to grow
+};
+
+/*
+ * Control listeners, for "ndc". Every nameserver needs at least one.
+ */
+controls {
+ inet * port 52 allow { any; }; // a bad idea
+ unix "/var/run/ndc" perm 0600 owner 0 group 0; // the default
};
zone "master.demo.zone" {
@@ -174,6 +191,7 @@ zone "master.demo.zone" {
zone "slave.demo.zone" {
type slave; // what used to be called "secondary"
file "slave.demo.zone";
+ ixfr-base "slave.demo.zone.ixfr"; // File name for IXFR transaction log file
masters {
1.2.3.4; // where to zone transfer from
5.6.7.8;
@@ -208,8 +226,14 @@ zone "stub.demo.zone" {
zone "." {
type hint; // used to be specified w/ "cache"
file "cache.db";
+ pubkey 257 255 1 "AQP2fHpZ4VMpKo/jc9Fod821uyfY5p8j5h/Am0V/KpBTMZjdXmp9QJe6yFRoIIzkaNCgTIftASdpXGgCwFB2j2KXP/rick6gvEer5VcDEkLR5Q==";
};
+trusted-keys {
+ . 257 255 1 "AQP2fHpZ4VMpKo/jc9Fod821uyfY5p8j5h/Am0V/KpBTMZjdXmp9QJe6yFRoIIzkaNCgTIftASdpXGgCwFB2j2KXP/rick6gvEer5VcDEkLR5Q==";
+};
+
+
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
@@ -226,16 +250,18 @@ zone "non-default-acl.demo.zone" {
};
};
-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 sample_key { // for TSIG
+ algorithm hmac-md5; // hmac-md5 is the supported algorithm
+ secret "abcdefgh"; // base 64 encoded secret
};
key key2 {
algorithm hmac-md5;
- secret "ereh terces rouy";
+ secret "87654321";
};
+acl key_acl { key sample_key; }; // a request signed with sample_key
+
server 1.2.3.4 {
bogus no; // if yes, we won't query or listen
// to this server
@@ -245,9 +271,10 @@ server 1.2.3.4 {
// 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
+ keys { sample_key; key2; }; // for TSIG; sign requests to this
+ // server with this key
+ support-ixfr yes; // for IXFR supported by server
+ // if yes, the listed server talks IXFR
};
logging {
diff --git a/contrib/bind/bin/named/named.h b/contrib/bind/bin/named/named.h
index 57e787b..18f4ac4 100644
--- a/contrib/bind/bin/named/named.h
+++ b/contrib/bind/bin/named/named.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-1999 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
@@ -16,10 +16,10 @@
*/
/*
- * $Id: named.h,v 8.12 1997/12/04 06:52:27 halley Exp $
+ * $Id: named.h,v 8.25 1999/10/13 18:00:19 vixie Exp $
*/
-/* Options. Leave these on. */
+/* Options. Change them at your peril. */
#define DEBUG
#define ADDAUTH
#define STUBS
@@ -30,31 +30,27 @@
#define QRYLOG
#define YPKLUDGE
#define RENICE
-#define FORCED_RELOAD
#define SLAVE_FORWARD
-#define BIND_UPDATE
+#define BIND_IXFR
#define BIND_NOTIFY
+#define BIND_UPDATE
#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
+#define STRICT_RFC2308
+#undef BIND_ZXFR
#include <isc/assertions.h>
#include <isc/list.h>
+#include <isc/ctl.h>
+
+#include <res_update.h>
#include "pathnames.h"
diff --git a/contrib/bind/bin/named/ns_config.c b/contrib/bind/bin/named/ns_config.c
index 4f95410..67bffbd 100644
--- a/contrib/bind/bin/named/ns_config.c
+++ b/contrib/bind/bin/named/ns_config.c
@@ -1,9 +1,9 @@
#if !defined(lint) && !defined(SABER)
-static char rcsid[] = "$Id: ns_config.c,v 8.35 1998/05/05 19:44:48 halley Exp $";
+static const char rcsid[] = "$Id: ns_config.c,v 8.104 1999/11/08 23:09:42 vixie Exp $";
#endif /* not lint */
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-1999 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
@@ -19,12 +19,33 @@ static char rcsid[] = "$Id: ns_config.c,v 8.35 1998/05/05 19:44:48 halley Exp $"
* SOFTWARE.
*/
+/*
+ * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc.
+ *
+ * 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 Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES
+ * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED
+ * 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 <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -46,6 +67,8 @@ static char rcsid[] = "$Id: ns_config.c,v 8.35 1998/05/05 19:44:48 halley Exp $"
#include <isc/logging.h>
#include <isc/memcluster.h>
+#include <isc/dst.h>
+
#include "port_after.h"
#ifdef HAVE_GETRUSAGE /* XXX */
@@ -55,6 +78,8 @@ static char rcsid[] = "$Id: ns_config.c,v 8.35 1998/05/05 19:44:48 halley Exp $"
#include "named.h"
#include "ns_parseutil.h"
+/* Private. */
+
static int tmpnum = 0;
static int config_initialized = 0;
@@ -90,8 +115,7 @@ 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);
+ undefine_symbol(zone_symbol_table, zp->z_origin, zp->z_class);
if (zp->z_flags & Z_TIMER_SET) {
free_zone_timerinfo(zp);
if (evClearTimer(ev, zp->z_timer) < 0)
@@ -102,22 +126,44 @@ free_zone_contents(struct zoneinfo *zp, int undefine_sym) {
}
if (zp->z_origin != NULL)
freestr(zp->z_origin);
+ zp->z_origin = NULL;
if (zp->z_source != NULL)
freestr(zp->z_source);
+ zp->z_source = NULL;
+ if (zp->z_ixfr_base != NULL)
+ freestr(zp->z_ixfr_base);
+ zp->z_ixfr_base = NULL;
+ if (zp->z_ixfr_tmp != NULL)
+ freestr(zp->z_ixfr_tmp);
+ zp->z_ixfr_tmp = NULL;
if (zp->z_update_acl != NULL)
free_ip_match_list(zp->z_update_acl);
+ zp->z_update_acl = NULL;
if (zp->z_query_acl != NULL)
free_ip_match_list(zp->z_query_acl);
+ zp->z_query_acl = NULL;
if (zp->z_transfer_acl != NULL)
free_ip_match_list(zp->z_transfer_acl);
+ zp->z_transfer_acl = NULL;
#ifdef BIND_UPDATE
if (zp->z_updatelog != NULL)
freestr(zp->z_updatelog);
+ zp->z_updatelog = NULL;
#endif /* BIND_UPDATE */
+#ifdef BIND_NOTIFY
+ if (zp->z_also_notify != NULL)
+ memput(zp->z_also_notify,
+ zp->z_notify_count * sizeof *zp->z_also_notify);
+ zp->z_also_notify = NULL;
+#endif
+ block_signals();
+ if (LINKED(zp, z_reloadlink))
+ UNLINK(reloadingzones, zp, z_reloadlink);
+ unblock_signals();
}
static void
-free_zone(struct zoneinfo *zp) {
+release_zone(struct zoneinfo *zp) {
INSIST(zp != NULL);
free_zone_contents(zp, 0);
@@ -125,16 +171,16 @@ free_zone(struct zoneinfo *zp) {
}
struct zoneinfo *
-find_zone(const char *name, int type, int class) {
+find_zone(const char *name, 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)) {
+ ns_debug(ns_log_config, 3, "find_zone(%s, %d)",
+ *name ? name : ".", class);
+ if (lookup_symbol(zone_symbol_table, name, class, &value)) {
INSIST(value.integer >= 0 && value.integer < nzones);
- ns_debug(ns_log_config, 3,
- "find_zone: existing zone %d", value.integer);
+ ns_debug(ns_log_config, 3, "find_zone: existing zone %d",
+ value.integer);
zp = &zones[value.integer];
return (zp);
}
@@ -146,33 +192,11 @@ 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++];
+ if (EMPTY(freezones))
+ make_new_zones();
+ zp = HEAD(freezones);
+ UNLINK(freezones, zp, z_freelink);
return (zp);
}
@@ -181,7 +205,6 @@ new_zone(int class, int type) {
*/
static int
validate_zone(struct zoneinfo *zp) {
- int warnings = 0;
char filename[MAXPATHLEN+1];
/* Check name */
@@ -204,7 +227,13 @@ validate_zone(struct zoneinfo *zp) {
zp->z_origin);
return (0);
}
- if (zp->z_type == z_hint && strcasecmp(zp->z_origin, "") != 0) {
+ if (zp->z_type == z_cache && ns_samename(zp->z_origin, "") != 1) {
+ ns_error(ns_log_config,
+ "only the root zone may be a cache zone (zone '%s')",
+ zp->z_origin);
+ return (0);
+ }
+ if (zp->z_type == z_hint && ns_samename(zp->z_origin, "") != 1) {
ns_error(ns_log_config,
"only the root zone may be a hint zone (zone '%s')",
zp->z_origin);
@@ -229,12 +258,25 @@ validate_zone(struct zoneinfo *zp) {
return (0);
}
+ if (zp->z_ixfr_base != NULL && strlen(zp->z_ixfr_base) > MAXPATHLEN) {
+ ns_error(ns_log_config, "ixfr filename too long for zone '%s'",
+ zp->z_origin);
+ return (0);
+ }
+ if (zp->z_ixfr_tmp != NULL && strlen(zp->z_ixfr_tmp) > MAXPATHLEN) {
+ ns_error(ns_log_config, "tmp ixfr 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) {
+ if (zp->z_type == z_master || zp->z_type == z_hint ||
+ zp->z_type == z_cache) {
ns_error(ns_log_config,
"'masters' statement present for %s zone '%s'",
- (zp->z_type == z_master) ? "master" : "hint",
+ (zp->z_type == z_master) ? "master" :
+ (zp->z_type == z_hint) ? "hint" : "cache",
zp->z_origin);
return (0);
}
@@ -247,6 +289,39 @@ validate_zone(struct zoneinfo *zp) {
}
}
+ /* Check allow-update and allow-transfer. */
+ if (zp->z_update_acl || zp->z_transfer_acl) {
+ if (zp->z_type != z_master && zp->z_type != z_slave) {
+ ns_error(ns_log_config,
+ "'allow-{update,transfer}' option for non-{master,slave} zone '%s'",
+ zp->z_origin);
+ return (0);
+ }
+ }
+
+ /* Check allow-query. */
+ if (zp->z_query_acl) {
+ if (zp->z_type != z_master &&
+ zp->z_type != z_slave &&
+ zp->z_type != z_stub) {
+ ns_error(ns_log_config,
+ "'allow-query' option for non-{master,slave,stub} zone '%s'",
+ zp->z_origin);
+ return (0);
+ }
+ }
+
+#ifdef BIND_NOTIFY
+ /* Check notify */
+ if (zp->z_notify != znotify_use_default) {
+ if (zp->z_type != z_master && zp->z_type != z_slave) {
+ ns_error(ns_log_config,
+ "'notify' given for non-master, non-slave 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) {
@@ -256,9 +331,43 @@ validate_zone(struct zoneinfo *zp) {
return (0);
}
}
+#endif
#ifdef BIND_UPDATE
/* XXX need more checking here */
+ if (!zp->z_updatelog && zp->z_source) {
+ /* 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);
+ }
+
+ /* Check forward */
+ if (zp->z_optset & OPTION_FORWARD_ONLY) {
+ if (zp->z_type == z_hint) {
+ ns_error(ns_log_config,
+ "'forward' given for hint zone '%s'",
+ zp->z_origin);
+ return (0);
+ }
+ }
+ /* Check forwarders */
+ if (zp->z_fwdtab) {
+ if (zp->z_type == z_hint) {
+ ns_error(ns_log_config,
+ "'forwarders' given for hint zone '%s'",
+ zp->z_origin);
+ return (0);
+ }
+ }
+
if (zp->z_type == z_master) {
if (!zp->z_soaincrintvl)
zp->z_soaincrintvl = SOAINCRINTVL;
@@ -266,22 +375,36 @@ validate_zone(struct zoneinfo *zp) {
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 */
+ if (!zp->z_ixfr_base && zp->z_source) {
+ /* XXX OS-specific filename validation here */
+ if ((strlen(zp->z_source) + (sizeof ".ixfr" - 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.ixfr", zp->z_source);
+ zp->z_ixfr_base = savestr(filename, 1);
+ }
+ if (!zp->z_ixfr_tmp && zp->z_source) {
+ /* XXX OS-specific filename validation here */
+ if ((strlen(zp->z_source) + (sizeof ".ixfr.tmp" - 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.ixfr.tmp", zp->z_source);
+ zp->z_ixfr_tmp = savestr(filename, 1);
+ }
+
return (1);
}
@@ -308,6 +431,12 @@ begin_zone(char *name, int class) {
zp->z_origin = name;
zp->z_class = class;
zp->z_checknames = not_set;
+ zp->z_log_size_ixfr = 0;
+ if (server_options->flags & OPTION_MAINTAIN_IXFR_BASE)
+ zp->z_maintain_ixfr_base = 1;
+ else
+ zp->z_maintain_ixfr_base = 0;
+ zp->z_max_log_size_ixfr = server_options->max_log_size_ixfr;
zh.opaque = zp;
return (zh);
}
@@ -318,7 +447,6 @@ begin_zone(char *name, int class) {
*/
static void
update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) {
- struct stat f_time;
char buf[MAXPATHLEN+1];
int i;
@@ -337,7 +465,7 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) {
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);
+ (void) zonedump(zp, ISNOTIXFR);
#endif
/*
@@ -348,6 +476,9 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) {
freestr(zp->z_origin);
zp->z_origin = new_zp->z_origin;
new_zp->z_origin = NULL;
+ zp->z_maintain_ixfr_base = new_zp->z_maintain_ixfr_base;
+ zp->z_max_log_size_ixfr = new_zp->z_max_log_size_ixfr;
+ zp->z_log_size_ixfr = new_zp->z_log_size_ixfr;
zp->z_class = new_zp->z_class;
zp->z_type = new_zp->z_type;
zp->z_checknames = new_zp->z_checknames;
@@ -368,11 +499,28 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) {
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;
-
+#ifdef BIND_NOTIFY
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];
+ if (zp->z_also_notify)
+ memput(zp->z_also_notify,
+ zp->z_notify_count * sizeof *zp->z_also_notify);
+ zp->z_also_notify = new_zp->z_also_notify;
zp->z_notify_count = new_zp->z_notify_count;
+ new_zp->z_also_notify = NULL;
+ new_zp->z_notify_count = 0;
+#endif
+ if ((new_zp->z_flags & Z_FORWARD_SET) != 0)
+ zp->z_flags |= Z_FORWARD_SET;
+ else
+ zp->z_flags &= ~Z_FORWARD_SET;
+ if (zp->z_fwdtab != NULL)
+ free_forwarders(zp->z_fwdtab);
+ zp->z_fwdtab = new_zp->z_fwdtab;
+ new_zp->z_fwdtab = NULL;
+
+ zp->z_dialup = new_zp->z_dialup;
+ zp->z_options = new_zp->z_options;
+ zp->z_optset = new_zp->z_optset;
#ifdef BIND_UPDATE
if (new_zp->z_flags & Z_DYNAMIC)
@@ -387,24 +535,21 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) {
zp->z_updatelog = new_zp->z_updatelog;
new_zp->z_updatelog = NULL;
#endif /* BIND_UPDATE */
+ zp->z_port = new_zp->z_port;
/*
- * now deal with files
+ * Now deal with files.
*/
switch (zp->z_type) {
+ case z_cache:
+ ns_panic(ns_log_config, 1, "impossible condition");
+ break;
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) {
+ if (zp->z_source != NULL &&
+ strcmp(new_zp->z_source, zp->z_source) == 0 &&
+ (reconfiging || !zonefile_changed_p(zp))) {
ns_debug(ns_log_config, 1, "cache is up to date");
break;
}
@@ -412,28 +557,37 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) {
/* File has changed, or hasn't been loaded yet. */
if (zp->z_source) {
freestr(zp->z_source);
- clean_cache(fcachetab, 1);
+ purge_zone(zp->z_origin, fcachetab, zp->z_class);
}
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);
+
+ if (zp->z_ixfr_base)
+ freestr(zp->z_ixfr_base);
+ zp->z_ixfr_base = new_zp->z_ixfr_base;
+ new_zp->z_ixfr_base = NULL;
+
+ if (zp->z_ixfr_tmp)
+ freestr(zp->z_ixfr_tmp);
+ zp->z_ixfr_tmp = new_zp->z_ixfr_tmp;
+ new_zp->z_ixfr_tmp = NULL;
+
+ ns_debug(ns_log_config, 1, "reloading hint zone");
+ (void) db_load(zp->z_source, zp->z_origin, zp, NULL,
+ ISNOTIXFR);
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,
+ * If we've loaded this file, and the file hasn't changed
* 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) {
+ if (zp->z_source != NULL &&
+ strcmp(new_zp->z_source, zp->z_source) == 0 &&
+ (reconfiging || !zonefile_changed_p(zp))) {
ns_debug(ns_log_config, 1, "zone is up to date");
- break; /* zone is already up to date */
+ break;
}
#ifdef BIND_UPDATE
if (zp->z_source && (zp->z_flags & Z_DYNAMIC))
@@ -447,41 +601,27 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) {
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)
+ if (zp->z_ixfr_base != NULL)
+ freestr(zp->z_ixfr_base);
+ zp->z_ixfr_base = new_zp->z_ixfr_base;
+ new_zp->z_ixfr_base = NULL;
+
+ if (zp->z_ixfr_tmp != NULL)
+ freestr(zp->z_ixfr_tmp);
+ zp->z_ixfr_tmp = new_zp->z_ixfr_tmp;
+ new_zp->z_ixfr_tmp = NULL;
+
+ if (reload_master(zp) == 1) {
/*
* 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
+ new_zp->z_source = savestr(zp->z_source, 1);
+ new_zp->z_ixfr_base = savestr(zp->z_ixfr_base, 1);
+ new_zp->z_ixfr_tmp = savestr(zp->z_ixfr_tmp, 1);
+ goto primary_reload;
+ }
break;
case z_slave:
@@ -505,10 +645,9 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) {
* 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)))) {
+ if (zp->z_source != NULL &&
+ (strcmp(new_zp->z_source, zp->z_source) != 0 ||
+ ((!reconfiging) && zonefile_changed_p(zp)))) {
ns_debug(ns_log_config, 1,
"backup file changed or missing");
freestr(zp->z_source);
@@ -516,42 +655,60 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) {
zp->z_serial = 0; /* force xfer */
ns_stopxfrs(zp);
/*
- * We only need to do_reload if we have
+ * We only need to reload if we have ever
* successfully transferred the zone.
*/
- if (zp->z_flags & Z_AUTH) {
+ if ((zp->z_flags & Z_AUTH) != 0) {
zp->z_flags &= ~Z_AUTH;
/*
- * Purge old data and reload parent so that
- * NS records are present during the zone
- * transfer.
+ * Purge old data and mark the parent for
+ * reloading so that NS records are present
+ * during the zone transfer.
*/
do_reload(zp->z_origin, zp->z_type,
- zp->z_class);
+ zp->z_class, 1);
}
}
if (zp->z_source == NULL) {
zp->z_source = new_zp->z_source;
new_zp->z_source = NULL;
}
- if (!(zp->z_flags & Z_AUTH))
+
+ if (zp->z_ixfr_base != NULL)
+ freestr(zp->z_ixfr_base);
+ zp->z_ixfr_base = new_zp->z_ixfr_base;
+ new_zp->z_ixfr_base = NULL;
+
+ if (zp->z_ixfr_tmp != NULL)
+ freestr(zp->z_ixfr_tmp);
+ zp->z_ixfr_tmp = new_zp->z_ixfr_tmp;
+ new_zp->z_ixfr_tmp = NULL;
+
+ if ((zp->z_flags & Z_AUTH) == 0)
zoneinit(zp);
-#ifdef FORCED_RELOAD
else {
/*
** Force secondary to try transfer soon
** after SIGHUP.
*/
- if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))
- && reloading) {
+ if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0 &&
+ reloading && !reconfiging) {
qserial_retrytime(zp, tt.tv_sec);
sched_zone_maint(zp);
}
}
-#endif /* FORCED_RELOAD */
+ break;
+ case z_forward:
+ /*
+ * We don't know if the forwarder's list has changed
+ * so just purge the cache. In the future we may want
+ * see if the forwarders list has changed and only
+ * do this then.
+ */
+ clean_cache_from(zp->z_origin, hashtab);
break;
}
- if ((zp->z_flags & Z_FOUND) && /* already found? */
+ if ((zp->z_flags & Z_FOUND) != 0 && /* 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);
@@ -582,40 +739,43 @@ end_zone(zone_config zh, int should_install) {
should_install);
if (!should_install) {
- free_zone(new_zp);
+ release_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);
+ release_zone(new_zp);
return;
}
- zp = find_zone(new_zp->z_origin, new_zp->z_type, new_zp->z_class);
+ zp = find_zone(new_zp->z_origin, new_zp->z_class);
+ if (zp != NULL && zp->z_type != new_zp->z_type) {
+ remove_zone(zp, "redefined");
+ zp = NULL;
+ }
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);
+ 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) {
+ if (new_zp->z_addrcnt != 0) {
int i;
ns_debug(ns_log_config, 5, " masters:");
- for (i=0; i<new_zp->z_addrcnt; i++)
+ 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);
+ release_zone(new_zp);
zh.opaque = NULL;
}
@@ -662,7 +822,63 @@ set_zone_checknames(zone_config zh, enum severity s) {
}
int
+set_zone_ixfr_file(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_ixfr_base != NULL)
+ return (0);
+ zp->z_ixfr_base = filename;
+ if (zp->z_ixfr_tmp == NULL) {
+ int len = strlen(zp->z_ixfr_base) + (sizeof ".tmp" - 1);
+ char *str = (char *) memget(len);
+
+ sprintf(str, "%s.tmp", zp->z_ixfr_base);
+ zp->z_ixfr_tmp = savestr(str, 1);
+ memput(str, len);
+ }
+
+ return (1);
+}
+
+int
+set_zone_ixfr_tmp(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_ixfr_tmp != NULL)
+ return (0);
+ zp->z_ixfr_tmp = filename;
+ return (1);
+}
+
+int
+set_zone_dialup(zone_config zh, int value) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ if (value) {
+ zp->z_dialup = zdialup_yes;
+#ifdef BIND_NOTIFY
+ zp->z_notify = znotify_yes;
+#endif
+ } else
+ zp->z_dialup = zdialup_no;
+
+ return (1);
+}
+
+int
set_zone_notify(zone_config zh, int value) {
+#ifdef BIND_NOTIFY
struct zoneinfo *zp;
zp = zh.opaque;
@@ -672,6 +888,17 @@ set_zone_notify(zone_config zh, int value) {
zp->z_notify = znotify_yes;
else
zp->z_notify = znotify_no;
+#endif
+ return (1);
+}
+
+int
+set_zone_maintain_ixfr_base(zone_config zh, int value) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+ zp->z_maintain_ixfr_base = value;
return (1);
}
@@ -683,7 +910,7 @@ set_zone_update_acl(zone_config zh, ip_match_list iml) {
zp = zh.opaque;
INSIST(zp != NULL);
- /* Fail if checknames already set for this zone */
+ /* Fail if update_acl already set for this zone */
if (zp->z_update_acl != NULL)
return (0);
zp->z_update_acl = iml;
@@ -712,6 +939,14 @@ set_zone_query_acl(zone_config zh, ip_match_list iml) {
}
int
+set_zone_master_port(zone_config zh, u_short port) {
+ struct zoneinfo *zp = zh.opaque;
+
+ zp->z_port = port;
+ return (1);
+}
+
+int
set_zone_transfer_source(zone_config zh, struct in_addr ina) {
struct zoneinfo *zp = zh.opaque;
@@ -748,6 +983,37 @@ set_zone_transfer_time_in(zone_config zh, long max_time) {
}
int
+set_zone_max_log_size_ixfr(zone_config zh, int size) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ zp->z_max_log_size_ixfr = size;
+ return (0);
+}
+
+int
+set_zone_pubkey(zone_config zh, const int flags, const int proto,
+ const int alg, const char *str)
+{
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ INSIST(zp != NULL && zp->z_origin != NULL);
+ return (add_trusted_key(zp->z_origin, flags, proto, alg, str));
+}
+
+int
+set_trusted_key(const char *name, const int flags, const int proto,
+ const int alg, const char *str) {
+ INSIST(name != NULL);
+ return (add_trusted_key(name, flags, proto, alg, str));
+}
+
+int
add_zone_master(zone_config zh, struct in_addr address) {
struct zoneinfo *zp;
@@ -766,18 +1032,51 @@ add_zone_master(zone_config zh, struct in_addr address) {
int
add_zone_notify(zone_config zh, struct in_addr address) {
+#ifdef BIND_NOTIFY
struct zoneinfo *zp;
+ int i;
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;
+ /* Check for duplicates. */
+
+ for (i = 0; i < zp->z_notify_count; i++) {
+ if (memcmp(zp->z_also_notify + i,
+ &address, sizeof address) == 0) {
+ ns_warning(ns_log_config,
+ "duplicate also-notify address ignored [%s] for zone '%s'",
+ inet_ntoa(address), zp->z_origin);
+ return (1);
+ }
}
+ i = 0;
+
+ if (zp->z_also_notify == NULL) {
+ zp->z_also_notify = memget(sizeof *zp->z_also_notify);
+ if (zp->z_also_notify == NULL)
+ i = 1;
+ } else {
+ register size_t size;
+ register struct in_addr *an_tmp;
+ size = zp->z_notify_count * sizeof *zp->z_also_notify;
+ an_tmp = memget(size + sizeof *zp->z_also_notify);
+ if (an_tmp == NULL) {
+ i = 1;
+ } else {
+ memcpy(an_tmp, zp->z_also_notify, size);
+ memput(zp->z_also_notify, size);
+ zp->z_also_notify = an_tmp;
+ }
+ }
+ if (i == 0) {
+ zp->z_also_notify[zp->z_notify_count] = address;
+ zp->z_notify_count++;
+ } else {
+ ns_warning(ns_log_config, "also-notify add failed (memget) [%s] for zone '%s'",
+ inet_ntoa(address), zp->z_origin);
+ }
+#endif
return (1);
}
@@ -786,13 +1085,12 @@ add_zone_notify(zone_config zh, struct in_addr address) {
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->version = savestr(ShortVersion, 1);
op->directory = savestr(".", 1);
op->pid_filename = savestr(_PATH_PIDFILE, 1);
op->named_xfer = savestr(_PATH_XFER, 1);
@@ -803,21 +1101,24 @@ new_options() {
op->transfers_in = DEFAULT_XFERS_RUNNING;
op->transfers_per_ns = DEFAULT_XFERS_PER_NS;
op->transfers_out = 0;
+ op->serial_queries = MAXQSERIAL;
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->axfr_src.s_addr = 0;
+#ifdef BIND_NOTIFY
+ op->notify_count = 0;
+ op->also_notify = NULL;
+#endif
+ op->blackhole_acl = NULL;
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->recursion_acl = NULL;
+ op->sortlist = NULL;
+ op->topology = NULL;
op->data_size = 0UL; /* use system default */
op->stack_size = 0UL; /* use system default */
op->core_size = 0UL; /* use system default */
@@ -831,6 +1132,12 @@ new_options() {
op->clean_interval = 3600;
op->interface_interval = 3600;
op->stats_interval = 3600;
+ op->ordering = NULL;
+ op->max_ncache_ttl = DEFAULT_MAX_NCACHE_TTL;
+ op->lame_ttl = NTTL;
+ op->heartbeat_interval = 3600;
+ op->max_log_size_ixfr = 20;
+ op->minroots = MINROOTS;
return (op);
}
@@ -838,6 +1145,8 @@ void
free_options(options op) {
INSIST(op != NULL);
+ if (op->version)
+ freestr(op->version);
if (op->directory)
freestr(op->directory);
if (op->pid_filename)
@@ -850,10 +1159,22 @@ free_options(options op) {
freestr(op->stats_filename);
if (op->memstats_filename)
freestr(op->memstats_filename);
+#ifdef BIND_NOTIFY
+ if (op->also_notify)
+ free_also_notify(op);
+#endif
+ if (op->blackhole_acl)
+ free_ip_match_list(op->blackhole_acl);
if (op->query_acl)
free_ip_match_list(op->query_acl);
+ if (op->recursion_acl)
+ free_ip_match_list(op->recursion_acl);
if (op->transfer_acl)
free_ip_match_list(op->transfer_acl);
+ if (op->sortlist)
+ free_ip_match_list(op->sortlist);
+ if (op->ordering)
+ free_rrset_order_list(op->ordering);
if (op->topology)
free_ip_match_list(op->topology);
if (op->listen_list)
@@ -863,9 +1184,9 @@ free_options(options op) {
memput(op, sizeof *op);
}
-void
-set_boolean_option(options op, int bool_opt, int value) {
- INSIST(op != NULL);
+static void
+set_boolean_option(u_int *op_flags, int bool_opt, int value) {
+ INSIST(op_flags != NULL);
switch (bool_opt) {
case OPTION_NORECURSE:
@@ -875,18 +1196,45 @@ set_boolean_option(options op, int bool_opt, int value) {
case OPTION_NONOTIFY:
case OPTION_NONAUTH_NXDOMAIN:
case OPTION_MULTIPLE_CNAMES:
+ case OPTION_USE_IXFR:
+ case OPTION_MAINTAIN_IXFR_BASE:
case OPTION_HOSTSTATS:
case OPTION_DEALLOC_ON_EXIT:
+ case OPTION_USE_ID_POOL:
+ case OPTION_NORFC2308_TYPE1:
+ case OPTION_NODIALUP:
+ case OPTION_TREAT_CR_AS_SPACE:
if (value)
- op->flags |= bool_opt;
+ *op_flags |= bool_opt;
else
- op->flags &= ~bool_opt;
+ *op_flags &= ~bool_opt;
break;
default:
panic("unexpected option in set_boolean_option", NULL);
}
}
+void
+set_global_boolean_option(options op, int bool_opt, int value) {
+
+ INSIST(op != NULL);
+
+ set_boolean_option(&op->flags, bool_opt, value);
+}
+
+void
+set_zone_boolean_option(zone_config zh, int bool_opt, int value) {
+ struct zoneinfo *zp;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ set_boolean_option(&zp->z_options, bool_opt, value);
+
+ /* Flag that zone option overrides corresponding global option */
+ zp->z_optset |= bool_opt;
+}
+
#ifdef HAVE_GETRUSAGE
enum limit { Datasize, Stacksize, Coresize, Files };
@@ -897,6 +1245,8 @@ static struct rlimit initial_num_files;
static void
get_initial_limits() {
+ int fdlimit = evHighestFD(ev) + 1;
+
# ifdef RLIMIT_DATA
if (getrlimit(RLIMIT_DATA, &initial_data_size) < 0)
ns_warning(ns_log_config, "getrlimit(DATA): %s",
@@ -916,6 +1266,19 @@ get_initial_limits() {
if (getrlimit(RLIMIT_NOFILE, &initial_num_files) < 0)
ns_warning(ns_log_config, "getrlimit(NOFILE): %s",
strerror(errno));
+ else if (initial_num_files.rlim_cur > fdlimit) {
+ initial_num_files.rlim_cur = fdlimit;
+ if (initial_num_files.rlim_cur > initial_num_files.rlim_max)
+ initial_num_files.rlim_max = fdlimit;
+ if (setrlimit(RLIMIT_NOFILE, &initial_num_files) < 0) {
+ ns_warning(ns_log_config, "setrlimit(files): %s",
+ strerror(errno));
+ } else {
+ ns_warning(ns_log_config,
+ "limit files set to fdlimit (%d)",
+ fdlimit);
+ }
+ }
# endif
}
@@ -923,13 +1286,14 @@ static void
ns_rlimit(enum limit limit, u_long limit_value) {
struct rlimit limits, old_limits;
int rlimit = -1;
+ int fdlimit = evHighestFD(ev) + 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),
+ value = MIN((rlimit_type)evHighestFD(ev) + 1,
initial_num_files.rlim_max);
else
#endif
@@ -970,7 +1334,8 @@ ns_rlimit(enum limit limit, u_long limit_value) {
name = "max number of open files";
if (value == 0)
limits = initial_num_files;
- /* XXX check < FD_SETSIZE? */
+ if (value > fdlimit)
+ limits.rlim_cur = limits.rlim_max = value = fdlimit;
break;
default:
name = NULL; /* Make gcc happy. */
@@ -994,8 +1359,7 @@ ns_rlimit(enum limit limit, u_long limit_value) {
return;
} else {
if (value == 0)
- ns_debug(ns_log_config, 3, "%s is default",
- name);
+ 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
@@ -1155,7 +1519,7 @@ periodic_getnetconf(evContext ctx, void *uap, struct timespec due,
{
getnetconf(1);
}
-
+
static void
set_interval_timer(int which_timer, int interval) {
evTimerID *tid = NULL;
@@ -1174,6 +1538,10 @@ set_interval_timer(int which_timer, int interval) {
tid = &stats_timer;
func = ns_logstats;
break;
+ case HEARTBEAT_TIMER:
+ tid = &heartbeat_timer;
+ func = ns_heartbeat;
+ break;
default:
ns_panic(ns_log_config, 1,
"set_interval_timer: unknown timer %d", which_timer);
@@ -1215,7 +1583,6 @@ set_interval_timer(int which_timer, int interval) {
*/
void
set_options(options op, int is_default) {
- listen_info li;
INSIST(op != NULL);
if (op->listen_list == NULL) {
@@ -1231,6 +1598,18 @@ set_options(options op, int is_default) {
add_to_ip_match_list(iml, ime);
add_listen_on(op, htons(NS_DEFAULTPORT), iml);
}
+ if (op->topology == NULL) {
+ ip_match_list iml;
+ ip_match_element ime;
+
+ /* 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;
+ }
if (server_options != NULL)
free_options(server_options);
server_options = op;
@@ -1263,6 +1642,14 @@ set_options(options op, int is_default) {
/* XXX currently transfers_out is not used */
+ if (!op->max_ncache_ttl)
+ op->max_ncache_ttl = DEFAULT_MAX_NCACHE_TTL;
+ else if (op->max_ncache_ttl > max_cache_ttl)
+ op->max_ncache_ttl = max_cache_ttl;
+
+ if (op->lame_ttl > (3 * NTTL))
+ op->lame_ttl = 3 * NTTL;
+
/*
* Limits
*/
@@ -1276,7 +1663,6 @@ set_options(options op, int is_default) {
ns_info(ns_log_config, "cannot set resource limits on this system");
#endif
-
/*
* Timers
*/
@@ -1284,6 +1670,8 @@ set_options(options op, int is_default) {
set_interval_timer(INTERFACE_TIMER,
server_options->interface_interval);
set_interval_timer(STATS_TIMER, server_options->stats_interval);
+ set_interval_timer(HEARTBEAT_TIMER,
+ server_options->heartbeat_interval);
options_installed = 1;
default_options_installed = is_default;
@@ -1295,6 +1683,129 @@ use_default_options() {
}
/*
+ * rrset order types
+ */
+static struct res_sym order_table [] = {
+ { unknown_order, " unknown " }, /* can't match */
+ { fixed_order, "fixed" },
+ { cyclic_order, "cyclic" },
+ { random_order, "random" },
+ { unknown_order, NULL }
+};
+
+/*
+ * Return the print name of the ordering value.
+ */
+const char *
+p_order(int order) {
+ return (__sym_ntos(order_table, order, (int *)0));
+}
+
+/*
+ * Lookup the ordering by name and return the matching enum value.
+ */
+enum ordering
+lookup_ordering(const char *name) {
+ int i;
+
+ for (i = 0; order_table[i].name != NULL; i++)
+ if (strcasecmp(name,order_table[i].name) == 0)
+ return ((enum ordering)order_table[i].number);
+ return (unknown_order);
+}
+
+/*
+ * rrset-order Lists
+ */
+rrset_order_list
+new_rrset_order_list() {
+ rrset_order_list rol ;
+
+ rol = (rrset_order_list)memget(sizeof (struct rrset_order_list));
+ if (rol == NULL)
+ panic("memget failed in new_rrset_order_list", NULL);
+ rol->first = NULL;
+ rol->last = NULL;
+
+ return (rol);
+}
+
+void
+free_rrset_order_list(rrset_order_list rol) {
+ rrset_order_element roe, next_element;
+
+ for (roe = rol->first; roe != NULL; roe = next_element) {
+ next_element = roe->next;
+ freestr(roe->name);
+ memput(roe, sizeof (*roe));
+ }
+ memput(rol, sizeof (*rol));
+}
+
+
+void
+add_to_rrset_order_list(rrset_order_list rol, rrset_order_element roe) {
+ INSIST(rol != NULL);
+ INSIST(roe != NULL);
+
+ if (rol->last != NULL)
+ rol->last->next = roe;
+ roe->next = NULL;
+ rol->last = roe;
+ if (rol->first == NULL)
+ rol->first = roe;
+}
+
+/* XXX this isn't being used yet, but it probably should be. Where? */
+void
+dprint_rrset_order_list(int category, rrset_order_list rol, int indent,
+ char *allow, char *deny) {
+ rrset_order_element roe ;
+ char spaces[40+1];
+
+ INSIST(rol != NULL);
+
+ if (indent > 40)
+ indent = 40;
+ if (indent)
+ memset(spaces, ' ', indent);
+ spaces[indent] = '\0';
+
+ for (roe = rol->first; roe != NULL; roe = roe->next) {
+ ns_debug(category, 7, "%sclass %s type %s name %s order %s",
+ spaces, p_class(roe->class), p_type(roe->type),
+ roe->name, p_order(roe->order));
+ }
+}
+
+
+rrset_order_element
+new_rrset_order_element(int class, int type, char *name, enum ordering order)
+{
+ rrset_order_element roe;
+ int i ;
+
+ roe = (rrset_order_element)memget(sizeof (struct rrset_order_element));
+ if (roe == NULL)
+ panic("memget failed in new_rrset_order_element", NULL);
+ roe->class = class ;
+ roe->type = type ;
+ roe->name = name;
+ roe->order = order;
+
+ i = strlen(roe->name) - 1;
+ INSIST (i >= 0);
+ if (roe->name[i - 1] == '.') {
+ /* We compare from right to left so we don't need a dot on
+ the end. */
+ roe->name[i - 1] = '\0' ;
+ }
+
+ return roe ;
+}
+
+
+/*
* IP Matching Lists
*/
@@ -1390,6 +1901,19 @@ new_ip_match_indirect(ip_match_list iml) {
}
ip_match_element
+new_ip_match_key(DST_KEY *dst_key) {
+ ip_match_element ime;
+
+ ime = (ip_match_element)memget(sizeof (struct ip_match_element));
+ if (ime == NULL)
+ panic("memget failed in new_ip_match_key", NULL);
+ ime->type = ip_match_key;
+ ime->flags = 0;
+ ime->u.key.key = dst_key;
+ return (ime);
+}
+
+ip_match_element
new_ip_match_localhost() {
ip_match_element ime;
@@ -1445,7 +1969,6 @@ dprint_ip_match_list(int category, ip_match_list iml, int indent,
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);
@@ -1488,6 +2011,11 @@ dprint_ip_match_list(int category, ip_match_list iml, int indent,
ime->u.indirect.list,
indent+2, allow, deny);
break;
+ case ip_match_key:
+ ns_debug(category, 7, "%s%skey %s", spaces,
+ (ime->flags & IP_MATCH_NEGATE) ? deny : allow,
+ ime->u.key.key->dk_key_name);
+ break;
default:
panic("unexpected ime type in dprint_ip_match_list()",
NULL);
@@ -1496,7 +2024,9 @@ dprint_ip_match_list(int category, ip_match_list iml, int indent,
}
int
-ip_match_address(ip_match_list iml, struct in_addr address) {
+ip_match_addr_or_key(ip_match_list iml, struct in_addr address,
+ DST_KEY *key)
+{
ip_match_element ime;
int ret;
int indirect;
@@ -1518,13 +2048,25 @@ ip_match_address(ip_match_list iml, struct in_addr address) {
ime->u.indirect.list = local_networks;
indirect = 1;
break;
+ case ip_match_key:
+ if (key == NULL) {
+ indirect = 0;
+ break;
+ }
+ else {
+ if (ns_samename(ime->u.key.key->dk_key_name,
+ key->dk_key_name) == 1)
+ return (1);
+ else
+ continue;
+ }
default:
- indirect = 0; /* Make gcc happy. */
- panic("unexpected ime type in ip_match_address()",
+ panic("unexpected ime type in ip_match_addr_or_key()",
NULL);
}
if (indirect) {
- ret = ip_match_address(ime->u.indirect.list, address);
+ ret = ip_match_addr_or_key(ime->u.indirect.list,
+ address, key);
if (ret >= 0) {
if (ime->flags & IP_MATCH_NEGATE)
ret = (ret) ? 0 : 1;
@@ -1544,18 +2086,30 @@ ip_match_address(ip_match_list iml, struct in_addr address) {
}
int
-ip_address_allowed(ip_match_list iml, struct in_addr address) {
+ip_match_address(ip_match_list iml, struct in_addr address) {
+ return ip_match_addr_or_key(iml, address, NULL);
+}
+
+int
+ip_addr_or_key_allowed(ip_match_list iml, struct in_addr address,
+ DST_KEY *key)
+{
int ret;
if (iml == NULL)
return (0);
- ret = ip_match_address(iml, address);
+ ret = ip_match_addr_or_key(iml, address, key);
if (ret < 0)
ret = 0;
return (ret);
}
int
+ip_address_allowed(ip_match_list iml, struct in_addr address) {
+ return(ip_addr_or_key_allowed(iml, address, NULL));
+}
+
+int
ip_match_network(ip_match_list iml, struct in_addr address,
struct in_addr mask) {
ip_match_element ime;
@@ -1579,6 +2133,9 @@ ip_match_network(ip_match_list iml, struct in_addr address,
ime->u.indirect.list = local_networks;
indirect = 1;
break;
+ case ip_match_key:
+ indirect = 0;
+ break;
default:
indirect = 0; /* Make gcc happy. */
panic("unexpected ime type in ip_match_network()",
@@ -1630,6 +2187,9 @@ distance_of_address(ip_match_list iml, struct in_addr address) {
ime->u.indirect.list = local_networks;
indirect = 1;
break;
+ case ip_match_key:
+ indirect = 0;
+ return (-1);
default:
indirect = 0; /* Make gcc happy. */
panic("unexpected ime type in distance_of_address()",
@@ -1666,14 +2226,14 @@ int
ip_match_is_none(ip_match_list iml) {
ip_match_element ime;
- if (iml == NULL)
+ if ((iml == NULL) || (iml->first == 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)
+ if ((iml == NULL) || (iml->first == NULL))
return (0);
ime = iml->first;
}
@@ -1694,30 +2254,13 @@ ip_match_is_none(ip_match_list iml) {
* 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);
+static void
+add_forwarder(struct fwdinfo **fipp, struct in_addr address) {
+ struct fwdinfo *fip = *fipp, *ftp = 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 */
+ while (fip != NULL && fip->next != NULL)
+ fip = fip->next;
ftp = (struct fwdinfo *)memget(sizeof(struct fwdinfo));
if (!ftp)
@@ -1733,19 +2276,95 @@ add_forwarder(options op, struct in_addr address) {
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 */
+ if (fip == NULL)
+ *fipp = ftp; /* First time only */
else
fip->next = ftp;
+}
+
+void
+free_also_notify(options op) {
+#ifdef BIND_NOTIFY
+ memput(op->also_notify, op->notify_count * sizeof *op->also_notify);
+ op->also_notify = NULL;
+ op->notify_count = 0;
+#endif
+}
+
+int
+add_global_also_notify(options op, struct in_addr address) {
+#ifdef BIND_NOTIFY
+ int i;
+
+ INSIST(op != NULL);
+
+ ns_debug(ns_log_config, 2, "adding global notify %s",
+ inet_ntoa(address));
+
+ /* Check for duplicates. */
+
+ for (i = 0; i < op->notify_count; i++) {
+ if (memcmp(op->also_notify + i,
+ &address, sizeof address) == 0) {
+ ns_warning(ns_log_config,
+ "duplicate global also-notify address ignored [%s]",
+ inet_ntoa(address));
+ return (1);
+ }
+ }
+ i = 0;
+
+ if (op->also_notify == NULL) {
+ op->also_notify = memget(sizeof *op->also_notify);
+ if (op->also_notify == NULL)
+ i = 1;
+ } else {
+ register size_t size;
+ register struct in_addr *an_tmp;
+ size = op->notify_count * sizeof *op->also_notify;
+ an_tmp = memget(size + sizeof *op->also_notify);
+ if (an_tmp == NULL) {
+ i = 1;
+ } else {
+ memcpy(an_tmp, op->also_notify, size);
+ memput(op->also_notify, size);
+ op->also_notify = an_tmp;
+ }
+ }
+ if (i == 0) {
+ op->also_notify[op->notify_count] = address;
+ op->notify_count++;
+ } else {
+ ns_warning(ns_log_config,
+ "global also-notify add failed (memget) [%s]",
+ inet_ntoa(address));
+ }
+#endif
+ return (1);
+}
+
+void
+add_global_forwarder(options op, struct in_addr address) {
#ifdef SLAVE_FORWARD
- forward_count++;
+ struct fwdinfo *fip;
+ int forward_count;
+#endif
+
+ INSIST(op != NULL);
+
+ ns_debug(ns_log_config, 2, "adding default forwarder %s",
+ inet_ntoa(address));
+ add_forwarder(&op->fwdtab, address);
+
+#ifdef SLAVE_FORWARD
/*
** Set the slave retry time to 60 seconds total divided
** between each forwarder
*/
+ for (forward_count = 0, fip = op->fwdtab; fip != NULL; fip = fip->next)
+ forward_count++;
if (forward_count != 0) {
slave_retry = (int) (60 / forward_count);
if(slave_retry <= 0)
@@ -1755,6 +2374,32 @@ add_forwarder(options op, struct in_addr address) {
}
void
+set_zone_forward(zone_config zh) {
+ struct zoneinfo *zp;
+ zp = zh.opaque;
+
+ zp->z_flags |= Z_FORWARD_SET;
+ set_zone_boolean_option(zh, OPTION_FORWARD_ONLY, 0);
+}
+
+void
+add_zone_forwarder(zone_config zh, struct in_addr address) {
+ struct zoneinfo *zp;
+ char *zname;
+
+ zp = zh.opaque;
+ INSIST(zp != NULL);
+
+ zname = (zp->z_origin[0] == '\0') ? "." : zp->z_origin;
+ ns_debug(ns_log_config, 2, "adding forwarder %s for zone zone '%s'",
+ inet_ntoa(address), zname);
+
+ zp->z_flags |= Z_FORWARD_SET;
+
+ add_forwarder(&zp->z_fwdtab, address);
+}
+
+void
free_forwarders(struct fwdinfo *fwdtab) {
struct fwdinfo *ftp, *fnext;
@@ -1762,13 +2407,13 @@ free_forwarders(struct fwdinfo *fwdtab) {
fnext = ftp->next;
memput(ftp, sizeof *ftp);
}
+ fwdtab = NULL;
}
/*
* Servers
*/
-
static server_info
new_server(struct in_addr address) {
server_info si;
@@ -1782,7 +2427,11 @@ new_server(struct in_addr address) {
si->transfer_format = axfr_use_default;
si->key_list = NULL;
si->next = NULL;
- return si;
+ if (server_options->flags & OPTION_MAINTAIN_IXFR_BASE)
+ si->flags |= SERVER_INFO_SUPPORT_IXFR;
+ else
+ si->flags &= ~SERVER_INFO_SUPPORT_IXFR;
+ return (si);
}
static void
@@ -1839,6 +2488,14 @@ free_nameserver_info() {
}
}
+static void
+free_secretkey_info() {
+ if (secretkey_info != NULL) {
+ free_key_info_list(secretkey_info);
+ secretkey_info = NULL;
+ }
+}
+
server_config
begin_server(struct in_addr address) {
server_config sc;
@@ -1872,6 +2529,7 @@ set_server_option(server_config sc, int bool_opt, int value) {
switch (bool_opt) {
case SERVER_INFO_BOGUS:
+ case SERVER_INFO_SUPPORT_IXFR:
if (value)
si->flags |= bool_opt;
else
@@ -1908,7 +2566,7 @@ set_server_transfer_format(server_config sc,
}
void
-add_server_key_info(server_config sc, key_info ki) {
+add_server_key_info(server_config sc, DST_KEY *dst_key) {
server_info si;
si = sc.opaque;
@@ -1917,44 +2575,75 @@ add_server_key_info(server_config sc, key_info ki) {
if (si->key_list == NULL)
si->key_list = new_key_info_list();
- add_to_key_info_list(si->key_list, ki);
+ add_to_key_info_list(si->key_list, dst_key);
}
/*
* Keys
*/
-key_info
+DST_KEY *
new_key_info(char *name, char *algorithm, char *secret) {
- key_info ki;
+ DST_KEY *dst_key;
+ int alg, blen;
+ u_char buffer[1024];
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);
+ alg = tsig_alg_value(algorithm);
+ if (alg == -1) {
+ ns_warning(ns_log_config, "Unsupported TSIG algorithm %s",
+ algorithm);
+ return (NULL);
+ }
+
+ blen = b64_pton(secret, buffer, sizeof(buffer));
+ if (blen < 0) {
+ ns_warning(ns_log_config, "Invalid TSIG secret \"%s\"", secret);
+ return (NULL);
+ }
+ dst_key = dst_buffer_to_key(name, alg,
+ NS_KEY_TYPE_AUTH_ONLY|NS_KEY_NAME_ENTITY,
+ NS_KEY_PROT_ANY, buffer, blen);
+ if (dst_key == NULL)
+ ns_warning(ns_log_config,
+ "dst_buffer_to_key failed in new_key_info");
+ return (dst_key);
}
void
-free_key_info(key_info ki) {
- INSIST(ki != NULL);
- freestr(ki->name);
- freestr(ki->algorithm);
- freestr(ki->secret);
- memput(ki, sizeof *ki);
+free_key_info(DST_KEY *dst_key) {
+ INSIST(dst_key != NULL);
+ dst_free_key(dst_key);
+}
+
+DST_KEY *
+find_key(char *name, char *algorithm) {
+ key_list_element ke;
+
+ if (secretkey_info == NULL)
+ return (NULL);
+
+ for (ke = secretkey_info->first; ke != NULL; ke = ke->next) {
+ DST_KEY *dst_key = ke->key;
+
+ if (ns_samename(name, dst_key->dk_key_name) != 1)
+ continue;
+ if (algorithm == NULL ||
+ dst_key->dk_alg == tsig_alg_value(algorithm))
+ break;
+ }
+ if (ke == NULL)
+ return (NULL);
+ return (ke->key);
}
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);
+dprint_key_info(DST_KEY *dst_key) {
+ INSIST(dst_key != NULL);
+ ns_debug(ns_log_config, 7, "key %s", dst_key->dk_key_name);
+ ns_debug(ns_log_config, 7, " algorithm %d", dst_key->dk_alg);
}
key_info_list
@@ -1983,16 +2672,16 @@ free_key_info_list(key_info_list kil) {
}
void
-add_to_key_info_list(key_info_list kil, key_info ki) {
+add_to_key_info_list(key_info_list kil, DST_KEY *dst_key) {
key_list_element kle;
INSIST(kil != NULL);
- INSIST(ki != NULL);
+ INSIST(dst_key != 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;
+ kle->key = dst_key;
if (kil->last != NULL)
kil->last->next = kle;
kle->next = NULL;
@@ -2008,7 +2697,7 @@ dprint_key_info_list(key_info_list kil) {
INSIST(kil != NULL);
for (kle = kil->first; kle != NULL; kle = kle->next)
- dprint_key_info(kle->info);
+ dprint_key_info(kle->key);
}
/*
@@ -2098,7 +2787,6 @@ open_special_channels() {
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;
@@ -2203,7 +2891,6 @@ use_default_logging() {
static void
init_default_log_channels() {
- FILE *null_stream;
u_int flags;
char *name;
FILE *stream;
@@ -2244,9 +2931,8 @@ shutdown_default_log_channels() {
log_free_channel(null_channel);
}
-void
+void
init_logging() {
- int i;
int size;
const struct ns_sym *s;
char category_name[256];
@@ -2266,7 +2952,7 @@ init_logging() {
use_default_logging();
}
-void
+void
shutdown_logging() {
int size;
const struct ns_sym *s;
@@ -2279,6 +2965,7 @@ shutdown_logging() {
freestr(logging_categories[s->number]);
size = ns_log_max_category * (sizeof (char *));
memput(logging_categories, size);
+ logging_categories = NULL;
}
/*
@@ -2297,6 +2984,7 @@ init_configuration() {
zone_symbol_table = new_symbol_table(ZONE_SYM_TABLE_SIZE, NULL);
use_default_options();
parser_initialize();
+ ns_ctl_initialize();
config_initialized = 1;
}
@@ -2304,6 +2992,7 @@ void
shutdown_configuration() {
REQUIRE(config_initialized);
+ ns_ctl_shutdown();
if (server_options != NULL) {
free_options(server_options);
server_options = NULL;
@@ -2311,6 +3000,7 @@ shutdown_configuration() {
if (current_pid_filename != NULL)
freestr(current_pid_filename);
free_nameserver_info();
+ free_secretkey_info();
free_symbol_table(zone_symbol_table);
parser_shutdown();
config_initialized = 0;
@@ -2329,6 +3019,7 @@ load_configuration(const char *filename) {
* global data structures we'll be updating.
*/
free_nameserver_info();
+ free_secretkey_info();
bogus_nameservers = new_ip_match_list();
options_installed = 0;
diff --git a/contrib/bind/bin/named/ns_ctl.c b/contrib/bind/bin/named/ns_ctl.c
new file mode 100644
index 0000000..259093b
--- /dev/null
+++ b/contrib/bind/bin/named/ns_ctl.c
@@ -0,0 +1,866 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ns_ctl.c,v 8.28 1999/10/13 16:39:04 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1997-1999 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.
+ */
+
+/* Extern. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.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"
+
+#include "named.h"
+
+/* Defs. */
+
+#define CONTROL_FOUND 0x0001 /* for mark and sweep. */
+#define MAX_STR_LEN 500
+
+struct control {
+ LINK(struct control) link;
+ enum { t_dead, t_inet, t_unix } type;
+ struct ctl_sctx *sctx;
+ u_int flags;
+ union {
+ struct {
+ struct sockaddr_in in;
+ ip_match_list allow;
+ } v_inet;
+ struct {
+ struct sockaddr_un un;
+ mode_t mode;
+ uid_t owner;
+ gid_t group;
+ } v_unix;
+ } var;
+};
+
+/* Forward. */
+
+static struct ctl_sctx *mksrvr(control, const struct sockaddr *, size_t);
+static control new_control(void);
+static void free_control(controls *, control);
+static void free_controls(controls *);
+static int match_control(control, control);
+static control find_control(controls, control);
+static void propagate_changes(const control, control);
+static void install(control);
+static void install_inet(control);
+static void install_unix(control);
+static void logger(enum ctl_severity, const char *fmt, ...);
+static void verb_connect(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+static void verb_getpid(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+static void getpid_closure(struct ctl_sctx *, struct ctl_sess *,
+ void *);
+static void verb_status(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+static void status_closure(struct ctl_sctx *, struct ctl_sess *,
+ void *);
+static void verb_stop(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+static void verb_exec(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+static void verb_reload(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+static void verb_reconfig(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+static void verb_dumpdb(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+static void verb_stats(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+static void verb_trace(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+static void trace_closure(struct ctl_sctx *, struct ctl_sess *,
+ void *);
+static void verb_notrace(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+static void verb_querylog(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+static void verb_help(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+static void verb_quit(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *, u_int, void *, void *);
+
+/* Private data. */
+
+static controls server_controls;
+
+static struct ctl_verb verbs[] = {
+ { "", verb_connect, ""},
+ { "getpid", verb_getpid, "getpid"},
+ { "status", verb_status, "status"},
+ { "stop", verb_stop, "stop"},
+ { "exec", verb_exec, "exec"},
+ { "reload", verb_reload, "reload [zone] ..."},
+ { "reconfig", verb_reconfig, "reconfig (just sees new/gone zones)"},
+ { "dumpdb", verb_dumpdb, "dumpdb"},
+ { "stats", verb_stats, "stats"},
+ { "trace", verb_trace, "trace [level]"},
+ { "notrace", verb_notrace, "notrace"},
+ { "querylog", verb_querylog, "querylog"},
+ { "qrylog", verb_querylog, "qrylog"},
+ { "help", verb_help, "help"},
+ { "quit", verb_quit, "quit"},
+ { NULL, NULL, NULL}
+};
+
+/* Public functions. */
+
+void
+ns_ctl_initialize(void) {
+ INIT_LIST(server_controls);
+}
+
+void
+ns_ctl_shutdown(void) {
+ if (!EMPTY(server_controls))
+ free_controls(&server_controls);
+}
+
+void
+ns_ctl_defaults(controls *list) {
+ ns_ctl_add(list, ns_ctl_new_unix(_PATH_NDCSOCK, 0600, 0, 0));
+}
+
+void
+ns_ctl_add(controls *list, control new) {
+ if (!find_control(*list, new))
+ APPEND(*list, new, link);
+}
+
+control
+ns_ctl_new_inet(struct in_addr saddr, u_int sport, ip_match_list allow) {
+ control new = new_control();
+
+ INIT_LINK(new, link);
+ new->type = t_inet;
+ memset(&new->var.v_inet.in, 0, sizeof new->var.v_inet.in);
+ new->var.v_inet.in.sin_family = AF_INET;
+ new->var.v_inet.in.sin_addr = saddr;
+ new->var.v_inet.in.sin_port = sport;
+ new->var.v_inet.allow = allow;
+ return (new);
+}
+
+control
+ns_ctl_new_unix(char *path, mode_t mode, uid_t owner, gid_t group) {
+ control new = new_control();
+
+ INIT_LINK(new, link);
+ new->type = t_unix;
+ memset(&new->var.v_unix.un, 0, sizeof new->var.v_unix.un);
+ new->var.v_unix.un.sun_family = AF_UNIX;
+ strncpy(new->var.v_unix.un.sun_path, path,
+ sizeof new->var.v_unix.un.sun_path - 1);
+ new->var.v_unix.mode = mode;
+ new->var.v_unix.owner = owner;
+ new->var.v_unix.group = group;
+ return (new);
+}
+
+void
+ns_ctl_install(controls *new) {
+ control ctl, old, next;
+
+ /* Find all the controls which aren't new or deleted. */
+ for (ctl = HEAD(server_controls); ctl != NULL; ctl = NEXT(ctl, link))
+ ctl->flags &= ~CONTROL_FOUND;
+ for (ctl = HEAD(*new); ctl != NULL; ctl = next) {
+ next = NEXT(ctl, link);
+ old = find_control(server_controls, ctl);
+ if (old != NULL) {
+ old->flags |= CONTROL_FOUND;
+ propagate_changes(ctl, old);
+ if (old->sctx == NULL)
+ free_control(&server_controls, old);
+ free_control(new, ctl);
+ }
+ }
+
+ /* Destroy any old controls which weren't found. */
+ for (ctl = HEAD(server_controls); ctl != NULL; ctl = next) {
+ next = NEXT(ctl, link);
+ if ((ctl->flags & CONTROL_FOUND) == 0)
+ free_control(&server_controls, ctl);
+ }
+
+ /* Add any new controls which were found. */
+ for (ctl = HEAD(*new); ctl != NULL; ctl = next) {
+ next = NEXT(ctl, link);
+ APPEND(server_controls, ctl, link);
+ install(ctl);
+ if (ctl->sctx == NULL)
+ free_control(&server_controls, ctl);
+ }
+}
+
+/* Private functions. */
+
+static struct ctl_sctx *
+mksrvr(control ctl, const struct sockaddr *sa, size_t salen) {
+ return (ctl_server(ev, sa, salen, verbs, 500, 222,
+ 600, 5, 10, logger, ctl));
+}
+
+static control
+new_control(void) {
+ control new = memget(sizeof *new);
+
+ if (new == NULL)
+ panic("memget failed in new_control()", NULL);
+ new->type = t_dead;
+ new->sctx = NULL;
+ return (new);
+}
+
+static void
+free_control(controls *list, control this) {
+ int was_live = 0;
+ struct stat sb;
+
+ if (this->sctx != NULL) {
+ ctl_endserver(this->sctx);
+ this->sctx = NULL;
+ was_live = 1;
+ }
+ switch (this->type) {
+ case t_inet:
+ if (this->var.v_inet.allow != NULL) {
+ free_ip_match_list(this->var.v_inet.allow);
+ this->var.v_inet.allow = NULL;
+ }
+ break;
+ case t_unix:
+ /* XXX Race condition. */
+ if (was_live &&
+ stat(this->var.v_unix.un.sun_path, &sb) == 0 &&
+ (S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) {
+ /* XXX Race condition. */
+ unlink(this->var.v_unix.un.sun_path);
+ }
+ break;
+ default:
+ panic("impossible type in free_control", NULL);
+ /* NOTREACHED */
+ }
+ UNLINK(*list, this, link);
+ memput(this, sizeof *this);
+}
+
+static void
+free_controls(controls *list) {
+ control ctl, next;
+
+ for (ctl = HEAD(*list); ctl != NULL; ctl = next) {
+ next = NEXT(ctl, link);
+ free_control(list, ctl);
+ }
+ INIT_LIST(*list);
+}
+
+static int
+match_control(control l, control r) {
+ int match = 1;
+
+ if (l->type != r->type)
+ match = 0;
+ else
+ switch (l->type) {
+ case t_inet:
+ if (l->var.v_inet.in.sin_family !=
+ r->var.v_inet.in.sin_family ||
+ l->var.v_inet.in.sin_port !=
+ r->var.v_inet.in.sin_port ||
+ l->var.v_inet.in.sin_addr.s_addr !=
+ r->var.v_inet.in.sin_addr.s_addr)
+ match = 0;
+ break;
+ case t_unix:
+ if (l->var.v_unix.un.sun_family !=
+ r->var.v_unix.un.sun_family ||
+ strcmp(l->var.v_unix.un.sun_path,
+ r->var.v_unix.un.sun_path) != 0)
+ match = 0;
+ break;
+ default:
+ panic("impossible type in match_control", NULL);
+ /* NOTREACHED */
+ }
+ ns_debug(ns_log_config, 20, "match_control(): %d", match);
+ return (match);
+}
+
+static control
+find_control(controls list, control new) {
+ control ctl;
+
+ for (ctl = HEAD(list); ctl != NULL; ctl = NEXT(ctl, link))
+ if (match_control(ctl, new))
+ return (ctl);
+ return (NULL);
+}
+
+static void
+propagate_changes(const control diff, control base) {
+ int need_install = 0;
+
+ switch (base->type) {
+ case t_inet:
+ if (base->var.v_inet.allow != NULL)
+ free_ip_match_list(base->var.v_inet.allow);
+ base->var.v_inet.allow = diff->var.v_inet.allow;
+ diff->var.v_inet.allow = NULL;
+ need_install++;
+ break;
+ case t_unix:
+ if (base->var.v_unix.mode != diff->var.v_unix.mode) {
+ base->var.v_unix.mode = diff->var.v_unix.mode;
+ need_install++;
+ }
+ if (base->var.v_unix.owner != diff->var.v_unix.owner) {
+ base->var.v_unix.owner = diff->var.v_unix.owner;
+ need_install++;
+ }
+ if (base->var.v_unix.group != diff->var.v_unix.group) {
+ base->var.v_unix.group = diff->var.v_unix.group;
+ need_install++;
+ }
+ break;
+ default:
+ panic("impossible type in ns_ctl::propagate_changes", NULL);
+ /* NOTREACHED */
+ }
+ if (need_install)
+ install(base);
+}
+
+static void
+install(control ctl) {
+ switch (ctl->type) {
+ case t_inet:
+ install_inet(ctl);
+ break;
+ case t_unix:
+ install_unix(ctl);
+ break;
+ default:
+ panic("impossible type in ns_ctl::install", NULL);
+ /* NOTREACHED */
+ }
+}
+
+static void
+install_inet(control ctl) {
+ if (ctl->sctx == NULL) {
+ ctl->sctx = mksrvr(ctl,
+ (struct sockaddr *)&ctl->var.v_inet.in,
+ sizeof ctl->var.v_inet.in);
+ }
+}
+
+/*
+ * Unattach an old unix domain socket if it exists.
+ */
+static void
+unattach(control ctl) {
+ int s;
+ struct stat sb;
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s < 0) {
+ ns_warning(ns_log_config,
+ "unix control \"%s\" socket failed: %s",
+ ctl->var.v_unix.un.sun_path,
+ strerror(errno));
+ return;
+ }
+
+ if (stat(ctl->var.v_unix.un.sun_path, &sb) < 0) {
+ switch (errno) {
+ case ENOENT: /* We exited cleanly last time */
+ break;
+ default:
+ ns_warning(ns_log_config,
+ "unix control \"%s\" stat failed: %s",
+ ctl->var.v_unix.un.sun_path,
+ strerror(errno));
+ break;
+ }
+ goto cleanup;
+ }
+
+ if (!(S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) {
+ ns_warning(ns_log_config, "unix control \"%s\" not socket",
+ ctl->var.v_unix.un.sun_path);
+ goto cleanup;
+ }
+
+ if (connect(s, (struct sockaddr *)&ctl->var.v_unix.un,
+ sizeof ctl->var.v_unix.un) < 0) {
+ switch (errno) {
+ case ECONNREFUSED:
+ case ECONNRESET:
+ if (unlink(ctl->var.v_unix.un.sun_path) < 0)
+ ns_warning(ns_log_config,
+ "unix control \"%s\" unlink failed: %s",
+ ctl->var.v_unix.un.sun_path,
+ strerror(errno));
+ break;
+ default:
+ ns_warning(ns_log_config,
+ "unix control \"%s\" connect failed: %s",
+ ctl->var.v_unix.un.sun_path,
+ strerror(errno));
+ break;
+ }
+ }
+ cleanup:
+ close(s);
+}
+
+static void
+install_unix(control ctl) {
+ if (ctl->sctx == NULL) {
+ unattach(ctl);
+ ctl->sctx = mksrvr(ctl,
+ (struct sockaddr *)&ctl->var.v_unix.un,
+ sizeof ctl->var.v_unix.un);
+ }
+ if (ctl->sctx != NULL) {
+ /* XXX Race condition. */
+ if (chmod(ctl->var.v_unix.un.sun_path,
+ ctl->var.v_unix.mode) < 0) {
+ ns_warning(ns_log_config, "chmod(\"%s\", 0%03o): %s",
+ ctl->var.v_unix.un.sun_path,
+ ctl->var.v_unix.mode,
+ strerror(errno));
+ }
+ if (chown(ctl->var.v_unix.un.sun_path,
+ ctl->var.v_unix.owner,
+ ctl->var.v_unix.group) < 0) {
+ ns_warning(ns_log_config, "chown(\"%s\", %d, %d): %s",
+ ctl->var.v_unix.un.sun_path,
+ ctl->var.v_unix.owner,
+ ctl->var.v_unix.group,
+ strerror(errno));
+ }
+ }
+}
+
+static void
+logger(enum ctl_severity ctlsev, const char *format, ...) {
+ va_list args;
+ int logsev;
+
+ switch (ctlsev) {
+ case ctl_debug: logsev = log_debug(5); break;
+ case ctl_warning: logsev = log_warning; break;
+ case ctl_error: logsev = log_error; break;
+ default: panic("invalid ctlsev in logger", NULL);
+ }
+ if (!log_ctx_valid)
+ return;
+ va_start(args, format);
+ log_vwrite(log_ctx, ns_log_control, logsev, format, args);
+ va_end(args);
+}
+
+static void
+verb_connect(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ const struct sockaddr *sa = (struct sockaddr *)respctx;
+ control nsctl = (control)uctx;
+
+ if (sa->sa_family == AF_INET) {
+ const struct sockaddr_in *in = (struct sockaddr_in *)sa;
+ const ip_match_list acl = nsctl->var.v_inet.allow;
+
+ if (!ip_address_allowed(acl, in->sin_addr)) {
+ ctl_response(sess, 502, "Permission denied.",
+ CTL_EXIT, NULL, NULL, NULL, NULL, 0);
+ return;
+ }
+ }
+ ctl_response(sess, 220, server_options->version, 0, NULL, NULL, NULL,
+ NULL, 0);
+}
+
+static void
+verb_getpid(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ char *msg = memget(MAX_STR_LEN);
+
+ if (msg == NULL) {
+ ctl_response(sess, 503, "(out of memory)", 0,
+ NULL, NULL, NULL, NULL, 0);
+ return;
+ }
+ sprintf(msg, "my pid is <%ld>", (long)getpid());
+ ctl_response(sess, 250, msg, 0, NULL, getpid_closure, msg, NULL, 0);
+}
+
+static void
+getpid_closure(struct ctl_sctx *sctx, struct ctl_sess *sess, void *uap) {
+ char *msg = uap;
+
+ memput(msg, MAX_STR_LEN);
+}
+
+enum state {
+ e_version = 0,
+ e_nzones,
+ e_debug,
+ e_xfersrun,
+ e_xfersdfr,
+ e_qserials,
+ e_qrylog,
+ e_priming,
+ e_loading,
+ e_finito
+};
+
+struct pvt_status {
+ enum state state;
+ char text[MAX_STR_LEN];
+};
+
+static void
+verb_status(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct pvt_status *pvt = ctl_getcsctx(sess);
+
+ if (pvt == NULL) {
+ pvt = memget(sizeof *pvt);
+ if (pvt == NULL) {
+ ctl_response(sess, 505, "(out of memory)",
+ 0, NULL, NULL, NULL, NULL, 0);
+ return;
+ }
+ pvt->state = e_version;
+ (void)ctl_setcsctx(sess, pvt);
+ }
+ switch (pvt->state++) {
+ case e_version:
+ strncpy(pvt->text, Version, sizeof pvt->text);
+ pvt->text[sizeof pvt->text - 1] = '\0';
+ break;
+ case e_nzones:
+ sprintf(pvt->text, "number of zones allocated: %d", nzones);
+ break;
+ case e_debug:
+ sprintf(pvt->text, "debug level: %d", debug);
+ break;
+ case e_xfersrun:
+ sprintf(pvt->text, "xfers running: %d", xfers_running);
+ break;
+ case e_xfersdfr:
+ sprintf(pvt->text, "xfers deferred: %d", xfers_deferred);
+ break;
+ case e_qserials:
+ sprintf(pvt->text, "soa queries in progress: %d",
+ qserials_running);
+ break;
+ case e_qrylog:
+ sprintf(pvt->text, "query logging is %s",
+ qrylog ? "ON" : "OFF");
+ break;
+ case e_priming:
+ sprintf(pvt->text, "server is %s priming",
+ priming ? "STILL" : "DONE");
+ break;
+ case e_loading:
+ sprintf(pvt->text, "server %s loading its configuration",
+ loading ? "IS" : "IS NOT");
+ break;
+ case e_finito:
+ return;
+ }
+ ctl_response(sess, 250, pvt->text,
+ (pvt->state == e_finito) ? 0 : CTL_MORE,
+ NULL, status_closure, NULL, NULL, 0);
+}
+
+static void
+status_closure(struct ctl_sctx *sctx, struct ctl_sess *sess, void *uap) {
+ struct pvt_status *pvt = ctl_getcsctx(sess);
+
+ memput(pvt, sizeof *pvt);
+ ctl_setcsctx(sess, NULL);
+}
+
+static void
+verb_stop(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ ns_need(main_need_exit);
+ ctl_response(sess, 250, "Shutdown initiated.", 0, NULL, NULL, NULL,
+ NULL, 0);
+}
+
+static void
+verb_exec(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct stat sb;
+
+ if (rest != NULL && *rest != '\0') {
+ if (stat(rest, &sb) < 0) {
+ ctl_response(sess, 503, strerror(errno),
+ 0, NULL, NULL, NULL, NULL, 0);
+ return;
+ }
+ saved_argv[0] = savestr(rest, 1); /* Never strfreed. */
+ }
+
+ if (stat(saved_argv[0], &sb) < 0) {
+ const char *save = strerror(errno);
+
+ ns_warning(ns_log_default, "can't exec, %s: %s",
+ saved_argv[0], save);
+ ctl_response(sess, 502, save, 0, NULL, NULL, NULL,
+ NULL, 0);
+ } else {
+ ns_need(main_need_restart);
+ ctl_response(sess, 250, "Restart initiated.", 0, NULL,
+ NULL, NULL, NULL, 0);
+ }
+}
+
+static void
+verb_reload(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ static const char spaces[] = " \t";
+ struct zoneinfo *zp;
+ char *tmp = NULL, *x;
+ const char *msg;
+ int class, code, success;
+
+ /* If there are no args, this is a classic reload of the config. */
+ if (rest == NULL || *rest == '\0') {
+ ns_need(main_need_reload);
+ code = 250;
+ msg = "Reload initiated.";
+ goto respond;
+ }
+
+ /* Look for optional zclass argument. Default is "in". */
+ tmp = savestr(rest, 1);
+ x = tmp + strcspn(tmp, spaces);
+ if (*x != '\0') {
+ *x++ = '\0';
+ x += strspn(x, spaces);
+ }
+ if (x == NULL || *x == '\0')
+ x = "in";
+ class = sym_ston(__p_class_syms, x, &success);
+ if (!success) {
+ code = 507;
+ msg = "unrecognized class";
+ goto respond;
+ }
+
+ /* Look for the zone, and do the right thing to it. */
+ zp = find_zone(tmp, class);
+ if (zp == NULL) {
+ code = 506;
+ msg = "Zone not found.";
+ goto respond;
+ }
+ switch (zp->z_type) {
+ case z_master:
+ ns_stopxfrs(zp);
+ /*FALLTHROUGH*/
+ case z_hint:
+ block_signals();
+ code = 251;
+ msg = deferred_reload_unsafe(zp);
+ unblock_signals();
+ break;
+ case z_slave:
+ case z_stub:
+ ns_stopxfrs(zp);
+ addxfer(zp);
+ code = 251;
+ msg = "Slave transfer queued.";
+ goto respond;
+ case z_forward:
+ case z_cache:
+ default:
+ msg = "Non reloadable zone.";
+ code = 507;
+ break;
+ }
+
+ respond:
+ ctl_response(sess, code, msg, 0, NULL, NULL, NULL, NULL, 0);
+ if (tmp != NULL)
+ freestr(tmp);
+}
+
+static void
+verb_reconfig(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ ns_need(main_need_reconfig);
+ ctl_response(sess, 250, "Reconfig initiated.",
+ 0, NULL, NULL, NULL, NULL, 0);
+}
+
+static void
+verb_dumpdb(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ ns_need(main_need_dump);
+ ctl_response(sess, 250, "Database dump initiated.", 0, NULL,
+ NULL, NULL, NULL, 0);
+}
+
+static void
+verb_stats(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ ns_need(main_need_statsdump);
+ ctl_response(sess, 250, "Statistics dump initiated.",
+ 0, NULL, NULL, NULL, NULL, 0);
+}
+
+static void
+verb_trace(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ int i = atoi(rest);
+ char *msg = memget(MAX_STR_LEN);
+
+ if (msg == NULL) {
+ ctl_response(sess, 503, "(out of memory)", 0,
+ NULL, NULL, NULL, NULL, 0);
+ return;
+ }
+ if (i > 0)
+ desired_debug = i;
+ else
+ desired_debug++;
+ ns_need(main_need_debug);
+ sprintf(msg, "Debug level: %d", desired_debug);
+ ctl_response(sess, 250, msg, 0, NULL, trace_closure, msg, NULL, 0);
+}
+
+static void
+trace_closure(struct ctl_sctx *sctx, struct ctl_sess *sess, void *uap) {
+ char *msg = uap;
+
+ memput(msg, MAX_STR_LEN);
+}
+
+static void
+verb_notrace(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ desired_debug = 0;
+ ns_need(main_need_debug);
+ ctl_response(sess, 250, "Debugging turned off.",
+ 0, NULL, NULL, NULL, NULL, 0);
+}
+
+static void
+verb_querylog(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ static const char on[] = "Query logging is now on.",
+ off[] = "Query logging is now off.";
+
+ toggle_qrylog();
+ ctl_response(sess, 250, qrylog ? on : off,
+ 0, NULL, NULL, NULL, NULL, 0);
+}
+
+static void
+verb_help(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ ctl_sendhelp(sess, 214);
+}
+
+static void
+verb_quit(struct ctl_sctx *ctl, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ ctl_response(sess, 221, "End of control session.", CTL_EXIT, NULL,
+ NULL, NULL, NULL, 0);
+}
diff --git a/contrib/bind/bin/named/ns_defs.h b/contrib/bind/bin/named/ns_defs.h
index 8d4bba7..801e5a9 100644
--- a/contrib/bind/bin/named/ns_defs.h
+++ b/contrib/bind/bin/named/ns_defs.h
@@ -1,6 +1,6 @@
/*
* from ns.h 4.33 (Berkeley) 8/23/90
- * $Id: ns_defs.h,v 8.39 1998/04/14 00:35:09 halley Exp $
+ * $Id: ns_defs.h,v 8.89 1999/10/07 08:24:08 vixie Exp $
*/
/*
@@ -36,7 +36,8 @@
* SUCH DAMAGE.
*/
-/* Portions Copyright (c) 1993 by Digital Equipment Corporation.
+/*
+ * 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
@@ -56,7 +57,7 @@
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -73,6 +74,26 @@
*/
/*
+ * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc.
+ *
+ * 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 Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES
+ * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED
+ * 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.
*/
@@ -92,6 +113,7 @@
* dies out in a little more than a minute.
* (sequence RETRYBASE, 2*RETRYBASE, 4*RETRYBASE... for MAXRETRY)
*/
+#define NEWZONES 64 /* must be a power of two. */
#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 */
@@ -107,6 +129,11 @@
/* every MIN_REFRESH seconds */
#define MIN_RETRY 1 /* never retry more frequently than once */
/* every MIN_RETRY seconds */
+#define MAX_REFRESH 2419200 /* perform a refresh query at least */
+ /* every 4 weeks*/
+#define MAX_RETRY 1209600 /* perform a retry after no more than 2 weeks */
+#define MAX_EXPIRE 31536000 /* expire a zone if we have not talked to */
+ /* the primary in 1 year */
#define NADDRECS 20 /* max addt'l rr's per resp */
#define XFER_TIMER 120 /* named-xfer's connect timeout */
@@ -117,35 +144,53 @@
#define DEFAULT_XFERS_PER_NS 2 /* default # of xfers per peer nameserver */
#define XFER_BUFSIZE (16*1024) /* arbitrary but bigger than most MTU's */
+ /* maximum time to cache negative answers */
+#define DEFAULT_MAX_NCACHE_TTL (3*60*60)
+
#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 */
+typedef enum need {
+ main_need_zreload = 0, /* ns_zreload() needed. */
+ main_need_reload, /* ns_reload() needed. */
+ main_need_reconfig, /* ns_reconfig() needed. */
+ main_need_endxfer, /* endxfer() needed. */
+ main_need_zoneload, /* loadxfer() needed. */
+ main_need_dump, /* doadump() needed. */
+ main_need_statsdump, /* ns_stats() needed. */
+ main_need_exit, /* exit() needed. */
+ main_need_qrylog, /* toggle_qrylog() needed. */
+ main_need_debug, /* use_desired_debug() needed. */
+ main_need_restart, /* exec() needed. */
+ main_need_reap, /* need to reap dead children */
+ main_need_num /* number of needs, used for array bound. */
+} main_need;
/* 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. */
+#ifdef BIND_NOTIFY
#define OPTION_NONOTIFY 0x0010 /* Turn off notify */
+#endif
#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 OPTION_USE_IXFR 0x0110 /* Use by delault ixfr in zone transfer */
+#define OPTION_MAINTAIN_IXFR_BASE 0x0120
+#define OPTION_NODIALUP 0x0200 /* Turn off dialup support */
+#define OPTION_NORFC2308_TYPE1 0x0400 /* Prevent type1 respones (RFC 2308)
+ * to cached negative respones */
+#define OPTION_USE_ID_POOL 0x0800 /* Use the memory hogging query ID */
+#define OPTION_TREAT_CR_AS_SPACE 0x1000 /* Treat CR in zone files as space */
-#define DEFAULT_OPTION_FLAGS 0
+#define DEFAULT_OPTION_FLAGS (OPTION_NODIALUP|OPTION_NONAUTH_NXDOMAIN|\
+ OPTION_USE_ID_POOL|OPTION_NORFC2308_TYPE1)
#ifdef BIND_UPDATE
#define SOAINCRINTVL 300 /* default value for the time after which
@@ -165,6 +210,7 @@
#define CLEAN_TIMER 0x01
#define INTERFACE_TIMER 0x02
#define STATS_TIMER 0x04
+#define HEARTBEAT_TIMER 0x08
/* IP address accessor, network byte order. */
#define ina_ulong(ina) (ina.s_addr)
@@ -186,6 +232,13 @@
(panic(panic_msg_no_options, NULL), 0) : \
((server_options->flags & option) != 0))
+#define NS_ZOPTION_P(zp, option) \
+ (((zp) != NULL && (((zp)->z_optset & option) != 0)) ? \
+ (((zp)->z_options & option) != 0) : NS_OPTION_P(option))
+
+#define NS_ZFWDTAB(zp) (((zp) == NULL) ? \
+ server_options->fwdtab : (zp)->z_fwdtab)
+
#define NS_INCRSTAT(addr, which) \
do { \
if ((int)which >= (int)nssLast) \
@@ -204,7 +257,11 @@
enum severity { ignore, warn, fail, not_set };
+#ifdef BIND_NOTIFY
enum znotify { znotify_use_default=0, znotify_yes, znotify_no };
+#endif
+
+enum zdialup { zdialup_use_default=0, zdialup_yes, zdialup_no };
enum axfr_format { axfr_use_default=0, axfr_one_answer, axfr_many_answers };
@@ -217,8 +274,12 @@ struct ip_match_indirect {
struct ip_match_list *list;
};
+struct ip_match_key {
+ struct dst_key *key;
+};
+
typedef enum { ip_match_pattern, ip_match_indirect, ip_match_localhost,
- ip_match_localnets } ip_match_type;
+ ip_match_localnets, ip_match_key } ip_match_type;
typedef struct ip_match_element {
ip_match_type type;
@@ -226,6 +287,7 @@ typedef struct ip_match_element {
union {
struct ip_match_direct direct;
struct ip_match_indirect indirect;
+ struct ip_match_key key;
} u;
struct ip_match_element *next;
} *ip_match_element;
@@ -259,12 +321,15 @@ struct zoneinfo {
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[] */
+ struct in_addr z_xaddr[NSMAX]; /* list of master servers for xfer */
+ u_char z_xaddrcnt; /* number of entries in z_xaddr[] */
u_char z_type; /* type of zone; see below */
- u_int16_t z_flags; /* state bits; see below */
+ u_int32_t z_flags; /* state bits; see below */
pid_t z_xferpid; /* xfer child pid */
+ u_int z_options; /* options set specific to this zone */
+ u_int z_optset; /* which opts override global opts */
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 */
@@ -286,60 +351,87 @@ struct zoneinfo {
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 */
+#ifdef BIND_NOTIFY
enum znotify z_notify; /* Notify mode */
- struct in_addr z_also_notify[NSMAX]; /* More nameservers to notify */
+ struct in_addr *z_also_notify; /* More nameservers to notify */
int z_notify_count;
+#endif
+ enum zdialup z_dialup; /* secondaries over a dialup link */
+ char *z_ixfr_base; /* where to find the history of the zone */
+ char *z_ixfr_tmp; /* tmp file for the ixfr */
+ int z_maintain_ixfr_base;
+ int z_log_size_ixfr;
+ int z_max_log_size_ixfr;
evTimerID z_timer; /* maintenance timer */
ztimer_info z_timerinfo; /* UAP associated with timer */
time_t z_nextmaint; /* time of next maintenance */
+ u_int16_t z_port; /* perform AXFR to this port */
+ struct fwdinfo *z_fwdtab; /* zone-specific forwarders */
+ LINK(struct zoneinfo) z_freelink; /* if it's on the free list. */
+ LINK(struct zoneinfo) z_reloadlink; /* if it's on the reload list. */
};
/* zone types (z_type) */
-enum zonetype { z_nil, z_master, z_slave, z_hint, z_stub, z_any };
+enum zonetype { z_nil, z_master, z_slave, z_hint, z_stub, z_forward,
+ z_cache, 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_CACHE z_cache /* XXX */
#define Z_STUB z_stub /* XXX */
+#define Z_FORWARD z_forward /* 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 */
+ /* zone state bits (32 bits) */
+#define Z_AUTH 0x00000001 /* zone is authoritative */
+#define Z_NEED_XFER 0x00000002 /* waiting to do xfer */
+#define Z_XFER_RUNNING 0x00000004 /* asynch. xfer is running */
+#define Z_NEED_RELOAD 0x00000008 /* waiting to do reload */
+#define Z_SYSLOGGED 0x00000010 /* have logged timeout */
+#define Z_QSERIAL 0x00000020 /* sysquery()'ing for serial number */
+#define Z_FOUND 0x00000040 /* found in boot file when reloading */
+#define Z_INCLUDE 0x00000080 /* set if include used in file */
+#define Z_DB_BAD 0x00000100 /* errors when loading file */
+#define Z_TMP_FILE 0x00000200 /* 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 */
+#define Z_DYNAMIC 0x00000400 /* allow dynamic updates */
+#define Z_NEED_DUMP 0x00000800 /* zone has changed, needs a dump */
+#define Z_NEED_SOAUPDATE 0x00001000 /* 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 */
+#define Z_XFER_ABORTED 0x00002000 /* zone transfer has been aborted */
+#define Z_XFER_GONE 0x00004000 /* zone transfer process is gone */
+#define Z_TIMER_SET 0x00008000 /* z_timer contains a valid id */
+#ifdef BIND_NOTIFY
+#define Z_NOTIFY 0x00010000 /* has an outbound notify executing */
+#endif
+#define Z_NEED_QSERIAL 0x00020000 /* we need to re-call qserial() */
+#define Z_PARENT_RELOAD 0x00040000 /* we need to reload this as parent */
+#define Z_FORWARD_SET 0x00080000 /* has forwarders been set */
/* 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 */
+#define XFER_SUCCESSAXFR 4 /* named-xfr recived a xfr */
+#define XFER_SUCCESSIXFR 5 /* named-xfr recived a ixfr */
+#define XFER_SUCCESSAXFRIXFRFILE 6 /* named-xfr received AXFR for IXFR */
+#define XFER_ISAXFR -1 /* the last XFR is AXFR */
+#define XFER_ISIXFR -2 /* the last XFR is IXFR */
+#define XFER_ISAXFRIXFR -3 /* the last XFR is AXFR but we must create IXFR base */
-/* 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 */
+ unsigned int forwarder:1; /* this entry is for a forwarder */
+ unsigned int nretry:31; /* # of times addr retried */
+ u_int32_t serial; /* valid if Q_ZSERIAL */
};
/*
@@ -357,7 +449,6 @@ struct qinfo {
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) */
@@ -375,15 +466,18 @@ struct qinfo {
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) */
+ struct zoneinfo *q_fzone; /* Forwarding zone, if any */
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()
+ int q_notifyzone; /* zone which needs another znotify()
* when the reply to this comes in.
*/
#endif
+ struct tsig_record *q_tsig; /* forwarded query's TSIG record */
+ struct tsig_record *q_nstsig; /* forwarded query's TSIG record */
};
/* q_flags bits (8 bits) */
@@ -392,9 +486,7 @@ struct qinfo {
#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 Q_NEXTADDR(qp,n) (&(qp)->q_addr[n].ns_addr)
#define RETRY_TIMEOUT 45
@@ -464,17 +556,27 @@ struct qstream {
u_int flags; /* see below */
struct qstream_xfr {
enum { s_x_base, s_x_firstsoa, s_x_zone,
- s_x_lastsoa, s_x_done }
+ s_x_lastsoa, s_x_done, s_x_adding,
+ s_x_deleting, s_x_addsoa, s_x_deletesoa }
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. */
+ type, /* type of 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. */
+ union {
+ struct namebuf *axfr; /* top np of an AXFR. */
+ struct ns_updrec *ixfr; /* top udp of an IXFR. */
+ } top;
+ int ixfr_zone;
+ u_int32_t serial; /* serial number requested in IXFR */
+ ns_tcp_tsig_state *tsig_state; /* used by ns_sign_tcp */
+ int tsig_skip; /* skip calling ns_sign_tcp
+ * during the next flush */
struct qs_x_lev { /* decompose the recursion. */
enum {sxl_ns, sxl_all, sxl_sub}
state; /* what's this level doing? */
@@ -500,6 +602,7 @@ struct qstream {
#define STREAM_CONNECT_EV 0x08
#define STREAM_DONE_CLOSE 0x10
#define STREAM_AXFR 0x20
+#define STREAM_AXFRIXFR 0x22
#define ALLOW_NETS 0x0001
#define ALLOW_HOSTS 0x0002
@@ -549,7 +652,8 @@ struct nameser {
u_int8_t xfers; /* #/xfers running right now */
};
-enum transport { primary_trans, secondary_trans, response_trans, num_trans };
+enum transport { primary_trans, secondary_trans, response_trans, update_trans,
+ num_trans };
/* types used by the parser or config routines */
@@ -573,8 +677,31 @@ typedef struct listen_info_list {
#endif
typedef RLIMIT_TYPE rlimit_type;
+struct control;
+typedef struct control *control;
+typedef LIST(struct control) controls;
+
+enum ordering { unknown_order, fixed_order, cyclic_order, random_order };
+
+#define DEFAULT_ORDERING cyclic_order
+
+typedef struct rrset_order_element {
+ int class;
+ int type;
+ char *name;
+ enum ordering order;
+ struct rrset_order_element *next;
+} *rrset_order_element ;
+
+typedef struct rrset_order_list {
+ rrset_order_element first;
+ rrset_order_element last;
+} *rrset_order_list;
+
+
typedef struct options {
u_int flags;
+ char *version;
char *directory;
char *dump_filename;
char *pid_filename;
@@ -584,12 +711,22 @@ typedef struct options {
int transfers_in;
int transfers_per_ns;
int transfers_out;
+ int serial_queries;
+ int max_log_size_ixfr;
enum axfr_format transfer_format;
long max_transfer_time_in;
struct sockaddr_in query_source;
+ struct in_addr axfr_src;
+#ifdef BIND_NOTIFY
+ int notify_count;
+ struct in_addr *also_notify;
+#endif
ip_match_list query_acl;
+ ip_match_list recursion_acl;
ip_match_list transfer_acl;
+ ip_match_list blackhole_acl;
ip_match_list topology;
+ ip_match_list sortlist;
enum severity check_names[num_trans];
u_long data_size;
u_long stack_size;
@@ -601,16 +738,15 @@ typedef struct options {
int clean_interval;
int interface_interval;
int stats_interval;
+ rrset_order_list ordering;
+ int heartbeat_interval;
+ u_int max_ncache_ttl;
+ u_int lame_ttl;
+ int minroots;
} *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 dst_key *key;
struct key_list_element *next;
} *key_list_element;
@@ -647,6 +783,7 @@ typedef struct server_config {
} server_config;
#define SERVER_INFO_BOGUS 0x01
+#define SERVER_INFO_SUPPORT_IXFR 0x02
typedef struct server_info {
struct in_addr address;
@@ -686,7 +823,9 @@ typedef enum ns_logging_categories {
ns_log_db,
ns_log_eventlib,
ns_log_packet,
+#ifdef BIND_NOTIFY
ns_log_notify,
+#endif
ns_log_cname,
ns_log_security,
ns_log_os,
@@ -694,6 +833,7 @@ typedef enum ns_logging_categories {
ns_log_maint,
ns_log_load,
ns_log_resp_checks,
+ ns_log_control,
ns_log_max_category
} ns_logging_categories;
@@ -709,9 +849,9 @@ struct map {
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 NOERROR_NODATA 15 /* only used internally by the server, used for
+ * -ve $ing non-existence of records. 15 is not
+ * a code used as yet anyway.
*/
#define NTTL 600 /* ttl for negative data: 10 minutes? */
@@ -722,24 +862,6 @@ struct map {
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
diff --git a/contrib/bind/bin/named/ns_forw.c b/contrib/bind/bin/named/ns_forw.c
index 9c72825..3a4e488 100644
--- a/contrib/bind/bin/named/ns_forw.c
+++ b/contrib/bind/bin/named/ns_forw.c
@@ -1,6 +1,6 @@
#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 $";
+static const char sccsid[] = "@(#)ns_forw.c 4.32 (Berkeley) 3/3/91";
+static const char rcsid[] = "$Id: ns_forw.c,v 8.68 1999/10/13 16:39:07 vixie Exp $";
#endif /* not lint */
/*
@@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_forw.c,v 8.34 1998/02/24 01:02:40 halley Exp $";
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -78,6 +78,7 @@ static char rcsid[] = "$Id: ns_forw.c,v 8.34 1998/02/24 01:02:40 halley Exp $";
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -95,6 +96,8 @@ static char rcsid[] = "$Id: ns_forw.c,v 8.34 1998/02/24 01:02:40 halley Exp $";
#include <isc/logging.h>
#include <isc/memcluster.h>
+#include <isc/dst.h>
+
#include "port_after.h"
#include "named.h"
@@ -122,14 +125,20 @@ 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 namebuf *np, int use_tcp, struct tsig_record *in_tsig)
{
struct qinfo *qp;
char tmpdomain[MAXDNAME];
struct sockaddr_in *nsa;
HEADER *hp;
u_int16_t id;
- int n;
+ int sendto_errno = 0;
+ int n, has_tsig, oldqlen;
+ u_char *oldqbuf;
+ u_char *smsg;
+ int smsglen, smsgsize, siglen;
+ u_char sig[TSIG_SIG_SIZE];
+ DST_KEY *key;
ns_debug(ns_log_default, 3, "ns_forw()");
@@ -155,23 +164,32 @@ ns_forw(struct databuf *nsp[], u_char *msg, int msglen,
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 (NS_ZFWDTAB(qp->q_fzone))
+ nsfwdadd(qp, NS_ZFWDTAB(qp->q_fzone));
+ if (NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY))
+ n = 0;
+ else
+ n = nslookup(nsp, qp, dname, "ns_forw");
if (n < 0) {
- ns_debug(ns_log_default, 2, "forw: nslookup reports danger");
+ if (n == -1)
+ ns_debug(ns_log_default, 2,
+ "forw: nslookup reports danger");
ns_freeqry(qp);
return (FW_SERVFAIL);
}
- if (n == 0 && !server_options->fwdtab) {
+ if (n == 0 && !NS_ZFWDTAB(qp->q_fzone)) {
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 (in_tsig != NULL)
+ qp->q_tsig = new_tsig(in_tsig->key, in_tsig->sig,
+ in_tsig->siglen);
if (use_tcp)
qp->q_flags |= Q_USEVC;
hp->id = qp->q_nsid = htons(nsid_next());
@@ -186,17 +204,16 @@ ns_forw(struct databuf *nsp[], u_char *msg, int msglen,
}
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;
- }
+ hp = (HEADER *) qp->q_msg;
+ hp->rd = (qp->q_addr[0].forwarder ? 1 : 0);
+ qp->q_addr[0].stime = tt;
#ifdef SLAVE_FORWARD
- if (NS_OPTION_P(OPTION_FORWARD_ONLY))
+ if (NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY))
schedretry(qp, (time_t)slave_retry);
else
#endif /* SLAVE_FORWARD */
- schedretry(qp, qp->q_fwd ?(2*RETRYBASE) :retrytime(qp));
+ schedretry(qp, retrytime(qp));
nsa = Q_NEXTADDR(qp, 0);
ns_debug(ns_log_default, 1,
@@ -208,10 +225,44 @@ ns_forw(struct databuf *nsp[], u_char *msg, int msglen,
? 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));
+ res_pquery(&res, msg, msglen, log_get_stream(packet_channel));
#endif
+ key = tsig_key_from_addr(nsa->sin_addr);
+ if (key != NULL) {
+ smsgsize = qp->q_msglen + TSIG_BUF_SIZE;
+ smsg = memget(smsgsize);
+ if (smsg == NULL)
+ ns_panic(ns_log_default, 1, "ns_forw: memget failed");
+ smsglen = qp->q_msglen;
+ siglen = sizeof(sig);
+ memcpy(smsg, qp->q_msg, qp->q_msglen);
+ n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0,
+ sig, &siglen, 0);
+ if (n == 0) {
+ oldqbuf = qp->q_msg;
+ oldqlen = qp->q_msglen;
+ qp->q_msglen = smsglen;
+ qp->q_msg = smsg;
+ hp = (HEADER *) qp->q_msg;
+ has_tsig = 1;
+ qp->q_nstsig = new_tsig(key, sig, siglen);
+ }
+ else {
+ has_tsig = 0;
+ free_tsig(qp->q_nstsig);
+ qp->q_nstsig = NULL;
+ INSIST(0);
+ }
+ }
+ else {
+ has_tsig = 0;
+ free_tsig(qp->q_nstsig);
+ qp->q_nstsig = NULL;
+ }
+
if (qp->q_flags & Q_USEVC) {
if (tcp_send(qp) != NOERROR) {
if (!haveComplained(ina_ulong(nsa->sin_addr),
@@ -220,20 +271,37 @@ ns_forw(struct databuf *nsp[], u_char *msg, int msglen,
"ns_forw: tcp_send(%s) failed: %s",
sin_ntoa(*nsa), strerror(errno));
}
- } else if (sendto(ds, (char *)msg, msglen, 0, (struct sockaddr *)nsa,
+ } else if (sendto(ds, (char *)qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)nsa,
sizeof(struct sockaddr_in)) < 0) {
+ sendto_errno = errno;
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 (has_tsig == 1) {
+ memput(qp->q_msg, smsgsize);
+ qp->q_msg = oldqbuf;
+ qp->q_msglen = oldqlen;
+ hp = (HEADER *) qp->q_msg;
+ }
+
if (NS_OPTION_P(OPTION_HOSTSTATS))
nameserIncr(from.sin_addr, nssRcvdFwdQ);
nameserIncr(nsa->sin_addr, nssSentFwdQ);
if (qpp)
*qpp = qp;
hp->rd = 1;
+ switch (sendto_errno) {
+ case ENETDOWN:
+ case ENETUNREACH:
+ case EHOSTDOWN:
+ case EHOSTUNREACH:
+ unsched(qp);
+ schedretry(qp, (time_t) 0);
+ }
return (0);
}
@@ -313,8 +381,6 @@ nslookupComplain(const char *sysloginfo, const char *queryname,
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);
@@ -395,13 +461,13 @@ nslookup(struct databuf *nsp[], struct qinfo *qp,
struct hashbuf *tmphtp;
char *dname;
const char *fname;
- int oldn, naddr, class, found_arr, potential_ns;
+ int oldn, naddr, class, found_arr, potential_ns, lame_ns;
time_t curtime;
ns_debug(ns_log_default, 3, "nslookup(nsp=%#x, qp=%#x, \"%s\")",
nsp, qp, syslogdname);
- potential_ns = 0;
+ lame_ns = potential_ns = 0;
naddr = n = qp->q_naddr;
curtime = (u_long) tt.tv_sec;
while ((nsdp = *nsp++) != NULL) {
@@ -421,8 +487,20 @@ nslookup(struct databuf *nsp[], struct qinfo *qp,
}
}
+ /* skip lame servers */
+ if ((nsdp->d_flags & DB_F_LAME) != 0) {
+ time_t when;
+ when = db_lame_find(qp->q_domain, nsdp);
+ if (when != 0 && when > tt.tv_sec) {
+ ns_debug(ns_log_default, 3,
+ "skipping lame NS");
+ lame_ns++;
+ goto skipserver;
+ }
+ }
+
tmphtp = ((nsdp->d_flags & DB_F_HINT) ?fcachetab :hashtab);
- np = nlookup(dname, &tmphtp, &fname, 1);
+ np = nlookup(dname, &tmphtp, &fname, 0);
if (np == NULL) {
ns_debug(ns_log_default, 3, "%s: not found %s %#x",
dname, fname, np);
@@ -430,45 +508,14 @@ nslookup(struct databuf *nsp[], struct qinfo *qp,
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;
+ goto need_sysquery;
}
found_arr = 0;
oldn = n;
/* look for name server addresses */
- delete_stale(np);
+ (void)delete_stale(np);
for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
struct in_addr nsa;
@@ -484,10 +531,7 @@ nslookup(struct databuf *nsp[], struct qinfo *qp,
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);
+ /* Negative caching element. */
goto skipserver;
}
if (ina_hlong(ina_get(dp->d_data)) == INADDR_ANY) {
@@ -553,6 +597,7 @@ nslookup(struct databuf *nsp[], struct qinfo *qp,
qs->ns_addr.sin_addr = nsa;
qs->ns = nsdp;
qs->nsdata = dp;
+ qs->forwarder = 0;
qs->nretry = 0;
/*
* If this A RR has no RTT, initialize its RTT to a
@@ -616,6 +661,10 @@ nslookup(struct databuf *nsp[], struct qinfo *qp,
if (ip_match_address(bogus_nameservers, nsa) > 0)
goto skipserver;
#endif
+ if (server_options->blackhole_acl != NULL &&
+ ip_match_address(server_options->blackhole_acl,
+ nsa) == 1)
+ continue;
n++;
if (n >= NSMAX)
@@ -629,7 +678,7 @@ nslookup(struct databuf *nsp[], struct qinfo *qp,
potential_ns++;
if (!(qp->q_flags & Q_SYSTEM))
(void) sysquery(dname, class, T_A, NULL, 0,
- QUERY);
+ ns_port, QUERY);
}
skipserver:
(void)NULL;
@@ -637,15 +686,17 @@ nslookup(struct databuf *nsp[], struct qinfo *qp,
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) {
+ if (n == 0 && potential_ns == 0 && !NS_ZFWDTAB(qp->q_fzone)) {
static char *complaint = "No possible A RRs";
+ if (lame_ns != 0)
+ complaint = "All possible A RR's lame";
if (sysloginfo && syslogdname &&
!haveComplained((u_long)syslogdname, (u_long)complaint))
{
ns_info(ns_log_default, "%s: query(%s) %s",
sysloginfo, syslogdname, complaint);
}
- return(-1);
+ return ((lame_ns == 0) ? -1 : -2);
}
/* Update the refcounts before the sort. */
for (i = naddr; i < (u_int)n; i++) {
@@ -846,14 +897,20 @@ retrytimer(evContext ctx, void *uap, struct timespec due,
*/
void
retry(struct qinfo *qp) {
- int n;
+ int n, has_tsig, oldqlen;
HEADER *hp;
struct sockaddr_in *nsa;
+ int sendto_errno = 0;
+ u_char *oldqbuf;
+ u_char *smsg;
+ int smsglen, smsgsize, siglen;
+ u_char sig[TSIG_SIG_SIZE];
+ DST_KEY *key;
ns_debug(ns_log_default, 3, "retry(%#lx) id=%d", (u_long)qp,
ntohs(qp->q_id));
- if (qp->q_msg == NULL) { /* XXX - why? */
+ if (qp->q_msg == NULL) {
qremove(qp);
return;
}
@@ -864,29 +921,25 @@ retry(struct qinfo *qp) {
(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;
+ goto fail;
}
- /* try next address */
+ /* 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);
+ do {
+ if (++n >= (int)qp->q_naddr)
+ n = 0;
+ if ((qp->q_flags & Q_ZSERIAL) != 0 &&
+ qp->q_addr[n].serial != 0)
+ continue;
+ if (qp->q_addr[n].nretry < MAXRETRY)
+ goto found;
+ } while (n != qp->q_curaddr);
+ if ((qp->q_flags & Q_ZSERIAL) != 0) {
+ qremove(qp);
+ return;
}
}
fail:
@@ -894,7 +947,7 @@ retry(struct qinfo *qp) {
* Give up. Can't reach destination.
*/
hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg);
- if (qp->q_flags & Q_PRIMING) {
+ if ((qp->q_flags & Q_PRIMING) != 0) {
/* Can't give up priming */
if (qp->q_expire < tt.tv_sec) {
/*
@@ -903,7 +956,6 @@ retry(struct qinfo *qp) {
*/
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;
@@ -920,36 +972,40 @@ retry(struct qinfo *qp) {
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;
+ if ((qp->q_flags & Q_SYSTEM) == 0) {
+ 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));
+ if (debug >= 10)
+ res_pquery(&res, 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 (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);
}
- 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)
+ if (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);
+ hp->rd = (qp->q_addr[n].forwarder ? 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"),
+ (qp->q_addr[n].forwarder ? "reforw" : "resend"),
n, qp->q_addr[n].nretry,
inet_ntoa(nsa->sin_addr),
ntohs(nsa->sin_port), ds,
@@ -959,9 +1015,38 @@ retry(struct qinfo *qp) {
: (-1));
#ifdef DEBUG
if (debug >= 10)
- fp_nquery(qp->q_msg, qp->q_msglen,
+ res_pquery(&res, qp->q_msg, qp->q_msglen,
log_get_stream(packet_channel));
#endif
+ key = tsig_key_from_addr(nsa->sin_addr);
+ if (key != NULL) {
+ smsgsize = qp->q_msglen + TSIG_BUF_SIZE;
+ smsg = memget(smsgsize);
+ smsglen = qp->q_msglen;
+ siglen = sizeof(sig);
+ memcpy(smsg, qp->q_msg, qp->q_msglen);
+ n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0,
+ sig, &siglen, 0);
+ if (n == 0) {
+ oldqbuf = qp->q_msg;
+ oldqlen = qp->q_msglen;
+ qp->q_msglen = smsglen;
+ qp->q_msg = smsg;
+ has_tsig = 1;
+ qp->q_nstsig = new_tsig(key, sig, siglen);
+ }
+ else {
+ has_tsig = 0;
+ free_tsig(qp->q_nstsig);
+ qp->q_nstsig = NULL;
+ INSIST(0);
+ }
+ } else {
+ has_tsig = 0;
+ free_tsig(qp->q_nstsig);
+ qp->q_nstsig = NULL;
+ }
+
if (qp->q_flags & Q_USEVC) {
if (tcp_send(qp) != NOERROR)
ns_debug(ns_log_default, 3,
@@ -971,18 +1056,32 @@ retry(struct qinfo *qp) {
(struct sockaddr *)nsa,
sizeof(struct sockaddr_in)) < 0)
{
+ sendto_errno = errno;
ns_debug(ns_log_default, 3, "error resending msg: %s",
strerror(errno));
}
+ if (has_tsig == 1) {
+ memput(qp->q_msg, smsgsize);
+ qp->q_msg = oldqbuf;
+ qp->q_msglen = oldqlen;
+ }
hp->rd = 1; /* leave set to 1 for dup detection */
nameserIncr(nsa->sin_addr, nssSentDupQ);
unsched(qp);
+ switch (sendto_errno) {
+ case ENETDOWN:
+ case ENETUNREACH:
+ case EHOSTDOWN:
+ case EHOSTUNREACH:
+ schedretry(qp, (time_t) 0);
+ return;
+ }
#ifdef SLAVE_FORWARD
- if (NS_OPTION_P(OPTION_FORWARD_ONLY))
+ if (NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY))
schedretry(qp, (time_t)slave_retry);
else
#endif /* SLAVE_FORWARD */
- schedretry(qp, qp->q_fwd ? (2*RETRYBASE) : retrytime(qp));
+ schedretry(qp, retrytime(qp));
}
/*
@@ -1020,16 +1119,10 @@ qflush() {
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);
+ if ((qp->q_flags & Q_ZSERIAL) != 0)
+ qserial_answer(qp);
unsched(qp);
ns_freeqry(qp);
}
@@ -1049,10 +1142,12 @@ qfindid(u_int16_t id) {
struct qinfo *
qnew(const char *name, int class, int type) {
struct qinfo *qp;
+ const char *s;
+ int escape = 0;
qp = (struct qinfo *)memget(sizeof *qp);
if (qp == NULL)
- panic("qnew: memget failed", NULL);
+ ns_panic(ns_log_default, 1, "qnew: memget failed");
memset(qp, 0, sizeof *qp);
ns_debug(ns_log_default, 5, "qnew(%#lx)", (u_long)qp);
#ifdef BIND_NOTIFY
@@ -1064,6 +1159,21 @@ qnew(const char *name, int class, int type) {
qp->q_class = (u_int16_t)class;
qp->q_type = (u_int16_t)type;
qp->q_flags = 0;
+ s = name;
+ for (;;) { /* find forwarding zone, if any */
+ if ((qp->q_fzone = find_zone(s, class)) != NULL &&
+ (qp->q_fzone->z_flags & Z_FORWARD_SET) != 0)
+ break;
+ qp->q_fzone = NULL;
+ if (*s == '\0')
+ break;
+ while (*s != '\0' && (escape || *s != '.')) {
+ escape = escape ? 0 : (*s == '\\');
+ s++;
+ }
+ if (*s != '\0')
+ s++;
+ }
return (qp);
}
@@ -1101,7 +1211,6 @@ ns_freeqns(struct qinfo *qp, char *where) {
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)
@@ -1115,6 +1224,10 @@ ns_freeqry(struct qinfo *qp) {
freestr(qp->q_domain);
if (qp->q_name != NULL)
freestr(qp->q_name);
+ if (qp->q_tsig != NULL)
+ memput(qp->q_tsig, sizeof(struct tsig_record));
+ if (qp->q_nstsig != NULL)
+ memput(qp->q_nstsig, sizeof(struct tsig_record));
ns_freeqns(qp, "ns_freeqry");
if (nsqhead == qp)
nsqhead = qp->q_link;
@@ -1130,3 +1243,27 @@ ns_freeqry(struct qinfo *qp) {
}
memput(qp, sizeof *qp);
}
+
+void
+nsfwdadd(struct qinfo *qp, struct fwdinfo *fwd) {
+ int i, n;
+ struct qserv *qs;
+
+ n = qp->q_naddr;
+ while (fwd != NULL && n < MAXNS) {
+ qs = qp->q_addr;
+ for (i = 0; i < (u_int)n; i++, qs++)
+ if (ina_equal(qs->ns_addr.sin_addr,
+ fwd->fwdaddr.sin_addr))
+ goto nextfwd;
+ qs->ns_addr = fwd->fwdaddr;
+ qs->ns = NULL;
+ qs->nsdata = NULL;
+ qs->forwarder = 1;
+ qs->nretry = 0;
+ n++;
+ nextfwd:
+ fwd = fwd->next;
+ }
+ qp->q_naddr = n;
+}
diff --git a/contrib/bind/bin/named/ns_func.h b/contrib/bind/bin/named/ns_func.h
index bf58528..88c181ca 100644
--- a/contrib/bind/bin/named/ns_func.h
+++ b/contrib/bind/bin/named/ns_func.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 1985, 1990
+/*
+ * Copyright (c) 1985, 1990
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +31,8 @@
* SUCH DAMAGE.
*/
-/* Portions Copyright (c) 1993 by Digital Equipment Corporation.
+/*
+ * 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
@@ -49,7 +51,8 @@
* SOFTWARE.
*/
-/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+/*
+ * Portions Copyright (c) 1996-1999 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
@@ -65,14 +68,35 @@
* SOFTWARE.
*/
+/*
+ * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc.
+ *
+ * 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 Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES
+ * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED
+ * 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 $
+ * $Id: ns_func.h,v 8.90 1999/10/11 18:22:20 vixie Exp $
*/
/* ++from ns_glue.c++ */
extern struct in_addr ina_get(const u_char *data);
extern const char *sin_ntoa(struct sockaddr_in);
+extern int ns_wouldlog(int category, int level);
extern void ns_debug(int, int, const char *, ...),
ns_info(int, const char *, ...),
ns_notice(int, const char *, ...),
@@ -92,6 +116,9 @@ extern char *__newstr(size_t, int),
*__savestr(const char *, int),
*checked_ctime(const time_t *t),
*ctimel(long);
+extern void __freestr_record(char *, char *, int);
+extern char *__newstr_record(size_t, int, char *, int);
+extern char *__savestr_record(const char *, int, char *, int);
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, ...);
@@ -103,21 +130,34 @@ extern void debug_freestr(char *, const char *, int);
#define savestr(s, n) debug_savestr((s), (n), __FILE__, __LINE__)
#define freestr(s) debug_freestr((s), __FILE__, __LINE__)
#else
+#ifdef RECORD_STRINGS
+#define newstr(l, n) __newstr_record((l), (n), __FILE__, __LINE__)
+#define savestr(s, n) __savestr_record((s), (n), __FILE__, __LINE__)
+#define freestr(s) __freestr_record((s), __FILE__, __LINE__)
+#else
#define newstr(l, n) __newstr((l), (n))
#define savestr(s, n) __savestr((s), (n))
#define freestr(s) __freestr((s))
+#endif
#endif /* DEBUG_STRINGS */
+int movefile(const char *, const char *);
/* --from ns_glue.c-- */
+/* ++from ns_notify.c++ */
+#ifdef BIND_NOTIFY
+void ns_notify(const char *, ns_class, ns_type);
+void ns_unnotify(void);
+#endif
+/* --from ns_notify.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 *);
+ delete_all(struct namebuf *, int, int);
+extern 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);
+ struct in_addr *, int, u_int16_t, 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 *),
@@ -125,7 +165,6 @@ extern int doupdate(u_char *, u_char *, struct databuf **,
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 *),
@@ -142,7 +181,7 @@ extern void ns_req(u_char *, int, int,
extern int stale(struct databuf *),
make_rr(const char *, struct databuf *,
u_char *, int, int,
- u_char **, u_char **),
+ u_char **, u_char **, int),
doaddinfo(HEADER *, u_char *, int),
doaddauth(HEADER *, u_char *, int,
struct namebuf *,
@@ -154,13 +193,33 @@ extern int findZonePri(const struct zoneinfo *,
/* --from ns_req.c-- */
/* ++from ns_xfr.c++ */
-extern void ns_xfr(struct qstream *qsp, struct namebuf *znp,
+void ns_xfr(struct qstream *qsp, struct namebuf *znp,
int zone, int class, int type,
- int id, int opcode),
+ int id, int opcode, u_int32_t serial_ixfr,
+ struct tsig_record *in_tsig),
ns_stopxfrs(struct zoneinfo *),
- ns_freexfr(struct qstream *);
+ ns_freexfr(struct qstream *),
+ sx_newmsg(struct qstream *qsp),
+ sx_sendlev(struct qstream *qsp),
+ sx_sendsoa(struct qstream *qsp);
/* --from ns_xfr.c-- */
+/* ++from ns_ctl.c++ */
+void ns_ctl_initialize(void);
+void ns_ctl_shutdown(void);
+void ns_ctl_defaults(controls *);
+void ns_ctl_add(controls *, control);
+control ns_ctl_new_inet(struct in_addr, u_int, ip_match_list);
+#ifndef WINNT
+control ns_ctl_new_unix(char *, mode_t, uid_t, gid_t);
+#endif
+void ns_ctl_install(controls *);
+/* --from ns_ctl.c-- */
+
+/* ++from ns_ixfr.c++ */
+void sx_send_ixfr(struct qstream *qsp);
+/* --from ns_ixfr.c-- */
+
/* ++from ns_forw.c++ */
extern time_t retrytime(struct qinfo *);
extern int ns_forw(struct databuf *nsp[],
@@ -174,7 +233,8 @@ extern int ns_forw(struct databuf *nsp[],
int class,
int type,
struct namebuf *np,
- int use_tcp),
+ int use_tcp,
+ struct tsig_record *in_tsig),
haveComplained(u_long, u_long),
nslookup(struct databuf *nsp[],
struct qinfo *qp,
@@ -191,7 +251,8 @@ extern void schedretry(struct qinfo *, time_t),
qremove(struct qinfo *),
ns_freeqns(struct qinfo *, char *),
ns_freeqry(struct qinfo *),
- freeComplaints(void);
+ freeComplaints(void),
+ nsfwdadd(struct qinfo *, struct fwdinfo *);
extern struct qinfo *qfindid(u_int16_t),
*qnew(const char *, int, int);
/* --from ns_forw.c-- */
@@ -209,59 +270,82 @@ extern void sq_remove(struct qstream *),
nsid_init(void),
ns_setoption(int option),
writestream(struct qstream *, const u_char *, int),
- ns_need(int need),
- opensocket_f(void);
+ ns_need_unsafe(enum need),
+ ns_need(enum need),
+ opensocket_f(void),
+ nsid_hash(u_char *, size_t);
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 *),
+extern void zone_maint(struct zoneinfo *),
sched_zone_maint(struct zoneinfo *),
ns_cleancache(evContext ctx, void *uap,
struct timespec due,
struct timespec inter),
+ clean_cache_from(char *dname, struct hashbuf *htp),
+ remove_zone(struct zoneinfo *, const char *),
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),
+ qserial_answer(struct qinfo *),
#ifdef DEBUG
printzoneinfo(int, int, int),
#endif
endxfer(void),
- ns_reload(void);
+ addxfer(struct zoneinfo *),
+ ns_zreload(void),
+ ns_reload(void),
+ ns_reconfig(void);
+#if 0
+extern int reload_all_unsafe(void);
+#endif
+extern int zonefile_changed_p(struct zoneinfo *);
+int reload_master(struct zoneinfo *);
+extern const char * deferred_reload_unsafe(struct zoneinfo *);
+extern struct namebuf * purge_node(struct hashbuf *htp, struct namebuf *np);
extern int clean_cache(struct hashbuf *, int);
-extern void reapchild(evContext, void *, int);
-extern const char * zoneTypeString(const struct zoneinfo *);
+extern void reapchild(void);
+extern const char * zoneTypeString(unsigned int);
+extern void ns_heartbeat(evContext ctx, void *uap,
+ struct timespec, struct timespec);
+extern void make_new_zones(void);
+extern void free_zone(struct zoneinfo *);
+extern struct zoneinfo *find_auth_zone(const char *, ns_class);
/* --from ns_maint.c-- */
+/* ++from ns_sort.c++ */
+extern void sort_response(u_char *, u_char *, int,
+ struct sockaddr_in *);
+/* --from ns_sort.c-- */
+
/* ++from ns_init.c++ */
-extern void ns_refreshtime(struct zoneinfo *, time_t),
- ns_retrytime(struct zoneinfo *, time_t),
- ns_init(const char *);
+extern void ns_refreshtime(struct zoneinfo *, time_t);
+extern void ns_retrytime(struct zoneinfo *, time_t);
+extern void ns_init(const char *);
+extern void purgeandload(struct zoneinfo *zp);
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,
+extern int ns_nameok(const struct qinfo *qry, 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);
+extern void zoneinit(struct zoneinfo *);
+extern void do_reload(const char *, int, int, int);
+extern void ns_shutdown(void);
/* --from ns_init.c-- */
/* ++from ns_ncache.c++ */
-extern void cache_n_resp(u_char *, int, struct sockaddr_in);
+extern void cache_n_resp(u_char *, int, struct sockaddr_in,
+ const char *, int, int);
/* --from ns_ncache.c-- */
/* ++from ns_udp.c++ */
@@ -280,42 +364,56 @@ extern struct nameser *nameserFind(struct in_addr addr, int flags);
/* --from ns_stats.c-- */
/* ++from ns_update.c++ */
-u_char *findsoaserial(u_char *data);
+void free_rrecp(ns_updque *, int rcode, struct sockaddr_in);
+int findzone(const char *, int, int, int *, int);
+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);
+int merge_logs(struct zoneinfo *zp, char *logname);
+int zonedump(struct zoneinfo *zp, int isixfr);
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);
+ int dfd, struct sockaddr_in from,
+ struct tsig_record *in_tsig);
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);
+struct zoneinfo * find_zone(const char *, 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);
+#ifdef BIND_NOTIFY
int set_zone_notify(zone_config, int value);
+#endif
+int set_zone_maintain_ixfr_base(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_pubkey(zone_config, const int, const int,
+ const int, const char *);
int set_zone_transfer_time_in(zone_config, long);
int add_zone_master(zone_config, struct in_addr);
+#ifdef BIND_NOTIFY
int add_zone_notify(zone_config, struct in_addr);
+#endif
+void set_zone_forward(zone_config);
+void add_zone_forwarder(zone_config, struct in_addr);
+void set_zone_boolean_option(zone_config, int, int);
options new_options(void);
void free_options(options);
-void set_boolean_option(options, int, int);
+void free_rrset_order_list(rrset_order_list);
+void set_global_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);
@@ -323,11 +421,15 @@ FILE * write_open(char *filename);
void update_pid_file(void);
void set_options(options, int);
void use_default_options(void);
+enum ordering lookup_ordering(const char *);
+rrset_order_list new_rrset_order_list(void);
+rrset_order_element new_rrset_order_element(int, int, char *, enum ordering);
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_key(struct dst_key *dst_key);
ip_match_element new_ip_match_localhost(void);
ip_match_element new_ip_match_localnets(void);
void ip_match_negate(ip_match_element);
@@ -335,12 +437,22 @@ 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_match_addr_or_key(ip_match_list, struct in_addr,
+ struct dst_key *key);
int ip_address_allowed(ip_match_list, struct in_addr);
+int ip_addr_or_key_allowed(ip_match_list iml,
+ struct in_addr,
+ struct dst_key *key);
int ip_match_network(ip_match_list, struct in_addr,
struct in_addr);
+int ip_match_key_name(ip_match_list iml, char *name);
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);
+#ifdef BIND_NOTIFY
+void free_also_notify(options);
+int add_global_also_notify(options, struct in_addr);
+#endif
+void add_global_forwarder(options, struct in_addr);
void free_forwarders(struct fwdinfo *);
server_info find_server(struct in_addr);
server_config begin_server(struct in_addr);
@@ -349,13 +461,14 @@ 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);
+void add_server_key_info(server_config, struct dst_key *);
+struct dst_key *new_key_info(char *, char *, char *);
+void free_key_info(struct dst_key *);
+struct dst_key *find_key(char *name, char *algorithm);
+void dprint_key_info(struct dst_key *);
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 add_to_key_info_list(key_info_list, struct dst_key *);
void dprint_key_info_list(key_info_list);
log_config begin_logging(void);
void add_log_channel(log_config, int, log_channel);
@@ -372,9 +485,14 @@ void load_configuration(const char *);
/* ++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);
+struct dst_key *lookup_key(char *);
+void define_key(char *, struct dst_key *);
void parse_configuration(const char *);
void parser_initialize(void);
void parser_shutdown(void);
/* --from parser.y-- */
+/* ++from ns_signal.c++ */
+void init_signals(void);
+void block_signals(void);
+void unblock_signals(void);
+/* --from ns_signal.c-- */
diff --git a/contrib/bind/bin/named/ns_glob.h b/contrib/bind/bin/named/ns_glob.h
index 8f39c84..b977f7b 100644
--- a/contrib/bind/bin/named/ns_glob.h
+++ b/contrib/bind/bin/named/ns_glob.h
@@ -1,9 +1,10 @@
/*
* from ns.h 4.33 (Berkeley) 8/23/90
- * $Id: ns_glob.h,v 8.35 1998/05/05 19:44:20 halley Exp $
+ * $Id: ns_glob.h,v 8.51 1999/10/15 21:53:32 vixie Exp $
*/
-/* Copyright (c) 1986
+/*
+ * Copyright (c) 1986
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,7 +36,8 @@
* SUCH DAMAGE.
*/
-/* Portions Copyright (c) 1993 by Digital Equipment Corporation.
+/*
+ * 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
@@ -54,7 +56,8 @@
* SOFTWARE.
*/
-/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+/*
+ * Portions Copyright (c) 1996-1999 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
@@ -74,6 +77,9 @@
* Global variables for the name server.
*/
+ /* original argv[] from main() */
+DECL char **saved_argv;
+
#ifdef DEBUG
DECL int debug INIT(0);
DECL int desired_debug INIT(0);
@@ -82,6 +88,9 @@ DECL int desired_debug INIT(0);
/* global event context */
DECL evContext ev;
+ /* global resolver context. */
+DECL struct __res_state res;
+
/* list of open streams */
DECL struct qstream *streamq;
@@ -117,17 +126,23 @@ DECL time_t resettime;
DECL struct qinfo *retryqp;
/* default configuration file */
-DECL char *conffile INIT(NULL);
+DECL char *conffile;
/* default debug output file */
-DECL const char *debugfile INIT(_PATH_DEBUG);
+DECL char *debugfile;
/* zone information */
DECL struct zoneinfo *zones;
- /* number of zones in use */
+ /* number of zones allocated */
DECL int nzones;
+ /* free list of unused zones[] elements. */
+DECL LIST(struct zoneinfo) freezones;
+
+ /* list of zones that have a reload pending. */
+DECL LIST(struct zoneinfo) reloadingzones;
+
/* set if we need a priming */
DECL int needs_prime_cache;
@@ -192,8 +207,9 @@ 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);
+DECL key_info_list secretkey_info INIT(NULL);
- /* These will disappear some day in favour of "struct nameser". */
+DECL int main_needs_exit INIT(0);
DECL ip_match_list bogus_nameservers INIT(NULL);
DECL log_context log_ctx;
@@ -210,7 +226,6 @@ 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[]
@@ -281,7 +296,9 @@ DECL const struct ns_sym category_constants[]
{ ns_log_db, "db" },
{ ns_log_eventlib, "eventlib" },
{ ns_log_packet, "packet" },
+#ifdef BIND_NOTIFY
{ ns_log_notify, "notify" },
+#endif
{ ns_log_cname, "cname" },
{ ns_log_security, "security" },
{ ns_log_os, "os" },
@@ -289,6 +306,7 @@ DECL const struct ns_sym category_constants[]
{ ns_log_maint, "maintenance" },
{ ns_log_load, "load" },
{ ns_log_resp_checks, "response-checks" },
+ { ns_log_control, "control" },
{ 0, NULL }
}
#endif
@@ -308,6 +326,7 @@ DECL u_long globalStats[nssLast];
DECL evTimerID clean_timer;
DECL evTimerID interface_timer;
DECL evTimerID stats_timer;
+DECL evTimerID heartbeat_timer;
DECL int active_timers INIT(0);
DECL uid_t user_id;
@@ -317,3 +336,7 @@ DECL char * group_name INIT(NULL);
DECL char * chroot_dir INIT(NULL);
DECL int loading INIT(0);
+
+DECL int xfers_running INIT(0);
+DECL int xfers_deferred INIT(0);
+DECL int qserials_running INIT(0);
diff --git a/contrib/bind/bin/named/ns_glue.c b/contrib/bind/bin/named/ns_glue.c
index 460b64d..4b7972c 100644
--- a/contrib/bind/bin/named/ns_glue.c
+++ b/contrib/bind/bin/named/ns_glue.c
@@ -1,9 +1,9 @@
#if !defined(lint) && !defined(SABER)
-static char rcsid[] = "$Id: ns_glue.c,v 8.7 1998/02/13 19:51:45 halley Exp $";
+static const char rcsid[] = "$Id: ns_glue.c,v 8.14 1999/10/19 02:06:26 gson Exp $";
#endif /* not lint */
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-1999 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
@@ -24,6 +24,7 @@ static char rcsid[] = "$Id: ns_glue.c,v 8.7 1998/02/13 19:51:45 halley Exp $";
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/uio.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -88,6 +89,13 @@ sin_ntoa(struct sockaddr_in sin) {
* Logging Support
*/
+int
+ns_wouldlog(int category, int level) {
+ if (log_ctx_valid)
+ return (log_check(log_ctx, category, level));
+ return (0);
+}
+
void
ns_debug(int category, int level, const char *format, ...) {
va_list args;
@@ -279,7 +287,7 @@ my_fclose(FILE *fp) {
s = fclose(fp);
if (s < 0)
- ns_info(ns_log_default, "fclose(%d) failed: %m", fd,
+ ns_info(ns_log_default, "fclose(%d) failed: %s", fd,
strerror(errno));
else
ns_debug(ns_log_default, 3, "fclose(%d) succeeded", fd);
@@ -303,6 +311,21 @@ savebuf(const u_char *buf, size_t len, int needpanic) {
return (bp);
}
+char *
+__newstr(size_t len, int needpanic) {
+ return (__newstr_record(len, needpanic, __FILE__, __LINE__));
+}
+
+char *
+__savestr(const char *str, int needpanic) {
+ return (__savestr_record(str, needpanic, __FILE__, __LINE__));
+}
+
+void
+__freestr(char *str) {
+ __freestr_record(str, __FILE__, __LINE__);
+}
+
#ifdef DEBUG_STRINGS
char *
debug_newstr(size_t len, int needpanic, const char *file, int line) {
@@ -310,7 +333,7 @@ debug_newstr(size_t len, int needpanic, const char *file, int line) {
size = len + 3; /* 2 length bytes + NUL. */
printf("%s:%d: newstr %d\n", file, line, size);
- return (__newstr(len, needpanic));
+ return (__newstr_record(len, needpanic, file, line));
}
char *
@@ -320,7 +343,7 @@ debug_savestr(const char *str, int needpanic, const char *file, int line) {
len = strlen(str);
len += 3; /* 2 length bytes + NUL. */
printf("%s:%d: savestr %d %s\n", file, line, len, str);
- return (__savestr(str, needpanic));
+ return (__savestr_record(str, needpanic, file, line));
}
void
@@ -333,7 +356,7 @@ debug_freestr(char *str, const char *file, int line) {
NS_GET16(len, bp);
len += 3; /* 2 length bytes + NUL. */
printf("%s:%d: freestr %d %s\n", file, line, len, str);
- __freestr(str);
+ __freestr_record(str, file, line);
return;
}
#endif /* DEBUG_STRINGS */
@@ -342,12 +365,12 @@ debug_freestr(char *str, const char *file, int line) {
* Return a counted string buffer big enough for a string of length 'len'.
*/
char *
-__newstr(size_t len, int needpanic) {
+__newstr_record(size_t len, int needpanic, char *file, int line) {
u_char *buf, *bp;
REQUIRE(len <= 65536);
- buf = (u_char *)memget(2/*Len*/ + len + 1/*Nul*/);
+ buf = (u_char *)__memget_record(2/*Len*/ + len + 1/*Nul*/, file, line);
if (buf == NULL) {
if (needpanic)
panic("savestr: memget failed (%s)", strerror(errno));
@@ -363,7 +386,7 @@ __newstr(size_t len, int needpanic) {
* Save a NUL terminated string and return a pointer to it.
*/
char *
-__savestr(const char *str, int needpanic) {
+__savestr_record(const char *str, int needpanic, char *file, int line) {
char *buf;
size_t len;
@@ -375,20 +398,20 @@ __savestr(const char *str, int needpanic) {
else
return (NULL);
}
- buf = __newstr(len, needpanic);
+ buf = __newstr_record(len, needpanic, file, line);
memcpy(buf, str, len + 1);
return (buf);
}
void
-__freestr(char *str) {
+__freestr_record(char *str, char *file, int line) {
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*/);
+ __memput_record(buf, 2/*Len*/ + len + 1/*Nul*/, file, line);
}
char *
@@ -414,3 +437,14 @@ ctimel(long l) {
return (checked_ctime(&t));
}
+
+/*
+ * rename() is lame (can't overwrite an existing file) on some systems.
+ * use movefile() instead, and let lame OS ports do what they need to.
+ */
+#ifndef HAVE_MOVEFILE
+int
+movefile(const char *oldname, const char *newname) {
+ return (rename(oldname, newname));
+}
+#endif
diff --git a/contrib/bind/bin/named/ns_init.c b/contrib/bind/bin/named/ns_init.c
index 920bfeb..cc95ce6 100644
--- a/contrib/bind/bin/named/ns_init.c
+++ b/contrib/bind/bin/named/ns_init.c
@@ -1,6 +1,6 @@
#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 $";
+static const char sccsid[] = "@(#)ns_init.c 4.38 (Berkeley) 3/21/91";
+static const char rcsid[] = "$Id: ns_init.c,v 8.63 1999/10/15 19:49:04 vixie Exp $";
#endif /* not lint */
/*
@@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_init.c,v 8.40 1998/04/07 18:11:58 halley Exp $";
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -79,6 +79,7 @@ static char rcsid[] = "$Id: ns_init.c,v 8.40 1998/04/07 18:11:58 halley Exp $";
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -97,6 +98,8 @@ static char rcsid[] = "$Id: ns_init.c,v 8.40 1998/04/07 18:11:58 halley Exp $";
#include <isc/logging.h>
#include <isc/memcluster.h>
+#include <isc/dst.h>
+
#include "port_after.h"
#include "named.h"
@@ -138,25 +141,37 @@ ns_init(const char *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. */
+ /* Init zone data. */
+ zones = NULL;
+ INIT_LIST(freezones);
+ INIT_LIST(reloadingzones);
+ nzones = 0;
+ make_new_zones();
+
+ /* Init cache. */
+ zones[0].z_type = z_cache;
+ zones[0].z_origin = savestr("", 1);
+
+ /* Allocate cache hash table, formerly the root hash table. */
hashtab = savehash((struct hashbuf *)NULL);
- /* allocate root-hints/file-cache hash table */
+ /* 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 other misc stuff. */
+ dst_init();
init_configuration();
} else {
/* Mark previous zones as not yet found in boot file. */
+ block_signals();
for (zp = &zones[1]; zp < &zones[nzones]; zp++)
- zp->z_flags &= ~Z_FOUND;
+ if (zp->z_type != z_nil) {
+ zp->z_flags &= ~Z_FOUND;
+ if (LINKED(zp, z_reloadlink))
+ UNLINK(reloadingzones, zp,
+ z_reloadlink);
+ }
+ unblock_signals();
}
#ifdef DEBUG
@@ -169,26 +184,20 @@ ns_init(const char *conffile) {
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));
+ for (zp = &zones[0]; zp < &zones[nzones]; zp++) {
+ if (zp->z_type == z_cache)
+ continue;
+ if (zp->z_type != z_nil && (zp->z_flags & Z_FOUND) == 0)
+ remove_zone(zp, "removed");
+ }
+ /* Reload parent zones of zones removed */
+ for (zp = &zones[0]; zp < &zones[nzones]; zp++) {
+ if (zp->z_type == z_cache)
+ continue;
+ if (zp->z_type != z_nil &&
+ (zp->z_flags & Z_PARENT_RELOAD) != 0) {
+ zp->z_flags &= ~Z_PARENT_RELOAD;
+ purgeandload(zp);
}
}
@@ -215,20 +224,22 @@ zoneinit(struct zoneinfo *zp) {
* we will refresh the zone from a primary
* immediately.
*/
- if (!zp->z_source)
+ if (zp->z_source == NULL)
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)) {
+ if (result == -1 ||
+ db_load(zp->z_source, zp->z_origin, zp, NULL, ISNOTIXFR))
+ {
/*
* 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))) {
+ if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0) {
zp->z_time = tt.tv_sec;
sched_zone_maint(zp);
}
@@ -240,12 +251,17 @@ zoneinit(struct zoneinfo *zp) {
}
}
+/*
+ * Purge the zone and reload all parent zones. This needs to be done when
+ * we unload a zone, since the child zone will have stomped the parent's
+ * delegation to that child when it was first loaded.
+ */
void
-do_reload(const char *domain, int type, int class) {
+do_reload(const char *domain, int type, int class, int mark) {
struct zoneinfo *zp;
- ns_debug(ns_log_config, 1, "do_reload: %s %d %d",
- *domain ? domain : ".", type, class);
+ ns_debug(ns_log_config, 1, "do_reload: %s %d %d %d",
+ *domain ? domain : ".", type, class, mark);
/*
* Check if the zone has changed type. If so, we might not need to
@@ -259,15 +275,11 @@ do_reload(const char *domain, int type, int class) {
*
* 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)
- )
+ zp = find_zone(domain, class);
+ if (zp != NULL &&
+ (type != z_master && zp->z_type == z_master) ||
+ (type != z_slave && zp->z_type == z_slave && zp->z_serial != 0) ||
+ (type != z_stub && zp->z_type == z_stub && zp->z_serial != 0))
return;
/*
@@ -301,49 +313,51 @@ do_reload(const char *domain, int type, int class) {
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))) {
-
+ zp = find_zone(domain, class);
+ if (zp != NULL) {
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);
+ if (mark)
+ zp->z_flags |= Z_PARENT_RELOAD;
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;
- }
+ purgeandload(zp);
break;
}
}
}
+void
+purgeandload(struct zoneinfo *zp) {
+ if (zp->z_type == Z_HINT)
+ 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, ISNOTIXFR) == 0)
+ zp->z_flags |= Z_AUTH;
+ break;
+ case Z_HINT:
+ case Z_CACHE:
+ (void)db_load(zp->z_source, zp->z_origin, zp, 0, ISNOTIXFR);
+ 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++) {
+ for (i = 0; i <= end; i++) {
printzoneinfo(i, ns_log_config, level);
}
}
@@ -353,7 +367,8 @@ enum context
ns_ptrcontext(owner)
const char *owner;
{
- if (samedomain(owner, "in-addr.arpa") || samedomain(owner, "ip6.int"))
+ if (ns_samedomain(owner, "in-addr.arpa") ||
+ ns_samedomain(owner, "ip6.int"))
return (hostname_ctx);
return (domain_ctx);
}
@@ -370,6 +385,7 @@ ns_ownercontext(type, transport)
case T_WKS:
case T_MX:
switch (transport) {
+ case update_trans:
case primary_trans:
case secondary_trans:
context = owner_ctx;
@@ -394,8 +410,8 @@ ns_ownercontext(type, transport)
}
int
-ns_nameok(const char *name, int class, struct zoneinfo *zp,
- enum transport transport,
+ns_nameok(const struct qinfo *qry, const char *name, int class,
+ struct zoneinfo *zp, enum transport transport,
enum context context,
const char *owner,
struct in_addr source)
@@ -428,19 +444,45 @@ ns_nameok(const char *name, int class, struct zoneinfo *zp,
"unexpected context %d in ns_nameok", (int)context);
}
if (!ok) {
- char *s, *o;
+ char *q, *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);
+ sizeof " from [000.000.000.000] for [000.000.000.000]", 0);
if (s)
- sprintf(s, "%s from [%s]",
+ if ( (transport == response_trans) &&
+ (qry != NULL) ) {
+
+ if ( qry->q_flags & Q_PRIMING ) {
+ sprintf(s, "%s from [%s] for priming",
+ transport_strings[transport],
+ inet_ntoa(source));
+ } else if ( qry->q_flags & Q_ZSERIAL ) {
+ sprintf(s, "%s from [%s] for soacheck",
transport_strings[transport],
inet_ntoa(source));
+ } else if ( qry->q_flags & Q_SYSTEM ) {
+ sprintf(s, "%s from [%s] for sysquery",
+ transport_strings[transport],
+ inet_ntoa(source));
+ } else {
+ q=strdup(inet_ntoa(qry->q_from.sin_addr));
+ sprintf(s, "%s from [%s] for [%s]",
+ transport_strings[transport],
+ inet_ntoa(source),
+ q != NULL ? q : "memget failed");
+ free(q);
+ }
+
+ } else {
+ sprintf(s, "%s from [%s]",
+ transport_strings[transport],
+ inet_ntoa(source));
+ }
}
- if (strcasecmp(owner, name) == 0)
+ if (ns_samename(owner, name) == 1)
o = savestr("", 0);
else {
const char *t = (*owner == '\0') ? "." : owner;
@@ -454,8 +496,11 @@ ns_nameok(const char *name, int class, struct zoneinfo *zp,
* the message formatting and arguments.
*/
log_write(log_ctx, ns_log_default,
- (transport == response_trans) ?
- log_info : log_notice,
+ (transport != response_trans) ||
+ (o == NULL) || (s == NULL) ||
+ ( (qry != NULL) &&
+ (qry->q_flags & (Q_PRIMING|Q_ZSERIAL)) ) ?
+ log_warning : log_info,
"%s name \"%s\"%s %s (%s) is invalid - %s",
context_strings[context],
name, o != NULL ? o : "[memget failed]",
@@ -484,29 +529,36 @@ void
ns_shutdown() {
struct zoneinfo *zp;
+#ifdef BIND_NOTIFY
+ ns_unnotify();
+#endif
/* Erase zones. */
for (zp = &zones[0]; zp < &zones[nzones]; zp++) {
if (zp->z_type) {
- if (zp->z_type != z_hint) {
+ if (zp->z_type != z_hint && zp->z_type != z_cache) {
ns_stopxfrs(zp);
purge_zone(zp->z_origin, hashtab, zp->z_class);
- }
+ } else if (zp->z_type == z_hint)
+ purge_zone(zp->z_origin, fcachetab,
+ 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);
+ hashtab = NULL;
clean_cache(fcachetab, 1);
fcachetab->h_cnt = 0; /* ??? */
rm_hash(fcachetab);
+ fcachetab = NULL;
+
+ if (zones != NULL)
+ memput(zones, nzones * sizeof *zones);
+ zones = NULL;
-#ifdef BIND_NOTIFY
- db_cancel_pending_notifies();
-#endif
freeComplaints();
shutdown_configuration();
}
diff --git a/contrib/bind/bin/named/ns_ixfr.c b/contrib/bind/bin/named/ns_ixfr.c
new file mode 100644
index 0000000..76dbe6e
--- /dev/null
+++ b/contrib/bind/bin/named/ns_ixfr.c
@@ -0,0 +1,563 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ns_ixfr.c,v 8.17 1999/11/05 04:48:28 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc.
+ *
+ * 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 Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES
+ * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED
+ * 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/stat.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 <res_update.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 void sx_new_ixfrmsg(struct qstream * qsp);
+void sx_send_ixfr(struct qstream * qsp);
+
+static int sx_flush(struct qstream * qsp),
+ sx_addrr(struct qstream * qsp,
+ const char *dname,
+ struct databuf * dp);
+extern void sx_sendsoa(struct qstream * qsp);
+
+/*
+ * u_char * sx_new_ixfrmsg(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_new_ixfrmsg(struct qstream *qsp) {
+ HEADER * hp = (HEADER *) qsp->xfr.msg;
+ ns_updrec * up;
+
+ memset(hp, 0, HFIXEDSZ);
+ hp->id = htons(qsp->xfr.id);
+ hp->opcode = qsp->xfr.opcode;
+ hp->qr = 1;
+ hp->aa = 1;
+ hp->rcode = NOERROR;
+
+ qsp->xfr.ptrs[0] = qsp->xfr.msg;
+ qsp->xfr.ptrs[1] = NULL;
+
+ qsp->xfr.cp = qsp->xfr.msg + HFIXEDSZ;
+ if (qsp->xfr.ixfr_zone == 0) {
+ int count, n;
+ int buflen;
+ struct namebuf *np;
+ struct hashbuf *htp;
+ struct zoneinfo *zp;
+ struct databuf *dp;
+ const char * fname;
+ u_char ** edp = qsp->xfr.ptrs +
+ sizeof qsp->xfr.ptrs / sizeof(u_char *);
+
+ qsp->xfr.ixfr_zone = qsp->xfr.zone;
+ zp = &zones[qsp->xfr.zone];
+ up = qsp->xfr.top.ixfr;
+ n = dn_comp(zp->z_origin, qsp->xfr.cp,
+ XFER_BUFSIZE - (qsp->xfr.cp - qsp->xfr.msg), NULL, NULL);
+ qsp->xfr.cp += n;
+ PUTSHORT((u_int16_t) T_IXFR, qsp->xfr.cp);
+ PUTSHORT((u_int16_t) zp->z_class, qsp->xfr.cp);
+ hp->qdcount = htons(ntohs(hp->qdcount) + 1);
+ count = qsp->xfr.cp - qsp->xfr.msg;
+ htp = hashtab;
+ np = nlookup(zp->z_origin, &htp, &fname, 0);
+ buflen = XFER_BUFSIZE;
+ foreach_rr(dp, np, T_SOA, qsp->xfr.class, qsp->xfr.zone) {
+ n = make_rr(zp->z_origin, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp, 0, qsp->xfr.ptrs, edp, 0);
+ qsp->xfr.cp += n;
+ hp->ancount = htons(ntohs(hp->ancount) + 1);
+ }
+ }
+}
+
+/*
+ * 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 sq_write() 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_new_ixfrmsg(qsp);
+ n = make_rr(dname, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp,
+ 0, qsp->xfr.ptrs, edp, 0);
+ if (n < 0) {
+ if (sx_flush(qsp) < 0)
+ return (-1);
+ if (qsp->xfr.cp == NULL)
+ sx_new_ixfrmsg(qsp);
+ n = make_rr(dname, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp,
+ 0, qsp->xfr.ptrs, edp, 0);
+ INSIST(n >= 0);
+ }
+ hp->ancount = htons(ntohs(hp->ancount) + 1);
+ qsp->xfr.cp += n;
+ return (0);
+}
+
+void
+sx_send_ixfr(struct qstream *qsp) {
+ char * cp;
+ u_int32_t serial = 0;
+ struct zoneinfo *zp = NULL;
+ struct databuf *soa_dp;
+ struct databuf *old_soadp;
+ ns_updrec * rp;
+ ns_updrec * trp;
+ int foundsoa;
+
+ zp = &zones[qsp->xfr.zone];
+ soa_dp = (struct databuf *) findzonesoa(zp);
+ if (soa_dp == NULL) {
+ /* XXX should be more graceful */
+ ns_panic(ns_log_update, 1,
+ "sx_send_ixfr: unable to locate soa");
+ }
+ old_soadp = memget(DATASIZE(soa_dp->d_size));
+ memcpy(old_soadp, soa_dp, DATASIZE(soa_dp->d_size));
+
+ again:
+ switch (qsp->xfr.state) {
+ case s_x_firstsoa:
+ /*
+ * The current SOA has been emited already.
+ * It would be cleaner if the first one was emited here...
+ *
+ * if (sx_addrr(qsp, zp->z_origin, soa_dp) < 0)
+ * goto cleanup;
+ */
+ qsp->xfr.state = s_x_deletesoa;
+ /* FALLTHROUGH */
+ case s_x_deletesoa:
+ if (qsp->xfr.top.ixfr) {
+ foundsoa = 0;
+ rp = qsp->xfr.top.ixfr;
+ while (PREV(rp, r_link) != NULL)
+ rp = PREV(rp, r_link);
+ while (rp != NULL) {
+ if (rp->r_opcode == DELETE &&
+ rp->r_dp != NULL &&
+ rp->r_dp->d_type == T_SOA) {
+ if (sx_addrr(qsp, rp->r_dname,
+ rp->r_dp) < 0)
+ goto cleanup;
+ db_freedata(rp->r_dp);
+ rp->r_dp = NULL;
+ foundsoa = 1;
+ break;
+ }
+ trp = rp;
+ rp = NEXT(rp, r_link);
+ }
+
+ if (!foundsoa) {
+ cp = (char *)findsoaserial(old_soadp->d_data);
+ PUTLONG(qsp->xfr.top.ixfr->r_zone, cp);
+
+ if (sx_addrr(qsp, zp->z_origin, old_soadp) < 0)
+ goto cleanup;
+ }
+ }
+ qsp->xfr.state = s_x_deleting;
+ /* FALLTHROUGH */
+ case s_x_deleting:
+ if (qsp->xfr.top.ixfr) {
+ /*
+ * The order s important here.
+ * Go to start of this update via PREV(r_link)
+ * then extract all deletions.
+ */
+ rp = qsp->xfr.top.ixfr;
+ while (PREV(rp, r_link) != NULL)
+ rp = PREV(rp, r_link);
+ while (rp != NULL) {
+ if (rp->r_opcode == DELETE &&
+ rp->r_dp != NULL) {
+ /*
+ * Drop any SOA deletes
+ */
+ if (rp->r_dp->d_type != T_SOA &&
+ sx_addrr(qsp, rp->r_dname,
+ rp->r_dp) < 0)
+ goto cleanup;
+ db_freedata(rp->r_dp);
+ rp->r_dp = NULL;
+ }
+ trp = rp;
+ rp = NEXT(rp, r_link);
+ }
+ }
+ qsp->xfr.state = s_x_addsoa;
+ /* FALLTHROUGH */
+ case s_x_addsoa:
+ if (qsp->xfr.top.ixfr) {
+ foundsoa = 0;
+ rp = qsp->xfr.top.ixfr;
+ while (PREV(rp, r_link) != NULL)
+ rp = PREV(rp, r_link);
+ while (rp != NULL) {
+ if (rp->r_opcode == ADD &&
+ rp->r_dp != NULL &&
+ rp->r_dp->d_type == T_SOA) {
+ if (sx_addrr(qsp, rp->r_dname,
+ rp->r_dp) < 0)
+ goto cleanup;
+ db_freedata(rp->r_dp);
+ rp->r_dp = NULL;
+ foundsoa = 1;
+ break;
+ }
+ trp = rp;
+ rp = NEXT(rp, r_link);
+ }
+
+ if (!foundsoa) {
+ cp = (char *)findsoaserial(old_soadp->d_data);
+ if (NEXT(qsp->xfr.top.ixfr, r_link) != NULL) {
+ trp = qsp->xfr.top.ixfr;
+ PUTLONG(NEXT(trp, r_link)->r_zone, cp);
+ if (sx_addrr(qsp, zp->z_origin,
+ old_soadp) < 0)
+ goto cleanup;
+ } else {
+ if (sx_addrr(qsp, zp->z_origin,
+ soa_dp) < 0)
+ goto cleanup;
+ }
+ }
+ }
+ qsp->xfr.state = s_x_adding;
+ /* FALLTHROUGH */
+ case s_x_adding:
+ if (qsp->xfr.top.ixfr) {
+ /* see s_x_deleting */
+ rp = qsp->xfr.top.ixfr;
+ while (PREV(rp, r_link) != NULL)
+ rp = PREV(rp, r_link);
+ while (rp != NULL) {
+ if (rp->r_opcode == ADD &&
+ rp->r_dp != NULL &&
+ rp->r_dp->d_type != T_SOA) {
+ if (sx_addrr(qsp, rp->r_dname,
+ rp->r_dp) < 0)
+ goto cleanup;
+ db_freedata(rp->r_dp);
+ rp->r_dp = NULL;
+ }
+ trp = rp;
+ rp = NEXT(rp, r_link);
+ }
+ /* move to next update */
+ rp = qsp->xfr.top.ixfr;
+ qsp->xfr.top.ixfr = NEXT(rp, r_link);
+ PREV(rp, r_link) = NULL;
+
+ /* clean up old update */
+ while (rp != NULL) {
+ trp = PREV(rp, r_link);
+ if (rp->r_dp != NULL) {
+ db_freedata(rp->r_dp);
+ rp->r_dp = NULL;
+ }
+ res_freeupdrec(rp);
+ rp = trp;
+ }
+ }
+ qsp->xfr.state = s_x_lastsoa;
+ /* FALLTHROUGH */
+ case s_x_lastsoa:
+ if (qsp->xfr.ixfr_zone != 0) {
+ sx_addrr(qsp, zp->z_origin, soa_dp);
+ }
+ break;
+ }
+ qsp->xfr.state = s_x_done;
+ sx_flush(qsp);
+ sq_writeh(qsp, sq_flushw);
+ cleanup:
+ memput(old_soadp, DATASIZE(old_soadp->d_size));
+}
+
+
+#ifndef MAXBSIZE
+#define MAXBSIZE 8192
+#endif
+
+
+int ixfr_log_maint(struct zoneinfo *zp) {
+ int fd, rcount, wcount, rval;
+ int found = 0, seek = 0;
+ FILE *to_fp, *from_fp, *db_fp;
+ static char *tmpname;
+ struct stat db_sb;
+ struct stat sb;
+ static char buf[MAXBSIZE];
+
+ ns_debug(ns_log_default, 3, "ixfr_log_maint(%s)", zp->z_origin);
+
+ tmpname = memget(strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1);
+ if (!tmpname) {
+ ns_warning(ns_log_default, "memget failed");
+ return (-1);
+ }
+#ifdef SHORT_FNAMES
+ filenamecpy(tmpname, zp->z_ixfr_base);
+#else
+ (void) strcpy(tmpname, zp->z_ixfr_base);
+#endif /* SHORT_FNAMES */
+
+ (void) strcat(tmpname, ".XXXXXX");
+ if ((fd = mkstemp(tmpname)) == -1) {
+ ns_warning(ns_log_db, "can't make tmpfile (%s): %s",
+ strerror(errno));
+ memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1));
+ return (-1);
+ }
+ if ((to_fp = fdopen(fd, "r+")) == NULL) {
+ ns_warning(ns_log_db, "%s: %s",
+ tmpname, strerror(errno));
+ (void) unlink(tmpname);
+ memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1));
+ (void) close(fd);
+ return (-1);
+ }
+ /* find out how big the zone db file is */
+ if ((db_fp = fopen(zp->z_source, "r")) == NULL) {
+ ns_warning(ns_log_db, "%s: %s",
+ zp->z_source, strerror(errno));
+ (void) unlink(tmpname);
+ memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1));
+ (void) my_fclose(to_fp);
+ (void) close(fd);
+ return (-1);
+ }
+ if (fstat(fileno(db_fp), &db_sb) < 0) {
+ ns_warning(ns_log_db, "%s: %s",
+ zp->z_source, strerror(errno));
+ (void) my_fclose(to_fp);
+ (void) my_fclose(db_fp);
+ (void) close(fd);
+ (void) unlink(tmpname);
+ memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1));
+ return (-1);
+ }
+ (void) my_fclose(db_fp);
+ ns_debug(ns_log_default, 3, "%s, size %d blk %d",
+ zp->z_source, db_sb.st_size,
+ db_sb.st_size);
+
+ /* open up the zone ixfr log */
+ if ((from_fp = fopen(zp->z_ixfr_base, "r")) == NULL) {
+ ns_warning(ns_log_db, "%s: %s",
+ zp->z_ixfr_base, strerror(errno));
+ (void) my_fclose(to_fp);
+ (void) close(fd);
+ (void) unlink(tmpname);
+ memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1));
+ return (-1);
+ }
+
+ if (fstat(fileno(from_fp), &sb) < 0) {
+ ns_warning(ns_log_db, "%s: %s",
+ zp->z_ixfr_base, strerror(errno));
+ (void) my_fclose(to_fp);
+ (void) close(fd);
+ (void) unlink(tmpname);
+ (void) my_fclose(from_fp);
+ memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1));
+ return (-1);
+ }
+ ns_debug(ns_log_default, 3, "%s, size %d log_s %d max %d\n",
+ zp->z_ixfr_base,
+ sb.st_size,
+ zp->z_log_size_ixfr,
+ zp->z_max_log_size_ixfr);
+ if (zp->z_max_log_size_ixfr) {
+ if (sb.st_size > zp->z_max_log_size_ixfr)
+ seek = sb.st_size - (zp->z_max_log_size_ixfr + (zp->z_max_log_size_ixfr *.10));
+ else
+ seek = 0;
+ } else {
+ if (sb.st_size > (db_sb.st_size * .50))
+ seek = sb.st_size - ((db_sb.st_size * .50)
+ + ((db_sb.st_size * zp->z_max_log_size_ixfr) *.10));
+ else
+ seek = 0;
+ }
+ ns_debug(ns_log_default, 3, "seek: %d", seek);
+ if (seek < 1)
+ {
+ ns_debug(ns_log_default, 3, "%s does not need to be reduced",
+ zp->z_ixfr_base);
+ (void) my_fclose(to_fp);
+ (void) close(fd);
+ (void) unlink(tmpname);
+ (void) my_fclose(from_fp);
+ memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1));
+ return (-1);
+ }
+
+
+ if (fgets(buf, sizeof(buf), from_fp) == NULL) {
+ ns_error(ns_log_update, "fgets() from %s failed: %s",
+ zp->z_ixfr_base, strerror(errno));
+ (void) my_fclose(from_fp);
+ (void) my_fclose(to_fp);
+ (void) close(fd);
+ (void) unlink(tmpname);
+ memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1));
+ return (-1);
+ }
+ if (strcmp(buf, LogSignature) != 0) {
+ ns_error(ns_log_update, "invalid log file %s",
+ zp->z_ixfr_base);
+ (void) my_fclose(from_fp);
+ (void) my_fclose(to_fp);
+ (void) close(fd);
+ (void) unlink(tmpname);
+ memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1));
+ return (-3);
+ }
+
+ if (fseek( from_fp, seek, 0) < 0) {
+ (void) my_fclose(from_fp);
+ (void) my_fclose(to_fp);
+ (void) close(fd);
+ (void) unlink(tmpname);
+ memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1));
+ return (-1);
+ }
+
+ found = 0;
+ for (;;) {
+ if (getword(buf, sizeof buf, from_fp, 0)) {
+ if (strcasecmp(buf, "[END_DELTA]") == 0) {
+ if (!(fgets(buf, 2, from_fp) == NULL)) /* eat <cr><lf> */
+ found = 1;
+ break;
+ }
+ }
+ if (feof(from_fp))
+ break;
+ }
+ if (found) {
+ ns_debug(ns_log_default, 1, "ixfr_log_maint(): found [END_DELTA]");
+
+ while ((rcount = fread(buf, sizeof(char), MAXBSIZE, from_fp)) > 0) {
+ wcount = fwrite(buf, sizeof(char), rcount, to_fp);
+ if (rcount != wcount || wcount == -1) {
+ ns_warning(ns_log_default, "ixfr_log_maint: error in writting copy");
+ rval = 1;
+ break;
+ }
+ }
+ if (rcount < 0) {
+ ns_warning(ns_log_default, "ixfr_log_maint: error in reading copy");
+ rval = 1;
+ }
+ }
+ (void) my_fclose(to_fp);
+ (void) close(fd);
+ (void) my_fclose(from_fp);
+ if (rename(tmpname, zp->z_ixfr_base) == -1) {
+ ns_warning(ns_log_default, "can not rename %s to %s :%s",
+ tmpname, zp->z_ixfr_base, strerror(errno));
+ }
+ (void) unlink(tmpname);
+ memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1));
+ if ((from_fp = fopen(zp->z_ixfr_base, "r")) == NULL) {
+ ns_warning(ns_log_db, "%s: %s",
+ zp->z_ixfr_base, strerror(errno));
+ return (-1);
+ }
+ if (fstat(fileno(from_fp), &sb) < 0) {
+ ns_warning(ns_log_db, "%s: %s",
+ zp->z_ixfr_base, strerror(errno));
+ (void) my_fclose(from_fp);
+ return (-1);
+ }
+ if (sb.st_size <= 0)
+ (void) unlink(zp->z_ixfr_base);
+ (void) my_fclose(from_fp);
+
+ ns_debug(ns_log_default, 3, "%s, size %d log_s %d max %d\n",
+ zp->z_ixfr_base,
+ sb.st_size,
+ zp->z_log_size_ixfr,
+ zp->z_max_log_size_ixfr);
+ return (0);
+}
diff --git a/contrib/bind/bin/named/ns_lexer.c b/contrib/bind/bin/named/ns_lexer.c
index fe319fa..244d5f6 100644
--- a/contrib/bind/bin/named/ns_lexer.c
+++ b/contrib/bind/bin/named/ns_lexer.c
@@ -1,9 +1,9 @@
#if !defined(lint) && !defined(SABER)
-static char rcsid[] = "$Id: ns_lexer.c,v 8.12 1997/12/04 08:11:52 halley Exp $";
+static const char rcsid[] = "$Id: ns_lexer.c,v 8.19 1999/10/13 16:39:08 vixie Exp $";
#endif /* not lint */
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-1999 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
@@ -22,6 +22,8 @@ static char rcsid[] = "$Id: ns_lexer.c,v 8.12 1997/12/04 08:11:52 halley Exp $";
#include "port_before.h"
#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -52,6 +54,7 @@ typedef enum lexer_state {
} LexerState;
#define LEX_EOF 0x01
+#define LEXER_MAX_PUSHBACK 2
typedef struct lexer_file_context {
const char * name;
@@ -61,6 +64,8 @@ typedef struct lexer_file_context {
u_int flags;
int warnings;
int errors;
+ u_int pushback_count;
+ char pushback[LEXER_MAX_PUSHBACK];
struct lexer_file_context *
next;
} *LexerFileContext;
@@ -216,21 +221,29 @@ static struct keyword keywords[] = {
{"acl", T_ACL},
{"address", T_ADDRESS},
{"algorithm", T_ALGID},
+ {"allow", T_ALLOW},
{"allow-query", T_ALLOW_QUERY},
+ {"allow-recursion", T_ALLOW_RECURSION},
{"allow-transfer", T_ALLOW_TRANSFER},
{"allow-update", T_ALLOW_UPDATE},
+#ifdef BIND_NOTIFY
{"also-notify", T_ALSO_NOTIFY},
+#endif
{"auth-nxdomain", T_AUTH_NXDOMAIN},
+ {"blackhole", T_BLACKHOLE},
{"bogus", T_BOGUS},
{"category", T_CATEGORY},
+ {"class", T_CLASS},
{"channel", T_CHANNEL},
{"check-names", T_CHECK_NAMES},
{"cleaning-interval", T_CLEAN_INTERVAL},
+ {"controls", T_CONTROLS},
{"coresize", T_CORESIZE},
{"datasize", T_DATASIZE},
{"deallocate-on-exit", T_DEALLOC_ON_EXIT},
{"debug", T_DEBUG},
{"default", T_DEFAULT},
+ {"dialup", T_DIALUP},
{"directory", T_DIRECTORY},
{"dump-file", T_DUMP_FILE},
{"dynamic", T_DYNAMIC},
@@ -243,47 +256,70 @@ static struct keyword keywords[] = {
{"first", T_FIRST},
{"forward", T_FORWARD},
{"forwarders", T_FORWARDERS},
+ {"group", T_GROUP},
+ {"has-old-clients", T_HAS_OLD_CLIENTS},
+ {"heartbeat-interval", T_HEARTBEAT},
{"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},
+ {"inet", T_INET},
{"interface-interval", T_INTERFACE_INTERVAL},
+ {"ixfr-base", T_FILE_IXFR},
+ {"ixfr-tmp-file", T_IXFR_TMP},
{"key", T_SEC_KEY},
{"keys", T_KEYS},
+ {"lame-ttl", T_LAME_TTL},
{"listen-on", T_LISTEN_ON},
{"logging", T_LOGGING},
+ {"maintain-ixfr-base", T_MAINTAIN_IXFR_BASE},
{"many-answers", T_MANY_ANSWERS},
{"master", T_MASTER},
{"masters", T_MASTERS},
+ {"max-ixfr-log-size", T_MAX_LOG_SIZE_IXFR},
+ {"max-ncache-ttl", T_MAX_NCACHE_TTL},
{"max-transfer-time-in", T_MAX_TRANSFER_TIME_IN},
{"memstatistics-file", T_MEMSTATS_FILE},
+ {"min-roots", T_MIN_ROOTS},
{"multiple-cnames", T_MULTIPLE_CNAMES},
+ {"name", T_NAME},
{"named-xfer", T_NAMED_XFER},
{"no", T_NO},
+#ifdef BIND_NOTIFY
{"notify", T_NOTIFY},
+#endif
{"null", T_NULL_OUTPUT},
{"one-answer", T_ONE_ANSWER},
{"only", T_ONLY},
+ {"order", T_ORDER},
{"options", T_OPTIONS},
+ {"owner", T_OWNER},
+ {"perm", T_PERM},
{"pid-file", T_PIDFILE},
{"port", T_PORT},
{"print-category", T_PRINT_CATEGORY},
{"print-severity", T_PRINT_SEVERITY},
{"print-time", T_PRINT_TIME},
+ {"pubkey", T_PUBKEY},
{"query-source", T_QUERY_SOURCE},
+ {"rfc2308-type1", T_RFC2308_TYPE1},
+ {"rrset-order", T_RRSET_ORDER},
{"recursion", T_RECURSION},
{"response", T_RESPONSE},
{"secret", T_SECRET},
+ {"serial-queries", T_SERIAL_QUERIES},
{"server", T_SERVER},
{"severity", T_SEVERITY},
{"size", T_SIZE},
{"slave", T_SLAVE},
+ {"sortlist", T_SORTLIST},
{"stacksize", T_STACKSIZE},
{"statistics-file", T_STATS_FILE},
{"statistics-interval", T_STATS_INTERVAL},
{"stub", T_STUB},
+ {"support-ixfr", T_SUPPORT_IXFR},
{"syslog", T_SYSLOG},
{"topology", T_TOPOLOGY},
{"transfer-format", T_TRANSFER_FORMAT},
@@ -292,9 +328,15 @@ static struct keyword keywords[] = {
{"transfers-in", T_TRANSFERS_IN},
{"transfers-out", T_TRANSFERS_OUT},
{"transfers-per-ns", T_TRANSFERS_PER_NS},
+ {"treat-cr-as-space", T_TREAT_CR_AS_SPACE},
{"true", T_TRUE},
+ {"trusted-keys", T_TRUSTED_KEYS},
{"type", T_TYPE},
+ {"unix", T_UNIX},
{"unlimited", T_UNLIMITED},
+ {"use-id-pool", T_USE_ID_POOL},
+ {"use-ixfr", T_USE_IXFR},
+ {"version", T_VERSION},
{"versions", T_VERSIONS},
{"warn", T_WARN},
{"yes", T_YES},
@@ -351,6 +393,7 @@ lexer_begin_file(const char *filename, FILE *stream) {
lf->flags = 0;
lf->warnings = 0;
lf->errors = 0;
+ lf->pushback_count = 0;
lf->next = current_file;
current_file = lf;
}
@@ -370,14 +413,29 @@ lexer_end_file(void) {
* Character Input
*/
+#define LEXER_GETC(c, cf) \
+ do { \
+ if ((cf)->pushback_count > 0) { \
+ (cf)->pushback_count--; \
+ (c) = (cf)->pushback[(cf)->pushback_count]; \
+ } else \
+ (c) = getc((cf)->stream); \
+ } while (0);
+
+#define LEXER_UNGETC(c, cf) \
+ do { \
+ INSIST((cf)->pushback_count < LEXER_MAX_PUSHBACK); \
+ (cf)->pushback[(cf)->pushback_count++] = (c); \
+ } while (0);
+
static void
scan_to_comment_end(int c_plus_plus_style) {
- int c, nc;
+ int c;
int done = 0;
int prev_was_star = 0;
while (!done) {
- c = getc(current_file->stream);
+ LEXER_GETC(c, current_file);
switch (c) {
case EOF:
if (!c_plus_plus_style)
@@ -399,7 +457,7 @@ scan_to_comment_end(int c_plus_plus_style) {
we want it to be a delimiter for
anything before the comment
started */
- ungetc(c, current_file->stream);
+ LEXER_UNGETC(c, current_file);
done = 1;
} else {
current_file->line_number++;
@@ -419,7 +477,7 @@ get_next_char(int comment_ok) {
if (current_file->flags & LEX_EOF)
return (EOF);
- c = getc(current_file->stream);
+ LEXER_GETC(c, current_file);
if (comment_ok) {
while (c == '/' || c == '#') {
@@ -427,9 +485,9 @@ get_next_char(int comment_ok) {
scan_to_comment_end(1);
if (current_file->flags & LEX_EOF)
return (EOF);
- c = getc(current_file->stream);
+ LEXER_GETC(c, current_file);
} else {
- nc = getc(current_file->stream);
+ LEXER_GETC(nc, current_file);
switch (nc) {
case EOF:
current_file->flags |= LEX_EOF;
@@ -439,10 +497,10 @@ get_next_char(int comment_ok) {
scan_to_comment_end((nc == '/'));
if (current_file->flags & LEX_EOF)
return (EOF);
- c = getc(current_file->stream);
+ LEXER_GETC(c, current_file);
break;
default:
- ungetc((nc), current_file->stream);
+ LEXER_UNGETC(nc, current_file);
return ('/');
}
}
@@ -461,7 +519,7 @@ put_back_char(int c) {
if (c == EOF)
current_file->flags |= LEX_EOF;
else {
- ungetc((c), current_file->stream);
+ LEXER_UNGETC(c, current_file);
if (c == '\n')
current_file->line_number--;
}
@@ -504,7 +562,7 @@ add_to_identifier(LexerIdentifier id, int c) {
parser_error(0, "identifier too long");
current_file->state = scan;
/* discard chars until we hit a non-identifier char */
- while (identifier_char(c)) {
+ while (c != EOF && identifier_char(c)) {
c = get_next_char(1);
}
put_back_char(c);
@@ -526,7 +584,7 @@ add_to_identifier(LexerIdentifier id, int c) {
*/
int
yylex() {
- int c, i;
+ int c;
int comment_ok = 1;
int token = -1;
symbol_value value;
@@ -581,7 +639,7 @@ yylex() {
break;
case number:
- if (identifier_char(c)) {
+ if (c != EOF && identifier_char(c)) {
if (!isdigit(c))
current_file->state =
(c == '.') ? ipv4 : identifier;
@@ -590,13 +648,13 @@ yylex() {
put_back_char(c);
current_file->state = scan;
finish_identifier(id);
- yylval.num = atoi(id->buffer);
+ yylval.num = strtol(id->buffer, (char**)0, 0);
token = L_NUMBER;
}
break;
case identifier:
- if (identifier_char(c)) {
+ if (c != EOF && identifier_char(c)) {
add_to_identifier(id, c);
} else {
put_back_char(c);
@@ -615,7 +673,7 @@ yylex() {
break;
case ipv4:
- if (identifier_char(c)) {
+ if (c != EOF && identifier_char(c)) {
if (!isdigit(c)) {
if (c != '.' ||
(id->flags & LEX_CONSECUTIVE_DOTS))
@@ -725,7 +783,7 @@ lexer_initialize() {
special_chars['*'] = 1;
id = (LexerIdentifier)memget(sizeof (struct lexer_identifier));
if (id == NULL)
- panic("memget failed in init_once", NULL);
+ panic("memget failed in lexer_initialize", NULL);
init_keywords();
import_all_constants();
lexer_initialized = 1;
@@ -746,5 +804,6 @@ lexer_shutdown(void) {
free_symbol_table(keyword_table);
free_symbol_table(constants);
memput(id, sizeof (struct lexer_identifier));
+ id = NULL;
lexer_initialized = 0;
}
diff --git a/contrib/bind/bin/named/ns_lexer.h b/contrib/bind/bin/named/ns_lexer.h
index 3491df3..66c19f2 100644
--- a/contrib/bind/bin/named/ns_lexer.h
+++ b/contrib/bind/bin/named/ns_lexer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-1999 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
@@ -15,8 +15,8 @@
* SOFTWARE.
*/
-#ifndef NS_LEXER_H
-#define NS_LEXER_H
+#ifndef _NS_LEXER_H
+#define _NS_LEXER_H
/*
* Note: <stdio.h> and "ns_parseutil.h" must be included
@@ -42,4 +42,4 @@ void lexer_shutdown(void);
extern symbol_table constants;
-#endif /* NS_LEXER_H */
+#endif /* !_NS_LEXER_H */
diff --git a/contrib/bind/bin/named/ns_main.c b/contrib/bind/bin/named/ns_main.c
index 194d368..1377098 100644
--- a/contrib/bind/bin/named/ns_main.c
+++ b/contrib/bind/bin/named/ns_main.c
@@ -1,6 +1,6 @@
#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.67 1998/04/28 19:17:46 halley Exp $";
+static const char sccsid[] = "@(#)ns_main.c 4.55 (Berkeley) 7/1/91";
+static const char rcsid[] = "$Id: ns_main.c,v 8.117 1999/11/08 23:01:38 vixie Exp $";
#endif /* not lint */
/*
@@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_main.c,v 8.67 1998/04/28 19:17:46 halley Exp $";
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -75,10 +75,11 @@ static char rcsid[] = "$Id: ns_main.c,v 8.67 1998/04/28 19:17:46 halley Exp $";
#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";
+"@(#) 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-1999 Internet Software Consortium\n"
+"portions Copyright (c) 1999 Check Point Software Technologies\n"
+"All rights reserved.\n";
#endif /* not lint */
/*
@@ -94,6 +95,7 @@ char copyright[] =
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
+#include <sys/un.h>
#ifdef SVR4 /* XXX */
# include <sys/sockio.h>
#else
@@ -139,21 +141,32 @@ char copyright[] =
/* list of interfaces */
static LIST(struct _interface) iflist;
static int iflist_initialized = 0;
+static int iflist_dont_rescan = 0;
-
-static const int drbufsize = 8 * 1024, /* UDP rcv buf size */
- dsbufsize = 16 * 1024, /* UDP snd buf size */
- sbufsize = 16 * 1024; /* TCP snd buf size */
+static const int drbufsize = 32 * 1024, /* UDP rcv buf size */
+ dsbufsize = 48 * 1024, /* UDP snd buf size */
+ sbufsize = 16 * 1024, /* TCP snd buf size */
+ nudptrans = 20, /* #/udps per select */
+ listenmax = 50;
static u_int16_t nsid_state;
-static int needs;
+static u_int16_t *nsid_pool; /* optional query id pool */
+static u_int16_t *nsid_vtable; /* optional shuffle table */
+static u_int32_t nsid_hash_state;
+static u_int16_t nsid_a1, nsid_a2, nsid_a3;
+static u_int16_t nsid_c1, nsid_c2, nsid_c3;
+static u_int16_t nsid_state2;
+static int nsid_algorithm;
+
+typedef void (*handler)(void);
+static int needs = 0;
+static handler handlers[main_need_num];
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);
+ dq_remove(interface *);
static int sq_dowrite(struct qstream *);
static void use_desired_debug(void);
static void stream_write(evContext, void *, int, int);
@@ -162,7 +175,8 @@ static interface * if_find(struct in_addr, u_int16_t port);
static int sq_here(struct qstream *);
-static void stream_accept(evContext, void *, int,
+static void deallocate_everything(void),
+ stream_accept(evContext, void *, int,
const void *, int,
const void *, int),
stream_getlen(evContext, void *, int, int),
@@ -175,14 +189,20 @@ static void stream_accept(evContext, void *, int,
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 init_needs(void),
+ handle_need(void);
+
+#ifndef HAVE_CUSTOM
+static void custom_init(void),
+ custom_shutdown(void);
+#endif
+
static void
usage() {
fprintf(stderr,
-"Usage: named [-d #] [-q] [-r] [-f] [-p port] [[-b|-c] configfile]\n");
+"Usage: named [-d #] [-q] [-r] [-v] [-f] [-p port] [[-b|-c] configfile]\n");
#ifdef CAN_CHANGE_ID
fprintf(stderr,
" [-u (username|uid)] [-g (groupname|gid)]\n");
@@ -202,20 +222,16 @@ 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 n;
+ char *p;
int ch;
- FILE *fp; /* file descriptor for pid file */
struct passwd *pw;
struct group *gr;
-#ifdef HAVE_GETRUSAGE
- struct rlimit rl;
+
+#ifdef _AUX_SOURCE
+ set42sig();
#endif
+ debugfile = savestr(_PATH_DEBUG, 1);
user_id = getuid();
group_id = getgid();
@@ -231,7 +247,17 @@ main(int argc, char *argv[], char *envp[]) {
(void) umask(022);
- while ((ch = getopt(argc, argv, "b:c:d:g:p:t:u:w:qrf")) != EOF) {
+ /* Save argv[] before getopt() destroys it -- needed for execvp(). */
+ saved_argv = malloc(sizeof(char *) * (argc + 1));
+ INSIST(saved_argv != NULL);
+ for (n = 0; n < argc; n++) {
+ saved_argv[n] = strdup(argv[n]);
+ INSIST(saved_argv[n] != NULL);
+ }
+ saved_argv[argc] = NULL;
+ /* XXX we need to free() this for clean shutdowns. */
+
+ while ((ch = getopt(argc, argv, "b:c:d:g:p:t:u:vw:qrf")) != -1) {
switch (ch) {
case 'b':
case 'c':
@@ -291,6 +317,10 @@ main(int argc, char *argv[], char *envp[]) {
chroot_dir = savestr(optarg, 1);
break;
+ case 'v':
+ fprintf(stderr, "%s\n", Version);
+ exit(1);
+
#ifdef CAN_CHANGE_ID
case 'u':
user_name = savestr(optarg, 1);
@@ -390,6 +420,10 @@ main(int argc, char *argv[], char *envp[]) {
/* Establish global event context. */
evCreate(&ev);
+ /* Establish global resolver context. */
+ res_ninit(&res);
+ res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
+
/*
* Set up logging.
*/
@@ -416,14 +450,14 @@ main(int argc, char *argv[], char *envp[]) {
use_desired_debug();
#endif
+ /* Perform system-dependent initialization */
+ custom_init();
+
+ init_needs();
init_signals();
ns_notice(ns_log_default, "starting. %s", Version);
- _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
-
- nsid_init();
-
/*
* Initialize and load database.
*/
@@ -434,6 +468,8 @@ main(int argc, char *argv[], char *envp[]) {
time(&boottime);
resettime = boottime;
+ nsid_init();
+
/*
* Fork and go into background now that
* we've done any slow initialization
@@ -477,21 +513,46 @@ main(int argc, char *argv[], char *envp[]) {
ns_panic(ns_log_security, 1, "setuid(%s): %s",
user_name, strerror(errno));
ns_info(ns_log_security, "user = %s", user_name);
+ if (user_id != 0)
+ iflist_dont_rescan++;
}
#endif /* CAN_CHANGE_ID */
ns_notice(ns_log_default, "Ready to answer queries.");
gettime(&tt);
prime_cache();
- for (;;) {
+ while (!main_needs_exit) {
evEvent event;
- if (needs)
- ns_handle_needs();
- INSIST_ERR(evGetNext(ev, &event, EV_WAIT) != -1);
- INSIST_ERR(evDispatch(ev, event) != -1);
+ ns_debug(ns_log_default, 15, "main loop");
+ if (needs != 0) {
+ /* Drain outstanding events; handlers ~block~. */
+ while (evGetNext(ev, &event, EV_POLL) != -1)
+ INSIST_ERR(evDispatch(ev, event) != -1);
+ INSIST_ERR(errno == EINTR || errno == EWOULDBLOCK);
+ handle_need();
+ } else if (evGetNext(ev, &event, EV_WAIT) != -1) {
+ INSIST_ERR(evDispatch(ev, event) != -1);
+ } else {
+ INSIST_ERR(errno == EINTR);
+ }
}
- /* NOTREACHED */
+ 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();
+ else
+ shutdown_configuration();
+
+ /* Cleanup for system-dependent stuff */
+ custom_shutdown();
+
return (0);
}
@@ -508,7 +569,7 @@ stream_accept(evContext lev, void *uap, int rfd,
interface *ifp = uap;
struct qstream *sp;
struct iovec iov;
- int n, len;
+ int len, n;
const int on = 1;
#ifdef IP_OPTIONS /* XXX */
u_char ip_opts[IP_OPT_BUF_SIZE];
@@ -594,21 +655,6 @@ stream_accept(evContext lev, void *uap, int rfd,
/* 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) {
@@ -626,6 +672,19 @@ stream_accept(evContext lev, void *uap, int rfd,
return;
}
+ 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;
+ }
+
/*
* 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
@@ -685,20 +744,23 @@ tcp_send(struct qinfo *qp) {
ns_debug(ns_log_default, 1, "tcp_send");
if ((sp = sq_add()) == NULL) {
- return(SERVFAIL);
+ return (SERVFAIL);
}
if ((sp->s_rfd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) == -1) {
sq_remove(sp);
- return(SERVFAIL);
+ return (SERVFAIL);
+ }
+ if (sp->s_rfd > evHighestFD(ev)) {
+ sq_remove(sp);
+ return (SERVFAIL);
}
-
if (sq_openw(sp, qp->q_msglen + INT16SZ) == -1) {
sq_remove(sp);
- return(SERVFAIL);
+ return (SERVFAIL);
}
if (sq_write(sp, qp->q_msg, qp->q_msglen) == -1) {
sq_remove(sp);
- return(SERVFAIL);
+ return (SERVFAIL);
}
if (setsockopt(sp->s_rfd, SOL_SOCKET, SO_KEEPALIVE,
@@ -711,17 +773,14 @@ tcp_send(struct qinfo *qp) {
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;
+ 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);
+ return (NOERROR);
}
static void
@@ -763,7 +822,8 @@ stream_write(evContext ctx, void *uap, int fd, int evmask) {
if (sp->s_wbuf) {
memput(sp->s_wbuf, sp->s_wbuf_end - sp->s_wbuf);
- sp->s_wbuf = NULL;
+ sp->s_wbuf_send = sp->s_wbuf_free = NULL;
+ sp->s_wbuf_end = sp->s_wbuf = NULL;
}
(void) evDeselectFD(ev, sp->evID_w);
sp->flags &= ~STREAM_WRITE_EV;
@@ -811,6 +871,13 @@ stream_getlen(evContext lev, void *uap, int fd, int bytes) {
*/
sp->s_size = ns_get16(sp->s_temp);
ns_debug(ns_log_default, 5, "stream message: %d bytes", sp->s_size);
+ if (sp->s_size < HFIXEDSZ) {
+ ns_error(ns_log_default,
+ "stream_getlen(%s): request too small",
+ sin_ntoa(sp->s_from));
+ sq_remove(sp);
+ return;
+ }
if (!(sp->flags & STREAM_MALLOC)) {
sp->s_bufsize = 64*1024-1; /* maximum tcp message size */
@@ -834,7 +901,6 @@ stream_getlen(evContext lev, void *uap, int fd, int bytes) {
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) {
@@ -847,10 +913,12 @@ stream_getmsg(evContext lev, void *uap, int fd, int bytes) {
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);
+ if (ns_wouldlog(ns_log_default,5)) {
+ 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
@@ -882,12 +950,16 @@ datagram_read(evContext lev, void *uap, int fd, int evmask) {
interface *ifp = uap;
struct sockaddr_in from;
int from_len = sizeof from;
- int n;
+ int n, nudp;
union {
HEADER h; /* Force alignment of 'buf'. */
u_char buf[PACKETSZ+1];
} u;
+ tt = evTimeVal(evNowTime());
+ nudp = 0;
+
+ more:
n = recvfrom(fd, (char *)u.buf, sizeof u.buf, 0,
(struct sockaddr *)&from, &from_len);
@@ -911,15 +983,6 @@ datagram_read(evContext lev, void *uap, int fd, int evmask) {
* 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
@@ -931,14 +994,14 @@ datagram_read(evContext lev, void *uap, int fd, int evmask) {
}
}
-#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 (ns_wouldlog(ns_log_default, 1)) {
+ ns_debug(ns_log_default, 1, "datagram from %s, fd %d, len %d",
+ sin_ntoa(from), fd, n);
+ }
if (n > PACKETSZ) {
/*
@@ -949,8 +1012,9 @@ datagram_read(evContext lev, void *uap, int fd, int evmask) {
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);
+ if (++nudp < nudptrans)
+ goto more;
}
static void
@@ -961,8 +1025,35 @@ dispatch_message(u_char *msg, int msglen, int buflen, struct qstream *qsp,
if (msglen < HFIXEDSZ) {
ns_debug(ns_log_default, 1, "dropping undersize message");
+ if (qsp) {
+ qsp->flags |= STREAM_DONE_CLOSE;
+ sq_done(qsp);
+ }
return;
}
+
+ if (server_options->blackhole_acl != NULL &&
+ ip_match_address(server_options->blackhole_acl,
+ from.sin_addr) == 1) {
+ ns_debug(ns_log_default, 1,
+ "dropping blackholed %s from %s",
+ hp->qr ? "response" : "query",
+ sin_ntoa(from));
+ if (qsp) {
+ qsp->flags |= STREAM_DONE_CLOSE;
+ sq_done(qsp);
+ }
+ return;
+ }
+
+ /* Drop UDP packets from port zero. They are invariable forged. */
+ if (qsp == NULL && ntohs(from.sin_port) == 0) {
+ ns_notice(ns_log_security,
+ "dropping source port zero packet from %s",
+ sin_ntoa(from));
+ return;
+ }
+
if (hp->qr) {
ns_resp(msg, msglen, from, qsp);
if (qsp)
@@ -976,6 +1067,10 @@ dispatch_message(u_char *msg, int msglen, int buflen, struct qstream *qsp,
ns_notice(ns_log_security,
"refused query on non-query socket from %s",
sin_ntoa(from));
+ if (qsp) {
+ qsp->flags |= STREAM_DONE_CLOSE;
+ sq_done(qsp);
+ }
/* XXX Send refusal here. */
}
}
@@ -986,17 +1081,24 @@ getnetconf(int periodic_scan) {
struct ifreq ifreq;
struct in_addr ina;
interface *ifp;
- char buf[32768], *cp, *cplim;
- u_int32_t nm;
+ char *buf, *cp, *cplim;
+ static int bufsiz = 4095;
time_t my_generation = time(NULL);
- int s, cpsize;
+ int s, cpsize, n;
int found;
listen_info li;
- u_int16_t port;
ip_match_element ime;
u_char *mask_ptr;
struct in_addr mask;
+ if (iflist_initialized) {
+ if (iflist_dont_rescan)
+ return;
+ } else {
+ INIT_LIST(iflist);
+ iflist_initialized = 1;
+ }
+
ns_debug(ns_log_default, 1, "getnetconf(generation %lu)",
(u_long)my_generation);
@@ -1010,11 +1112,6 @@ getnetconf(int periodic_scan) {
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();
@@ -1022,11 +1119,46 @@ getnetconf(int periodic_scan) {
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));
+ for (;;) {
+ buf = memget(bufsiz);
+ if (!buf)
+ ns_panic(ns_log_default, 1,
+ "memget(interface)", NULL);
+ ifc.ifc_len = bufsiz;
+ ifc.ifc_buf = buf;
+#ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
+ /*
+ * This is a fix for IRIX OS in which the call to ioctl with
+ * the flag SIOCGIFCONF may not return an entry for all the
+ * interfaces like most flavors of Unix.
+ */
+ if (emul_ioctl(&ifc) >= 0)
+ break;
+#else
+ if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) {
+ /*
+ * Some OS's just return what will fit rather
+ * than set EINVAL if the buffer is too small
+ * to fit all the interfaces in. If
+ * ifc.ifc_len is too near to the end of the
+ * buffer we will grow it just in case and
+ * retry.
+ */
+ if (ifc.ifc_len + 2 * sizeof(ifreq) < bufsiz)
+ break;
+ }
+#endif
+ if ((n == -1) && errno != EINVAL)
+ ns_panic(ns_log_default, 1,
+ "get interface configuration: %s",
+ strerror(errno));
+
+ if (bufsiz > 1000000)
+ ns_panic(ns_log_default, 1,
+ "get interface configuration: maximum buffer size exceeded");
+ memput(buf, bufsiz);
+ bufsiz += 4096;
+ }
ns_debug(ns_log_default, 2, "getnetconf: SIOCGIFCONF: ifc_len = %d",
ifc.ifc_len);
@@ -1035,7 +1167,7 @@ getnetconf(int periodic_scan) {
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 HAVE_SA_LEN
#ifdef FIX_ZERO_SA_LEN
if (ifreq.ifr_addr.sa_len == 0)
ifreq.ifr_addr.sa_len = 16;
@@ -1228,6 +1360,7 @@ getnetconf(int periodic_scan) {
}
}
close(s);
+ memput(buf, bufsiz);
ns_debug(ns_log_default, 7, "local addresses:");
dprint_ip_match_list(ns_log_default, local_addresses, 2, "", "");
@@ -1270,6 +1403,23 @@ opensocket_d(interface *ifp) {
strerror(errno));
return (-1);
}
+ if (ifp->dfd > evHighestFD(ev)) {
+ ns_error(ns_log_default, "socket too high: %d", ifp->dfd);
+ close(ifp->dfd);
+ return (-1);
+ }
+ if ((n = fcntl(ifp->dfd, F_GETFL, 0)) == -1) {
+ ns_info(ns_log_default, "fcntl(ifp->dfd, F_GETFL): %s",
+ strerror(errno));
+ (void) close(ifp->dfd);
+ return (-1);
+ }
+ if (fcntl(ifp->dfd, F_SETFL, n|PORT_NONBLOCK) == -1) {
+ ns_info(ns_log_default, "fcntl(ifp->dfd, NONBLOCK): %s",
+ strerror(errno));
+ (void) close(ifp->dfd);
+ return (-1);
+ }
#ifdef F_DUPFD /* XXX */
/*
* Leave a space for stdio to work in.
@@ -1350,6 +1500,11 @@ opensocket_s(interface *ifp) {
strerror(errno));
return (-1);
}
+ if (ifp->sfd > evHighestFD(ev)) {
+ ns_error(ns_log_default, "socket too high: %d", ifp->sfd);
+ close(ifp->sfd);
+ return (-1);
+ }
#ifdef F_DUPFD /* XXX */
/*
* Leave a space for stdio to work in.
@@ -1386,7 +1541,7 @@ opensocket_s(interface *ifp) {
sleep(30);
goto again;
}
- if (evListen(ev, ifp->sfd, 5/*XXX*/, stream_accept, ifp, &ifp->evID_s)
+ if (evListen(ev, ifp->sfd, listenmax, stream_accept, ifp, &ifp->evID_s)
== -1) {
ns_error(ns_log_default, "evListen(sfd=%d): %s",
ifp->sfd, strerror(errno));
@@ -1460,6 +1615,8 @@ opensocket_f() {
if ((ds = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
ns_panic(ns_log_default, 1, "socket(SOCK_DGRAM): %s",
strerror(errno));
+ if (ds > evHighestFD(ev))
+ ns_panic(ns_log_default, 1, "socket too high: %d", ds);
if (setsockopt(ds, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof on) != 0) {
ns_notice(ns_log_default, "setsockopt(REUSEADDR): %s",
@@ -1468,7 +1625,7 @@ opensocket_f() {
}
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",
+ ns_panic(ns_log_default, 0, "opensocket_f: bind(%s): %s",
sin_ntoa(server_options->query_source),
strerror(errno));
@@ -1513,56 +1670,6 @@ setdebug(int new_debug) {
#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
*/
@@ -1601,7 +1708,8 @@ sq_remove(struct qstream *qp) {
if (qp->s_wbuf != NULL) {
memput(qp->s_wbuf, qp->s_wbuf_end - qp->s_wbuf);
- qp->s_wbuf = NULL;
+ qp->s_wbuf_send = qp->s_wbuf_free = NULL;
+ qp->s_wbuf_end = qp->s_wbuf = NULL;
}
if (qp->flags & STREAM_MALLOC)
memput(qp->s_buf, qp->s_bufsize);
@@ -1655,7 +1763,7 @@ sq_flush(struct qstream *allbut) {
*/
int
sq_openw(struct qstream *qs, int buflen) {
-#ifdef SO_LINGER /* XXX */
+#ifdef DO_SO_LINGER /* XXX */
static const struct linger ll = { 1, 120 };
#endif
@@ -1666,7 +1774,7 @@ sq_openw(struct qstream *qs, int buflen) {
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 */
+#ifdef DO_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...
@@ -1685,6 +1793,7 @@ 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);
+ INSIST(qs->s_wbuf != NULL);
if (n < 0) {
if (errno != EINTR && errno != EAGAIN
#if (EWOULDBLOCK != EAGAIN)
@@ -1831,8 +1940,10 @@ sq_done(struct qstream *sp) {
struct iovec iov;
if (sp->s_wbuf != NULL) {
+ INSIST(sp->s_wbuf_send == sp->s_wbuf_free);
memput(sp->s_wbuf, sp->s_wbuf_end - sp->s_wbuf);
- sp->s_wbuf = NULL;
+ sp->s_wbuf_send = sp->s_wbuf_free = NULL;
+ sp->s_wbuf_end = sp->s_wbuf = NULL;
}
if (sp->flags & STREAM_AXFR)
ns_freexfr(sp);
@@ -1950,7 +2061,6 @@ net_mask(struct in_addr ina) {
*/
int
aIsUs(struct in_addr addr) {
- interface *ifp;
if (ina_hlong(addr) == INADDR_ANY || if_find(addr, 0) != NULL)
return (1);
@@ -1982,22 +2092,397 @@ if_find(struct in_addr addr, u_int16_t port) {
* 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.
+ *
+ * This is true but ... most clients only send out a few queries, they
+ * use varying port numbers, and the queries aren't sent to the outside
+ * world which we know is full of spoofers. Doing a good job of randomizing
+ * ids may also be to expensive for each client. Queries forwarded by the
+ * server always come from the same port (unless you let 8.x pick a port
+ * and restart it periodically - maybe it should open several and use
+ * them randomly). The server sends out lots more queries, and if it's
+ * cache is corrupted, it has the potential to affect more clients.
+ * NOTE: - randomizing the ID or source port doesn't help a bit if the
+ * queries can be sniffed.
+ * -- DL
+ */
+
+/*
+ * Allow the user to pick one of two ID randomization algorithms.
+ *
+ * The first algorithm is an adaptation of the sequence shuffling
+ * algorithm discovered by Carter Bays and S. D. Durham [ACM Trans. Math.
+ * Software 2 (1976), 59-64], as documented as Algorithm B in Chapter
+ * 3.2.2 in Volume 2 of Knuth's "The Art of Computer Programming". We use
+ * a randomly selected linear congruential random number generator with a
+ * modulus of 2^16, whose increment is a randomly picked odd number, and
+ * whose multiplier is picked from a set which meets the following
+ * criteria:
+ * Is of the form 8*n+5, which ensures "high potency" according to
+ * principle iii in the summary chapter 3.6. This form also has a
+ * gcd(a-1,m) of 4 which is good according to principle iv.
+ *
+ * Is between 0.01 and 0.99 times the modulus as specified by
+ * principle iv.
+ *
+ * Passes the spectral test "with flying colors" (ut >= 1) in
+ * dimensions 2 through 6 as calculated by Algorithm S in Chapter
+ * 3.3.4 and the ratings calculated by formula 35 in section E.
+ *
+ * Of the multipliers that pass this test, pick the set that is
+ * best according to the theoretical bounds of the serial
+ * correlation test. This was calculated using a simplified
+ * version of Knuth's Theorem K in Chapter 3.3.3.
+ *
+ * These criteria may not be important for this use, but we might as well
+ * pick from the best generators since there are so many possible ones and
+ * we don't have that many random bits to do the picking.
+ *
+ * We use a modulus of 2^16 instead of something bigger so that we will
+ * tend to cycle through all the possible IDs before repeating any,
+ * however the shuffling will perturb this somewhat. Theoretically there
+ * is no minimimum interval between two uses of the same ID, but in
+ * practice it seems to be >64000.
+ *
+ * Our adaptatation of Algorithm B mixes the hash state which has
+ * captured various random events into the shuffler to perturb the
+ * sequence.
+ *
+ * One disadvantage of this algorithm is that if the generator parameters
+ * were to be guessed, it would be possible to mount a limited brute force
+ * attack on the ID space since the IDs are only shuffled within a limited
+ * range.
+ *
+ * The second algorithm uses the same random number generator to populate
+ * a pool of 65536 IDs. The hash state is used to pick an ID from a window
+ * of 4096 IDs in this pool, then the chosen ID is swapped with the ID
+ * at the beginning of the window and the window position is advanced.
+ * This means that the interval between uses of the ID will be no less
+ * than 65536-4096. The ID sequence in the pool will become more random
+ * over time.
+ *
+ * For both algorithms, two more linear congruential random number generators
+ * are selected. The ID from the first part of algorithm is used to seed
+ * the first of these generators, and its output is used to seed the second.
+ * The strategy is use these generators as 1 to 1 hashes to obfuscate the
+ * properties of the generator used in the first part of either algorithm.
+ *
+ * The first algorithm may be suitable for use in a client resolver since
+ * its memory requirements are fairly low and it's pretty random out of
+ * the box. It is somewhat succeptible to a limited brute force attack,
+ * so the second algorithm is probably preferable for a longer running
+ * program that issues a large number of queries and has time to randomize
+ * the pool.
+ */
+
+#define NSID_SHUFFLE_TABLE_SIZE 100 /* Suggested by Knuth */
+/*
+ * Pick one of the next 4096 IDs in the pool.
+ * There is a tradeoff here between randomness and how often and ID is reused.
+ */
+#define NSID_LOOKAHEAD 4096 /* Must be a power of 2 */
+#define NSID_SHUFFLE_ONLY 1 /* algorithm 1 */
+#define NSID_USE_POOL 2 /* algorithm 2 */
+
+/*
+ * Keep a running hash of various bits of data that we'll use to
+ * stir the ID pool or perturb the ID generator
+ */
+void
+nsid_hash(u_char *data, size_t len) {
+ /*
+ * Hash function similar to the one we use for hashing names.
+ * We don't fold case or toss the upper bit here, though.
+ * This hash doesn't do much interesting when fed binary zeros,
+ * so there may be a better hash function.
+ * This function doesn't need to be very strong since we're
+ * only using it to stir the pool, but it should be reasonably
+ * fast.
+ */
+ while (len-- > 0) {
+ HASHROTATE(nsid_hash_state);
+ nsid_hash_state += *data++;
+ }
+}
+
+/*
+ * Table of good linear congruential multipliers for modulus 2^16
+ * in order of increasing serial correlation bounds (so trim from
+ * the end).
*/
+static const u_int16_t nsid_multiplier_table[] = {
+ 17565, 25013, 11733, 19877, 23989, 23997, 24997, 25421,
+ 26781, 27413, 35901, 35917, 35973, 36229, 38317, 38437,
+ 39941, 40493, 41853, 46317, 50581, 51429, 53453, 53805,
+ 11317, 11789, 12045, 12413, 14277, 14821, 14917, 18989,
+ 19821, 23005, 23533, 23573, 23693, 27549, 27709, 28461,
+ 29365, 35605, 37693, 37757, 38309, 41285, 45261, 47061,
+ 47269, 48133, 48597, 50277, 50717, 50757, 50805, 51341,
+ 51413, 51581, 51597, 53445, 11493, 14229, 20365, 20653,
+ 23485, 25541, 27429, 29421, 30173, 35445, 35653, 36789,
+ 36797, 37109, 37157, 37669, 38661, 39773, 40397, 41837,
+ 41877, 45293, 47277, 47845, 49853, 51085, 51349, 54085,
+ 56933, 8877, 8973, 9885, 11365, 11813, 13581, 13589,
+ 13613, 14109, 14317, 15765, 15789, 16925, 17069, 17205,
+ 17621, 17941, 19077, 19381, 20245, 22845, 23733, 24869,
+ 25453, 27213, 28381, 28965, 29245, 29997, 30733, 30901,
+ 34877, 35485, 35613, 36133, 36661, 36917, 38597, 40285,
+ 40693, 41413, 41541, 41637, 42053, 42349, 45245, 45469,
+ 46493, 48205, 48613, 50861, 51861, 52877, 53933, 54397,
+ 55669, 56453, 56965, 58021, 7757, 7781, 8333, 9661,
+ 12229, 14373, 14453, 17549, 18141, 19085, 20773, 23701,
+ 24205, 24333, 25261, 25317, 27181, 30117, 30477, 34757,
+ 34885, 35565, 35885, 36541, 37957, 39733, 39813, 41157,
+ 41893, 42317, 46621, 48117, 48181, 49525, 55261, 55389,
+ 56845, 7045, 7749, 7965, 8469, 9133, 9549, 9789,
+ 10173, 11181, 11285, 12253, 13453, 13533, 13757, 14477,
+ 15053, 16901, 17213, 17269, 17525, 17629, 18605, 19013,
+ 19829, 19933, 20069, 20093, 23261, 23333, 24949, 25309,
+ 27613, 28453, 28709, 29301, 29541, 34165, 34413, 37301,
+ 37773, 38045, 38405, 41077, 41781, 41925, 42717, 44437,
+ 44525, 44613, 45933, 45941, 47077, 50077, 50893, 52117,
+ 5293, 55069, 55989, 58125, 59205, 6869, 14685, 15453,
+ 16821, 17045, 17613, 18437, 21029, 22773, 22909, 25445,
+ 25757, 26541, 30709, 30909, 31093, 31149, 37069, 37725,
+ 37925, 38949, 39637, 39701, 40765, 40861, 42965, 44813,
+ 45077, 45733, 47045, 50093, 52861, 52957, 54181, 56325,
+ 56365, 56381, 56877, 57013, 5741, 58101, 58669, 8613,
+ 10045, 10261, 10653, 10733, 11461, 12261, 14069, 15877,
+ 17757, 21165, 23885, 24701, 26429, 26645, 27925, 28765,
+ 29197, 30189, 31293, 39781, 39909, 40365, 41229, 41453,
+ 41653, 42165, 42365, 47421, 48029, 48085, 52773, 5573,
+ 57037, 57637, 58341, 58357, 58901, 6357, 7789, 9093,
+ 10125, 10709, 10765, 11957, 12469, 13437, 13509, 14773,
+ 15437, 15773, 17813, 18829, 19565, 20237, 23461, 23685,
+ 23725, 23941, 24877, 25461, 26405, 29509, 30285, 35181,
+ 37229, 37893, 38565, 40293, 44189, 44581, 45701, 47381,
+ 47589, 48557, 4941, 51069, 5165, 52797, 53149, 5341,
+ 56301, 56765, 58581, 59493, 59677, 6085, 6349, 8293,
+ 8501, 8517, 11597, 11709, 12589, 12693, 13517, 14909,
+ 17397, 18085, 21101, 21269, 22717, 25237, 25661, 29189,
+ 30101, 31397, 33933, 34213, 34661, 35533, 36493, 37309,
+ 40037, 4189, 42909, 44309, 44357, 44389, 4541, 45461,
+ 46445, 48237, 54149, 55301, 55853, 56621, 56717, 56901,
+ 5813, 58437, 12493, 15365, 15989, 17829, 18229, 19341,
+ 21013, 21357, 22925, 24885, 26053, 27581, 28221, 28485,
+ 30605, 30613, 30789, 35437, 36285, 37189, 3941, 41797,
+ 4269, 42901, 43293, 44645, 45221, 46893, 4893, 50301,
+ 50325, 5189, 52109, 53517, 54053, 54485, 5525, 55949,
+ 56973, 59069, 59421, 60733, 61253, 6421, 6701, 6709,
+ 7101, 8669, 15797, 19221, 19837, 20133, 20957, 21293,
+ 21461, 22461, 29085, 29861, 30869, 34973, 36469, 37565,
+ 38125, 38829, 39469, 40061, 40117, 44093, 47429, 48341,
+ 50597, 51757, 5541, 57629, 58405, 59621, 59693, 59701,
+ 61837, 7061, 10421, 11949, 15405, 20861, 25397, 25509,
+ 25893, 26037, 28629, 28869, 29605, 30213, 34205, 35637,
+ 36365, 37285, 3773, 39117, 4021, 41061, 42653, 44509,
+ 4461, 44829, 4725, 5125, 52269, 56469, 59085, 5917,
+ 60973, 8349, 17725, 18637, 19773, 20293, 21453, 22533,
+ 24285, 26333, 26997, 31501, 34541, 34805, 37509, 38477,
+ 41333, 44125, 46285, 46997, 47637, 48173, 4925, 50253,
+ 50381, 50917, 51205, 51325, 52165, 52229, 5253, 5269,
+ 53509, 56253, 56341, 5821, 58373, 60301, 61653, 61973,
+ 62373, 8397, 11981, 14341, 14509, 15077, 22261, 22429,
+ 24261, 28165, 28685, 30661, 34021, 34445, 39149, 3917,
+ 43013, 43317, 44053, 44101, 4533, 49541, 49981, 5277,
+ 54477, 56357, 57261, 57765, 58573, 59061, 60197, 61197,
+ 62189, 7725, 8477, 9565, 10229, 11437, 14613, 14709,
+ 16813, 20029, 20677, 31445, 3165, 31957, 3229, 33541,
+ 36645, 3805, 38973, 3965, 4029, 44293, 44557, 46245,
+ 48917, 4909, 51749, 53709, 55733, 56445, 5925, 6093,
+ 61053, 62637, 8661, 9109, 10821, 11389, 13813, 14325,
+ 15501, 16149, 18845, 22669, 26437, 29869, 31837, 33709,
+ 33973, 34173, 3677, 3877, 3981, 39885, 42117, 4421,
+ 44221, 44245, 44693, 46157, 47309, 5005, 51461, 52037,
+ 55333, 55693, 56277, 58949, 6205, 62141, 62469, 6293,
+ 10101, 12509, 14029, 17997, 20469, 21149, 25221, 27109,
+ 2773, 2877, 29405, 31493, 31645, 4077, 42005, 42077,
+ 42469, 42501, 44013, 48653, 49349, 4997, 50101, 55405,
+ 56957, 58037, 59429, 60749, 61797, 62381, 62837, 6605,
+ 10541, 23981, 24533, 2701, 27333, 27341, 31197, 33805,
+ 3621, 37381, 3749, 3829, 38533, 42613, 44381, 45901,
+ 48517, 51269, 57725, 59461, 60045, 62029, 13805, 14013,
+ 15461, 16069, 16157, 18573, 2309, 23501, 28645, 3077,
+ 31541, 36357, 36877, 3789, 39429, 39805, 47685, 47949,
+ 49413, 5485, 56757, 57549, 57805, 58317, 59549, 62213,
+ 62613, 62853, 62933, 8909, 12941, 16677, 20333, 21541,
+ 24429, 26077, 26421, 2885, 31269, 33381, 3661, 40925,
+ 42925, 45173, 4525, 4709, 53133, 55941, 57413, 57797,
+ 62125, 62237, 62733, 6773, 12317, 13197, 16533, 16933,
+ 18245, 2213, 2477, 29757, 33293, 35517, 40133, 40749,
+ 4661, 49941, 62757, 7853, 8149, 8573, 11029, 13421,
+ 21549, 22709, 22725, 24629, 2469, 26125, 2669, 34253,
+ 36709, 41013, 45597, 46637, 52285, 52333, 54685, 59013,
+ 60997, 61189, 61981, 62605, 62821, 7077, 7525, 8781,
+ 10861, 15277, 2205, 22077, 28517, 28949, 32109, 33493,
+ 3685, 39197, 39869, 42621, 44997, 48565, 5221, 57381,
+ 61749, 62317, 63245, 63381, 23149, 2549, 28661, 31653,
+ 33885, 36341, 37053, 39517, 42805, 45853, 48997, 59349,
+ 60053, 62509, 63069, 6525, 1893, 20181, 2365, 24893,
+ 27397, 31357, 32277, 33357, 34437, 36677, 37661, 43469,
+ 43917, 50997, 53869, 5653, 13221, 16741, 17893, 2157,
+ 28653, 31789, 35301, 35821, 61613, 62245, 12405, 14517,
+ 17453, 18421, 3149, 3205, 40341, 4109, 43941, 46869,
+ 48837, 50621, 57405, 60509, 62877, 8157, 12933, 12957,
+ 16501, 19533, 3461, 36829, 52357, 58189, 58293, 63053,
+ 17109, 1933, 32157, 37701, 59005, 61621, 13029, 15085,
+ 16493, 32317, 35093, 5061, 51557, 62221, 20765, 24613,
+ 2629, 30861, 33197, 33749, 35365, 37933, 40317, 48045,
+ 56229, 61157, 63797, 7917, 17965, 1917, 1973, 20301,
+ 2253, 33157, 58629, 59861, 61085, 63909, 8141, 9221,
+ 14757, 1581, 21637, 26557, 33869, 34285, 35733, 40933,
+ 42517, 43501, 53653, 61885, 63805, 7141, 21653, 54973,
+ 31189, 60061, 60341, 63357, 16045, 2053, 26069, 33997,
+ 43901, 54565, 63837, 8949, 17909, 18693, 32349, 33125,
+ 37293, 48821, 49053, 51309, 64037, 7117, 1445, 20405,
+ 23085, 26269, 26293, 27349, 32381, 33141, 34525, 36461,
+ 37581, 43525, 4357, 43877, 5069, 55197, 63965, 9845,
+ 12093, 2197, 2229, 32165, 33469, 40981, 42397, 8749,
+ 10853, 1453, 18069, 21693, 30573, 36261, 37421, 42533
+};
+#define NSID_MULT_TABLE_SIZE \
+ ((sizeof nsid_multiplier_table)/(sizeof nsid_multiplier_table[0]))
void
-nsid_init() {
- nsid_state = res_randomid();
+nsid_init(void) {
+ struct timeval now;
+ pid_t mypid;
+ u_int16_t a1ndx, a2ndx, a3ndx, c1ndx, c2ndx, c3ndx;
+ int i;
+
+ if (nsid_algorithm != 0)
+ return;
+
+ gettimeofday(&now, NULL);
+ mypid = getpid();
+
+ /* Initialize the state */
+ nsid_hash_state = 0;
+ nsid_hash((u_char *)&now, sizeof now);
+ nsid_hash((u_char *)&mypid, sizeof mypid);
+
+ /*
+ * Select our random number generators and initial seed.
+ * We could really use more random bits at this point,
+ * but we'll try to make a silk purse out of a sows ear ...
+ */
+ /* generator 1 */
+ a1ndx = ((u_long) NSID_MULT_TABLE_SIZE *
+ (nsid_hash_state & 0xFFFF)) >> 16;
+ nsid_a1 = nsid_multiplier_table[a1ndx];
+ c1ndx = (nsid_hash_state >> 9) & 0x7FFF;
+ nsid_c1 = 2*c1ndx + 1;
+ /* generator 2, distinct from 1 */
+ a2ndx = ((u_long) (NSID_MULT_TABLE_SIZE - 1) *
+ ((nsid_hash_state >> 10) & 0xFFFF)) >> 16;
+ if (a2ndx >= a1ndx)
+ a2ndx++;
+ nsid_a2 = nsid_multiplier_table[a2ndx];
+ c2ndx = nsid_hash_state % 32767;
+ if (c2ndx >= c1ndx)
+ c2ndx++;
+ nsid_c2 = 2*c2ndx + 1;
+ /* generator 3, distinct from 1 and 2 */
+ a3ndx = ((u_long) (NSID_MULT_TABLE_SIZE - 2) *
+ ((nsid_hash_state >> 20) & 0xFFFF)) >> 16;
+ if (a3ndx >= a1ndx || a3ndx >= a2ndx)
+ a3ndx++;
+ if (a3ndx >= a1ndx && a3ndx >= a2ndx)
+ a3ndx++;
+ nsid_a3 = nsid_multiplier_table[a3ndx];
+ c3ndx = nsid_hash_state % 32766;
+ if (c3ndx >= c1ndx || c3ndx >= c2ndx)
+ c3ndx++;
+ if (c3ndx >= c1ndx && c3ndx >= c2ndx)
+ c3ndx++;
+ nsid_c3 = 2*c3ndx + 1;
+
+ nsid_state = ((nsid_hash_state >> 16) ^ (nsid_hash_state)) & 0xFFFF;
+
+ /* Do the algorithm specific initialization */
+ INSIST(server_options != NULL);
+ if (NS_OPTION_P(OPTION_USE_ID_POOL) == 0) {
+ /* Algorithm 1 */
+ nsid_algorithm = NSID_SHUFFLE_ONLY;
+ nsid_vtable = memget(NSID_SHUFFLE_TABLE_SIZE *
+ (sizeof(u_int16_t)) );
+ if (!nsid_vtable)
+ ns_panic(ns_log_default, 1, "memget(nsid_vtable)",
+ NULL);
+ for (i = 0; i < NSID_SHUFFLE_TABLE_SIZE; i++) {
+ nsid_vtable[i] = nsid_state;
+ nsid_state = (((u_long) nsid_a1 * nsid_state) + nsid_c1)
+ & 0xFFFF;
+ }
+ nsid_state2 = nsid_state;
+ } else {
+ /* Algorithm 2 */
+ nsid_algorithm = NSID_USE_POOL;
+ nsid_pool = memget(0x10000 * (sizeof(u_int16_t)));
+ if (!nsid_pool)
+ ns_panic(ns_log_default, 1, "memget(nsid_pool)", NULL);
+ for (i = 0; ; i++) {
+ nsid_pool[i] = nsid_state;
+ nsid_state = (((u_long) nsid_a1 * nsid_state) + nsid_c1) & 0xFFFF;
+ if (i == 0xFFFF)
+ break;
+ }
+ }
}
+#define NSID_RANGE_MASK (NSID_LOOKAHEAD - 1)
+
+#define NSID_POOL_MASK 0xFFFF /* used to wrap the pool index */
+
u_int16_t
nsid_next() {
- if (nsid_state == 65535)
- nsid_state = 0;
- else
- nsid_state++;
- return (nsid_state);
+ u_int16_t id, compressed_hash;
+
+ compressed_hash = ((nsid_hash_state >> 16) ^ (nsid_hash_state)) &
+ 0xFFFF;
+ if (nsid_algorithm == NSID_SHUFFLE_ONLY) {
+ u_int16_t j;
+
+ /*
+ * This is the original Algorithm B
+ * j = ((u_long) NSID_SHUFFLE_TABLE_SIZE * nsid_state2)
+ * >> 16;
+ *
+ * We'll perturb it with some random stuff ...
+ */
+ j = ((u_long) NSID_SHUFFLE_TABLE_SIZE *
+ (nsid_state2 ^ compressed_hash)) >> 16;
+ nsid_state2 = id = nsid_vtable[j];
+ nsid_state = (((u_long) nsid_a1 * nsid_state) + nsid_c1) &
+ 0xFFFF;
+ nsid_vtable[j] = nsid_state;
+ } else if (nsid_algorithm == NSID_USE_POOL) {
+ u_int16_t pick;
+
+ pick = compressed_hash & NSID_RANGE_MASK;
+ id = nsid_pool[(nsid_state + pick) & NSID_POOL_MASK];
+ if (pick != 0) {
+ /* Swap two IDs to stir the pool */
+ nsid_pool[(nsid_state + pick) & NSID_POOL_MASK] =
+ nsid_pool[nsid_state];
+ nsid_pool[nsid_state] = id;
+ }
+
+ /* increment the base pointer into the pool */
+ if (nsid_state == 65535)
+ nsid_state = 0;
+ else
+ nsid_state++;
+ } else
+ ns_panic(ns_log_default, 1, "Unknown ID algorithm", NULL);
+
+ /* Now lets obfuscate ... */
+ id = (((u_long) nsid_a2 * id) + nsid_c2) & 0xFFFF;
+ id = (((u_long) nsid_a3 * id) + nsid_c3) & 0xFFFF;
+
+ return (id);
}
+/* Note: this function CAN'T deallocate the saved_argv[]. */
static void
deallocate_everything(void) {
FILE *f;
@@ -2010,6 +2495,7 @@ deallocate_everything(void) {
free_addinfo();
ns_shutdown();
dq_remove_all();
+ db_lame_destroy();
if (local_addresses != NULL)
free_ip_match_list(local_addresses);
if (local_networks != NULL)
@@ -2020,12 +2506,23 @@ deallocate_everything(void) {
evDestroy(ev);
if (conffile != NULL)
freestr(conffile);
+ conffile = NULL;
+ if (debugfile != NULL)
+ freestr(debugfile);
+ debugfile = NULL;
if (user_name != NULL)
freestr(user_name);
+ user_name = NULL;
if (group_name != NULL)
freestr(group_name);
+ group_name = NULL;
if (chroot_dir != NULL)
freestr(chroot_dir);
+ chroot_dir = NULL;
+ if (nsid_pool != NULL)
+ memput(nsid_pool, 0x10000 * (sizeof(u_int16_t)));
+ nsid_pool = NULL;
+ irs_destroy();
if (f != NULL) {
memstats(f);
(void)fclose(f);
@@ -2034,7 +2531,12 @@ deallocate_everything(void) {
static void
ns_exit(void) {
- ns_info(ns_log_default, "named shutting down");
+ main_needs_exit++;
+}
+
+static void
+ns_restart(void) {
+ ns_info(ns_log_default, "named restarting");
#ifdef BIND_UPDATE
dynamic_about_to_exit();
#endif
@@ -2043,16 +2545,18 @@ ns_exit(void) {
ns_logstats(ev, NULL, evNowTime(), evConsTime(0, 0));
if (NS_OPTION_P(OPTION_DEALLOC_ON_EXIT))
deallocate_everything();
- exit(0);
+ else
+ shutdown_configuration();
+ execvp(saved_argv[0], saved_argv);
+ abort();
}
static void
use_desired_debug(void) {
#ifdef DEBUG
sigset_t set;
- int bad;
- /* protect against race conditions by blocking debugging signals */
+ /* Protect against race conditions by blocking debugging signals. */
if (sigemptyset(&set) < 0) {
ns_error(ns_log_os,
@@ -2086,73 +2590,76 @@ use_desired_debug(void) {
#endif
}
-static void
+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);
+wild(void) {
+ ns_panic(ns_log_default, 1, "wild need", NULL);
}
-#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 }
- };
+static void
+init_needs(void) {
+ int need;
+
+ for (need = 0; need < main_need_num; need++)
+ handlers[need] = wild;
+ handlers[main_need_zreload] = ns_zreload;
+ handlers[main_need_reload] = ns_reload;
+ handlers[main_need_reconfig] = ns_reconfig;
+ handlers[main_need_endxfer] = endxfer;
+ handlers[main_need_zoneload] = loadxfer;
+ handlers[main_need_dump] = doadump;
+ handlers[main_need_statsdump] = ns_stats;
+ handlers[main_need_exit] = ns_exit;
+ handlers[main_need_qrylog] = toggle_qrylog;
+ handlers[main_need_debug] = use_desired_debug;
+ handlers[main_need_restart] = ns_restart;
+ handlers[main_need_reap] = reapchild;
+}
-void
-ns_setoption(int option) {
- ns_warning(ns_log_default, "used obsolete ns_setoption(%d)", option);
+static void
+handle_need(void) {
+ int need;
+
+ ns_debug(ns_log_default, 15, "handle_need()");
+ for (need = 0; need < main_need_num; need++)
+ if ((needs & (1 << need)) != 0) {
+ /* Turn off flag first, handlers ~turn~ it back on. */
+ block_signals();
+ needs &= ~(1 << need);
+ unblock_signals();
+ (handlers[need])();
+ return;
+ }
+ ns_panic(ns_log_default, 1, "handle_need() found no needs", NULL);
}
void
-ns_need(int need) {
- needs |= need;
+ns_need(enum need need) {
+ block_signals();
+ ns_need_unsafe(need);
+ unblock_signals();
}
-int
-ns_need_p(int need) {
- return ((needs & need) != 0);
+/* Note: this function should only be called with signals blocked. */
+void
+ns_need_unsafe(enum need need) {
+ needs |= (1 << need);
}
-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
+ns_setoption(int option) {
+ ns_warning(ns_log_default, "used obsolete ns_setoption(%d)", option);
}
-
void
writestream(struct qstream *sp, const u_char *msg, int msglen) {
if (sq_openw(sp, msglen + INT16SZ) == -1) {
@@ -2166,45 +2673,6 @@ writestream(struct qstream *sp, const u_char *msg, int msglen) {
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')
@@ -2216,3 +2684,54 @@ only_digits(const char *s) {
}
return (1);
}
+#if defined(__GNUC__) && defined(__BOUNDS_CHECKING_ON)
+ /* Use bounds checking malloc, etc. */
+void *
+memget(size_t len) {
+ return (malloc(len));
+}
+
+void
+memput(void *addr, size_t len) {
+ free(addr);
+}
+
+int
+meminit(size_t init_max_size, size_t target_size) {
+ return (0);
+}
+
+void *
+memget_debug(size_t size, const char *file, int line) {
+ void *ptr;
+ ptr = __memget(size);
+ fprintf(stderr, "%s:%d: memget(%lu) -> %p\n", file, line,
+ (u_long)size, ptr);
+ return (ptr);
+}
+
+void
+memput_debug(void *ptr, size_t size, const char *file, int line) {
+ fprintf(stderr, "%s:%d: memput(%p, %lu)\n", file, line, ptr,
+ (u_long)size);
+ __memput(ptr, size);
+}
+
+void
+memstats(FILE *out) {
+ fputs("No memstats\n", out);
+}
+#endif
+
+#ifndef HAVE_CUSTOM
+/* Standard implementation has nothing here */
+static void
+custom_init(void) {
+ /* Noop. */
+}
+
+static void
+custom_shutdown(void) {
+ /* Noop. */
+}
+#endif
diff --git a/contrib/bind/bin/named/ns_maint.c b/contrib/bind/bin/named/ns_maint.c
index 75568ff..69a8fc3 100644
--- a/contrib/bind/bin/named/ns_maint.c
+++ b/contrib/bind/bin/named/ns_maint.c
@@ -1,6 +1,6 @@
#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.39 1998/04/14 00:34:39 halley Exp $";
+static const char sccsid[] = "@(#)ns_maint.c 4.39 (Berkeley) 3/2/91";
+static const char rcsid[] = "$Id: ns_maint.c,v 8.95 1999/10/13 16:39:09 vixie Exp $";
#endif /* not lint */
/*
@@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $";
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -73,6 +73,26 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $";
* SOFTWARE.
*/
+/*
+ * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc.
+ *
+ * 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 Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES
+ * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED
+ * 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>
@@ -80,11 +100,13 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $";
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/stat.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
+#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <resolv.h>
@@ -99,25 +121,25 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $";
#include <isc/logging.h>
#include <isc/memcluster.h>
+#include <isc/dst.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),
+static int 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)
+#ifndef HAVE_SPAWNXFER
+static pid_t spawnxfer(char **, struct zoneinfo *);
+#endif
-static time_t stats_time;
+static time_t stats_time; /* Redundant ??? XXX ogud */
/* State of all running zone transfers */
static struct {
@@ -132,23 +154,6 @@ static struct {
/*
- * 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
@@ -173,10 +178,16 @@ zone_maint(struct zoneinfo *zp) {
#endif
if (zp->z_serial != 0 &&
((zp->z_lastupdate+zp->z_expire) < (u_int32_t)tt.tv_sec)) {
+ /* calls purge_zone */
+ do_reload(zp->z_origin, zp->z_type, zp->z_class, 0);
+ /* reset zone state */
+ zp->z_flags &= ~Z_AUTH;
+ zp->z_refresh = INIT_REFRESH;
+ zp->z_retry = INIT_REFRESH;
zp->z_serial = 0;
- /* XXX should we clear Z_AUTH here? */
}
- if (zp->z_flags & (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL)) {
+ if ((zp->z_flags & (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL)) != 0)
+ {
ns_retrytime(zp, tt.tv_sec);
break;
}
@@ -190,12 +201,26 @@ zone_maint(struct zoneinfo *zp) {
zp->z_time = tt.tv_sec + 30;
break;
}
- qserial_query(zp);
+ /*
+ * If we don't have the zone loaded or dialup is off
+ * or we attempted a qserial_query before and the queue was
+ * full attempt to verify / load the zone.
+ */
+ if ((zp->z_serial == 0) || (zp->z_flags & Z_NEED_QSERIAL) ||
+ (zp->z_dialup == zdialup_no) ||
+ (zp->z_dialup == zdialup_use_default &&
+ NS_OPTION_P(OPTION_NODIALUP)))
+ qserial_query(zp);
+ else {
+ ns_info(ns_log_default, "Suppressed qserial_query(%s)",
+ *(zp->z_origin) ? zp->z_origin : ".");
+ ns_refreshtime(zp, tt.tv_sec);
+ }
break;
#ifdef BIND_UPDATE
case Z_PRIMARY:
- if (! (zp->z_flags & Z_DYNAMIC))
+ if ((zp->z_flags & Z_DYNAMIC) == 0)
break;
if (tt.tv_sec >= zp->z_soaincrtime &&
zp->z_soaincrintvl > 0 &&
@@ -214,7 +239,7 @@ zone_maint(struct zoneinfo *zp) {
if (tt.tv_sec >= zp->z_dumptime &&
zp->z_dumpintvl > 0 &&
zp->z_flags & Z_NEED_DUMP) {
- if (zonedump(zp) < 0) {
+ if (zonedump(zp, ISNOTIXFR) < 0) {
/* Try again later. */
ns_error(ns_log_maint,
"zone dump for '%s' failed, rescheduling",
@@ -222,6 +247,8 @@ zone_maint(struct zoneinfo *zp) {
zp->z_dumptime = 0;
(void)schedule_dump(zp);
}
+ if (zp->z_maintain_ixfr_base)
+ ixfr_log_maint(zp);
}
break;
#endif /* BIND_UPDATE */
@@ -249,11 +276,18 @@ do_zone_maint(evContext ctx, void *uap, struct timespec due,
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);
+ zp = find_zone(zti->name, 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,
+ zoneTypeString(zti->type), zti->name,
+ p_class(zti->class));
+ return;
+ }
+ if (zp->z_type != zti->type) {
+ ns_error(ns_log_maint,
+ "do_zone_maint: %s zone '%s' (class %s) has changed its type",
+ zoneTypeString(zti->type), zti->name,
p_class(zti->class));
return;
}
@@ -270,13 +304,12 @@ do_zone_maint(evContext ctx, void *uap, struct timespec due,
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_type == z_master && (zp->z_flags & Z_DYNAMIC) != 0) {
if (zp->z_soaincrintvl > 0 &&
(next_maint == 0 || next_maint > zp->z_soaincrtime))
next_maint = zp->z_soaincrtime;
@@ -363,10 +396,46 @@ ns_cleancache(evContext ctx, void *uap,
gettime(&tt);
INSIST(uap == NULL);
deleted = clean_cache(hashtab, 0);
- ns_info(ns_log_maint, "Cleaned cache of %d RR%s",
+ ns_info(ns_log_maint, "Cleaned cache of %d RRset%s",
deleted, (deleted==1) ? "" : "s");
}
+void
+ns_heartbeat(evContext ctx, void *uap, struct timespec due,
+ struct timespec inter)
+{
+ struct zoneinfo *zp;
+
+ gettime(&tt);
+ INSIST(uap == NULL);
+
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ enum zonetype zt = zp->z_type;
+
+ if ((zt == z_nil) ||
+ (zp->z_dialup == zdialup_no) ||
+ (zp->z_dialup == zdialup_use_default &&
+ NS_OPTION_P(OPTION_NODIALUP)))
+ continue;
+#ifdef BIND_NOTIFY
+ if ((zp->z_notify == znotify_no) ||
+ ((zp->z_notify == znotify_use_default) &&
+ NS_OPTION_P(OPTION_NONOTIFY)))
+ continue;
+#endif
+ if ((zt == z_slave || zt == z_stub) &&
+ (zp->z_flags &
+ (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL|Z_XFER_RUNNING)
+ ) == 0) {
+ ns_info(ns_log_default,
+ "Heartbeat: qserial \"%s\"",
+ *(zp->z_origin) ? zp->z_origin : ".");
+ qserial_query(zp);
+ }
+ }
+}
+
+
/*
* Mark a zone "up to date" after named-xfer tells us this or we
* discover it through the qserial_*() logic.
@@ -418,57 +487,131 @@ qserial_query(struct zoneinfo *zp) {
ns_debug(ns_log_default, 1, "qserial_query(%s)", zp->z_origin);
- if (qserial_qfull()) {
+ if (qserials_running >= server_options->serial_queries) {
qserial_retrytime(zp, tt.tv_sec);
+ zp->z_flags |= Z_NEED_QSERIAL;
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);
+ zp->z_addr, zp->z_addrcnt,
+ ntohs(zp->z_port) ? zp->z_port : ns_port,
+ QUERY);
+ if (qp == NULL) {
+ ns_debug(ns_log_default, 1,
+ "qserial_query(%s): sysquery FAILED",
+ zp->z_origin);
/* XXX - this is bad, we should do something */
qserial_retrytime(zp, tt.tv_sec);
+ zp->z_flags |= Z_NEED_QSERIAL;
return;
}
qp->q_flags |= Q_ZSERIAL;
qp->q_zquery = zp;
zp->z_flags |= Z_QSERIAL;
- zp->z_xaddr = inaddr_any;
+ zp->z_flags &= ~Z_NEED_QSERIAL;
+ zp->z_xaddrcnt = 0;
ns_refreshtime(zp, tt.tv_sec);
qserials_running++;
ns_debug(ns_log_default, 1, "qserial_query(%s) QUEUED", zp->z_origin);
}
+static int
+qserv_compare(const void *a, const void *b) {
+ const struct qserv *qs1 = a, *qs2 = b;
+ u_int32_t s1 = qs1->serial, s2 = qs2->serial;
+
+ /* Note that we sort the "best" serial numbers to the front. */
+ if (s1 == s2)
+ return (0);
+ if (s1 == 0)
+ return (-1);
+ if (s2 == 0)
+ return (1);
+ if (!SEQ_GT(s1, s2))
+ return (1);
+ assert(SEQ_GT(s1, s2));
+ return (-1);
+}
+
void
-qserial_answer(struct qinfo *qp, u_int32_t serial, struct sockaddr_in from) {
+qserial_answer(struct qinfo *qp) {
struct zoneinfo *zp = qp->q_zquery;
+ struct qserv *qs = NULL;
+ u_int32_t serial = 0;
+ int n, cnt = 0;
- ns_debug(ns_log_default, 1, "qserial_answer(%s, %u)", zp->z_origin,
- serial);
+ /* Take this query out of the global quotas. */
zp->z_flags &= ~Z_QSERIAL;
qp->q_flags &= ~Q_ZSERIAL; /* keeps us from being called twice */
qserials_running--;
+
+ /* Find best serial among those returned. */
+ for (n = 0; n < qp->q_naddr; n++) {
+ qs = &qp->q_addr[n];
+ ns_debug(ns_log_default, 1, "qserial_answer(%s): [%s] -> %lu",
+ zp->z_origin, inet_ntoa(qs->ns_addr.sin_addr),
+ qs->serial);
+ /* Don't consider serials which weren't set by a response. */
+ if (qs->serial == 0)
+ continue;
+ /* Count valid answers. */
+ cnt++;
+ /* Remove from consideration serials which aren't "better." */
+ if (zp->z_serial != 0 && !SEQ_GT(qs->serial, zp->z_serial)) {
+ if (serial == 0 && qs->serial == zp->z_serial)
+ serial = qs->serial;
+
+ if (qs->serial != zp->z_serial)
+ ns_notice(ns_log_xfer_in,
+ "Zone \"%s\" (%s) SOA serial# (%lu) rcvd from [%s] is < ours (%lu)%s",
+ zp->z_origin, p_class(zp->z_class),
+ qs->serial,
+ inet_ntoa(qs->ns_addr.sin_addr),
+ zp->z_serial, qp->q_naddr != 1 ?
+ ": skipping" : "");
+ qs->serial = 0;
+ continue;
+ }
+ if (serial == 0 || SEQ_GT(qs->serial, serial))
+ serial = qs->serial;
+ }
+
+ /* If we have an existing serial number, then sort by "better." */
+ if (zp->z_serial != 0) {
+ qsort(qp->q_addr, qp->q_naddr, sizeof(struct qserv),
+ qserv_compare);
+ for (n = 0; n < qp->q_naddr; n++) {
+ qs = &qp->q_addr[n];
+ ns_debug(ns_log_default, 1,
+ "qserial_answer after sort: [%s] -> %lu",
+ inet_ntoa(qs->ns_addr.sin_addr),
+ qs->serial);
+ }
+ }
+
+ /* Now see about kicking off an inbound transfer. */
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);
+ /* An error occurred, or the all queries timed out. */
+ if (qp->q_naddr != cnt)
+ ns_info(ns_log_xfer_in,
+ "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,
+ } else if (zp->z_serial == 0 || SEQ_GT(serial, zp->z_serial)) {
+ ns_debug(ns_log_xfer_in, 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);
+ /* Use all servers whose serials are better than ours. */
+ zp->z_xaddrcnt = 0;
+ for (n = 0; n < qp->q_naddr; n++) {
+ qs = &qp->q_addr[n];
+ if (qs->serial != 0)
+ zp->z_xaddr[zp->z_xaddrcnt++] =
+ qs->ns_addr.sin_addr;
}
- } else {
- ns_debug(ns_log_default, 1,
+ addxfer(zp);
+ } else if (zp->z_serial == serial) {
+ ns_debug(ns_log_xfer_in, 1,
"qserial_answer: zone serial is still OK");
markUpToDate(zp);
sched_zone_maint(zp);
@@ -476,34 +619,86 @@ qserial_answer(struct qinfo *qp, u_int32_t serial, struct sockaddr_in from) {
}
/*
- * 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.
+ * Writes TSIG key info for an address to a file, optionally opening it first.
+ */
+static int
+write_tsig_info(struct in_addr addr, char *name, int *fd, int creat_failed) {
+ server_info si;
+ DST_KEY *dst_key;
+ int tsig_fd = *fd;
+ char tsig_str[1024], secret_buf64[172];
+ u_char secret_buf[128];
+ int secret_len;
+
+ si = find_server(addr);
+ if (si == NULL || si->key_list == NULL || si->key_list->first == NULL)
+ return(0);
+ dst_key = si->key_list->first->key;
+ if (tsig_fd < 0 && creat_failed == 0) {
+ *fd = tsig_fd = creat(name, S_IRUSR);
+ if (tsig_fd < 0) {
+ ns_warning(ns_log_default,
+ "write_tsig_info: creat(%s) for TSIG info failed",
+ name);
+ return(-1);
+ }
+ }
+ if (creat_failed != 0)
+ return(-1);
+ memset(secret_buf, 0, sizeof(secret_buf));
+ secret_len = dst_key_to_buffer(dst_key, secret_buf, sizeof(secret_buf));
+ b64_ntop(secret_buf, secret_len, secret_buf64, sizeof(secret_buf64));
+ sprintf(tsig_str, "%s\n%s\n%d\n%s\n",
+ inet_ntoa(addr), dst_key->dk_key_name, dst_key->dk_alg,
+ secret_buf64);
+ write(tsig_fd, tsig_str, strlen(tsig_str));
+ return (0);
+}
+
+/*
+ * Start an asynchronous zone transfer for a zone. Depends on current time
+ * being in tt. Caller must do a sched_zone_maint(zp) after we return.
*/
static void
startxfer(struct zoneinfo *zp) {
- char *argv[NSMAX + 20], argv_ns[NSMAX][MAXDNAME];
- int argc = 0, argc_ns = 0, pid, i;
+ char *argv[NSMAX*2 + 20], argv_ns[NSMAX][MAXDNAME];
+ int argc = 0, argc_ns = 0, i;
+ pid_t pid;
u_int cnt;
char debug_str[10];
char serial_str[10];
char port_str[10];
char class_str[10];
char src_str[20];
+ int tsig_fd = -1;
+ char tsig_name[MAXPATHLEN+1], *s;
+ int tsig_ret = 0;
- ns_debug(ns_log_default, 1, "startxfer() %s", zp->z_origin);
+ ns_debug(ns_log_default, 1, "startxfer() %s",
+ zp->z_origin[0] != '\0' ? 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) {
+#ifdef BIND_IXFR
+ if (zp->z_ixfr_tmp) {
+ argv[argc++] = "-i";
+ argv[argc++] = zp->z_ixfr_tmp;
+ }
+#endif
+ if (zp->z_serial != 0) {
+ argv[argc++] = "-s";
+ sprintf(serial_str, "%u", zp->z_serial);
+ argv[argc++] = serial_str;
+ }
+ if (zp->z_axfr_src.s_addr != 0 ||
+ server_options->axfr_src.s_addr != 0) {
argv[argc++] = "-x";
- argv[argc++] = strcpy(src_str, inet_ntoa(zp->z_axfr_src));
+ argv[argc++] = strcpy(src_str, inet_ntoa(
+ (zp->z_axfr_src.s_addr != 0) ? zp->z_axfr_src :
+ server_options->axfr_src));
}
argv[argc++] = "-C";
sprintf(class_str, "%d", zp->z_class);
@@ -511,8 +706,14 @@ startxfer(struct zoneinfo *zp) {
if (zp->z_flags & Z_SYSLOGGED)
argv[argc++] = "-q";
argv[argc++] = "-P";
- sprintf(port_str, "%d", ns_port);
+ sprintf(port_str, "%d", ntohs(zp->z_port) != 0 ? zp->z_port : ns_port);
argv[argc++] = port_str;
+ argv[argc++] = "-T";
+ sprintf(tsig_name, "%s.%d", zp->z_origin, getpid());
+ s = tsig_name;
+ while ((s = strchr(s, '/')) != NULL)
+ *s = '_';
+ argv[argc++] = tsig_name;
#ifdef STUBS
if (zp->z_type == Z_STUB)
argv[argc++] = "-S";
@@ -531,40 +732,45 @@ startxfer(struct zoneinfo *zp) {
}
#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));
+ if (zp->z_xaddrcnt == 0) {
+ for (zp->z_xaddrcnt = 0;
+ zp->z_xaddrcnt < zp->z_addrcnt;
+ zp->z_xaddrcnt++)
+ zp->z_xaddr[zp->z_xaddrcnt] =
+ zp->z_addr[zp->z_xaddrcnt];
}
/*
* Copy the server ip addresses into argv, after converting
- * to ascii and saving the static inet_ntoa result. Skip zp->z_xaddr
- * if seen.
+ * to ascii and saving the static inet_ntoa result.
+ * Also, send TSIG key info into a file for the child.
*/
- for (cnt = 0; cnt < zp->z_addrcnt; cnt++) {
+ for (cnt = 0; cnt < zp->z_xaddrcnt; 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));
+ a = zp->z_xaddr[cnt];
+ if (aIsUs(a) && ns_port == zp->z_port) {
+ if (!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));
+#ifdef BIND_IXFR
+ if (zp->z_ixfr_tmp != NULL) {
+ server_info si = find_server(a);
+
+ if (si != NULL &&
+ (si->flags & SERVER_INFO_SUPPORT_IXFR) != 0)
+ argv[argc++] = "ixfr";
+ else
+ argv[argc++] = "axfr";
+ }
+#endif
+ tsig_ret = write_tsig_info(a, tsig_name, &tsig_fd, tsig_ret);
}
+ if (tsig_fd > 0)
+ close(tsig_fd);
argv[argc] = NULL;
@@ -594,26 +800,21 @@ startxfer(struct zoneinfo *zp) {
#endif /* DEBUG */
gettime(&tt);
- for (i = 0; i < MAX_XFERS_RUNNING; i++) {
- if (xferstatus[i].xfer_pid == 0) {
- xferstatus[i].xfer_state = XFER_RUNNING;
+ for (i = 0; i < MAX_XFERS_RUNNING; i++)
+ if (xferstatus[i].xfer_pid == 0)
break;
- }
- }
- if ((pid = vfork()) == -1) {
- ns_error(ns_log_default, "xfer vfork: %s", strerror(errno));
+ if (i == MAX_XFERS_RUNNING) {
+ ns_warning(ns_log_default,
+ "startxfer: too many xfers running");
zp->z_time = tt.tv_sec + 10;
+ (void)nxfers(zp, -1);
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. */
+
+ if ((pid = spawnxfer(argv, zp)) == -1)
+ unlink(tsig_name);
+
+ xferstatus[i].xfer_state = XFER_RUNNING;
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);
@@ -628,18 +829,20 @@ startxfer(struct zoneinfo *zp) {
}
const char *
-zoneTypeString(const struct zoneinfo *zp) {
+zoneTypeString(u_int type) {
static char ret[sizeof "(4294967296?)"]; /* 2^32 */
- switch (zp->z_type) {
+ switch (type) {
case Z_MASTER: return ("master");
case Z_SLAVE: return ("slave");
#ifdef STUBS
case Z_STUB: return ("stub");
#endif
+ case Z_HINT: return ("hint");
case Z_CACHE: return ("cache");
+ case Z_FORWARD: return ("forward");
default:
- sprintf(ret, "(%u?)", (u_int32_t)zp->z_type);
+ sprintf(ret, "(%u?)", type);
return (ret);
}
}
@@ -660,7 +863,7 @@ printzoneinfo(int zonenum, int category, int level) {
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));
+ p_class(zp->z_class), zoneTypeString(zp->z_type));
if (zp->z_source)
ns_debug(category, level, "\tsource %s", zp->z_source);
ns_debug(category, level, "\tflags %lx, serial %u, minimum %u",
@@ -674,7 +877,7 @@ printzoneinfo(int zonenum, int category, int level) {
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) {
+ if (zp->z_type == z_master && (zp->z_flags & Z_DYNAMIC) != 0) {
ns_debug(category, level,
"\tdumpintvl %lu, soaincrintvl %lu deferupdcnt %lu",
zp->z_dumpintvl, zp->z_soaincrintvl,
@@ -700,13 +903,58 @@ printzoneinfo(int zonenum, int category, int level) {
}
#endif /* DEBUG */
+/*
+ * Remove all cached data below dname, class independent.
+ */
+void
+clean_cache_from(char *dname, struct hashbuf *htp) {
+ const char *fname;
+ struct databuf *dp, *pdp;
+ struct namebuf *np;
+ struct hashbuf *phtp = htp;
+ int root_zone = 0;
+
+ ns_debug(ns_log_default, 1, "clean_cache_from(%s)", dname);
+ 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_zone == DB_Z_CACHE)
+ 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;
+ (void)clean_cache(h, 1);
+ if (h->h_cnt == 0 && !root_zone) {
+ rm_hash(np->n_hash);
+ np->n_hash = NULL;
+ }
+ }
+
+ if (!root_zone && np->n_hash == NULL && np->n_data == NULL)
+ (void) purge_node(htp, np);
+ }
+}
+
/* 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.
+ * number of deleted RRs (all=1) or RRsets (all=0).
*/
int
clean_cache(struct hashbuf *htp, int all) {
@@ -718,12 +966,17 @@ clean_cache(struct hashbuf *htp, int all) {
nppend = htp->h_tab + htp->h_size;
for (npp = htp->h_tab; npp < nppend; npp++) {
for (pnp = NULL, np = *npp; np != NULL; np = npn) {
+ again:
for (pdp = NULL, dp = np->n_data; dp != NULL;
(void)NULL) {
- if (dp->d_zone == DB_Z_CACHE &&
- (stale(dp) || all)) {
+ if (all && dp->d_zone == DB_Z_CACHE) {
dp = rm_datum(dp, np, pdp, NULL);
deleted++;
+ } else if (dp->d_zone == DB_Z_CACHE &&
+ stale(dp)) {
+ delete_all(np, dp->d_class, dp->d_type);
+ deleted++;
+ goto again;
} else {
pdp = dp;
dp = dp->d_next;
@@ -753,6 +1006,78 @@ clean_cache(struct hashbuf *htp, int all) {
return (deleted);
}
+/* struct namebuf *
+ * purge_node(htp, np)
+ * Remove entry from cache.
+ * Prerequisites:
+ * Node is empty and has no children.
+ * Paramters:
+ * htp - root of recursive hash table this node is part of.
+ * np - the node to be deleted.
+ * Return:
+ * pointer to parent.
+ */
+struct namebuf *
+purge_node(struct hashbuf *htp, struct namebuf *np) {
+ struct namebuf **npp, **nppend;
+ struct namebuf *npn, *pnp, *nnp, *parent;
+ struct hashbuf *phtp;
+
+ ns_debug(ns_log_default, 3, "purge_node: cleaning cache");
+ INSIST(np->n_hash == NULL && np->n_data == NULL);
+
+ /* Walk parent hashtable looking for ourself. */
+ parent = np->n_parent;
+ if (parent != NULL)
+ phtp = parent->n_hash;
+ else
+ phtp = htp;
+
+ if (phtp == NULL) {
+ /* XXX why shouldn't we panic? */
+ } else {
+ 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_node: found ourself");
+ npn = rm_name(nnp, npp, pnp);
+ phtp->h_cnt--;
+ } else {
+ npn = nnp->n_next;
+ pnp = nnp;
+ }
+ }
+ }
+ }
+ return (parent);
+}
+
+void
+remove_zone(struct zoneinfo *zp, const char *verb) {
+#ifdef BIND_UPDATE
+ /*
+ * A dynamic zone might have changed, so we
+ * need to dump it before removing it.
+ */
+ if ((zp->z_flags & Z_DYNAMIC) != 0 &&
+ ((zp->z_flags & Z_NEED_SOAUPDATE) != 0 ||
+ (zp->z_flags & Z_NEED_DUMP) != 0))
+ (void) zonedump(zp, ISNOTIXFR);
+#endif
+ ns_stopxfrs(zp);
+ do_reload(zp->z_origin, zp->z_type, zp->z_class, 1);
+ ns_notice(ns_log_config, "%s zone \"%s\" (%s) %s",
+ zoneTypeString(zp->z_type), zp->z_origin,
+ p_class(zp->z_class), verb);
+ free_zone_contents(zp, 1);
+ memset(zp, 0, sizeof(*zp));
+ zp->z_type = z_nil; /* Pedantic; memset() did it. */
+ INIT_LINK(zp, z_reloadlink);
+ free_zone(zp);
+}
+
void
purge_zone(const char *dname, struct hashbuf *htp, int class) {
const char *fname;
@@ -783,7 +1108,6 @@ purge_zone(const char *dname, struct hashbuf *htp, int class) {
h = htp;
else
h = np->n_hash;
-
purge_z_2(h, class);
if (h->h_cnt == 0 && !root_zone) {
rm_hash(np->n_hash);
@@ -791,39 +1115,8 @@ purge_zone(const char *dname, struct hashbuf *htp, int class) {
}
}
- /* 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;
- }
- }
- }
- }
- }
+ if (!root_zone && np->n_hash == NULL && np->n_data == NULL)
+ (void) purge_node(htp, np);
}
}
@@ -903,12 +1196,12 @@ nxfers(struct zoneinfo *zp, int delta) {
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
+ if (zp->z_xaddrcnt != 0)
+ nsa = zp->z_xaddr[0]; /* first ns holds zone's xfer limit */
+ else if (zp->z_addrcnt != 0)
nsa = zp->z_addr[0]; /* first ns holds zone's xfer limit */
+ else
+ return (-1);
if (!(nsp = nameserFind(nsa, NS_F_INSERT)))
return (-1); /* probably ENOMEM */
@@ -976,27 +1269,25 @@ pid %lu - forgetting, processes may accumulate",
}
/*
- * SIGCHLD signal handler: process exit of xfer's.
+ * Process exit of xfer's.
*/
void
-reapchild(evContext ctx, void *uap, int sig) {
- int pid, i;
+reapchild(void) {
+ int i;
+ pid_t pid;
WAIT_T status;
- int saved_errno = errno;
gettime(&tt);
- while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ while ((pid = (pid_t)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);
+ ns_need(main_need_endxfer);
break;
}
}
}
-
- errno = saved_errno;
}
/*
@@ -1005,7 +1296,8 @@ reapchild(evContext ctx, void *uap, int sig) {
void
endxfer() {
struct zoneinfo *zp;
- int exitstatus, pid, i;
+ int exitstatus, i;
+ pid_t pid;
WAIT_T status;
gettime(&tt);
@@ -1045,11 +1337,43 @@ endxfer() {
sched_zone_maint(zp);
break;
- case XFER_SUCCESS:
+ case XFER_SUCCESSAXFR:
+ case XFER_SUCCESSAXFRIXFRFILE:
+ zp->z_xferpid = XFER_ISAXFR;
+ if (exitstatus == XFER_SUCCESSAXFRIXFRFILE) {
+ zp->z_xferpid = XFER_ISAXFRIXFR;
+ }
+ movefile(zp->z_ixfr_tmp, zp->z_source);
/* XXX should incorporate loadxfer() */
zp->z_flags |= Z_NEED_RELOAD;
zp->z_flags &= ~Z_SYSLOGGED;
- ns_need(MAIN_NEED_ZONELOAD);
+ ns_need(main_need_zoneload);
+ break;
+
+ case XFER_SUCCESSIXFR:
+ zp->z_xferpid = XFER_ISIXFR;
+ zp->z_log_size_ixfr++;
+ ns_notice(ns_log_default,
+ "IXFR Success %s",
+ zp->z_ixfr_tmp);
+ if (merge_logs(zp, zp->z_ixfr_tmp) >= 0) {
+ ns_notice(ns_log_default,
+ "IXFR Merge success %s",
+ zp->z_ixfr_tmp);
+
+ (void)unlink(zp->z_updatelog);
+ (void)unlink(zp->z_ixfr_base);
+ movefile(zp->z_ixfr_tmp,
+ zp->z_ixfr_base);
+ (void)unlink(zp->z_ixfr_tmp);
+ if (zonedump(zp, ISIXFR) < 0)
+ ns_warning(ns_log_db,
+ "error in write ixfr updates to zone file %s",
+ zp ->z_source);
+ } else
+ ns_notice(ns_log_default,
+ "IXFR Merge failed %s",
+ zp->z_ixfr_tmp);
break;
case XFER_TIMEOUT:
@@ -1157,8 +1481,11 @@ tryxfer() {
* Reload zones whose transfers have completed.
*/
void
-loadxfer() {
+loadxfer(void) {
struct zoneinfo *zp;
+ u_int32_t old_serial,new_serial;
+ char *tmpnom;
+ int isixfr;
gettime(&tt);
for (zp = zones; zp < &zones[nzones]; zp++) {
@@ -1166,11 +1493,35 @@ loadxfer() {
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. */
+/* XXX this is bad, should be done in ns_zreload() 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))
+ old_serial = zp->z_serial;
+ if (zp->z_xferpid == XFER_ISIXFR) {
+ tmpnom = zp->z_ixfr_tmp;
+ isixfr = ISIXFR;
+ } else {
+ tmpnom = zp->z_source;
+ purge_zone(zp->z_origin, hashtab, zp->z_class);
+ isixfr = ISNOTIXFR;
+ }
+ if (zp->z_xferpid == XFER_ISAXFRIXFR) {
+ tmpnom= zp->z_source;
+ purge_zone(zp->z_origin, hashtab, zp->z_class);
+ isixfr = ISNOTIXFR;
+ }
+
+ if (!db_load(tmpnom, zp->z_origin, zp, NULL, isixfr)) {
zp->z_flags |= Z_AUTH;
+ if (isixfr == ISIXFR) {
+ new_serial= zp ->z_serial;
+ ns_warning(ns_log_db, "ISIXFR");
+ ns_warning(ns_log_db, "error in updating ixfr data base file %s from %s", zp -> z_ixfr_base, zp ->z_ixfr_tmp);
+ if (zonedump(zp,ISIXFR)<0)
+ ns_warning(ns_log_db, "error in write ixfr updates to zone file %s", zp ->z_source);
+
+ }
+ }
+ zp->z_xferpid = 0;
if (zp->z_flags & Z_TMP_FILE)
(void) unlink(zp->z_source);
sched_zone_maint(zp);
@@ -1181,7 +1532,7 @@ loadxfer() {
/*
* Add this zone to the set of those needing transfers.
*/
-static void
+void
addxfer(struct zoneinfo *zp) {
if (!(zp->z_flags & Z_NEED_XFER)) {
zp->z_flags |= Z_NEED_XFER;
@@ -1191,21 +1542,203 @@ addxfer(struct zoneinfo *zp) {
}
/*
- * Flush and reload data base.
+ * Mark one zone as requiring a reload.
+ * Note that it should be called with signals blocked,
+ * and should not allocate memory (since it can be called from a sighandler).
+ */
+const char *
+deferred_reload_unsafe(struct zoneinfo *zp) {
+ INSIST(zp->z_type != z_nil);
+ if (!zonefile_changed_p(zp))
+ return ("Zone file has not changed.");
+ if (LINKED(zp, z_reloadlink))
+ return ("Zone is already scheduled for reloading.");
+ APPEND(reloadingzones, zp, z_reloadlink);
+ ns_need_unsafe(main_need_zreload);
+ return ("Zone is now scheduled for reloading.");
+}
+
+/*
+ * If we've loaded this file, and the file has not been modified and contains
+ * no $INCLUDE, then there's no need to reload.
+ */
+int
+zonefile_changed_p(struct zoneinfo *zp) {
+ struct stat sb;
+
+ INSIST(zp->z_type != z_nil);
+ return ((zp->z_flags & Z_INCLUDE) != 0 ||
+ stat(zp->z_source, &sb) == -1 ||
+ zp->z_ftime != sb.st_mtime);
+}
+
+int
+reload_master(struct zoneinfo *zp) {
+ INSIST(zp->z_type == z_master);
+ zp->z_flags &= ~Z_AUTH;
+ ns_stopxfrs(zp);
+ /* XXX what about parent zones? */
+ 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) != 0) {
+ 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)) != 0)
+ 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, ISNOTIXFR))
+ 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) != 0)
+ if (merge_logs(zp, zp->z_updatelog) == 1)
+ return (1);
+#endif
+ return (0);
+}
+
+/*
+ * Called by main() when main_need_zreload has been set. Should pull one
+ * zone off of the reloadingzones list and reload it, then if the list is
+ * not then empty, should turn main_need_zreload on again for the next call.
+ * It is not an error to call this when the reloadingzones list is empty.
+ */
+void
+ns_zreload(void) {
+ struct zoneinfo *zp;
+
+ block_signals();
+ if (EMPTY(reloadingzones)) {
+ unblock_signals();
+ return;
+ }
+ zp = HEAD(reloadingzones);
+ UNLINK(reloadingzones, zp, z_reloadlink);
+ unblock_signals();
+
+ reload_master(zp);
+
+ block_signals();
+ if (!EMPTY(reloadingzones))
+ ns_need_unsafe(main_need_zreload);
+ unblock_signals();
+}
+
+/*
+ * Flush and reload configuration file and data base.
*/
void
-ns_reload() {
+ns_reload(void) {
ns_notice(ns_log_default, "reloading nameserver");
+ INSIST(reloading == 0);
qflush();
sq_flush(NULL);
-#ifdef FORCED_RELOAD
- reloading = 1; /* to force transfer if secondary and backing up */
-#endif
+ reloading++; /* To force transfer if secondary and backing up. */
ns_init(conffile);
time(&resettime);
-#ifdef FORCED_RELOAD
- reloading = 0;
-#endif /* FORCED_RELOAD */
+ reloading--;
ns_notice(ns_log_default, "Ready to answer queries.");
}
+
+/*
+ * Reload configuration, look for new or deleted zones, not changed ones.
+ */
+void
+ns_reconfig(void) {
+ INSIST(reconfiging == 0);
+ reconfiging++; /* To ignore zones which aren't new or deleted. */
+ ns_reload();
+ reconfiging--;
+}
+
+void
+make_new_zones(void) {
+ struct zoneinfo *zp;
+ int n;
+
+ ns_debug(ns_log_config, 1, "Adding %d template zones", NEWZONES);
+ zp = (struct zoneinfo *)
+ memget((nzones + NEWZONES) * sizeof(struct zoneinfo));
+ if (zp == NULL)
+ panic("no memory for more zones", NULL);
+ memset(zp, 0, (nzones + NEWZONES) * sizeof(struct zoneinfo));
+ if (zones != NULL) {
+ memcpy(zp, zones, nzones * sizeof(struct zoneinfo));
+ memput(zones, nzones * sizeof(struct zoneinfo));
+ }
+ zones = zp;
+ block_signals();
+ for (n = 0; n < NEWZONES; n++) {
+ INIT_LINK(&zones[nzones], z_reloadlink);
+ if (nzones != 0)
+ free_zone(&zones[nzones]);
+ nzones++;
+ }
+ unblock_signals();
+}
+
+void
+free_zone(struct zoneinfo *zp) {
+ if (LINKED(zp, z_reloadlink))
+ panic("freeing reloading zone", NULL);
+ if (zp->z_type != z_nil)
+ panic("freeing unfree zone", NULL);
+ APPEND(freezones, zp, z_freelink);
+}
+
+#ifndef HAVE_SPAWNXFER
+static pid_t
+spawnxfer(char **argv, struct zoneinfo *zp) {
+ pid_t pid = (pid_t)vfork();
+
+ if (pid == -1) {
+ ns_error(ns_log_default, "xfer vfork: %s", strerror(errno));
+ zp->z_time = tt.tv_sec + 10;
+ return (pid);
+ }
+ 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));
+ (void)nxfers(zp, -1);
+ _exit(XFER_FAIL); /* Avoid duplicate buffer flushes. */
+ }
+ return (pid);
+}
+#endif
+
+struct zoneinfo *
+find_auth_zone(const char *zname, ns_class zclass) {
+ struct zoneinfo *zp;
+ struct hashbuf *htp;
+ struct namebuf *np;
+ const char *fname;
+ int zn;
+
+ zp = find_zone(zname, zclass);
+ if (zp != NULL &&
+ (zp->z_type == z_slave ||
+ zp->z_type == z_master ||
+ zp->z_type == z_stub))
+ return (zp);
+
+ htp = hashtab;
+ np = nlookup(zname, &htp, &fname, 0);
+ if (np != NULL && (zn = findMyZone(np, zclass)) != DB_Z_CACHE)
+ return (&zones[zn]);
+
+ return (NULL);
+}
diff --git a/contrib/bind/bin/named/ns_ncache.c b/contrib/bind/bin/named/ns_ncache.c
index 413ccc6..437072c 100644
--- a/contrib/bind/bin/named/ns_ncache.c
+++ b/contrib/bind/bin/named/ns_ncache.c
@@ -1,9 +1,9 @@
#if !defined(lint) && !defined(SABER)
-static char rcsid[] = "$Id: ns_ncache.c,v 8.17 1998/03/20 01:12:01 halley Exp $";
+static const char rcsid[] = "$Id: ns_ncache.c,v 8.26 1999/10/13 16:39:10 vixie Exp $";
#endif /* not lint */
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-1999 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
@@ -25,6 +25,7 @@ static char rcsid[] = "$Id: ns_ncache.c,v 8.17 1998/03/20 01:12:01 halley Exp $"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/file.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -51,44 +52,77 @@ static char rcsid[] = "$Id: ns_ncache.c,v 8.17 1998/03/20 01:12:01 halley Exp $"
} while (0)
void
-cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from) {
+cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from,
+ const char *qname, int qclass, int qtype)
+{
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;
+ int n, type, class, flags;
+ u_int ancount, nscount, dlen;
+#ifdef RETURNSOA
+ u_int32_t ttl;
+ u_int16_t atype;
+ u_char *sp, *cp1;
+ u_char data[MAXDATA];
+ size_t len = sizeof data;
+#endif
nameserIncr(from.sin_addr, nssRcvdNXD);
hp = (HEADER *)msg;
- cp = msg+HFIXEDSZ;
+ 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");
+
+ switch (ntohs(hp->qdcount)) {
+ case 0:
+ dname[sizeof dname - 1] = '\0';
+ strncpy(dname, qname, sizeof dname);
+ if (dname[sizeof dname - 1] != '\0') {
+ ns_debug(ns_log_ncache, 1,
+ "qp->qname too long (%d)", strlen(qname));
+ hp->rcode = FORMERR;
+ return;
+ }
+ class = qclass;
+ type = qtype;
+ break;
+ case 1:
+ 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);
+ if (class > CLASS_MAX) {
+ ns_debug(ns_log_ncache, 1,
+ "bad class in cache_n_resp");
+ hp->rcode = FORMERR;
+ return;
+ }
+ break;
+ default:
+ ns_debug(ns_log_ncache, 1,
+ "QDCOUNT>1 (%d) in cache_n_resp", ntohs(hp->qdcount));
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);
+ nscount = ntohs(hp->nscount);
while (ancount--) {
u_int32_t ttl;
- u_int16_t atype;
- u_int16_t aclass;
+ u_int atype, aclass;
+
n = dn_skipname(cp, eom);
if (n < 0) {
ns_debug(ns_log_ncache, 3, "ncache: form error");
@@ -99,7 +133,9 @@ cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from) {
GETSHORT(atype, cp);
GETSHORT(aclass, cp);
if (atype != T_CNAME || aclass != class) {
- ns_debug(ns_log_ncache, 3, "ncache: form error");
+ ns_debug(ns_log_ncache, 3,
+ "ncache: not CNAME (%s) or wrong class (%s)",
+ p_type(atype), p_class(aclass));
return;
}
GETLONG(ttl, cp);
@@ -108,84 +144,81 @@ cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from) {
rdatap = cp;
n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname);
if (n < 0) {
- ns_debug(ns_log_ncache, 3, "ncache: form error");
+ ns_debug(ns_log_ncache, 3, "ncache: bad cname target");
return;
}
cp += n;
if (cp != rdatap + dlen) {
- ns_debug(ns_log_ncache, 3, "ncache: form error");
+ ns_debug(ns_log_ncache, 3, "ncache: bad cname rdata");
return;
}
}
+ dp = NULL;
#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;
+ while (nscount--) {
+ sp = cp;
/* 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);
+ n = dn_skipname(cp, msg + msglen);
if (n < 0) {
ns_debug(ns_log_ncache, 3, "ncache: form error");
return;
}
- tp += n;
+ cp += n;
- BOUNDS_CHECK(tp, 3 * INT16SZ + INT32SZ);
- GETSHORT(atype, tp); /* type */
+ BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
+ GETSHORT(atype, cp); /* type */
+ cp += INT16SZ; /* class */
+ GETLONG(ttl, cp); /* ttl */
+ GETSHORT(dlen, cp); /* dlen */
+ BOUNDS_CHECK(cp, dlen);
if (atype != T_SOA) {
ns_debug(ns_log_ncache, 3,
"ncache: type (%d) != T_SOA", atype);
- goto no_soa;
+ cp += dlen;
+ continue;
}
- tp += INT16SZ; /* class */
- GETLONG(ttl, tp); /* ttl */
- GETSHORT(dlen, tp); /* dlen */
- BOUNDS_CHECK(tp, dlen);
- rdatap = tp;
+ rdatap = cp;
/* origin */
- n = dn_expand(msg, msg + msglen, tp, (char*)data, len);
+ n = dn_expand(msg, msg + msglen, cp, (char*)data, len);
if (n < 0) {
ns_debug(ns_log_ncache, 3,
"ncache: origin form error");
return;
}
- tp += n;
+ cp += n;
n = strlen((char*)data) + 1;
cp1 = data + n;
len -= n;
/* mail */
- n = dn_expand(msg, msg + msglen, tp, (char*)cp1, len);
+ n = dn_expand(msg, msg + msglen, cp, (char*)cp1, len);
if (n < 0) {
ns_debug(ns_log_ncache, 3, "ncache: mail form error");
return;
}
- tp += n;
+ cp += n;
n = strlen((char*)cp1) + 1;
cp1 += n;
len -= n;
n = 5 * INT32SZ;
- BOUNDS_CHECK(tp, n);
- memcpy(cp1, tp, n);
+ BOUNDS_CHECK(cp, n);
+ memcpy(cp1, cp, n);
/* serial, refresh, retry, expire, min */
cp1 += n;
len -= n;
- tp += n;
- if (tp != rdatap + dlen) {
+ cp += n;
+ if (cp != 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);
+ n = dn_expand(msg, msg + msglen, sp, (char*)cp1, len);
if (n < 0) {
ns_debug(ns_log_ncache, 3, "ncache: form error 2");
return;
@@ -193,17 +226,28 @@ cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from) {
n = strlen((char*)cp1) + 1;
cp1 += n;
- dp = savedata(class, type, MIN(ttl, NTTL) + tt.tv_sec, data,
+ /*
+ * we only want to store these long enough so that
+ * ns_resp can find it.
+ */
+ if (qtype == T_SOA && hp->rcode == NXDOMAIN)
+ ttl = 0;
+ dp = savedata(class, type,
+ MIN(ttl, server_options->max_ncache_ttl) +
+ tt.tv_sec, data,
cp1 - data);
- } else {
- no_soa:
-#endif
- dp = savedata(class, type, NTTL + tt.tv_sec, NULL, 0);
-#ifdef RETURNSOA
+ break;
}
#endif
+ if (dp == NULL)
+#ifdef STRICT_RFC2308
+ dp = savedata(class, type, tt.tv_sec, NULL, 0);
+#else
+ dp = savedata(class, type, NTTL + tt.tv_sec, NULL, 0);
+#endif
dp->d_zone = DB_Z_CACHE;
dp->d_cred = hp->aa ? DB_C_AUTH : DB_C_ANSWER;
+ dp->d_secure = DB_S_INSECURE; /* BEW - should be UNCHECKED */
dp->d_clev = 0;
if(hp->rcode == NXDOMAIN) {
dp->d_rcode = NXDOMAIN;
diff --git a/contrib/bind/bin/named/ns_notify.c b/contrib/bind/bin/named/ns_notify.c
new file mode 100644
index 0000000..ac03732e
--- /dev/null
+++ b/contrib/bind/bin/named/ns_notify.c
@@ -0,0 +1,379 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ns_notify.c,v 8.4 1999/10/15 19:49:04 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1994-1999 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.
+ */
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/un.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 <isc/dst.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+#ifdef BIND_NOTIFY
+
+/* Types. */
+
+struct notify {
+ char * name;
+ ns_class class;
+ ns_type type;
+ evTimerID timer;
+ LINK(struct notify) link;
+};
+
+/* Forward. */
+
+static void sysnotify(const char *, ns_class, ns_type);
+static void sysnotify_slaves(const char *, const char *,
+ ns_class, ns_type, int, int *, int *);
+static void sysnotify_ns(const char *, const char *,
+ ns_class, ns_type, int, int *, int *);
+static void free_notify(struct notify *);
+static void notify_timer(evContext, void *,
+ struct timespec, struct timespec);
+
+/* Local. */
+
+static LIST(struct notify) pending_notifies;
+
+/* Public. */
+
+/*
+ * ns_notify(dname, class, type)
+ * call this when a zone has changed and its slaves need to know.
+ */
+void
+ns_notify(const char *dname, ns_class class, ns_type type) {
+ static const char no_room[] = "%s failed, cannot notify for zone %s";
+ int delay, max_delay;
+ struct zoneinfo *zp;
+ struct notify *ni;
+
+ zp = find_auth_zone(dname, class);
+ if (zp == NULL) {
+ ns_warning(ns_log_notify,
+ "no zone found for notify (\"%s\" %s %s)",
+ (dname && *dname) ? dname : ".",
+ p_class(class), p_type(type));
+ return;
+ }
+ if ((zp->z_flags & Z_NOTIFY) != 0) {
+ ns_info(ns_log_notify,
+ "suppressing duplicate notify (\"%s\" %s %s)",
+ (dname && *dname) ? dname : ".",
+ p_class(class), p_type(type));
+ return;
+ }
+ ni = memget(sizeof *ni);
+ if (ni == NULL) {
+ ns_info(ns_log_notify, no_room, "memget", dname);
+ return;
+ }
+ ni->name = savestr(dname, 0);
+ if (ni->name == NULL) {
+ memput(ni, sizeof *ni);
+ ni = NULL;
+ ns_info(ns_log_notify, no_room, "memget", dname);
+ return;
+ }
+ ni->class = class;
+ ni->type = type;
+ evInitID(&ni->timer);
+
+ /* 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);
+ if (evSetTimer(ev, notify_timer, ni,
+ evAddTime(evNowTime(), evConsTime(delay, 0)),
+ evConsTime(0, 0), &ni->timer) < 0) {
+ ns_error(ns_log_notify, "evSetTimer() failed: %s",
+ strerror(errno));
+ freestr(ni->name);
+ memput(ni, sizeof *ni);
+ return;
+ }
+
+ zp->z_flags |= Z_NOTIFY;
+ APPEND(pending_notifies, ni, link);
+ ns_debug(ns_log_notify, 3,
+ "ns_notify(%s, %s, %s): ni %p, zp %p, delay %d",
+ (dname && *dname) ? dname : ".",
+ p_class(class), p_type(type),
+ ni, zp, delay);
+}
+
+/*
+ * ns_unnotify()
+ * call this when all pending notifies are now considered junque.
+ */
+void
+ns_unnotify(void) {
+ while (!EMPTY(pending_notifies)) {
+ struct notify *ni = HEAD(pending_notifies);
+
+ INSIST(LINKED(ni, link));
+ UNLINK(pending_notifies, ni, link);
+ free_notify(ni);
+ }
+}
+
+/* Private. */
+
+/*
+ * sysnotify(dname, class, type)
+ * cause a NOTIFY request to be sysquery()'d to each slave server
+ * of the zone that "dname" is within.
+ */
+static void
+sysnotify(const char *dname, ns_class class, ns_type type) {
+ const char *zname, *fname;
+ int nns, na, i;
+ struct zoneinfo *zp;
+ struct in_addr *also_addr;
+
+ ns_debug(ns_log_notify, 3, "sysnotify(%s, %s, %s)",
+ dname, p_class(class), p_type(type));
+ zp = find_auth_zone(dname, class);
+ if (zp == NULL) {
+ ns_warning(ns_log_notify, "sysnotify: can't find \"%s\" (%s)",
+ dname, p_class(class));
+ return;
+ }
+ if (ns_samename(dname, zp->z_origin) != 1) {
+ ns_warning(ns_log_notify, "sysnotify: not auth for zone %s",
+ dname);
+ return;
+ }
+ 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, type,
+ zp - zones, &nns, &na);
+
+ /*
+ * Handle any global or zone-specific also-notify clauses
+ */
+ if (zp->z_notify_count != 0) {
+ /* zone-specific also notify */
+
+ ns_debug(ns_log_notify, 3, "zone notify ns = %d",
+ zp->z_notify_count);
+
+ also_addr = zp->z_also_notify;
+ for (i = 0; i < zp->z_notify_count; i++) {
+ ns_debug(ns_log_notify, 4, "notifying %s",
+ inet_ntoa(*also_addr));
+ sysquery(dname, class, type, also_addr, 1, ns_port,
+ NS_NOTIFY_OP);
+ also_addr++;
+ }
+ nns += zp->z_notify_count;
+ na += zp->z_notify_count;
+ } else if (server_options->notify_count != 0) {
+ ns_debug(ns_log_notify, 4, "global notify ns = %d",
+ server_options->notify_count);
+ also_addr = server_options->also_notify;
+ for (i = 0; i < server_options->notify_count; i++) {
+ ns_debug(ns_log_notify, 3, "notifying %s",
+ inet_ntoa(*also_addr));
+ sysquery(dname, class, type, also_addr,
+ 1, ns_port, ns_o_notify);
+ also_addr++;
+ }
+ nns += server_options->notify_count;
+ na += server_options->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,
+ ns_class class, ns_type type,
+ 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 == NULL) {
+ ns_warning(ns_log_notify,
+ "sysnotify: found name \"%s\" but not zone",
+ dname);
+ return;
+ }
+ mname = NULL;
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (dp->d_zone == DB_Z_CACHE || !match(dp, class, ns_t_soa))
+ continue;
+ if (dp->d_type == ns_t_sig)
+ 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, ns_t_ns))
+ continue;
+ if (dp->d_type == ns_t_sig)
+ continue;
+ if (ns_samename((char*)dp->d_data, mname) == 1)
+ continue;
+ sysnotify_ns(dname, (char *)dp->d_data, class, type,
+ zn, nns, na);
+ }
+}
+
+static void
+sysnotify_ns(const char *dname, const char *aname,
+ ns_class class, ns_type type,
+ 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;
+ if (adp->d_type == ns_t_sig)
+ 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, ns_t_a, 0, 0, ns_port,
+ ns_o_query);
+ if (qp != NULL)
+ qp->q_notifyzone = zn;
+ }
+ return;
+ }
+ sysquery(dname, class, type, nss, nsc, ns_port, ns_o_notify);
+ (*nns)++;
+ *na += nsc;
+}
+
+static void
+free_notify(struct notify *ni) {
+ struct zoneinfo *zp;
+
+ INSIST(!LINKED(ni, link));
+ zp = find_auth_zone(ni->name, ni->class);
+ if (zp != NULL) {
+ INSIST((zp->z_flags & Z_NOTIFY) != 0);
+ zp->z_flags &= ~Z_NOTIFY;
+ }
+ if (evTestID(ni->timer)) {
+ evClearTimer(ev, ni->timer);
+ evInitID(&ni->timer);
+ }
+ freestr(ni->name);
+ memput(ni, sizeof *ni);
+}
+
+static void
+notify_timer(evContext ctx, void *uap,
+ struct timespec due,
+ struct timespec inter)
+{
+ struct notify *ni = uap;
+
+ INSIST(evTestID(ni->timer));
+ evInitID(&ni->timer);
+ INSIST(LINKED(ni, link));
+ UNLINK(pending_notifies, ni, link);
+ sysnotify(ni->name, ni->class, ni->type);
+ free_notify(ni);
+}
+
+#endif /*BIND_NOTIFY*/
diff --git a/contrib/bind/bin/named/ns_parser.y b/contrib/bind/bin/named/ns_parser.y
index 77dee0b..b381083 100644
--- a/contrib/bind/bin/named/ns_parser.y
+++ b/contrib/bind/bin/named/ns_parser.y
@@ -1,10 +1,10 @@
%{
#if !defined(lint) && !defined(SABER)
-static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $";
+static char rcsid[] = "$Id: ns_parser.y,v 8.51 1999/11/12 05:29:18 vixie Exp $";
#endif /* not lint */
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-1999 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
@@ -25,6 +25,8 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $"
#include "port_before.h"
#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -32,6 +34,7 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $"
#include <ctype.h>
#include <limits.h>
+#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -41,6 +44,8 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $"
#include <isc/eventlib.h>
#include <isc/logging.h>
+#include <isc/dst.h>
+
#include "port_after.h"
#include "named.h"
@@ -61,11 +66,13 @@ static symbol_table symtab;
static symbol_table authtab = NULL;
static zone_config current_zone;
-static int seen_zone;
+static int should_install;
static options current_options;
static int seen_options;
+static controls current_controls;
+
static topology_config current_topology;
static int seen_topology;
@@ -90,7 +97,7 @@ static void define_channel(char *, log_channel);
static char *canonical_name(char *);
int yyparse();
-
+
%}
%union {
@@ -102,7 +109,9 @@ int yyparse();
struct in_addr ip_addr;
ip_match_element ime;
ip_match_list iml;
- key_info keyi;
+ rrset_order_list rol;
+ rrset_order_element roe;
+ struct dst_key * keyi;
enum axfr_format axfr_fmt;
}
@@ -121,22 +130,29 @@ int yyparse();
%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_FAKE_IQUERY T_RECURSION T_FETCH_GLUE
%token T_QUERY_SOURCE T_LISTEN_ON T_PORT T_ADDRESS
+%token T_RRSET_ORDER T_ORDER T_NAME T_CLASS
+%token T_CONTROLS T_INET T_UNIX T_PERM T_OWNER T_GROUP T_ALLOW
%type <us_int> in_port
%type <us_int> maybe_port
+%type <us_int> maybe_zero_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_FILES T_VERSION
%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
+%token T_SERIAL_QUERIES 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
+%token T_NOTIFY T_AUTH_NXDOMAIN T_MULTIPLE_CNAMES T_USE_IXFR T_MAINTAIN_IXFR_BASE
+%token T_CLEAN_INTERVAL T_INTERFACE_INTERVAL T_STATS_INTERVAL T_MAX_LOG_SIZE_IXFR
+%token T_HEARTBEAT T_USE_ID_POOL
+%token T_MAX_NCACHE_TTL T_HAS_OLD_CLIENTS T_RFC2308_TYPE1
+%token T_LAME_TTL T_MIN_ROOTS
+%token T_TREAT_CR_AS_SPACE
/* Items used for the "logging" statement: */
%token T_LOGGING T_CATEGORY T_CHANNEL T_SEVERITY T_DYNAMIC
@@ -147,9 +163,18 @@ int yyparse();
%type <cp> category_name channel_name facility_name
%type <s_int> maybe_syslog_facility
+/* Items used for the "sortlist" statement: */
+%token T_SORTLIST
+
/* Items used for the "topology" statement: */
%token T_TOPOLOGY
+%type <s_int> ordering_class
+%type <s_int> ordering_type
+%type <cp> ordering_name
+%type <rol> rrset_ordering_list
+%type <roe> rrset_ordering_element
+
/* ip_match_list */
%type <ime> address_match_simple address_match_element address_name
%type <iml> address_match_list
@@ -160,6 +185,7 @@ int yyparse();
%token T_BOGUS
%token T_TRANSFERS
%token T_KEYS
+%token T_SUPPORT_IXFR
/* Items used for "zone" statements: */
%token T_ZONE
@@ -170,11 +196,20 @@ int yyparse();
%token T_MASTER T_SLAVE T_STUB T_RESPONSE
%token T_HINT
%token T_MASTERS T_TRANSFER_SOURCE
+%token T_PUBKEY
%token T_ALSO_NOTIFY
+%token T_DIALUP
+%token T_FILE_IXFR
+%token T_IXFR_TMP
+
+/* Items used for "trusted-keys" statements: */
+%token T_TRUSTED_KEYS
/* Items used for access control lists and "allow" clauses: */
%token T_ACL
%token T_ALLOW_UPDATE T_ALLOW_QUERY T_ALLOW_TRANSFER
+%token T_ALLOW_RECURSION
+%token T_BLACKHOLE
/* Items related to the "key" statement: */
%token T_SEC_KEY T_ALGID T_SECRET
@@ -204,7 +239,9 @@ int yyparse();
%%
config_file: statement_list
{
- /* nothing */
+ if (EMPTY(current_controls))
+ ns_ctl_defaults(&current_controls);
+ ns_ctl_install(&current_controls);
}
;
@@ -214,9 +251,11 @@ statement_list: statement
statement: include_stmt
| options_stmt L_EOS
+ | controls_stmt L_EOS
| logging_stmt L_EOS
| server_stmt L_EOS
| zone_stmt L_EOS
+ | trusted_keys_stmt L_EOS
| acl_stmt L_EOS
| key_stmt L_EOS
| L_END_INCLUDE
@@ -253,6 +292,12 @@ options: option L_EOS
;
option: /* Empty */
+ | T_VERSION L_QSTRING
+ {
+ if (current_options->version != NULL)
+ freestr(current_options->version);
+ current_options->version = $2;
+ }
| T_DIRECTORY L_QSTRING
{
if (current_options->directory != NULL)
@@ -291,42 +336,75 @@ option: /* Empty */
}
| T_FAKE_IQUERY yea_or_nay
{
- set_boolean_option(current_options, OPTION_FAKE_IQUERY, $2);
+ set_global_boolean_option(current_options,
+ OPTION_FAKE_IQUERY, $2);
}
| T_RECURSION yea_or_nay
{
- set_boolean_option(current_options, OPTION_NORECURSE, !$2);
+ set_global_boolean_option(current_options,
+ OPTION_NORECURSE, !$2);
}
| T_FETCH_GLUE yea_or_nay
{
- set_boolean_option(current_options, OPTION_NOFETCHGLUE, !$2);
+ set_global_boolean_option(current_options,
+ OPTION_NOFETCHGLUE, !$2);
}
| T_NOTIFY yea_or_nay
{
- set_boolean_option(current_options, OPTION_NONOTIFY, !$2);
+ set_global_boolean_option(current_options,
+ OPTION_NONOTIFY, !$2);
}
| T_HOSTSTATS yea_or_nay
{
- set_boolean_option(current_options, OPTION_HOSTSTATS, $2);
+ set_global_boolean_option(current_options,
+ OPTION_HOSTSTATS, $2);
}
| T_DEALLOC_ON_EXIT yea_or_nay
{
- set_boolean_option(current_options, OPTION_DEALLOC_ON_EXIT,
- $2);
+ set_global_boolean_option(current_options,
+ OPTION_DEALLOC_ON_EXIT, $2);
+ }
+ | T_USE_IXFR yea_or_nay
+ {
+ set_global_boolean_option(current_options, OPTION_USE_IXFR, $2);
+ }
+ | T_MAINTAIN_IXFR_BASE yea_or_nay
+ {
+ set_global_boolean_option(current_options,
+ OPTION_MAINTAIN_IXFR_BASE, $2);
+ }
+ | T_HAS_OLD_CLIENTS yea_or_nay
+ {
+ set_global_boolean_option(current_options,
+ OPTION_MAINTAIN_IXFR_BASE, $2);
+ set_global_boolean_option(current_options,
+ OPTION_NORFC2308_TYPE1, $2);
+ set_global_boolean_option(current_options,
+ OPTION_NONAUTH_NXDOMAIN, !$2);
}
| T_AUTH_NXDOMAIN yea_or_nay
{
- set_boolean_option(current_options, OPTION_NONAUTH_NXDOMAIN,
+ set_global_boolean_option(current_options, OPTION_NONAUTH_NXDOMAIN,
!$2);
}
| T_MULTIPLE_CNAMES yea_or_nay
{
- set_boolean_option(current_options, OPTION_MULTIPLE_CNAMES,
- $2);
+ set_global_boolean_option(current_options,
+ OPTION_MULTIPLE_CNAMES, $2);
}
| T_CHECK_NAMES check_names_type check_names_opt
{
- current_options->check_names[$2] = $3;
+ current_options->check_names[$2] = (enum severity)$3;
+ }
+ | T_USE_ID_POOL yea_or_nay
+ {
+ set_global_boolean_option(current_options,
+ OPTION_USE_ID_POOL, $2);
+ }
+ | T_RFC2308_TYPE1 yea_or_nay
+ {
+ set_global_boolean_option(current_options,
+ OPTION_NORFC2308_TYPE1, !$2);
}
| T_LISTEN_ON maybe_port '{' address_match_list '}'
{
@@ -356,23 +434,73 @@ option: /* Empty */
}
'{' opt_forwarders_list '}'
| T_QUERY_SOURCE query_source
+ | T_TRANSFER_SOURCE maybe_wild_addr
+ {
+ current_options->axfr_src = $2;
+ }
| T_ALLOW_QUERY '{' address_match_list '}'
{
- if (current_options->query_acl)
- free_ip_match_list(current_options->query_acl);
- current_options->query_acl = $3;
+ if (current_options->query_acl) {
+ parser_warning(0,
+ "options allow-query acl already set; skipping");
+ free_ip_match_list($3);
+ } else
+ current_options->query_acl = $3;
+ }
+ | T_ALLOW_RECURSION '{' address_match_list '}'
+ {
+ if (current_options->recursion_acl) {
+ parser_warning(0,
+ "options allow-recursion acl already set; skipping");
+ free_ip_match_list($3);
+ } else
+ current_options->recursion_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;
+ if (current_options->transfer_acl) {
+ parser_warning(0,
+ "options allow-transfer acl already set; skipping");
+ free_ip_match_list($3);
+ } else
+ current_options->transfer_acl = $3;
+ }
+ | T_SORTLIST '{' address_match_list '}'
+ {
+ if (current_options->sortlist) {
+ parser_warning(0,
+ "options sortlist already set; skipping");
+ free_ip_match_list($3);
+ } else
+ current_options->sortlist = $3;
+ }
+ | T_ALSO_NOTIFY
+ {
+ if (current_options->also_notify) {
+ parser_warning(0,
+ "duplicate also-notify clause: overwriting");
+ free_also_notify(current_options);
+ current_options->also_notify = NULL;
+ }
+ }
+ '{' opt_also_notify_list '}'
+ | T_BLACKHOLE '{' address_match_list '}'
+ {
+ if (current_options->blackhole_acl) {
+ parser_warning(0,
+ "options blackhole already set; skipping");
+ free_ip_match_list($3);
+ } else
+ current_options->blackhole_acl = $3;
}
| T_TOPOLOGY '{' address_match_list '}'
{
- if (current_options->topology)
- free_ip_match_list(current_options->topology);
- current_options->topology = $3;
+ if (current_options->topology) {
+ parser_warning(0,
+ "options topology already set; skipping");
+ free_ip_match_list($3);
+ } else
+ current_options->topology = $3;
}
| size_clause
{
@@ -387,6 +515,10 @@ option: /* Empty */
{
current_options->max_transfer_time_in = $2 * 60;
}
+ | T_SERIAL_QUERIES L_NUMBER
+ {
+ current_options->serial_queries = $2;
+ }
| T_CLEAN_INTERVAL L_NUMBER
{
current_options->clean_interval = $2 * 60;
@@ -399,9 +531,168 @@ option: /* Empty */
{
current_options->stats_interval = $2 * 60;
}
+ | T_MAX_LOG_SIZE_IXFR L_NUMBER
+ {
+ current_options->max_log_size_ixfr = $2;
+ }
+ | T_MAX_NCACHE_TTL L_NUMBER
+ {
+ current_options->max_ncache_ttl = $2;
+ }
+ | T_LAME_TTL L_NUMBER
+ {
+ current_options->lame_ttl = $2;
+ }
+ | T_HEARTBEAT L_NUMBER
+ {
+ current_options->heartbeat_interval = $2 * 60;
+ }
+ | T_DIALUP yea_or_nay
+ {
+ set_global_boolean_option(current_options,
+ OPTION_NODIALUP, !$2);
+ }
+ | T_RRSET_ORDER '{' rrset_ordering_list '}'
+ {
+ if (current_options->ordering)
+ free_rrset_order_list(current_options->ordering);
+ current_options->ordering = $3;
+ }
+ | T_TREAT_CR_AS_SPACE yea_or_nay
+ {
+ set_global_boolean_option(current_options,
+ OPTION_TREAT_CR_AS_SPACE, $2);
+ }
+ | T_MIN_ROOTS L_NUMBER
+ {
+ if ($2 >= 1)
+ current_options->minroots = $2;
+ }
+ | error
+ ;
+
+/*
+ * Controls.
+ */
+controls_stmt: T_CONTROLS '{' controls '}'
+ ;
+
+controls: control L_EOS
+ | controls control L_EOS
+ ;
+
+control: /* Empty */
+ | T_INET maybe_wild_addr T_PORT in_port
+ T_ALLOW '{' address_match_list '}'
+ {
+ ns_ctl_add(&current_controls, ns_ctl_new_inet($2, $4, $7));
+ }
+ | T_UNIX L_QSTRING T_PERM L_NUMBER T_OWNER L_NUMBER T_GROUP L_NUMBER
+ {
+ ns_ctl_add(&current_controls, ns_ctl_new_unix($2, $4, $6, $8));
+ }
| error
;
+rrset_ordering_list: rrset_ordering_element L_EOS
+ {
+ rrset_order_list rol;
+
+ rol = new_rrset_order_list();
+ if ($1 != NULL) {
+ add_to_rrset_order_list(rol, $1);
+ }
+
+ $$ = rol;
+ }
+ | rrset_ordering_list rrset_ordering_element L_EOS
+ {
+ if ($2 != NULL) {
+ add_to_rrset_order_list($1, $2);
+ }
+ $$ = $1;
+ }
+ ;
+
+ordering_class: /* nothing */
+ {
+ $$ = C_ANY;
+ }
+ | T_CLASS any_string
+ {
+ symbol_value value;
+
+ if (lookup_symbol(constants, $2, SYM_CLASS, &value))
+ $$ = value.integer;
+ else {
+ parser_error(0, "unknown class '%s'; using ANY", $2);
+ $$ = C_ANY;
+ }
+ freestr($2);
+ }
+ ;
+
+ordering_type: /* nothing */
+ {
+ $$ = ns_t_any;
+ }
+ | T_TYPE any_string
+ {
+ int success;
+
+ if (strcmp($2, "*") == 0) {
+ $$ = ns_t_any;
+ } else {
+ $$ = __sym_ston(__p_type_syms, $2, &success);
+ if (success == 0) {
+ $$ = ns_t_any;
+ parser_error(0,
+ "unknown type '%s'; assuming ANY",
+ $2);
+ }
+ }
+ freestr($2);
+ }
+
+ordering_name: /* nothing */
+ {
+ $$ = savestr("*", 1);
+ }
+ | T_NAME L_QSTRING
+ {
+ if (strcmp(".",$2) == 0 || strcmp("*.",$2) == 0) {
+ $$ = savestr("*", 1);
+ freestr($2);
+ } else {
+ $$ = $2 ;
+ }
+ /* XXX Should do any more name validation here? */
+ }
+
+
+rrset_ordering_element: ordering_class ordering_type ordering_name T_ORDER L_STRING
+ {
+ enum ordering o;
+
+ if (strlen($5) == 0) {
+ parser_error(0, "null order name");
+ $$ = NULL ;
+ } else {
+ o = lookup_ordering($5);
+ if (o == unknown_order) {
+ o = (enum ordering)DEFAULT_ORDERING;
+ parser_error(0,
+ "invalid order name '%s'; using %s",
+ $5, p_order(o));
+ }
+
+ freestr($5);
+
+ $$ = new_rrset_order_element($1, $2, $3, o);
+ }
+ }
+
+
transfer_format: T_ONE_ANSWER
{
$$ = axfr_one_answer;
@@ -442,6 +733,11 @@ maybe_port: /* nothing */ { $$ = htons(NS_DEFAULTPORT); }
| T_PORT in_port { $$ = $2; }
;
+maybe_zero_port: /* nothing */ { $$ = htons(0); }
+ | T_PORT in_port { $$ = $2; }
+ ;
+
+
yea_or_nay: T_YES
{
$$ = 1;
@@ -500,11 +796,13 @@ check_names_opt: T_WARN
forward_opt: T_ONLY
{
- set_boolean_option(current_options, OPTION_FORWARD_ONLY, 1);
+ set_global_boolean_option(current_options,
+ OPTION_FORWARD_ONLY, 1);
}
| T_FIRST
{
- set_boolean_option(current_options, OPTION_FORWARD_ONLY, 0);
+ set_global_boolean_option(current_options,
+ OPTION_FORWARD_ONLY, 0);
}
| T_IF_NO_ANSWER
{
@@ -591,7 +889,27 @@ forwarders_in_addr_list: forwarders_in_addr L_EOS
forwarders_in_addr: L_IPADDR
{
- add_forwarder(current_options, $1);
+ add_global_forwarder(current_options, $1);
+ }
+ ;
+
+opt_also_notify_list: /* nothing */
+ | also_notify_in_addr_list
+ ;
+
+also_notify_in_addr_list: also_notify_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ | also_notify_in_addr_list also_notify_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ ;
+
+also_notify_in_addr: L_IPADDR
+ {
+ add_global_also_notify(current_options, $1);
}
;
@@ -697,12 +1015,10 @@ channel_severity: any_string
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;
}
;
@@ -851,7 +1167,7 @@ category: category_name
server_stmt: T_SERVER L_IPADDR
{
- char *ip_printable;
+ const char *ip_printable;
symbol_value value;
ip_printable = inet_ntoa($2);
@@ -883,6 +1199,10 @@ server_info: T_BOGUS yea_or_nay
{
set_server_option(current_server, SERVER_INFO_BOGUS, $2);
}
+ | T_SUPPORT_IXFR yea_or_nay
+ {
+ set_server_option(current_server, SERVER_INFO_SUPPORT_IXFR, $2);
+ }
| T_TRANSFERS L_NUMBER
{
set_server_transfers(current_server, (int)$2);
@@ -923,6 +1243,25 @@ address_match_element: address_match_simple
ip_match_negate($2);
$$ = $2;
}
+ | T_SEC_KEY L_STRING
+ {
+ char *key_name;
+ struct dst_key *dst_key;
+
+ key_name = canonical_name($2);
+ if (key_name == NULL) {
+ parser_error(0, "can't make key name '%s' canonical",
+ $2);
+ key_name = savestr("__bad_key__", 1);
+ }
+ dst_key = find_key(key_name, NULL);
+ if (dst_key == NULL) {
+ parser_error(0, "key \"%s\" not found", key_name);
+ $$ = NULL;
+ }
+ else
+ $$ = new_ip_match_key(dst_key);
+ }
;
address_match_simple: L_IPADDR
@@ -997,14 +1336,23 @@ address_name: any_string
key_ref: any_string
{
- key_info ki;
+ struct dst_key *dst_key;
+ char *key_name;
- ki = lookup_key($1);
- if (ki == NULL) {
- parser_error(0, "unknown key '%s'", $1);
+ key_name = canonical_name($1);
+ if (key_name == NULL) {
+ parser_error(0, "can't make key name '%s' canonical",
+ $1);
$$ = NULL;
- } else
- $$ = ki;
+ } else {
+ dst_key = lookup_key(key_name);
+ if (dst_key == NULL) {
+ parser_error(0, "unknown key '%s'", key_name);
+ $$ = NULL;
+ } else
+ $$ = dst_key;
+ freestr(key_name);
+ }
freestr($1);
}
;
@@ -1030,21 +1378,37 @@ key_stmt: T_SEC_KEY
}
any_string '{' key_definition '}'
{
- key_info ki;
+ struct dst_key *dst_key;
+ char *key_name;
- if (lookup_key($3) != NULL) {
- parser_error(0, "can't redefine key '%s'", $3);
- freestr($3);
+ key_name = canonical_name($3);
+ if (key_name == NULL) {
+ parser_error(0, "can't make key name '%s' canonical",
+ $3);
+ } else if (lookup_key(key_name) != NULL) {
+ parser_error(0, "can't redefine key '%s'", key_name);
+ freestr(key_name);
} 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);
+ current_secret == NULL) {
+ parser_error(0, "skipping bad key '%s'",
+ key_name);
+ freestr(key_name);
+ } else {
+ dst_key = new_key_info(key_name,
+ current_algorithm,
+ current_secret);
+ if (dst_key != NULL) {
+ define_key(key_name, dst_key);
+ if (secretkey_info == NULL)
+ secretkey_info =
+ new_key_info_list();
+ add_to_key_info_list(secretkey_info,
+ dst_key);
+ }
}
}
+ freestr($3);
}
;
@@ -1104,24 +1468,29 @@ zone_stmt: T_ZONE L_QSTRING optional_class
if (zone_name == NULL) {
parser_error(0, "can't make zone name '%s' canonical",
$2);
- seen_zone = 1;
+ should_install = 0;
zone_name = savestr("__bad_zone__", 1);
} else {
- seen_zone = lookup_symbol(symtab, zone_name, sym_type,
- NULL);
- if (seen_zone) {
+ if (lookup_symbol(symtab, zone_name, sym_type, NULL)) {
+ should_install = 0;
parser_error(0,
- "cannot redefine zone '%s' class %d",
- zone_name, $3);
- } else
- define_symbol(symtab, zone_name, sym_type,
- value, 0);
+ "cannot redefine zone '%s' class %s",
+ *zone_name ? zone_name : ".",
+ p_class($3));
+ } else {
+ should_install = 1;
+ define_symbol(symtab, savestr(zone_name, 1),
+ sym_type, value,
+ SYMBOL_FREE_KEY);
+ }
}
freestr($2);
current_zone = begin_zone(zone_name, $3);
}
optional_zone_options_list
- { end_zone(current_zone, !seen_zone); }
+ {
+ end_zone(current_zone, should_install);
+ }
;
optional_zone_options_list: /* Empty */
@@ -1162,6 +1531,10 @@ zone_type: T_MASTER
{
$$ = Z_STUB;
}
+ | T_FORWARD
+ {
+ $$ = Z_FORWARD;
+ }
;
zone_option_list: zone_option L_EOS
@@ -1179,14 +1552,29 @@ zone_option: T_TYPE zone_type
parser_warning(0,
"zone filename already set; skipping");
}
- | T_MASTERS '{' master_in_addr_list '}'
+ | T_FILE_IXFR L_QSTRING
+ {
+ if (!set_zone_ixfr_file(current_zone, $2))
+ parser_warning(0,
+ "zone ixfr data base already set; skipping");
+ }
+ | T_IXFR_TMP L_QSTRING
+ {
+ if (!set_zone_ixfr_tmp(current_zone, $2))
+ parser_warning(0,
+ "zone ixfr temp filename already set; skipping");
+ }
+ | T_MASTERS maybe_zero_port '{' master_in_addr_list '}'
+ {
+ set_zone_master_port(current_zone, $2);
+ }
| 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))
+ if (!set_zone_checknames(current_zone, (enum severity)$2))
parser_warning(0,
"zone checknames already set; skipping");
}
@@ -1208,17 +1596,56 @@ zone_option: T_TYPE zone_type
parser_warning(0,
"zone transfer acl already set; skipping");
}
+ | T_FORWARD zone_forward_opt
+ | T_FORWARDERS
+ {
+ struct zoneinfo *zp = current_zone.opaque;
+ if (zp->z_fwdtab) {
+ free_forwarders(zp->z_fwdtab);
+ zp->z_fwdtab = NULL;
+ }
+
+ }
+ '{' opt_zone_forwarders_list '}'
| 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_MAX_LOG_SIZE_IXFR L_NUMBER
+ {
+ set_zone_max_log_size_ixfr(current_zone, $2);
+ }
| T_NOTIFY yea_or_nay
{
set_zone_notify(current_zone, $2);
}
+ | T_MAINTAIN_IXFR_BASE yea_or_nay
+ {
+ set_zone_maintain_ixfr_base(current_zone, $2);
+ }
+ | T_PUBKEY L_NUMBER L_NUMBER L_NUMBER L_QSTRING
+ {
+ /* flags proto alg key */
+ set_zone_pubkey(current_zone, $2, $3, $4, $5);
+ }
+ | T_PUBKEY L_STRING L_NUMBER L_NUMBER L_QSTRING
+ {
+ /* flags proto alg key */
+ char *endp;
+ int flags = (int) strtol($2, &endp, 0);
+ if (*endp != '\0')
+ ns_panic(ns_log_parser, 1,
+ "Invalid flags string: %s", $2);
+ set_zone_pubkey(current_zone, flags, $3, $4, $5);
+
+ }
| T_ALSO_NOTIFY '{' opt_notify_in_addr_list '}'
+ | T_DIALUP yea_or_nay
+ {
+ set_zone_dialup(current_zone, $2);
+ }
| error
;
@@ -1258,6 +1685,73 @@ notify_in_addr: L_IPADDR
}
;
+zone_forward_opt: T_ONLY
+ {
+ set_zone_boolean_option(current_zone, OPTION_FORWARD_ONLY, 1);
+ }
+ | T_FIRST
+ {
+ set_zone_boolean_option(current_zone, OPTION_FORWARD_ONLY, 0);
+ }
+ ;
+
+opt_zone_forwarders_list: /* nothing */
+ {
+ set_zone_forward(current_zone);
+ }
+ | zone_forwarders_in_addr_list
+ ;
+
+zone_forwarders_in_addr_list: zone_forwarders_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ | zone_forwarders_in_addr_list zone_forwarders_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ ;
+
+zone_forwarders_in_addr: L_IPADDR
+ {
+ add_zone_forwarder(current_zone, $1);
+ }
+ ;
+
+/*
+ * Trusted Key statement
+ */
+
+trusted_keys_stmt: T_TRUSTED_KEYS '{' trusted_keys_list '}'
+ {
+ }
+ ;
+trusted_keys_list: trusted_key L_EOS
+ {
+ /* nothing */
+ }
+ | trusted_keys_list trusted_key L_EOS
+ {
+ /* nothing */
+ }
+ ;
+trusted_key: L_STRING L_NUMBER L_NUMBER L_NUMBER L_QSTRING
+ {
+ /* name flags proto alg key */
+ set_trusted_key($1, $2, $3, $4, $5);
+ }
+ | L_STRING L_STRING L_NUMBER L_NUMBER L_QSTRING
+ {
+ /* name flags proto alg key */
+ char *endp;
+ int flags = (int) strtol($2, &endp, 0);
+ if (*endp != '\0')
+ ns_panic(ns_log_parser, 1,
+ "Invalid flags string: %s", $2);
+ set_trusted_key($1, flags, $3, $4, $5);
+ }
+ ;
+
/*
* Misc.
*/
@@ -1383,6 +1877,7 @@ parser_setup() {
authtab = new_symbol_table(AUTH_TABLE_SIZE, free_sym_value);
init_acls();
define_builtin_channels();
+ INIT_LIST(current_controls);
}
static void
@@ -1423,25 +1918,25 @@ define_acl(char *name, ip_match_list iml) {
dprint_ip_match_list(ns_log_parser, iml, 2, "allow ", "deny ");
}
-key_info
+struct dst_key *
lookup_key(char *name) {
symbol_value value;
if (lookup_symbol(authtab, name, SYM_KEY, &value))
- return ((key_info)(value.pointer));
+ return ((struct dst_key *)(value.pointer));
return (NULL);
}
void
-define_key(char *name, key_info ki) {
+define_key(char *name, struct dst_key *dst_key) {
symbol_value value;
INSIST(name != NULL);
- INSIST(ki != NULL);
+ INSIST(dst_key != NULL);
- value.pointer = ki;
+ value.pointer = dst_key;
define_symbol(authtab, name, SYM_KEY, value, SYMBOL_FREE_VALUE);
- dprint_key_info(ki);
+ dprint_key_info(dst_key);
}
void
diff --git a/contrib/bind/bin/named/ns_parseutil.c b/contrib/bind/bin/named/ns_parseutil.c
index aed15af..60b189a 100644
--- a/contrib/bind/bin/named/ns_parseutil.c
+++ b/contrib/bind/bin/named/ns_parseutil.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-1999 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
@@ -21,6 +21,8 @@
#include "port_before.h"
#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -178,7 +180,7 @@ define_symbol(symbol_table st, char *key, int type, symbol_value value,
void
undefine_symbol(symbol_table st, char *key, int type) {
int hash;
- symbol_entry prev_ste, ste, next_ste;
+ symbol_entry prev_ste, ste;
hash = symbol_hash(key, st->size);
for (prev_ste = NULL, ste = st->table[hash];
diff --git a/contrib/bind/bin/named/ns_parseutil.h b/contrib/bind/bin/named/ns_parseutil.h
index d241bea..78356f8 100644
--- a/contrib/bind/bin/named/ns_parseutil.h
+++ b/contrib/bind/bin/named/ns_parseutil.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-1999 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
@@ -15,8 +15,8 @@
* SOFTWARE.
*/
-#ifndef NS_PARSEUTIL_H
-#define NS_PARSEUTIL_H
+#ifndef _NS_PARSEUTIL_H
+#define _NS_PARSEUTIL_H
/*
* Symbol Table
@@ -62,4 +62,4 @@ void undefine_symbol(symbol_table, char *, int type);
int unit_to_ulong(char *, u_long *);
-#endif /* !NS_PARSEUTIL_H */
+#endif /* !_NS_PARSEUTIL_H */
diff --git a/contrib/bind/bin/named/ns_req.c b/contrib/bind/bin/named/ns_req.c
index ee60ce4..d7ee0b5 100644
--- a/contrib/bind/bin/named/ns_req.c
+++ b/contrib/bind/bin/named/ns_req.c
@@ -1,6 +1,6 @@
#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 $";
+static const char sccsid[] = "@(#)ns_req.c 4.47 (Berkeley) 7/1/91";
+static const char rcsid[] = "$Id: ns_req.c,v 8.104 1999/10/15 19:49:04 vixie Exp $";
#endif /* not lint */
/*
@@ -82,7 +82,7 @@ static char rcsid[] = "$Id: ns_req.c,v 8.46 1998/03/27 00:21:03 halley Exp $";
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -105,6 +105,7 @@ static char rcsid[] = "$Id: ns_req.c,v 8.46 1998/03/27 00:21:03 halley Exp $";
#include <sys/uio.h>
#include <sys/file.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -123,6 +124,8 @@ static char rcsid[] = "$Id: ns_req.c,v 8.46 1998/03/27 00:21:03 halley Exp $";
#include <isc/logging.h>
#include <isc/memcluster.h>
+#include <isc/dst.h>
+
#include "port_after.h"
#include "named.h"
@@ -131,7 +134,8 @@ 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 */
+ u_int16_t a_type; /* type for data */
+ u_int16_t a_class; /* class for data */
};
#ifndef BIND_UPDATE
@@ -140,14 +144,15 @@ enum req_action { Finish, Refuse, Return };
static struct addinfo addinfo[NADDRECS];
static void addname(const char *, const char *,
- u_int16_t, u_int16_t);
+ u_int16_t, 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);
+ u_char *msg, int dfd, int *ra,
+ struct sockaddr_in from,
+ struct tsig_record *in_tsig);
static enum req_action req_iquery(HEADER *hp, u_char **cpp, u_char *eom,
int *buflenp, u_char *msg,
@@ -168,14 +173,89 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
HEADER *hp = (HEADER *) msg;
u_char *cp, *eom;
enum req_action action;
- int n;
+ int n, ra, has_tsig, msglen_orig, tsig_size, siglen, sig2len;
+ u_char *tsigstart;
+ u_char sig[TSIG_SIG_SIZE], sig2[TSIG_SIG_SIZE];
+ struct tsig_record *in_tsig = NULL;
+ int error = NOERROR;
+ DST_KEY *key;
+ time_t tsig_time;
#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));
+ res_pquery(&res, msg, msglen, log_get_stream(packet_channel));
}
#endif
+ msglen_orig = msglen;
+ siglen = sizeof(sig);
+
+ tsigstart = ns_find_tsig(msg, msg + msglen);
+ if (tsigstart == NULL)
+ has_tsig = 0;
+ else {
+ char buf[MAXDNAME];
+
+ has_tsig = 1;
+ ns_name_ntop(tsigstart, buf, sizeof(buf));
+ key = find_key(buf, NULL);
+ if (key == NULL) {
+ error = ns_r_badkey;
+ ns_debug(ns_log_default, 1,
+ "ns_req: TSIG verify failed - unknown key %s",
+ buf);
+ }
+ }
+ if (has_tsig && key != NULL) {
+ n = ns_verify(msg, &msglen, key, NULL, 0, sig, &siglen,
+ &tsig_time, 0);
+ if (n != 0) {
+ hp->rcode = ns_r_notauth;
+ /* A query should never have an error code set */
+ if (n == ns_r_badsig || n == ns_r_badkey ||
+ n == ns_r_badtime) {
+ ns_debug(ns_log_default, 1,
+ "ns_req: TSIG verify failed - query had error %s (%d) set",
+ p_rcode(n), n);
+ error = n;
+ action = Return;
+ }
+ /* If there's a processing error just respond */
+ else if (n == -ns_r_badsig || n == -ns_r_badkey ||
+ n == -ns_r_badtime) {
+ n = -n;
+ ns_debug(ns_log_default, 1,
+ "ns_req: TSIG verify failed - %s (%d)",
+ p_rcode(n), n);
+ error = n;
+ } else {
+ ns_debug(ns_log_default, 1,
+ "ns_req: TSIG verify failed - FORMERR");
+ error = ns_r_formerr;
+ }
+ action = Finish;
+ }
+ in_tsig = memget(sizeof(struct tsig_record));
+ if (in_tsig == NULL)
+ ns_panic(ns_log_default, 1, "memget failed");
+ in_tsig->key = key;
+ in_tsig->siglen = siglen;
+ memcpy(in_tsig->sig, sig, siglen);
+ tsig_size = msglen_orig - msglen;
+ } else if (has_tsig) {
+ action = Finish;
+ in_tsig = memget(sizeof(struct tsig_record));
+ if (in_tsig == NULL)
+ ns_panic(ns_log_default, 1, "memget failed");
+ in_tsig->key = NULL;
+ in_tsig->siglen = 0;
+ tsig_size = msg + msglen - tsigstart;
+ msglen = tsigstart - msg;
+ }
+
+ /* Hash some stuff so it's nice and random */
+ nsid_hash((u_char *)&tt, sizeof(tt));
+ nsid_hash(msg, (msglen > 512) ? 512 : msglen);
/*
* It's not a response so these bits have no business
@@ -184,8 +264,10 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
* comes in.
*/
hp->aa = hp->ra = 0;
+ ra = (NS_OPTION_P(OPTION_NORECURSE) == 0);
- hp->rcode = NOERROR;
+ if (error == NOERROR)
+ hp->rcode = ns_r_noerror;
cp = msg + HFIXEDSZ;
eom = msg + msglen;
buflen -= HFIXEDSZ;
@@ -193,49 +275,58 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
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;
+ if (error == NOERROR) {
+ switch (hp->opcode) {
+ case ns_o_query:
+ action = req_query(hp, &cp, eom, qsp,
+ &buflen, &msglen,
+ msg, dfd, &ra, from, in_tsig);
+ break;
- case ns_o_iquery:
- action = req_iquery(hp, &cp, eom, &buflen, msg, 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;
+ 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;
+ case ns_o_update:
+ action = req_update(hp, cp, eom, msg, qsp, dfd, from,
+ in_tsig);
+ 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;
+ 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 = ns_r_notimpl;
+ action = Finish;
+ }
+ }
+
+ if (in_tsig != NULL) {
+ memput(in_tsig, sizeof(struct tsig_record));
+ in_tsig = NULL;
}
/*
- * vector via internal opcode. (yes, it was even uglier before.)
+ * Vector via internal opcode.
*/
switch (action) {
case Return:
return;
case Refuse:
- hp->rcode = REFUSED;
+ hp->rcode = ns_r_refused;
cp = eom;
/*FALLTHROUGH*/
case Finish:
@@ -247,22 +338,73 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
}
/*
- * apply final polish
+ * Apply final polish.
*/
hp->qr = 1; /* set Response flag */
- hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0);
+ hp->ra = ra; /* init above, may be modified by req_query */
- n = doaddinfo(hp, cp, buflen);
- cp += n;
- buflen -= n;
+ if (!hp->tc && has_tsig > 0 && buflen < tsig_size)
+ hp->tc = 1;
+
+ /*
+ * If there was a format error, then we don't know what the msg has.
+ */
+ if (hp->rcode == ns_r_formerr) {
+ hp->qdcount = htons(0);
+ hp->ancount = htons(0);
+ hp->nscount = htons(0);
+ hp->arcount = htons(0);
+ }
+
+ /*
+ * If the query had a TSIG and the message is truncated or there was
+ * a TSIG error, build a new message with no data and a TSIG.
+ */
+ if ((hp->tc || error != NOERROR) && has_tsig > 0) {
+ hp->ancount = htons(0);
+ hp->nscount = htons(0);
+ hp->arcount = htons(0);
+ cp = msg + HFIXEDSZ;
+ cp += ns_skiprr(cp, msg + msglen, ns_s_qd, ntohs(hp->qdcount));
+ sig2len = sizeof(sig2);
+ buflen += (msglen - (cp - msg));
+ msglen = cp - msg;
+ n = ns_sign(msg, &msglen, msglen + buflen, error, key,
+ sig, siglen, sig2, &sig2len, tsig_time);
+ if (n != 0) {
+ INSIST(0);
+ }
+ cp = msg + msglen;
+
+ }
+ /* Either the message is not truncated or there was no TSIG */
+ else {
+ if (has_tsig > 0)
+ buflen -= tsig_size;
+ n = doaddinfo(hp, cp, buflen);
+ cp += n;
+ buflen -= n;
+ if (has_tsig > 0) {
+ buflen += tsig_size;
+ sig2len = sizeof(sig2);
+ msglen = cp - msg;
+ n = ns_sign(msg, &msglen, msglen + buflen, error, key,
+ sig, siglen, sig2, &sig2len, tsig_time);
+ if (n != 0) {
+ INSIST(0);
+ }
+ cp = msg + msglen;
+ }
+ }
#ifdef DEBUG
ns_debug(ns_log_default, 1,
- "ns_req: answer -> %s fd=%d id=%d size=%d",
+ "ns_req: answer -> %s fd=%d id=%d size=%d rc=%d",
sin_ntoa(from), (qsp == NULL) ? dfd : qsp->s_rfd,
- ntohs(hp->id), cp - msg);
+ ntohs(hp->id), cp - msg, hp->rcode);
if (debug >= 10)
- fp_nquery(msg, cp - msg, log_get_stream(packet_channel));
+ res_pquery(&res, msg, cp - msg,
+ log_get_stream(packet_channel));
#endif /*DEBUG*/
if (qsp == NULL) {
if (sendto(dfd, (char*)msg, cp - msg, 0,
@@ -276,7 +418,7 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
nameserIncr(from.sin_addr, nssSendtoErr);
}
nameserIncr(from.sin_addr, nssSentAns);
- if (hp->rcode == NXDOMAIN)
+ if (hp->rcode == ns_r_nxdomain)
nameserIncr(from.sin_addr, nssSentNXD);
if (!hp->aa)
nameserIncr(from.sin_addr, nssSentNaAns);
@@ -307,22 +449,13 @@ req_notify(HEADER *hp, u_char **cpp, u_char *eom, u_char *msg,
{
int n, type, class, zn;
char dnbuf[MAXDNAME];
- struct namebuf *np;
- const char *fname;
- struct hashbuf *htp = hashtab; /* lookup relative to root */
+ struct zoneinfo *zp;
- /* 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) {
+ /* valid notify's have one question */
+ if (ntohs(hp->qdcount) != 1) {
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;
+ hp->rcode = ns_r_formerr;
return (Finish);
}
@@ -330,14 +463,14 @@ req_notify(HEADER *hp, u_char **cpp, u_char *eom, u_char *msg,
if (n < 0) {
ns_debug(ns_log_notify, 1,
"FORMERR Query expand name failed");
- hp->rcode = FORMERR;
+ hp->rcode = ns_r_formerr;
return (Finish);
}
*cpp += n;
if (*cpp + 2 * INT16SZ > eom) {
ns_debug(ns_log_notify, 1,
"FORMERR notify too short");
- hp->rcode = FORMERR;
+ hp->rcode = ns_r_formerr;
return (Finish);
}
GETSHORT(type, *cpp);
@@ -347,76 +480,95 @@ req_notify(HEADER *hp, u_char **cpp, u_char *eom, u_char *msg,
/* 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) {
+ /* Find the zone this NOTIFY refers to. */
+ zp = find_auth_zone(dnbuf, class);
+ if (zp == NULL) {
ns_info(ns_log_notify,
- "rcvd NOTIFY for \"%s\", name not in cache",
+ "rcvd NOTIFY for \"%s\", name not one of our zones",
dnbuf);
- hp->rcode = SERVFAIL;
+ hp->rcode = ns_r_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;
- }
+ /* Access control. */
switch (type) {
case T_SOA:
- if (strcasecmp(dnbuf, zones[zn].z_origin) != 0) {
+ if (zp->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(SOA) for non-secondary name (%s), from %s",
+ dnbuf, sin_ntoa(from));
+ goto refuse;
+ }
+ if (ns_samename(dnbuf, zp->z_origin) != 1) {
ns_info(ns_log_notify,
"NOTIFY(SOA) for non-origin (%s), from %s",
dnbuf, sin_ntoa(from));
goto refuse;
}
- if (zones[zn].z_flags &
+ if (findZonePri(zp, from) == -1) {
+ ns_info(ns_log_notify,
+ "NOTIFY(SOA) from non-master server (zone %s), from %s",
+ zp->z_origin, sin_ntoa(from));
+ goto refuse;
+ }
+ break;
+ default:
+ /* No access requirements defined for other types. */
+ break;
+ }
+ /* The work occurs here. */
+ switch (type) {
+ case T_SOA:
+ if (zp->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]);
+ zp->z_time = tt.tv_sec;
+ qserial_query(zp);
+ sched_zone_maint(zp);
break;
default:
- /* unimplemented, but it's not a protocol error, just
+ /*
+ * Unimplemented, but it's not a protocol error, just
* something to be ignored.
*/
- break;
+ hp->rcode = ns_r_notimpl;
+ return (Finish);
}
noerror:
- hp->rcode = NOERROR;
+ hp->rcode = ns_r_noerror;
return (Finish);
refuse:
- hp->rcode = REFUSED;
+ hp->rcode = ns_r_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 *buflenp, int *msglenp, u_char *msg, int dfd, int *ra,
+ struct sockaddr_in from, struct tsig_record *in_tsig)
{
int n, class, type, count, zone, foundname, founddata, omsglen, cname;
+ int recursion_blocked_by_acl;
u_int16_t id;
- u_char **dpp, *omsg, *answers;
+ u_int32_t serial_ixfr;
+ int ixfr_found;
+ int ixfr_error = 0;
+ char dnbuf2[MAXDNAME];
+ u_char **dpp, *omsg, *answers, *afterq;
char dnbuf[MAXDNAME], *dname;
const char *fname;
struct hashbuf *htp;
@@ -425,6 +577,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
struct qinfo *qp;
struct zoneinfo *zp;
struct databuf *dp;
+ DST_KEY *in_key = (in_tsig != NULL) ? in_tsig->key : NULL;
nameserIncr(from.sin_addr, nssRcvdQ);
@@ -438,19 +591,15 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
omsglen = 0;
omsg = NULL;
id = 0;
+ recursion_blocked_by_acl = 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;
+ hp->rcode = ns_r_formerr;
return (Finish);
}
@@ -464,35 +613,101 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
if (n < 0) {
ns_debug(ns_log_default, 1,
"FORMERR Query expand name failed");
- hp->rcode = FORMERR;
+ hp->rcode = ns_r_formerr;
return (Finish);
}
*cpp += n;
+ answers = *cpp;
if (*cpp + 2 * INT16SZ > eom) {
ns_debug(ns_log_default, 1,
"FORMERR Query message length short");
- hp->rcode = FORMERR;
+ hp->rcode = ns_r_formerr;
return (Finish);
}
GETSHORT(type, *cpp);
GETSHORT(class, *cpp);
- if (*cpp < eom) {
+ if (*cpp < eom && type != ns_t_ixfr) {
ns_debug(ns_log_default, 6,
"message length > received message");
*msglenp = *cpp - msg;
}
+ if (((ntohs(hp->nscount) != 0) && (type != ns_t_ixfr)) ||
+ ((ntohs(hp->nscount) != 1) && (type == ns_t_ixfr)))
+ {
+ ns_debug(ns_log_default, 1, "FORMERR Query nscount wrong");
+ hp->rcode = ns_r_formerr;
+ return (Finish);
+ }
+
+ afterq = *cpp;
qtypeIncr(type);
/*
* Process query.
*/
- if (type == T_AXFR) {
+ if (type == ns_t_ixfr) {
+ hp->nscount = htons(0);
+ hp->rd = 0; /* Force IXFR queries to be non recursive. */
+ n = dn_expand(msg, eom, *cpp, dnbuf2, sizeof dnbuf2);
+ if (n < 0) {
+ ns_debug(ns_log_default, 1,
+ "FORMERR Query expand name failed");
+ hp->rcode = ns_r_formerr;
+ return (Finish);
+ }
+ *cpp += n;
+ if (*cpp + 3 * INT16SZ + INT32SZ > eom) {
+ ns_debug(ns_log_default, 1,
+ "ran out of data in IXFR query");
+ hp->rcode = ns_r_formerr;
+ return (Finish);
+ }
+ GETSHORT(n, *cpp);
+ if (n != ns_t_soa || ns_samename(dnbuf, dnbuf2) != 1) {
+ ns_debug(ns_log_default, 1,
+ "FORMERR SOA record expected");
+ hp->rcode = ns_r_formerr;
+ return (Finish);
+ }
+ *cpp += INT32SZ + INT16SZ * 2; /* skip class, ttl, dlen */
+ if (0 >= (n = dn_skipname(*cpp, eom))) {
+ ns_debug(ns_log_default, 1,
+ "FORMERR Query expand name failed");
+ hp->rcode = ns_r_formerr;
+ return (Finish);
+ }
+ *cpp += n; /* mname */
+ if (0 >= (n = dn_skipname(*cpp, eom))) {
+ ns_debug(ns_log_default, 1,
+ "FORMERR Query expand name failed");
+ hp->rcode = ns_r_formerr;
+ return (Finish);
+ }
+ *cpp += n; /* rname */
+ if (*cpp + 5 * INT32SZ > eom) {
+ ns_debug(ns_log_default, 1,
+ "ran out of data in IXFR query");
+ hp->rcode = ns_r_formerr;
+ return (Finish);
+ }
+ GETLONG(serial_ixfr, *cpp);
+ /* ignore other soa counters */
+ if ((*cpp + (4 * INT32SZ)) < eom)
+ ns_debug(ns_log_default, 6,
+ "ixfr: message length > received message");
+ /* Reset msglenp to cover just the question. */
+ *msglenp = afterq - msg;
+ }
+ *cpp = afterq;
+
+ if (!ns_t_udp_p(type)) {
/* 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 : ".");
+ "rejected UDP %s from %s for \"%s\"",
+ p_type(type), sin_ntoa(from),
+ *dnbuf ? dnbuf : ".");
return (Refuse);
}
/* The position of this is subtle. */
@@ -507,10 +722,11 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
#ifdef QRYLOG
if (qrylog) {
- ns_info(ns_log_queries, "XX /%s/%s/%s",
+ ns_info(ns_log_queries, "%s/%s/%s/%s/%s",
+ (hp->rd) ? "XX+" : "XX ",
inet_ntoa(from.sin_addr),
(dname[0] == '\0') ? "." : dname,
- p_type(type));
+ p_type(type), p_class(class));
}
#endif /*QRYLOG*/
@@ -542,7 +758,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
struct in_addr ina;
if (inet_aton(dname, &ina)) {
- hp->rcode = NXDOMAIN;
+ hp->rcode = ns_r_nxdomain;
hp->aa = 1;
ns_debug(ns_log_default, 3,
"ypkludge: hit as '%s'", dname);
@@ -582,10 +798,42 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
zp = &zones[zone];
+ ixfr_found = 0;
+ if (type == ns_t_ixfr && zone != DB_Z_CACHE) {
+ if (SEQ_GT(serial_ixfr, zp->z_serial))
+ ixfr_found = 0;
+ else {
+ ixfr_error = ixfr_have_log(zp, serial_ixfr, zp->z_serial);
+ if (ixfr_error < 0) {
+ ns_debug(ns_log_default,
+ 1, "ixfr_have_log(%d %d) failed %d",
+ serial_ixfr, zp->z_serial, ixfr_error);
+ ixfr_found = 0;
+ /* Refuse IXFR and send AXFR */
+ type = ns_t_axfr;
+ } else
+ ixfr_found = 1;
+ }
+ }
+ /*
+ * If recursion is turned on, we need to check recursion ACL
+ * if it exists - and return result to caller.
+ */
+ {
+ ip_match_list recursion_acl;
+
+ recursion_acl = server_options->recursion_acl;
+ if (!NS_OPTION_P(OPTION_NORECURSE) && recursion_acl != NULL
+ && !ip_address_allowed(recursion_acl, from.sin_addr)) {
+ recursion_blocked_by_acl = 1;
+ *ra = 0;
+ }
+ }
+
/*
* Are queries allowed from this host?
*/
- if (type != T_AXFR) {
+ if (!ns_t_xfr_p(type)) {
ip_match_list query_acl;
if (zp->z_query_acl != NULL)
@@ -594,7 +842,52 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
query_acl = server_options->query_acl;
if (query_acl != NULL
- && !ip_address_allowed(query_acl, from.sin_addr)) {
+ && !ip_addr_or_key_allowed(query_acl, from.sin_addr,
+ in_key))
+ {
+ /*
+ * If this is *not* a zone acl and we would not
+ * have recursed and we have some answer return
+ * what we have with a referral.
+ */
+ if ((zp->z_query_acl == NULL) &&
+ (!hp->rd || NS_OPTION_P(OPTION_NORECURSE) ||
+ recursion_blocked_by_acl) &&
+ (ntohs(hp->ancount) != 0)) {
+ goto fetchns;
+ }
+
+ /*
+ * See if we would have made a referral from
+ * an enclosing zone if we are actually in the
+ * cache.
+ */
+ if (zp->z_type == z_cache && np != NULL) {
+ struct namebuf *access_np;
+
+ zone = DB_Z_CACHE;
+ 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->d_zone == DB_Z_CACHE))
+ dp = dp->d_next;
+ if (dp != NULL) {
+ zone = dp->d_zone;
+ np = access_np;
+ break;
+ }
+ }
+ zp = &zones[zone];
+ if (zp->z_type != z_cache &&
+ zp->z_query_acl != NULL &&
+ ip_addr_or_key_allowed(zp->z_query_acl,
+ from.sin_addr, in_key) &&
+ (!hp->rd || recursion_blocked_by_acl ||
+ NS_OPTION_P(OPTION_NORECURSE))) {
+ goto fetchns;
+ }
+ }
ns_notice(ns_log_security,
"unapproved query from %s for \"%s\"",
sin_ntoa(from), *dname ? dname : ".");
@@ -611,10 +904,23 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
transfer_acl = server_options->transfer_acl;
if (transfer_acl != NULL
- && !ip_address_allowed(transfer_acl, from.sin_addr)) {
+ && !ip_addr_or_key_allowed(transfer_acl, from.sin_addr,
+ in_key))
+ {
ns_notice(ns_log_security,
- "unapproved AXFR from %s for \"%s\" (acl)",
- sin_ntoa(from), *dname ? dname : ".");
+ "unapproved %s from %s for \"%s\" (acl)",
+ p_type(type), sin_ntoa(from),
+ *dname ? dname : ".");
+ return (Refuse);
+ }
+
+ /* Are we master or slave? */
+
+ if (zp->z_type != z_master && zp->z_type != z_slave) {
+ ns_notice(ns_log_security,
+ "unapproved %s from %s for \"%s\" (not master/slave)",
+ p_type(type), sin_ntoa(from),
+ *dname ? dname : ".");
return (Refuse);
}
@@ -622,39 +928,40 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
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 : ".");
+ "unapproved %s from %s for \"%s\" (not authoritative)",
+ p_type(type), sin_ntoa(from),
+ *dname ? dname : ".");
return (Refuse);
}
/* Is the name at a zone cut? */
- if (strcasecmp(zp->z_origin, dname) != 0) {
+ if (ns_samename(zp->z_origin, dname) != 1) {
ns_notice(ns_log_security,
- "unapproved AXFR from %s for \"%s\" (not zone top)",
- sin_ntoa(from), *dname ? dname : ".");
+ "unapproved %s from %s for \"%s\" (not zone top)",
+ p_type(type), sin_ntoa(from),
+ *dname ? dname : ".");
return (Refuse);
}
- ns_info(ns_log_security, "approved AXFR from %s for \"%s\"",
- sin_ntoa(from), *dname ? dname : ".");
+ ns_info(ns_log_security, "approved %s from %s for \"%s\"",
+ p_type(type), sin_ntoa(from), *dname ? dname : ".");
}
/*
* End Access Control Point
*/
-
/*
* Yow!
*/
- if (!strcasecmp(dnbuf, "VERSION.BIND") &&
- class == C_CHAOS && type == T_TXT) {
+ if (class == ns_c_chaos && type == ns_t_txt &&
+ ns_samename(dnbuf, "VERSION.BIND") == 1) {
u_char *tp;
hp->ancount = htons(1);
hp->nscount = htons(0);
hp->arcount = htons(0);
- hp->rcode = NOERROR;
+ hp->rcode = ns_r_noerror;
hp->aa = 1;
hp->ra = 0;
copyCharString(cpp, "VERSION"); /* Name */
@@ -665,7 +972,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
PUTLONG(0, *cpp); /* TTL */
tp = *cpp; /* Temp RdLength */
PUTSHORT(0, *cpp);
- copyCharString(cpp, ShortVersion);
+ copyCharString(cpp, server_options->version);
PUTSHORT((*cpp) - (tp + INT16SZ), tp); /* Real RdLength */
*msglenp = *cpp - msg; /* Total message length */
return (Finish);
@@ -682,11 +989,14 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
answers = *cpp;
count = *cpp - msg;
+ /* The response is authoritative until we add insecure data */
+ hp->ad = 1;
+
/* 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) &&
+ if (!stale(dp) && (dp->d_rcode == ns_r_nxdomain) &&
(dp->d_class == class)) {
#ifdef RETURNSOA
n = finddata(np, class, T_SOA, hp, &dname,
@@ -700,12 +1010,14 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
}
if (hp->rcode == NOERROR_NODATA) {
/* this should not occur */
- hp->rcode = NOERROR;
+ hp->rcode = ns_r_noerror;
return (Finish);
}
}
+#else
+ count = 0;
#endif
- hp->rcode = NXDOMAIN;
+ hp->rcode = ns_r_nxdomain;
/*
* XXX forcing AA all the time isn't right, but
* we have to work that way by default
@@ -715,7 +1027,10 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
hp->aa = 1;
ns_debug(ns_log_default, 3, "NXDOMAIN aa = %d",
hp->aa);
- return (Finish);
+ if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1))
+ return (Finish);
+ founddata = 1;
+ goto fetchns;
}
}
@@ -727,19 +1042,19 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
n = finddata(np, class, type, hp, &dname, buflenp, &count);
if (n == 0) {
/*
- * NO data available. Refuse AXFR requests, or
+ * NO data available. Refuse transfer requests, or
* look for better servers for other requests.
*/
- if (type == T_AXFR) {
+ if (ns_t_xfr_p(type)) {
ns_debug(ns_log_default, 1,
- "T_AXFR refused: no data");
+ "transfer refused: no data");
return (Refuse);
}
goto fetchns;
}
if (hp->rcode == NOERROR_NODATA) {
- hp->rcode = NOERROR;
+ hp->rcode = ns_r_noerror;
#ifdef RETURNSOA
if (count) {
*cpp += n;
@@ -749,7 +1064,10 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
}
#endif
founddata = 1;
- return (Finish);
+ ns_debug(ns_log_default, 1, "count = %d", count);
+ if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1))
+ return (Finish);
+ goto fetchns;
}
*cpp += n;
@@ -760,7 +1078,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
if (cname++ >= MAXCNAMES) {
ns_debug(ns_log_default, 3,
"resp: leaving, MAXCNAMES exceeded");
- hp->rcode = SERVFAIL;
+ hp->rcode = ns_r_servfail;
return (Finish);
}
goto try_again;
@@ -770,11 +1088,46 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
"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));
+ if (ns_t_xfr_p(type)) {
+#ifdef BIND_UPDATE
+ if ((zp->z_flags & Z_NEED_SOAUPDATE) != 0)
+ 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
+ /*
+ * Just return SOA if "up to date".
+ */
+ if (type == ns_t_ixfr) {
+ hp->aa = 1;
+ if ((SEQ_GT(serial_ixfr, zp->z_serial) ||
+ serial_ixfr == zp->z_serial))
+ return (Finish);
+ }
+
+ /*
+ * We don't handle UDP based IXFR queries (yet).
+ * Tell client to retry with TCP by returning SOA.
+ */
+ if (qsp == NULL)
+ return (Finish);
+ else {
+ if (!ixfr_found) {
+ qsp->flags |= STREAM_AXFRIXFR;
+ hp->qdcount = htons(1);
+ }
+ ns_xfr(qsp, np, zone, class, type,
+ hp->opcode, ntohs(hp->id),
+ serial_ixfr, in_tsig);
+ }
return (Return);
}
+ if (count > 1 && type == T_A && !NS_OPTION_P(OPTION_NORECURSE) &&
+ hp->rd)
+ sort_response(answers, *cpp, count, &from);
+
fetchns:
/*
* If we're already out of room in the response, we're done.
@@ -782,6 +1135,9 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
if (hp->tc)
return (Finish);
+ if (hp->ancount == 0)
+ hp->ad = 0;
+
/*
* Look for name servers to refer to and fill in the authority
* section or record the address for forwarding the query
@@ -794,7 +1150,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
case NXDOMAIN:
/* We are authoritative for this np. */
if (!foundname)
- hp->rcode = NXDOMAIN;
+ hp->rcode = ns_r_nxdomain;
ns_debug(ns_log_default, 3, "req: leaving (%s, rcode %d)",
dname, hp->rcode);
if (class != C_ANY) {
@@ -838,21 +1194,29 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
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;
+ !(NS_ZOPTION_P(zp, OPTION_FORWARD_ONLY) &&
+ NS_ZFWDTAB(zp))) {
+ hp->rcode = ns_r_servfail;
free_nsp(nsp);
return (Finish);
}
}
+ if (!founddata && hp->rd && recursion_blocked_by_acl) {
+ ns_notice(ns_log_security,
+ "unapproved recursive query from %s for %s",
+ sin_ntoa(from), *dname ? dname : ".");
+ }
+
/*
* 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.
+ * never recursing, or recursion is prohibited by ACL, then
+ * add the nameserver references("authority section") here
+ * and we're done.
*/
- if (founddata || !hp->rd || NS_OPTION_P(OPTION_NORECURSE)) {
+ if (founddata || !hp->rd || NS_OPTION_P(OPTION_NORECURSE)
+ || recursion_blocked_by_acl) {
/*
* 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
@@ -867,7 +1231,8 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
}
*cpp += n;
*buflenp -= n;
- hp->nscount = htons((u_int16_t)count);
+ hp->nscount = htons(ntohs(hp->nscount) +
+ (u_int16_t)count);
}
free_nsp(nsp);
@@ -886,29 +1251,31 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
omsg = (u_char *)memget((unsigned) *msglenp);
if (omsg == NULL) {
ns_info(ns_log_default, "ns_req: Out Of Memory");
- hp->rcode = SERVFAIL;
+ hp->rcode = ns_r_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);
+ n = res_nmkquery(&res, 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;
+ hp->rcode = ns_r_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)
+ dname, class, type, np, 0, in_tsig);
+ if (n != FW_OK && cname) {
memput(omsg, omsglen);
+ omsg = NULL;
+ }
switch (n) {
case FW_OK:
if (cname) {
@@ -931,7 +1298,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
if (NAME(*np)[0] == '\0') {
ns_notice(ns_log_default,
"ns_req: no address for root server");
- hp->rcode = SERVFAIL;
+ hp->rcode = ns_r_servfail;
free_nsp(nsp);
return (Finish);
}
@@ -961,7 +1328,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp,
goto fetchns; /* Try again. */
case FW_SERVFAIL:
do_servfail:
- hp->rcode = SERVFAIL;
+ hp->rcode = ns_r_servfail;
free_nsp(nsp);
return (Finish);
}
@@ -984,11 +1351,7 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp,
|| 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;
+ hp->rcode = ns_r_formerr;
return (Finish);
}
@@ -998,14 +1361,14 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp,
if ((n = dn_skipname(*cpp, eom)) < 0) {
ns_debug(ns_log_default, 1,
"FORMERR IQuery packet name problem");
- hp->rcode = FORMERR;
+ hp->rcode = ns_r_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;
+ hp->rcode = ns_r_formerr;
return (Finish);
}
GETSHORT(type, *cpp);
@@ -1016,7 +1379,7 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp,
if (*cpp != eom) {
ns_debug(ns_log_default, 1,
"FORMERR IQuery message length off");
- hp->rcode = FORMERR;
+ hp->rcode = ns_r_formerr;
return (Finish);
}
@@ -1025,10 +1388,18 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp,
*/
switch (type) {
case T_A:
- if (!NS_OPTION_P(OPTION_FAKE_IQUERY) || dlen != INT32SZ)
+ if (!NS_OPTION_P(OPTION_FAKE_IQUERY) || dlen != INT32SZ) {
+ if (dlen != INT32SZ)
+ ns_warning(ns_log_security,
+ "bad iquery from %s",
+ inet_ntoa(from.sin_addr));
return (Refuse);
+ }
break;
default:
+ ns_warning(ns_log_security,
+ "unsupported iquery type from %s",
+ inet_ntoa(from.sin_addr));
return (Refuse);
}
ns_debug(ns_log_default, 1,
@@ -1036,8 +1407,12 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp,
fname = (char *)msg + HFIXEDSZ;
alen = (char *)*cpp - fname;
- if ((size_t)alen > sizeof anbuf)
+ if ((size_t)alen > sizeof anbuf) {
+ ns_warning(ns_log_security,
+ "bad iquery from %s",
+ inet_ntoa(from.sin_addr));
return (Refuse);
+ }
memcpy(anbuf, fname, alen);
data = anbuf + alen - dlen;
*cpp = (u_char *)fname;
@@ -1124,7 +1499,7 @@ stale(struct databuf *dp) {
zp->z_origin);
}
zp->z_flags &= ~Z_AUTH;
- if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))) {
+ if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0) {
zp->z_time = tt.tv_sec;
sched_zone_maint(zp);
}
@@ -1137,7 +1512,7 @@ stale(struct databuf *dp) {
zp->z_origin);
}
zp->z_flags &= ~Z_AUTH;
- if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))) {
+ if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0) {
zp->z_time = tt.tv_sec;
sched_zone_maint(zp);
}
@@ -1146,6 +1521,7 @@ stale(struct databuf *dp) {
return (0);
case z_hint:
+ case z_cache:
if (dp->d_flags & DB_F_HINT ||
dp->d_ttl >= (u_int32_t)tt.tv_sec)
return (0);
@@ -1169,7 +1545,8 @@ stale(struct databuf *dp) {
*/
int
make_rr(const char *name, struct databuf *dp, u_char *buf,
- int buflen, int doadd, u_char **comp_ptrs, u_char **edp)
+ int buflen, int doadd, u_char **comp_ptrs, u_char **edp,
+ int use_minimum)
{
u_char *cp;
u_char *cp1, *sp;
@@ -1177,20 +1554,13 @@ make_rr(const char *name, struct databuf *dp, u_char *buf,
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
- )
+ if (dp->d_rcode && dp->d_size == 0)
panic("make_rr: impossible d_rcode value", NULL);
zp = &zones[dp->d_zone];
@@ -1202,7 +1572,7 @@ make_rr(const char *name, struct databuf *dp, u_char *buf,
} else
ttl = dp->d_ttl - (u_int32_t) tt.tv_sec;
} else {
- if (dp->d_ttl != USE_MINIMUM)
+ if (dp->d_ttl != USE_MINIMUM && !use_minimum)
ttl = dp->d_ttl;
else
ttl = zp->z_minimum; /* really default */
@@ -1251,9 +1621,11 @@ make_rr(const char *name, struct databuf *dp, u_char *buf,
return (-1);
PUTSHORT((u_int16_t)n, sp);
cp += n;
- if (doadd)
+ if (doadd) {
addname((char*)dp->d_data, name,
- type, dp->d_class);
+ type, T_A, dp->d_class);
+ addname(name, name, type, T_KEY, dp->d_class);
+ }
break;
case T_SOA:
@@ -1284,6 +1656,8 @@ make_rr(const char *name, struct databuf *dp, u_char *buf,
n = 5 * INT32SZ;
memcpy(cp, cp1, n);
cp += n;
+ if (doadd)
+ addname(name, name, type, T_KEY, dp->d_class);
}
n = (u_int16_t)((cp - sp) - INT16SZ);
PUTSHORT((u_int16_t)n, sp);
@@ -1389,7 +1763,9 @@ make_rr(const char *name, struct databuf *dp, u_char *buf,
cp1 += INT16SZ*2;
}
- n = dn_comp((char *)cp1, cp, buflen, comp_ptrs, edp);
+ n = dn_comp((char *)cp1, cp, buflen,
+ (type == ns_t_mx) ? comp_ptrs : NULL,
+ (type == ns_t_mx) ? edp : NULL);
if (n < 0)
return (-1);
cp += n;
@@ -1398,7 +1774,7 @@ make_rr(const char *name, struct databuf *dp, u_char *buf,
n = (u_int16_t)((cp - sp) - INT16SZ);
PUTSHORT((u_int16_t)n, sp);
if (doadd)
- addname((char*)cp1, name, type, dp->d_class);
+ addname((char*)cp1, name, type, T_A, dp->d_class);
break;
case T_PX:
@@ -1461,7 +1837,32 @@ make_rr(const char *name, struct databuf *dp, u_char *buf,
PUTSHORT((u_int16_t)n, sp);
break;
+ case T_NXT:
+ cp1 = dp->d_data;
+ n = dn_comp((char *)cp1, cp, buflen, NULL, NULL);
+ if (n < 0)
+ return (-1);
+
+ cp += n;
+ buflen -=n;
+ cp1 += strlen((char *)cp1) + 1;
+
+ /* copy nxt bit map */
+ 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;
+ buflen -= n;
+
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ PUTSHORT((u_int16_t)n, sp);
+
+ break;
+
default:
+ if ((type == T_A || type == T_AAAA) && doadd)
+ addname(name, name, type, T_KEY, dp->d_class);
if (dp->d_size > buflen)
return (-1);
memcpy(cp, dp->d_data, dp->d_size);
@@ -1473,13 +1874,13 @@ make_rr(const char *name, struct databuf *dp, u_char *buf,
static void
addname(const char *dname, const char *rname,
- u_int16_t rtype, u_int16_t class)
+ u_int16_t rtype, u_int16_t type, u_int16_t class)
{
struct addinfo *ap;
int n;
for (ap = addinfo, n = addcount; --n >= 0; ap++)
- if (strcasecmp(ap->a_dname, dname) == 0)
+ if (ns_samename(ap->a_dname, dname) == 1 && ap->a_type == type)
return;
/* add domain name to additional section */
@@ -1488,28 +1889,36 @@ addname(const char *dname, const char *rname,
ap->a_dname = savestr(dname, 1);
ap->a_rname = savestr(rname, 1);
ap->a_rtype = rtype;
+ ap->a_type = type;
ap->a_class = class;
}
}
/*
- * Lookup addresses for names in addinfo and put into the message's
+ * Lookup addresses/keys 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;
+ register struct namebuf *np;
+ register struct databuf *dp;
+ register struct addinfo *ap;
+ register u_char *cp;
struct hashbuf *htp;
const char *fname;
- int n, count;
+ register int n, count;
+ register int ns_logging;
+ int finishedA = 0;
+ int save_addcount = addcount;
if (!addcount)
return (0);
- ns_debug(ns_log_default, 3, "doaddinfo() addcount = %d", addcount);
+ ns_logging = ns_wouldlog(ns_log_default, 3);
+
+ if (ns_logging)
+ ns_debug(ns_log_default, 3,
+ "doaddinfo() addcount = %d", addcount);
if (hp->tc) {
ns_debug(ns_log_default, 4,
@@ -1519,6 +1928,7 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) {
count = 0;
cp = msg;
+loop:
for (ap = addinfo; --addcount >= 0; ap++) {
int foundany = 0,
foundcname = 0,
@@ -1526,37 +1936,50 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) {
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);
+ if ((finishedA == 1 && ap->a_type == T_A) ||
+ (finishedA == 0 && ap->a_type == T_KEY))
+ continue;
+ if (ns_logging)
+ 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");
+ if (ns_logging)
+ ns_debug(ns_log_default, 3, "found it");
/* look for the data */
- delete_stale(np);
+ (void)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)) {
+ if ((match(dp, (int)ap->a_class, T_CNAME) &&
+ dp->d_type == T_CNAME) ||
+ (match(dp, C_IN, T_CNAME) &&
+ dp->d_type == T_CNAME)) {
foundcname++;
break;
}
- if (!match(dp, (int)ap->a_class, T_A) &&
+ if (ap->a_type == T_A &&
+ !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;
}
+ if (ap->a_type == T_KEY &&
+ !match(dp, (int)ap->a_class, T_KEY) &&
+ !match(dp, C_IN, T_KEY))
+ 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) {
+ dnptrs, dnptrs_end, 0)) < 0) {
/* truncation in the additional-data section
* is not all that serious. we do not set TC,
* since the answer and authority sections are
@@ -1583,10 +2006,11 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) {
}
next_rr:
if (!NS_OPTION_P(OPTION_NOFETCHGLUE) &&
- !foundcname && !foundany) {
+ !foundcname && !foundany &&
+ (ap->a_type == T_A || ap->a_type == T_AAAA)) {
/* ask a real server for this info */
- (void) sysquery(ap->a_dname, (int)ap->a_class, T_A,
- NULL, 0, QUERY);
+ (void) sysquery(ap->a_dname, (int)ap->a_class,
+ ap->a_type, NULL, 0, ns_port, QUERY);
}
if (foundcname) {
if (!haveComplained(nhash(ap->a_dname),
@@ -1600,6 +2024,11 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) {
freestr(ap->a_dname);
freestr(ap->a_rname);
}
+ if (finishedA == 0) {
+ finishedA = 1;
+ addcount = save_addcount;
+ goto loop; /* now do the KEYs... */
+ }
hp->arcount = htons((u_int16_t)count);
return (cp - msg);
}
@@ -1618,7 +2047,7 @@ doaddauth(HEADER *hp, u_char *cp, int buflen,
dnbuf, buflen);
return (0);
}
- n = make_rr(dnbuf, dp, cp, buflen, 1, dnptrs, dnptrs_end);
+ n = make_rr(dnbuf, dp, cp, buflen, 1, dnptrs, dnptrs_end, 1);
if (n <= 0) {
ns_debug(ns_log_default, 1,
"doaddauth: can't add oversize '%s' (%d) (n=%d)",
@@ -1628,6 +2057,8 @@ doaddauth(HEADER *hp, u_char *cp, int buflen,
}
return (0);
}
+ if (dp->d_secure != DB_S_SECURE)
+ hp->ad = 0;
hp->nscount = htons(ntohs(hp->nscount) + 1);
return (n);
}
diff --git a/contrib/bind/bin/named/ns_resp.c b/contrib/bind/bin/named/ns_resp.c
index 012f89e..d20b1ef 100644
--- a/contrib/bind/bin/named/ns_resp.c
+++ b/contrib/bind/bin/named/ns_resp.c
@@ -1,6 +1,6 @@
#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 $";
+static const char sccsid[] = "@(#)ns_resp.c 4.65 (Berkeley) 3/3/91";
+static const char rcsid[] = "$Id: ns_resp.c,v 8.133 1999/11/05 04:40:57 vixie Exp $";
#endif /* not lint */
/*
@@ -82,7 +82,7 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.56 1998/03/16 19:40:07 halley Exp $";
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -104,6 +104,7 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.56 1998/03/16 19:40:07 halley Exp $";
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/file.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -122,6 +123,8 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.56 1998/03/16 19:40:07 halley Exp $";
#include <isc/logging.h>
#include <isc/memcluster.h>
+#include <isc/dst.h>
+
#include "port_after.h"
#include "named.h"
@@ -164,23 +167,27 @@ struct flush_set {
static void rrsetadd(struct flush_set *, const char *,
struct databuf *),
rrsetupdate(struct flush_set *, int flags,
- struct sockaddr_in),
+ struct sockaddr_in, int),
flushrrset(struct flush_set *, struct sockaddr_in),
- free_flushset(struct flush_set *, int);
-static int rrsetcmp(char *, struct db_list *),
+ free_flushset(struct flush_set *, int),
+ check_hints(struct flush_set *);
+static int rrsetcmp(char *, struct db_list *, struct hashbuf *),
check_root(void),
check_ns(void),
+ wanted(const struct databuf *, int, int),
+ wantedsig(const struct databuf *, int, int),
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 mark_bad(struct qinfo *qp, struct sockaddr_in from);
+static void mark_lame(struct qinfo *qp, struct sockaddr_in from);
+static void fast_retry(struct qinfo *qp, struct sockaddr_in from);
static void add_related_additional(char *);
static void free_related_additional(void);
static int related_additional(char *);
static void freestr_maybe(char **);
+static enum ordering match_order(const struct namebuf *, int, int);
+static int match_name(const struct namebuf *, const char *, size_t);
#define MAX_RELATED 100
@@ -266,18 +273,19 @@ learntFrom(struct qinfo *qp, struct sockaddr_in *server) {
}
void
-ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
+ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp)
+{
struct qinfo *qp;
HEADER *hp;
- struct qserv *qs;
+ struct qserv *qs = NULL;
struct databuf *ns, *ns2;
- u_char *cp;
- u_char *eom = msg + msglen;
+ u_char *cp, *answers, *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;
+ int soacount;
u_int qtype, qclass;
int restart; /* flag for processing cname response */
int validanswer, dbflags;
@@ -286,7 +294,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
int buflen;
int newmsglen;
char name[MAXDNAME], qname[MAXDNAME], aname[MAXDNAME];
- char msgbuf[MAXDNAME];
+ char msgbuf[MAXDNAME+100];
char *dname, tmpdomain[MAXDNAME];
const char *fname;
const char *formerrmsg = "brain damage";
@@ -299,6 +307,14 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
struct databuf *dp;
int forcecmsg = 0;
char *tname = NULL;
+ int sendto_errno = 0;
+ int has_tsig, oldqlen;
+ u_char *oldqbuf;
+ u_char *smsg;
+ int smsglen, smsgsize, siglen;
+ u_char sig[TSIG_SIG_SIZE];
+ time_t tsig_time;
+ DST_KEY *key;
nameserIncr(from.sin_addr, nssRcvdR);
nsp[0] = NULL;
@@ -310,18 +326,39 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
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));
+ if (ns_wouldlog(ns_log_default, 2)) {
+ 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));
+ }
+
+ if (qp->q_nstsig == NULL)
+ has_tsig = 0;
+ else {
+ int ret;
+
+ ret = ns_verify(msg, &msglen, qp->q_nstsig->key,
+ qp->q_nstsig->sig, qp->q_nstsig->siglen,
+ NULL, NULL, &tsig_time, 0);
+ if (ret == 0)
+ has_tsig = 1;
+ else {
+ if (hp->rcode == NOERROR)
+ hp->rcode = NOTAUTH;
+ ns_debug(ns_log_default, 1,
+ "resp: error bad tsig, record dropped");
+ return;
+ }
+ }
/*
* Here we handle high level formatting problems by parsing the header.
*/
qdcount = ntohs(hp->qdcount);
ancount = ntohs(hp->ancount);
- aucount = ntohs(hp->nscount); /* !!! */
+ aucount = ntohs(hp->nscount);
arcount = ntohs(hp->arcount);
free_addinfo(); /* sets addcount to zero */
cp = msg + HFIXEDSZ;
@@ -343,7 +380,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
}
GETSHORT(qtype, cp);
GETSHORT(qclass, cp);
- if (!ns_nameok(qname, qclass, NULL, response_trans,
+ if (!ns_nameok(qp, qname, qclass, NULL, response_trans,
ns_ownercontext(qtype, response_trans),
qname, from.sin_addr)) {
formerrmsg = badNameFound;
@@ -362,7 +399,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
formerrmsg = msgbuf;
goto formerr;
}
- if (strcasecmp(qp->q_name, qname) != 0 ||
+ if (ns_samename(qp->q_name, qname) != 1 ||
qp->q_class != qclass ||
qp->q_type != qtype) {
formerrmsg = wrongQuestion;
@@ -405,20 +442,11 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
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);
+ if (ns_samename(qp->q_name, qp->q_domain) == 1 &&
+ hp->rcode == SERVFAIL && hp->opcode == QUERY)
+ mark_lame(qp, from);
+ mark_bad(qp, from);
+ fast_retry(qp, from);
return;
}
@@ -434,7 +462,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
* might have forwarded the query will be dropped.
* XXX - should put this in STATS somewhere.
*/
- for (fwd = server_options->fwdtab; fwd; fwd = fwd->next)
+ for (fwd = NS_ZFWDTAB(qp->q_fzone); fwd; fwd = fwd->next)
if (ina_equal(fwd->fwdaddr.sin_addr, from.sin_addr))
break;
/*
@@ -451,9 +479,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
if (fwd == NULL) {
struct timeval *stp;
- for (n = 0, qs = qp->q_addr;
- (u_int)n < qp->q_naddr;
- n++, qs++)
+ 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) {
@@ -472,7 +498,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
stp = &qs->stime;
/* Handle response from different (untried) interface. */
- if ((qs->ns != NULL) && (stp->tv_sec == 0)) {
+ if (qs->ns != NULL && stp->tv_sec == 0) {
ns = qs->ns;
while (qs > qp->q_addr
&& (qs->stime.tv_sec == 0 || qs->ns != ns))
@@ -498,11 +524,13 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
(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);
+ if (ns_wouldlog(ns_log_default,3)) {
+ 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) {
@@ -534,9 +562,11 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
*/
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);
+ if (ns_wouldlog(ns_log_default,2)) {
+ ns_debug(ns_log_default, 2,
+ "NS #%d addr %s used, rtt %d",
+ n, sin_ntoa(qs->ns_addr), ns->d_nstime);
+ }
}
/*
@@ -573,9 +603,11 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
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);
+ if (ns_wouldlog(ns_log_default,2)) {
+ ns_debug(ns_log_default, 2, "NS #%d %s rtt now %d", n,
+ sin_ntoa(qs->ns_addr),
+ ns2->d_nstime);
+ }
}
}
@@ -586,11 +618,91 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
* a NOTIFY-QR is to remove it from the query queue.
*/
if (hp->opcode == NS_NOTIFY_OP) {
+ ns_info(ns_log_notify,
+ "Received NOTIFY answer from %s for \"%s %s %s\"",
+ inet_ntoa(from.sin_addr),
+ *(qp->q_name) ? qp->q_name : ".",
+ p_class(qp->q_class), p_type(qp->q_type));
qremove(qp);
return;
}
#endif
+ if ((qp->q_flags & Q_ZSERIAL) != 0) {
+ 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(qp, name, class, NULL, response_trans,
+ ns_ownercontext(type, response_trans),
+ name, from.sin_addr)) {
+ formerrmsg = badNameFound;
+ goto refused;
+ }
+ if (ns_samename(qname, name) != 1 ||
+ 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;
+ }
+ 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 (n == qp->q_naddr) {
+ qserial_answer(qp);
+ qremove(qp);
+ return;
+ }
+ qs->serial = serial;
+ }
+ retry(qp);
+ return;
+ }
+
/*
* Non-authoritative, no answer, no error, with referral.
*/
@@ -603,7 +715,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
int type, class;
#ifdef DEBUG
if (debug > 0)
- fp_nquery(msg, msglen, log_get_stream(packet_channel));
+ res_pquery(&res, msg, msglen,
+ log_get_stream(packet_channel));
#endif
/*
* Since there is no answer section (ancount == 0),
@@ -622,7 +735,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
}
GETSHORT(type, tp);
GETSHORT(class, tp);
- if (!ns_nameok(name, class, NULL, response_trans,
+ if (!ns_nameok(qp, name, class, NULL, response_trans,
ns_ownercontext(type, response_trans),
name, from.sin_addr)) {
formerrmsg = badNameFound;
@@ -638,14 +751,10 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
* classes tend to not have good strong delegation graphs).
*/
- if (type == T_NS && samedomain(qp->q_domain, name)) {
+ if (type == T_NS && 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;
+ mark_lame(qp, from);
+ mark_bad(qp, from);
if (class == C_IN &&
!haveComplained(ina_ulong(from.sin_addr),
nhash(qp->q_domain))) {
@@ -661,92 +770,21 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
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);
+ fast_retry(qp, from);
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;
+ /* Don't return if it's a TSIG signed truncated message */
+ if (has_tsig > 0 && hp->tc)
+ goto tcp_retry;
+
/* -ve $ing non-existence of record, must handle non-authoritative
* NOERRORs with c == 0.
*/
@@ -769,11 +807,47 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
count -= ancount; /* things are pretty grim */
}
+tcp_retry:
/* 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);
+
+ nsa = Q_NEXTADDR(qp, 0);
+
+ key = tsig_key_from_addr(nsa->sin_addr);
+ if (key != NULL) {
+ smsgsize = qp->q_msglen + TSIG_BUF_SIZE;
+ smsg = memget(smsgsize);
+ smsglen = qp->q_msglen;
+ siglen = sizeof(sig);
+ memcpy(smsg, qp->q_msg, qp->q_msglen);
+ n = ns_sign(smsg, &smsglen, smsgsize,
+ NOERROR, key, NULL, 0,
+ sig, &siglen, 0);
+ if (n == 0) {
+ oldqbuf = qp->q_msg;
+ oldqlen = qp->q_msglen;
+ qp->q_msglen = smsglen;
+ qp->q_msg = smsg;
+ has_tsig = 1;
+ qp->q_nstsig = new_tsig(key, sig,
+ siglen);
+ }
+ else {
+ has_tsig = 0;
+ free_tsig(qp->q_nstsig);
+ qp->q_nstsig = NULL;
+ INSIST(0);
+ }
+ }
+ else {
+ has_tsig = 0;
+ free_tsig(qp->q_nstsig);
+ qp->q_nstsig = NULL;
+ }
+
if (tcp_send(qp) != NOERROR)
/*
* We're probably in trouble if tcp_send
@@ -781,6 +855,12 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
* there isn't anything else to do.
*/
retry(qp);
+
+ if (has_tsig == 1) {
+ memput(qp->q_msg, smsgsize);
+ qp->q_msg = oldqbuf;
+ qp->q_msglen = oldqlen;
+ }
return;
} else if (!qsp) {
/* outstanding udp response */
@@ -789,15 +869,11 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
/* XXX truncated tcp response */
ns_error(ns_log_default,
- "ns_resp: TCP truncated: \"%s\" %s %s",
- qname, p_class(qclass), p_type(qtype));
+ "ns_resp: TCP truncated: \"%s\" %s %s from %s",
+ qname, p_class(qclass), p_type(qtype),
+ sin_ntoa(from));
/* 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;
-
+ mark_bad(qp, from);
/* try another server, it may have a bigger write buffer */
retry(qp);
return;
@@ -808,6 +884,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
restart = 0;
validanswer = 0;
nscount = 0;
+ soacount = 0;
cname = 0;
lastwascname = 0;
externalcname = 0;
@@ -854,7 +931,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
type = dp->d_type;
if (i < ancount) {
/* Answer section. */
- if (externalcname || strcasecmp(name, aname) != 0) {
+ if (externalcname || ns_samename(name, aname) != 1) {
if (!externalcname)
ns_info(ns_log_resp_checks,
"wrong ans. name (%s != %s)",
@@ -870,7 +947,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
if (type == T_CNAME &&
qtype != T_CNAME && qtype != T_ANY) {
strcpy(aname, (char *)dp->d_data);
- if (!samedomain(aname, qp->q_domain))
+ if (!ns_samedomain(aname, qp->q_domain))
externalcname = 1;
cname++;
lastwascname = 1;
@@ -884,7 +961,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
tname = NULL;
}
- dp->d_cred = (hp->aa && !strcasecmp(name, qname))
+ dp->d_cred = (hp->aa && ns_samename(name, qname) == 1)
? DB_C_AUTH
: DB_C_ANSWER;
} else {
@@ -900,14 +977,14 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
switch (type) {
case T_NS:
case T_SOA:
- if (!samedomain(aname, name)){
+ if (!ns_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,
+ } else if (!ns_samedomain(name,
qp->q_domain)) {
if (!externalcname)
ns_info(ns_log_resp_checks,
@@ -923,6 +1000,9 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
add_related_additional(tname);
tname = NULL;
}
+ if (type == T_SOA) {
+ soacount++;
+ }
break;
case T_NXT:
/* XXX check */
@@ -939,13 +1019,17 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
db_freedata(dp);
continue;
}
+ dp->d_cred = (hp->aa && (cname == 0)) ?
+ DB_C_AUTH : (qp->q_flags & Q_PRIMING)
+ ? DB_C_ANSWER
+ : DB_C_ADDITIONAL;
} else {
/* Additional section. */
switch (type) {
case T_A:
case T_AAAA:
if (externalcname ||
- !samedomain(name, qp->q_domain)) {
+ !ns_samedomain(name, qp->q_domain)) {
ns_debug(ns_log_resp_checks, 3,
"ignoring additional info '%s' type %s",
name, p_type(type));
@@ -980,21 +1064,29 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
db_freedata(dp);
continue;
}
+ dp->d_cred = (qp->q_flags & Q_PRIMING)
+ ? DB_C_ANSWER
+ : DB_C_ADDITIONAL;
}
- 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);
+ if ((qp->q_flags & Q_SYSTEM) && (qp->q_flags & Q_PRIMING)) {
+ check_hints(flushset); /* before rrsetupdate */
+ rrsetupdate(flushset, dbflags, from, 1);
+ } else
+ rrsetupdate(flushset, dbflags, from, 0);
free_flushset(flushset, flushset_size);
}
if (lastwascname && !externalcname)
- ns_info(ns_log_cname, "%s (%s)", danglingCname, aname);
+ ns_debug(ns_log_cname, 3, "%s (%s) q(%s %s %s) %s qd(%s)",
+ danglingCname, aname,
+ (qname && *qname) ? qname : ".",
+ p_class(qclass), p_type(qtype),
+ sin_ntoa(from), qp->q_domain);
if (cp > eom) {
formerrmsg = outofDataAFinal;
@@ -1004,18 +1096,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
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);
+ mark_bad(qp, from);
+ fast_retry(qp, from);
return;
}
ns_debug(ns_log_default, 3,
@@ -1024,9 +1106,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
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);
+ ns_notify(zp->z_origin, zp->z_class, ns_t_soa);
}
#endif
qremove(qp);
@@ -1052,6 +1133,9 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
restart = 1;
}
+ if (!restart && !qp->q_cmsglen && ancount > 1 && qtype == T_A)
+ sort_response(tp, eom, ancount, &qp->q_from);
+
/*
* An answer to a T_ANY query or a successful answer to a
* regular query with no indirection, then just return answer.
@@ -1068,11 +1152,19 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
* 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!
+ *
+ * As some servers incorrectly return a NODATA indication when
+ * there is a CNAME chain instead of NXDOMAIN, we requery to get
+ * a definitive answer.
*/
- if (((hp->rcode == NXDOMAIN) && (cname == ancount)) ||
- ((hp->rcode == NOERROR) && (ancount == 0) && (nscount == 0)))
+ if ((hp->rcode == NXDOMAIN && cname == ancount) ||
+ (hp->rcode == NOERROR && ancount == 0 &&
+ (nscount == 0 || soacount != 0)
+ )
+ )
{
- cache_n_resp(msg, msglen, from);
+ cache_n_resp(msg, msglen, from, qp->q_name,
+ qp->q_class, qp->q_type);
if (!qp->q_cmsglen) {
ns_debug(ns_log_default, 3,
@@ -1153,6 +1245,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
goto fetch_ns;
foundname++;
+ answers = cp;
count = cp - newmsg;
/*
* Look for NXDOMAIN record.
@@ -1175,6 +1268,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
goto return_newmsg;
}
}
+#else
+ count = 0;
#endif
hp->rcode = NXDOMAIN;
/*
@@ -1186,7 +1281,10 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
hp->aa = 1;
ns_debug(ns_log_default, 3, "resp: NXDOMAIN aa = %d",
hp->aa);
- goto return_newmsg;
+ if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1))
+ goto return_newmsg;
+ founddata = 1;
+ goto fetch_ns;
}
}
n = finddata(np, qclass, qtype, hp, &dname, &buflen, &count);
@@ -1202,7 +1300,10 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
hp->nscount = htons((u_int16_t)count);
}
#endif
- goto return_newmsg;
+ if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1))
+ goto return_newmsg;
+ founddata = 1;
+ goto fetch_ns;
}
cp += n;
buflen -= n;
@@ -1217,6 +1318,9 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
"resp: foundname=%d, count=%d, founddata=%d, cname=%d",
foundname, count, founddata, cname);
+ if (count > 1 && qtype == T_A)
+ sort_response(answers, cp, count, &qp->q_from);
+
fetch_ns:
if (hp->tc)
goto return_newmsg;
@@ -1256,7 +1360,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
}
cp += n;
buflen -= n;
- hp->nscount = htons((u_int16_t)count);
+ hp->nscount = htons((u_int16_t)count + ntohs(hp->nscount));
goto return_newmsg;
}
@@ -1279,17 +1383,20 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
ns_freeqns(qp, "ns_resp");
qp->q_naddr = 0;
qp->q_curaddr = 0;
- qp->q_fwd = server_options->fwdtab;
+ nsfwdadd(qp, NS_ZFWDTAB(qp->q_fzone));
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 (NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY))
+ n = 0;
+ else if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) {
if (n < 0) {
- ns_debug(ns_log_default, 3,
- "resp: nslookup reports danger");
+ if (n == -1)
+ 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;
@@ -1316,8 +1423,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
}
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;
+ qp->q_addr[0].stime = tt;
if (cname) {
if (qp->q_cname++ == MAXCNAMES) {
ns_debug(ns_log_default, 3,
@@ -1339,8 +1445,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
goto servfail;
}
qp->q_msgsize = PACKETSZ;
- n = res_mkquery(QUERY, dname, qclass, qtype,
- NULL, 0, NULL, qp->q_msg, PACKETSZ);
+ n = res_nmkquery(&res, 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);
@@ -1355,23 +1461,55 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
} else
hp = (HEADER *) qp->q_msg;
hp->id = qp->q_nsid = htons(nsid_next());
- if (qp->q_fwd)
+ if (qp->q_addr[0].forwarder)
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);
+ if (ns_wouldlog(ns_log_default,1)) {
+ 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));
+ res_pquery(&res, qp->q_msg, qp->q_msglen,
+ log_get_stream(packet_channel));
#endif
+ key = tsig_key_from_addr(nsa->sin_addr);
+ if (key != NULL) {
+ smsgsize = qp->q_msglen + TSIG_BUF_SIZE;
+ smsg = memget(smsgsize);
+ smsglen = qp->q_msglen;
+ siglen = sizeof(sig);
+ memcpy(smsg, qp->q_msg, qp->q_msglen);
+ n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0,
+ sig, &siglen, 0);
+ if (n == 0) {
+ oldqbuf = qp->q_msg;
+ oldqlen = qp->q_msglen;
+ qp->q_msglen = smsglen;
+ qp->q_msg = smsg;
+ has_tsig = 1;
+ qp->q_nstsig = new_tsig(key, sig, siglen);
+ }
+ else {
+ has_tsig = 0;
+ free_tsig(qp->q_nstsig);
+ qp->q_nstsig = NULL;
+ INSIST(0);
+ }
+ }
+ else {
+ has_tsig = 0;
+ free_tsig(qp->q_nstsig);
+ qp->q_nstsig = NULL;
+ }
+
if (qp->q_flags & Q_USEVC) {
if (tcp_send(qp) != NOERROR) {
if (!haveComplained(ina_ulong(nsa->sin_addr),
@@ -1384,23 +1522,38 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) {
(struct sockaddr *)nsa,
sizeof(struct sockaddr_in)) < 0)
{
+ sendto_errno = errno;
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);
}
+ if (has_tsig == 1) {
+ memput(qp->q_msg, smsgsize);
+ qp->q_msg = oldqbuf;
+ qp->q_msglen = oldqlen;
+ }
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);
+ switch (sendto_errno) {
+ case ENETDOWN:
+ case ENETUNREACH:
+ case EHOSTDOWN:
+ case EHOSTUNREACH:
+ unsched(qp);
+ schedretry(qp, (time_t) 0);
+ }
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);
+ fast_retry(qp, from);
free_nsp(nsp);
return;
@@ -1487,7 +1640,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
{
u_char *cp, *eom, *rdatap;
u_int class, type, dlen;
- int n, n1;
+ int n, n1, n2;
u_int32_t ttl;
u_char *cp1, data[MAXDATA*2];
HEADER *hp = (HEADER *)msg;
@@ -1507,6 +1660,11 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
GETSHORT(type, cp);
GETSHORT(class, cp);
+ if (class > CLASS_MAX) {
+ ns_debug(ns_log_default, 3, "bad class in rrextract");
+ hp->rcode = FORMERR;
+ return (-1);
+ }
GETLONG(ttl, cp);
if (ttl > MAXIMUM_TTL) {
ns_debug(ns_log_default, 5, "%s: converted TTL > %u to 0",
@@ -1516,7 +1674,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
GETSHORT(dlen, cp);
BOUNDS_CHECK(cp, dlen);
rdatap = cp;
- if (!ns_nameok(dname, class, NULL, response_trans,
+ if (!ns_nameok(NULL, dname, class, NULL, response_trans,
ns_ownercontext(type, response_trans),
dname, from.sin_addr)) {
hp->rcode = REFUSED;
@@ -1558,6 +1716,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
case T_AAAA:
case T_LOC:
case T_KEY:
+ case ns_t_cert:
cp1 = cp;
n = dlen;
cp += n;
@@ -1574,7 +1733,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
hp->rcode = FORMERR;
return (-1);
}
- if (!ns_nameok((char *)data, class, NULL, response_trans,
+ if (!ns_nameok(NULL, (char *)data, class, NULL, response_trans,
type == T_PTR ?ns_ptrcontext(dname) :domain_ctx,
dname, from.sin_addr)) {
hp->rcode = FORMERR;
@@ -1600,7 +1759,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
hp->rcode = FORMERR;
return (-1);
}
- if (!ns_nameok((char *)data, class, NULL, response_trans,
+ if (!ns_nameok(NULL, (char *)data, class, NULL, response_trans,
context, dname, from.sin_addr)) {
hp->rcode = FORMERR;
return (-1);
@@ -1623,7 +1782,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
context = domain_ctx;
else
context = mailname_ctx;
- if (!ns_nameok((char *)cp1, class, NULL, response_trans,
+ if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans,
context, dname, from.sin_addr)) {
hp->rcode = FORMERR;
return (-1);
@@ -1679,7 +1838,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
hp->rcode = FORMERR;
return (-1);
}
- if (!ns_nameok((char *)cp1, class, NULL, response_trans,
+ if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans,
hostname_ctx, dname, from.sin_addr)) {
hp->rcode = FORMERR;
return (-1);
@@ -1718,7 +1877,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
hp->rcode = FORMERR;
return (-1);
}
- if (!ns_nameok((char *)cp1, class, NULL, response_trans,
+ if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans,
hostname_ctx, dname, from.sin_addr)) {
hp->rcode = FORMERR;
return (-1);
@@ -1749,7 +1908,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
hp->rcode = FORMERR;
return (-1);
}
- if (!ns_nameok((char *)cp1, class, NULL, response_trans,
+ if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans,
domain_ctx, dname, from.sin_addr)) {
hp->rcode = FORMERR;
return (-1);
@@ -1766,7 +1925,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
hp->rcode = FORMERR;
return (-1);
}
- if (!ns_nameok((char *)cp1, class, NULL, response_trans,
+ if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans,
domain_ctx, dname, from.sin_addr)) {
hp->rcode = FORMERR;
return (-1);
@@ -1779,13 +1938,16 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
case T_SIG: {
u_long origTTL, exptime, signtime, timetilexp, now;
+ u_int8_t alg;
/* Check signature time, expiration, and adjust TTL. */
/* This code is similar to that in db_load.c. */
- /* Skip coveredType, alg, labels */
+ /* Skip coveredType, save alg, skip labels */
BOUNDS_CHECK(cp, INT16SZ + 1 + 1 + 3*INT32SZ);
- cp1 = cp + INT16SZ + 1 + 1;
+ cp1 = cp + INT16SZ;
+ alg = *cp1++;
+ cp1++;
GETLONG(origTTL, cp1);
GETLONG(exptime, cp1);
GETLONG(signtime, cp1);
@@ -1836,7 +1998,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
/* then the signer's name */
n = dn_expand(msg, eom, cp, (char *)cp1, (sizeof data) - 18);
- if (n < 0) {
+ if (n < 0 || n + NS_SIG_SIGNER > dlen) {
hp->rcode = FORMERR;
return (-1);
}
@@ -1845,15 +2007,31 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
/* 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))) {
+ n = dlen - (NS_SIG_SIGNER + n);
+
+ if (n > (sizeof data) - (cp1 - (u_char *)data)) {
hp->rcode = FORMERR;
return (-1); /* out of room! */
}
+
+ switch (alg) {
+ case NS_ALG_MD5RSA:
+ if (n < NS_MD5RSA_MIN_SIZE || n > NS_MD5RSA_MAX_SIZE)
+ hp->rcode = FORMERR;
+ break;
+
+ case NS_ALG_DSA:
+ if (n != NS_DSA_SIG_SIZE)
+ hp->rcode = FORMERR;
+ break;
+
+ default:
+ break;
+ }
+
+ if (hp->rcode == FORMERR)
+ return (-1);
+
memcpy(cp1, cp, n);
cp += n;
cp1 += n;
@@ -1864,6 +2042,63 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
break;
}
+ case T_NXT:
+ n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
+ /*
+ * By testing if n >= dlen, we are requiring that the type
+ * bitmap be at least one octet. This is reasonable
+ * because we always have to look at the 0 bit to see if
+ * this is a "different format" NXT or not.
+ */
+ if (n < 0 || n >= dlen) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if (!ns_nameok(NULL, (char *)data, class, NULL, response_trans,
+ domain_ctx, dname, from.sin_addr)) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ n1 = strlen((char *)data) + 1;
+ cp1 = data + n1;
+ /*
+ * We don't need to BOUNDS_CHECK() cp here because we've
+ * previously checked that 'dlen' bytes are in bounds, and
+ * we know that n < dlen.
+ */
+ n2 = dlen - n;
+ /*
+ * The first bit of the first octet determines the format
+ * of the NXT record. A format for types >= 128 has not
+ * yet been defined, so if bit zero is set, we just copy
+ * what's there because we don't understand it.
+ */
+ if ((*cp & 0x80) == 0) {
+ /*
+ * Bit zero is not set; this is an ordinary NXT
+ * record. The bitmap must be at least 4 octets
+ * because the NXT bit should be set. It should be
+ * less than or equal to 16 octets because this NXT
+ * format is only defined for types < 128.
+ */
+ if (n2 < 4 || n2 > 16) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ }
+ if (n2 > sizeof data - n1) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ memcpy(cp1, cp, n2);
+ cp += n2;
+
+ /* 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);
@@ -1895,17 +2130,25 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp,
int
send_msg(u_char *msg, int msglen, struct qinfo *qp) {
+ HEADER *hp = (HEADER *) msg;
+ u_char *oldmsg;
+ int oldlen;
+ int msgsize;
+ int ret;
+
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));
+ if (ns_wouldlog(ns_log_default, 1)) {
+ 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) {
+ if (ns_wouldlog(ns_log_default, 4)) {
struct qinfo *tqp;
for (tqp = nsqhead; tqp != NULL; tqp = tqp->q_link) {
@@ -1922,9 +2165,44 @@ send_msg(u_char *msg, int msglen, struct qinfo *qp) {
}
}
if (debug >= 6)
- fp_nquery(msg, msglen, log_get_stream(packet_channel));
+ res_pquery(&res, msg, msglen, log_get_stream(packet_channel));
#endif /* DEBUG */
+
+ if (qp->q_tsig != NULL) {
+ u_char sig[TSIG_SIG_SIZE];
+ int siglen = sizeof(sig);
+
+ oldmsg = msg;
+ oldlen = msglen;
+
+ msgsize = msglen + TSIG_BUF_SIZE;
+ msg = memget(msgsize);
+ memcpy(msg, oldmsg, oldlen);
+
+ ret = ns_sign(msg, &msglen, msgsize, NOERROR, qp->q_tsig->key,
+ qp->q_tsig->sig, qp->q_tsig->siglen,
+ sig, &siglen, 0);
+
+ if (ret != 0) {
+ INSIST(0);
+ }
+ }
+
if (qp->q_stream == NULL) {
+ /*
+ * Don't send FORMERR to these well known ports
+ * (loop avoidance).
+ */
+ switch (ntohs(qp->q_from.sin_port)) {
+ case 7: /* echo */
+ case 13: /* daytime */
+ case 19: /* chargen */
+ case 37: /* time */
+ if (hp->rcode == FORMERR)
+ return (-1);
+ default:
+ break;
+ }
if (sendto(qp->q_dfd, (char*)msg, msglen, 0,
(struct sockaddr *)&qp->q_from,
sizeof(qp->q_from)) < 0) {
@@ -1942,232 +2220,78 @@ send_msg(u_char *msg, int msglen, struct qinfo *qp) {
}
} 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 (qp->q_tsig != NULL)
+ memput(msg, oldlen + TSIG_BUF_SIZE);
- 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);
+ return (0);
}
-#endif
-void
-prime_cache() {
- struct qinfo *qp;
+static int
+root_server_p(ns_class class) {
+ struct zoneinfo *zp = find_zone("", class);
- /*
- * 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;
+ return (zp != NULL &&
+ (zp->z_type == z_master || zp->z_type == z_slave));
}
-#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);
- }
-}
+prime_cache(void) {
+ int root = root_server_p(ns_c_in);
-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;
+ ns_debug(ns_log_default, 1, "prime_cache: priming = %d, root = %d",
+ priming, root);
+ if (!priming && !root) {
+ struct qinfo *qp = sysquery("", ns_c_in, ns_t_ns,
+ NULL, 0, ns_port, ns_o_query);
- qp = sysquery(aname, class, T_A, 0, 0, QUERY);
- if (qp != NULL)
- qp->q_notifyzone = zn;
+ if (qp != NULL) {
+ qp->q_flags |= (Q_SYSTEM | Q_PRIMING);
+ priming++;
}
- return;
}
- (void) sysquery(dname, class, T_SOA, nss, nsc, NS_NOTIFY_OP);
- (*nns)++;
- *na += nsc;
+ needs_prime_cache = 0;
}
-#endif /*BIND_NOTIFY*/
struct qinfo *
sysquery(const char *dname, int class, int type,
- struct in_addr *nss, int nsc, int opcode)
+ struct in_addr *nss, int nsc, u_int16_t port, int opcode)
{
struct qinfo *qp, *oqp;
HEADER *hp;
char tmpdomain[MAXDNAME];
- struct namebuf *np;
+ struct namebuf *np = NULL;
struct databuf *nsp[NSMAX];
- struct hashbuf *htp;
+ struct hashbuf *htp1;
+ struct hashbuf *htp2;
+ struct hashbuf *htp3;
struct sockaddr_in *nsa;
const char *fname;
int n, count;
+ int sendto_errno = 0;
+ u_char *oldqbuf;
+ int oldqlen, has_tsig;
+ u_char *smsg;
+ int smsglen, smsgsize, siglen;
+ u_char sig[TSIG_SIG_SIZE];
+ DST_KEY *key;
nsp[0] = NULL;
- ns_debug(ns_log_default, 3, "sysquery(%s, %d, %d, %#x, %d)",
- dname, class, type, nss, nsc);
+ ns_debug(ns_log_default, 3, "sysquery(%s, %d, %d, %#x, %d, %d)",
+ dname, class, type, nss, nsc, ntohs(port));
qp = qnew(dname, class, type);
- if (nss && nsc)
+ if (nss != NULL && nsc != 0)
np = NULL;
- else {
- htp = hashtab;
+ else if (!NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) {
+ htp1 = hashtab;
+ htp2 = hashtab;
+ htp3 = fcachetab;
if (priming && dname[0] == '\0') {
np = NULL;
- } else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) {
+ } else if (((np = nlookup(dname, &htp1, &fname, 0)) == NULL) &&
+ ((np = nlookup("", &htp2, &fname, 0)) == NULL) &&
+ ((np = nlookup("", &htp3, &fname, 0)) == NULL)) {
ns_info(ns_log_default,
"sysquery: nlookup error on %s?",
dname);
@@ -2190,13 +2314,11 @@ sysquery(const char *dname, int class, int type,
}
}
- /* build new qinfo struct */
+ /* 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;
+ if (nss == NULL || nsc == 0)
+ nsfwdadd(qp, NS_ZFWDTAB(qp->q_fzone));
qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2;
qp->q_flags |= Q_SYSTEM;
@@ -2208,9 +2330,9 @@ sysquery(const char *dname, int class, int type,
goto err2;
}
qp->q_msgsize = PACKETSZ;
- n = res_mkquery(opcode, dname, class,
- type, NULL, 0, NULL,
- qp->q_msg, PACKETSZ);
+ n = res_nmkquery(&res, 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);
@@ -2219,9 +2341,9 @@ sysquery(const char *dname, int class, int type,
qp->q_msglen = n;
hp = (HEADER *) qp->q_msg;
hp->id = qp->q_nsid = htons(nsid_next());
- hp->rd = (qp->q_fwd ? 1 : 0);
+ hp->rd = (qp->q_addr[qp->q_curaddr].forwarder ? 1 : 0);
- /* First check for an already pending query for this data */
+ /* 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)
@@ -2242,30 +2364,30 @@ sysquery(const char *dname, int class, int type,
}
}
- if (nss && nsc) {
+ if (nss != NULL && nsc != 0) {
int i;
struct qserv *qs;
- for (i = 0, qs = qp->q_addr;
- i < nsc;
- i++, 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_addr.sin_port = port;
qs->ns = NULL;
qs->nsdata = NULL;
qs->stime = tt;
+ qs->forwarder = 0;
qs->nretry = 0;
}
qp->q_naddr = nsc;
- } else {
+ } else if (!NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) {
fetch_a:
count = nslookup(nsp, qp, dname, "sysquery");
if (count <= 0) {
if (count < 0) {
- ns_info(ns_log_default,
+ if (n == -1)
+ ns_info(ns_log_default,
"sysquery: nslookup reports danger (%s)",
- dname);
+ dname);
goto err2;
} else if (np && NAME(*np)[0] == '\0') {
/*
@@ -2303,6 +2425,10 @@ sysquery(const char *dname, int class, int type,
n, dname);
goto err2;
}
+ getname(np, tmpdomain, sizeof tmpdomain);
+ if (qp->q_domain != NULL)
+ freestr(qp->q_domain);
+ qp->q_domain = savestr(tmpdomain, 1);
goto fetch_a;
}
goto err2;
@@ -2310,8 +2436,7 @@ sysquery(const char *dname, int class, int type,
}
schedretry(qp, retrytime(qp));
- if (qp->q_fwd == NULL)
- qp->q_addr[0].stime = tt; /* XXX - why not every? */
+ qp->q_addr[0].stime = tt; /* XXX - why not every? */
nsa = Q_NEXTADDR(qp, 0);
ns_debug(ns_log_default, 1,
@@ -2321,20 +2446,67 @@ sysquery(const char *dname, int class, int type,
(long)qp->q_time);
#ifdef DEBUG
if (debug >= 10)
- fp_nquery(qp->q_msg, qp->q_msglen,
- log_get_stream(packet_channel));
+ res_pquery(&res, qp->q_msg, qp->q_msglen,
+ log_get_stream(packet_channel));
#endif
+
+ key = tsig_key_from_addr(nsa->sin_addr);
+ if (key != NULL) {
+ smsgsize = qp->q_msglen + TSIG_BUF_SIZE;
+ smsg = memget(smsgsize);
+ smsglen = qp->q_msglen;
+ siglen = sizeof(sig);
+ memcpy(smsg, qp->q_msg, qp->q_msglen);
+ n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0,
+ sig, &siglen, 0);
+ if (n == 0) {
+ oldqbuf = qp->q_msg;
+ oldqlen = qp->q_msglen;
+ qp->q_msglen = smsglen;
+ qp->q_msg = smsg;
+ has_tsig = 1;
+ qp->q_nstsig = new_tsig(key, sig, siglen); /* BEW? */
+
+ }
+ else {
+ INSIST(0);
+ has_tsig = 0;
+ free_tsig(qp->q_nstsig);
+ qp->q_nstsig = NULL;
+ }
+ }
+ else {
+ has_tsig = 0;
+ free_tsig(qp->q_nstsig);
+ qp->q_nstsig = NULL;
+ }
+
if (sendto(qp->q_dfd, (char*)qp->q_msg, qp->q_msglen, 0,
(struct sockaddr *)nsa,
sizeof(struct sockaddr_in)) < 0) {
+ sendto_errno = errno;
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);
}
+ if (has_tsig == 1) {
+ memput(qp->q_msg, smsgsize);
+ qp->q_msg = oldqbuf;
+ qp->q_msglen = oldqlen;
+ }
+
nameserIncr(nsa->sin_addr, nssSentSysQ);
free_nsp(nsp);
+ switch (sendto_errno) {
+ case ENETDOWN:
+ case ENETUNREACH:
+ case EHOSTDOWN:
+ case EHOSTUNREACH:
+ unsched(qp);
+ schedretry(qp, (time_t) 0);
+ }
return (qp);
}
@@ -2360,7 +2532,7 @@ check_root() {
if (dp->d_type == T_NS)
count++;
ns_debug(ns_log_default, 1, "%d root servers", count);
- if (count < MINROOTS) {
+ if (count < server_options->minroots) {
ns_notice(ns_log_default,
"check_root: %d root servers after query to root server < min",
count);
@@ -2429,12 +2601,12 @@ check_ns() {
"check_ns: %s: not found %s %#lx",
dname, fname, (u_long)tnp);
sysquery(dname, dp->d_class, T_A, NULL,
- 0, QUERY);
+ 0, ns_port, QUERY);
continue;
}
/* look for name server addresses */
found_arr = 0;
- delete_stale(tnp);
+ (void)delete_stale(tnp);
for (tdp = tnp->n_data;
tdp != NULL;
tdp = tdp->d_next) {
@@ -2463,7 +2635,7 @@ check_ns() {
NAME(*np), NAME(*tnp));
else
sysquery(dname, dp->d_class, T_A, NULL,
- 0, QUERY);
+ 0, ns_port, QUERY);
}
}
@@ -2530,7 +2702,7 @@ findns(struct namebuf **npp, int class,
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)) {
+ match(dp, class, T_SOA) && dp->d_type == T_SOA) {
ns_debug(ns_log_default, 3,
"findns: SOA found");
if (zones[dp->d_zone].z_flags & Z_AUTH) {
@@ -2552,7 +2724,7 @@ findns(struct namebuf **npp, int class,
/* If no SOA records, look for NS records. */
nspp = &nsp[0];
*nspp = NULL;
- delete_stale(np);
+ (void)delete_stale(np);
for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
if (!match(dp, class, T_NS))
continue;
@@ -2630,46 +2802,48 @@ finddata(struct namebuf *np, int class, int type,
struct databuf *dp;
char *cp;
int buflen, n, count = 0;
+ char *new_dnamep = NULL;
+ int defer = 0, found_count = 0, choice, i;
+ struct databuf **found = NULL;
+ struct databuf **tmpfound = NULL;
+ int foundcname;
+ int stalecount;
+ int ret = 0;
+
+ stalecount = delete_stale(np);
+
+ /* We don't want to return cached SIG records when asked for SIGs,
+ * since we may have an incomplete set.
+ */
+ if (type == T_SIG && findMyZone(np, class) == DB_Z_CACHE)
+ return(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;
- }
- }
+ if (type != T_ANY && type != T_PTR && type != T_NXT) {
+ found = memget((stalecount + 1) * sizeof *found);
+ tmpfound = memget((stalecount + 1) * sizeof *tmpfound);
+ if (found == NULL || tmpfound == NULL)
+ ns_panic(ns_log_default, 1, "finddata: out of memory");
+ defer = 1;
}
-#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;
+ foundcname = 0;
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;
+ if (dp->d_type != T_NXT &&
+ dp->d_type != T_KEY &&
+ dp->d_type != T_SIG) {
+ ret = 0;
+ goto done;
+ }
}
continue;
}
@@ -2706,8 +2880,8 @@ finddata(struct namebuf *np, int class, int type,
continue;
hp->rcode = NOERROR_NODATA;
if (dp->d_size == 0) { /* !RETURNSOA */
- *countp = 0;
- return 1; /* XXX - we have to report success */
+ ret = 1;
+ goto done;
}
}
if (dp->d_rcode == NXDOMAIN) {
@@ -2722,8 +2896,8 @@ finddata(struct namebuf *np, int class, int type,
}
hp->rcode = NXDOMAIN;
if (dp->d_size == 0) { /* !RETURNSOA */
- *countp = 0;
- return 1; /* XXX - we have to report success */
+ ret = 1;
+ goto done;
}
}
@@ -2733,49 +2907,285 @@ finddata(struct namebuf *np, int class, int type,
(!((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);
- }
+ if (!defer) {
+ if (foundcname != 0 && dp->d_type == T_CNAME)
+ continue;
- 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) {
+ if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1,
+ dnptrs, dnptrs_end, 0)) < 0) {
+ hp->tc = 1;
+ ret = *lenp - buflen;
+ goto done;
+ }
+ if (dp->d_secure != DB_S_SECURE)
+ hp->ad = 0;
+ cp += n;
+ buflen -= n;
+ count++;
+
+ if (dp->d_type == T_CNAME) {
+ foundcname = 1;
+#define FOLLOWCNAME(type) \
+ (type != T_KEY) && (type != T_SIG) && (type != T_NXT) && (type != T_ANY)
/* 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;
+
+ if (FOLLOWCNAME(type))
+ new_dnamep = (char *)dp->d_data;
}
- break;
+ } else {
+ if (dp->d_type == T_CNAME)
+ foundcname = 1;
+ found[found_count++] = dp;
}
}
+
+ if (found_count == 0 && count == 0) {
+ ret = 0;
+ goto done;
+ }
+
/*
- * Cache invalidate the other RR's of same type
- * if some have timed out
+ * If the query type was SIG or ANY we will have returned the SIG
+ * records already.
*/
+ if (type != T_SIG && type != T_ANY) {
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!wantedsig(dp, class, type))
+ 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
+ }
+ if (!defer) {
+ if ((n = make_rr(*dnamep, dp, (u_char *)cp,
+ buflen, 1, dnptrs, dnptrs_end,
+ 0)) < 0) {
+ hp->tc = 1;
+ ret = *lenp - buflen;
+ goto done;
+ }
+ if (dp->d_secure != DB_S_SECURE)
+ hp->ad = 0;
+ cp += n;
+ buflen -= n;
+ count++;
+ } else
+ found[found_count++] = dp;
+ }
+ }
+
+ if (defer && found_count > 0) {
+ int first_sig;
+ int non_sig_count;
+ int sig_count; /* number of SIG records in found */
+ int idx, jdx;
+ enum ordering order;
+
+ order = match_order(np, class, foundcname ? T_CNAME : type);
+
+ /* shuffle the SIG records down to the bottom of the array
+ * as we need to make sure they get packed last, no matter
+ * what the ordering is. We're sure to maintain the
+ * original ordering within the two sets of records (so
+ * that fixed_order can work).
+ * First we pack the non-SIG records into the temp array.
+ */
+ for (idx = jdx = 0 ; idx < found_count ; idx++) {
+ if (found[idx]->d_type != T_SIG) {
+ tmpfound[jdx++] = found[idx];
+ }
+ }
+ non_sig_count = jdx;
+ sig_count = found_count - jdx;
+ first_sig = jdx ;
+
+ /* now shift the SIG records down to the end of the array
+ * and copy in the non-SIG records
+ */
+ for (i = idx = found_count - 1 ; idx >= 0 ; idx--) {
+ if (i < non_sig_count) {
+ found[i] = tmpfound[i];
+ i--;
+ } else if (found[idx]->d_type == T_SIG) {
+ found[i--] = found[idx] ;
+ }
+ }
+
+ foundcname = 0;
+ switch (order) {
+ case fixed_order:
+ for (i = 0; i < found_count; i++) {
+ dp = found[i];
+ if (foundcname != 0 && dp->d_type == T_CNAME)
+ continue;
+ if (dp->d_type == T_CNAME) {
+ foundcname = 1;
+ if (FOLLOWCNAME(type)) {
+ new_dnamep = (char *)dp->d_data;
+ }
+ }
+ if ((n = make_rr(*dnamep, dp, (u_char *)cp,
+ buflen, 1,
+ dnptrs, dnptrs_end, 0)) < 0) {
+ hp->tc = 1;
+ ret = *lenp - buflen;
+ goto done;
+ }
+ if (dp->d_secure != DB_S_SECURE)
+ hp->ad = 0;
+ cp += n;
+ buflen -= n;
+ count++;
+ }
+ break;
+
+ case random_order: {
+ /* first we shuffle the non-SIG records */
+ int iters = non_sig_count;
+ for (i = 0; i < iters; i++) {
+ choice = ((u_int)rand()>>3) % non_sig_count;
+ non_sig_count--;
+ dp = found[choice];
+ found[choice] = found[non_sig_count];
+ if (foundcname != 0 && dp->d_type == T_CNAME)
+ continue;
+ if (dp->d_type == T_CNAME) {
+ foundcname = 1;
+ if (FOLLOWCNAME(type)) {
+ new_dnamep = (char *)dp->d_data;
+ }
+ }
+ if ((n = make_rr(*dnamep, dp, (u_char *)cp,
+ buflen, 1,
+ dnptrs, dnptrs_end, 0)) < 0) {
+ hp->tc = 1;
+ ret = *lenp - buflen;
+ goto done;
+ }
+ if (dp->d_secure != DB_S_SECURE)
+ hp->ad = 0;
+ cp += n;
+ buflen -= n;
+ count++;
+ }
+
+ /* now shuffle the SIG records */
+ iters = sig_count;
+ for (i = 0; i < iters; i++) {
+ choice = ((u_int)rand()>>3) % sig_count;
+ choice += first_sig;
+ sig_count--;
+ dp = found[choice];
+ found[choice] = found[sig_count + first_sig];
+ if ((n = make_rr(*dnamep, dp, (u_char *)cp,
+ buflen, 1,
+ dnptrs, dnptrs_end, 0)) < 0) {
+ hp->tc = 1;
+ ret = *lenp - buflen;
+ goto done;
+ }
+ if (dp->d_secure != DB_S_SECURE)
+ hp->ad = 0;
+ cp += n;
+ buflen -= n;
+ count++;
+ }
+ break;
+ }
+
+ case cyclic_order:
+ /* first we do the non-SIG records */
+ choice = ((u_int)rand()>>3) % non_sig_count;
+ for (i = 0; i < non_sig_count ; i++) {
+ dp = found[(i + choice) % non_sig_count];
+ if (foundcname != 0 && dp->d_type == T_CNAME)
+ continue;
+ if (dp->d_type == T_CNAME) {
+ foundcname = 1;
+ if (FOLLOWCNAME(type)) {
+ new_dnamep = (char *)dp->d_data;
+ }
+ }
+ if ((n = make_rr(*dnamep, dp, (u_char *)cp,
+ buflen, 1,
+ dnptrs, dnptrs_end, 0)) < 0) {
+ hp->tc = 1;
+ ret = *lenp - buflen;
+ goto done;
+ }
+ if (dp->d_secure != DB_S_SECURE)
+ hp->ad = 0;
+ cp += n;
+ buflen -= n;
+ count++;
+ }
+
+ /* now do the SIG record rotation. */
+ if (sig_count > 0) {
+ choice = ((u_int)rand()>>3) % sig_count;
+ choice += first_sig;
+ i = choice;
+ do {
+ dp = found[i];
+ if ((n = make_rr(*dnamep, dp,
+ (u_char *)cp,
+ buflen, 1,
+ dnptrs,
+ dnptrs_end, 0)) < 0) {
+ hp->tc = 1;
+ ret = *lenp - buflen;
+ goto done;
+ }
+ if (dp->d_secure != DB_S_SECURE)
+ hp->ad = 0;
+ cp += n;
+ buflen -= n;
+ count++;
+ i++;
+ if (i >= found_count)
+ i = first_sig;
+ } while (i != choice);
+ }
+
+ break;
+
+ default:
+ ns_warning(ns_log_default, "finddata: unknown ordering: %d",
+ order);
+ break;
+ }
+ }
+
+ if (new_dnamep != NULL)
+ *dnamep = new_dnamep;
+
ns_debug(ns_log_default, 3, "finddata: added %d class %d type %d RRs",
count, class, type);
+ ret = *lenp - buflen;
+ done:
+ if (found != NULL)
+ memput(found, (stalecount + 1) * sizeof *found);
+ if (tmpfound != NULL)
+ memput(tmpfound, (stalecount + 1) * sizeof *tmpfound);
*countp = count;
- return (*lenp - buflen);
+ return (ret);
}
/*
* 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
+static int
wanted(const struct databuf *dp, int class, int type) {
const u_char *cp;
int coveredType;
@@ -2818,7 +3228,7 @@ wanted(const struct databuf *dp, int class, int type) {
cp += INT16SZ + INT32SZ; /* skip alg, labels, & orig TTL */
GETLONG(expiration,cp);
- if (type == T_ANY || type == T_SIG || type == coveredType) {
+ if (type == T_ANY || type == T_SIG) {
if (expiration > time(0))
return (1); /* Unexpired matching SIG */
}
@@ -2833,11 +3243,9 @@ wanted(const struct databuf *dp, int class, int type) {
break;
}
/* OK, now look at the type of query. */
- switch (type) {
- case T_ANY:
+ if (type == ns_t_any)
return (1);
-
- case T_MAILB:
+ else if (type == ns_t_mailb)
switch (dp->d_type) {
case T_MR:
case T_MB:
@@ -2845,14 +3253,57 @@ wanted(const struct databuf *dp, int class, int type) {
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
+ else if (ns_t_xfr_p(type)) {
+ /*
+ * This is used to validate transfer requests, not
+ * generate transfer responses. Is there an SOA?
+ */
+ if (dp->d_type == ns_t_soa && dp->d_zone != DB_Z_CACHE
&& (zones[dp->d_zone].z_flags & Z_AUTH))
return (1);
- break;
+ }
+ return (0);
+}
+
+static int
+wantedsig(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, "wantedtsig(%#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);
+ if (dp->d_type != T_SIG || dp->d_rcode != 0)
+ return (0);
+
+ cp = dp->d_data;
+ GETSHORT(coveredType, cp);
+ cp += INT16SZ + INT32SZ; /* skip alg, labels, & orig TTL */
+ GETLONG(expiration,cp);
+ if (expiration < time(0))
+ return (0);
+
+ if (type == T_ANY || type == T_SIG || type == coveredType)
+ return (1);
+ if (type == ns_t_mailb) {
+ switch (coveredType) {
+ case T_MR:
+ case T_MB:
+ case T_MG:
+ case T_MINFO:
+ return (1);
+ }
}
return (0);
}
@@ -2879,7 +3330,7 @@ add_data(struct namebuf *np, struct databuf **dpp,
if (dp->d_rcode)
continue;
if ((n = make_rr(dname, dp, cp, buflen, 1,
- dnptrs, dnptrs_end)) < 0)
+ dnptrs, dnptrs_end, 0)) < 0)
return (-bytes); /* Truncation */
cp += n;
buflen -= n;
@@ -2895,7 +3346,7 @@ rrsetadd(struct flush_set *flushset, const char *name, struct databuf *dp) {
struct db_list *dbl;
while (fs->fs_name && (
- strcasecmp(fs->fs_name,name) ||
+ ns_samename(fs->fs_name,name) != 1 ||
(fs->fs_class != dp->d_class) ||
(fs->fs_type != dp->d_type) ||
(fs->fs_cred != dp->d_cred))) {
@@ -2989,14 +3440,19 @@ ttlcheck(const char *name, struct db_list *dbl, int update) {
return(1);
}
+/*
+ * lookup rrset in table and compare to dbl
+ * tri state result
+ * -1: lookup failed
+ * 0: rrsets same
+ * 1: rrsets differ
+ */
+
static int
-rrsetcmp(name, dbl)
- char *name;
- struct db_list *dbl;
-{
+rrsetcmp(char * name, struct db_list * dbl, struct hashbuf * table) {
int type = dbl->db_dp->d_type;
int class = dbl->db_dp->d_class;
- struct hashbuf *htp = hashtab;
+ struct hashbuf *htp = table;
const char *fname;
struct namebuf *np;
struct db_list *dbp = dbl;
@@ -3013,8 +3469,9 @@ rrsetcmp(name, dbl)
/* 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 (!match(dp, class, type))
+ continue;
+ exists = 1;
if (!db_cmp(dp, dbp->db_dp)
#ifdef NOADDITIONAL
&& ((dp->d_cred == dbp->db_dp->d_cred) ||
@@ -3056,38 +3513,130 @@ rrsetcmp(name, dbl)
return (0);
}
+/*
+ * verify incoming answer against what we already have in the hints
+ * issue warnings / errors if differences detected.
+ */
+
static void
-rrsetupdate(struct flush_set * flushset, int flags, struct sockaddr_in from) {
+check_hints(struct flush_set * flushset) {
+ struct zoneinfo *zp;
+ struct flush_set *fs;
+ struct db_list *dbp;
+
+ /* We don't use hints when in forward only mode */
+ if (NS_OPTION_P(OPTION_FORWARD_ONLY))
+ return;
+
+ /* find "." NS rrset and hence class */
+ for (fs = flushset; fs->fs_name != NULL; fs++) {
+ if ((fs->fs_name[0] != '\0') || (fs->fs_type != ns_t_ns))
+ continue;
+
+ /* see if we are a root server */
+ zp = find_zone(fs->fs_name, fs->fs_class);
+ if (zp != NULL &&
+ (zp->z_type == z_master || zp->z_type == z_slave))
+ return;
+ switch (rrsetcmp(fs->fs_name, fs->fs_list, fcachetab)) {
+ case -1:
+ ns_error(ns_log_default,
+ "check_hints: no NS records for class %d in hints",
+ fs->fs_class);
+ break;
+ case 1:
+ ns_warning(ns_log_default,
+ "check_hints: root NS list in hints for class %d does not match root NS list",
+ fs->fs_class);
+ break;
+ case 0:
+ break;
+ default:
+ ns_error(ns_log_default,
+ "check_hints: unexpected response from rrsetcmp");
+ break;
+ }
+ break;
+ }
+
+ if (fs->fs_name == NULL) /* no root NS records */
+ return;
+
+ dbp = fs->fs_list;
+ while (dbp) {
+ /* for each NS find A rrset in answer and check */
+ for (fs = flushset; fs->fs_name != NULL; fs++) {
+ if (ns_samename(fs->fs_name, (char *)dbp->db_dp->d_data) != 1
+ || fs->fs_type != ns_t_a)
+ continue;
+ switch (rrsetcmp(fs->fs_name, fs->fs_list, fcachetab)) {
+ case -1:
+ ns_error(ns_log_default,
+ "check_hints: no A records for %s class %d in hints",
+ fs->fs_name[0] ? fs->fs_name : ".",
+ fs->fs_class);
+ break;
+ case 1:
+ ns_warning(ns_log_default,
+ "check_hints: A records for %s class %d do not match hint records",
+ fs->fs_name[0] ? fs->fs_name : ".",
+ fs->fs_class);
+ break;
+ case 0:
+ break;
+ default:
+ ns_error(ns_log_default,
+ "check_hints: unexpected response from rrsetcmp");
+ break;
+ }
+ break;
+ }
+
+ if (fs->fs_name == NULL)
+ ns_debug(ns_log_default, 2,
+ "check_hints: no A records for %s",
+ dbp->db_dp->d_data);
+
+ dbp = dbp->db_next;
+ }
+}
+
+static void
+rrsetupdate(struct flush_set * flushset, int flags, struct sockaddr_in from,
+ int updatettl) {
struct flush_set *fs = flushset;
struct db_list *dbp, *odbp;
int n;
+ void *state = NULL;
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)) &&
+ if ((n = rrsetcmp(fs->fs_name, fs->fs_list, hashtab)) &&
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);
+ n = db_set_update(fs->fs_name, dbp->db_dp,
+ &state, flags,
+ &hashtab, from, NULL,
+ 0, NULL);
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);
}
+ ns_debug(ns_log_default, 3,
+ "rrsetupdate: %s %d",
+ fs->fs_name[0] ? fs->fs_name : ".", n);
} else {
- if (n == 0)
- (void)ttlcheck(fs->fs_name,fs->fs_list, 1);
+ if ((n == 0) && updatettl)
+ (void)ttlcheck(fs->fs_name,fs->fs_list, 1);
dbp = fs->fs_list;
while (dbp) {
db_freedata(dbp->db_dp);
@@ -3099,6 +3648,8 @@ rrsetupdate(struct flush_set * flushset, int flags, struct sockaddr_in from) {
fs->fs_list = NULL;
fs++;
}
+ n = db_set_update(NULL, NULL, &state, flags, &hashtab, from,
+ NULL, 0, NULL);
}
static void
@@ -3161,22 +3712,26 @@ delete_all(struct namebuf *np, int class, int type) {
* arguments:
* np = pointer to namebuf to be cleaned.
* returns:
- * void.
+ * number of RRs associated with this name.
* side effects:
* delete_all() can be called, freeing memory and relinking chains.
*/
-void
+int
delete_stale(np)
struct namebuf *np;
{
struct databuf *dp;
- again:
+ int count;
+ again:
+ count = 0;
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;
}
+ count++;
}
+ return (count);
}
@@ -3256,6 +3811,44 @@ trunc_adjust(u_char *msg, int msglen, int outlen) {
return (cp - msg);
}
+/*
+ * mark the server "from" bad in the qp structure so it won't be retried.
+ */
+static void
+mark_bad(struct qinfo *qp, struct sockaddr_in from) {
+ int i;
+
+ 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;
+}
+
+static void
+mark_lame(struct qinfo *qp, struct sockaddr_in from) {
+ int i;
+
+ 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].ns != NULL) {
+ qp->q_addr[i].ns->d_flags |= DB_F_LAME;
+ db_lame_add(qp->q_domain,
+ (char*)qp->q_addr[i].ns->d_data,
+ tt.tv_sec + server_options->lame_ttl);
+ }
+}
+
+/*
+ * Retry the message if and only if from matches where the query was
+ * last sent to. The code does not handle responses sent from the
+ * wrong interface an a multihomed server.
+ */
+static void
+fast_retry(struct qinfo *qp, struct sockaddr_in from) {
+ if (ina_equal(qp->q_addr[qp->q_curaddr].ns_addr.sin_addr,
+ from.sin_addr))
+ retry(qp);
+}
+
static void
add_related_additional(char *name) {
int i;
@@ -3263,7 +3856,7 @@ add_related_additional(char *name) {
if (num_related >= MAX_RELATED - 1)
return;
for (i = 0; i < num_related; i++)
- if (strcasecmp(name, related[i]) == 0) {
+ if (ns_samename(name, related[i]) == 1) {
freestr(name);
return;
}
@@ -3284,7 +3877,7 @@ related_additional(char *name) {
int i;
for (i = 0; i < num_related; i++)
- if (strcasecmp(name, related[i]) == 0)
+ if (ns_samename(name, related[i]) == 1)
return (1);
return (0);
}
@@ -3296,3 +3889,87 @@ freestr_maybe(char **tname) {
freestr(*tname);
*tname = NULL;
}
+
+/*
+ * Match a request namebuf against the configured rrset-order info. First
+ * match wins. There is an implicit '*.' at the front to the ordering names.
+ */
+static enum ordering
+match_order(const struct namebuf *np, int class, int type) {
+ rrset_order_list orders = server_options->ordering;
+ rrset_order_element roe;
+
+ if (orders == NULL)
+ return (DEFAULT_ORDERING);
+
+ for (roe = orders->first ; roe != NULL ; roe = roe->next) {
+ if (roe->class != C_ANY && roe->class != class)
+ continue;
+ if (roe->type != T_ANY && roe->type != type)
+ continue;
+
+ if (match_name(np, roe->name, strlen(roe->name)) == 0) {
+ return (roe->order);
+ }
+ }
+
+ /* none matched so use default */
+ return (DEFAULT_ORDERING);
+}
+
+/* Do a simple compare of the NP data against the given NAME, recursively
+ * looking at the NP parent if necessary. NAMELEN is the length of the NAME
+ * that needs to be matched. Matching happen from right to left. Returns -1
+ * on failure, on success the index of the first character of the matched
+ * portion of the string is returned. In the first level call a return
+ * value of 0 is of interest.
+ */
+static int
+match_name(const struct namebuf *np, const char *name, size_t namelen)
+{
+ int matched ;
+
+ if (name[0] == '*' && name[1] == '\0')
+ return 0;
+
+ if (np->n_parent != NULL) { /* recurse to end of np list */
+ matched = match_name(np->n_parent,name,namelen);
+ } else {
+ matched = namelen;
+ }
+
+ if (matched > 0) {
+ int labellen = NAMELEN(*np);
+ char pch;
+ const char *start;
+
+ if (labellen > matched) {
+ return -1;
+ } else if (labellen < matched) {
+ /* string is longer than this namebuf's data, so
+ make sure there's a period before the end of the
+ match so we don't just match a suffix. */
+ start = name + (matched - labellen);
+ pch = start[-1];
+ if (pch != '.') {
+ return -1;
+ }
+ } else {
+ start = name ;
+ }
+
+ if (strncasecmp(start, NAME(*np), labellen) == 0) {
+ /* looking good. tell our caller what portion of
+ the tail of string has been matched */
+ if (start == name)
+ return (0) ;
+ else
+ return (start - name - 1); /* matched '.' too */
+ } else {
+ return (-1);
+ }
+ }
+
+ return (matched);
+}
+
diff --git a/contrib/bind/bin/named/ns_signal.c b/contrib/bind/bin/named/ns_signal.c
new file mode 100644
index 0000000..4c7c48a
--- /dev/null
+++ b/contrib/bind/bin/named/ns_signal.c
@@ -0,0 +1,264 @@
+#if !defined(lint) && !defined(SABER)
+static const char sccsid[] = "@(#)ns_main.c 4.55 (Berkeley) 7/1/91";
+static const char rcsid[] = "$Id: ns_signal.c,v 8.11 1999/10/13 16:39:12 vixie 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-1999 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.
+ */
+
+/* Import. */
+
+#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"
+#include "named.h"
+
+/* Forward. */
+
+static SIG_FN onhup(int);
+static SIG_FN onintr(int);
+static SIG_FN setdumpflg(int);
+static SIG_FN setIncrDbgFlg(int);
+static SIG_FN setNoDbgFlg(int);
+static SIG_FN setQrylogFlg(int);
+static SIG_FN setstatsflg(int);
+static SIG_FN discard_pipe(int);
+static SIG_FN setreapflg(int);
+
+/* Data. */
+
+static struct {
+ int sig;
+ SIG_FN (*hand)(int);
+} sighandlers[] = {
+#ifdef DEBUG
+ { SIGUSR1, setIncrDbgFlg },
+ { SIGUSR2, setNoDbgFlg },
+#endif
+#if defined(SIGWINCH) && defined(QRYLOG)
+ { SIGWINCH, setQrylogFlg },
+#endif
+#if defined(SIGXFSZ)
+ { SIGXFSZ, onhup }, /* Wierd DEC Hesiodism, harmless. */
+#endif
+ { SIGINT, setdumpflg },
+ { SIGILL, setstatsflg },
+ { SIGHUP, onhup },
+ { SIGCHLD, setreapflg },
+ { SIGPIPE, discard_pipe },
+ { SIGTERM, onintr }
+};
+
+static sigset_t mask;
+static int blocked = 0;
+
+/* Private. */
+
+static SIG_FN
+onhup(int sig) {
+ ns_need_unsafe(main_need_reload);
+}
+
+static SIG_FN
+onintr(int sig) {
+ ns_need_unsafe(main_need_exit);
+}
+
+static SIG_FN
+setdumpflg(int sig) {
+ ns_need_unsafe(main_need_dump);
+}
+
+#ifdef DEBUG
+static SIG_FN
+setIncrDbgFlg(int sig) {
+ desired_debug++;
+ ns_need_unsafe(main_need_debug);
+}
+
+static SIG_FN
+setNoDbgFlg(int sig) {
+ desired_debug = 0;
+ ns_need_unsafe(main_need_debug);
+}
+#endif /*DEBUG*/
+
+#if defined(QRYLOG) && defined(SIGWINCH)
+static SIG_FN
+setQrylogFlg(int sig) {
+ ns_need_unsafe(main_need_qrylog);
+}
+#endif /*QRYLOG && SIGWINCH*/
+
+static SIG_FN
+setstatsflg(int sig) {
+ ns_need_unsafe(main_need_statsdump);
+}
+
+static SIG_FN
+discard_pipe(int sig) {
+#ifdef SIGPIPE_ONE_SHOT
+ int saved_errno = errno;
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof sa);
+ sa.sa_mask = mask;
+ sa.sa_handler = discard_pipe;
+ if (sigaction(SIGPIPE, &sa, NULL) < 0)
+ ns_error(ns_log_os, "sigaction failed in discard_pipe: %s",
+ strerror(errno));
+ errno = saved_errno;
+#endif
+}
+
+static SIG_FN
+setreapflg(int sig) {
+ ns_need_unsafe(main_need_reap);
+}
+
+/* Public. */
+
+void
+init_signals(void) {
+ int sh;
+
+ /* The mask of all our handlers will block all our other handlers. */
+ (void)sigemptyset(&mask);
+ for (sh = 0; sh < sizeof sighandlers / sizeof sighandlers[0]; sh++)
+ sigaddset(&mask, sighandlers[sh].sig);
+
+ /* Install our signal handlers with that shared mask. */
+ for (sh = 0; sh < sizeof sighandlers / sizeof sighandlers[0]; sh++) {
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof sa);
+ sa.sa_mask = mask;
+ sa.sa_handler = sighandlers[sh].hand;
+ if (sigaction(sighandlers[sh].sig, &sa, NULL) < 0)
+ ns_error(ns_log_os,
+ "sigaction failed in set_signal_handler(%d): %s",
+ sighandlers[sh].sig, strerror(errno));
+ }
+}
+
+void
+block_signals(void) {
+ INSIST(!blocked);
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
+ ns_panic(ns_log_os, 1, "sigblock failed: %s", strerror(errno));
+ blocked = 1;
+}
+
+void
+unblock_signals(void) {
+ INSIST(blocked);
+ if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0)
+ ns_panic(ns_log_os, 1, "sigblock failed: %s", strerror(errno));
+ blocked = 0;
+}
diff --git a/contrib/bind/bin/named/ns_sort.c b/contrib/bind/bin/named/ns_sort.c
new file mode 100644
index 0000000..25c74eb
--- /dev/null
+++ b/contrib/bind/bin/named/ns_sort.c
@@ -0,0 +1,410 @@
+#if !defined(lint) && !defined(SABER)
+static const char sccsid[] = "@(#)ns_sort.c 4.10 (Berkeley) 3/3/91";
+static const char rcsid[] = "$Id: ns_sort.c,v 8.5 1999/10/13 16:39:12 vixie 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-1999 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.
+ */
+
+/*
+ * Sorting should really be handled by the resolver, but:
+ * 1) There are too many brain dead resolvers out there that can't be replaced.
+ * 2) It would be a pain to individually configure all those resolvers anyway.
+ *
+ * Here's the scoop:
+ *
+ * To enable address sorting in responses, you need to supply the sortlist
+ * statement in the config file. The sortlist statement takes an
+ * address match list and interprets it even more specially than the
+ * topology statement does.
+ *
+ * Each top level statement in the sortlist must itself be an explicit
+ * address match list with one or two elements. The first element
+ * (which may be an IP address, an IP prefix, an ACL name or nested
+ * address match list) of each top level list is checked against the
+ * source address of the query until a match is found.
+ *
+ * Once the source address of the query has been matched, if the top level
+ * statement contains only one element, the actual primitive element that
+ * matched the source address is used to select the address in the response
+ * to move to the beginning of the response. If the statement is a list
+ * of two elements, then the second element is treated like the address
+ * match list in a topology statement. Each top level element is assigned
+ * a distance and the address in the response with the minimum distance is
+ * moved to the beginning of the response.
+ *
+ * In the following example, any queries received from any of the addresses
+ * of the host itself will get responses preferring addresses on any of
+ * the locally connected networks. Next most preferred are addresses on
+ * the 192.168.1/24 network, and after that either the 192.168.2/24 or
+ * 192.168.3/24 network with no preference shown between these two networks.
+ * Queries received from a host on the 192.168.1/24 network will prefer
+ * other addresses on that network to the 192.168.2/24 and 192.168.3/24
+ * networks. Queries received from a host on the 192.168.4/24 or the
+ * 192.168.5/24 network will only prefer other addresses on their
+ * directly connected networks.
+ *
+ * sortlist {
+ * {
+ * localhost;
+ * {
+ * localnets;
+ * 192.168.1/24;
+ * { 192,168.2/24; 192.168.3/24; };
+ * };
+ * };
+ * {
+ * 192.168.1/24;
+ * {
+ * 192.168.1/24;
+ * { 192.168.2/24; 192.168.3/24; };
+ * };
+ * };
+ * {
+ * 192.168.2/24;
+ * {
+ * 192.168.2/24;
+ * { 192.168.1/24; 192.168.3/24; };
+ * };
+ * };
+ * {
+ * 192.168.3/24;
+ * {
+ * 192.168.3/24;
+ * { 192.168.1/24; 192.168.2/24; };
+ * };
+ * };
+ * {
+ * { 192.168.4/24; 192.168.5/24; };
+ * };
+ * };
+ *
+ *
+ * The following example will give reasonable behaviour for the local host
+ * and hosts on directly connected networks. It is similar to the behavior
+ * of the address sort in BIND 4.9.x. Responses sent to queries from the
+ * local host will favor any of the directly connected networks. Responses
+ * sent to queries from any other hosts on a directly connected network will
+ * prefer addresses on that same network. Responses to other queries will
+ * not be sorted.
+ *
+ * sortlist {
+ * { localhost; localnets; };
+ * { localnets; };
+ * };
+ *
+ * XXX - it wouldb e nice to have an ACL called "source" that matched the
+ * source address of a query so that a host could be configured to
+ * automatically prefer itself, and an ACL called "sourcenet", that
+ * would return the primitive IP match element that matched the source
+ * address so that you could do:
+ * { localnets; { sourcenet; { other stuff ...}; };
+ * and automatically get similar behaviour to what you get with:
+ * { localnets; };
+ *
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <resolv.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+
+#include "port_after.h"
+
+#include "named.h"
+
+static int sort_rr(u_char *cp, u_char *eom, int ancount, ip_match_list iml);
+
+static int ip_match_address_elt(ip_match_list, struct in_addr,
+ ip_match_element *);
+
+void
+sort_response(u_char *cp, u_char *eom, int ancount, struct sockaddr_in *from) {
+ struct in_addr address;
+ struct ip_match_element imelement;
+ ip_match_element imetl, imematch, imeprimitive;
+ struct ip_match_list imlist;
+ ip_match_list iml;
+ int indirect, matched;
+
+ if (server_options->sortlist == NULL)
+ return;
+
+ if (from->sin_family != AF_INET)
+ return;
+
+ address = from->sin_addr;
+
+ for (imetl = server_options->sortlist->first; imetl != NULL;
+ imetl = imetl->next) {
+ if (imetl->type == ip_match_indirect)
+ imematch = imetl->u.indirect.list->first;
+ else
+ /*
+ * allow a bare pattern as a top level statement
+ * and treat it like {pattern;};
+ */
+ imematch = imetl;
+
+ switch (imematch->type) {
+ case ip_match_pattern:
+ indirect = 0;
+ break;
+ case ip_match_indirect:
+ indirect = 1;
+ break;
+ case ip_match_localhost:
+ imematch->u.indirect.list = local_addresses;
+ indirect = 1;
+ break;
+ case ip_match_localnets:
+ imematch->u.indirect.list = local_networks;
+ indirect = 1;
+ break;
+ default:
+ panic("unexpected ime type in ip_match_address()",
+ NULL);
+ }
+ if (indirect) {
+ imeprimitive = NULL;
+ matched = ip_match_address_elt(imematch->u.indirect.list,
+ address, &imeprimitive);
+ if (matched >= 0) {
+ if (imematch->flags & IP_MATCH_NEGATE)
+ /* Don't sort */
+ return;
+ } else
+ continue;
+ } else {
+ if (ina_onnet(address, imematch->u.direct.address,
+ imematch->u.direct.mask)) {
+ if (imematch->flags & IP_MATCH_NEGATE)
+ /* Don't sort */
+ return;
+ else
+ imeprimitive = imematch;
+ } else
+ continue;
+ }
+ if (imetl != imematch && imematch->next != NULL) {
+ /*
+ * Not a bare pattern at the top level, but a two
+ * element list
+ */
+ switch (imematch->next->type) {
+ case ip_match_pattern:
+ case ip_match_localhost:
+ case ip_match_localnets:
+ imelement = *(imematch->next);
+ imelement.next = NULL;
+ iml = &imlist;
+ iml->first = iml->last = &imelement;
+ break;
+ case ip_match_indirect:
+ iml = imematch->next->u.indirect.list;
+ break;
+ default:
+ panic("unexpected ime type in ip_match_address()",
+ NULL);
+ }
+ } else if (imeprimitive) {
+ imelement = *imeprimitive;
+ imelement.next = NULL;
+ iml = &imlist;
+ iml->first = iml->last = &imelement;
+ } else {
+ /* Don't sort because we'd just use "any" */
+ return;
+ }
+ sort_rr(cp, eom, ancount, iml);
+ break;
+ }
+
+ return;
+}
+
+static int
+sort_rr(u_char *cp, u_char *eom, int ancount, ip_match_list iml) {
+ int type, class, dlen, n, c, distance, closest;
+ struct in_addr inaddr;
+ u_char *rr1 = NULL, *rrbest, *cpstart;
+
+ rr1 = NULL;
+ cpstart = cp;
+ for (c = ancount; c > 0; --c) {
+ n = dn_skipname(cp, eom);
+ if (n < 0)
+ return (1); /* bogus, stop processing */
+ cp += n;
+ if (cp + QFIXEDSZ > eom)
+ return (1);
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ cp += INT32SZ;
+ GETSHORT(dlen, cp);
+ if (dlen > eom - cp)
+ return (1); /* bogus, stop processing */
+ switch (type) {
+ case T_A:
+ switch (class) {
+ case C_IN:
+ case C_HS:
+ memcpy((char *)&inaddr, cp, INADDRSZ);
+ /* Find the address with the minimum distance */
+ if (rr1 == NULL) {
+ rr1 = cp;
+ rrbest = cp;
+ closest = distance_of_address(iml, inaddr);
+ } else {
+ distance = distance_of_address(iml, inaddr);
+ if (distance < closest) {
+ rrbest = cp;
+ closest = distance;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ cp += dlen;
+ }
+ if (rr1 != rrbest && rr1 != NULL) {
+ memcpy((char *)&inaddr, rrbest, INADDRSZ);
+ memcpy(rrbest, rr1, INADDRSZ);
+ memcpy(rr1, (char *)&inaddr, INADDRSZ);
+ }
+ return (0);
+}
+
+/*
+ * Just like ip_match_address(), but also returns a pointer to the primitive
+ * element that matched.
+ */
+
+static int
+ip_match_address_elt(ip_match_list iml, struct in_addr address,
+ ip_match_element *imep) {
+ 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:
+ panic("unexpected ime type in ip_match_address()",
+ NULL);
+ }
+ if (indirect) {
+ ret = ip_match_address_elt(ime->u.indirect.list,
+ address, imep);
+ 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)) {
+ *imep = ime;
+ if (ime->flags & IP_MATCH_NEGATE)
+ return (0);
+ else
+ return (1);
+ }
+ }
+ }
+ return (-1);
+}
diff --git a/contrib/bind/bin/named/ns_stats.c b/contrib/bind/bin/named/ns_stats.c
index 5be0257..44552ed 100644
--- a/contrib/bind/bin/named/ns_stats.c
+++ b/contrib/bind/bin/named/ns_stats.c
@@ -1,6 +1,6 @@
#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 $";
+static const char sccsid[] = "@(#)ns_stats.c 4.10 (Berkeley) 6/27/90";
+static const char rcsid[] = "$Id: ns_stats.c,v 8.27 1999/10/13 16:39:12 vixie Exp $";
#endif /* not lint */
/*
@@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_stats.c,v 8.18 1998/02/13 19:50:24 halley Exp $";
*/
/*
- * Portions Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-1999 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
@@ -77,12 +77,15 @@ static char rcsid[] = "$Id: ns_stats.c,v 8.18 1998/02/13 19:50:24 halley Exp $";
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <errno.h>
+#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -103,39 +106,7 @@ static char rcsid[] = "$Id: ns_stats.c,v 8.18 1998/02/13 19:50:24 halley Exp $";
#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 u_long typestats[T_ANY+1];
static void nameserStats(FILE *);
void
@@ -161,25 +132,39 @@ ns_stats() {
/* 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);
- }
+ for (i = 1; i < T_ANY+1; i++)
+ fprintf(f, "%lu\t%s queries\n", typestats[i], p_type(i));
/* name server statistics */
nameserStats(f);
+ fprintf(f, "--- Statistics Dump --- (%ld) %s",
+ (long)timenow, checked_ctime(&timenow));
+ (void) my_fclose(f);
+
+ /* Now do the memory statistics file */
+ if (!(f = fopen(server_options->memstats_filename, "a"))) {
+ ns_notice(ns_log_statistics, "cannot open memstat file, \"%s\"",
+ server_options->memstats_filename);
+ return;
+ }
+
+ fprintf(f, "+++ Memory 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));
+
fprintf(f, "++ Memory Statistics ++\n");
memstats(f);
fprintf(f, "-- Memory Statistics --\n");
- fprintf(f, "--- Statistics Dump --- (%ld) %s",
+
+ fprintf(f, "--- Memory Statistics Dump --- (%ld) %s",
(long)timenow, checked_ctime(&timenow));
(void) my_fclose(f);
+
ns_notice(ns_log_statistics, "done dumping nameserver stats");
}
@@ -370,11 +355,7 @@ ns_logstats(evContext ctx, void *uap, struct timespec due,
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]);
+ sprintf(buffer2, " %s=%lu", p_type(i), typestats[i]);
if (strlen(buffer) + strlen(buffer2) >
sizeof(buffer) - 1) {
ns_info(ns_log_statistics, buffer);
diff --git a/contrib/bind/bin/named/ns_udp.c b/contrib/bind/bin/named/ns_udp.c
index 8b1af5e..95f0438 100644
--- a/contrib/bind/bin/named/ns_udp.c
+++ b/contrib/bind/bin/named/ns_udp.c
@@ -1,9 +1,9 @@
#if !defined(lint) && !defined(SABER)
-static char rcsid[] = "$Id: ns_udp.c,v 8.5 1997/05/21 19:52:26 halley Exp $";
+static const char rcsid[] = "$Id: ns_udp.c,v 8.8 1999/10/13 16:39:13 vixie Exp $";
#endif /* not lint */
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-1999 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
@@ -26,6 +26,7 @@ static char rcsid[] = "$Id: ns_udp.c,v 8.5 1997/05/21 19:52:26 halley Exp $";
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/file.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
diff --git a/contrib/bind/bin/named/ns_update.c b/contrib/bind/bin/named/ns_update.c
index 48db076..4f9817f 100644
--- a/contrib/bind/bin/named/ns_update.c
+++ b/contrib/bind/bin/named/ns_update.c
@@ -1,9 +1,9 @@
#if !defined(lint) && !defined(SABER)
-static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $";
+static const char rcsid[] = "$Id: ns_update.c,v 8.68 1999/11/05 04:40:58 vixie Exp $";
#endif /* not lint */
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-1999 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
@@ -20,6 +20,26 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $"
*/
/*
+ * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc.
+ *
+ * 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 Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES
+ * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED
+ * 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>
*/
@@ -31,6 +51,7 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $"
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -40,6 +61,7 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $"
#include <fcntl.h>
#include <limits.h>
#include <resolv.h>
+#include <res_update.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -52,10 +74,14 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $"
#include <isc/logging.h>
#include <isc/memcluster.h>
+#include <isc/dst.h>
+
#include "port_after.h"
#include "named.h"
+static ns_updque curupd;
+
#define WRITEABLE_MASK (S_IWUSR | S_IWGRP | S_IWOTH)
/* XXXRTH almost all funcs. in here should be static!
@@ -106,14 +132,8 @@ static struct map m_section[] = {
};
#define M_SECTION_CNT (sizeof(m_section) / sizeof(struct map))
+/* Forward. */
-/* 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);
@@ -134,6 +154,21 @@ open_transaction_log(struct zoneinfo *zp) {
return (fp);
}
+static FILE *
+open_ixfr_log(struct zoneinfo *zp) {
+ FILE *fp;
+
+ fp = fopen(zp->z_ixfr_base, "a+");
+ if (fp == NULL) {
+ ns_error(ns_log_update, "can't open %s: %s", zp->z_ixfr_base,
+ strerror(errno));
+ return (NULL);
+ }
+ if (ftell(fp) == 0L) {
+ fprintf(fp, "%s", LogSignature);
+ }
+ return (fp);
+}
static int
close_transaction_log(struct zoneinfo *zp, FILE *fp) {
@@ -155,13 +190,69 @@ close_transaction_log(struct zoneinfo *zp, FILE *fp) {
return (0);
}
+static int
+close_ixfr_log(struct zoneinfo *zp, FILE *fp) {
+ if (fflush(fp) == EOF) {
+ ns_error(ns_log_update, "fflush() of %s failed: %s",
+ zp->z_ixfr_base, strerror(errno));
+ fclose(fp);
+ return (-1);
+ }
+ if (fsync(fileno(fp)) < 0) {
+ ns_error(ns_log_update, "fsync() of %s failed: %s",
+ zp->z_ixfr_base, strerror(errno));
+ fclose(fp);
+ return (-1);
+ }
+ if (fclose(fp) == EOF) {
+ ns_error(ns_log_update, "fclose() of %s failed: %s",
+ zp->z_ixfr_base, strerror(errno));
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * return true if 'db' had been added.
+ */
+static int
+was_added(const ns_updque *updlist, struct databuf *dp) {
+ ns_updrec *rrecp;
+
+ for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link))
+ if (rrecp->r_section == S_UPDATE && rrecp->r_dp == dp)
+ return (1);
+ return (0);
+}
+
+/*
+ * return true if 'db' had been deleted.
+ */
+static int
+was_deleted(const ns_updque *updlist, struct databuf *dp) {
+ ns_updrec *rrecp;
+ struct databuf *adp;
+
+
+ for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link))
+ if (rrecp->r_section == S_UPDATE &&
+ rrecp->r_deldp != NULL) {
+ adp = rrecp->r_deldp;
+ do {
+ if (adp == dp)
+ return (1);
+ } while ((adp = adp->d_next) != NULL);
+ }
+ return (0);
+}
+
/*
- * printupdatelog(srcaddr, firstp, hp, zp, old_serial)
+ * printupdatelog(srcaddr, updlist, 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,
+ const ns_updque *updlist,
HEADER *hp,
struct zoneinfo *zp,
u_int32_t old_serial)
@@ -171,25 +262,35 @@ printupdatelog(struct sockaddr_in srcaddr,
ns_updrec *rrecp;
int opcode;
char time[25];
- FILE *fp;
+ FILE *fp, *ifp;
- if (!firstp)
+ if (EMPTY(*updlist))
return;
fp = open_transaction_log(zp);
if (fp == NULL)
return;
+ ifp = open_ixfr_log(zp);
+ if (ifp == NULL) {
+ (void) close_transaction_log(zp, fp);
+ 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) {
+ ntohs(hp->id), sin_ntoa(srcaddr), time, (long)getpid());
+ fprintf(ifp, "[DYNAMIC_UPDATE] id %u from %s %s (named pid %ld):\n",
+ ntohs(hp->id), sin_ntoa(srcaddr), time, (long)getpid());
+ for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) {
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);
+ fprintf(ifp, "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;
@@ -207,6 +308,45 @@ printupdatelog(struct sockaddr_in srcaddr,
break;
case S_UPDATE:
opcode = rrecp->r_opcode;
+ /*
+ * Translate all deletes into explict actions by
+ * looking at what was actually deleted from the
+ * zone for the ixfr log.
+ */
+ dp = rrecp->r_deldp;
+ while (dp != NULL) {
+ if (dp->d_rcode == 0 &&
+ !was_added(updlist, dp)) {
+ fprintf(ifp,
+ "update:\t{%s} %s. %u %s %s ",
+ "delete",
+ rrecp->r_dname,
+ dp->d_ttl,
+ p_class(dp->d_class),
+ p_type(dp->d_type));
+ (void) rdata_dump(dp, ifp);
+ fprintf(ifp, "\n");
+ }
+ dp = dp->d_next;
+ }
+ /*
+ * Only successful adds should be recorded.
+ * Don't add changes that are undone later.
+ * SOA additions performed later.
+ */
+ if (opcode == ADD && (dp = rrecp->r_dp) != NULL &&
+ dp->d_type != T_SOA &&
+ (dp->d_mark & D_MARK_ADDED) != 0 &&
+ !was_deleted(updlist, dp)) {
+ fprintf(ifp, "update:\t{%s} %s. ",
+ opcodes[opcode], rrecp->r_dname);
+ fprintf(ifp, "%u ", rrecp->r_ttl);
+ fprintf(ifp, "%s ", p_class(zp->z_class));
+ fprintf(ifp, "%s ", p_type(rrecp->r_type));
+ (void) rdata_dump(dp, ifp);
+ fprintf(ifp, "\n");
+ }
+ /* Update log. */
fprintf(fp, "update:\t{%s} %s. ",
opcodes[opcode], rrecp->r_dname);
if (opcode == ADD)
@@ -228,8 +368,37 @@ printupdatelog(struct sockaddr_in srcaddr,
/*NOTREACHED*/
}
}
+ /*
+ * SOA additions must be last in this update as they
+ * (or [INCR_SERIAL]) terminate an IXFR chunk. Only the last SOA
+ * addition will be emitted for any dynamic update regardless
+ * of the number of SOA changes in the update.
+ */
+ for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) {
+ INSIST(zp == &zones[rrecp->r_zone]);
+ switch (rrecp->r_section) {
+ case S_UPDATE:
+ opcode = rrecp->r_opcode;
+ if (opcode == ADD && (dp = rrecp->r_dp) != NULL &&
+ dp->d_type == T_SOA &&
+ (dp->d_mark & D_MARK_ADDED) != 0 &&
+ !was_deleted(updlist, dp)) {
+ fprintf(ifp, "update:\t{%s} %s. ",
+ opcodes[opcode], rrecp->r_dname);
+ fprintf(ifp, "%u ", rrecp->r_ttl);
+ fprintf(ifp, "%s ", p_class(zp->z_class));
+ fprintf(ifp, "%s ", p_type(rrecp->r_type));
+ (void) rdata_dump(dp, ifp);
+ fprintf(ifp, "\n[END_DELTA]\n");
+ }
+ break;
+ default:
+ break;
+ }
+ }
fprintf(fp, "\n");
(void) close_transaction_log(zp, fp);
+ (void) close_ixfr_log(zp, ifp);
}
static void
@@ -379,8 +548,15 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) {
}
htp = hashtab;
np = nlookup(dname, &htp, &fname, 0);
- if (fname != dname)
- np = NULL; /* Matching by wildcard not allowed here. */
+ /*
+ * Matching by wildcard not allowed here.
+ * We need to post check for a wildcard match.
+ */
+ if (fname != dname ||
+ (np != NULL && ns_wildcard(NAME(*np)) &&
+ (dname[0] != '*' || (dname[1] != '.' && dname[1] != '\0'))))
+ np = NULL;
+
if (class == C_ANY) {
if (rdp->d_size) {
ns_debug(ns_log_update, 1,
@@ -411,7 +587,8 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) {
for (dp = np->n_data;
dp && !found;
dp = dp->d_next)
- if (match(dp, class, type))
+ if (match(dp, class, type) &&
+ dp->d_type == type)
found = 1;
if (!found) {
ns_debug(ns_log_update, 1,
@@ -485,12 +662,12 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) {
return (0);
}
for (dp = np->n_data; dp; dp = dp->d_next) {
- if (match(dp, class, type)) {
+ if (match(dp, class, type) && dp->d_type == type) {
int found = 0;
for (tmp = ur;
- tmp && !found;
- tmp = tmp->r_next) {
+ tmp != NULL && !found;
+ tmp = NEXT(tmp, r_link)) {
if (tmp->r_section != S_PREREQ)
break;
if (!db_cmp(dp, tmp->r_dp)) {
@@ -505,9 +682,9 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) {
}
}
}
- for (tmp = ur; tmp; tmp = tmp->r_next)
+ for (tmp = ur; tmp != NULL; tmp = NEXT(tmp, r_link))
if (tmp->r_section == S_PREREQ &&
- !strcasecmp(dname, tmp->r_dname) &&
+ ns_samename(dname, tmp->r_dname) == 1 &&
tmp->r_class == class &&
tmp->r_type == type &&
(ur->r_dp->d_mark & D_MARK_FOUND) == 0) {
@@ -527,6 +704,153 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) {
return (1);
}
+static int
+prescan_nameok(ns_updrec *ur, int *rcodep, u_int16_t zclass,
+ struct zoneinfo *zp) {
+ const char *dname = ur->r_dname;
+ const char *owner = ur->r_dname;
+ u_int16_t class = ur->r_class;
+ u_int16_t type = ur->r_type;
+ char *cp = (char *)ur->r_dp->d_data;
+ enum context context;
+
+ int ret = 1;
+
+ /* We don't care about deletes */
+ if (ur->r_class != zclass)
+ return (1);
+
+ context = ns_ownercontext(type, primary_trans);
+ if (!ns_nameok(NULL, owner, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+
+ switch (type) {
+ case ns_t_soa:
+ context = hostname_ctx;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ cp += strlen(cp) + 1;
+ context = mailname_ctx;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ break;
+ case ns_t_rp:
+ context = mailname_ctx;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ cp += strlen(cp) + 1;
+ context = domain_ctx;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ break;
+ case ns_t_minfo:
+ context = mailname_ctx;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ cp += strlen(cp) + 1;
+ context = mailname_ctx;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ break;
+ case ns_t_ns:
+ context = hostname_ctx;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ break;
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ context = domain_ctx;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ break;
+ case ns_t_ptr:
+ context = ns_ptrcontext(owner);
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ break;
+ case ns_t_naptr:
+ /*
+ * Order (2)
+ * Preference (2)
+ * Flags (1)
+ */
+ cp += 5;
+ /* Service (txt) */
+ cp += strlen(cp) + 1;
+ /* Pattern (txt) */
+ cp += strlen(cp) + 1;
+ context = domain_ctx;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ break;
+ case ns_t_srv:
+ cp += 4;
+ /* FALLTHROUGH */
+ case ns_t_mx:
+ case ns_t_afsdb:
+ case ns_t_rt:
+ case ns_t_kx:
+ cp += 2;
+ context = hostname_ctx;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ break;
+ case ns_t_px:
+ cp += 2;
+ context = domain_ctx;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ cp += strlen(cp) + 1;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ break;
+ case ns_t_sig:
+ /*
+ * Type covered (2)
+ * Alg (1) *
+ * Labels (1)
+ * ttl (4)
+ * expires (4)
+ * signed (4)
+ * footprint (2)
+ */
+ cp += 18;
+ context = domain_ctx;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ break;
+ case ns_t_nxt:
+ context = domain_ctx;
+ if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner,
+ inaddr_any))
+ goto refused;
+ break;
+ default:
+ break;
+ }
+ return (1);
+ refused:
+ *rcodep = REFUSED;
+ return (0);
+}
+
/*
* int
* prescan_update(ur, rcodep)
@@ -549,9 +873,7 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) {
struct namebuf *np;
if (class == zclass) {
- if (type == T_ANY ||
- type == T_AXFR || type == T_IXFR ||
- type == T_MAILA || type == T_MAILB) {
+ if (!ns_t_rr_p(type)) {
ns_debug(ns_log_update, 1,
"prescan_update: invalid type (%s)",
p_type(type));
@@ -560,19 +882,18 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) {
}
} else if (class == C_ANY) {
if (ttl != 0 || rdp->d_size ||
- type == T_AXFR || type == T_IXFR ||
- type == T_MAILA || type == T_MAILB) {
+ (!ns_t_rr_p(type) && type != T_ANY))
+ {
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) {
+ if (ttl != 0 || !ns_t_rr_p(type)) {
ns_debug(ns_log_update, 1,
- "prescan_update: formerr(#3)");
+ "prescan_update: formerr(#3) %d %s",
+ ttl, p_type(type));
*rcodep = FORMERR;
return (0);
}
@@ -589,7 +910,7 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) {
/*
* int
- * process_updates(firstp, rcodep, from)
+ * process_updates(updlist, rcodep, from)
* Process prerequisites and apply updates from the list to the database.
* returns:
* number of successful updates, 0 if none were successful.
@@ -598,7 +919,9 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) {
* can schedule maintainance for zone dumps and soa.serial# increments.
*/
static int
-process_updates(ns_updrec *firstp, int *rcodep, struct sockaddr_in from) {
+process_updates(const ns_updque *updlist, int *rcodep,
+ struct sockaddr_in from)
+{
int i, j, n, dbflags, matches, zonenum;
int numupdated = 0, soaupdated = 0, schedmaint = 0;
u_int16_t zclass;
@@ -609,11 +932,12 @@ process_updates(ns_updrec *firstp, int *rcodep, struct sockaddr_in from) {
int zonelist[MAXDNAME];
*rcodep = SERVFAIL;
- if (!firstp)
+ if (EMPTY(*updlist))
return (0);
- if (firstp->r_section == S_ZONE) {
- zclass = firstp->r_class;
- zonenum = firstp->r_zone;
+ ur = HEAD(*updlist);
+ if (ur->r_section == S_ZONE) {
+ zclass = ur->r_class;
+ zonenum = ur->r_zone;
zp = &zones[zonenum];
} else {
ns_debug(ns_log_update, 1,
@@ -622,7 +946,7 @@ process_updates(ns_updrec *firstp, int *rcodep, struct sockaddr_in from) {
}
/* Process prereq records and prescan update records. */
- for (ur = firstp; ur != NULL; ur = ur->r_next) {
+ for (ur = HEAD(*updlist); ur != NULL; ur = NEXT(ur, r_link)) {
const char * dname = ur->r_dname;
u_int16_t class = ur->r_class;
u_int16_t type = ur->r_type;
@@ -642,7 +966,9 @@ class=%s, type=%s, ttl=%d, dp=0x%0x",
for (j = 0; j < matches && !ur->r_zone; j++)
if (zonelist[j] == zonenum)
ur->r_zone = zonelist[j];
- if (!ur->r_zone) {
+ if (!ur->r_zone ||
+ (section != S_ADDT && type == T_SOA &&
+ ns_samename(dname, zp->z_origin) != 1)) {
ns_debug(ns_log_update, 1,
"process_updates: record does not belong to the zone %s",
zones[zonenum].z_origin);
@@ -661,6 +987,8 @@ class=%s, type=%s, ttl=%d, dp=0x%0x",
case S_UPDATE:
if (!prescan_update(ur, rcodep, zclass))
return (0); /* *rcodep has been set. */
+ if (!prescan_nameok(ur, rcodep, zclass, zp))
+ return (0); /* *rcodep has been set. */
ns_debug(ns_log_update, 3, "update prescan succeeded");
break;
case S_ADDT:
@@ -673,7 +1001,7 @@ class=%s, type=%s, ttl=%d, dp=0x%0x",
}
/* Now process the records in update section. */
- for (ur = firstp; ur != NULL; ur = ur->r_next) {
+ for (ur = HEAD(*updlist); ur != NULL; ur = NEXT(ur, r_link)) {
const char * dname = ur->r_dname;
u_int16_t class = ur->r_class;
@@ -689,10 +1017,11 @@ class=%s, type=%s, ttl=%d, dp=0x%0x",
* is done in db_update().
*/
ur->r_opcode = ADD;
- dbflags |= DB_NODATA;
+ dbflags |= DB_NODATA | DB_REPLACE;
n = db_update(dname, dp, dp, &savedp,
dbflags, hashtab, from);
- if (n != OK) {
+ if (!((n == OK) ||
+ ((zp->z_xferpid == XFER_ISIXFR) && (n == DATAEXISTS)))) {
ns_debug(ns_log_update, 3,
"process_updates: failed to add databuf (%d)",
n);
@@ -723,10 +1052,11 @@ class=%s, type=%s, ttl=%d, dp=0x%0x",
dbflags |= DB_DELETE;
n = db_update(dname, dp, NULL, &savedp,
dbflags, hashtab, from);
- if (n != OK)
+ if (!((n == OK) ||
+ ((zp->z_xferpid == XFER_ISIXFR) && (n == NODATA)))) {
ns_debug(ns_log_update, 3,
"process_updates: delete failed");
- else {
+ } else {
ns_debug(ns_log_update, 3,
"process_updates: delete succeeded");
numupdated++;
@@ -771,7 +1101,7 @@ class=%s, type=%s, ttl=%d, dp=0x%0x",
schedmaint = 1;
#ifdef BIND_NOTIFY
if (!loading)
- sysnotify(zp->z_origin, zp->z_class, T_SOA);
+ ns_notify(zp->z_origin, zp->z_class, ns_t_soa);
#endif
} else {
if (schedule_soa_update(zp, numupdated))
@@ -784,7 +1114,8 @@ class=%s, type=%s, ttl=%d, dp=0x%0x",
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)
+ struct qstream *qsp, int dfd, struct sockaddr_in from,
+ struct tsig_record *in_tsig)
{
char dnbuf[MAXDNAME], *dname;
u_int zocount, prcount, upcount, adcount, class, type, dlen;
@@ -801,6 +1132,9 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg,
int zonelist[MAXDNAME];
int should_use_tcp;
u_int32_t old_serial;
+ int unapproved_ip = 0;
+ int tsig_len;
+ DST_KEY *in_key = (in_tsig != NULL) ? in_tsig->key : NULL;
nsp[0] = NULL;
@@ -854,7 +1188,7 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg,
* Begin Access Control Point
*/
- if (!ip_address_allowed(zp->z_update_acl, from.sin_addr)) {
+ if (!ip_addr_or_key_allowed(zp->z_update_acl, from.sin_addr, in_key)) {
ns_notice(ns_log_security, "unapproved update from %s for %s",
sin_ntoa(from), *dname ? dname : ".");
return (Refuse);
@@ -864,8 +1198,6 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg,
* 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,
@@ -877,11 +1209,12 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg,
if (zp->z_type == Z_SECONDARY) {
/*
- * XXX the code below is broken. Until fixed, we just
- * refuse.
+ * XXX The code below is broken.
+ * Until fixed, we just refuse.
*/
+#if 1
return (Refuse);
-
+#else
/* 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,
@@ -892,8 +1225,15 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg,
* If the request came in over TCP, forward it over TCP
*/
should_use_tcp = (qsp != NULL);
+ if (in_tsig != NULL) {
+ tsig_len = ns_skiprr(eom, eom + TSIG_BUF_SIZE,
+ ns_s_ar, 1);
+ eom += tsig_len;
+ }
n = ns_forw(nsp, msg, eom-msg, from, qsp, dfd, &qp,
- dname, class, type, NULL, should_use_tcp);
+ dname, class, type, NULL, should_use_tcp, NULL);
+ if (in_tsig != NULL)
+ eom -= tsig_len;
free_nsp(nsp);
switch (n) {
case FW_OK:
@@ -905,6 +1245,7 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg,
hp->rcode = SERVFAIL;
return (Finish);
}
+#endif
}
/*
* We are the primary master server for this zone,
@@ -920,11 +1261,10 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg,
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;
+ rrecp = res_mkupdrec(S_ZONE, dname, class, type, 0);
+ rrecp->r_zone = zonenum;
+
+ APPEND(curupd, rrecp, r_link);
/*
* Parse the prerequisite and update sections for format errors.
@@ -946,6 +1286,12 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg,
}
GETSHORT(type, cp);
GETSHORT(class, cp);
+ if (class > CLASS_MAX) {
+ ns_debug(ns_log_update, 1,
+ "req_update: bad class");
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
GETLONG(ttl, cp);
GETSHORT(dlen, cp);
n = 0;
@@ -972,14 +1318,12 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg,
dp = savedata(class, type, ttl, rdata, n);
dp->d_zone = zonenum;
dp->d_cred = DB_C_ZONE;
+ dp->d_secure = DB_S_INSECURE; /* should be UNCHECKED */
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;
+ APPEND(curupd, rrecp, r_link);
if (cp > eom) {
ns_info(ns_log_update,
"Malformed response from %s (overrun)",
@@ -990,44 +1334,47 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg,
}
/* Now process all parsed records in the prereq and update sections. */
- numupdated = process_updates(rrecp_start, &rcode, from);
+ numupdated = process_updates(&curupd, &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));
+ if (rcode != NOERROR)
+ ns_error(ns_log_update,
+ "error processing update packet (%s) id %d from %s",
+ p_rcode(rcode), ntohs(hp->id), sin_ntoa(from));
return (Finish);
}
+ /*
+ * Stop any outbound zone transfers.
+ * (Eventlib is synchronous for this.)
+ */
+ ns_stopxfrs(zp);
+
/* Make a log of the update. */
- (void) printupdatelog(from, rrecp_start, hp, zp, old_serial);
+ (void) printupdatelog(from, &curupd, hp, zp, old_serial);
return (Finish);
}
-static void
-free_rrecp(ns_updrec **startpp, ns_updrec **lastpp, int rcode,
- struct sockaddr_in from)
-{
+void
+free_rrecp(ns_updque *updlist, 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;
+ first_rrecp = HEAD(*updlist);
msg = "free_rrecp: update transaction succeeded, cleaning up";
} else {
- first_rrecp = *lastpp;
+ first_rrecp = TAIL(*updlist);
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;
+ next_rrecp = NEXT(rrecp, r_link);
else
- next_rrecp = rrecp->r_prev;
+ next_rrecp = PREV(rrecp, r_link);
if (rrecp->r_section != S_UPDATE) {
if (rrecp->r_dp)
db_freedata(rrecp->r_dp);
@@ -1096,7 +1443,7 @@ free_rrecp(ns_updrec **startpp, ns_updrec **lastpp, int rcode,
/* Add the databuf back. */
tmpdp->d_mark &= ~D_MARK_DELETED;
if (db_update(dname, tmpdp, tmpdp, NULL,
- 0, hashtab, from) != OK) {
+ DB_REPLACE, 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));
@@ -1109,18 +1456,19 @@ free_rrecp(ns_updrec **startpp, ns_updrec **lastpp, int rcode,
}
res_freeupdrec(rrecp);
}
- *startpp = NULL;
- *lastpp = NULL;
+ INIT_LIST(*updlist);
}
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)
+ struct qstream *qsp, int dfd, struct sockaddr_in from,
+ struct tsig_record *in_tsig)
{
enum req_action ret;
- ret = req_update_private(hp, cp, eom, msg, qsp, dfd, from);
- free_rrecp(&rrecp_start, &rrecp_last, hp->rcode, from);
+ INIT_LIST(curupd);
+ ret = req_update_private(hp, cp, eom, msg, qsp, dfd, from, in_tsig);
+ free_rrecp(&curupd, ret == Refuse ? ns_r_refused : hp->rcode, from);
if (ret == Finish) {
hp->qdcount = hp->ancount = hp->nscount = hp->arcount = 0;
memset(msg + HFIXEDSZ, 0, (eom - msg) - HFIXEDSZ);
@@ -1139,11 +1487,13 @@ rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp,
{
const u_char *cpinit = cp;
const u_char *cp1init = cp1;
- int n, i;
+ int n, i, n1;
switch (type) {
case T_A:
- if (dlen != INT32SZ)
+ case T_AAAA:
+ if ((type == T_A && dlen != INT32SZ) ||
+ (type == T_AAAA && dlen != NS_IN6ADDRSZ))
return (0);
/*FALLTHROUGH*/
case T_WKS:
@@ -1153,6 +1503,8 @@ rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp,
case T_ISDN:
case T_NSAP:
case T_LOC:
+ case T_KEY:
+ case ns_t_cert:
if (size < dlen)
return (0);
memcpy(cp1, cp, dlen);
@@ -1249,6 +1601,56 @@ rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp,
if (cp != cpinit + dlen)
return (0);
return (cp1 - cp1init);
+ case T_SIG:
+ if (dlen < SIG_HDR_SIZE || size < dlen)
+ return (0);
+ memcpy(cp1, cp, SIG_HDR_SIZE);
+ size -= SIG_HDR_SIZE;
+ cp += SIG_HDR_SIZE;
+ cp1 += SIG_HDR_SIZE;
+ n = dn_expand(msg, eom, cp, (char *)cp1, size);
+ if (n < 0 || n + SIG_HDR_SIZE > dlen)
+ return (0);
+ cp += n;
+ n1 = dlen - n - SIG_HDR_SIZE;
+ n = strlen((char *)cp1) + 1;
+ cp1 += n;
+ if (size < n1)
+ return (0);
+ memcpy(cp1, cp, n1);
+ cp1 += n1;
+ return (cp1 - cp1init);
+ case T_NXT:
+ n = dn_expand(msg, eom, cp, (char *)cp1, size);
+ if (n < 0 || (u_int)n >= dlen)
+ return (0);
+ size -= n;
+ cp += n;
+ n1 = dlen - n;
+ n = strlen((char *)cp1) + 1;
+ cp1 += n;
+ /*
+ * The first bit of the first octet determines the format
+ * of the NXT record. A format for types >= 128 has not
+ * yet been defined, so if bit zero is set, we just copy
+ * what's there because we don't understand it.
+ */
+ if ((*cp & 0x80) == 0) {
+ /*
+ * Bit zero is not set; this is an ordinary NXT
+ * record. The bitmap must be at least 4 octets
+ * because the NXT bit should be set. It should be
+ * less than or equal to 16 octets because this NXT
+ * format is only defined for types < 128.
+ */
+ if (n1 < 4 || n1 > 16)
+ return (0);
+ }
+ if (n1 > size)
+ return (0);
+ memcpy(cp1, cp, n1);
+ cp1 += n1;
+ return (cp1 - cp1init);
default:
ns_debug(ns_log_update, 3, "unknown type %d", type);
return (0);
@@ -1267,6 +1669,10 @@ rdata_dump(struct databuf *dp, FILE *fp) {
u_char *cp, *end;
int i, j;
const char *proto;
+ u_char *savecp;
+ char temp_base64[NS_MD5RSA_MAX_BASE64];
+ u_int16_t keyflags;
+ u_char *sigdata, *certdata;
cp = (u_char *)dp->d_data;
switch (dp->d_type) {
@@ -1339,6 +1745,15 @@ rdata_dump(struct databuf *dp, FILE *fp) {
fprintf(fp, "%u", n);
fprintf(fp, " %s.", cp);
break;
+ case T_SRV:
+ GETSHORT(n, cp); /* priority */
+ fprintf(fp, "%u ", n);
+ GETSHORT(n, cp); /* weight */
+ fprintf(fp, "%u ", n);
+ GETSHORT(n, cp); /* port */
+ fprintf(fp, "%u ", n);
+ fprintf(fp, " %s.", cp);
+ break;
case T_PX:
GETSHORT(n, cp);
fprintf(fp, "%u", n);
@@ -1353,12 +1768,16 @@ rdata_dump(struct databuf *dp, FILE *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);
+ if ((*cp < ' ') || (*cp > '~')) {
+ fprintf(fp, "\\%03.3d", *cp++);
+ } else if (*cp == '\\' || *cp =='"') {
+ putc('\\', fp);
+ putc(*cp++, fp);
} else
(void) putc(*cp++, fp);
}
+ if (cp != end)
+ fputs("\" \"", fp);
}
/* XXXVIX need to keep the segmentation (see 4.9.5). */
(void) fputs("\"", fp);
@@ -1393,6 +1812,91 @@ rdata_dump(struct databuf *dp, FILE *fp) {
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) */
+ /* XXXX 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;
+ case ns_t_cert:
+ certdata = cp;
+ NS_GET16(n,cp);
+ fprintf(fp, "%d ", n); /* cert type */
+
+ NS_GET16(n,cp);
+ fprintf(fp, "%d %d ", n, *cp++); /* tag & alg */
+
+ /* Certificate (base64 of any length) */
+ i = b64_ntop(cp, dp->d_size - (cp - certdata),
+ temp_base64, sizeof(temp_base64));
+ if (i < 0)
+ fprintf(fp, "; BAD BASE64");
+ else
+ fprintf(fp, "%s", temp_base64);
+ break;
+ case ns_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;
+ }
default:
fprintf(fp, "\t;?d_type=%d?", dp->d_type);
}
@@ -1404,7 +1908,7 @@ rdata_dump(struct databuf *dp, FILE *fp) {
* authoritative zone numbers will be stored in "zonelist", ordered
* deepest match first.
*/
-static int
+int
findzone(const char *dname, int class, int depth, int *zonelist, int maxzones){
char *tmpdname;
char tmpdnamebuf[MAXDNAME];
@@ -1428,7 +1932,7 @@ zonelist=0x%x, maxzones=%d)",
tmpdname = tmpdnamebuf;
/*
* The code to handle trailing dots and escapes is adapted
- * from samedomain().
+ * from ns_samedomain().
*/
tmpdnamelen = strlen(tmpdname);
/*
@@ -1538,7 +2042,7 @@ zonelist=0x%x, maxzones=%d)",
* returns -1 on error, 0 on success, 1 if dump reload needed
*/
int
-merge_logs(struct zoneinfo *zp) {
+merge_logs(struct zoneinfo *zp, char *logname) {
char origin[MAXDNAME], data[MAXDATA], dnbuf[MAXDNAME], sclass[3];
char buf[BUFSIZ], buf2[100];
FILE *fp;
@@ -1558,6 +2062,7 @@ merge_logs(struct zoneinfo *zp) {
u_char *serialp;
struct sockaddr_in empty_from;
int datasize;
+ unsigned long l;
empty_from.sin_family = AF_INET;
empty_from.sin_addr.s_addr = htonl(INADDR_ANY);
@@ -1568,64 +2073,67 @@ merge_logs(struct zoneinfo *zp) {
* getword() is used here just to be consistent with db_load()
*/
+ ns_debug(ns_log_update, 3, "merge_logs(%s)", logname);
+
/* If there is no log file, just return. */
- if (stat(zp->z_updatelog, &st) < 0) {
+ if (stat(logname, &st) < 0) {
if (errno != ENOENT)
ns_error(ns_log_update,
"unexpected stat(%s) failure: %s",
- zp->z_updatelog, strerror(errno));
+ logname, strerror(errno));
return (-1);
}
- fp = fopen(zp->z_updatelog, "r");
+ fp = fopen(logname, "r");
if (fp == NULL) {
ns_error(ns_log_update, "fopen(%s) failed: %s",
- zp->z_updatelog, strerror(errno));
+ logname, 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
+ * that was in the process of being movefiled, 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));
+ logname, strerror(errno));
fclose(fp);
return (-1);
}
if (strcmp(buf, DumpSignature) == 0) {
- /* It's a dump; finish rename that was interrupted. */
+ /* It's a dump; finish movefile that was interrupted. */
ns_info(ns_log_update,
- "completing interrupted dump rename for %s",
+ "completing interrupted dump movefile 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,
+ fclose(fp);
+ if (movefile(logname, zp->z_source) < 0) {
+ ns_error(ns_log_update, "movefile(%s,%s) failed: %s :1",
+ logname, zp->z_source,
strerror(errno));
+ fclose(fp);
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);
+ logname);
fclose(fp);
return (-1);
}
ns_debug(ns_log_update, 3, "merging logs for %s from %s",
- zp->z_origin, zp->z_updatelog);
+ zp->z_origin, logname);
lineno = 1;
- rrecp_start = NULL;
- rrecp_last = NULL;
+ INIT_LIST(curupd);
for (;;) {
+ err = 0;
if (!getword(buf, sizeof buf, fp, 0)) {
- if (lineno == (nonempty_lineno + 1)) {
+ if (lineno == (nonempty_lineno + 1) && !(feof(fp))) {
/*
* End of a nonempty line inside an update
* packet or not inside an update packet.
@@ -1644,7 +2152,8 @@ merge_logs(struct zoneinfo *zp) {
nonempty_lineno = lineno;
}
- if (!strcasecmp(buf, "[DYNAMIC_UPDATE]")) {
+ if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") ||
+ !strcasecmp(buf, "[IXFR_UPDATE]")) {
err = 0;
rcode = NOERROR;
cp = fgets(buf, sizeof buf, fp);
@@ -1665,13 +2174,13 @@ merge_logs(struct zoneinfo *zp) {
&old_serial, &new_serial)) {
ns_error(ns_log_update,
"incr_serial problem with %s",
- zp->z_updatelog);
+ logname);
} 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);
+ serial, logname);
} else {
set_serial(zp, new_serial);
/*
@@ -1682,26 +2191,30 @@ merge_logs(struct zoneinfo *zp) {
sched_zone_maint(zp);
ns_info(ns_log_update,
"set serial to %u (log file %s)",
- new_serial, zp->z_updatelog);
+ new_serial, logname);
}
}
prev_pktdone = 1;
cont = 1;
+ } else if (!strcasecmp(buf, "[END_DELTA]")) {
+ prev_pktdone = 1;
+ cont = 1;
}
if (prev_pktdone) {
- if (rrecp_start) {
- n = process_updates(rrecp_start, &rcode,
+ if (!EMPTY(curupd)) {
+ n = process_updates(&curupd, &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
+ id, logname);
+ 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);
+ id, logname);
+ return(-1);
+ }
+ free_rrecp(&curupd, rcode, empty_from);
}
prev_pktdone = 0;
if (feof(fp))
@@ -1738,7 +2251,7 @@ merge_logs(struct zoneinfo *zp) {
*buf = '\0';
n = sscanf(cp, "origin %s class %s serial %ul",
origin, sclass, &serial);
- if (n != 3 || strcasecmp(origin, zp->z_origin))
+ if (n != 3 || ns_samename(origin, zp->z_origin) != 1)
err++;
if (cp)
lineno++;
@@ -1746,7 +2259,7 @@ merge_logs(struct zoneinfo *zp) {
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);
+ logname);
inside_next = 0;
err++;
}
@@ -1809,11 +2322,11 @@ merge_logs(struct zoneinfo *zp) {
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) {
+ if (ns_parse_ttl(buf, &l) < 0) {
err++;
break;
}
+ ttl = l;
(void) getword(buf, sizeof buf, fp, 1);
}
@@ -1888,45 +2401,56 @@ merge_logs(struct zoneinfo *zp) {
case T_MINFO:
case T_RP:
(void) strcpy(data, buf);
- cp = data + strlen(data) + 1;
+ cp = data + strlen(data) -1;
+ *(cp++) = 0; /* ditch dot */
if (!getword((char *)cp,
sizeof data - (cp - data),
fp, 1)) {
err++;
break;
}
- cp += strlen((char *)cp) + 1;
+ cp += strlen((char *)cp) -1;
+ *(cp++) = 0; /* ditch dot */
if (type != T_SOA) {
n = cp - data;
break;
}
+ else
+ n = cp - data;
if (class != zp->z_class ||
- strcasecmp(dname, zp->z_origin)) {
+ ns_samename(dname, zp->z_origin) != 1) {
err++;
break;
}
- c = getnonblank(fp, zp->z_updatelog);
+ c = getnonblank(fp, logname);
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) {
+ n = getnum(fp, logname, GETNUM_SERIAL);
+ if (getnum_error) {
+ err++;
+ break;
+ }
+ PUTLONG(n, cp);
+ for (i = 0; i < 4; i++) {
+ if (getttl(fp, logname, lineno,
+ &n, &multiline) <= 0)
+ {
err++;
break;
}
PUTLONG(n, cp);
}
if (multiline &&
- getnonblank(fp, zp->z_updatelog)
- != ')') {
+ (getnonblank(fp, logname)
+ != ')')) {
err++;
break;
}
+ n = cp - data;
endline(fp);
break;
case T_WKS:
@@ -1938,11 +2462,11 @@ merge_logs(struct zoneinfo *zp) {
cp = data;
PUTLONG(n, cp);
*cp = (char)getprotocol(fp,
- zp->z_updatelog
+ logname
);
n = INT32SZ + sizeof(char);
n = getservices((int)n, data,
- fp, zp->z_updatelog);
+ fp, logname);
break;
case T_NS:
case T_CNAME:
@@ -2012,22 +2536,24 @@ merge_logs(struct zoneinfo *zp) {
cp = data;
datasize = sizeof data;
cp1 = buf;
- while (i > 255) {
- if (datasize < 256) {
+ while (i > MAXCHARSTRING) {
+ if (datasize <= MAXCHARSTRING){
ns_error(ns_log_update,
"record too big");
+ fclose(fp);
return (-1);
}
- datasize -= 255;
- *cp++ = 255;
- memcpy(cp, cp1, 255);
- cp += 255;
- cp1 += 255;
- i -= 255;
+ datasize -= MAXCHARSTRING;
+ *cp++ = (char)MAXCHARSTRING;
+ memcpy(cp, cp1, MAXCHARSTRING);
+ cp += MAXCHARSTRING;
+ cp1 += MAXCHARSTRING;
+ i -= MAXCHARSTRING;
}
if (datasize < i + 1) {
ns_error(ns_log_update,
"record too big");
+ fclose(fp);
return (-1);
}
*cp++ = i;
@@ -2064,6 +2590,29 @@ merge_logs(struct zoneinfo *zp) {
}
endline(fp);
break;
+ case ns_t_sig:
+ case ns_t_key:
+ case ns_t_nxt:
+ case ns_t_cert:
+ {
+ char * errmsg = NULL;
+ int s;
+
+ s = parse_sec_rdata(buf, sizeof(buf),
+ 1,
+ (u_char *)data,
+ sizeof(data),
+ fp, zp, dnbuf,
+ ttl, type,
+ domain_ctx,
+ primary_trans,
+ &errmsg);
+ if (s < 0) {
+ err++;
+ break;
+ }
+ break;
+ }
default:
err++;
}
@@ -2086,11 +2635,22 @@ merge_logs(struct zoneinfo *zp) {
}
} else { /* section == S_UPDATE */
if (opcode == DELETE) {
+ ttl = 0;
if (n == 0) {
class = C_ANY;
if (type == -1)
type = T_ANY;
- } else {
+ /* WTF? C_NONE or C_ANY _must_ be the case if
+ * we really are to delete this. If
+ * C_NONE is used, according to process_updates(),
+ * the class is gotten from the zone's class.
+ * This still isn't perfect, but it will at least
+ * work.
+ *
+ * Question: What is so special about the class
+ * of the update while we are deleting??
+ */
+ } else /* if (zp->z_xferpid != XFER_ISIXFR) */ {
class = C_NONE;
}
}
@@ -2108,8 +2668,7 @@ merge_logs(struct zoneinfo *zp) {
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);
+ free_rrecp(&curupd, FORMERR, empty_from);
continue;
}
rrecp = res_mkupdrec(section, dname, class, type, ttl);
@@ -2118,21 +2677,12 @@ merge_logs(struct zoneinfo *zp) {
dp->d_zone = zonenum;
dp->d_cred = DB_C_ZONE;
dp->d_clev = nlabels(zp->z_origin);
+ dp->d_secure = DB_S_INSECURE; /* should be UNCHECKED */
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;
- }
+ APPEND(curupd, rrecp, r_link);
} /* for (;;) */
fclose(fp);
@@ -2144,9 +2694,7 @@ merge_logs(struct zoneinfo *zp) {
* Create a disk database to back up zones
*/
int
-zonedump(zp)
- struct zoneinfo *zp;
-{
+zonedump(struct zoneinfo *zp, int mode) {
FILE *fp;
const char *fname;
struct hashbuf *htp;
@@ -2213,11 +2761,13 @@ zonedump(zp)
if (fflush(fp) == EOF) {
ns_error(ns_log_update, "fflush() of %s failed: %s",
tmp_name, strerror(errno));
+ fclose(fp);
return (-1);
}
if (fsync(fileno(fp)) < 0) {
ns_error(ns_log_update, "fsync() of %s failed: %s",
tmp_name, strerror(errno));
+ fclose(fp);
return (-1);
}
if (fclose(fp) == EOF) {
@@ -2242,16 +2792,47 @@ zonedump(zp)
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);
+
+ if (mode == ISIXFR) {
+ if (movefile(tmp_name, zp->z_ixfr_tmp) < 0) {
+ ns_error(ns_log_update, "movefile(%s,%s) failed: %s :2",
+ tmp_name, zp->z_ixfr_tmp, strerror(errno));
+ return (-1);
+ }
+ if (chmod(zp->z_source, 0644) < 0)
+ ns_error(ns_log_update,
+ "chmod(%s,%o) failed, pressing on: %s",
+ zp->z_source, st.st_mode,
+ strerror(errno));
+ if (movefile(zp->z_ixfr_tmp, zp->z_source) < 0) {
+ ns_error(ns_log_update, "movefile(%s,%s) failed: %s :3",
+ zp->z_ixfr_tmp, zp->z_source,
+ strerror(errno));
+ return (-1);
+ }
+ st.st_mode &= ~WRITEABLE_MASK;
+ if (chmod(zp->z_source, st.st_mode) < 0)
+ ns_error(ns_log_update,
+ "chmod(%s,%o) failed, pressing on: %s",
+ zp->z_source, st.st_mode,
+ strerror(errno));
+ } else if (mode == ISNOTIXFR) {
+ if (movefile(tmp_name, zp->z_updatelog) < 0) {
+ ns_error(ns_log_update, "movefile(%s,%s) failed: %s :4",
+ tmp_name, zp->z_updatelog, strerror(errno));
+ return (-1);
+ }
+ if (movefile(zp->z_updatelog, zp->z_source) < 0) {
+ ns_error(ns_log_update, "movefile(%s,%s) failed: %s:5",
+ zp->z_updatelog, zp->z_source,
+ strerror(errno));
+ return (-1);
+ }
+ } else {
+ if (movefile(tmp_name, zp->z_source) < 0) {
+ ns_error(ns_log_update, "movefile(%s,%s) failed: % s :6", tmp_name, zp->z_source, strerror(errno));
+ return (-1);
+ }
}
} else
ns_debug(ns_log_update, 1, "zonedump: no zone to dump");
@@ -2332,10 +2913,10 @@ set_serial(struct zoneinfo *zp, u_int32_t serial) {
zp->z_updatecnt = 0;
#ifdef BIND_NOTIFY
if (!loading)
- sysnotify(zp->z_origin, zp->z_class, T_SOA);
+ ns_notify(zp->z_origin, zp->z_class, ns_t_soa);
#endif
/*
- * Note: caller is responsible for scheduling a dump
+ * Note: caller is responsible for scheduling a dump.
*/
}
@@ -2346,8 +2927,10 @@ set_serial(struct zoneinfo *zp, u_int32_t serial) {
int
incr_serial(struct zoneinfo *zp) {
u_int32_t serial, old_serial;
- FILE *fp;
+ FILE *fp, *ifp;
time_t t;
+ struct databuf *dp, *olddp;
+ unsigned char *cp;
old_serial = get_serial(zp);
serial = old_serial + 1;
@@ -2364,6 +2947,32 @@ incr_serial(struct zoneinfo *zp) {
old_serial, serial, checked_ctime(&t));
if (close_transaction_log(zp, fp)<0)
return (-1);
+ ifp = open_ixfr_log(zp);
+ if (ifp == NULL)
+ return (-1);
+ dp = findzonesoa(zp);
+ if (dp) {
+ olddp = memget(DATASIZE(dp->d_size));
+ if (olddp != NULL) {
+ memcpy(olddp, dp, DATASIZE(dp->d_size));
+ cp = findsoaserial(olddp->d_data);
+ PUTLONG(old_serial, cp);
+ fprintf(ifp, "update: {delete} %s. %u %s %s ",
+ zp->z_origin, dp->d_ttl,
+ p_class(dp->d_class), p_type(dp->d_type));
+ (void) rdata_dump(olddp, ifp);
+ fprintf(ifp, "\n");
+ memput(olddp, DATASIZE(dp->d_size));
+ }
+ fprintf(ifp, "update: {add} %s. %u %s %s ",
+ zp->z_origin, dp->d_ttl,
+ p_class(dp->d_class), p_type(dp->d_type));
+ (void) rdata_dump(dp, ifp);
+ fprintf(ifp, "\n");
+ }
+ fprintf(ifp, "[END_DELTA]\n");
+ if (close_ixfr_log(zp, ifp)<0)
+ return (-1);
/*
* This shouldn't happen, but we check to be sure.
@@ -2390,6 +2999,6 @@ dynamic_about_to_exit(void) {
if ((zp->z_flags & Z_DYNAMIC) &&
((zp->z_flags & Z_NEED_SOAUPDATE) ||
(zp->z_flags & Z_NEED_DUMP)))
- (void)zonedump(zp);
+ (void)zonedump(zp, ISNOTIXFR);
}
}
diff --git a/contrib/bind/bin/named/ns_xfr.c b/contrib/bind/bin/named/ns_xfr.c
index 52d3464..e25a536 100644
--- a/contrib/bind/bin/named/ns_xfr.c
+++ b/contrib/bind/bin/named/ns_xfr.c
@@ -1,9 +1,9 @@
#if !defined(lint) && !defined(SABER)
-static char rcsid[] = "$Id: ns_xfr.c,v 8.25 1998/03/25 18:47:34 halley Exp $";
+static const char rcsid[] = "$Id: ns_xfr.c,v 8.55 1999/10/13 16:39:13 vixie Exp $";
#endif /* not lint */
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-1999 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
@@ -24,6 +24,7 @@ static char rcsid[] = "$Id: ns_xfr.c,v 8.25 1998/03/25 18:47:34 halley Exp $";
#include <sys/param.h>
#include <sys/file.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
@@ -32,26 +33,26 @@ static char rcsid[] = "$Id: ns_xfr.c,v 8.25 1998/03/25 18:47:34 halley Exp $";
#include <errno.h>
#include <fcntl.h>
#include <resolv.h>
+#include <res_update.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 <isc/dst.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,
@@ -59,20 +60,18 @@ static int sx_flush(struct qstream *qsp),
sx_nsrrs(struct qstream *qsp),
sx_allrrs(struct qstream *qsp),
sx_pushlev(struct qstream *qsp, struct namebuf *np);
+static struct databuf *db_next(struct databuf *dp);
/*
* void
- * ns_xfr(qsp, znp, zone, class, type, opcode, id)
+ * ns_xfr(qsp, znp, zone, class, type, opcode, id, serial_ixfr, in_tsig)
* 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)
+ int opcode, int id, u_int32_t serial_ixfr, struct tsig_record *in_tsig)
{
- FILE *rfp;
- int fdstat;
- pid_t pid;
server_info si;
#ifdef SO_SNDBUF
static const int sndbuf = XFER_BUFSIZE * 2;
@@ -80,9 +79,26 @@ ns_xfr(struct qstream *qsp, struct namebuf *znp,
#ifdef SO_SNDLOWAT
static const int sndlowat = XFER_BUFSIZE;
#endif
+ ns_updrec *changes;
- 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));
+ switch (type) {
+ case ns_t_axfr: /*FALLTHROUGH*/
+ case ns_t_ixfr:
+#ifdef BIND_ZXFR
+ case ns_t_zxfr:
+#endif
+ ns_info(ns_log_xfer_out,
+ "zone transfer (%s) of \"%s\" (%s) to %s",
+ p_type(type), zones[zone].z_origin, p_class(class),
+ sin_ntoa(qsp->s_from));
+ break;
+ default:
+ ns_warning(ns_log_xfer_out,
+ "unsupported XFR (type %s) of \"%s\" (%s) to %s",
+ p_type(type), zones[zone].z_origin, p_class(class),
+ sin_ntoa(qsp->s_from));
+ goto abort;
+ }
#ifdef SO_SNDBUF
/*
@@ -104,9 +120,10 @@ ns_xfr(struct qstream *qsp, struct namebuf *znp,
if (sq_openw(qsp, 64*1024) == -1)
goto abort;
memset(&qsp->xfr, 0, sizeof qsp->xfr);
- qsp->xfr.top = znp;
+ qsp->xfr.top.axfr = znp;
qsp->xfr.zone = zone;
qsp->xfr.class = class;
+ qsp->xfr.type = type;
qsp->xfr.id = id;
qsp->xfr.opcode = opcode;
qsp->xfr.msg = memget(XFER_BUFSIZE);
@@ -118,19 +135,76 @@ ns_xfr(struct qstream *qsp, struct namebuf *znp,
zones[zone].z_numxfrs++;
qsp->flags |= STREAM_AXFR;
+#ifdef BIND_ZXFR
+ if (type == ns_t_zxfr) {
+ enum { rd = 0, wr = 1 };
+ int z[2];
+ pid_t p;
+
+ if (pipe(z) < 0) {
+ ns_error(ns_log_xfer_out, "pipe: %s", strerror(errno));
+ goto abort;
+ }
+ p = vfork();
+ if (p < 0) {
+ ns_error(ns_log_xfer_out, "vfork: %s", strerror(errno));
+ goto abort;
+ }
+ if (p == 0) {
+ /* Child. */
+ dup2(z[rd], STDIN_FILENO);
+ dup2(qsp->s_rfd, STDOUT_FILENO);
+ execlp("gzip", "gzip", NULL);
+ ns_error(ns_log_xfer_out, "execlp: %s", strerror(errno));
+ _exit(1);
+ }
+ ns_info(ns_log_xfer_out, "zxfr gzip pid %lu", p);
+ /* Parent. */
+ dup2(z[wr], qsp->s_rfd);
+ close(z[wr]);
+ close(z[rd]);
+
+ /* When a ZXFR completes, there can be no more requests. */
+ qsp->flags |= STREAM_DONE_CLOSE;
+ }
+#endif
+
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 (in_tsig == NULL)
+ qsp->xfr.tsig_state = NULL;
+ else {
+ qsp->xfr.tsig_state = memget(sizeof(ns_tcp_tsig_state));
+ ns_sign_tcp_init(in_tsig->key, in_tsig->sig, in_tsig->siglen,
+ qsp->xfr.tsig_state);
+ qsp->xfr.tsig_skip = 0;
+ }
- if (sx_pushlev(qsp, znp) < 0) {
- abort:
- (void) shutdown(qsp->s_rfd, 2);
- sq_remove(qsp);
- return;
+ if (type == ns_t_ixfr) {
+ changes = ixfr_get_change_list(&zones[zone], serial_ixfr,
+ zones[zone].z_serial);
+ if (changes != NULL)
+ {
+ qsp->xfr.serial = serial_ixfr;
+ qsp->xfr.top.ixfr = changes;
+ }
+ else
+ type = ns_t_axfr;
}
- (void) sq_writeh(qsp, sx_sendsoa);
+ if (sx_pushlev(qsp, znp) < 0) {
+ abort:
+ (void) shutdown(qsp->s_rfd, 2);
+ sq_remove(qsp);
+ return;
+ }
+ if (type != ns_t_ixfr)
+ (void) sq_writeh(qsp, sx_sendsoa);
+ else
+ (void) sq_writeh(qsp, sx_send_ixfr);
+
}
/*
@@ -176,7 +250,7 @@ ns_freexfr(struct qstream *qsp) {
* init the header of a message, reset the compression pointers, and
* reset the write pointer to the first byte following the header.
*/
-static void
+void
sx_newmsg(struct qstream *qsp) {
HEADER *hp = (HEADER *)qsp->xfr.msg;
@@ -190,6 +264,11 @@ sx_newmsg(struct qstream *qsp) {
qsp->xfr.ptrs[1] = NULL;
qsp->xfr.cp = qsp->xfr.msg + HFIXEDSZ;
+
+ qsp->xfr.eom = qsp->xfr.msg + XFER_BUFSIZE;
+
+ if (qsp->xfr.tsig_state != NULL)
+ qsp->xfr.eom -= TSIG_BUF_SIZE;
}
/*
@@ -205,12 +284,30 @@ sx_flush(struct qstream *qsp) {
#ifdef DEBUG
if (debug >= 10)
- fp_nquery(qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg,
- log_get_stream(packet_channel));
+ res_pquery(&res, qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg,
+ log_get_stream(packet_channel));
#endif
+ if (qsp->xfr.tsig_state != NULL && qsp->xfr.tsig_skip == 0) {
+ int msglen = qsp->xfr.cp - qsp->xfr.msg;
+
+ ns_sign_tcp(qsp->xfr.msg, &msglen, qsp->xfr.eom - qsp->xfr.msg,
+ NOERROR, qsp->xfr.tsig_state,
+ qsp->xfr.state == s_x_done);
+
+ if (qsp->xfr.state == s_x_done) {
+ memput(qsp->xfr.tsig_state, sizeof(ns_tcp_tsig_state));
+ qsp->xfr.tsig_state = NULL;
+ }
+ qsp->xfr.cp = qsp->xfr.msg + msglen;
+
+ }
ret = sq_write(qsp, qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg);
- if (ret >= 0)
+ if (ret >= 0) {
qsp->xfr.cp = NULL;
+ qsp->xfr.tsig_skip = 0;
+ }
+ else
+ qsp->xfr.tsig_skip = 1;
return (ret);
}
@@ -229,7 +326,7 @@ 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;
+ int n, type;
if (qsp->xfr.cp != NULL) {
if (qsp->xfr.transfer_format == axfr_one_answer &&
@@ -238,15 +335,34 @@ sx_addrr(struct qstream *qsp, const char *dname, struct databuf *dp) {
}
if (qsp->xfr.cp == NULL)
sx_newmsg(qsp);
+
+ /*
+ * Add question to first answer.
+ */
+ if (qsp->xfr.state == s_x_firstsoa && dp->d_type == T_SOA ) {
+ if ((qsp->xfr.type == ns_t_ixfr) || (qsp->flags & STREAM_AXFRIXFR)) {
+ n = dn_comp(dname, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp,
+ qsp->xfr.ptrs, edp);
+ if (n > 0 && (qsp->xfr.cp + n + INT16SZ * 2) <= qsp->xfr.eom) {
+ qsp->xfr.cp += n;
+ type = (qsp->xfr.type == ns_t_zxfr) ?
+ ns_t_axfr : qsp->xfr.type;
+ PUTSHORT((u_int16_t) type, qsp->xfr.cp);
+ PUTSHORT((u_int16_t) qsp->xfr.class, qsp->xfr.cp);
+ hp->qdcount = htons(ntohs(hp->qdcount) + 1);
+ }
+ }
+ }
+
n = make_rr(dname, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp,
- 0, qsp->xfr.ptrs, edp);
+ 0, qsp->xfr.ptrs, edp, 0);
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);
+ 0, qsp->xfr.ptrs, edp, 0);
INSIST(n >= 0);
}
hp->ancount = htons(ntohs(hp->ancount) + 1);
@@ -264,18 +380,37 @@ sx_addrr(struct qstream *qsp, const char *dname, struct databuf *dp) {
* side effects:
* if progress was made, header and pointers will be advanced.
*/
-static int
+int
sx_soarr(struct qstream *qsp) {
struct databuf *dp;
+ int added_soa = 0;
- foreach_rr(dp, qsp->xfr.top, T_SOA, qsp->xfr.class, qsp->xfr.zone) {
+ foreach_rr(dp, qsp->xfr.top.axfr, 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);
+ added_soa = 1;
+ break;
}
- ns_panic(ns_log_xfer_out, 1, "no SOA at zone top");
+ if (added_soa == 0)
+ ns_panic(ns_log_xfer_out, 1, "no SOA at zone top");
+ if (qsp->xfr.state == s_x_firstsoa) {
+ foreach_rr(dp, qsp->xfr.top.axfr, T_SIG, qsp->xfr.class,
+ qsp->xfr.zone)
+ {
+ if (SIG_COVERS(dp) != T_SOA)
+ continue;
+ if (sx_addrr(qsp, zones[qsp->xfr.zone].z_origin, dp) <
+ 0)
+ {
+ /* RR wouldn't fit. Bail out. */
+ return (-1);
+ }
+ }
+ }
+ return (0);
}
/*
@@ -283,6 +418,9 @@ sx_soarr(struct qstream *qsp) {
* sx_nsrrs(qsp)
* add the NS RR's at the current level's current np,
* to the assembly message
+ * This function also adds the SIG(NS), KEY, SIG(KEY), NXT, SIG(NXT)
+ * the reason for this these records are part of the delegation.
+ *
* return:
* >1 = number of NS RRs added, note that there may be more
* 0 = success, there are no more NS RRs at this level
@@ -303,11 +441,11 @@ sx_nsrrs(struct qstream *qsp) {
int rrcount, class;
class = qsp->xfr.class;
- top = qsp->xfr.top;
+ top = qsp->xfr.top.axfr;
rrcount = 0;
for ((void)NULL;
(dp = qsp->xfr.lev->dp) != NULL;
- qsp->xfr.lev->dp = dp->d_next) {
+ qsp->xfr.lev->dp = db_next(dp)) {
/* XYZZY foreach_rr? */
if (dp->d_class != class && class != C_ANY)
continue;
@@ -323,14 +461,21 @@ sx_nsrrs(struct qstream *qsp) {
*/
if (dp->d_zone == DB_Z_CACHE)
continue;
- if (dp->d_type != T_NS)
+
+ if (dp->d_type != T_NS && dp->d_type != T_KEY &&
+ dp->d_type != T_NXT && dp->d_type != T_SIG)
+ continue;
+ if (dp->d_type == T_SIG && ((SIG_COVERS(dp) != T_NS) &&
+ (SIG_COVERS(dp) != T_KEY) && (SIG_COVERS(dp) != T_NXT)))
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++;
+ if (dp->d_type != T_NS) /* no glue processing */
+ continue;
+ rrcount++; /* only count NS records */
}
/*
@@ -373,6 +518,16 @@ sx_nsrrs(struct qstream *qsp) {
*/
return (-1);
}
+ /* for IPv6 glue AAAA record transfer */
+ /* patched by yasuhiro@nic.ad.jp, 1999/5/23 */
+ foreach_rr(gdp, gnp, T_AAAA, 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);
@@ -383,6 +538,8 @@ sx_nsrrs(struct qstream *qsp) {
* sx_allrrs(qsp)
* add the non-(SOA,NS) RR's at the current level's current np,
* to the assembly message
+ * do not add the DNSSEC types KEY and NXT as the delegation check
+ * wrote these types out.
* return:
* >0 = number of RR's added, note that there may be more
* 0 = success, there are no more RRs at this level
@@ -396,20 +553,18 @@ sx_nsrrs(struct qstream *qsp) {
*/
static int
sx_allrrs(struct qstream *qsp) {
- struct databuf *dp, *tdp, *gdp;
- struct namebuf *gnp, *tnp, *top;
- struct hashbuf *htp;
- const char *fname;
+ struct databuf *dp;
+ struct namebuf *top;
int rrcount, class;
u_int zone;
class = qsp->xfr.class;
- top = qsp->xfr.top;
+ top = qsp->xfr.top.axfr;
zone = qsp->xfr.zone;
rrcount = 0;
for ((void)NULL;
(dp = qsp->xfr.lev->dp) != NULL;
- qsp->xfr.lev->dp = dp->d_next) {
+ qsp->xfr.lev->dp = db_next(dp)) {
/* XYZZY foreach_rr? */
if (dp->d_class != class && class != C_ANY)
continue;
@@ -417,18 +572,13 @@ sx_allrrs(struct qstream *qsp) {
continue;
if (dp->d_zone != zone || stale(dp))
continue;
- if (dp->d_type == T_SOA || dp->d_type == T_NS)
+ if (dp->d_type == T_SOA || dp->d_type == T_NS ||
+ dp->d_type == T_NXT || dp->d_type == T_KEY)
+ continue;
+ if (dp->d_type == T_SIG &&
+ (SIG_COVERS(dp) == T_SOA || SIG_COVERS(dp) == T_NS ||
+ SIG_COVERS(dp) == T_KEY || SIG_COVERS(dp) == T_NXT))
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) {
@@ -452,7 +602,7 @@ sx_allrrs(struct qstream *qsp) {
* qsp->xfr.state at the end of the topmost level. changes the
* qsp->xfr.lev->state several times per domain name.
*/
-static void
+void
sx_sendlev(struct qstream *qsp) {
struct qs_x_lev *lev;
int rrcount;
@@ -462,6 +612,12 @@ sx_sendlev(struct qstream *qsp) {
switch (lev->state) {
case sxl_ns: {
while (lev->dp) {
+ /* Was the child zone reloaded under us? */
+ if ((lev->dp->d_flags & DB_F_ACTIVE) == 0) {
+ (void) shutdown(qsp->s_rfd, 2);
+ sq_remove(qsp);
+ return;
+ }
rrcount = sx_nsrrs(qsp);
/* If we can't pack this one in, come back later. */
if (rrcount < 0)
@@ -470,7 +626,7 @@ sx_sendlev(struct qstream *qsp) {
* NS RRs other than those at the
* zone top are zone cuts.
*/
- if (rrcount > 0 && qsp->xfr.top != lev->np)
+ if (rrcount > 0 && qsp->xfr.top.axfr != lev->np)
lev->flags |= SXL_ZONECUT;
}
/* No more DP's for the NS RR pass on this NP. */
@@ -481,10 +637,18 @@ sx_sendlev(struct qstream *qsp) {
/* No NS RR's, so it's safe to send other types. */
lev->state = sxl_all;
lev->dp = lev->np->n_data;
+ if (lev->dp)
+ DRCNTINC(lev->dp);
goto again;
}
case sxl_all: {
while (lev->dp) {
+ /* Was a record updated under us? */
+ if ((lev->dp->d_flags & DB_F_ACTIVE) == 0) {
+ (void) shutdown(qsp->s_rfd, 2);
+ sq_remove(qsp);
+ return;
+ }
/* If we can't pack this one in, come back later. */
if (sx_allrrs(qsp) < 0)
return;
@@ -535,11 +699,15 @@ sx_sendlev(struct qstream *qsp) {
* side effects:
* changes qsp->xfr.state. adds RR to output buffer.
*/
-static void
+void
sx_sendsoa(struct qstream *qsp) {
+ HEADER * hp = (HEADER *) qsp->xfr.msg;
+
if (sx_soarr(qsp) == -1)
return; /* No state change, come back here later. */
+ hp->aa = 1;
+
switch (qsp->xfr.state) {
case s_x_firstsoa: {
/* Next thing to do is send the zone. */
@@ -549,8 +717,8 @@ sx_sendsoa(struct qstream *qsp) {
}
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;
+ (void)sx_flush(qsp);
sq_writeh(qsp, sq_flushw);
break;
}
@@ -581,6 +749,8 @@ sx_pushlev(struct qstream *qsp, struct namebuf *np) {
new->state = sxl_ns;
new->np = np;
new->dp = np->n_data;
+ if (new->dp)
+ DRCNTINC(new->dp);
getname(np, new->dname, sizeof new->dname);
/*
* We find the subdomains by looking in the hash table for this
@@ -637,6 +807,26 @@ static struct qs_x_lev *
sx_freelev(struct qs_x_lev *lev) {
struct qs_x_lev *next = lev->next;
+ if (lev->dp) {
+ DRCNTDEC(lev->dp);
+ if (lev->dp->d_rcnt == 0)
+ db_freedata(lev->dp);
+ }
memput(lev, sizeof *lev);
return (next);
}
+
+static struct databuf *
+db_next(struct databuf *dp) {
+ struct databuf *next = dp->d_next;
+
+ DRCNTDEC(dp);
+ if (dp->d_rcnt == 0)
+ db_freedata(dp);
+
+ if (next)
+ DRCNTINC(next);
+
+ return (next);
+}
+
diff --git a/contrib/bind/bin/named/pathtemplate.h b/contrib/bind/bin/named/pathtemplate.h
index d339ef8..65056b6 100644
--- a/contrib/bind/bin/named/pathtemplate.h
+++ b/contrib/bind/bin/named/pathtemplate.h
@@ -1,9 +1,9 @@
/*
- * $Id: pathtemplate.h,v 8.1 1998/03/19 19:53:21 halley Exp $
+ * $Id: pathtemplate.h,v 8.4 1999/01/08 19:28:30 vixie Exp $
*/
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-1999 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
@@ -41,6 +41,10 @@
#define _PATH_PIDFILE "%DESTRUN%/named.pid"
#endif
+#ifndef _PATH_NDCSOCK
+#define _PATH_NDCSOCK "%DESTRUN%/ndc"
+#endif
+
#ifndef _PATH_STATS
#define _PATH_STATS "named.stats"
#endif
diff --git a/contrib/bind/bin/named/test/named.conf b/contrib/bind/bin/named/test/named.conf
index b852604..0e43eac 100644
--- a/contrib/bind/bin/named/test/named.conf
+++ b/contrib/bind/bin/named/test/named.conf
@@ -5,6 +5,8 @@ options {
// directory "/var/named";
check-names master warn; /* default. */
datasize 20M;
+ deallocate-on-exit yes;
+ listen-on { 10.0.0.53; };
};
zone "localhost" IN {
@@ -27,3 +29,17 @@ zone "." IN {
type hint;
file "root.hint";
};
+
+logging {
+ channel xfer-log {
+ file "/var/tmp/bind-xfer.log" versions unlimited size 10m;
+ print-category yes;
+ print-severity yes;
+ print-time yes;
+ severity info;
+ };
+ category xfer-in { xfer-log; };
+ category xfer-out { xfer-log; };
+ category notify { xfer-log; };
+ category load { xfer-log; };
+};
diff --git a/contrib/bind/bin/named/version.c b/contrib/bind/bin/named/version.c
index 9468be2..31820f5 100644
--- a/contrib/bind/bin/named/version.c
+++ b/contrib/bind/bin/named/version.c
@@ -1,11 +1,11 @@
/*
* @(#)Version.c 4.9 (Berkeley) 7/21/90
- * $Id: version.c,v 8.2 1997/04/24 23:59:02 vixie Exp $
+ * $Id: version.c,v 8.3 1999/01/02 06:05:14 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 $";
+char rcsid[] = "$Id: version.c,v 8.3 1999/01/02 06:05:14 vixie Exp $";
#endif /* not lint */
char Version[] = "named %VERSION% %WHEN%\n\t%WHOANDWHERE%";
diff --git a/contrib/bind/bin/ndc/Makefile b/contrib/bind/bin/ndc/Makefile
index 13340c2..d2b9feb 100644
--- a/contrib/bind/bin/ndc/Makefile
+++ b/contrib/bind/bin/ndc/Makefile
@@ -1,4 +1,4 @@
-## Copyright (c) 1996 by Internet Software Consortium
+## Copyright (c) 1996,1999 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
@@ -13,7 +13,7 @@
## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
## SOFTWARE.
-# $Id: Makefile,v 1.6 1997/06/19 03:22:10 halley Exp $
+# $Id: Makefile,v 1.15 1999/08/08 17:51:02 vixie Exp $
DESTDIR=
CC= cc
@@ -31,56 +31,64 @@ A=a
O=o
LEX = lex -I
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
+AR= ar cru
INSTALL= install
STRIP=-s
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
PS=ps
LDFLAGS=
CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} ${DEFS}
PROG= ndc
-SRCS=
-OBJS=
+SRCS= ${PROG}.c
+OBJS= ${PROG}.${O}
+HDRS= pathnames.h
-all: ${PROG}
+all: ${PROG}${EXE}
-${PROG}: ${PROG}.sh ../named/pathnames ../named/pathnames.h Makefile
- sed -e "s|%PIDFILE%|"`../named/pathnames _path_pidfile`"|" \
- -e "s|%NAMED%|"`../named/pathnames _path_named`"|" \
- -e "s|%PS%|${PS}|" \
- < ndc.sh > ndc
- chmod +x ndc
+${PROG}${EXE}: ${HDRS} ${OBJS} ${LIBBIND} Makefile
+ ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} ${LIBBIND} ${SYSLIBS}
+
+.c.${O}:
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c
+
+pathnames.h: ${TOP}/.settings Makefile ../named/pathtemplate.h
+ rm -f pathnames.h
+ sed -e "s|%DESTSBIN%|${DESTSBIN}|" \
+ -e "s|%DESTEXEC%|${DESTEXEC}|" \
+ -e "s|%DESTETC%|${DESTETC}|" \
+ -e "s|%DESTRUN%|${DESTRUN}|" \
+ < ../named/pathtemplate.h > pathnames.h
distclean: clean
clean: FRC
- rm -f ${PROG} ${OBJS} core .depend
+ rm -f ${PROG}${EXE} ${OBJS} core .depend
rm -f *.BAK *.CKP *~ *.orig
+ rm -f pathnames.h
-depend:
+depend: ${SRCS} pathnames.h
+ mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
${DESTDIR}${DESTSBIN}:
mkdir -p ${DESTDIR}${DESTSBIN}
-install: ${DESTDIR}${DESTSBIN} ${PROG}
- ${INSTALL} -c -m 755 ${PROG} ${DESTDIR}${DESTSBIN}/${PROG}
+install: ${DESTDIR}${DESTSBIN} ${PROG}${EXE}
+ ${INSTALL} ${INSTALL_EXEC} ${STRIP} -c -m 755 ${PROG}${EXE} ${DESTDIR}${DESTSBIN}/${PROG}${EXE}
links: FRC
- @set -e; ln -s SRC/*.sh .
+ @set -e; ln -s SRC/*.[ch] .
tags: FRC
ctags ${SRCS} *.h
-commands.c: commands.l
- ${LEX} -t $< > $@ || rm $@
-
FRC:
# DO NOT DELETE THIS LINE -- mkdep uses it.
diff --git a/contrib/bind/bin/ndc/ndc.c b/contrib/bind/bin/ndc/ndc.c
new file mode 100644
index 0000000..764d05b
--- /dev/null
+++ b/contrib/bind/bin/ndc/ndc.c
@@ -0,0 +1,698 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ndc.c,v 1.13 1999/10/13 16:39:16 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * Portions Copyright (c) 1999 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/file.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <isc/eventlib.h>
+#include <isc/ctl.h>
+
+#include "port_after.h"
+#include "pathnames.h"
+
+typedef union {
+ struct sockaddr_in in;
+ struct sockaddr_un un;
+} sockaddr_t;
+
+typedef void (*closure)(void *, const char *, int);
+
+static const char * program = "amnesia";
+static enum { e_channel, e_signals } mode = e_channel;
+static char * channel = _PATH_NDCSOCK;
+static const char helpfmt[] = "\t%-16s\t%s\n";
+static const char * pidfile = _PATH_PIDFILE;
+static sockaddr_t client, server;
+static int quiet = 0, tracing = 0, silent = 0, client_set = 0;
+static int debug = 0, errors = 0, doneflag, exitflag;
+static int logger_show = 1;
+static evContext ev;
+static char cmd[1000];
+static const char * named_path = _PATH_NAMED;
+
+static int slashcmd(void);
+static void slashhelp(void);
+static int builtincmd(void);
+static void command(void);
+static int running(int, pid_t *);
+static void command_channel(void);
+static void channel_loop(char *, int, closure, void *);
+static void getpid_closure(void *, const char *, int);
+static void banner(struct ctl_cctx *, void *, const char *, u_int);
+static void done(struct ctl_cctx *, void *, const char *, u_int);
+static void logger(enum ctl_severity, const char *fmt, ...);
+static void command_signals(void);
+static void stop_named(pid_t);
+static void start_named(const char *, int);
+static int fgetpid(const char *, pid_t *);
+static int get_sockaddr(char *, sockaddr_t *);
+static size_t impute_addrlen(const struct sockaddr *);
+static void vtrace(const char *, va_list);
+static void trace(const char *, ...);
+static void result(const char *, ...);
+static void fatal(const char *, ...);
+static void verror(const char *, va_list);
+static void error(const char *, ...);
+
+static void
+usage(const char *fmt, ...) {
+ va_list args;
+
+ va_start(args, fmt);
+ fprintf(stderr, "%s: usage error: ", program);
+ vfprintf(stderr, fmt, args);
+ fputc('\n', stderr);
+ va_end(args);
+ fatal("usage: %s \
+[-l localsock] [-c channel] [-p pidfile] [-n namedpath] \
+[-dqst] [command [args]]\n\
+",
+ program);
+}
+
+/* Public. */
+
+int
+main(int argc, char *argv[], char *envp[]) {
+ char *p;
+ int ch;
+
+ if ((program = strrchr(argv[0], '/')) != NULL)
+ program++;
+ else
+ program = argv[0];
+ while ((ch = getopt(argc, argv, "c:p:l:n:dqst")) != -1) {
+ switch (ch) {
+ case 'c':
+ channel = optarg;
+ mode = e_channel;
+ break;
+ case 'p':
+ pidfile = optarg;
+ mode = e_signals;
+ break;
+ case 'l':
+ if (!get_sockaddr(optarg, &client))
+ usage("bad local socket (%s)", optarg);
+ client_set++;
+ break;
+ case 'n':
+ named_path = optarg;
+ break;
+ case 'd':
+ tracing++;
+ debug++;
+ break;
+ case 'q':
+ quiet++;
+ break;
+ case 's':
+ silent++;
+ break;
+ case 't':
+ tracing++;
+ break;
+ default:
+ usage("unrecognized command option (%c)", ch);
+ /* NOTREACHED */
+ }
+ }
+ if (mode != e_channel && client_set)
+ usage("the -l flag is only valid for control channels");
+ if (mode == e_channel) {
+ if (!get_sockaddr(channel, &server))
+ usage("bad channel name (%s)", channel);
+ if (evCreate(&ev) < 0)
+ fatal("evCreate - %s", strerror(errno));
+ }
+ *(p = cmd) = '\0';
+ for (argc -= optind, argv += optind;
+ argc > 0;
+ argc--, argv++) {
+ size_t t = strlen(*argv);
+
+ if ((p - cmd) + t + 2 > sizeof cmd)
+ usage("command too long");
+ strcpy(p, *argv);
+ p += t;
+ if (argv[1] != NULL)
+ *p++ = ' ';
+ *p = '\0';
+ }
+ if (cmd[0] != '\0') {
+ command();
+ } else {
+ if (!quiet)
+ result("Type help -or- /h if you need help.");
+ for (exitflag = 0; !exitflag; (void)NULL) {
+ if (!quiet) {
+ printf("%s> ", program);
+ fflush(stdout);
+ }
+ if (!fgets(cmd, sizeof cmd, stdin)) {
+ if (!quiet)
+ result("EOF");
+ exitflag++;
+ continue;
+ }
+ if (cmd[strlen(cmd) - 1] == '\n')
+ cmd[strlen(cmd) - 1] = '\0';
+ if (cmd[0] == '\0')
+ continue;
+ if (slashcmd())
+ continue;
+ command();
+ }
+ }
+ if (mode == e_channel)
+ evDestroy(ev);
+ exit(errors != 0);
+}
+
+/* Private. */
+
+static int
+slashcmd(void) {
+ if (strncasecmp(cmd, "/help", strlen(cmd)) == 0)
+ slashhelp();
+ else if (strncasecmp(cmd, "/exit", strlen(cmd)) == 0)
+ exitflag++;
+ else if (strncasecmp(cmd, "/trace", strlen(cmd)) == 0)
+ result("tracing now %s",
+ (tracing = !tracing) ? "on" : "off");
+ else if (strncasecmp(cmd, "/debug", strlen(cmd)) == 0)
+ result("debugging now %s",
+ (debug = !debug) ? "on" : "off");
+ else if (strncasecmp(cmd, "/quiet", strlen(cmd)) == 0)
+ result("%s is now %s", program,
+ (quiet = !quiet) ? "quiet" : "noisy");
+ else if (strncasecmp(cmd, "/silent", strlen(cmd)) == 0)
+ result("%s is now %s", program,
+ (silent = !silent)
+ ? "silent" : "gregarious");
+ else
+ return (0);
+ return (1);
+}
+
+static void
+slashhelp(void) {
+ printf(helpfmt, "/h(elp)", "this text");
+ printf(helpfmt, "/e(xit)", "leave this program");
+ printf(helpfmt, "/t(race)",
+ "toggle tracing (protocol and system events)");
+ printf(helpfmt, "/d(ebug)",
+ "toggle debugging (internal program events)");
+ printf(helpfmt, "/q(uiet)",
+ "toggle quietude (prompts and results)");
+ printf(helpfmt, "/s(ilent)",
+ "toggle silence (suppresses nonfatal errors)");
+}
+
+static int
+builtincmd(void) {
+ static const char spaces[] = " \t";
+ char *rest, *syscmd;
+ pid_t pid;
+ int save_quiet = quiet;
+ int len;
+
+ quiet = 1;
+
+ len = strcspn(cmd, spaces);
+ rest = cmd + len;
+ if (*rest != '\0') {
+ rest++;
+ rest += strspn(rest, spaces);
+ }
+ syscmd = malloc(strlen(named_path) + sizeof " " + strlen(rest));
+ if (syscmd == NULL)
+ fatal("malloc() failed - %s", strerror(errno));
+ strcpy(syscmd, named_path);
+ if (*rest != '\0') {
+ strcat(syscmd, " ");
+ strcat(syscmd, rest);
+ }
+ if (strncasecmp(cmd, "start", len) == 0) {
+ if (running(debug, &pid))
+ error("name server already running? (pid %ld)",
+ (long)pid);
+ else
+ start_named(syscmd, save_quiet);
+ quiet = save_quiet;
+ free(syscmd);
+ return (1);
+ } else if (strncasecmp(cmd, "restart", len) == 0) {
+ if (!running(debug, &pid))
+ error("name server was not running (warning only)");
+ else
+ stop_named(pid);
+ start_named(syscmd, save_quiet);
+ quiet = save_quiet;
+ free(syscmd);
+ return (1);
+ }
+ quiet = save_quiet;
+ free(syscmd);
+ return (0);
+}
+
+static void
+builtinhelp(void) {
+ printf(helpfmt, "start", "start the server");
+ printf(helpfmt, "restart", "stop server if any, start a new one");
+}
+
+static void
+command(void) {
+ if (builtincmd())
+ return;
+ switch (mode) {
+ case e_channel:
+ command_channel();
+ break;
+ case e_signals:
+ command_signals();
+ break;
+ default:
+ abort();
+ }
+}
+
+static int
+running(int show, pid_t *pidp) {
+ pid_t pid;
+
+ switch (mode) {
+ case e_channel:
+ pid = 0;
+ channel_loop("getpid", show, getpid_closure, &pid);
+ if (pid != 0) {
+ if (tracing)
+ result("pid %ld is running", (long)pid);
+ *pidp = pid;
+ return (1);
+ }
+ break;
+ case e_signals:
+ if (fgetpid(pidfile, pidp)) {
+ if (tracing)
+ result("pid %ld is running", (long)pid);
+ return (1);
+ }
+ break;
+ default:
+ abort();
+ }
+ if (show)
+ error("pid not valid or server not running");
+ return (0);
+}
+
+static void
+getpid_closure(void *uap, const char *text, int flags) {
+ pid_t *pidp = uap;
+ const char *cp;
+
+ flags = flags;
+ if ((cp = strchr(text, '<')) != NULL) {
+ long l = 0;
+ char ch;
+
+ while ((ch = *++cp) != '\0' && ch != '>' && isdigit(ch))
+ l *= 10, l += (ch - '0');
+ if (ch == '>') {
+ *pidp = (pid_t)l;
+ return;
+ }
+ }
+ error("response does not contain pid (%s)", text);
+}
+
+static void
+command_channel(void) {
+ int helping = (strcasecmp(cmd, "help") == 0);
+ int save_quiet = quiet;
+
+ if (helping)
+ quiet = 0;
+ channel_loop(cmd, !quiet, NULL, NULL);
+ quiet = save_quiet;
+}
+
+struct args {
+ const char *cmd;
+ closure cl;
+ void *ua;
+};
+
+static void
+channel_loop(char *cmdtext, int show, closure cl, void *ua) {
+ struct ctl_cctx *ctl;
+ struct sockaddr *client_addr;
+ struct args a;
+ evEvent e;
+ int save_logger_show = logger_show;
+
+ if (!client_set)
+ client_addr = NULL;
+ else
+ client_addr = (struct sockaddr *)&client;
+ a.cmd = cmdtext;
+ a.cl = cl;
+ a.ua = ua;
+ logger_show = show;
+ ctl = ctl_client(ev, client_addr, impute_addrlen(client_addr),
+ (struct sockaddr *)&server,
+ impute_addrlen((struct sockaddr *)&server),
+ banner, &a, 15, logger);
+ if (ctl == NULL) {
+ if (show)
+ error("cannot connect to command channel (%s)",
+ channel);
+ } else {
+ doneflag = 0;
+ while (evGetNext(ev, &e, EV_WAIT) == 0)
+ if (evDispatch(ev, e) < 0 || doneflag)
+ break;
+ ctl_endclient(ctl);
+ }
+ logger_show = save_logger_show;
+}
+
+static void
+banner(struct ctl_cctx *ctl, void *uap, const char *msg, u_int flags) {
+ struct args *a = uap;
+
+ if (msg == NULL) {
+ trace("EOF");
+ doneflag = 1;
+ return;
+ }
+ trace("%s", msg);
+ if ((flags & CTL_MORE) != 0)
+ return;
+ if (ctl_command(ctl, a->cmd, strlen(a->cmd), done, a) < 0) {
+ error("ctl_command failed - %s", strerror(errno));
+ doneflag = 1;
+ }
+}
+
+static void
+done(struct ctl_cctx *ctl, void *uap, const char *msg, u_int flags) {
+ struct args *a = uap;
+
+ if (msg == NULL) {
+ trace("EOF");
+ doneflag = 1;
+ return;
+ }
+ if (!tracing && !quiet && strlen(msg) > 4)
+ result("%s", msg + 4);
+ trace("%s", msg);
+ if (a->cl)
+ (a->cl)(a->ua, msg, flags);
+ if ((flags & CTL_MORE) == 0)
+ doneflag = 1;
+}
+
+static void
+logger(enum ctl_severity ctlsev, const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ switch (ctlsev) {
+ case ctl_debug:
+ /* FALLTHROUGH */
+ case ctl_warning:
+ if (debug)
+ vtrace(format, args);
+ break;
+ case ctl_error:
+ if (logger_show)
+ verror(format, args);
+ break;
+ default:
+ abort();
+ }
+ va_end(args);
+}
+
+static struct cmdsig {
+ const char * cmd;
+ int sig;
+ const char * help;
+} cmdsigs[] = {
+ { "dumpdb", SIGINT, "dump cache database to a file" },
+ { "reload", SIGHUP, "reload configuration file" },
+ { "stats", SIGILL, "dump statistics to a file" },
+ { "trace", SIGUSR1, "increment trace level" },
+ { "notrace", SIGUSR2, "turn off tracing" },
+#ifdef SIGWINCH
+ { "querylog", SIGWINCH, "toggle query logging" },
+ { "qrylog", SIGWINCH, "alias for querylog" },
+#endif
+ { NULL, 0 }
+};
+
+static void
+command_signals(void) {
+ struct cmdsig *cmdsig;
+ pid_t pid;
+ int sig;
+
+ if (strcasecmp(cmd, "help") == 0) {
+ printf(helpfmt, "help", "this output");
+ printf(helpfmt, "status", "check for running server");
+ printf(helpfmt, "stop", "stop the server");
+ builtinhelp();
+ for (cmdsig = cmdsigs; cmdsig->cmd != NULL; cmdsig++)
+ printf(helpfmt, cmdsig->cmd, cmdsig->help);
+ } else if (strcasecmp(cmd, "status") == 0) {
+ if (!fgetpid(pidfile, &pid))
+ error("pid not valid or server not running");
+ else
+ result("pid %ld is running", (long)pid);
+ } else if (strcasecmp(cmd, "stop") == 0) {
+ if (!fgetpid(pidfile, &pid))
+ error("name server not running");
+ else
+ stop_named(pid);
+ } else {
+ for (cmdsig = cmdsigs; cmdsig->cmd != NULL; cmdsig++)
+ if (strcasecmp(cmd, cmdsig->cmd) == 0)
+ break;
+ if (cmdsig->cmd == NULL)
+ error("unrecognized command (%s)", cmd);
+ else if (!fgetpid(pidfile, &pid))
+ error("can't get pid (%s)", pidfile);
+ else if (kill(pid, cmdsig->sig) < 0)
+ error("kill() failed - %s", strerror(errno));
+ else
+ trace("pid %ld sig %d OK", (long)pid, cmdsig->sig);
+ }
+}
+
+static void
+stop_named(pid_t pid) {
+ int n;
+
+ trace("stopping named (pid %ld)", (long)pid);
+ switch (mode) {
+ case e_signals:
+ if (kill(pid, SIGTERM) < 0) {
+ error("kill(%ld, SIGTERM) failed - %s",
+ (long)pid, strerror(errno));
+ return;
+ }
+ trace("SIGTERM ok, waiting for death");
+ break;
+ case e_channel:
+ channel_loop("stop", tracing, NULL, NULL);
+ break;
+ default:
+ abort();
+ }
+ for (n = 0; n < 10; n++) {
+ if (kill(pid, 0) != 0) {
+ trace("named (pid %ld) is dead", (long)pid);
+ return;
+ }
+ sleep(1);
+ }
+ error("named (pid %ld) didn't die", (long)pid);
+}
+
+static void
+start_named(const char *syscmd, int local_quiet) {
+ pid_t pid;
+
+ if (system(syscmd) != 0)
+ error("could not start new name server (%s)", syscmd);
+ else {
+ sleep(3);
+ if (!running(0, &pid))
+ error("name server has not started (yet?)");
+ else if (!local_quiet)
+ result("new pid is %ld", (long)pid);
+ }
+}
+
+static int
+fgetpid(const char *f, pid_t *pid) {
+ FILE *fp;
+ int try;
+ long t;
+
+ for (try = 0; try < 5; try++) {
+ trace("pidfile is \"%s\" (try #%d)", pidfile, try + 1);
+ if ((fp = fopen(pidfile, "r")) == NULL)
+ trace("pid file (%s) unavailable - %s",
+ pidfile, strerror(errno));
+ else if (fscanf(fp, "%ld\n", &t) != 1)
+ trace("pid file (%s) format is bad", pidfile);
+ else if (*pid = (pid_t)t, fclose(fp), kill(*pid, 0) < 0)
+ trace("pid file (%s) contains unusable pid (%d) - %s",
+ pidfile, *pid, strerror(errno));
+ else {
+ trace("pid is %ld", (long)*pid);
+ return (1);
+ }
+ sleep(1);
+ }
+ trace("pid not found");
+ return (0);
+}
+
+static int
+get_sockaddr(char *name, sockaddr_t *addr) {
+ char *slash;
+
+ if (name[0] == '/') {
+ memset(&addr->un, '\0', sizeof addr->un);
+ addr->un.sun_family = AF_UNIX;
+ strncpy(addr->un.sun_path, name, sizeof addr->un.sun_path - 1);
+ addr->un.sun_path[sizeof addr->un.sun_path - 1] = '\0';
+ } else if ((slash = strrchr(name, '/')) != NULL) {
+ *slash = '\0';
+ memset(&addr->in, '\0', sizeof addr->in);
+ if (!inet_pton(AF_INET, name, &addr->in.sin_addr))
+ usage("bad ip address (%s)", name);
+ if ((addr->in.sin_port = htons(atoi(slash+1))) == 0)
+ usage("bad ip port (%s)", slash+1);
+ addr->in.sin_family = AF_INET;
+ *slash = ':';
+ } else {
+ return (0);
+ }
+ return (1);
+}
+
+static size_t
+impute_addrlen(const struct sockaddr *sa) {
+ if (sa == 0)
+ return (0);
+ switch (sa->sa_family) {
+ case AF_INET:
+ return (sizeof(struct sockaddr_in));
+ case AF_UNIX:
+ return (sizeof(struct sockaddr_un));
+ default:
+ abort();
+ }
+}
+
+static void
+vtrace(const char *fmt, va_list ap) {
+ if (tracing) {
+ fprintf(stdout, "%s: [", program);
+ vfprintf(stdout, fmt, ap);
+ fputs("]\n", stdout);
+ }
+}
+
+static void
+trace(const char *fmt, ...) {
+ va_list args;
+
+ va_start(args, fmt);
+ vtrace(fmt, args);
+ va_end(args);
+}
+
+static void
+result(const char *fmt, ...) {
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stdout, fmt, args);
+ fputc('\n', stdout);
+ va_end(args);
+}
+
+static void
+fatal(const char *fmt, ...) {
+ va_list args;
+
+ va_start(args, fmt);
+ fprintf(stderr, "%s: fatal error: ", program);
+ vfprintf(stderr, fmt, args);
+ fputc('\n', stderr);
+ va_end(args);
+ exit(1);
+}
+
+static void
+verror(const char *fmt, va_list ap) {
+ fprintf(stderr, "%s: error: ", program);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ errors++;
+}
+
+static void
+error(const char *fmt, ...) {
+ va_list args;
+
+ va_start(args, fmt);
+ if (silent)
+ vtrace(fmt, args);
+ else
+ verror(fmt, args);
+ va_end(args);
+}
diff --git a/contrib/bind/bin/nslookup/Makefile b/contrib/bind/bin/nslookup/Makefile
index 15cc94f..0f6db20 100644
--- a/contrib/bind/bin/nslookup/Makefile
+++ b/contrib/bind/bin/nslookup/Makefile
@@ -1,4 +1,4 @@
-## Copyright (c) 1996 by Internet Software Consortium
+## Copyright (c) 1996,1999 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
@@ -13,7 +13,7 @@
## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
## SOFTWARE.
-# $Id: Makefile,v 8.18 1997/12/03 22:55:16 halley Exp $
+# $Id: Makefile,v 8.24 1999/10/13 01:14:46 vixie Exp $
DESTDIR=
CC= cc
@@ -29,18 +29,20 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include
LIBBIND = ${TOP}/lib/libbind.a
A=a
O=o
+EXE=
LEX = lex -I
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
STRIP=-s
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
LDFLAGS=
-DEFS= -D_PATH_HELPFILE=\"${DESTDIR}${DESTHELP}/nslookup.help\"
+DEFS= -D_PATH_HELPFILE=\"${DESTHELP}/nslookup.help\"
CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} ${DEFS}
PROG= nslookup
@@ -49,17 +51,20 @@ SRCS= ${CSRCS} commands.l
OBJS= main.${O} getinfo.${O} debug.${O} send.${O} skip.${O} list.${O} \
subr.${O} commands.${O}
-all: ${PROG}
+all: ${PROG}${EXE}
-${PROG}: ${OBJS} ${LIBBIND} Makefile
- ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} \
+${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile
+ ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \
${LIBBIND} ${SYSLIBS}
+.c.${O}:
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c
+
distclean: clean
rm -f commands.c
clean: FRC
- rm -f ${PROG} ${OBJS} core .depend
+ rm -f ${PROG}${EXE} ${OBJS} core .depend
rm -f *.BAK *.CKP *~ *.orig
rm -f lex.yy.c lex.yy.o
@@ -72,9 +77,9 @@ ${DESTDIR}${DESTHELP}:
${DESTDIR}${DESTBIN}:
mkdir -p ${DESTDIR}${DESTBIN}
-install: ${DESTDIR}${DESTBIN} ${DESTDIR}${DESTHELP} ${PROG}
- ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTBIN}/${PROG}
- ${INSTALL} -c -o bin -g bin -m 444 nslookup.help ${DESTDIR}${DESTHELP}/
+install: ${DESTDIR}${DESTBIN} ${DESTDIR}${DESTHELP} ${PROG}${EXE}
+ ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE}
+ ${INSTALL} -c ${INSTALL_LIB} -m 444 nslookup.help ${DESTDIR}${DESTHELP}/
links: FRC
@set -e; ln -s SRC/*.[chl] SRC/nslookup.help .
diff --git a/contrib/bind/bin/nslookup/list.c b/contrib/bind/bin/nslookup/list.c
index 6d23e57..1b7f452 100644
--- a/contrib/bind/bin/nslookup/list.c
+++ b/contrib/bind/bin/nslookup/list.c
@@ -52,8 +52,8 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)list.c 5.23 (Berkeley) 3/21/91";
-static char rcsid[] = "$Id: list.c,v 8.13 1997/11/18 00:32:33 halley Exp $";
+static const char sccsid[] = "@(#)list.c 5.23 (Berkeley) 3/21/91";
+static const char rcsid[] = "$Id: list.c,v 8.21 1999/10/15 19:49:08 vixie Exp $";
#endif /* not lint */
/*
@@ -91,7 +91,6 @@ static char rcsid[] = "$Id: list.c,v 8.13 1997/11/18 00:32:33 halley Exp $";
#include "res.h"
-extern char *_res_resultcodes[]; /* res_debug.c */
extern char *pager;
typedef union {
@@ -151,14 +150,28 @@ int ListSubr();
void
ListHostsByType(char *string, int putToFile) {
char *namePtr, name[NAME_LEN], option[NAME_LEN];
- int i, qtype, result;
+ int i, j, qtype, result;
/*
* Parse the command line. It maybe of the form "ls -t domain"
* or "ls -t type domain".
*/
- i = sscanf(string, " ls -t %s %s", option, name);
+ /* simulate sscanf(string, " ls -t %s %s", option, name) */
+ i = matchString(" ls -t ", string);
+ if (i > 0) {
+ j = pickString(string + i, option, sizeof option);
+ if (j > 0) {
+ j = pickString(string + i + j, name, sizeof name);
+ if (j > 0)
+ i = 2;
+ else
+ i = 1;
+ } else {
+ i = 0;
+ }
+ }
+
if (putToFile && i == 2 && name[0] == '>')
i--;
if (i == 2) {
@@ -182,13 +195,28 @@ ListHostsByType(char *string, int putToFile) {
void
ListHosts(char *string, int putToFile) {
char *namePtr, name[NAME_LEN], option[NAME_LEN];
- int i, qtype, result;
+ int i, j, qtype, result;
/*
* Parse the command line. It maybe of the form "ls domain",
* "ls -X domain".
*/
- i = sscanf(string, " ls %s %s", option, name);
+
+ /* simulate i = sscanf(string, " ls %s %s", option, name) */
+ i = matchString(" ls ", string);
+ if (i > 0) {
+ j = pickString(string + i, option, sizeof option);
+ if (j > 0) {
+ j = pickString(string + i + j, name, sizeof name);
+ if (j > 0)
+ i = 2;
+ else
+ i = 1;
+ } else {
+ i = 0;
+ }
+ }
+
if (putToFile && i == 2 && name[0] == '>')
i--;
if (i == 2) {
@@ -236,18 +264,18 @@ ListSubr(int qtype, char *domain, char *cmd) {
int numAnswers = 0;
int numRecords = 0;
u_char tmp[INT16SZ], *cp;
- char soaname[2][NAME_LEN], file[NAME_LEN];
+ char soaname[2][NAME_LEN], file[PATH_MAX];
enum { NO_ERRORS, ERR_READING_LEN, ERR_READING_MSG, ERR_PRINTING }
error = NO_ERRORS;
/*
* Create a query packet for the requested domain name.
*/
- msglen = res_mkquery(QUERY, domain, queryClass, T_AXFR,
- NULL, 0, 0, buf.qb2, sizeof buf);
+ msglen = res_nmkquery(&res, QUERY, domain, queryClass, T_AXFR,
+ NULL, 0, 0, buf.qb2, sizeof buf);
if (msglen < 0) {
if (_res.options & RES_DEBUG)
- fprintf(stderr, "*** ls: res_mkquery failed\n");
+ fprintf(stderr, "*** ls: res_nmkquery failed\n");
return (ERROR);
}
@@ -308,7 +336,7 @@ ListSubr(int qtype, char *domain, char *cmd) {
if (cmd == NULL) {
filePtr = stdout;
} else {
- filePtr = OpenFile(cmd, file);
+ filePtr = OpenFile(cmd, file, sizeof file);
if (filePtr == NULL) {
fprintf(stderr, "*** Can't open %s for writing\n",
file);
@@ -405,7 +433,7 @@ ListSubr(int qtype, char *domain, char *cmd) {
break;
}
strcpy(name_ctx, name);
- numAnswers++;
+ numRecords++;
fputs(buf, filePtr);
fputc('\n', filePtr);
}
@@ -413,9 +441,13 @@ ListSubr(int qtype, char *domain, char *cmd) {
strcpy(soaname[soacnt], name);
if (soacnt == 0)
soacnt = 1;
- else if (strcasecmp(soaname[0],
- soaname[1]) == 0) {
+ else if (ns_samename(soaname[0],
+ soaname[1]) == 1) {
soacnt = 2;
+ /* This means we're finished.
+ * But we've to reset origin and
+ * name_ctx now ! */
+ origin[0] = name_ctx[0] ='\0';
}
}
}
@@ -456,7 +488,7 @@ ListSubr(int qtype, char *domain, char *cmd) {
fprintf(stderr,"*** ls: error receiving zone transfer:\n");
fprintf(stderr,
" result: %s, answers = %d, authority = %d, additional = %d\n",
- _res_resultcodes[headerPtr->rcode],
+ p_rcode(headerPtr->rcode),
ntohs(headerPtr->ancount), ntohs(headerPtr->nscount),
ntohs(headerPtr->arcount));
return (ERROR);
@@ -476,14 +508,46 @@ ListSubr(int qtype, char *domain, char *cmd) {
*******************************************************************************
*/
-ViewList(string)
- char *string;
-{
+void
+ViewList(char *string) {
char file[PATH_MAX];
char command[PATH_MAX];
+ int i, j;
+ char soafile[PATH_MAX];
+
+ /* sscanf(string, " view %s", file); */
+ i = matchString(" view ", string);
+ if (i > 0) {
+ j = pickString(string + i, file, sizeof file);
+ if (j == 0) {
+ fprintf(stderr, "*** invalid file name: %s\n", string + i);
+ return ;
+ }
+ }
- sscanf(string, " view %s", file);
- (void)sprintf(command, "grep \"^ \" %s | sort | %s", file, pager);
+ if ( !mktemp(strcpy(soafile,"/var/tmp/nslookup_tmpXXXXXX"))) {
+ fprintf(stderr, "*** cannot create temp file\n");
+ return ;
+ }
+ (void)sprintf(command, "sed '\
+/^$/,${\
+/@/,$d\
+}\
+/^[^ ]/{\
+h\
+s/^\\([^ ]* *\\).*/\\1/\
+x\
+}\
+1,/^$/{\
+w %s\
+d\
+}\
+/^ /{\
+G\
+s/^ *//\
+s/^\\(.*\\)\\n\\(.*\\)$/\\2\\1/\
+}' %s | sort | (cat %s -; rm %s) | %s",
+ soafile, file, soafile, soafile, pager);
system(command);
}
@@ -515,7 +579,8 @@ Finger(string, putToFile)
int c;
int lastc;
char name[NAME_LEN];
- char file[NAME_LEN];
+ char file[PATH_MAX];
+ int i;
/*
* We need a valid current host info to get an inet address.
@@ -525,7 +590,20 @@ Finger(string, putToFile)
return (ERROR);
}
- if (sscanf(string, " finger %s", name) == 1) {
+ /* simulate: sscanf("finger %s") ; */
+
+ i = matchString(" finger ", string);
+ if (i > 0) {
+ i = pickString(string + i, name, sizeof name);
+ if (i > 0) {
+ i = 1 ;
+ }
+ /* note that if the argument to the finger command is
+ bigger than sizeof name it will be treated as if there
+ was no argument. */
+ }
+
+ if (i == 1) {
if (putToFile && (name[0] == '>')) {
name[0] = '\0';
}
@@ -566,7 +644,7 @@ Finger(string, putToFile)
if (!putToFile) {
filePtr = stdout;
} else {
- filePtr = OpenFile(string, file);
+ filePtr = OpenFile(string, file, sizeof file);
if (filePtr == NULL) {
fprintf(stderr, "*** Can't open %s for writing\n", file);
close(sockFD);
@@ -613,6 +691,7 @@ Finger(string, putToFile)
return (SUCCESS);
}
+void
ListHost_close()
{
if (sockFD != -1) {
diff --git a/contrib/bind/bin/nslookup/res.h b/contrib/bind/bin/nslookup/res.h
index cffbe3c..5ffd6ce 100644
--- a/contrib/bind/bin/nslookup/res.h
+++ b/contrib/bind/bin/nslookup/res.h
@@ -55,7 +55,7 @@
/*
* @(#)res.h 5.10 (Berkeley) 6/1/90
- * $Id: res.h,v 8.4 1996/12/04 09:38:59 vixie Exp $
+ * $Id: res.h,v 8.5 1998/09/16 17:03:17 vixie Exp $
*/
/*
@@ -156,6 +156,11 @@ extern FILE *filePtr;
extern unsigned short nsport;
/*
+ * Our resolver context.
+ */
+extern struct __res_state res;
+
+/*
* External routines:
*/
diff --git a/contrib/bind/bin/nslookup/send.c b/contrib/bind/bin/nslookup/send.c
index e9ca590..61a8751 100644
--- a/contrib/bind/bin/nslookup/send.c
+++ b/contrib/bind/bin/nslookup/send.c
@@ -52,8 +52,8 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)send.c 5.18 (Berkeley) 3/2/91";
-static char rcsid[] = "$Id: send.c,v 8.6 1997/05/21 19:49:58 halley Exp $";
+static const char sccsid[] = "@(#)send.c 5.18 (Berkeley) 3/2/91";
+static const char rcsid[] = "$Id: send.c,v 8.9 1999/10/13 16:39:19 vixie Exp $";
#endif /* not lint */
/*
@@ -95,18 +95,6 @@ static char rcsid[] = "$Id: send.c,v 8.6 1997/05/21 19:49:58 halley Exp $";
static int s = -1; /* socket used for communications */
-
-#ifndef FD_SET
-#define NFDBITS 32
-#define FD_SETSIZE 32
-#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
-#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
-#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
-#define FD_ZERO(p) memset((p), 0, sizeof(*(p)))
-#endif
-
-
-
unsigned short nsport = NAMESERVER_PORT;
@@ -148,19 +136,19 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
char junk[512];
struct sockaddr_in sin, sa;
- if (_res.options & RES_DEBUG2) {
+ if (res.options & RES_DEBUG2) {
printf("------------\nSendRequest(), len %d\n", buflen);
Print_query(buf, buf + buflen, 1);
}
sin.sin_family = AF_INET;
sin.sin_port = htons(nsport);
sin.sin_addr = *nsAddrPtr;
- v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
+ v_circuit = (res.options & RES_USEVC) || buflen > PACKETSZ;
id = hp->id;
/*
* Send request, RETRY times, or until successful
*/
- for (try = 0; try < _res.retry; try++) {
+ for (try = 0; try < res.retry; try++) {
usevc:
if (v_circuit) {
int truncated = 0;
@@ -169,19 +157,19 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
* Use virtual circuit;
* at most one attempt per server.
*/
- try = _res.retry;
+ try = res.retry;
if (s < 0) {
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
terrno = errno;
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
perror("socket (vc) failed");
continue;
}
if (connect(s, (struct sockaddr *)&sin,
sizeof(struct sockaddr)) < 0) {
terrno = errno;
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
perror("connect failed");
(void) close(s);
s = -1;
@@ -198,7 +186,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
iov[1].iov_len = buflen;
if (writev(s, iov, 2) != INT16SZ + buflen) {
terrno = errno;
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
perror("write failed");
(void) close(s);
s = -1;
@@ -216,7 +204,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
}
if (n <= 0) {
terrno = errno;
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
perror("read failed");
(void) close(s);
s = -1;
@@ -236,7 +224,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
}
cp = answer;
if ((resplen = ns_get16((u_char*)cp)) > anslen) {
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
fprintf(stderr, "response truncated\n");
len = anslen;
truncated = 1;
@@ -249,7 +237,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
}
if (n <= 0) {
terrno = errno;
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
perror("read failed");
(void) close(s);
s = -1;
@@ -279,7 +267,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
terrno = errno;
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
perror("socket (dg) failed");
continue;
}
@@ -288,14 +276,14 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
if (connected == 0) {
if (connect(s, (struct sockaddr *)&sin,
sizeof sin) < 0) {
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
perror("connect");
continue;
}
connected = 1;
}
if (send(s, buf, buflen, 0) != buflen) {
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
perror("send");
continue;
}
@@ -303,7 +291,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
if (sendto(s, (const char *)buf, buflen, 0,
(struct sockaddr *) &sin,
sizeof sin) != buflen) {
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
perror("sendto");
continue;
}
@@ -312,7 +300,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
/*
* Wait for reply
*/
- timeout.tv_sec = (_res.retrans << try);
+ timeout.tv_sec = (res.retrans << try);
if (timeout.tv_sec <= 0)
timeout.tv_sec = 1;
timeout.tv_usec = 0;
@@ -322,7 +310,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
n = select(s+1, &dsmask, (fd_set *)NULL,
(fd_set *)NULL, &timeout);
if (n < 0) {
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
perror("select");
continue;
}
@@ -330,7 +318,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
/*
* timeout
*/
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
printf("timeout\n");
#if BSD >= 43
gotsomewhere = 1;
@@ -342,7 +330,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
resplen = recvfrom(s, (char *)answer, anslen, 0,
(struct sockaddr *)&sa, &salen);
if (resplen <= 0) {
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
perror("recvfrom");
continue;
}
@@ -351,18 +339,18 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
/*
* response from old query, ignore it
*/
- if (_res.options & RES_DEBUG2) {
+ if (res.options & RES_DEBUG2) {
printf("------------\nOld answer:\n");
Print_query(answer, answer+resplen, 1);
}
goto wait;
}
- if (!(_res.options & RES_IGNTC) && anhp->tc) {
+ if (!(res.options & RES_IGNTC) && anhp->tc) {
/*
* get rest of answer;
* use TCP with same server.
*/
- if (_res.options & RES_DEBUG)
+ if (res.options & RES_DEBUG)
printf("truncated answer\n");
(void) close(s);
s = -1;
@@ -370,8 +358,8 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen,
goto usevc;
}
}
- if (_res.options & RES_DEBUG) {
- if (_res.options & RES_DEBUG2)
+ if (res.options & RES_DEBUG) {
+ if (res.options & RES_DEBUG2)
printf("------------\nGot answer (%d bytes):\n",
resplen);
else
diff --git a/contrib/bind/bin/nslookup/skip.c b/contrib/bind/bin/nslookup/skip.c
index 0290d98..5318ef6 100644
--- a/contrib/bind/bin/nslookup/skip.c
+++ b/contrib/bind/bin/nslookup/skip.c
@@ -52,8 +52,8 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)skip.c 5.12 (Berkeley) 3/21/91";
-static char rcsid[] = "$Id: skip.c,v 8.4 1997/04/25 00:27:19 vixie Exp $";
+static const char sccsid[] = "@(#)skip.c 5.12 (Berkeley) 3/21/91";
+static const char rcsid[] = "$Id: skip.c,v 8.5 1999/10/13 16:39:20 vixie Exp $";
#endif /* not lint */
/*
diff --git a/contrib/bind/bin/nslookup/subr.c b/contrib/bind/bin/nslookup/subr.c
index cefc2eb..a3b9f96 100644
--- a/contrib/bind/bin/nslookup/subr.c
+++ b/contrib/bind/bin/nslookup/subr.c
@@ -52,8 +52,8 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)subr.c 5.24 (Berkeley) 3/2/91";
-static char rcsid[] = "$Id: subr.c,v 8.9 1997/04/25 00:27:19 vixie Exp $";
+static const char sccsid[] = "@(#)subr.c 5.24 (Berkeley) 3/2/91";
+static const char rcsid[] = "$Id: subr.c,v 8.13 1999/10/13 16:39:20 vixie Exp $";
#endif /* not lint */
/*
@@ -126,6 +126,7 @@ IntrHandler()
extern FILE *yyin; /* scanner input file */
extern void yyrestart(); /* routine to restart scanner after interrupt */
#endif
+ extern void ListHost_close(void);
SendRequest_close();
ListHost_close();
@@ -204,9 +205,8 @@ Malloc(size)
fflush(stderr);
abort();
/*NOTREACHED*/
- } else {
- return(ptr);
}
+ return (ptr);
}
char *
@@ -324,7 +324,8 @@ PrintHostInfo(file, title, hp)
* OpenFile --
*
* Parses a command string for a file name and opens
- * the file.
+ * the file. The file name is copued to the argument FILE. The
+ * parameter SIZE parameter includes space for a null byte.
*
* Results:
* file pointer - the open was successful.
@@ -335,12 +336,14 @@ PrintHostInfo(file, title, hp)
*/
FILE *
-OpenFile(string, file)
+OpenFile(string, file, size)
char *string;
char *file;
+ size_t size;
{
char *redirect;
FILE *tmpPtr;
+ int i;
/*
* Open an output file if we see '>' or >>'.
@@ -351,12 +354,18 @@ OpenFile(string, file)
if (redirect == NULL) {
return(NULL);
}
+
+ tmpPtr = NULL;
if (redirect[1] == '>') {
- sscanf(redirect, ">> %s", file);
- tmpPtr = fopen(file, "a+");
+ i = pickString(redirect + 2, file, size);
+ if (i > 0) {
+ tmpPtr = fopen(file, "a+");
+ }
} else {
- sscanf(redirect, "> %s", file);
- tmpPtr = fopen(file, "w");
+ i = pickString(redirect + 1, file, size);
+ if (i > 0) {
+ tmpPtr = fopen(file, "w");
+ }
}
if (tmpPtr != NULL) {
@@ -473,3 +482,110 @@ DecodeType(type)
return (sym_ntop(__p_type_syms, type, (int *)0));
}
+
+
+
+
+/*
+ * Skip over leading white space in SRC and then copy the next sequence of
+ * non-whitespace characters into DEST. No more than (DEST_SIZE - 1)
+ * characters are copied. DEST is always null-terminated. Returns 0 if no
+ * characters could be copied into DEST. Returns the number of characters
+ * in SRC that were processed (i.e. the count of characters in the leading
+ * white space and the first non-whitespace sequence).
+ *
+ * int i;
+ * char *p = " foo bar ", *q;
+ * char buf[100];
+ *
+ * q = p + pickString(p, buf, sizeof buff);
+ * assert (strcmp (q, " bar ") == 0) ;
+ *
+ */
+
+int
+pickString(const char *src, char *dest, size_t dest_size) {
+ const char *start;
+ const char *end ;
+ size_t sublen ;
+
+ if (dest_size == 0 || dest == NULL || src == NULL)
+ return 0;
+
+ for (start = src ; isspace(*start) ; start++)
+ /* nada */ ;
+
+ for (end = start ; *end != '\0' && !isspace(*end) ; end++)
+ /* nada */ ;
+
+ sublen = end - start ;
+
+ if (sublen == 0 || sublen > (dest_size - 1))
+ return 0;
+
+ strncpy (dest, start, sublen);
+
+ dest[sublen] = '\0' ;
+
+ return (end - src);
+}
+
+
+
+
+/*
+ * match the string FORMAT against the string SRC. Leading whitespace in
+ * FORMAT will match any amount of (including no) leading whitespace in
+ * SRC. Any amount of whitespace inside FORMAT matches any non-zero amount
+ * of whitespace in SRC. Value returned is 0 if match didn't occur, or the
+ * amount of characters in SRC that did match
+ *
+ * int i ;
+ *
+ * i = matchString(" a b c", "a b c") ;
+ * assert (i == 5) ;
+ * i = matchString("a b c", " a b c");
+ * assert (i == 0) ; becasue no leading white space in format
+ * i = matchString(" a b c", " a b c");
+ * assert(i == 12);
+ * i = matchString("aa bb ", "aa bb ddd sd");
+ * assert(i == 16);
+ */
+int
+matchString (const char *format, const char *src) {
+ const char *f = format;
+ const char *s = src;
+
+ if (f == NULL || s == NULL)
+ goto notfound;
+
+ if (isspace(*f)) {
+ while (isspace(*f))
+ f++ ;
+ while (isspace(*s))
+ s++ ;
+ }
+
+ while (1) {
+ if (isspace(*f)) {
+ if (!isspace(*s))
+ goto notfound;
+ while(isspace(*s))
+ s++;
+ /* any amount of whitespace in the format string
+ will match any amount of space in the source
+ string. */
+ while (isspace(*f))
+ f++;
+ } else if (*f == '\0') {
+ return (s - src);
+ } else if (*f != *s) {
+ goto notfound;
+ } else {
+ s++ ;
+ f++ ;
+ }
+ }
+ notfound:
+ return 0 ;
+}
diff --git a/contrib/bind/bin/nsupdate/Makefile b/contrib/bind/bin/nsupdate/Makefile
index 46806b6..b3b07c0 100644
--- a/contrib/bind/bin/nsupdate/Makefile
+++ b/contrib/bind/bin/nsupdate/Makefile
@@ -1,4 +1,4 @@
-## Copyright (c) 1996 by Internet Software Consortium
+## Copyright (c) 1996,1999 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
@@ -13,7 +13,7 @@
## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
## SOFTWARE.
-# $Id: Makefile,v 8.18 1997/06/19 03:22:11 halley Exp $
+# $Id: Makefile,v 8.24 1999/08/08 17:51:02 vixie Exp $
DESTDIR=
CC= cc
@@ -29,15 +29,17 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include
LIBBIND = ${TOP}/lib/libbind.a
A=a
O=o
+EXE=
LEX = lex -I
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
STRIP=-s
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
LDFLAGS=
CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL}
@@ -46,26 +48,29 @@ PROG= nsupdate
SRCS= ${PROG}.c
OBJS= ${PROG}.${O}
-all: ${PROG}
+all: ${PROG}${EXE}
-${PROG}: ${OBJS} ${LIBBIND} Makefile
- ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} \
+${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile
+ ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \
${LIBBIND} ${SYSLIBS}
+.c.${O}:
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c
+
distclean: clean
clean: FRC
- rm -f ${PROG} ${OBJS} core .depend
+ rm -f ${PROG}${EXE} ${OBJS} core .depend
rm -f *.BAK *.CKP *~ *.orig
depend: ${SRCS}
- mkdep -p ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
+ mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS}
${DESTDIR}${DESTBIN}:
mkdir -p ${DESTDIR}${DESTBIN}
-install: ${DESTDIR}${DESTBIN} ${PROG}
- ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTBIN}/${PROG}
+install: ${DESTDIR}${DESTBIN} ${PROG}${EXE}
+ ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE}
links: FRC
@set -e; ln -s SRC/*.[ch] .
diff --git a/contrib/bind/bin/nsupdate/nsupdate.c b/contrib/bind/bin/nsupdate/nsupdate.c
index 2b31716..a02d0ad 100644
--- a/contrib/bind/bin/nsupdate/nsupdate.c
+++ b/contrib/bind/bin/nsupdate/nsupdate.c
@@ -1,9 +1,9 @@
#if !defined(lint) && !defined(SABER)
-static char rcsid[] = "$Id: nsupdate.c,v 8.5 1998/02/14 20:54:48 halley Exp $";
+static const char rcsid[] = "$Id: nsupdate.c,v 8.21 1999/10/19 22:22:59 cyarnell Exp $";
#endif /* not lint */
/*
- * Copyright (c) 1996 by Internet Software Consortium.
+ * Copyright (c) 1996,1999 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
@@ -20,20 +20,28 @@ static char rcsid[] = "$Id: nsupdate.c,v 8.5 1998/02/14 20:54:48 halley Exp $";
*/
#include "port_before.h"
+
#include <sys/param.h>
#include <sys/socket.h>
+
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
+
+#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <netdb.h>
#include <resolv.h>
+#include <res_update.h>
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include <string.h>
#include <ctype.h>
+#include <isc/dst.h>
#include "port_after.h"
+#include "../named/db_defs.h"
/* XXX all of this stuff should come from libbind.a */
@@ -74,8 +82,19 @@ struct map type_strs[] = {
{ "rt", T_RT },
{ "nsap", T_NSAP },
{ "nsap_ptr", T_NSAP_PTR },
+ { "sig", T_SIG },
+ { "key", T_KEY },
{ "px", T_PX },
{ "loc", T_LOC },
+ { "nxt", T_NXT },
+ { "eid", T_EID },
+ { "nimloc", T_NIMLOC },
+ { "srv", T_SRV },
+ { "atma", T_ATMA },
+ { "naptr", T_NAPTR },
+ { "kx", ns_t_kx },
+ { "cert", ns_t_cert },
+ { "aaaa", ns_t_aaaa },
};
#define M_TYPE_CNT (sizeof(type_strs) / sizeof(struct map))
@@ -97,12 +116,17 @@ struct map opcode_strs[] = {
};
#define M_OPCODE_CNT (sizeof(opcode_strs) / sizeof(struct map))
+static int getcharstring(char *, char *, int, int, int);
static char *progname;
-static FILE *log;
static void usage(void);
static int getword_str(char *, int, char **, char *);
+static struct __res_state res;
+
+int dns_findprimary (res_state, char *, struct ns_tsig_key *, char *,
+ int, struct in_addr *);
+
/*
* format of file read by nsupdate is kept the same as the log
* file generated by updates, so that the log file can be fed
@@ -123,27 +147,32 @@ main(argc, argv)
{
FILE *fp = NULL;
char buf[BUFSIZ], buf2[BUFSIZ], hostbuf[100], filebuf[100];
- char dnbuf[MAXDNAME];
+ char dnbuf[MAXDNAME], data[MAXDATA];
u_char packet[PACKETSZ], answer[PACKETSZ];
char *host = hostbuf, *batchfile = filebuf;
char *r_dname, *cp, *startp, *endp, *svstartp;
char section[15], opcode[10];
int i, c, n, n1, inside, lineno = 0, vc = 0,
debug = 0, r_size, r_section, r_opcode,
- prompt = 0, ret = 0;
+ prompt = 0, ret = 0, stringtobin = 0;
int16_t r_class, r_type;
u_int32_t r_ttl;
struct map *mp;
- ns_updrec *rrecp_start = NULL, *rrecp, *tmprrecp;
+ ns_updrec *rrecp;
+ ns_updque listuprec;
struct in_addr hostaddr;
extern int getopt();
extern char *optarg;
extern int optind, opterr, optopt;
+ ns_tsig_key key;
+ char *keyfile=NULL, *keyname=NULL, *p, *pp;
+ int file_major, file_minor, alg;
+
progname = argv[0];
- while ((c = getopt(argc, argv, "dv")) != EOF) {
+ while ((c = getopt(argc, argv, "dsvk:n:")) != -1) {
switch (c) {
case 'v':
vc = 1;
@@ -151,11 +180,130 @@ main(argc, argv)
case 'd':
debug = 1;
break;
+ case 's':
+ stringtobin = 1;
+ break;
+ case 'k': {
+ /* -k keydir:keyname */
+ char *colon;
+
+ if ((colon=strchr(optarg, ':'))==NULL) {
+ fprintf(stderr, "key option argument should be keydir:keyname\n");
+ exit(1);
+ }
+ keyname=colon+1;
+ keyfile=optarg;
+ *colon='\0';
+ break;
+ }
+ case 'n':
+ keyname=optarg;
+ break;
default:
usage();
}
}
+ if (keyfile) {
+#ifdef PARSE_KEYFILE
+ if ((fp=fopen(keyfile, "r"))==NULL) {
+ perror("open keyfile");
+ exit(1);
+ }
+ /* now read the header info from the file */
+ if ((i=fread(buf, 1, BUFSIZ, fp)) < 5) {
+ fclose(fp);
+ exit(1);
+ }
+ fclose(fp);
+ fp=NULL;
+
+ p=buf;
+
+ n=strlen(p); /* get length of strings */
+ n1=strlen("Private-key-format: v");
+ if (n1 > n || strncmp(buf, "Private-key-format: v", n1)) {
+ fprintf(stderr, "Invalid key file format\n");
+ exit(1); /* not a match */
+ }
+ p+=n1; /* advance pointer */
+ sscanf((char *)p, "%d.%d", &file_major, &file_minor);
+ /* should do some error checking with these someday */
+ while (*p++!='\n'); /* skip to end of line */
+
+ n=strlen(p); /* get length of strings */
+ n1=strlen("Algorithm: ");
+ if (n1 > n || strncmp(p, "Algorithm: ", n1)) {
+ fprintf(stderr, "Invalid key file format\n");
+ exit(1); /* not a match */
+ }
+ p+=n1; /* advance pointer */
+ if (sscanf((char *)p, "%d", &alg)!=1) {
+ fprintf(stderr, "Invalid key file format\n");
+ exit(1);
+ }
+ while (*p++!='\n'); /* skip to end of line */
+
+ n=strlen(p); /* get length of strings */
+ n1=strlen("Key: ");
+ if (n1 > n || strncmp(p, "Key: ", n1)) {
+ fprintf(stderr, "Invalid key file format\n");
+ exit(1); /* not a match */
+ }
+ p+=n1; /* advance pointer */
+ pp=p;
+ while (*pp++!='\n'); /* skip to end of line, terminate it */
+ *--pp='\0';
+
+ key.data=malloc(1024*sizeof(char));
+ key.len=b64_pton(p, key.data, 1024);
+
+ strcpy(key.name, keyname);
+ strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT");
+#else
+ /* use the dst* routines to parse the key files
+ *
+ * This requires that both the .key and the .private files
+ * exist in your cwd, so the keyfile parmeter here is
+ * assumed to be a path in which the K*.{key,private} files
+ * exist.
+ */
+ DST_KEY *dst_key;
+ char cwd[PATH_MAX+1];
+
+ if (getcwd(cwd, PATH_MAX)==NULL) {
+ perror("unable to get current directory");
+ exit(1);
+ }
+ if (chdir(keyfile)<0) {
+ fprintf(stderr, "unable to chdir to %s: %s\n", keyfile,
+ strerror(errno));
+ exit(1);
+ }
+
+ dst_init();
+ dst_key = dst_read_key(keyname,
+ 0 /* not used for private keys */,
+ KEY_HMAC_MD5, DST_PRIVATE);
+ if (!dst_key) {
+ fprintf(stderr, "dst_read_key: error reading key\n");
+ exit(1);
+ }
+ key.data=malloc(1024*sizeof(char));
+ dst_key_to_buffer(dst_key, key.data, 1024);
+ key.len=dst_key->dk_key_size;
+
+ strcpy(key.name, keyname);
+ strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT");
+
+ if (chdir(cwd)<0) {
+ fprintf(stderr, "unable to chdir to %s: %s\n", cwd,
+ strerror(errno));
+ exit(1);
+ }
+#endif
+ }
+
if ((argc - optind) == 0) {
/* no file specified, read from stdin */
ret = system("tty -s");
@@ -383,7 +531,7 @@ main(argc, argv)
break;
default:
fprintf(stderr,
- "unknown operation in update section\"%s\"\n", opcode);
+ "unknown operation in update section \"%s\"\n", opcode);
exit (1);
}
break;
@@ -396,38 +544,60 @@ main(argc, argv)
if ( !(rrecp = res_mkupdrec(r_section, r_dname, r_class,
r_type, r_ttl)) ||
(r_size > 0 && !(rrecp->r_data = (u_char *)malloc(r_size))) ) {
+ if (rrecp)
+ res_freeupdrec(rrecp);
fprintf(stderr, "saverrec error\n");
exit (1);
}
+ if (stringtobin) {
+ switch(r_opcode) {
+ case T_HINFO:
+ if (!getcharstring(buf,(char *)data,2,2,lineno))
+ exit(1);
+ cp = data;
+ break;
+ case T_ISDN:
+ if (!getcharstring(buf,(char *)data,1,2,lineno))
+ exit(1);
+ cp = data;
+ break;
+ case T_TXT:
+ if (!getcharstring(buf,(char *)data,1,0,lineno))
+ exit(1);
+ cp = data;
+ break;
+ case T_X25:
+ if (!getcharstring(buf,(char *)data,1,1,lineno))
+ exit(1);
+ cp = data;
+ break;
+ default:
+ break;
+ }
+ }
rrecp->r_opcode = r_opcode;
rrecp->r_size = r_size;
(void) strncpy((char *)rrecp->r_data, cp, r_size);
- /* append current record to the end of linked list of
- * records seen so far */
- if (rrecp_start == NULL)
- rrecp_start = rrecp;
- else {
- tmprrecp = rrecp_start;
- while (tmprrecp->r_next != NULL)
- tmprrecp = tmprrecp->r_next;
- tmprrecp->r_next = rrecp;
- }
+ APPEND(listuprec, rrecp, r_link);
} else { /* end of an update packet */
- (void) res_init();
+ (void) res_ninit(&res);
if (vc)
- _res.options |= RES_USEVC | RES_STAYOPEN;
+ res.options |= RES_USEVC | RES_STAYOPEN;
if (debug)
- _res.options |= RES_DEBUG;
- if (rrecp_start) {
- if ((n = res_update(rrecp_start)) < 0)
- fprintf(stderr, "failed update packet\n");
- /* free malloc'ed memory */
- while(rrecp_start) {
- tmprrecp = rrecp_start;
- rrecp_start = rrecp_start->r_next;
- free((char *)tmprrecp->r_dname);
- free((char *)tmprrecp);
- }
+ res.options |= RES_DEBUG;
+ if (!EMPTY(listuprec)) {
+ n = res_nupdate(&res, HEAD(listuprec),
+ keyfile != NULL ? &key : NULL);
+ if (n < 0)
+ fprintf(stderr, "failed update packet\n");
+ while (!EMPTY(listuprec)) {
+ ns_updrec *tmprrecp = HEAD(listuprec);
+
+ UNLINK(listuprec, tmprrecp, r_link);
+ if (tmprrecp->r_size != 0)
+ free((char *)tmprrecp->r_data);
+ res_freeupdrec(tmprrecp);
+ }
}
}
} /* for */
@@ -436,7 +606,7 @@ main(argc, argv)
static void
usage() {
- fprintf(stderr, "Usage: %s [-d] [-v] [file]\n",
+ fprintf(stderr, "Usage: %s [ -k keydir:keyname ] [-d] [-v] [file]\n",
progname);
exit(1);
}
@@ -469,3 +639,51 @@ getword_str(char *buf, int size, char **startpp, char *endp) {
*cp = '\0';
return (cp != buf);
}
+
+#define MAXCHARSTRING 255
+
+static int
+getcharstring(char *buf, char *data,
+ int minfields, int maxfields, int lineno)
+{
+ int nfield = 0, n = 0, i;
+
+ do {
+ nfield++;
+ i = 0;
+ if (*buf == '"') {
+ buf++;
+ while(buf[i] && buf[i] != '"')
+ i++;
+ } else {
+ while(isspace(*buf))
+ i++;
+ }
+ if (i > MAXCHARSTRING) {
+ fprintf(stderr,
+ "%d: RDATA field %d too long",
+ lineno, nfield);
+ return(0);
+ }
+ if (n + i + 1 > MAXDATA) {
+ fprintf(stderr,
+ "%d: total RDATA too long", lineno);
+ return(0);
+ }
+ data[n]=i;
+ memmove(data + 1 + n, buf, i);
+ buf += i + 1;
+ n += i + 1;
+ while(*buf && isspace(*buf))
+ buf++;
+ } while (nfield < maxfields && *buf);
+
+ if (nfield < minfields) {
+ fprintf(stderr,
+ "%d: expected %d RDATA fields, only saw %d",
+ lineno, minfields, nfield);
+ return (0);
+ }
+
+ return (n);
+}
OpenPOWER on IntegriCloud