From 4ef23ce6957fc75fc005885496d605fed48213e1 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 30 Nov 1999 02:43:11 +0000 Subject: Import bind v8.2.2.p5, minus the crypto for the time being. The bind package does have BXA export approval, but the licensing strings on the dnssafe code are a bit unpleasant. The crypto is easy to restore and bind will run without it - just without full dnssec support. Obtained from: The Internet Software Consortium (www.isc.org) --- contrib/bind/bin/Makefile | 19 +- contrib/bind/bin/addr/Makefile | 25 +- contrib/bind/bin/addr/addr.c | 11 +- contrib/bind/bin/dig/Makefile | 27 +- contrib/bind/bin/dig/dig.c | 707 ++++-- contrib/bind/bin/dnskeygen/Makefile | 85 + contrib/bind/bin/dnskeygen/dnskeygen.c | 318 +++ contrib/bind/bin/dnsquery/Makefile | 25 +- contrib/bind/bin/dnsquery/dnsquery.c | 56 +- contrib/bind/bin/host/Makefile | 25 +- contrib/bind/bin/host/host.c | 867 ++++++-- contrib/bind/bin/irpd/Makefile | 98 + contrib/bind/bin/irpd/irpd.c | 2252 +++++++++++++++++++ contrib/bind/bin/irpd/irs-irpd.conf | 11 + contrib/bind/bin/irpd/version.c | 25 + contrib/bind/bin/mkservdb/Makefile | 83 + contrib/bind/bin/mkservdb/mkservdb.c | 169 ++ .../bind/bin/named-bootconf/Grot/named-bootconf.pl | 324 +++ contrib/bind/bin/named-bootconf/Makefile | 76 + contrib/bind/bin/named-bootconf/named-bootconf.sh | 306 +++ contrib/bind/bin/named-xfer/Makefile | 31 +- contrib/bind/bin/named-xfer/named-xfer.c | 1134 ++++++++-- contrib/bind/bin/named/Makefile | 54 +- contrib/bind/bin/named/db_defs.h | 108 +- contrib/bind/bin/named/db_dump.c | 64 +- contrib/bind/bin/named/db_func.h | 98 +- contrib/bind/bin/named/db_glob.h | 33 +- contrib/bind/bin/named/db_glue.c | 318 +-- contrib/bind/bin/named/db_ixfr.c | 861 ++++++++ contrib/bind/bin/named/db_load.c | 1750 +++++++++------ contrib/bind/bin/named/db_lookup.c | 106 +- contrib/bind/bin/named/db_save.c | 26 +- contrib/bind/bin/named/db_sec.c | 1097 ++++++++++ contrib/bind/bin/named/db_tsig.c | 158 ++ contrib/bind/bin/named/db_update.c | 141 +- contrib/bind/bin/named/named.conf | 41 +- contrib/bind/bin/named/named.h | 24 +- contrib/bind/bin/named/ns_config.c | 1153 ++++++++-- contrib/bind/bin/named/ns_ctl.c | 866 ++++++++ contrib/bind/bin/named/ns_defs.h | 272 ++- contrib/bind/bin/named/ns_forw.c | 367 +++- contrib/bind/bin/named/ns_func.h | 214 +- contrib/bind/bin/named/ns_glob.h | 41 +- contrib/bind/bin/named/ns_glue.c | 58 +- contrib/bind/bin/named/ns_init.c | 240 +- contrib/bind/bin/named/ns_ixfr.c | 563 +++++ contrib/bind/bin/named/ns_lexer.c | 95 +- contrib/bind/bin/named/ns_lexer.h | 8 +- contrib/bind/bin/named/ns_main.c | 1027 ++++++--- contrib/bind/bin/named/ns_maint.c | 901 ++++++-- contrib/bind/bin/named/ns_ncache.c | 156 +- contrib/bind/bin/named/ns_notify.c | 379 ++++ contrib/bind/bin/named/ns_parser.c | 2300 +++++++++++++------- contrib/bind/bin/named/ns_parser.h | 187 +- contrib/bind/bin/named/ns_parser.y | 637 +++++- contrib/bind/bin/named/ns_parseutil.c | 6 +- contrib/bind/bin/named/ns_parseutil.h | 8 +- contrib/bind/bin/named/ns_req.c | 843 +++++-- contrib/bind/bin/named/ns_resp.c | 1749 ++++++++++----- contrib/bind/bin/named/ns_signal.c | 264 +++ contrib/bind/bin/named/ns_sort.c | 410 ++++ contrib/bind/bin/named/ns_stats.c | 83 +- contrib/bind/bin/named/ns_udp.c | 5 +- contrib/bind/bin/named/ns_update.c | 959 ++++++-- contrib/bind/bin/named/ns_xfr.c | 302 ++- contrib/bind/bin/named/pathtemplate.h | 8 +- contrib/bind/bin/named/test/named.conf | 16 + contrib/bind/bin/named/version.c | 4 +- contrib/bind/bin/ndc/Makefile | 50 +- contrib/bind/bin/ndc/ndc.c | 698 ++++++ contrib/bind/bin/nslookup/Makefile | 27 +- contrib/bind/bin/nslookup/commands.c | 381 ++-- contrib/bind/bin/nslookup/commands.l | 5 +- contrib/bind/bin/nslookup/debug.c | 20 +- contrib/bind/bin/nslookup/getinfo.c | 84 +- contrib/bind/bin/nslookup/list.c | 127 +- contrib/bind/bin/nslookup/main.c | 253 ++- contrib/bind/bin/nslookup/res.h | 7 +- contrib/bind/bin/nslookup/send.c | 62 +- contrib/bind/bin/nslookup/skip.c | 4 +- contrib/bind/bin/nslookup/subr.c | 136 +- contrib/bind/bin/nsupdate/Makefile | 25 +- contrib/bind/bin/nsupdate/nsupdate.c | 282 ++- 83 files changed, 22710 insertions(+), 5125 deletions(-) create mode 100644 contrib/bind/bin/dnskeygen/Makefile create mode 100644 contrib/bind/bin/dnskeygen/dnskeygen.c create mode 100644 contrib/bind/bin/irpd/Makefile create mode 100644 contrib/bind/bin/irpd/irpd.c create mode 100644 contrib/bind/bin/irpd/irs-irpd.conf create mode 100644 contrib/bind/bin/irpd/version.c create mode 100644 contrib/bind/bin/mkservdb/Makefile create mode 100644 contrib/bind/bin/mkservdb/mkservdb.c create mode 100644 contrib/bind/bin/named-bootconf/Grot/named-bootconf.pl create mode 100644 contrib/bind/bin/named-bootconf/Makefile create mode 100644 contrib/bind/bin/named-bootconf/named-bootconf.sh create mode 100644 contrib/bind/bin/named/db_ixfr.c create mode 100644 contrib/bind/bin/named/db_sec.c create mode 100644 contrib/bind/bin/named/db_tsig.c create mode 100644 contrib/bind/bin/named/ns_ctl.c create mode 100644 contrib/bind/bin/named/ns_ixfr.c create mode 100644 contrib/bind/bin/named/ns_notify.c create mode 100644 contrib/bind/bin/named/ns_signal.c create mode 100644 contrib/bind/bin/named/ns_sort.c create mode 100644 contrib/bind/bin/ndc/ndc.c (limited to 'contrib/bind/bin') 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 #include #include +#include #include #include #include +#include + #include #include #include @@ -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 +#include +#include +#include +#include +#include "arpa/nameser.h" + +#include + +#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 ", 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.public and K.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} [-F] -{zhu} [-ac] [-p ]" + " [-s ] -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 \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 #include #include +#include #include #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 #include -#include "port_after.h" +#include +#include +#include +#include -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)= 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 +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef EMPTY +/* Digital UNIX utmp.h defines this. */ +#undef EMPTY +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 +#include +#include +#include + +#include +#ifdef IRS_LCL_SV_DB +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#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-xfer/named-xfer.c b/contrib/bind/bin/named-xfer/named-xfer.c index 292714e..50c299e 100644 --- a/contrib/bind/bin/named-xfer/named-xfer.c +++ b/contrib/bind/bin/named-xfer/named-xfer.c @@ -1,5 +1,5 @@ /* - * The original version of xfer by Kevin Dunlap. + * The original version of named-xfer by Kevin Dunlap. * Completed and integrated with named by David Waitzman * (dwaitzman@bbn.com) 3/14/88. * Modified by M. Karels and O. Kure 10-88. @@ -84,7 +84,8 @@ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ -/* 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 @@ -100,27 +101,45 @@ * SOFTWARE. */ +/* + * Portions Copyright (c) 1998 by MetaInfo, Incorporated. + * + * 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 MetaInfo 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 METAINFO INCORPORATED DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL METAINFO 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. + */ #if !defined(lint) && !defined(SABER) char copyright[] = "@(#) Copyright (c) 1988, 1990 The Regents of the University of California.\n\ portions Copyright (c) 1993 Digital Equipment Corporation\n\ + portions Copyright (c) 1998 MetaInfo, Inc.\n\ portions Copyright (c) 1995, 1996 Internet Software Consorium\n\ All rights reserved.\n"; #endif /* not lint */ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)named-xfer.c 4.18 (Berkeley) 3/7/91"; -static char rcsid[] = "$Id: named-xfer.c,v 8.38 1998/03/27 00:19:28 halley Exp $"; +static const char sccsid[] = "@(#)named-xfer.c 4.18 (Berkeley) 3/7/91"; +static const char rcsid[] = "$Id: named-xfer.c,v 8.89 1999/11/09 20:36:54 marka Exp $"; #endif /* not lint */ #include "port_before.h" -#include "fd_setsize.h" - #include #include #include #include #include +#include #include #include @@ -141,26 +160,39 @@ static char rcsid[] = "$Id: named-xfer.c,v 8.38 1998/03/27 00:19:28 halley Exp $ #include #include +#include #include +/* This still uses malloc/free, but the tsig routines allocate memory with + * memget, and we free it with memput. + */ +#include + +#include #include "port_after.h" + #define MAIN_PROGRAM #include "../named/named.h" #undef MAIN_PROGRAM #define MAX_XFER_RESTARTS 2 +#define ENABLE_IXFR 0 + # ifdef SHORT_FNAMES extern long pathconf __P((const char *path, int name)); /* XXX */ # endif + static struct zoneinfo zone; /* zone information */ -static char ddtfilename[] = _PATH_TMPXFER, - *ddtfile = ddtfilename, - *tmpname, - *domain; /* domain being xfered */ +static char *ddtfilename = NULL, + *ddtfile = NULL; + +static char *tmpname = NULL, + *tmpiname = NULL, /* temporary file name for ixfr transaction file */ + *domain; /* domain being xfered */ static int quiet = 0, read_interrupted = 0, @@ -168,30 +200,48 @@ static int quiet = 0, domain_len; /* strlen(domain) */ static FILE *fp = NULL, - *dbfp = NULL; + *dbfp = NULL, + *ixfp = NULL; static char *ProgName; -static void usage(const char *); +static void usage(const char *), + tsig_init(const char *); static int getzone(struct zoneinfo *, u_int32_t, int), print_output(struct zoneinfo *, u_int32_t, u_char *, int, u_char *), netread(int, char *, int, int), writemsg(int, const u_char *, int); +static void ixfr_log(const u_char *msg, int len, int *delete, + FILE *file, struct sockaddr_in *sin, + char *domain, u_int32_t serial_no, int *); static SIG_FN read_alarm(void); static SIG_FN term_handler(void); -static const char *soa_zinfo(struct zoneinfo *, u_char *, u_char*); +static const char *soa_zinfo(struct zoneinfo *, u_char *, u_char*), + *tsig_rcode(int); struct zoneinfo zp_start, zp_finish; static int restarts = 0; +static int check_serial = 0; +static int xfr_qtype = T_AXFR; +static u_int32_t old_serial; FILE *ddt = NULL; +int servermethode[NSMAX]; +char *soa_buf; + +typedef struct _tsig_node { + struct in_addr addr; + DST_KEY *dst_key; + LINK(struct _tsig_node) link; +} tsig_node; + +LIST(tsig_node) tsig_list; /* * Debugging printf. */ -#ifdef DEBUG void dprintf(int level, const char *format, ...) { va_list ap; @@ -201,10 +251,9 @@ dprintf(int level, const char *format, ...) { (void) vfprintf(ddt, format, ap); va_end(ap); } -#endif /*DEBUG*/ -static -int init_xfer_logging() { +static int +init_xfer_logging() { log_channel chan; if (log_new_context(ns_log_max_category, NULL, &log_ctx) < 0) { @@ -243,7 +292,26 @@ void cleanup_for_exit(void) { #ifdef DEBUG if (!debug) #endif + { (void) unlink(tmpname); + if (tmpiname != NULL) + (void) unlink(tmpiname); + } + if(tmpiname) + free(tmpiname); + tmpiname = NULL; + if (ddtfilename != NULL) { + free(ddtfilename); + if (ddtfilename == ddtfile) + ddtfile = NULL; + ddtfilename = NULL; + } + if(tmpname) + free(tmpname); + tmpname = NULL; + if(ddtfile) + free(ddtfile); + ddtfile = NULL; } @@ -252,18 +320,22 @@ main(int argc, char *argv[]) { struct zoneinfo *zp; struct hostent *hp; struct in_addr axfr_src; - char *dbfile = NULL, *tracefile = NULL, *tm = NULL; - int dbfd, ddtd, result, c, fd, closed = 0; + char *dbfile = NULL, *tracefile = NULL, *tm = NULL, *tsigfile = NULL; + char *ixfrfile = NULL; + u_int32_t new_serial_no = 0; + int dbfd, ddtd, result, c, fd, ixfd; u_int32_t serial_no = 0; u_int port = htons(NAMESERVER_PORT); struct stat statbuf; -#ifdef STUBS int stub_only = 0; -#endif int class = C_IN; int n; long num_files; +#ifdef _AUX_SOURCE + set42sig(); +#endif + memset(&axfr_src, 0, sizeof axfr_src); ProgName = strrchr(argv[0], '/'); if (ProgName != NULL) ProgName++; @@ -272,10 +344,9 @@ main(int argc, char *argv[]) { (void) umask(022); - /* this is a hack; closing everything in the parent is hard. */ - num_files = MIN(sysconf(_SC_OPEN_MAX), FD_SETSIZE); - for (fd = num_files - 1; fd > STDERR_FILENO; fd--) - closed += (close(fd) == 0); + ddtfilename = (char *)malloc(strlen(_PATH_TMPXFER) + 1); + strcpy(ddtfilename, _PATH_TMPXFER); + ddtfile = ddtfilename; #ifdef RENICE nice(-40); /* this is the recommended procedure to */ @@ -283,24 +354,21 @@ main(int argc, char *argv[]) { nice(0); /* to "normal" (== 0) - see nice(3) */ #endif + n = LOG_PID; #ifdef LOG_PERROR - n = LOG_PERROR; -#else - n = 0; + n |= LOG_PERROR; #endif -#ifdef SYSLOG_42BSD - openlog(ProgName, LOG_PID); -#else - openlog(ProgName, LOG_PID|LOG_CONS|n, LOG_DAEMON); +#if defined(LOG_CONS) && defined(USE_LOG_CONS) + n |= LOG_CONS; #endif - axfr_src.s_addr = 0; -#ifdef STUBS - while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:qx:S")) != EOF) +#ifdef SYSLOG_42BSD + openlog(ProgName, n); #else - while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:qx:")) != EOF) + openlog(ProgName, n, LOG_DAEMON); #endif - switch (c) { - case 'C': + while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:i:p:P:qx:ST:Z")) != -1) + switch (c) { + case 'C': class = get_class(optarg); break; case 'd': @@ -322,6 +390,7 @@ main(int argc, char *argv[]) { break; case 's': serial_no = strtoul(optarg, (char **)NULL, 10); + check_serial++; break; case 't': tracefile = optarg; @@ -345,17 +414,29 @@ main(int argc, char *argv[]) { (void) strcpy(tmpname, optarg); #endif /* SHORT_FNAMES */ break; + case 'i': +#if ENABLE_IXFR + ixfrfile = optarg; + tmpiname = (char *) malloc(strlen(optarg) + + sizeof(".XXXXXX") + 1); + if (!tmpiname) + panic("malloc(tmpiname)", NULL); +#ifdef SHORT_FNAMES + filenamecpy(tmpiname, optarg); +#else + (void) strcpy(tmpiname, optarg); +#endif /* SHORT_FNAMES */ +#endif /* ENABLE_IXFR */ + break; case 'p': port = htons((u_int16_t)atoi(optarg)); break; case 'P': port = (u_int16_t)atoi(optarg); break; -#ifdef STUBS case 'S': stub_only = 1; break; -#endif case 'q': quiet++; break; @@ -363,13 +444,18 @@ main(int argc, char *argv[]) { if (!inet_aton(optarg, &axfr_src)) panic("bad -x addr: %s", optarg); break; + case 'T': + tsigfile = optarg; + break; + case 'Z': + xfr_qtype = ns_t_zxfr; + break; case '?': default: usage("unrecognized argument"); /* NOTREACHED */ - } - - if (!domain || !dbfile || optind >= argc) { + } + if (!domain || ((!dbfile) && (!ixfrfile)) || optind >= argc) { if (!domain) usage("no domain"); if (!dbfile) @@ -382,6 +468,14 @@ main(int argc, char *argv[]) { !S_ISREG(statbuf.st_mode) && !S_ISFIFO(statbuf.st_mode)) usage("dbfile must be a regular file or FIFO"); + if (ixfrfile && (stat(ixfrfile, &statbuf) != -1 && + !S_ISREG(statbuf.st_mode) && + !S_ISFIFO(statbuf.st_mode))) + usage("ixfrfile must be a regular file or FIFO"); + if (tsigfile && stat(tsigfile, &statbuf) != -1 && + !S_ISREG(statbuf.st_mode) && + !S_ISFIFO(statbuf.st_mode)) + usage("tsigfile must be a regular file or FIFO"); if (tracefile && (fp = fopen(tracefile, "w")) == NULL) perror(tracefile); (void) strcat(tmpname, ".XXXXXX"); @@ -389,8 +483,8 @@ main(int argc, char *argv[]) { if ((dbfd = mkstemp(tmpname)) == -1) { perror(tmpname); if (!quiet) - syslog(LOG_ERR, "can't make tmpfile (%s): %m\n", - tmpname); + syslog(LOG_ERR, "can't make tmpfile (%s): %s\n", + tmpname, strerror(errno)); exit(XFER_FAIL); } #ifdef HAVE_FCHMOD /* XXX */ @@ -401,8 +495,8 @@ main(int argc, char *argv[]) { { perror(tmpname); if (!quiet) - syslog(LOG_ERR, "can't [f]chmod tmpfile (%s): %m\n", - tmpname); + syslog(LOG_ERR, "can't [f]chmod tmpfile (%s): %s\n", + tmpname, strerror(errno)); exit(XFER_FAIL); } if ((dbfp = fdopen(dbfd, "r+")) == NULL) { @@ -411,6 +505,36 @@ main(int argc, char *argv[]) { syslog(LOG_ERR, "can't fdopen tmpfile (%s)", tmpname); exit(XFER_FAIL); } + if (ixfrfile) { + (void) strcat(tmpiname, ".XXXXXX"); + if ((ixfd = mkstemp(tmpiname)) == -1) { + perror(tmpiname); + if (!quiet) + syslog(LOG_ERR, + "can't make tmpifile (%s): %s\n", + tmpiname, strerror(errno)); + (void) fclose(dbfp); + (void) close(dbfd); + exit(XFER_FAIL); + } +#ifdef HAVE_FCHMOD /* XXX */ + if (fchmod(ixfd, 0644) == -1) +#else + if (chmod(tmpiname, 0644) == -1) +#endif + { + perror(tmpiname); + if (!quiet) + syslog(LOG_ERR, + "can't [f]chmod tmpifile (%s): %s\n", + tmpiname, strerror(errno)); + (void) fclose(dbfp); + (void) close(dbfd); + (void) close(ixfd); + exit(XFER_FAIL); + } + close(ixfd); + } #ifdef DEBUG if (debug) { /* ddtfile is now something like "/usr/tmp/xfer.ddt.XXXXXX" */ @@ -433,8 +557,8 @@ main(int argc, char *argv[]) { setvbuf(ddt, NULL, _IOLBF, 0); } #endif - if (!init_xfer_logging()) { + cleanup_for_exit(); perror("init_xfer_logging"); } @@ -464,20 +588,25 @@ main(int argc, char *argv[]) { (void) signal(SIGFPE, SIG_IGN); #endif /* SIGUSR1&&SIGUSR2 */ - dprintf(1, "domain `%s'; file `%s'; serial %u; closed %d\n", - domain, dbfile, serial_no, closed); + if (dbfile) + dprintf(1, "domain `%s'; file `%s'; serial %u\n", + domain, dbfile, serial_no); + + if (ixfrfile) + dprintf(1, "domain `%s'; ixfrfile `%s'; serial %u\n", + domain, ixfrfile, serial_no); buildservicelist(); buildprotolist(); + tsig_init(tsigfile); + /* init zone data */ zp = &zone; -#ifdef STUBS if (stub_only) zp->z_type = Z_STUB; else -#endif zp->z_type = Z_SECONDARY; zp->z_class = class; zp->z_origin = domain; @@ -490,8 +619,34 @@ main(int argc, char *argv[]) { zp->z_source); for (; optind != argc; optind++) { + int tmpsupportixfr; + tm = argv[optind]; + tmpsupportixfr = ISNOTIXFR; + if ((optind+1) != argc) { + if (strcasecmp("ixfr", argv[optind+1]) == 0) { +#if ENABLE_IXFR + tmpsupportixfr = ISIXFR; + servermethode[zp->z_addrcnt] = tmpsupportixfr; +#endif + optind++; + } else if (strcasecmp("axfr", argv[optind+1]) == 0) { + tmpsupportixfr = ISNOTIXFR; + optind++; + } + } if (!inet_aton(tm, &zp->z_addr[zp->z_addrcnt])) { + if (strcmp("-ixfr",tm)==0) { +#if ENABLE_IXFR + tmpsupportixfr = ISIXFR; + servermethode[zp->z_addrcnt-1] = tmpsupportixfr; +#endif + continue; + } else + if (strcmp("-axfr",tm)==0) { + tmpsupportixfr = ISNOTIXFR; + continue; + } hp = gethostbyname(tm); if (hp == NULL) { syslog(LOG_NOTICE, @@ -502,7 +657,7 @@ main(int argc, char *argv[]) { memcpy(&zp->z_addr[zp->z_addrcnt], hp->h_addr, INADDRSZ); - dprintf(1, "Arg: \"%s\"\n", tm); + dprintf(1, "Arg: \"%s\" %s\n", tm,((tmpsupportixfr) ? "IXFR":"AXFR")); } if (++zp->z_addrcnt >= NSMAX) { zp->z_addrcnt = NSMAX; @@ -512,24 +667,71 @@ main(int argc, char *argv[]) { } dprintf(1, "addrcnt = %d\n", zp->z_addrcnt); - res_init(); - _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE); + res_ninit(&res); + res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE); result = getzone(zp, serial_no, port); - (void) my_fclose(dbfp); + (void) fclose(dbfp); + (void) close(dbfd); + + if (ixfp) + (void) my_fclose(ixfp); + else + close(ixfd); + switch (result) { - case XFER_SUCCESS: /* ok exit */ - if (rename(tmpname, dbfile) == -1) { - perror("rename"); + case XFER_SUCCESSAXFR: /* ok exit */ + if (tmpiname != NULL) + unlink(tmpiname); + if (ixfrfile) { + /* + * An IXFR was requested but we performed an + * AXFR. Rename the temporary file to the IXFR + * name, named will rename it again to the dbname. + */ + if (movefile(tmpname, ixfrfile) == -1) { + perror("movefile"); +#ifdef DEBUG + if (debug) + (void) unlink(ddtfile); +#endif + if (!quiet) + syslog(LOG_ERR, + "rename %s to %s: %s", + tmpname, ixfrfile, strerror(errno)); + cleanup_for_exit(); + exit(XFER_FAIL); + }; + exit(XFER_SUCCESSAXFRIXFRFILE); + } + if (movefile(tmpname, dbfile) == -1) { + perror("movefile"); if (!quiet) - syslog(LOG_ERR, "rename %s to %s: %m", + syslog(LOG_ERR, "movefile %s to %s: %m", tmpname, dbfile); + cleanup_for_exit(); exit(XFER_FAIL); } - exit(XFER_SUCCESS); + exit(XFER_SUCCESSAXFR); + + case XFER_SUCCESSIXFR: + unlink(tmpname); + if (movefile(tmpiname, ixfrfile) == -1) { + perror("movefile"); + if (!quiet) + syslog(LOG_ERR, "movefile %s to %s: %m", + tmpiname, ixfrfile); + cleanup_for_exit(); + exit(XFER_FAIL); + } + cleanup_for_exit(); + exit(XFER_SUCCESSIXFR); case XFER_UPTODATE: /* the zone was already uptodate */ (void) unlink(tmpname); + if (tmpiname != NULL) + (void) unlink(tmpiname); + cleanup_for_exit(); exit(XFER_UPTODATE); default: @@ -537,6 +739,7 @@ main(int argc, char *argv[]) { /* fall through */ case XFER_TIMEOUT: case XFER_FAIL: + (void) unlink(tmpname); cleanup_for_exit(); exit(result); /* error or timeout */ } @@ -547,17 +750,17 @@ main(int argc, char *argv[]) { static char *UsageText[] = { "\t-z zone_to_transfer\n", "\t-f db_file\n", - "\t-s serial_no\n", + "\t[-i ixfr_file]\n", + "\t[-s serial_no]\n", "\t[-d debug_level]\n", "\t[-l debug_log_file]\n", "\t[-t trace_file]\n", "\t[-p port]\n", -#ifdef STUBS - "\t[-S]\n", -#endif + "\t[-S] [-Z]\n", "\t[-C class]\n", "\t[-x axfr-src]\n", - "\tservers...\n", + "\t[-T tsig_info_file]\n", + "\tservers [-ixfr|-axfr]...\n", NULL }; @@ -572,13 +775,66 @@ usage(const char *msg) { exit(XFER_FAIL); } +static void +tsig_init(const char *file) { + char buf[1024]; + int n; + FILE *fp; + char *s; + + if (file == NULL) + return; + fp = fopen(file, "r"); + if (fp == NULL) + return; + dst_init(); + INIT_LIST(tsig_list); + while (1) { + tsig_node *n = malloc(sizeof(tsig_node)); + int alg, secret_len; + char *address, *name; + char *cp; + u_char secret[128]; + + s = fgets(buf, sizeof(buf), fp); + if (s == NULL) + break; + buf[strlen(buf)-1] = 0; + inet_aton(buf, &n->addr); + + fgets(buf, sizeof(buf), fp); + buf[strlen(buf)-1] = 0; + name = strdup(buf); + + fscanf(fp, "%d", &alg); + fgets(buf, sizeof(buf), fp); + + fgets(buf, sizeof(buf), fp); + buf[strlen(buf)-1] = 0; + cp = buf; + while (isspace(*cp)) + cp++; + + secret_len = b64_pton(cp, secret, sizeof(secret)); + n->dst_key = dst_buffer_to_key(name, alg, 0, 0, + secret, secret_len); + + free(name); + APPEND(tsig_list, n, link); + } + fclose(fp); + unlink(file); +} + #define DEF_DNAME '\001' /* '\0' means the root domain */ /* XXX: The following variables should probably all be "static" */ u_int32_t minimum_ttl = 0; -int soa_cnt = 0; -#ifdef STUBS +int soa_cnt = 0, scdsoa = 0, methode = ISNOTIXFR; +int delete_soa = 1; +u_int32_t final_serial = 0; +int ixfr_soa = 0; +int firstsoa = 1; int ns_cnt = 0; -#endif int query_type = 0; int prev_comment = 0; /* was previous record a comment? */ char zone_top[MAXDNAME]; /* the top of the zone */ @@ -592,19 +848,32 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { u_int len; u_int32_t serial; int s, n, l, error = 0; + int was_ixfr = 0; u_int cnt; u_char *cp, *nmp, *eom, *tmp ; - u_char *buf = NULL; + u_char *buf = NULL, *cpp = NULL; u_int bufsize = 0; char name[MAXDNAME], name2[MAXDNAME]; struct sockaddr_in sin; + struct sockaddr_in local; + int locallen; #ifdef POSIX_SIGNALS struct sigaction sv, osv; #else struct sigvec sv, osv; #endif - int qdcount, ancount, aucount, class, type; + int qdcount, ancount, aucount, arcount, class, type; const char *badsoa_msg = "Nil"; + struct sockaddr_in my_addr; + char my_addr_text[30]; + int alen, ret, tsig_req; + DST_KEY *tsig_key; + ns_tcp_tsig_state tsig_state; + int tsig_signed = 0; + u_char sig[64]; + int siglen; + int ixfr_first = 1; + time_t timesigned; #ifdef DEBUG if (debug) { @@ -648,9 +917,23 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { if ((l = strlen(zone_top)) != 0 && zone_top[l - 1] == '.') zone_top[l - 1] = '\0'; strcpy(prev_origin, zone_top); + for (cnt = 0; cnt < zp->z_addrcnt; cnt++) { + methode = servermethode[cnt]; + sin.sin_addr = zp->z_addr[cnt]; + dprintf(3, "address [%s] %s\n", + inet_ntoa(sin.sin_addr), + (methode == ISIXFR) ? "IXFR":"AXFR"); + } for (cnt = 0; cnt < zp->z_addrcnt; cnt++) { + methode = ISNOTIXFR; curclass = zp->z_class; + /* + * If we have been given a serial number and a ixfr log + * file name then set methode. + */ + if (check_serial && tmpiname != NULL) + methode = servermethode[cnt]; error = 0; if (buf == NULL) { if ((buf = (u_char *)malloc(2 * PACKETSZ)) == NULL) { @@ -661,6 +944,7 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { } bufsize = 2 * PACKETSZ; } + try_again: if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { syslog(LOG_INFO, "socket: %m"); error++; @@ -684,20 +968,72 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { dprintf(2, "connecting to server #%d [%s].%d\n", cnt+1, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + if (zp->z_axfr_src.s_addr != 0) { + dprintf(2, "connect failed, trying w/o -x"); + zp->z_axfr_src.s_addr = 0; + (void) my_close(s); + goto try_again; + } if (!quiet) syslog(LOG_INFO, - "connect(%s) for zone %s failed: %m", - inet_ntoa(sin.sin_addr), zp->z_origin); + "connect(%s) for zone %s failed: %s", + inet_ntoa(sin.sin_addr), zp->z_origin, strerror(errno)); error++; (void) my_close(s); continue; } - n = res_mkquery(QUERY, zp->z_origin, curclass, - T_SOA, NULL, 0, NULL, buf, bufsize); + if (methode == ISIXFR) { + hp = (HEADER *) buf; + cpp = buf; + n = res_nmkquery(&res, QUERY, zp->z_origin, curclass, + T_IXFR, NULL, 0, NULL, buf, bufsize); + dprintf(1, "len = %d\n", n); + if (n < 0) { + if (!quiet) + syslog(LOG_INFO, + "zone %s: dn_comp for ixfr failed", + zp->z_origin); + (void) my_close(s); +#ifdef POSIX_SIGNALS + sigaction(SIGALRM, + &osv, + (struct sigaction*)0); +#else + sigvec(SIGALRM, + &osv, + (struct sigvec *)0); +#endif + return (XFER_FAIL); + } + hp->nscount = htons(1+ntohs(hp->nscount)); + cpp += n; + n = dn_comp(zp->z_origin, cpp, bufsize-(cpp-buf), + NULL, NULL); + if (n > 0) + 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(serial_no, cpp); + PUTLONG(0xDEAD, cpp); /* Refresh */ + PUTLONG(0xBEEF, cpp); /* Retry */ + PUTLONG(0xABCD, cpp); /* Expire */ + PUTLONG(0x1776, cpp); /* Min TTL */ + n = cpp-buf; + dprintf(1, "len = %d\n", cpp-buf); + if (debug) + res_pquery(&res, buf, n, ddt); + } + else { + n = res_nmkquery(&res, QUERY, zp->z_origin, curclass, + T_SOA, NULL, 0, NULL, buf, bufsize); if (n < 0) { if (!quiet) syslog(LOG_INFO, - "zone %s: res_mkquery T_SOA failed", + "zone %s: res_nmkquery T_SOA failed", zp->z_origin); (void) my_close(s); #ifdef POSIX_SIGNALS @@ -707,6 +1043,19 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { #endif return (XFER_FAIL); } + } + /* + * Append TSIG to SOA query if desired + */ + tsig_key = tsig_key_from_addr(sin.sin_addr); + if (tsig_key != NULL) { + siglen = sizeof(sig); + ret = ns_sign(buf, &n, bufsize, NOERROR, tsig_key, + NULL, 0, sig, &siglen, timesigned); + if (ret == 0) + tsig_signed = 1; + } + /* * Send length & message for SOA query */ @@ -719,6 +1068,7 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { /* * Get out your butterfly net and catch the SOA */ + if (netread(s, (char *)buf, INT16SZ, XFER_TIMER) < 0) { error++; (void) my_close(s); @@ -745,16 +1095,52 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { (void) my_close(s); continue; } + /* + * Verify the TSIG if expected + */ + if (tsig_signed != 0) { + ret = ns_verify(buf, (int *)&len, tsig_key, sig, siglen, + NULL, NULL, ×igned, 0); + if (ret != 0) { + syslog(LOG_NOTICE, + "SOA TSIG verification from server [%s], zone %s: %s (%d)\n", + inet_ntoa(sin.sin_addr), zp->z_origin, + tsig_rcode(ret), ret); + error++; + continue; + } + } + #ifdef DEBUG if (debug >= 3) { (void)fprintf(ddt,"len = %d\n", len); - fp_nquery(buf, len, ddt); + res_pquery(&res, buf, len, ddt); } #endif + if ((methode == ISIXFR) && (ixfp == NULL)) { + delete_soa = 1; + firstsoa = 1; + ixfr_soa = 0; + old_serial = serial_no; + if (ixfp != NULL) { + fflush(ixfp); + /* XXX error */ + ftruncate(fileno(ixfp), 0); + } else if ((ixfp = fopen(tmpiname, "w+")) == NULL) { + perror(tmpiname); + if (!quiet) + syslog(LOG_ERR, + "can't fdopen ixfr log (%s)", + tmpname); + exit(XFER_FAIL); + } + } + hp = (HEADER *) buf; qdcount = ntohs(hp->qdcount); ancount = ntohs(hp->ancount); aucount = ntohs(hp->nscount); + arcount = ntohs(hp->arcount); /* * close socket if any of these apply: @@ -809,8 +1195,8 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { } NS_GET16(type, tmp); NS_GET16(class, tmp); - if (class != curclass || type != T_SOA || - strcasecmp(zp->z_origin, name2) != 0) { + if (class != curclass || ((type != T_SOA) && type != T_IXFR) || + ns_samename(zp->z_origin, name2) != 1) { syslog(LOG_INFO, "wrong query in resp from [%s], zone %s: [%s %s %s]\n", inet_ntoa(sin.sin_addr), zp->z_origin, @@ -857,7 +1243,7 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { tmp = cp4 + dlen; } while (1); - if (strcasecmp(zp->z_origin, name2) != 0) { + if (ns_samename(zp->z_origin, name2) != 1) { syslog(LOG_INFO, "wrong answer in resp from [%s], zone %s: [%s %s %s]\n", inet_ntoa(sin.sin_addr), zp->z_origin, @@ -869,16 +1255,35 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { badsoa_msg = soa_zinfo(&zp_start, tmp, eom); if (badsoa_msg) goto badsoa; - if (SEQ_GT(zp_start.z_serial, serial_no) || !serial_no) { - const char *l, *nl; + if (SEQ_GT(zp_start.z_serial, serial_no) || !check_serial) { + const char *l, *nl, *t; + dprintf(1, "need update, serial %u\n", zp_start.z_serial); hp = (HEADER *) buf; - soa_cnt = 0; -#ifdef STUBS + if ((methode == ISIXFR) && (soa_cnt == 0)) { + if (type == T_IXFR) { + if (ixfp) + ixfr_log(buf, len, &delete_soa, ixfp, + &sin, domain, serial_no, + &ixfr_first); + soa_cnt = 2; + } else { + dprintf(1, + "server %s rejected IXFR and responded with AXFR\n", + inet_ntoa(sin.sin_addr)); + methode = ISNOTIXFR; + was_ixfr++; + soa_cnt++; + } + } ns_cnt = 0; -#endif gettime(&tt); + locallen = sizeof local; + if (getsockname(s, (struct sockaddr *)&local, + &locallen) < 0) { + memset(&local, 0, sizeof local); + } for (l = Version; l; l = nl) { size_t len; if ((nl = strchr(l, '\n')) != NULL) { @@ -894,41 +1299,62 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { fprintf(dbfp, "; BIND version %.*s\n", (int)len, l); } - fprintf(dbfp, "; zone '%s' last serial %u\n", + fprintf(dbfp, check_serial? + "; zone '%s' last serial %u\n": + "; zone '%s' first transfer\n", domain, serial_no); - fprintf(dbfp, "; from %s at %s", - inet_ntoa(sin.sin_addr), + t = strdup(inet_ntoa(sin.sin_addr)); + fprintf(dbfp, "; from %s:%d (local %s) using %s at %s", + t, ntohs(sin.sin_port), + inet_ntoa(local.sin_addr), + (methode == ISIXFR) ? "IXFR":"AXFR", ctimel(tt.tv_sec)); + free((void *)t); for (;;) { if ((soa_cnt == 0) || (zp->z_type == Z_STUB)) { -#ifdef STUBS if (zp->z_type == Z_STUB) { if (soa_cnt == 1 && ns_cnt == 0) query_type = T_NS; else query_type = T_SOA; - } else -#endif - query_type = T_AXFR; - n = res_mkquery(QUERY, zp->z_origin, - curclass, query_type, - NULL, 0, - NULL, buf, bufsize); + } else if (methode == ISIXFR) + query_type = T_IXFR; + else + query_type = xfr_qtype; + n = res_nmkquery(&res, QUERY, + zp->z_origin, + curclass, query_type, + NULL, 0, + NULL, buf, bufsize); + syslog(LOG_INFO, + "send %s query %d to %s", + (query_type == T_IXFR) ? "IXFR" : + (query_type == T_AXFR) ? "AXFR" : + (query_type == ns_t_zxfr) ? "ZXFR" : + (query_type == T_SOA) ? "SOA" : "NS", + cnt, inet_ntoa(sin.sin_addr)); + dprintf(1, + "send %s query to %s\n", + (query_type == T_IXFR) ? "IXFR" : + (query_type == T_AXFR) ? "AXFR" : + (query_type == ns_t_zxfr) ? "ZXFR" : + (query_type == T_SOA) ? "SOA" : "NS", + inet_ntoa(sin.sin_addr)); + dprintf(1,"bufsize = %d\n", bufsize); if (n < 0) { if (!quiet) { -#ifdef STUBS if (zp->z_type == Z_STUB) syslog(LOG_INFO, (query_type == T_SOA) - ? "zone %s: res_mkquery T_SOA failed" - : "zone %s: res_mkquery T_NS failed", + ? "zone %s: res_nmkquery T_SOA failed" + : "zone %s: res_nmkquery T_NS failed", zp->z_origin); else -#endif syslog(LOG_INFO, - "zone %s: res_mkquery T_AXFR failed", - zp->z_origin); + "zone %s: res_nmkquery %s failed", + zp->z_origin, + p_type(query_type)); } (void) my_close(s); #ifdef POSIX_SIGNALS @@ -940,10 +1366,25 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { #endif return (XFER_FAIL); } + cpp = buf + n; + /* + * Append TSIG to AXFR query if desired + */ + if (tsig_signed != 0) { + siglen = sizeof(sig); + ns_sign(buf, &n, bufsize, + NOERROR, tsig_key, + NULL, 0, sig, &siglen, + timesigned); + cpp = buf + n; + ns_verify_tcp_init(tsig_key, + sig, siglen, + &tsig_state); + } /* * Send length & msg for zone transfer */ - if (writemsg(s, buf, n) < 0) { + if (writemsg(s, buf, cpp - buf) < 0) { syslog(LOG_INFO, "writemsg: %m"); error++; @@ -951,6 +1392,8 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { break; } } +/*XXX ZXFR*/ + if (methode == ISNOTIXFR && !was_ixfr) { /* * Receive length & response */ @@ -966,7 +1409,7 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { buf = (u_char *)realloc(buf, len); if (buf == NULL) { syslog(LOG_INFO, - "malloc(%u) failed for packet from server [%s], zone %s\n", + "malloc(%u) failed for packet from server [%s], zone %s\n", len, inet_ntoa(sin.sin_addr), zp->z_origin); @@ -982,18 +1425,36 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { error++; break; } + } #ifdef DEBUG if (debug >= 3) { (void)fprintf(ddt,"len = %d\n", len); - fp_nquery(buf, len, ddt); + res_pquery(&res, buf, len, ddt); } if (fp) - fp_nquery(buf, len, fp); + res_pquery(&res, buf, len, fp); #endif + /* + * Verify the TSIG if expected + */ + if (tsig_signed != 0) { + tsig_req = (soa_cnt == 0); + ret = ns_verify_tcp(buf, (int *)&len, + &tsig_state, + tsig_req); + eom = buf + len; + + if (ret != 0) { + syslog(LOG_NOTICE, + "TSIG verification from server [%s], zone %s: %s (%d)\n", + inet_ntoa(sin.sin_addr), + zp->z_origin, + tsig_rcode(ret), ret); + error++; + break; + } + } if (len < HFIXEDSZ) { - struct sockaddr_in my_addr; - char my_addr_text[30]; - int alen; badrec: error++; @@ -1009,25 +1470,54 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { sin_addr), ntohs(my_addr.sin_port) ); - syslog(LOG_INFO, + if ((hp->rcode == REFUSED) && + (len >= HFIXEDSZ)) { + syslog(LOG_INFO, + "[%s] transfer refused from [%s], zone %s\n", + my_addr_text, + inet_ntoa(sin.sin_addr), + zp->z_origin); + } else { + syslog(LOG_INFO, "[%s] record too short from [%s], zone %s\n", - my_addr_text, - inet_ntoa(sin.sin_addr), - zp->z_origin); + my_addr_text, + inet_ntoa(sin.sin_addr), + zp->z_origin); + } break; } + if (query_type == T_IXFR) + if (hp->rcode != NOERROR) { + dprintf(1, + "server %s did not support IXFR\n", + inet_ntoa(sin.sin_addr)); + methode = ISNOTIXFR; + continue; + }; cp = buf + HFIXEDSZ; - if (hp->qdcount) { - if ((n = dn_skipname(cp, eom)) == -1 - || n + QFIXEDSZ >= eom - cp) + if (ntohs(hp->qdcount) == 1) { + if ((query_type == T_IXFR) && (methode == ISIXFR)) { + dprintf(1, + "server %s rejected IXFR and responded with AXFR\n", + inet_ntoa(sin.sin_addr)); + methode = ISNOTIXFR; + } + n = dn_skipname(cp, eom); + if ((n == -1) || + ((n + QFIXEDSZ) >= (eom - cp))) goto badrec; cp += n + QFIXEDSZ; + } else { + if (methode == ISIXFR && ixfp) + ixfr_log(buf, len, &delete_soa, ixfp, + &sin, domain, serial_no, + &ixfr_first); + } nmp = cp; if ((n = dn_skipname(cp, eom)) == -1) goto badrec; tmp = cp + n; -#ifdef STUBS if (zp->z_type == Z_STUB) { ancount = ntohs(hp->ancount); n = 0; @@ -1091,11 +1581,8 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { break; } } else { -#endif /*STUBS*/ ancount = ntohs(hp->ancount); - for (n = cnt = 0; - cnt < (u_int)ancount; - cnt++) { + for (n = cnt = 0; cnt < (u_int)ancount; cnt++) { n = print_output(zp, serial_no, buf, len, cp); if (n < 0) @@ -1117,13 +1604,12 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { error++; break; } -#ifdef STUBS } -#endif - if (soa_cnt >= 2) + if ((soa_cnt >= 2) && (methode == ISNOTIXFR)) + break; + if ((soa_cnt == -1) && (methode == ISIXFR)) break; - } (void) my_close(s); if (error == 0) { @@ -1133,21 +1619,43 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { #else (void) sigvec(SIGALRM, &osv, (struct sigvec *)0); #endif - return (XFER_SUCCESS); + if (methode == ISIXFR) { + fprintf(ixfp, "update:\t{add} "); + if (soa_buf) + fputs(soa_buf, ixfp); + fprintf(ixfp, "[END_DELTA]\n"); + (void) my_close(s); + return (XFER_SUCCESSIXFR); + } else { + if (ixfp) { + (void) fclose(ixfp); + ixfp = NULL; + } + return (XFER_SUCCESSAXFR); + } + } + if (ixfp) { + (void) fclose(ixfp); + ixfp = NULL; } dprintf(2, "error receiving zone transfer\n"); } else if (zp_start.z_serial == serial_no) { - (void) my_close(s); - dprintf(1, "zone up-to-date, serial %u\n", zp_start.z_serial); - return (XFER_UPTODATE); + (void) my_close(s); + dprintf(1, "zone up-to-date, serial %u\n", zp_start.z_serial); + if (ixfp) { + (void) unlink (tmpiname); + (void) fclose(ixfp); + ixfp = NULL; + } + return (XFER_UPTODATE); } else { - (void) my_close(s); - if (!quiet) - syslog(LOG_NOTICE, + (void) my_close(s); + if (!quiet) + syslog(LOG_NOTICE, "serial from [%s], zone %s: %u lower than current: %u\n", inet_ntoa(sin.sin_addr), zp->z_origin, zp_start.z_serial, serial_no); - return (XFER_FAIL); + return (XFER_FAIL); } } #ifdef POSIX_SIGNALS @@ -1155,6 +1663,11 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { #else (void) sigvec(SIGALRM, &osv, (struct sigvec *)0); #endif + if (ixfp) { + (void) unlink (tmpiname); + (void) my_fclose(ixfp); + ixfp = 0; + } if (!error) return (XFER_TIMEOUT); return (XFER_FAIL); @@ -1382,6 +1895,7 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, case T_NSAP: case T_AAAA: case T_KEY: + case ns_t_cert: cp1 = cp; n = dlen; cp += n; @@ -1640,14 +2154,14 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, */ if (type == T_SOA) { - if (strcasecmp(dname, zp->z_origin) != 0) { + if (ns_samename(dname, zp->z_origin) != 1) { syslog(LOG_INFO, - "wrong zone name in AXFR (wanted \"%s\", got \"%s\")", + "wrong zone name in XFR (wanted \"%s\", got \"%s\")", zp->z_origin, dname); hp->rcode = FORMERR; return (-1); } - if (!soa_cnt) { + if (soa_cnt == 0) { badsoa_msg = soa_zinfo(&zp_start, rr_type_ptr, eom); if (badsoa_msg) { syslog(LOG_INFO, @@ -1657,13 +2171,33 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, return (-1); } if (SEQ_GT(zp_start.z_serial, serial_no) || - !serial_no) + !check_serial) { soa_cnt++; - else { + } else { syslog(LOG_INFO, "serial went backwards after transfer started"); return (-1); } + } else if (soa_cnt == 1) { + badsoa_msg = soa_zinfo(&zp_finish, rr_type_ptr, eom); + if (badsoa_msg) { + syslog(LOG_INFO, + "malformed SOA for zone %s: %s", + zp->z_origin, badsoa_msg); + hp->rcode = FORMERR; + return (-1); + } + if (zp_start.z_serial == zp_finish.z_serial) { + methode = ISNOTIXFR; + } else if (zp_finish.z_serial != serial_no) { + syslog(LOG_INFO, + "Unexpected serial number for zone %s: %u", + zp->z_origin, zp_finish.z_serial); + } + soa_cnt++; + if ((methode == ISIXFR) || (soa_cnt >= 2)) { + return (result); + } } else { badsoa_msg = soa_zinfo(&zp_finish, rr_type_ptr, eom); if (badsoa_msg) { @@ -1673,45 +2207,56 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, hp->rcode = FORMERR; return (-1); } - dprintf(2, "SOA, serial %u\n", zp_finish.z_serial); - if (zp_start.z_serial != zp_finish.z_serial) { - dprintf(1, "serial changed, restart\n"); - restarts++; - if (restarts > MAX_XFER_RESTARTS) { - syslog(LOG_INFO, - "too many transfer restarts for zone %s", - zp->z_origin); - hp->rcode = FORMERR; - return (-1); - } - soa_cnt = 0; -#ifdef STUBS - ns_cnt = 0; -#endif - minimum_ttl = 0; - strcpy(prev_origin, zp->z_origin); - prev_dname[0] = DEF_DNAME; - /* - * Flush buffer, truncate file - * and seek to beginning to restart. - */ - fflush(dbfp); - if (ftruncate(fileno(dbfp), 0) != 0) { - if (!quiet) + if (methode == ISIXFR) { + if (zp_start.z_serial == zp_finish.z_serial) { + if (scdsoa) { + soa_cnt = -1; + return (result); + } else { + scdsoa = 1; + soa_cnt++; + }; + } else + soa_cnt++; + } else { + dprintf(2, "SOA, serial %u\n", + zp_finish.z_serial); + if (zp_start.z_serial != zp_finish.z_serial) { + dprintf(1, "serial changed, restart\n"); + restarts++; + if (restarts > MAX_XFER_RESTARTS) { syslog(LOG_INFO, - "ftruncate %s: %m\n", - tmpname); - return (-1); + "too many transfer restarts for zone %s", + zp->z_origin); + hp->rcode = FORMERR; + return (-1); + } + soa_cnt = 0; + ns_cnt = 0; + minimum_ttl = 0; + strcpy(prev_origin, zp->z_origin); + prev_dname[0] = DEF_DNAME; + /* + * Flush buffer, truncate file + * and seek to beginning to restart. + */ + fflush(dbfp); + if (ftruncate(fileno(dbfp), 0) != 0) { + if (!quiet) + syslog(LOG_INFO, + "ftruncate %s: %m\n", + tmpname); + return (-1); + } + fseek(dbfp, 0L, 0); + return (result); } - fseek(dbfp, 0L, 0); + soa_cnt++; return (result); } - soa_cnt++; - return (result); } } -#ifdef STUBS if (zp->z_type == Z_STUB) { if (query_type == T_NS && type == T_NS) ns_cnt++; @@ -1724,9 +2269,8 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, if (query_type == T_SOA && type != T_SOA) return (result); } -#endif - if (!soa_cnt || soa_cnt >= 2) { + if ((!soa_cnt || soa_cnt > 2) && methode == ISNOTIXFR) { char *gripe; if (!soa_cnt) @@ -1756,17 +2300,21 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, * where the remote server sends MX records soon after the * NS records for a particular domain. If sent earlier, we lose. XXX */ - if (!samedomain(dname, domain)) { + if (!ns_samedomain(dname, domain)) { (void) fprintf(dbfp, "; Ignoring info about %s, not in zone %s.\n", dname, domain); ignore = "; "; } else if (type != T_NS && type != T_A && - strcasecmp(zone_top, dname) != 0 && - strcasecmp(prev_ns_dname, dname) == 0) + ns_samename(zone_top, dname) != 1 && + ns_samename(prev_ns_dname, dname) == 1) { (void) fprintf(dbfp, "; Ignoring extra info about %s, invalid after NS delegation.\n", dname); ignore = "; "; + } else if (class != zp->z_class) { + (void) fprintf(dbfp, "; Ignoring info about %s, not class %s\n", + dname, p_class(zp->z_class)); + ignore = "; "; } /* @@ -1794,13 +2342,13 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, /* * If the origin has changed, print the new origin */ - if (strcasecmp(prev_origin, origin)) { + if (ns_samename(prev_origin, origin) != 1) { (void) strcpy(prev_origin, origin); (void) fprintf(dbfp, "%s$ORIGIN %s.\n", ignore, origin); } tab = 0; - if (strcasecmp(prev_dname, dname)) { + if (ns_samename(prev_dname, dname) != 1) { /* * set the prev_dname to be the current dname, then cut off all * characters of dname after (and including) the first '.' @@ -1837,10 +2385,7 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, tab = 1; } - if (ttl != minimum_ttl) - (void) fprintf(dbfp, "%d\t", (int) ttl); - else if (tab) - (void) putc('\t', dbfp); + (void) fprintf(dbfp, "%d\t", (int) ttl); (void) fprintf(dbfp, "%s\t%s\t", p_class(class), p_type(type)); cp = cdata; @@ -2085,8 +2630,8 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, /* algorithm id */ (void) fprintf(dbfp," %d",*cp++); - /* labels (# of labels in name) - skip in textual record */ - cp++; + /* labels (# of labels in name) */ + (void) fprintf(dbfp," %d",*cp++); /* orig time to live (TTL)) */ (void) fprintf(dbfp," %u", (u_int32_t)ns_get32((u_char*)cp)); @@ -2128,6 +2673,33 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, fprintf(dbfp,"\n"); break; + case ns_t_cert: { + int databufsize = n * 4 / 3 + 4; + char *databuf = malloc(databufsize); + + if (databuf == NULL) + panic("cert malloc failed", NULL); + + /* Object id */ + (void) fprintf(dbfp,"%d ", ns_get16((u_char*)cp)); + cp += INT16SZ; + + /* Key tag */ + (void) fprintf(dbfp,"%d ", ns_get16((u_char*)cp)); + cp += INT16SZ; + + /* Algorithm id */ + (void) fprintf(dbfp,"%d ", (u_char)*cp); + cp += 1; + + n = b64_ntop(cp, n - 2 * INT16SZ - 1, databuf, databufsize); + if (n < 0) + panic ("cert b64_ntop failed", NULL); + fprintf (dbfp, "%s\n", databuf); + free(databuf); + break; + } + default: cp1 = cp + n; while (cp < cp1) @@ -2175,3 +2747,199 @@ filenamecpy(char *ddtfile, char *optarg) { (void) strcpy(ddtfile, optarg); } #endif /* SHORT_FNAMES */ + +DST_KEY * +tsig_key_from_addr(struct in_addr addr) { + tsig_node *n; + for (n = HEAD(tsig_list); n != NULL; n = NEXT(n, link)) + if (memcpy(&addr, &n->addr, sizeof(struct in_addr))) + return n->dst_key; + return NULL; +} + +static void +do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file, int *delete) { + int n, sflag, rrnum; + char buf[2048]; /* XXX need to malloc */ + ns_opcode opcode; + ns_rr rr; + const unsigned char *cp; + const unsigned char *eom; + u_int32_t serial; + time_t now; + + time(&now); + + /* + * Print answer records. + */ + sflag = (_res.pfcode & pflag); + if (_res.pfcode && !sflag) + return; + + opcode = (ns_opcode)ns_msg_getflag(*handle, ns_f_opcode); + rrnum = 0; + for (;;) { + if (ns_parserr(handle, section, rrnum, &rr)) { + if (errno != ENODEV) + fprintf(file, ";; ns_parserr: %s\n", + strerror(errno)); + else if (rrnum > 0 && sflag != 0 && + (_res.pfcode & RES_PRF_HEAD1)) + putc('\n', file); + return; + } + if (rrnum == 0 && sflag != 0 && (_res.pfcode & RES_PRF_HEAD1)) + fprintf(file, ";; %s SECTION:\n", + p_section(section, opcode)); + if (section == ns_s_qd) + fprintf(file, ";;\t%s, type = %s, class = %s\n", + ns_rr_name(rr), + p_type(ns_rr_type(rr)), + p_class(ns_rr_class(rr))); + else { + int print_record = 1; + if (rr.type == ns_t_soa) { + print_record = 0; + *delete = !*delete; + cp = ns_rr_rdata(rr); + eom = cp + ns_rr_rdlen(rr); + if ((n = dn_skipname(cp, eom)) < 0) { + rrnum++; + continue; + } + cp += n; + if ((n = dn_skipname(cp, eom)) < 0) { + rrnum++; + continue; + } + cp += n; + NS_GET32(serial, cp); + if (*delete && serial != old_serial) + /*XXX*/; + old_serial = serial; + switch (++ixfr_soa) { + case 1: + final_serial = serial; + if (soa_buf == NULL) { + if ((soa_buf = (char *)malloc(2 * PACKETSZ)) == NULL) { + syslog(LOG_INFO, "malloc(%u) failed", 2 * PACKETSZ); + return; + } + n = ns_sprintrr(handle, &rr, NULL, NULL, + soa_buf, 2*PACKETSZ); + if (n < 0) { + fprintf(file, ";; ns_sprintrr: %s\n", + strerror(errno)); + return; + } + } + print_record = 0; + break; + case 2: + fprintf(file, + "zone:\torigin %s class %s serial %u\n", + ns_rr_name(rr), + p_class(ns_rr_class(rr)), + serial); + print_record = 0; + break; + default: + print_record = 0; + break; + } + + } + + if (print_record) { + if (rr.type != ns_t_soa) { + fprintf(file, "update:\t{%s} ", + *delete ? "delete" : "add"); + + n = ns_sprintrr(handle, &rr, NULL, NULL, + buf, sizeof buf); + if (n < 0) { + fprintf(file, ";; ns_sprintrr: %s\n", + strerror(errno)); + return; + } + fputs(buf, file); + fputc('\n', file); + } + } + + } + rrnum++; + } +} + +static void +ixfr_log(const u_char *msg, int len, int *delete, FILE *file, + struct sockaddr_in *sin, char *domain, u_int32_t serial_no, + int *first_rr) +{ + ns_msg handle; + ns_type type; + ns_class class; + ns_opcode opcode; + ns_rcode rcode; + u_int id, n; + char time[25]; + ns_rr rr; + char *cp; + HEADER *hp; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return; + + if (ns_initparse(msg, len, &handle) < 0) { + fprintf(file, ";; ns_initparse: %s\n", strerror(errno)); + return; + } + opcode = (ns_opcode) ns_msg_getflag(handle, ns_f_opcode); + rcode = (ns_rcode) ns_msg_getflag(handle, ns_f_rcode); + id = ns_msg_id(handle); + + if (ns_parserr(&handle, ns_s_an, 0, &rr)) + { + + (void) fprintf(file,"ns_parserr() failed"); + return; + } + type = (ns_type)rr.type; + class = (ns_class)rr.rr_class; + + if (*first_rr == 1) { + gettime(&tt); + (void) fprintf(file,"%s", LogSignature); + sprintf(time, "at %lu", (u_long)tt.tv_sec); + fprintf(file, + "[IXFR_UPDATE] id %u from [%s].%d %s (named-xfr pid %ld):\n", + id, inet_ntoa(sin->sin_addr), + ntohs(sin->sin_port), time, (long)getpid()); + (*first_rr)++; + } + do_section(&handle, ns_s_an, RES_PRF_ANS, file, delete); +} + +static const char * +tsig_rcode(int rcode) { + static char buffer[64]; + + switch (rcode) { + case ns_r_badkey: + case ns_r_badsig: + case ns_r_badtime: + sprintf(buffer, "message had %s set", p_rcode(rcode)); + return (buffer); + case -ns_r_badkey: + case -ns_r_badsig: + case -ns_r_badtime: + return (p_rcode(-rcode)); + case NS_TSIG_ERROR_NO_TSIG: + return ("no TSIG present"); + default: + break; + } + return ("FORMERR"); +} diff --git a/contrib/bind/bin/named/Makefile b/contrib/bind/bin/named/Makefile index 7e30cd0..6eac2b1 100644 --- a/contrib/bind/bin/named/Makefile +++ b/contrib/bind/bin/named/Makefile @@ -1,4 +1,4 @@ -## 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 @@ -13,7 +13,7 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -# $Id: Makefile,v 8.31 1998/03/20 00:49:46 halley Exp $ +# $Id: Makefile,v 8.47 1999/08/26 18:42:31 vixie Exp $ DESTDIR= CC= cc @@ -29,18 +29,21 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.a A=a O=o -LEX = lex -I +EXE= YACC = yacc -d SYSLIBS = -ll -lutil -PIDDIR = /var/run DESTBIN = /usr/local/bin DESTSBIN = /usr/local/sbin DESTEXEC = /usr/local/libexec DESTMAN = /usr/share/man DESTHELP= /usr/share/misc -AR= ar cruv +DESTETC= /etc +DESTRUN= /var/run +AR= ar cru INSTALL= install STRIP=-s +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin PS=ps LDFLAGS= @@ -52,23 +55,25 @@ HOSTNAMECMD= hostname || uname -n PROG= named HDRS= db_defs.h db_glob.h ns_defs.h ns_glob.h named.h pathnames.h SRCS= db_dump.c db_load.c db_lookup.c db_save.c db_update.c \ - db_glue.c \ - ns_parser.c ns_lexer.c ns_parseutil.c \ + db_glue.c db_ixfr.c db_sec.c db_tsig.c \ + ns_parser.c ns_lexer.c ns_parseutil.c ns_ctl.c \ ns_forw.c ns_init.c ns_main.c ns_maint.c ns_req.c \ ns_resp.c ns_stats.c ns_ncache.c ns_xfr.c ns_glue.c \ - ns_udp.c ns_config.c ns_update.c + ns_udp.c ns_config.c ns_update.c ns_ixfr.c ns_signal.c \ + ns_sort.c ns_notify.c OBJS= db_dump.${O} db_load.${O} db_lookup.${O} db_save.${O} db_update.${O} \ - db_glue.${O} \ - ns_parser.${O} ns_lexer.${O} ns_parseutil.${O} \ + db_glue.${O} db_ixfr.${O} db_sec.${O} db_tsig.${O} \ + ns_parser.${O} ns_lexer.${O} ns_parseutil.${O} ns_ctl.${O} \ ns_forw.${O} ns_init.${O} ns_main.${O} ns_maint.${O} ns_req.${O} \ ns_resp.${O} ns_stats.${O} ns_ncache.${O} ns_xfr.${O} ns_glue.${O} \ - ns_udp.${O} ns_config.${O} ns_update.${O} + ns_udp.${O} ns_config.${O} ns_update.${O} ns_ixfr.${O} ns_signal.${O} \ + ns_sort.${O} ns_notify.${O} -all: ${PROG} pathnames +all: ${PROG}${EXE} -${PROG}: pathnames.h ${OBJS} ${LIBBIND} Makefile tmp_version.${O} - ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} tmp_version.${O} \ - ${LIBBIND} ${SYSLIBS} +${PROG}${EXE}: pathnames.h ${OBJS} ${LIBBIND} Makefile tmp_version.${O} + ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \ + tmp_version.${O} ${LIBBIND} ${SYSLIBS} ns_parser.c ns_parser.h: ns_parser.y ${YACC} ns_parser.y @@ -83,7 +88,7 @@ tmp_version.c: version.c Makefile ../Makefile ${SRCS} ${HDRS} -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \ < version.c > tmp_version.c) -pathnames.h: ${TOP}/.settings Makefile +pathnames.h: ${TOP}/.settings Makefile pathtemplate.h rm -f pathnames.h sed -e "s|%DESTSBIN%|${DESTSBIN}|" \ -e "s|%DESTEXEC%|${DESTEXEC}|" \ @@ -91,19 +96,20 @@ pathnames.h: ${TOP}/.settings Makefile -e "s|%DESTRUN%|${DESTRUN}|" \ < pathtemplate.h > pathnames.h -pathnames: pathnames.${O} pathnames.h ${LIBBIND} Makefile - ${CC} ${CDEBUG} ${LDFLAGS} -o $@ pathnames.${O} \ - ${LIBBIND} ${SYSLIBS} +ns_signal.${O}: ns_signal.c + ${CC} ${CPPFLAGS} ${CFLAGS} -c $*.c + +.c.${O}: + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c distclean: clean rm -f ns_parser.c ns_parser.h clean: FRC - rm -f ${PROG} ${OBJS} core .depend + rm -f ${PROG}${EXE} ${OBJS} core .depend rm -f *.BAK *.CKP *~ *.orig rm -f tmp_version.c tmp_version.${O} - rm -f pathnames pathnames.${O} tmp_pathnames.h pathnames.h - rm -f y.tab.h y.tab.c + rm -f pathnames.h y.tab.h y.tab.c depend: ${SRCS} pathnames.h mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${DEFS} ${SRCS} @@ -111,8 +117,8 @@ depend: ${SRCS} pathnames.h ${DESTDIR}${DESTSBIN}: mkdir -p ${DESTDIR}${DESTSBIN} -install: ${DESTDIR}${DESTSBIN} ${PROG} - ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTSBIN}/${PROG} +install: ${DESTDIR}${DESTSBIN} ${PROG}${EXE} + ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTSBIN}/${PROG}${EXE} links: FRC @ln -s SRC/*.[chy] SRC/test .; rm -f ns_parser.[ch] 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<> ((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 #include #include +#include #include #include @@ -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 #include #include +#include +#include #include #include @@ -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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 #include #include +#include #include #include @@ -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 #include #include +#include #include #include @@ -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 #include #include +#include #include #include @@ -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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#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: + * + */ + 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) ? "" : (*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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#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 #include #include +#include #include #include @@ -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 #include +#include + +#include #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 #include #include #include +#include #include #include @@ -46,6 +67,8 @@ static char rcsid[] = "$Id: ns_config.c,v 8.35 1998/05/05 19:44:48 halley Exp $" #include #include +#include + #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; iz_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 +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 #include #include +#include #include #include @@ -95,6 +96,8 @@ static char rcsid[] = "$Id: ns_forw.c,v 8.34 1998/02/24 01:02:40 halley Exp $"; #include #include +#include + #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 #include #include +#include #include #include @@ -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 #include #include +#include #include #include @@ -97,6 +98,8 @@ static char rcsid[] = "$Id: ns_init.c,v 8.40 1998/04/07 18:11:58 halley Exp $"; #include #include +#include + #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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 */ + 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 +#include +#include #include #include @@ -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: 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 #include #include +#include #ifdef SVR4 /* XXX */ # include #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 @@ -80,11 +100,13 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $"; #include #include #include +#include #include #include #include +#include #include #include #include @@ -99,25 +121,25 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $"; #include #include +#include + #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 #include #include +#include #include #include @@ -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 +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#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.c b/contrib/bind/bin/named/ns_parser.c index 47944ea..03d0a84 100644 --- a/contrib/bind/bin/named/ns_parser.c +++ b/contrib/bind/bin/named/ns_parser.c @@ -13,11 +13,11 @@ static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93 (BSDI)"; #define YYPREFIX "yy" #line 2 "ns_parser.y" #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $"; +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 @@ -38,6 +38,8 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include "port_before.h" #include +#include +#include #include #include @@ -45,6 +47,7 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include #include +#include #include #include #include @@ -54,6 +57,8 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include #include +#include + #include "port_after.h" #include "named.h" @@ -74,11 +79,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; @@ -103,8 +110,8 @@ static void define_channel(char *, log_channel); static char *canonical_name(char *); int yyparse(); - -#line 96 "ns_parser.y" + +#line 103 "ns_parser.y" typedef union { char * cp; int s_int; @@ -114,10 +121,12 @@ typedef union { 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; } YYSTYPE; -#line 121 "y.tab.c" +#line 130 "y.tab.c" #define L_EOS 257 #define L_IPADDR 258 #define L_NUMBER 259 @@ -139,231 +148,316 @@ typedef union { #define T_LISTEN_ON 275 #define T_PORT 276 #define T_ADDRESS 277 -#define T_DATASIZE 278 -#define T_STACKSIZE 279 -#define T_CORESIZE 280 -#define T_DEFAULT 281 -#define T_UNLIMITED 282 -#define T_FILES 283 -#define T_HOSTSTATS 284 -#define T_DEALLOC_ON_EXIT 285 -#define T_TRANSFERS_IN 286 -#define T_TRANSFERS_OUT 287 -#define T_TRANSFERS_PER_NS 288 -#define T_TRANSFER_FORMAT 289 -#define T_MAX_TRANSFER_TIME_IN 290 -#define T_ONE_ANSWER 291 -#define T_MANY_ANSWERS 292 -#define T_NOTIFY 293 -#define T_AUTH_NXDOMAIN 294 -#define T_MULTIPLE_CNAMES 295 -#define T_CLEAN_INTERVAL 296 -#define T_INTERFACE_INTERVAL 297 -#define T_STATS_INTERVAL 298 -#define T_LOGGING 299 -#define T_CATEGORY 300 -#define T_CHANNEL 301 -#define T_SEVERITY 302 -#define T_DYNAMIC 303 -#define T_FILE 304 -#define T_VERSIONS 305 -#define T_SIZE 306 -#define T_SYSLOG 307 -#define T_DEBUG 308 -#define T_NULL_OUTPUT 309 -#define T_PRINT_TIME 310 -#define T_PRINT_CATEGORY 311 -#define T_PRINT_SEVERITY 312 -#define T_TOPOLOGY 313 -#define T_SERVER 314 -#define T_LONG_AXFR 315 -#define T_BOGUS 316 -#define T_TRANSFERS 317 -#define T_KEYS 318 -#define T_ZONE 319 -#define T_IN 320 -#define T_CHAOS 321 -#define T_HESIOD 322 -#define T_TYPE 323 -#define T_MASTER 324 -#define T_SLAVE 325 -#define T_STUB 326 -#define T_RESPONSE 327 -#define T_HINT 328 -#define T_MASTERS 329 -#define T_TRANSFER_SOURCE 330 -#define T_ALSO_NOTIFY 331 -#define T_ACL 332 -#define T_ALLOW_UPDATE 333 -#define T_ALLOW_QUERY 334 -#define T_ALLOW_TRANSFER 335 -#define T_SEC_KEY 336 -#define T_ALGID 337 -#define T_SECRET 338 -#define T_CHECK_NAMES 339 -#define T_WARN 340 -#define T_FAIL 341 -#define T_IGNORE 342 -#define T_FORWARD 343 -#define T_FORWARDERS 344 -#define T_ONLY 345 -#define T_FIRST 346 -#define T_IF_NO_ANSWER 347 -#define T_IF_NO_DOMAIN 348 -#define T_YES 349 -#define T_TRUE 350 -#define T_NO 351 -#define T_FALSE 352 +#define T_RRSET_ORDER 278 +#define T_ORDER 279 +#define T_NAME 280 +#define T_CLASS 281 +#define T_CONTROLS 282 +#define T_INET 283 +#define T_UNIX 284 +#define T_PERM 285 +#define T_OWNER 286 +#define T_GROUP 287 +#define T_ALLOW 288 +#define T_DATASIZE 289 +#define T_STACKSIZE 290 +#define T_CORESIZE 291 +#define T_DEFAULT 292 +#define T_UNLIMITED 293 +#define T_FILES 294 +#define T_VERSION 295 +#define T_HOSTSTATS 296 +#define T_DEALLOC_ON_EXIT 297 +#define T_TRANSFERS_IN 298 +#define T_TRANSFERS_OUT 299 +#define T_TRANSFERS_PER_NS 300 +#define T_TRANSFER_FORMAT 301 +#define T_MAX_TRANSFER_TIME_IN 302 +#define T_SERIAL_QUERIES 303 +#define T_ONE_ANSWER 304 +#define T_MANY_ANSWERS 305 +#define T_NOTIFY 306 +#define T_AUTH_NXDOMAIN 307 +#define T_MULTIPLE_CNAMES 308 +#define T_USE_IXFR 309 +#define T_MAINTAIN_IXFR_BASE 310 +#define T_CLEAN_INTERVAL 311 +#define T_INTERFACE_INTERVAL 312 +#define T_STATS_INTERVAL 313 +#define T_MAX_LOG_SIZE_IXFR 314 +#define T_HEARTBEAT 315 +#define T_USE_ID_POOL 316 +#define T_MAX_NCACHE_TTL 317 +#define T_HAS_OLD_CLIENTS 318 +#define T_RFC2308_TYPE1 319 +#define T_LAME_TTL 320 +#define T_MIN_ROOTS 321 +#define T_TREAT_CR_AS_SPACE 322 +#define T_LOGGING 323 +#define T_CATEGORY 324 +#define T_CHANNEL 325 +#define T_SEVERITY 326 +#define T_DYNAMIC 327 +#define T_FILE 328 +#define T_VERSIONS 329 +#define T_SIZE 330 +#define T_SYSLOG 331 +#define T_DEBUG 332 +#define T_NULL_OUTPUT 333 +#define T_PRINT_TIME 334 +#define T_PRINT_CATEGORY 335 +#define T_PRINT_SEVERITY 336 +#define T_SORTLIST 337 +#define T_TOPOLOGY 338 +#define T_SERVER 339 +#define T_LONG_AXFR 340 +#define T_BOGUS 341 +#define T_TRANSFERS 342 +#define T_KEYS 343 +#define T_SUPPORT_IXFR 344 +#define T_ZONE 345 +#define T_IN 346 +#define T_CHAOS 347 +#define T_HESIOD 348 +#define T_TYPE 349 +#define T_MASTER 350 +#define T_SLAVE 351 +#define T_STUB 352 +#define T_RESPONSE 353 +#define T_HINT 354 +#define T_MASTERS 355 +#define T_TRANSFER_SOURCE 356 +#define T_PUBKEY 357 +#define T_ALSO_NOTIFY 358 +#define T_DIALUP 359 +#define T_FILE_IXFR 360 +#define T_IXFR_TMP 361 +#define T_TRUSTED_KEYS 362 +#define T_ACL 363 +#define T_ALLOW_UPDATE 364 +#define T_ALLOW_QUERY 365 +#define T_ALLOW_TRANSFER 366 +#define T_ALLOW_RECURSION 367 +#define T_BLACKHOLE 368 +#define T_SEC_KEY 369 +#define T_ALGID 370 +#define T_SECRET 371 +#define T_CHECK_NAMES 372 +#define T_WARN 373 +#define T_FAIL 374 +#define T_IGNORE 375 +#define T_FORWARD 376 +#define T_FORWARDERS 377 +#define T_ONLY 378 +#define T_FIRST 379 +#define T_IF_NO_ANSWER 380 +#define T_IF_NO_DOMAIN 381 +#define T_YES 382 +#define T_TRUE 383 +#define T_NO 384 +#define T_FALSE 385 #define YYERRCODE 256 short yylhs[] = { -1, - 0, 25, 25, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 27, 34, 28, 35, 35, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 38, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 5, 5, 4, 4, 3, 3, 43, 44, 40, 40, - 40, 40, 2, 2, 23, 23, 23, 23, 23, 21, - 21, 21, 22, 22, 22, 37, 37, 37, 37, 41, - 41, 41, 41, 20, 20, 20, 20, 42, 42, 42, - 39, 39, 45, 45, 46, 47, 29, 48, 48, 48, - 50, 49, 52, 49, 54, 54, 54, 54, 55, 55, - 56, 57, 57, 57, 57, 57, 58, 9, 9, 10, - 10, 59, 60, 60, 60, 60, 60, 60, 60, 53, - 53, 53, 8, 8, 61, 51, 51, 51, 7, 7, - 7, 6, 62, 30, 63, 63, 64, 64, 64, 64, - 64, 14, 14, 12, 12, 11, 11, 11, 11, 11, - 13, 17, 66, 65, 65, 65, 67, 33, 68, 68, - 68, 18, 19, 32, 70, 31, 69, 69, 15, 15, - 16, 16, 16, 16, 71, 71, 72, 72, 72, 72, - 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, - 75, 74, 74, 76, 76, 77, 1, 24, 24, + 0, 31, 31, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 33, 42, 34, 43, 43, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 46, 44, 44, 44, 44, 44, + 44, 44, 49, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 35, 53, 53, 54, 54, 54, 54, + 15, 15, 12, 12, 13, 13, 14, 14, 16, 6, + 6, 5, 5, 4, 4, 55, 56, 48, 48, 48, + 48, 2, 2, 3, 3, 29, 29, 29, 29, 29, + 27, 27, 27, 28, 28, 28, 45, 45, 45, 45, + 51, 51, 51, 51, 26, 26, 26, 26, 52, 52, + 52, 47, 47, 57, 57, 58, 50, 50, 59, 59, + 60, 61, 36, 62, 62, 62, 64, 63, 66, 63, + 68, 68, 68, 68, 69, 69, 70, 71, 71, 71, + 71, 71, 72, 10, 10, 11, 11, 73, 74, 74, + 74, 74, 74, 74, 74, 67, 67, 67, 9, 9, + 75, 65, 65, 65, 8, 8, 8, 7, 76, 37, + 77, 77, 78, 78, 78, 78, 78, 78, 20, 20, + 18, 18, 18, 17, 17, 17, 17, 17, 19, 23, + 80, 79, 79, 79, 81, 41, 82, 82, 82, 24, + 25, 40, 84, 38, 83, 83, 21, 21, 22, 22, + 22, 22, 22, 85, 85, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 89, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 87, 87, 92, + 91, 91, 93, 93, 94, 88, 88, 90, 90, 95, + 95, 96, 39, 97, 97, 98, 98, 1, 30, 30, }; short yylen[] = { 2, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, - 1, 2, 2, 3, 0, 5, 2, 3, 0, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 3, 5, 2, 0, 5, 2, 4, - 4, 4, 1, 1, 2, 2, 2, 2, 2, 1, - 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, - 2, 2, 0, 2, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, - 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, - 0, 1, 2, 3, 1, 0, 5, 2, 3, 1, - 0, 6, 0, 6, 1, 1, 2, 1, 2, 2, - 2, 0, 1, 1, 2, 2, 3, 1, 1, 0, - 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, - 3, 1, 1, 1, 1, 2, 3, 1, 1, 1, - 1, 1, 0, 6, 2, 3, 2, 2, 2, 4, - 1, 2, 3, 1, 2, 1, 3, 3, 1, 3, - 1, 1, 1, 2, 3, 1, 0, 6, 2, 2, - 1, 3, 3, 5, 0, 5, 0, 3, 0, 1, - 1, 1, 1, 1, 2, 3, 2, 2, 4, 2, - 2, 4, 4, 4, 2, 2, 4, 1, 2, 3, - 1, 0, 1, 2, 3, 1, 1, 1, 1, + 2, 2, 1, 2, 2, 3, 0, 5, 2, 3, + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 2, 2, 5, 2, 0, 5, 2, 2, 4, 4, + 4, 4, 0, 5, 4, 4, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, + 2, 2, 1, 4, 2, 3, 0, 8, 8, 1, + 2, 3, 0, 2, 0, 2, 0, 2, 5, 1, + 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, + 2, 0, 2, 0, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, + 2, 0, 1, 2, 3, 1, 0, 1, 2, 3, + 1, 0, 5, 2, 3, 1, 0, 6, 0, 6, + 1, 1, 2, 1, 2, 2, 2, 0, 1, 1, + 2, 2, 3, 1, 1, 0, 1, 2, 1, 1, + 1, 2, 2, 2, 2, 2, 3, 1, 1, 1, + 1, 2, 3, 1, 1, 1, 1, 1, 0, 6, + 2, 3, 2, 2, 2, 2, 4, 1, 2, 3, + 1, 2, 2, 1, 3, 3, 1, 3, 1, 1, + 1, 2, 3, 1, 0, 6, 2, 2, 1, 3, + 3, 5, 0, 5, 0, 3, 0, 1, 1, 1, + 1, 1, 1, 2, 3, 2, 2, 2, 2, 5, + 2, 2, 4, 4, 4, 2, 0, 5, 2, 2, + 2, 2, 5, 5, 4, 2, 1, 2, 3, 1, + 0, 1, 2, 3, 1, 1, 1, 0, 1, 2, + 3, 1, 4, 2, 3, 5, 5, 1, 1, 1, }; short yydefred[] = { 0, - 0, 11, 0, 15, 96, 0, 0, 0, 167, 0, - 0, 2, 4, 0, 0, 0, 0, 0, 0, 12, - 13, 0, 0, 0, 143, 0, 208, 209, 0, 0, - 3, 5, 6, 7, 8, 9, 10, 14, 0, 0, - 0, 175, 180, 0, 0, 50, 0, 0, 0, 0, + 0, 13, 0, 17, 0, 142, 0, 0, 0, 0, + 215, 0, 0, 2, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 14, 15, 0, 0, 0, 0, 189, + 0, 0, 279, 280, 0, 0, 3, 5, 6, 7, + 8, 9, 10, 11, 12, 16, 0, 80, 0, 0, + 0, 0, 0, 0, 223, 228, 0, 0, 0, 0, + 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, - 0, 0, 43, 44, 100, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 154, 0, 159, 0, 161, - 0, 20, 22, 21, 25, 23, 24, 69, 65, 66, - 67, 68, 26, 27, 28, 0, 0, 39, 0, 0, - 0, 0, 85, 86, 87, 80, 84, 81, 82, 83, - 30, 31, 88, 89, 90, 51, 52, 45, 46, 29, - 32, 33, 47, 48, 49, 0, 0, 0, 70, 71, - 72, 0, 76, 77, 78, 79, 36, 0, 16, 0, - 17, 140, 141, 101, 142, 139, 134, 103, 133, 97, - 0, 98, 151, 0, 0, 0, 0, 0, 0, 0, - 176, 0, 0, 0, 155, 152, 174, 0, 171, 0, - 0, 0, 0, 0, 207, 56, 55, 58, 53, 54, - 57, 61, 62, 64, 0, 0, 0, 0, 73, 74, - 75, 34, 0, 18, 0, 0, 99, 149, 147, 148, - 0, 144, 0, 145, 198, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 157, 158, - 160, 153, 0, 0, 169, 170, 168, 0, 42, 40, - 41, 95, 0, 0, 0, 0, 0, 166, 163, 162, - 0, 0, 146, 195, 196, 188, 181, 182, 184, 183, - 187, 0, 190, 0, 0, 0, 0, 191, 178, 0, - 185, 172, 173, 35, 38, 0, 93, 138, 135, 0, - 0, 132, 0, 0, 0, 125, 0, 0, 0, 0, - 123, 124, 0, 150, 0, 164, 201, 0, 0, 206, - 0, 0, 0, 0, 0, 0, 186, 94, 102, 0, - 136, 108, 0, 105, 126, 0, 119, 121, 122, 118, - 127, 128, 129, 104, 0, 130, 165, 189, 0, 199, - 197, 0, 204, 192, 193, 194, 137, 107, 0, 0, - 0, 0, 117, 131, 200, 205, 109, 110, 111, 115, - 116, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, + 0, 0, 0, 0, 0, 45, 0, 0, 57, 58, + 92, 93, 0, 0, 74, 0, 75, 146, 0, 0, + 0, 0, 0, 0, 0, 0, 273, 0, 274, 0, + 0, 0, 0, 0, 201, 0, 207, 0, 209, 0, + 23, 25, 24, 28, 26, 27, 110, 106, 107, 108, + 109, 29, 30, 31, 0, 0, 47, 0, 0, 0, + 0, 0, 126, 127, 128, 121, 125, 122, 123, 124, + 22, 33, 34, 129, 130, 131, 90, 91, 59, 60, + 61, 32, 38, 39, 35, 36, 62, 63, 64, 65, + 68, 41, 66, 37, 42, 67, 72, 71, 0, 0, + 48, 0, 69, 0, 0, 0, 0, 111, 112, 113, + 0, 117, 118, 119, 120, 44, 0, 18, 0, 19, + 0, 0, 76, 186, 187, 147, 188, 185, 180, 149, + 179, 143, 0, 144, 198, 0, 0, 0, 0, 0, + 0, 0, 0, 224, 0, 0, 275, 0, 0, 203, + 0, 202, 199, 222, 0, 219, 0, 0, 0, 0, + 0, 278, 95, 94, 97, 96, 100, 101, 103, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 114, 115, 116, 40, 0, 20, 0, 0, 0, + 0, 145, 196, 193, 195, 0, 194, 190, 0, 191, + 257, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, + 0, 0, 0, 0, 205, 206, 208, 200, 0, 0, + 217, 218, 216, 0, 84, 0, 0, 70, 0, 81, + 52, 56, 141, 0, 0, 0, 49, 51, 50, 55, + 136, 0, 0, 0, 0, 0, 0, 0, 214, 211, + 210, 0, 0, 192, 249, 251, 252, 250, 237, 229, + 230, 232, 231, 233, 236, 0, 0, 241, 0, 0, + 0, 256, 238, 239, 0, 0, 0, 242, 266, 267, + 246, 0, 226, 0, 234, 276, 277, 220, 221, 43, + 86, 0, 0, 82, 54, 0, 139, 46, 0, 134, + 0, 0, 184, 181, 0, 0, 178, 0, 0, 0, + 171, 0, 0, 0, 0, 169, 170, 0, 197, 0, + 212, 105, 0, 0, 0, 265, 0, 0, 0, 0, + 0, 0, 0, 235, 88, 0, 140, 135, 0, 0, + 148, 0, 182, 154, 0, 151, 172, 0, 165, 167, + 168, 164, 173, 174, 175, 150, 0, 176, 213, 260, + 0, 0, 0, 0, 255, 0, 263, 243, 244, 245, + 272, 0, 0, 0, 89, 78, 79, 183, 153, 0, + 0, 0, 0, 163, 177, 240, 0, 258, 253, 254, + 264, 248, 0, 270, 155, 156, 157, 161, 162, 259, + 271, }; -short yydgoto[] = { 10, - 197, 122, 198, 201, 138, 164, 165, 289, 328, 329, - 96, 97, 98, 99, 42, 271, 259, 192, 193, 126, - 152, 212, 113, 100, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 23, 81, 82, 157, 158, 253, 118, - 83, 84, 119, 120, 254, 255, 24, 88, 89, 215, - 290, 216, 300, 325, 351, 352, 353, 301, 302, 303, - 291, 41, 178, 179, 261, 262, 30, 194, 181, 91, - 237, 238, 308, 311, 309, 312, 313, +short yydgoto[] = { 12, + 274, 171, 387, 275, 123, 189, 236, 237, 424, 470, + 471, 282, 347, 413, 283, 284, 145, 146, 147, 148, + 55, 385, 370, 269, 270, 176, 221, 295, 162, 149, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 27, 117, 118, 226, 227, 362, 167, 212, 354, + 119, 120, 51, 52, 168, 169, 363, 364, 355, 356, + 29, 131, 132, 300, 425, 301, 435, 467, 502, 503, + 504, 436, 437, 438, 426, 54, 251, 252, 372, 373, + 36, 271, 254, 134, 331, 332, 481, 401, 402, 492, + 447, 482, 448, 449, 493, 494, 58, 59, }; -short yysindex[] = { 122, - -200, 0, -238, 0, 0, -227, -228, -188, 0, 0, - 122, 0, 0, -220, -176, -164, -158, -155, -149, 0, - 0, -147, -88, -4, 0, -188, 0, 0, 4, -188, - 0, 0, 0, 0, 0, 0, 0, 0, 79, -240, - 11, 0, 0, 16, 20, 0, -218, -60, -40, -34, - -24, -14, -53, -53, -53, -193, -95, -190, -190, -190, - -190, -53, -53, -98, -56, -41, -162, -31, -53, -53, - -53, 6, 19, 22, 102, 161, 163, -204, -57, 0, - -120, 36, 0, 0, 0, -73, -205, -115, 38, -241, - 177, 257, 258, 16, -69, 0, 49, 0, -29, 0, - -226, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, -33, -36, 0, 31, 32, - 51, 185, 0, 0, 0, 0, 0, 0, 0, 0, +short yysindex[] = { 419, + -172, 0, -236, 0, -91, 0, -224, -211, -71, -178, + 0, 0, 419, 0, 0, -166, -160, -158, -156, -154, + -144, -139, -128, 0, 0, -126, -49, -195, 10, 0, + -178, -198, 0, 0, 12, -178, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 349, 0, -7, -123, + -112, -115, -238, 23, 0, 0, -189, -110, -105, 43, + 31, 0, -98, -96, -94, -85, -76, -73, -190, -190, + -190, -86, -106, 33, -81, -81, -81, -81, -58, -190, + -190, -59, -50, -45, -121, -34, -32, -190, -190, -190, + -190, -190, 51, 56, 63, 64, 66, -190, 68, -190, + -190, 69, 71, -190, 123, 136, -7, 0, -190, 212, + 219, 220, 222, -258, -182, 0, 168, 89, 0, 0, + 0, 0, 73, 62, 0, 93, 0, 0, -181, -216, + -69, 94, -220, 230, 95, 96, 0, 99, 0, 312, + 313, 104, 43, -100, 0, 108, 0, -29, 0, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, - 0, -277, 0, 0, 0, 0, 0, 188, 0, 55, + 0, 0, 0, 0, -31, -7, 0, 100, 92, 111, + 254, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 57, 0, 0, -162, -53, 56, 193, -118, 60, 104, - 0, 59, 63, -25, 0, 0, 0, 69, 0, -188, - -188, -11, -7, 203, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 16, -20, -16, -9, 0, 0, - 0, 0, 73, 0, 209, 210, 0, 0, 0, 0, - -143, 0, 77, 0, 0, 78, -53, 75, -184, 215, - -36, 216, 217, 218, 232, -277, -10, 99, 0, 0, - 0, 0, 113, 114, 0, 0, 0, -1, 0, 0, - 0, 0, 236, 73, 123, -214, -222, 0, 0, 0, - -81, 124, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 121, 0, 125, 16, 16, 16, 0, 0, 130, - 0, 0, 0, 0, 0, 131, 0, 0, 0, -104, - 132, 0, -202, 129, -221, 0, -53, -53, -53, -100, - 0, 0, 134, 0, 136, 0, 0, -96, 138, 0, - 271, 125, 141, 3, 8, 12, 0, 0, 0, 142, - 0, 0, 143, 0, 0, -89, 0, 0, 0, 0, - 0, 0, 0, 0, 144, 0, 0, 0, 146, 0, - 0, 147, 0, 0, 0, 0, 0, 0, -185, -190, - 76, 100, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 43, 43, + 0, 257, 0, 43, 43, 43, 43, 0, 0, 0, + -68, 0, 0, 0, 0, 0, 258, 0, 127, 0, + 111, 126, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 129, 0, 0, -121, -190, 130, 265, -190, + -120, 133, 374, 0, 134, 135, 0, 137, 138, 0, + -25, 0, 0, 0, 141, 0, -178, -178, 21, 32, + 275, 0, 0, 0, 0, 0, 0, 0, 0, 43, + -178, 52, -108, 146, -21, -17, 147, -11, 5, 9, + 14, 0, 0, 0, 0, 148, 0, 116, 121, 286, + 287, 0, 0, 0, 0, -151, 0, 0, 154, 0, + 0, 155, -190, -190, 157, 152, -13, 143, -7, 35, + 294, -190, 160, 161, 300, 302, 304, -68, -70, 0, + 236, 171, 169, 170, 0, 0, 0, 0, 172, 175, + 0, 0, 0, 18, 0, -178, 164, 0, 188, 0, + 0, 0, 0, 322, 147, 191, 0, 0, 0, 0, + 0, 324, 148, 193, 328, 194, -207, -2, 0, 0, + 0, -92, 195, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 111, 331, 0, 196, 197, + 202, 0, 0, 0, 43, 43, 43, 0, 0, 0, + 0, 338, 0, 215, 0, 0, 0, 0, 0, 0, + 0, 232, 216, 0, 0, 237, 0, 0, 239, 0, + 43, 186, 0, 0, -41, 243, 0, -145, 240, -183, + 0, -190, -190, -190, -118, 0, 0, 245, 0, 246, + 0, 0, 249, 250, 251, 0, 379, 202, 255, 22, + 26, 30, 253, 0, 0, 248, 0, 0, 39, 256, + 0, 259, 0, 0, 260, 0, 0, -16, 0, 0, + 0, 0, 0, 0, 0, 0, 261, 0, 0, 0, + -101, 263, 252, 264, 0, 271, 0, 0, 0, 0, + 0, 389, 253, 272, 0, 0, 0, 0, 0, -218, + -81, 187, 192, 0, 0, 0, 273, 0, 0, 0, + 0, 0, 274, 0, 0, 0, 0, 0, 0, 0, 0, }; short yyrindex[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, -85, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 149, 0, + 0, 0, 522, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 280, 0, 0, + -117, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 282, 0, 0, 0, + 280, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 409, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 149, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 155, 158, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 159, 160, + 0, 0, 0, 284, 0, 0, 0, 0, 0, 290, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 291, 292, 0, + 0, -222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -371,137 +465,215 @@ short yyrindex[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 294, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 295, 0, 0, 0, 0, 0, 0, + 0, 41, -222, 0, 0, 0, 418, 0, 0, 0, + 0, 0, 0, 0, 0, 426, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 299, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 429, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 171, 0, 0, 172, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 276, 0, 0, 0, + 0, 0, 0, 0, 428, 0, 0, 0, 0, 0, + 0, 0, 431, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 173, 174, 0, 0, 0, 0, 0, 0, 0, 0, + 432, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 297, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 433, 0, 0, + 0, 0, 434, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 303, 0, 0, 305, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 436, 0, 0, 0, 0, 0, 0, 0, + 0, 306, 308, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; short yygindex[] = { 0, - 311, 0, 0, 211, 266, 0, 0, 357, 0, 0, - 350, 95, 0, -80, 0, 0, 0, 253, 255, -58, - 0, 212, -43, -8, 0, 438, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 369, 0, 0, 0, 0, - 0, 0, 331, 333, 0, 199, 0, 0, 367, 0, - 0, 0, 0, 0, 105, 108, 0, 0, 0, 156, - 170, 0, 0, 283, 0, 201, 0, 0, 0, 0, - 0, 226, 0, 0, 157, 0, 152, + -124, 0, 0, 0, -93, 320, 0, 0, 437, 0, + 0, 0, 0, 0, 0, 285, 425, -84, 0, 102, + 0, 0, 0, 301, 307, -75, 0, 242, -61, -10, + 0, 559, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 456, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 523, 406, 410, 0, 214, 0, 224, + 0, 0, 449, 0, 0, 0, 0, 0, 78, 80, + 0, 0, 0, 149, 158, 0, 0, 335, 0, 217, + 0, 0, 0, 0, 0, 267, 0, 0, 0, 0, + 0, 106, 0, 140, 0, 97, 0, 541, }; -#define YYTABLESIZE 465 -short yytable[] = { 29, - 128, 129, 130, 95, 159, 200, 222, 95, 196, 170, - 114, 115, 95, 184, 173, 85, 95, 43, 131, 132, - 319, 45, 22, 95, 334, 140, 141, 142, 338, 189, - 25, 95, 26, 292, 39, 95, 32, 179, 27, 28, - 95, 288, 102, 304, 95, 27, 28, 174, 95, 127, - 127, 127, 127, 94, 27, 28, 20, 27, 28, 86, - 87, 21, 209, 210, 211, 206, 207, 208, 123, 27, - 28, 27, 28, 357, 175, 176, 177, 166, 169, 293, - 33, 294, 116, 117, 295, 327, 296, 297, 298, 299, - 124, 125, 34, 94, 167, 187, 358, 94, 35, 241, - 322, 36, 94, 167, 249, 323, 94, 37, 250, 38, - 190, 191, 258, 94, 279, 251, 27, 28, 40, 149, - 150, 94, 151, 284, 248, 94, 44, 344, 136, 137, - 94, 219, 345, 90, 94, 46, 346, 173, 94, 267, - 268, 269, 101, 270, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 27, 28, 58, 59, 60, - 133, 307, 61, 62, 63, 64, 65, 66, 67, 68, - 174, 179, 69, 70, 71, 72, 73, 74, 27, 28, - 121, 243, 244, 265, 86, 87, 27, 28, 92, 93, - 27, 28, 75, 188, 314, 315, 316, 175, 176, 177, - 103, 293, 134, 294, 167, 108, 295, 162, 296, 297, - 298, 299, 260, 76, 77, 349, 350, 135, 78, 163, - 104, 199, 79, 80, 146, 195, 105, 139, 92, 93, - 27, 28, 92, 93, 27, 28, 106, 92, 93, 27, - 28, 92, 93, 27, 28, 225, 107, 169, 92, 93, - 27, 28, 260, 331, 332, 333, 92, 93, 27, 28, - 92, 93, 27, 28, 143, 92, 93, 27, 28, 92, - 93, 27, 28, 92, 93, 27, 28, 144, 188, 226, - 145, 169, 227, 147, 324, 148, 330, 153, 154, 155, - 156, 359, 161, 228, 172, 109, 110, 111, 112, 180, - 188, 188, 188, 182, 183, 186, 116, 205, 117, 195, - 213, 214, 229, 217, 220, 221, 224, 239, 230, 231, - 232, 240, 233, 234, 235, 242, 191, 247, 236, 190, - 252, 256, 257, 263, 46, 266, 264, 272, 274, 275, - 276, 127, 188, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 277, 281, 58, 59, 60, 225, - 285, 61, 62, 63, 64, 65, 66, 67, 68, 282, - 283, 69, 70, 71, 72, 73, 74, 1, 307, 287, - 306, 350, 310, 2, 3, 4, 317, 318, 321, 326, - 336, 75, 337, 226, 340, 341, 227, 343, 347, 1, - 354, 348, 355, 356, 349, 19, 63, 228, 188, 188, - 188, 177, 76, 77, 156, 59, 60, 78, 91, 92, - 5, 79, 80, 202, 120, 203, 229, 106, 112, 113, - 114, 204, 230, 231, 232, 6, 233, 234, 235, 218, - 7, 273, 236, 168, 185, 246, 245, 278, 31, 160, - 203, 202, 286, 8, 171, 335, 361, 9, 360, 320, - 223, 305, 280, 342, 339, +#define YYTABLESIZE 788 +short yytable[] = { 35, + 178, 179, 180, 144, 308, 227, 476, 144, 163, 164, + 273, 144, 125, 211, 137, 144, 348, 128, 182, 183, + 56, 144, 143, 506, 26, 61, 192, 193, 194, 195, + 196, 28, 439, 30, 122, 245, 202, 144, 204, 205, + 515, 144, 208, 33, 34, 279, 144, 213, 423, 31, + 144, 32, 33, 34, 144, 242, 83, 83, 144, 266, + 48, 57, 144, 265, 177, 177, 177, 177, 157, 135, + 136, 144, 276, 47, 516, 144, 33, 34, 33, 34, + 246, 33, 34, 461, 24, 129, 130, 49, 50, 25, + 38, 218, 219, 143, 220, 264, 39, 143, 40, 337, + 41, 143, 42, 351, 369, 143, 298, 352, 33, 34, + 234, 143, 43, 357, 33, 34, 239, 44, 238, 241, + 247, 248, 249, 250, 235, 239, 83, 143, 45, 358, + 46, 143, 53, 359, 60, 245, 143, 124, 360, 227, + 143, 127, 410, 48, 143, 133, 488, 469, 143, 57, + 489, 139, 143, 150, 490, 172, 480, 140, 141, 33, + 34, 143, 151, 496, 152, 143, 153, 33, 34, 170, + 49, 50, 281, 267, 268, 154, 265, 173, 33, 34, + 246, 464, 187, 188, 155, 304, 465, 156, 307, 165, + 166, 158, 159, 160, 161, 222, 223, 224, 225, 184, + 265, 265, 181, 265, 265, 265, 265, 428, 185, 429, + 174, 175, 430, 186, 431, 432, 433, 434, 33, 34, + 247, 248, 249, 250, 190, 388, 191, 272, 140, 141, + 33, 34, 140, 141, 33, 34, 140, 141, 33, 34, + 140, 141, 33, 34, 261, 209, 140, 141, 33, 34, + 121, 376, 377, 427, 129, 130, 339, 340, 210, 265, + 392, 442, 140, 141, 33, 34, 140, 141, 33, 34, + 345, 140, 141, 33, 34, 140, 141, 33, 34, 140, + 141, 33, 34, 140, 141, 33, 34, 140, 141, 33, + 34, 239, 228, 389, 390, 371, 140, 141, 33, 34, + 140, 141, 33, 34, 292, 293, 294, 399, 400, 197, + 285, 286, 500, 501, 198, 288, 289, 290, 291, 85, + 85, 199, 200, 428, 201, 429, 203, 206, 430, 207, + 431, 432, 433, 434, 214, 411, 380, 381, 382, 142, + 383, 215, 216, 142, 217, 230, 232, 142, 231, 233, + 244, 142, 253, 255, 256, 257, 241, 142, 258, 259, + 403, 371, 384, 260, 263, 265, 265, 265, 166, 272, + 473, 474, 475, 142, 265, 165, 280, 142, 281, 287, + 296, 344, 142, 297, 299, 302, 142, 306, 305, 310, + 142, 268, 333, 334, 142, 335, 336, 338, 142, 343, + 346, 267, 350, 365, 353, 361, 366, 142, 367, 368, + 374, 142, 379, 375, 241, 378, 391, 466, 386, 472, + 393, 394, 395, 62, 396, 517, 397, 405, 408, 406, + 407, 409, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 412, 414, 74, 415, 417, 418, 420, + 421, 441, 422, 443, 444, 445, 75, 76, 77, 446, + 453, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 454, 460, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 177, 311, 455, 457, 456, 458, 450, 451, 452, 463, + 468, 478, 479, 485, 105, 106, 480, 495, 483, 484, + 491, 487, 509, 512, 497, 498, 501, 505, 499, 508, + 500, 1, 459, 107, 510, 108, 109, 511, 514, 520, + 521, 102, 110, 111, 112, 113, 77, 312, 21, 114, + 225, 313, 137, 115, 116, 314, 204, 98, 99, 315, + 132, 104, 138, 166, 87, 133, 261, 262, 268, 152, + 269, 158, 159, 316, 160, 303, 240, 349, 262, 398, + 342, 37, 229, 126, 278, 341, 419, 277, 416, 243, + 519, 518, 462, 477, 317, 309, 507, 486, 440, 513, + 318, 319, 320, 321, 322, 323, 324, 404, 138, 325, + 326, 327, 0, 0, 62, 0, 0, 328, 0, 0, + 0, 329, 330, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 0, 0, 74, 0, 0, 311, + 0, 0, 0, 0, 0, 0, 0, 75, 76, 77, + 0, 0, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 0, 0, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 0, 0, 0, 1, 312, 0, 0, 0, 313, + 2, 3, 4, 314, 0, 105, 106, 315, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 316, 0, 0, 107, 0, 108, 109, 0, 0, + 0, 0, 0, 110, 111, 112, 113, 0, 0, 0, + 114, 0, 317, 0, 115, 116, 0, 0, 318, 319, + 320, 321, 322, 323, 324, 0, 0, 325, 326, 327, + 0, 6, 0, 0, 0, 328, 0, 0, 0, 329, + 330, 0, 0, 0, 0, 0, 0, 7, 0, 0, + 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 10, 0, 0, 0, 0, 0, 11, }; -short yycheck[] = { 8, - 59, 60, 61, 33, 125, 42, 125, 33, 42, 125, - 54, 55, 33, 94, 256, 256, 33, 26, 62, 63, - 125, 30, 261, 33, 125, 69, 70, 71, 125, 256, - 258, 33, 261, 256, 123, 33, 257, 123, 260, 261, - 33, 256, 261, 125, 33, 260, 261, 289, 33, 58, - 59, 60, 61, 123, 260, 261, 257, 260, 261, 300, - 301, 262, 340, 341, 342, 146, 147, 148, 259, 260, - 261, 260, 261, 259, 316, 317, 318, 86, 87, 302, - 257, 304, 276, 277, 307, 307, 309, 310, 311, 312, - 281, 282, 257, 123, 309, 125, 282, 123, 257, 125, - 303, 257, 123, 309, 125, 308, 123, 257, 125, 257, - 337, 338, 256, 123, 125, 125, 260, 261, 123, 324, - 325, 123, 327, 125, 205, 123, 123, 125, 291, 292, - 123, 175, 125, 123, 123, 256, 125, 256, 123, 324, - 325, 326, 123, 328, 265, 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, 260, 261, 278, 279, 280, - 259, 258, 283, 284, 285, 286, 287, 288, 289, 290, - 289, 257, 293, 294, 295, 296, 297, 298, 260, 261, - 276, 190, 191, 227, 300, 301, 260, 261, 258, 259, - 260, 261, 313, 99, 275, 276, 277, 316, 317, 318, - 261, 302, 259, 304, 309, 259, 307, 281, 309, 310, - 311, 312, 221, 334, 335, 305, 306, 259, 339, 293, - 261, 258, 343, 344, 123, 259, 261, 259, 258, 259, - 260, 261, 258, 259, 260, 261, 261, 258, 259, 260, - 261, 258, 259, 260, 261, 256, 261, 256, 258, 259, - 260, 261, 261, 297, 298, 299, 258, 259, 260, 261, - 258, 259, 260, 261, 259, 258, 259, 260, 261, 258, - 259, 260, 261, 258, 259, 260, 261, 259, 184, 290, - 259, 290, 293, 123, 293, 123, 295, 345, 346, 347, - 348, 350, 257, 304, 257, 349, 350, 351, 352, 123, - 206, 207, 208, 47, 47, 257, 276, 123, 277, 259, - 123, 257, 323, 257, 259, 123, 257, 259, 329, 330, - 331, 259, 333, 334, 335, 257, 338, 125, 339, 337, - 258, 123, 123, 257, 256, 261, 259, 123, 123, 123, - 123, 350, 248, 265, 266, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 123, 257, 278, 279, 280, 256, - 125, 283, 284, 285, 286, 287, 288, 289, 290, 257, - 257, 293, 294, 295, 296, 297, 298, 256, 258, 257, - 257, 306, 258, 262, 263, 264, 257, 257, 257, 261, - 257, 313, 257, 290, 257, 125, 293, 257, 257, 0, - 257, 259, 257, 257, 305, 257, 123, 304, 314, 315, - 316, 257, 334, 335, 257, 257, 257, 339, 125, 125, - 299, 343, 344, 125, 257, 125, 323, 257, 257, 257, - 257, 121, 329, 330, 331, 314, 333, 334, 335, 174, - 319, 231, 339, 87, 95, 193, 192, 236, 11, 81, - 120, 119, 254, 332, 88, 300, 352, 336, 351, 290, - 178, 261, 237, 312, 308, +short yycheck[] = { 10, + 76, 77, 78, 33, 125, 123, 125, 33, 70, 71, + 42, 33, 125, 107, 125, 33, 125, 256, 80, 81, + 31, 33, 123, 125, 261, 36, 88, 89, 90, 91, + 92, 123, 125, 258, 42, 256, 98, 33, 100, 101, + 259, 33, 104, 260, 261, 170, 33, 109, 256, 261, + 33, 123, 260, 261, 33, 125, 279, 280, 33, 256, + 256, 260, 33, 148, 75, 76, 77, 78, 259, 259, + 260, 33, 166, 123, 293, 33, 260, 261, 260, 261, + 301, 260, 261, 125, 257, 324, 325, 283, 284, 262, + 257, 350, 351, 123, 353, 125, 257, 123, 257, 125, + 257, 123, 257, 125, 256, 123, 231, 125, 260, 261, + 292, 123, 257, 125, 260, 261, 333, 257, 129, 130, + 341, 342, 343, 344, 306, 333, 349, 123, 257, 125, + 257, 123, 123, 125, 123, 256, 123, 261, 125, 257, + 123, 257, 125, 256, 123, 123, 125, 331, 123, 260, + 125, 257, 123, 123, 125, 123, 258, 258, 259, 260, + 261, 123, 261, 125, 261, 123, 261, 260, 261, 276, + 283, 284, 281, 370, 371, 261, 261, 259, 260, 261, + 301, 327, 304, 305, 261, 247, 332, 261, 250, 276, + 277, 382, 383, 384, 385, 378, 379, 380, 381, 259, + 285, 286, 261, 288, 289, 290, 291, 326, 259, 328, + 292, 293, 331, 259, 333, 334, 335, 336, 260, 261, + 341, 342, 343, 344, 259, 319, 259, 259, 258, 259, + 260, 261, 258, 259, 260, 261, 258, 259, 260, 261, + 258, 259, 260, 261, 143, 123, 258, 259, 260, 261, + 258, 313, 314, 256, 324, 325, 267, 268, 123, 344, + 322, 386, 258, 259, 260, 261, 258, 259, 260, 261, + 281, 258, 259, 260, 261, 258, 259, 260, 261, 258, + 259, 260, 261, 258, 259, 260, 261, 258, 259, 260, + 261, 333, 125, 259, 260, 306, 258, 259, 260, 261, + 258, 259, 260, 261, 373, 374, 375, 378, 379, 259, + 209, 210, 329, 330, 259, 214, 215, 216, 217, 279, + 280, 259, 259, 326, 259, 328, 259, 259, 331, 259, + 333, 334, 335, 336, 123, 346, 350, 351, 352, 369, + 354, 123, 123, 369, 123, 257, 285, 369, 276, 257, + 257, 369, 123, 259, 259, 257, 367, 369, 47, 47, + 125, 372, 376, 260, 257, 450, 451, 452, 277, 259, + 432, 433, 434, 369, 459, 276, 123, 369, 281, 123, + 123, 280, 369, 257, 259, 257, 369, 123, 259, 257, + 369, 371, 259, 259, 369, 259, 259, 257, 369, 125, + 349, 370, 257, 288, 258, 258, 286, 369, 123, 123, + 257, 369, 261, 259, 425, 259, 123, 428, 276, 430, + 261, 261, 123, 256, 123, 501, 123, 257, 257, 261, + 261, 257, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 280, 257, 278, 125, 257, 125, 257, + 123, 257, 259, 123, 259, 259, 289, 290, 291, 258, + 123, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 257, 287, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 501, 256, 261, 257, 279, 257, 395, 396, 397, 257, + 261, 257, 257, 125, 337, 338, 258, 260, 259, 259, + 258, 257, 261, 125, 259, 257, 330, 257, 259, 257, + 329, 0, 421, 356, 261, 358, 359, 257, 257, 257, + 257, 123, 365, 366, 367, 368, 257, 302, 257, 372, + 257, 306, 125, 376, 377, 310, 257, 257, 257, 314, + 125, 123, 125, 257, 279, 125, 125, 125, 125, 257, + 125, 257, 257, 328, 257, 246, 130, 283, 144, 328, + 270, 13, 117, 51, 169, 269, 363, 168, 355, 131, + 503, 502, 425, 435, 349, 251, 481, 448, 372, 493, + 355, 356, 357, 358, 359, 360, 361, 331, 58, 364, + 365, 366, -1, -1, 256, -1, -1, 372, -1, -1, + -1, 376, 377, 265, 266, 267, 268, 269, 270, 271, + 272, 273, 274, 275, -1, -1, 278, -1, -1, 256, + -1, -1, -1, -1, -1, -1, -1, 289, 290, 291, + -1, -1, 294, 295, 296, 297, 298, 299, 300, 301, + 302, 303, -1, -1, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, -1, -1, -1, 256, 302, -1, -1, -1, 306, + 262, 263, 264, 310, -1, 337, 338, 314, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 282, 328, -1, -1, 356, -1, 358, 359, -1, -1, + -1, -1, -1, 365, 366, 367, 368, -1, -1, -1, + 372, -1, 349, -1, 376, 377, -1, -1, 355, 356, + 357, 358, 359, 360, 361, -1, -1, 364, 365, 366, + -1, 323, -1, -1, -1, 372, -1, -1, -1, 376, + 377, -1, -1, -1, -1, -1, -1, 339, -1, -1, + -1, -1, -1, 345, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 362, 363, -1, -1, -1, -1, -1, 369, }; -#define YYFINAL 10 +#define YYFINAL 12 #ifndef YYDEBUG #define YYDEBUG 0 #endif -#define YYMAXTOKEN 352 +#define YYMAXTOKEN 385 #if YYDEBUG char *yyname[] = { "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -514,18 +686,25 @@ char *yyname[] = { "L_IPADDR","L_NUMBER","L_STRING","L_QSTRING","L_END_INCLUDE","T_INCLUDE", "T_OPTIONS","T_DIRECTORY","T_PIDFILE","T_NAMED_XFER","T_DUMP_FILE", "T_STATS_FILE","T_MEMSTATS_FILE","T_FAKE_IQUERY","T_RECURSION","T_FETCH_GLUE", -"T_QUERY_SOURCE","T_LISTEN_ON","T_PORT","T_ADDRESS","T_DATASIZE","T_STACKSIZE", -"T_CORESIZE","T_DEFAULT","T_UNLIMITED","T_FILES","T_HOSTSTATS", -"T_DEALLOC_ON_EXIT","T_TRANSFERS_IN","T_TRANSFERS_OUT","T_TRANSFERS_PER_NS", -"T_TRANSFER_FORMAT","T_MAX_TRANSFER_TIME_IN","T_ONE_ANSWER","T_MANY_ANSWERS", -"T_NOTIFY","T_AUTH_NXDOMAIN","T_MULTIPLE_CNAMES","T_CLEAN_INTERVAL", -"T_INTERFACE_INTERVAL","T_STATS_INTERVAL","T_LOGGING","T_CATEGORY","T_CHANNEL", +"T_QUERY_SOURCE","T_LISTEN_ON","T_PORT","T_ADDRESS","T_RRSET_ORDER","T_ORDER", +"T_NAME","T_CLASS","T_CONTROLS","T_INET","T_UNIX","T_PERM","T_OWNER","T_GROUP", +"T_ALLOW","T_DATASIZE","T_STACKSIZE","T_CORESIZE","T_DEFAULT","T_UNLIMITED", +"T_FILES","T_VERSION","T_HOSTSTATS","T_DEALLOC_ON_EXIT","T_TRANSFERS_IN", +"T_TRANSFERS_OUT","T_TRANSFERS_PER_NS","T_TRANSFER_FORMAT", +"T_MAX_TRANSFER_TIME_IN","T_SERIAL_QUERIES","T_ONE_ANSWER","T_MANY_ANSWERS", +"T_NOTIFY","T_AUTH_NXDOMAIN","T_MULTIPLE_CNAMES","T_USE_IXFR", +"T_MAINTAIN_IXFR_BASE","T_CLEAN_INTERVAL","T_INTERFACE_INTERVAL", +"T_STATS_INTERVAL","T_MAX_LOG_SIZE_IXFR","T_HEARTBEAT","T_USE_ID_POOL", +"T_MAX_NCACHE_TTL","T_HAS_OLD_CLIENTS","T_RFC2308_TYPE1","T_LAME_TTL", +"T_MIN_ROOTS","T_TREAT_CR_AS_SPACE","T_LOGGING","T_CATEGORY","T_CHANNEL", "T_SEVERITY","T_DYNAMIC","T_FILE","T_VERSIONS","T_SIZE","T_SYSLOG","T_DEBUG", "T_NULL_OUTPUT","T_PRINT_TIME","T_PRINT_CATEGORY","T_PRINT_SEVERITY", -"T_TOPOLOGY","T_SERVER","T_LONG_AXFR","T_BOGUS","T_TRANSFERS","T_KEYS","T_ZONE", -"T_IN","T_CHAOS","T_HESIOD","T_TYPE","T_MASTER","T_SLAVE","T_STUB","T_RESPONSE", -"T_HINT","T_MASTERS","T_TRANSFER_SOURCE","T_ALSO_NOTIFY","T_ACL", -"T_ALLOW_UPDATE","T_ALLOW_QUERY","T_ALLOW_TRANSFER","T_SEC_KEY","T_ALGID", +"T_SORTLIST","T_TOPOLOGY","T_SERVER","T_LONG_AXFR","T_BOGUS","T_TRANSFERS", +"T_KEYS","T_SUPPORT_IXFR","T_ZONE","T_IN","T_CHAOS","T_HESIOD","T_TYPE", +"T_MASTER","T_SLAVE","T_STUB","T_RESPONSE","T_HINT","T_MASTERS", +"T_TRANSFER_SOURCE","T_PUBKEY","T_ALSO_NOTIFY","T_DIALUP","T_FILE_IXFR", +"T_IXFR_TMP","T_TRUSTED_KEYS","T_ACL","T_ALLOW_UPDATE","T_ALLOW_QUERY", +"T_ALLOW_TRANSFER","T_ALLOW_RECURSION","T_BLACKHOLE","T_SEC_KEY","T_ALGID", "T_SECRET","T_CHECK_NAMES","T_WARN","T_FAIL","T_IGNORE","T_FORWARD", "T_FORWARDERS","T_ONLY","T_FIRST","T_IF_NO_ANSWER","T_IF_NO_DOMAIN","T_YES", "T_TRUE","T_NO","T_FALSE", @@ -537,9 +716,11 @@ char *yyrule[] = { "statement_list : statement_list statement", "statement : include_stmt", "statement : options_stmt L_EOS", +"statement : controls_stmt L_EOS", "statement : logging_stmt L_EOS", "statement : server_stmt L_EOS", "statement : zone_stmt L_EOS", +"statement : trusted_keys_stmt L_EOS", "statement : acl_stmt L_EOS", "statement : key_stmt L_EOS", "statement : L_END_INCLUDE", @@ -551,6 +732,7 @@ char *yyrule[] = { "options : option L_EOS", "options : options option L_EOS", "option :", +"option : T_VERSION L_QSTRING", "option : T_DIRECTORY L_QSTRING", "option : T_NAMED_XFER L_QSTRING", "option : T_PIDFILE L_QSTRING", @@ -563,25 +745,61 @@ char *yyrule[] = { "option : T_NOTIFY yea_or_nay", "option : T_HOSTSTATS yea_or_nay", "option : T_DEALLOC_ON_EXIT yea_or_nay", +"option : T_USE_IXFR yea_or_nay", +"option : T_MAINTAIN_IXFR_BASE yea_or_nay", +"option : T_HAS_OLD_CLIENTS yea_or_nay", "option : T_AUTH_NXDOMAIN yea_or_nay", "option : T_MULTIPLE_CNAMES yea_or_nay", "option : T_CHECK_NAMES check_names_type check_names_opt", +"option : T_USE_ID_POOL yea_or_nay", +"option : T_RFC2308_TYPE1 yea_or_nay", "option : T_LISTEN_ON maybe_port '{' address_match_list '}'", "option : T_FORWARD forward_opt", "$$2 :", "option : T_FORWARDERS $$2 '{' opt_forwarders_list '}'", "option : T_QUERY_SOURCE query_source", +"option : T_TRANSFER_SOURCE maybe_wild_addr", "option : T_ALLOW_QUERY '{' address_match_list '}'", +"option : T_ALLOW_RECURSION '{' address_match_list '}'", "option : T_ALLOW_TRANSFER '{' address_match_list '}'", +"option : T_SORTLIST '{' address_match_list '}'", +"$$3 :", +"option : T_ALSO_NOTIFY $$3 '{' opt_also_notify_list '}'", +"option : T_BLACKHOLE '{' address_match_list '}'", "option : T_TOPOLOGY '{' address_match_list '}'", "option : size_clause", "option : transfer_clause", "option : T_TRANSFER_FORMAT transfer_format", "option : T_MAX_TRANSFER_TIME_IN L_NUMBER", +"option : T_SERIAL_QUERIES L_NUMBER", "option : T_CLEAN_INTERVAL L_NUMBER", "option : T_INTERFACE_INTERVAL L_NUMBER", "option : T_STATS_INTERVAL L_NUMBER", +"option : T_MAX_LOG_SIZE_IXFR L_NUMBER", +"option : T_MAX_NCACHE_TTL L_NUMBER", +"option : T_LAME_TTL L_NUMBER", +"option : T_HEARTBEAT L_NUMBER", +"option : T_DIALUP yea_or_nay", +"option : T_RRSET_ORDER '{' rrset_ordering_list '}'", +"option : T_TREAT_CR_AS_SPACE yea_or_nay", +"option : T_MIN_ROOTS L_NUMBER", "option : error", +"controls_stmt : T_CONTROLS '{' controls '}'", +"controls : control L_EOS", +"controls : controls control L_EOS", +"control :", +"control : T_INET maybe_wild_addr T_PORT in_port T_ALLOW '{' address_match_list '}'", +"control : T_UNIX L_QSTRING T_PERM L_NUMBER T_OWNER L_NUMBER T_GROUP L_NUMBER", +"control : error", +"rrset_ordering_list : rrset_ordering_element L_EOS", +"rrset_ordering_list : rrset_ordering_list rrset_ordering_element L_EOS", +"ordering_class :", +"ordering_class : T_CLASS any_string", +"ordering_type :", +"ordering_type : T_TYPE any_string", +"ordering_name :", +"ordering_name : T_NAME L_QSTRING", +"rrset_ordering_element : ordering_class ordering_type ordering_name T_ORDER L_STRING", "transfer_format : T_ONE_ANSWER", "transfer_format : T_MANY_ANSWERS", "maybe_wild_addr : L_IPADDR", @@ -596,6 +814,8 @@ char *yyrule[] = { "query_source : query_source_port query_source_address", "maybe_port :", "maybe_port : T_PORT in_port", +"maybe_zero_port :", +"maybe_zero_port : T_PORT in_port", "yea_or_nay : T_YES", "yea_or_nay : T_TRUE", "yea_or_nay : T_NO", @@ -627,15 +847,20 @@ char *yyrule[] = { "forwarders_in_addr_list : forwarders_in_addr L_EOS", "forwarders_in_addr_list : forwarders_in_addr_list forwarders_in_addr L_EOS", "forwarders_in_addr : L_IPADDR", -"$$3 :", -"logging_stmt : T_LOGGING $$3 '{' logging_opts_list '}'", +"opt_also_notify_list :", +"opt_also_notify_list : also_notify_in_addr_list", +"also_notify_in_addr_list : also_notify_in_addr L_EOS", +"also_notify_in_addr_list : also_notify_in_addr_list also_notify_in_addr L_EOS", +"also_notify_in_addr : L_IPADDR", +"$$4 :", +"logging_stmt : T_LOGGING $$4 '{' logging_opts_list '}'", "logging_opts_list : logging_opt L_EOS", "logging_opts_list : logging_opts_list logging_opt L_EOS", "logging_opts_list : error", -"$$4 :", -"logging_opt : T_CATEGORY category $$4 '{' channel_list '}'", "$$5 :", -"logging_opt : T_CHANNEL channel_name $$5 '{' channel_opt_list '}'", +"logging_opt : T_CATEGORY category $$5 '{' channel_list '}'", +"$$6 :", +"logging_opt : T_CHANNEL channel_name $$6 '{' channel_opt_list '}'", "channel_severity : any_string", "channel_severity : T_DEBUG", "channel_severity : T_DEBUG L_NUMBER", @@ -674,11 +899,12 @@ char *yyrule[] = { "category_name : T_DEFAULT", "category_name : T_NOTIFY", "category : category_name", -"$$6 :", -"server_stmt : T_SERVER L_IPADDR $$6 '{' server_info_list '}'", +"$$7 :", +"server_stmt : T_SERVER L_IPADDR $$7 '{' server_info_list '}'", "server_info_list : server_info L_EOS", "server_info_list : server_info_list server_info L_EOS", "server_info : T_BOGUS yea_or_nay", +"server_info : T_SUPPORT_IXFR yea_or_nay", "server_info : T_TRANSFERS L_NUMBER", "server_info : T_TRANSFER_FORMAT transfer_format", "server_info : T_KEYS '{' key_list '}'", @@ -687,6 +913,7 @@ char *yyrule[] = { "address_match_list : address_match_list address_match_element L_EOS", "address_match_element : address_match_simple", "address_match_element : '!' address_match_simple", +"address_match_element : T_SEC_KEY L_STRING", "address_match_simple : L_IPADDR", "address_match_simple : L_IPADDR '/' L_NUMBER", "address_match_simple : L_NUMBER '/' L_NUMBER", @@ -698,16 +925,16 @@ char *yyrule[] = { "key_list : key_list_element L_EOS", "key_list : key_list key_list_element L_EOS", "key_list : error", -"$$7 :", -"key_stmt : T_SEC_KEY $$7 any_string '{' key_definition '}'", +"$$8 :", +"key_stmt : T_SEC_KEY $$8 any_string '{' key_definition '}'", "key_definition : algorithm_id secret", "key_definition : secret algorithm_id", "key_definition : error", "algorithm_id : T_ALGID any_string L_EOS", "secret : T_SECRET any_string L_EOS", "acl_stmt : T_ACL any_string '{' address_match_list '}'", -"$$8 :", -"zone_stmt : T_ZONE L_QSTRING optional_class $$8 optional_zone_options_list", +"$$9 :", +"zone_stmt : T_ZONE L_QSTRING optional_class $$9 optional_zone_options_list", "optional_zone_options_list :", "optional_zone_options_list : '{' zone_option_list '}'", "optional_class :", @@ -716,19 +943,30 @@ char *yyrule[] = { "zone_type : T_SLAVE", "zone_type : T_HINT", "zone_type : T_STUB", +"zone_type : T_FORWARD", "zone_option_list : zone_option L_EOS", "zone_option_list : zone_option_list zone_option L_EOS", "zone_option : T_TYPE zone_type", "zone_option : T_FILE L_QSTRING", -"zone_option : T_MASTERS '{' master_in_addr_list '}'", +"zone_option : T_FILE_IXFR L_QSTRING", +"zone_option : T_IXFR_TMP L_QSTRING", +"zone_option : T_MASTERS maybe_zero_port '{' master_in_addr_list '}'", "zone_option : T_TRANSFER_SOURCE maybe_wild_addr", "zone_option : T_CHECK_NAMES check_names_opt", "zone_option : T_ALLOW_UPDATE '{' address_match_list '}'", "zone_option : T_ALLOW_QUERY '{' address_match_list '}'", "zone_option : T_ALLOW_TRANSFER '{' address_match_list '}'", +"zone_option : T_FORWARD zone_forward_opt", +"$$10 :", +"zone_option : T_FORWARDERS $$10 '{' opt_zone_forwarders_list '}'", "zone_option : T_MAX_TRANSFER_TIME_IN L_NUMBER", +"zone_option : T_MAX_LOG_SIZE_IXFR L_NUMBER", "zone_option : T_NOTIFY yea_or_nay", +"zone_option : T_MAINTAIN_IXFR_BASE yea_or_nay", +"zone_option : T_PUBKEY L_NUMBER L_NUMBER L_NUMBER L_QSTRING", +"zone_option : T_PUBKEY L_STRING L_NUMBER L_NUMBER L_QSTRING", "zone_option : T_ALSO_NOTIFY '{' opt_notify_in_addr_list '}'", +"zone_option : T_DIALUP yea_or_nay", "zone_option : error", "master_in_addr_list : master_in_addr L_EOS", "master_in_addr_list : master_in_addr_list master_in_addr L_EOS", @@ -738,6 +976,18 @@ char *yyrule[] = { "notify_in_addr_list : notify_in_addr L_EOS", "notify_in_addr_list : notify_in_addr_list notify_in_addr L_EOS", "notify_in_addr : L_IPADDR", +"zone_forward_opt : T_ONLY", +"zone_forward_opt : T_FIRST", +"opt_zone_forwarders_list :", +"opt_zone_forwarders_list : zone_forwarders_in_addr_list", +"zone_forwarders_in_addr_list : zone_forwarders_in_addr L_EOS", +"zone_forwarders_in_addr_list : zone_forwarders_in_addr_list zone_forwarders_in_addr L_EOS", +"zone_forwarders_in_addr : L_IPADDR", +"trusted_keys_stmt : T_TRUSTED_KEYS '{' trusted_keys_list '}'", +"trusted_keys_list : trusted_key L_EOS", +"trusted_keys_list : trusted_keys_list trusted_key L_EOS", +"trusted_key : L_STRING L_NUMBER L_NUMBER L_NUMBER L_QSTRING", +"trusted_key : L_STRING L_STRING L_NUMBER L_NUMBER L_QSTRING", "in_port : L_NUMBER", "any_string : L_STRING", "any_string : L_QSTRING", @@ -768,7 +1018,7 @@ struct yystack { int yychar; /* some people use this, so we copy it in & out */ int yyerrflag; /* must be global for yyerrok & YYRECOVERING */ YYSTYPE yylval; -#line 1282 "ns_parser.y" +#line 1776 "ns_parser.y" static char * canonical_name(char *name) { @@ -873,6 +1123,7 @@ parser_setup() { authtab = new_symbol_table(AUTH_TABLE_SIZE, free_sym_value); init_acls(); define_builtin_channels(); + INIT_LIST(current_controls); } static void @@ -913,25 +1164,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 @@ -961,7 +1212,7 @@ parser_shutdown(void) { free_symbol_table(authtab); lexer_shutdown(); } -#line 965 "y.tab.c" +#line 1216 "y.tab.c" /* allocate initial stack */ #if defined(__STDC__) || defined(__cplusplus) static int yyinitstack(struct yystack *sp) @@ -1157,25 +1408,27 @@ yyreduce: switch (yyn) { case 1: -#line 206 "ns_parser.y" +#line 241 "ns_parser.y" { - /* nothing */ + if (EMPTY(current_controls)) + ns_ctl_defaults(¤t_controls); + ns_ctl_install(¤t_controls); } break; -case 14: -#line 227 "ns_parser.y" +case 16: +#line 266 "ns_parser.y" { lexer_begin_file(yyvsp[-1].cp, NULL); } break; -case 15: -#line 235 "ns_parser.y" +case 17: +#line 274 "ns_parser.y" { if (seen_options) parser_error(0, "cannot redefine options"); current_options = new_options(); } break; -case 16: -#line 241 "ns_parser.y" +case 18: +#line 280 "ns_parser.y" { if (!seen_options) set_options(current_options, 0); @@ -1185,113 +1438,164 @@ case 16: seen_options = 1; } break; -case 20: -#line 257 "ns_parser.y" +case 22: +#line 296 "ns_parser.y" +{ + if (current_options->version != NULL) + freestr(current_options->version); + current_options->version = yyvsp[0].cp; + } +break; +case 23: +#line 302 "ns_parser.y" { if (current_options->directory != NULL) freestr(current_options->directory); current_options->directory = yyvsp[0].cp; } break; -case 21: -#line 263 "ns_parser.y" +case 24: +#line 308 "ns_parser.y" { if (current_options->named_xfer != NULL) freestr(current_options->named_xfer); current_options->named_xfer = yyvsp[0].cp; } break; -case 22: -#line 269 "ns_parser.y" +case 25: +#line 314 "ns_parser.y" { if (current_options->pid_filename != NULL) freestr(current_options->pid_filename); current_options->pid_filename = yyvsp[0].cp; } break; -case 23: -#line 275 "ns_parser.y" +case 26: +#line 320 "ns_parser.y" { if (current_options->stats_filename != NULL) freestr(current_options->stats_filename); current_options->stats_filename = yyvsp[0].cp; } break; -case 24: -#line 281 "ns_parser.y" +case 27: +#line 326 "ns_parser.y" { if (current_options->memstats_filename != NULL) freestr(current_options->memstats_filename); current_options->memstats_filename = yyvsp[0].cp; } break; -case 25: -#line 287 "ns_parser.y" +case 28: +#line 332 "ns_parser.y" { if (current_options->dump_filename != NULL) freestr(current_options->dump_filename); current_options->dump_filename = yyvsp[0].cp; } break; -case 26: -#line 293 "ns_parser.y" +case 29: +#line 338 "ns_parser.y" { - set_boolean_option(current_options, OPTION_FAKE_IQUERY, yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_FAKE_IQUERY, yyvsp[0].num); } break; -case 27: -#line 297 "ns_parser.y" +case 30: +#line 343 "ns_parser.y" { - set_boolean_option(current_options, OPTION_NORECURSE, !yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_NORECURSE, !yyvsp[0].num); } break; -case 28: -#line 301 "ns_parser.y" +case 31: +#line 348 "ns_parser.y" { - set_boolean_option(current_options, OPTION_NOFETCHGLUE, !yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_NOFETCHGLUE, !yyvsp[0].num); } break; -case 29: -#line 305 "ns_parser.y" +case 32: +#line 353 "ns_parser.y" { - set_boolean_option(current_options, OPTION_NONOTIFY, !yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_NONOTIFY, !yyvsp[0].num); } break; -case 30: -#line 309 "ns_parser.y" +case 33: +#line 358 "ns_parser.y" { - set_boolean_option(current_options, OPTION_HOSTSTATS, yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_HOSTSTATS, yyvsp[0].num); } break; -case 31: -#line 313 "ns_parser.y" +case 34: +#line 363 "ns_parser.y" { - set_boolean_option(current_options, OPTION_DEALLOC_ON_EXIT, - yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_DEALLOC_ON_EXIT, yyvsp[0].num); } break; -case 32: -#line 318 "ns_parser.y" +case 35: +#line 368 "ns_parser.y" +{ + set_global_boolean_option(current_options, OPTION_USE_IXFR, yyvsp[0].num); + } +break; +case 36: +#line 372 "ns_parser.y" { - set_boolean_option(current_options, OPTION_NONAUTH_NXDOMAIN, + set_global_boolean_option(current_options, + OPTION_MAINTAIN_IXFR_BASE, yyvsp[0].num); + } +break; +case 37: +#line 377 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_MAINTAIN_IXFR_BASE, yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_NORFC2308_TYPE1, yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_NONAUTH_NXDOMAIN, !yyvsp[0].num); + } +break; +case 38: +#line 386 "ns_parser.y" +{ + set_global_boolean_option(current_options, OPTION_NONAUTH_NXDOMAIN, !yyvsp[0].num); } break; -case 33: -#line 323 "ns_parser.y" +case 39: +#line 391 "ns_parser.y" { - set_boolean_option(current_options, OPTION_MULTIPLE_CNAMES, - yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_MULTIPLE_CNAMES, yyvsp[0].num); } break; -case 34: -#line 328 "ns_parser.y" +case 40: +#line 396 "ns_parser.y" { - current_options->check_names[yyvsp[-1].s_int] = yyvsp[0].s_int; + current_options->check_names[yyvsp[-1].s_int] = (enum severity)yyvsp[0].s_int; } break; -case 35: -#line 332 "ns_parser.y" +case 41: +#line 400 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_USE_ID_POOL, yyvsp[0].num); + } +break; +case 42: +#line 405 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_NORFC2308_TYPE1, !yyvsp[0].num); + } +break; +case 43: +#line 410 "ns_parser.y" { char port_string[10]; symbol_value value; @@ -1310,8 +1614,8 @@ case 35: } break; -case 37: -#line 351 "ns_parser.y" +case 45: +#line 429 "ns_parser.y" { if (current_options->fwdtab) { free_forwarders(current_options->fwdtab); @@ -1319,332 +1623,598 @@ case 37: } } break; -case 40: -#line 360 "ns_parser.y" +case 48: +#line 438 "ns_parser.y" { - if (current_options->query_acl) - free_ip_match_list(current_options->query_acl); - current_options->query_acl = yyvsp[-1].iml; + current_options->axfr_src = yyvsp[0].ip_addr; } break; -case 41: -#line 366 "ns_parser.y" +case 49: +#line 442 "ns_parser.y" { - if (current_options->transfer_acl) - free_ip_match_list(current_options->transfer_acl); - current_options->transfer_acl = yyvsp[-1].iml; + if (current_options->query_acl) { + parser_warning(0, + "options allow-query acl already set; skipping"); + free_ip_match_list(yyvsp[-1].iml); + } else + current_options->query_acl = yyvsp[-1].iml; } break; -case 42: -#line 372 "ns_parser.y" +case 50: +#line 451 "ns_parser.y" { - if (current_options->topology) - free_ip_match_list(current_options->topology); - current_options->topology = yyvsp[-1].iml; + if (current_options->recursion_acl) { + parser_warning(0, + "options allow-recursion acl already set; skipping"); + free_ip_match_list(yyvsp[-1].iml); + } else + current_options->recursion_acl = yyvsp[-1].iml; } break; -case 43: -#line 378 "ns_parser.y" +case 51: +#line 460 "ns_parser.y" { - /* To get around the $$ = $1 default rule. */ + if (current_options->transfer_acl) { + parser_warning(0, + "options allow-transfer acl already set; skipping"); + free_ip_match_list(yyvsp[-1].iml); + } else + current_options->transfer_acl = yyvsp[-1].iml; } break; -case 45: -#line 383 "ns_parser.y" +case 52: +#line 469 "ns_parser.y" { - current_options->transfer_format = yyvsp[0].axfr_fmt; + if (current_options->sortlist) { + parser_warning(0, + "options sortlist already set; skipping"); + free_ip_match_list(yyvsp[-1].iml); + } else + current_options->sortlist = yyvsp[-1].iml; } break; -case 46: -#line 387 "ns_parser.y" +case 53: +#line 478 "ns_parser.y" { - current_options->max_transfer_time_in = yyvsp[0].num * 60; + if (current_options->also_notify) { + parser_warning(0, + "duplicate also-notify clause: overwriting"); + free_also_notify(current_options); + current_options->also_notify = NULL; + } } break; -case 47: -#line 391 "ns_parser.y" +case 55: +#line 488 "ns_parser.y" { - current_options->clean_interval = yyvsp[0].num * 60; + if (current_options->blackhole_acl) { + parser_warning(0, + "options blackhole already set; skipping"); + free_ip_match_list(yyvsp[-1].iml); + } else + current_options->blackhole_acl = yyvsp[-1].iml; } break; -case 48: -#line 395 "ns_parser.y" +case 56: +#line 497 "ns_parser.y" { - current_options->interface_interval = yyvsp[0].num * 60; + if (current_options->topology) { + parser_warning(0, + "options topology already set; skipping"); + free_ip_match_list(yyvsp[-1].iml); + } else + current_options->topology = yyvsp[-1].iml; } break; -case 49: -#line 399 "ns_parser.y" +case 57: +#line 506 "ns_parser.y" { - current_options->stats_interval = yyvsp[0].num * 60; + /* To get around the $$ = $1 default rule. */ } break; -case 51: -#line 406 "ns_parser.y" +case 59: +#line 511 "ns_parser.y" { - yyval.axfr_fmt = axfr_one_answer; + current_options->transfer_format = yyvsp[0].axfr_fmt; } break; -case 52: -#line 410 "ns_parser.y" +case 60: +#line 515 "ns_parser.y" { - yyval.axfr_fmt = axfr_many_answers; + current_options->max_transfer_time_in = yyvsp[0].num * 60; } break; -case 53: -#line 415 "ns_parser.y" -{ yyval.ip_addr = yyvsp[0].ip_addr; } -break; -case 54: -#line 416 "ns_parser.y" -{ yyval.ip_addr.s_addr = htonl(INADDR_ANY); } -break; -case 55: -#line 419 "ns_parser.y" -{ yyval.us_int = yyvsp[0].us_int; } -break; -case 56: -#line 420 "ns_parser.y" -{ yyval.us_int = htons(0); } -break; -case 57: -#line 424 "ns_parser.y" +case 61: +#line 519 "ns_parser.y" { - current_options->query_source.sin_addr = yyvsp[0].ip_addr; + current_options->serial_queries = yyvsp[0].num; } break; -case 58: -#line 430 "ns_parser.y" +case 62: +#line 523 "ns_parser.y" { - current_options->query_source.sin_port = yyvsp[0].us_int; + current_options->clean_interval = yyvsp[0].num * 60; } break; case 63: -#line 441 "ns_parser.y" -{ yyval.us_int = htons(NS_DEFAULTPORT); } +#line 527 "ns_parser.y" +{ + current_options->interface_interval = yyvsp[0].num * 60; + } break; case 64: -#line 442 "ns_parser.y" -{ yyval.us_int = yyvsp[0].us_int; } +#line 531 "ns_parser.y" +{ + current_options->stats_interval = yyvsp[0].num * 60; + } break; case 65: -#line 446 "ns_parser.y" -{ - yyval.num = 1; +#line 535 "ns_parser.y" +{ + current_options->max_log_size_ixfr = yyvsp[0].num; } break; case 66: -#line 450 "ns_parser.y" -{ - yyval.num = 1; +#line 539 "ns_parser.y" +{ + current_options->max_ncache_ttl = yyvsp[0].num; } break; case 67: -#line 454 "ns_parser.y" -{ - yyval.num = 0; +#line 543 "ns_parser.y" +{ + current_options->lame_ttl = yyvsp[0].num; } break; case 68: -#line 458 "ns_parser.y" -{ - yyval.num = 0; +#line 547 "ns_parser.y" +{ + current_options->heartbeat_interval = yyvsp[0].num * 60; } break; case 69: -#line 462 "ns_parser.y" -{ - if (yyvsp[0].num == 1 || yyvsp[0].num == 0) { - yyval.num = yyvsp[0].num; - } else { - parser_warning(0, - "number should be 0 or 1; assuming 1"); - yyval.num = 1; - } +#line 551 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_NODIALUP, !yyvsp[0].num); } break; case 70: -#line 474 "ns_parser.y" +#line 556 "ns_parser.y" { - yyval.s_int = primary_trans; + if (current_options->ordering) + free_rrset_order_list(current_options->ordering); + current_options->ordering = yyvsp[-1].rol; } break; case 71: -#line 478 "ns_parser.y" +#line 562 "ns_parser.y" { - yyval.s_int = secondary_trans; + set_global_boolean_option(current_options, + OPTION_TREAT_CR_AS_SPACE, yyvsp[0].num); } break; case 72: -#line 482 "ns_parser.y" -{ - yyval.s_int = response_trans; - } -break; -case 73: -#line 488 "ns_parser.y" -{ - yyval.s_int = warn; - } -break; -case 74: -#line 492 "ns_parser.y" -{ - yyval.s_int = fail; - } -break; -case 75: -#line 496 "ns_parser.y" -{ - yyval.s_int = ignore; - } -break; -case 76: -#line 502 "ns_parser.y" -{ - set_boolean_option(current_options, OPTION_FORWARD_ONLY, 1); - } -break; -case 77: -#line 506 "ns_parser.y" +#line 567 "ns_parser.y" { - set_boolean_option(current_options, OPTION_FORWARD_ONLY, 0); + if (yyvsp[0].num >= 1) + current_options->minroots = yyvsp[0].num; } break; case 78: -#line 510 "ns_parser.y" +#line 587 "ns_parser.y" { - parser_warning(0, "forward if-no-answer is unimplemented"); + ns_ctl_add(¤t_controls, ns_ctl_new_inet(yyvsp[-6].ip_addr, yyvsp[-4].us_int, yyvsp[-1].iml)); } break; case 79: -#line 514 "ns_parser.y" +#line 591 "ns_parser.y" { - parser_warning(0, "forward if-no-domain is unimplemented"); - } -break; -case 80: -#line 520 "ns_parser.y" -{ - current_options->data_size = yyvsp[0].ul_int; + ns_ctl_add(¤t_controls, ns_ctl_new_unix(yyvsp[-6].cp, yyvsp[-4].num, yyvsp[-2].num, yyvsp[0].num)); } break; case 81: -#line 524 "ns_parser.y" +#line 598 "ns_parser.y" { - current_options->stack_size = yyvsp[0].ul_int; + rrset_order_list rol; + + rol = new_rrset_order_list(); + if (yyvsp[-1].roe != NULL) { + add_to_rrset_order_list(rol, yyvsp[-1].roe); + } + + yyval.rol = rol; } break; case 82: -#line 528 "ns_parser.y" +#line 609 "ns_parser.y" { - current_options->core_size = yyvsp[0].ul_int; + if (yyvsp[-1].roe != NULL) { + add_to_rrset_order_list(yyvsp[-2].rol, yyvsp[-1].roe); + } + yyval.rol = yyvsp[-2].rol; } break; case 83: -#line 532 "ns_parser.y" +#line 618 "ns_parser.y" { - current_options->files = yyvsp[0].ul_int; + yyval.s_int = C_ANY; } break; case 84: -#line 538 "ns_parser.y" +#line 622 "ns_parser.y" { - u_long result; + symbol_value value; - if (unit_to_ulong(yyvsp[0].cp, &result)) - yyval.ul_int = result; + if (lookup_symbol(constants, yyvsp[0].cp, SYM_CLASS, &value)) + yyval.s_int = value.integer; else { - parser_error(0, "invalid unit string '%s'", yyvsp[0].cp); - /* 0 means "use default" */ - yyval.ul_int = 0; + parser_error(0, "unknown class '%s'; using ANY", yyvsp[0].cp); + yyval.s_int = C_ANY; } freestr(yyvsp[0].cp); } break; case 85: -#line 551 "ns_parser.y" -{ - yyval.ul_int = (u_long)yyvsp[0].num; +#line 636 "ns_parser.y" +{ + yyval.s_int = ns_t_any; } break; case 86: -#line 555 "ns_parser.y" +#line 640 "ns_parser.y" { - yyval.ul_int = 0; + int success; + + if (strcmp(yyvsp[0].cp, "*") == 0) { + yyval.s_int = ns_t_any; + } else { + yyval.s_int = __sym_ston(__p_type_syms, yyvsp[0].cp, &success); + if (success == 0) { + yyval.s_int = ns_t_any; + parser_error(0, + "unknown type '%s'; assuming ANY", + yyvsp[0].cp); + } + } + freestr(yyvsp[0].cp); } break; case 87: -#line 559 "ns_parser.y" +#line 658 "ns_parser.y" { - yyval.ul_int = ULONG_MAX; + yyval.cp = savestr("*", 1); } break; case 88: -#line 565 "ns_parser.y" +#line 662 "ns_parser.y" { - current_options->transfers_in = (u_long) yyvsp[0].num; + if (strcmp(".",yyvsp[0].cp) == 0 || strcmp("*.",yyvsp[0].cp) == 0) { + yyval.cp = savestr("*", 1); + freestr(yyvsp[0].cp); + } else { + yyval.cp = yyvsp[0].cp ; + } + /* XXX Should do any more name validation here? */ } break; case 89: -#line 569 "ns_parser.y" +#line 674 "ns_parser.y" { - current_options->transfers_out = (u_long) yyvsp[0].num; + enum ordering o; + + if (strlen(yyvsp[0].cp) == 0) { + parser_error(0, "null order name"); + yyval.roe = NULL ; + } else { + o = lookup_ordering(yyvsp[0].cp); + if (o == unknown_order) { + o = (enum ordering)DEFAULT_ORDERING; + parser_error(0, + "invalid order name '%s'; using %s", + yyvsp[0].cp, p_order(o)); + } + + freestr(yyvsp[0].cp); + + yyval.roe = new_rrset_order_element(yyvsp[-4].s_int, yyvsp[-3].s_int, yyvsp[-2].cp, o); + } } break; case 90: -#line 573 "ns_parser.y" +#line 697 "ns_parser.y" { - current_options->transfers_per_ns = (u_long) yyvsp[0].num; + yyval.axfr_fmt = axfr_one_answer; } break; -case 93: -#line 583 "ns_parser.y" +case 91: +#line 701 "ns_parser.y" { - /* nothing */ + yyval.axfr_fmt = axfr_many_answers; } break; -case 94: -#line 587 "ns_parser.y" +case 92: +#line 706 "ns_parser.y" +{ yyval.ip_addr = yyvsp[0].ip_addr; } +break; +case 93: +#line 707 "ns_parser.y" +{ yyval.ip_addr.s_addr = htonl(INADDR_ANY); } +break; +case 94: +#line 710 "ns_parser.y" +{ yyval.us_int = yyvsp[0].us_int; } +break; +case 95: +#line 711 "ns_parser.y" +{ yyval.us_int = htons(0); } +break; +case 96: +#line 715 "ns_parser.y" +{ + current_options->query_source.sin_addr = yyvsp[0].ip_addr; + } +break; +case 97: +#line 721 "ns_parser.y" +{ + current_options->query_source.sin_port = yyvsp[0].us_int; + } +break; +case 102: +#line 732 "ns_parser.y" +{ yyval.us_int = htons(NS_DEFAULTPORT); } +break; +case 103: +#line 733 "ns_parser.y" +{ yyval.us_int = yyvsp[0].us_int; } +break; +case 104: +#line 736 "ns_parser.y" +{ yyval.us_int = htons(0); } +break; +case 105: +#line 737 "ns_parser.y" +{ yyval.us_int = yyvsp[0].us_int; } +break; +case 106: +#line 742 "ns_parser.y" +{ + yyval.num = 1; + } +break; +case 107: +#line 746 "ns_parser.y" +{ + yyval.num = 1; + } +break; +case 108: +#line 750 "ns_parser.y" +{ + yyval.num = 0; + } +break; +case 109: +#line 754 "ns_parser.y" +{ + yyval.num = 0; + } +break; +case 110: +#line 758 "ns_parser.y" +{ + if (yyvsp[0].num == 1 || yyvsp[0].num == 0) { + yyval.num = yyvsp[0].num; + } else { + parser_warning(0, + "number should be 0 or 1; assuming 1"); + yyval.num = 1; + } + } +break; +case 111: +#line 770 "ns_parser.y" +{ + yyval.s_int = primary_trans; + } +break; +case 112: +#line 774 "ns_parser.y" +{ + yyval.s_int = secondary_trans; + } +break; +case 113: +#line 778 "ns_parser.y" +{ + yyval.s_int = response_trans; + } +break; +case 114: +#line 784 "ns_parser.y" +{ + yyval.s_int = warn; + } +break; +case 115: +#line 788 "ns_parser.y" +{ + yyval.s_int = fail; + } +break; +case 116: +#line 792 "ns_parser.y" +{ + yyval.s_int = ignore; + } +break; +case 117: +#line 798 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_FORWARD_ONLY, 1); + } +break; +case 118: +#line 803 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_FORWARD_ONLY, 0); + } +break; +case 119: +#line 808 "ns_parser.y" +{ + parser_warning(0, "forward if-no-answer is unimplemented"); + } +break; +case 120: +#line 812 "ns_parser.y" +{ + parser_warning(0, "forward if-no-domain is unimplemented"); + } +break; +case 121: +#line 818 "ns_parser.y" +{ + current_options->data_size = yyvsp[0].ul_int; + } +break; +case 122: +#line 822 "ns_parser.y" +{ + current_options->stack_size = yyvsp[0].ul_int; + } +break; +case 123: +#line 826 "ns_parser.y" +{ + current_options->core_size = yyvsp[0].ul_int; + } +break; +case 124: +#line 830 "ns_parser.y" +{ + current_options->files = yyvsp[0].ul_int; + } +break; +case 125: +#line 836 "ns_parser.y" +{ + u_long result; + + if (unit_to_ulong(yyvsp[0].cp, &result)) + yyval.ul_int = result; + else { + parser_error(0, "invalid unit string '%s'", yyvsp[0].cp); + /* 0 means "use default" */ + yyval.ul_int = 0; + } + freestr(yyvsp[0].cp); + } +break; +case 126: +#line 849 "ns_parser.y" +{ + yyval.ul_int = (u_long)yyvsp[0].num; + } +break; +case 127: +#line 853 "ns_parser.y" +{ + yyval.ul_int = 0; + } +break; +case 128: +#line 857 "ns_parser.y" +{ + yyval.ul_int = ULONG_MAX; + } +break; +case 129: +#line 863 "ns_parser.y" +{ + current_options->transfers_in = (u_long) yyvsp[0].num; + } +break; +case 130: +#line 867 "ns_parser.y" +{ + current_options->transfers_out = (u_long) yyvsp[0].num; + } +break; +case 131: +#line 871 "ns_parser.y" +{ + current_options->transfers_per_ns = (u_long) yyvsp[0].num; + } +break; +case 134: +#line 881 "ns_parser.y" { /* nothing */ } break; -case 95: -#line 593 "ns_parser.y" +case 135: +#line 885 "ns_parser.y" { - add_forwarder(current_options, yyvsp[0].ip_addr); + /* nothing */ } break; -case 96: -#line 603 "ns_parser.y" +case 136: +#line 891 "ns_parser.y" +{ + add_global_forwarder(current_options, yyvsp[0].ip_addr); + } +break; +case 139: +#line 901 "ns_parser.y" +{ + /* nothing */ + } +break; +case 140: +#line 905 "ns_parser.y" +{ + /* nothing */ + } +break; +case 141: +#line 911 "ns_parser.y" +{ + add_global_also_notify(current_options, yyvsp[0].ip_addr); + } +break; +case 142: +#line 921 "ns_parser.y" { current_logging = begin_logging(); } break; -case 97: -#line 607 "ns_parser.y" +case 143: +#line 925 "ns_parser.y" { end_logging(current_logging, 1); current_logging = NULL; } break; -case 101: -#line 619 "ns_parser.y" +case 147: +#line 937 "ns_parser.y" { current_category = yyvsp[0].s_int; } break; -case 103: -#line 624 "ns_parser.y" +case 149: +#line 942 "ns_parser.y" { chan_type = log_null; chan_flags = 0; chan_level = log_info; } break; -case 104: -#line 630 "ns_parser.y" +case 150: +#line 948 "ns_parser.y" { log_channel current_channel = NULL; @@ -1684,8 +2254,8 @@ case 104: } } break; -case 105: -#line 671 "ns_parser.y" +case 151: +#line 989 "ns_parser.y" { symbol_value value; @@ -1698,86 +2268,84 @@ case 105: freestr(yyvsp[0].cp); } break; -case 106: -#line 683 "ns_parser.y" +case 152: +#line 1001 "ns_parser.y" { chan_level = log_debug(1); } break; -case 107: -#line 687 "ns_parser.y" +case 153: +#line 1005 "ns_parser.y" { chan_level = yyvsp[0].num; } break; -case 108: -#line 691 "ns_parser.y" +case 154: +#line 1009 "ns_parser.y" { chan_level = 0; chan_flags |= LOG_USE_CONTEXT_LEVEL|LOG_REQUIRE_DEBUG; } break; -case 109: -#line 698 "ns_parser.y" +case 155: +#line 1016 "ns_parser.y" { chan_versions = yyvsp[0].num; - chan_flags |= LOG_TRUNCATE; } break; -case 110: -#line 703 "ns_parser.y" +case 156: +#line 1020 "ns_parser.y" { chan_versions = LOG_MAX_VERSIONS; - chan_flags |= LOG_TRUNCATE; } break; -case 111: -#line 710 "ns_parser.y" +case 157: +#line 1026 "ns_parser.y" { chan_max_size = yyvsp[0].ul_int; } break; -case 112: -#line 716 "ns_parser.y" +case 158: +#line 1032 "ns_parser.y" { chan_versions = 0; chan_max_size = ULONG_MAX; } break; -case 113: -#line 721 "ns_parser.y" +case 159: +#line 1037 "ns_parser.y" { chan_max_size = ULONG_MAX; } break; -case 114: -#line 725 "ns_parser.y" +case 160: +#line 1041 "ns_parser.y" { chan_versions = 0; } break; -case 117: -#line 733 "ns_parser.y" +case 163: +#line 1049 "ns_parser.y" { chan_flags |= LOG_CLOSE_STREAM; chan_type = log_file; chan_name = yyvsp[-1].cp; } break; -case 118: -#line 741 "ns_parser.y" +case 164: +#line 1057 "ns_parser.y" { yyval.cp = yyvsp[0].cp; } break; -case 119: -#line 742 "ns_parser.y" +case 165: +#line 1058 "ns_parser.y" { yyval.cp = savestr("syslog", 1); } break; -case 120: -#line 745 "ns_parser.y" +case 166: +#line 1061 "ns_parser.y" { yyval.s_int = LOG_DAEMON; } break; -case 121: -#line 747 "ns_parser.y" +case 167: +#line 1063 "ns_parser.y" { symbol_value value; @@ -1790,33 +2358,33 @@ case 121: freestr(yyvsp[0].cp); } break; -case 122: -#line 761 "ns_parser.y" +case 168: +#line 1077 "ns_parser.y" { chan_type = log_syslog; chan_facility = yyvsp[0].s_int; } break; -case 123: -#line 767 "ns_parser.y" +case 169: +#line 1083 "ns_parser.y" { /* nothing to do */ } break; -case 124: -#line 768 "ns_parser.y" +case 170: +#line 1084 "ns_parser.y" { /* nothing to do */ } break; -case 125: -#line 770 "ns_parser.y" +case 171: +#line 1086 "ns_parser.y" { chan_type = log_null; } break; -case 126: -#line 773 "ns_parser.y" +case 172: +#line 1089 "ns_parser.y" { /* nothing to do */ } break; -case 127: -#line 775 "ns_parser.y" +case 173: +#line 1091 "ns_parser.y" { if (yyvsp[0].num) chan_flags |= LOG_TIMESTAMP; @@ -1824,8 +2392,8 @@ case 127: chan_flags &= ~LOG_TIMESTAMP; } break; -case 128: -#line 782 "ns_parser.y" +case 174: +#line 1098 "ns_parser.y" { if (yyvsp[0].num) chan_flags |= LOG_PRINT_CATEGORY; @@ -1833,8 +2401,8 @@ case 128: chan_flags &= ~LOG_PRINT_CATEGORY; } break; -case 129: -#line 789 "ns_parser.y" +case 175: +#line 1105 "ns_parser.y" { if (yyvsp[0].num) chan_flags |= LOG_PRINT_LEVEL; @@ -1842,12 +2410,12 @@ case 129: chan_flags &= ~LOG_PRINT_LEVEL; } break; -case 134: -#line 803 "ns_parser.y" +case 180: +#line 1119 "ns_parser.y" { yyval.cp = savestr("null", 1); } break; -case 135: -#line 807 "ns_parser.y" +case 181: +#line 1123 "ns_parser.y" { log_channel channel; symbol_value value; @@ -1863,16 +2431,16 @@ case 135: freestr(yyvsp[0].cp); } break; -case 140: -#line 829 "ns_parser.y" +case 186: +#line 1145 "ns_parser.y" { yyval.cp = savestr("default", 1); } break; -case 141: -#line 830 "ns_parser.y" +case 187: +#line 1146 "ns_parser.y" { yyval.cp = savestr("notify", 1); } break; -case 142: -#line 834 "ns_parser.y" +case 188: +#line 1150 "ns_parser.y" { symbol_value value; @@ -1886,10 +2454,10 @@ case 142: freestr(yyvsp[0].cp); } break; -case 143: -#line 853 "ns_parser.y" +case 189: +#line 1169 "ns_parser.y" { - char *ip_printable; + const char *ip_printable; symbol_value value; ip_printable = inet_ntoa(yyvsp[0].ip_addr); @@ -1908,32 +2476,38 @@ case 143: current_server = begin_server(yyvsp[0].ip_addr); } break; -case 144: -#line 873 "ns_parser.y" +case 190: +#line 1189 "ns_parser.y" { end_server(current_server, !seen_server); } break; -case 147: -#line 883 "ns_parser.y" +case 193: +#line 1199 "ns_parser.y" { set_server_option(current_server, SERVER_INFO_BOGUS, yyvsp[0].num); } break; -case 148: -#line 887 "ns_parser.y" +case 194: +#line 1203 "ns_parser.y" +{ + set_server_option(current_server, SERVER_INFO_SUPPORT_IXFR, yyvsp[0].num); + } +break; +case 195: +#line 1207 "ns_parser.y" { set_server_transfers(current_server, (int)yyvsp[0].num); } break; -case 149: -#line 891 "ns_parser.y" +case 196: +#line 1211 "ns_parser.y" { set_server_transfer_format(current_server, yyvsp[0].axfr_fmt); } break; -case 152: -#line 903 "ns_parser.y" +case 199: +#line 1223 "ns_parser.y" { ip_match_list iml; @@ -1943,30 +2517,51 @@ case 152: yyval.iml = iml; } break; -case 153: -#line 912 "ns_parser.y" +case 200: +#line 1232 "ns_parser.y" { if (yyvsp[-1].ime != NULL) add_to_ip_match_list(yyvsp[-2].iml, yyvsp[-1].ime); yyval.iml = yyvsp[-2].iml; } break; -case 155: -#line 921 "ns_parser.y" +case 202: +#line 1241 "ns_parser.y" { if (yyvsp[0].ime != NULL) ip_match_negate(yyvsp[0].ime); yyval.ime = yyvsp[0].ime; } break; -case 156: -#line 929 "ns_parser.y" +case 203: +#line 1247 "ns_parser.y" +{ + char *key_name; + struct dst_key *dst_key; + + key_name = canonical_name(yyvsp[0].cp); + if (key_name == NULL) { + parser_error(0, "can't make key name '%s' canonical", + yyvsp[0].cp); + 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); + yyval.ime = NULL; + } + else + yyval.ime = new_ip_match_key(dst_key); + } +break; +case 204: +#line 1268 "ns_parser.y" { yyval.ime = new_ip_match_pattern(yyvsp[0].ip_addr, 32); } break; -case 157: -#line 933 "ns_parser.y" +case 205: +#line 1272 "ns_parser.y" { if (yyvsp[0].num < 0 || yyvsp[0].num > 32) { parser_error(0, "mask bits out of range; skipping"); @@ -1979,8 +2574,8 @@ case 157: } } break; -case 158: -#line 945 "ns_parser.y" +case 206: +#line 1284 "ns_parser.y" { struct in_addr ia; @@ -2002,8 +2597,8 @@ case 158: } } break; -case 160: -#line 967 "ns_parser.y" +case 208: +#line 1306 "ns_parser.y" { char name[256]; @@ -2016,8 +2611,8 @@ case 160: yyval.ime = new_ip_match_indirect(yyvsp[-1].iml); } break; -case 161: -#line 981 "ns_parser.y" +case 209: +#line 1320 "ns_parser.y" { ip_match_list iml; @@ -2030,22 +2625,31 @@ case 161: freestr(yyvsp[0].cp); } break; -case 162: -#line 999 "ns_parser.y" +case 210: +#line 1338 "ns_parser.y" { - key_info ki; + struct dst_key *dst_key; + char *key_name; - ki = lookup_key(yyvsp[0].cp); - if (ki == NULL) { - parser_error(0, "unknown key '%s'", yyvsp[0].cp); + key_name = canonical_name(yyvsp[0].cp); + if (key_name == NULL) { + parser_error(0, "can't make key name '%s' canonical", + yyvsp[0].cp); yyval.keyi = NULL; - } else - yyval.keyi = ki; + } else { + dst_key = lookup_key(key_name); + if (dst_key == NULL) { + parser_error(0, "unknown key '%s'", key_name); + yyval.keyi = NULL; + } else + yyval.keyi = dst_key; + freestr(key_name); + } freestr(yyvsp[0].cp); } break; -case 163: -#line 1013 "ns_parser.y" +case 211: +#line 1361 "ns_parser.y" { if (yyvsp[0].keyi == NULL) parser_error(0, "empty key not added to server list "); @@ -2053,64 +2657,80 @@ case 163: add_server_key_info(current_server, yyvsp[0].keyi); } break; -case 167: -#line 1027 "ns_parser.y" +case 215: +#line 1375 "ns_parser.y" { current_algorithm = NULL; current_secret = NULL; } break; -case 168: -#line 1032 "ns_parser.y" +case 216: +#line 1380 "ns_parser.y" { - key_info ki; + struct dst_key *dst_key; + char *key_name; - if (lookup_key(yyvsp[-3].cp) != NULL) { - parser_error(0, "can't redefine key '%s'", yyvsp[-3].cp); - freestr(yyvsp[-3].cp); + key_name = canonical_name(yyvsp[-3].cp); + if (key_name == NULL) { + parser_error(0, "can't make key name '%s' canonical", + yyvsp[-3].cp); + } 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'", yyvsp[-3].cp); - else { - ki = new_key_info(yyvsp[-3].cp, current_algorithm, - current_secret); - define_key(yyvsp[-3].cp, 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(yyvsp[-3].cp); } break; -case 169: -#line 1052 "ns_parser.y" +case 217: +#line 1416 "ns_parser.y" { current_algorithm = yyvsp[-1].cp; current_secret = yyvsp[0].cp; } break; -case 170: -#line 1057 "ns_parser.y" +case 218: +#line 1421 "ns_parser.y" { current_algorithm = yyvsp[0].cp; current_secret = yyvsp[-1].cp; } break; -case 171: -#line 1062 "ns_parser.y" +case 219: +#line 1426 "ns_parser.y" { current_algorithm = NULL; current_secret = NULL; } break; -case 172: -#line 1068 "ns_parser.y" +case 220: +#line 1432 "ns_parser.y" { yyval.cp = yyvsp[-1].cp; } break; -case 173: -#line 1071 "ns_parser.y" +case 221: +#line 1435 "ns_parser.y" { yyval.cp = yyvsp[-1].cp; } break; -case 174: -#line 1079 "ns_parser.y" +case 222: +#line 1443 "ns_parser.y" { if (lookup_acl(yyvsp[-3].cp) != NULL) { parser_error(0, "can't redefine ACL '%s'", yyvsp[-3].cp); @@ -2119,8 +2739,8 @@ case 174: define_acl(yyvsp[-3].cp, yyvsp[-1].iml); } break; -case 175: -#line 1093 "ns_parser.y" +case 223: +#line 1457 "ns_parser.y" { int sym_type; symbol_value value; @@ -2135,35 +2755,40 @@ case 175: if (zone_name == NULL) { parser_error(0, "can't make zone name '%s' canonical", yyvsp[-1].cp); - 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, yyvsp[0].num); - } else - define_symbol(symtab, zone_name, sym_type, - value, 0); + "cannot redefine zone '%s' class %s", + *zone_name ? zone_name : ".", + p_class(yyvsp[0].num)); + } else { + should_install = 1; + define_symbol(symtab, savestr(zone_name, 1), + sym_type, value, + SYMBOL_FREE_KEY); + } } freestr(yyvsp[-1].cp); current_zone = begin_zone(zone_name, yyvsp[0].num); } break; -case 176: -#line 1124 "ns_parser.y" -{ end_zone(current_zone, !seen_zone); } +case 224: +#line 1491 "ns_parser.y" +{ + end_zone(current_zone, should_install); + } break; -case 179: -#line 1132 "ns_parser.y" +case 227: +#line 1501 "ns_parser.y" { yyval.num = C_IN; } break; -case 180: -#line 1136 "ns_parser.y" +case 228: +#line 1505 "ns_parser.y" { symbol_value value; @@ -2176,135 +2801,284 @@ case 180: freestr(yyvsp[0].cp); } break; -case 181: -#line 1150 "ns_parser.y" +case 229: +#line 1519 "ns_parser.y" { yyval.s_int = Z_MASTER; } break; -case 182: -#line 1154 "ns_parser.y" +case 230: +#line 1523 "ns_parser.y" { yyval.s_int = Z_SLAVE; } break; -case 183: -#line 1158 "ns_parser.y" +case 231: +#line 1527 "ns_parser.y" { yyval.s_int = Z_HINT; } break; -case 184: -#line 1162 "ns_parser.y" +case 232: +#line 1531 "ns_parser.y" { yyval.s_int = Z_STUB; } break; -case 187: -#line 1172 "ns_parser.y" +case 233: +#line 1535 "ns_parser.y" +{ + yyval.s_int = Z_FORWARD; + } +break; +case 236: +#line 1545 "ns_parser.y" { if (!set_zone_type(current_zone, yyvsp[0].s_int)) parser_warning(0, "zone type already set; skipping"); } break; -case 188: -#line 1177 "ns_parser.y" +case 237: +#line 1550 "ns_parser.y" { if (!set_zone_filename(current_zone, yyvsp[0].cp)) parser_warning(0, "zone filename already set; skipping"); } break; -case 190: -#line 1184 "ns_parser.y" +case 238: +#line 1556 "ns_parser.y" +{ + if (!set_zone_ixfr_file(current_zone, yyvsp[0].cp)) + parser_warning(0, + "zone ixfr data base already set; skipping"); + } +break; +case 239: +#line 1562 "ns_parser.y" +{ + if (!set_zone_ixfr_tmp(current_zone, yyvsp[0].cp)) + parser_warning(0, + "zone ixfr temp filename already set; skipping"); + } +break; +case 240: +#line 1568 "ns_parser.y" +{ + set_zone_master_port(current_zone, yyvsp[-3].us_int); + } +break; +case 241: +#line 1572 "ns_parser.y" { set_zone_transfer_source(current_zone, yyvsp[0].ip_addr); } break; -case 191: -#line 1188 "ns_parser.y" +case 242: +#line 1576 "ns_parser.y" { - if (!set_zone_checknames(current_zone, yyvsp[0].s_int)) + if (!set_zone_checknames(current_zone, (enum severity)yyvsp[0].s_int)) parser_warning(0, "zone checknames already set; skipping"); } break; -case 192: -#line 1194 "ns_parser.y" +case 243: +#line 1582 "ns_parser.y" { if (!set_zone_update_acl(current_zone, yyvsp[-1].iml)) parser_warning(0, "zone update acl already set; skipping"); } break; -case 193: -#line 1200 "ns_parser.y" +case 244: +#line 1588 "ns_parser.y" { if (!set_zone_query_acl(current_zone, yyvsp[-1].iml)) parser_warning(0, "zone query acl already set; skipping"); } break; -case 194: -#line 1206 "ns_parser.y" +case 245: +#line 1594 "ns_parser.y" { if (!set_zone_transfer_acl(current_zone, yyvsp[-1].iml)) parser_warning(0, "zone transfer acl already set; skipping"); } break; -case 195: -#line 1212 "ns_parser.y" +case 247: +#line 1601 "ns_parser.y" +{ + struct zoneinfo *zp = current_zone.opaque; + if (zp->z_fwdtab) { + free_forwarders(zp->z_fwdtab); + zp->z_fwdtab = NULL; + } + + } +break; +case 249: +#line 1611 "ns_parser.y" { if (!set_zone_transfer_time_in(current_zone, yyvsp[0].num*60)) parser_warning(0, "zone max transfer time (in) already set; skipping"); } break; -case 196: -#line 1218 "ns_parser.y" +case 250: +#line 1617 "ns_parser.y" +{ + set_zone_max_log_size_ixfr(current_zone, yyvsp[0].num); + } +break; +case 251: +#line 1621 "ns_parser.y" { set_zone_notify(current_zone, yyvsp[0].num); } break; -case 199: -#line 1226 "ns_parser.y" +case 252: +#line 1625 "ns_parser.y" +{ + set_zone_maintain_ixfr_base(current_zone, yyvsp[0].num); + } +break; +case 253: +#line 1629 "ns_parser.y" +{ + /* flags proto alg key */ + set_zone_pubkey(current_zone, yyvsp[-3].num, yyvsp[-2].num, yyvsp[-1].num, yyvsp[0].cp); + } +break; +case 254: +#line 1634 "ns_parser.y" +{ + /* flags proto alg key */ + char *endp; + int flags = (int) strtol(yyvsp[-3].cp, &endp, 0); + if (*endp != '\0') + ns_panic(ns_log_parser, 1, + "Invalid flags string: %s", yyvsp[-3].cp); + set_zone_pubkey(current_zone, flags, yyvsp[-2].num, yyvsp[-1].num, yyvsp[0].cp); + + } +break; +case 256: +#line 1646 "ns_parser.y" +{ + set_zone_dialup(current_zone, yyvsp[0].num); + } +break; +case 258: +#line 1653 "ns_parser.y" { /* nothing */ } break; -case 200: -#line 1230 "ns_parser.y" +case 259: +#line 1657 "ns_parser.y" { /* nothing */ } break; -case 201: -#line 1236 "ns_parser.y" +case 260: +#line 1663 "ns_parser.y" { add_zone_master(current_zone, yyvsp[0].ip_addr); } break; -case 204: -#line 1246 "ns_parser.y" +case 263: +#line 1673 "ns_parser.y" { /* nothing */ } break; -case 205: -#line 1250 "ns_parser.y" +case 264: +#line 1677 "ns_parser.y" { /* nothing */ } break; -case 206: -#line 1256 "ns_parser.y" +case 265: +#line 1683 "ns_parser.y" { add_zone_notify(current_zone, yyvsp[0].ip_addr); } break; -case 207: -#line 1266 "ns_parser.y" +case 266: +#line 1689 "ns_parser.y" +{ + set_zone_boolean_option(current_zone, OPTION_FORWARD_ONLY, 1); + } +break; +case 267: +#line 1693 "ns_parser.y" +{ + set_zone_boolean_option(current_zone, OPTION_FORWARD_ONLY, 0); + } +break; +case 268: +#line 1699 "ns_parser.y" +{ + set_zone_forward(current_zone); + } +break; +case 270: +#line 1706 "ns_parser.y" +{ + /* nothing */ + } +break; +case 271: +#line 1710 "ns_parser.y" +{ + /* nothing */ + } +break; +case 272: +#line 1716 "ns_parser.y" +{ + add_zone_forwarder(current_zone, yyvsp[0].ip_addr); + } +break; +case 273: +#line 1726 "ns_parser.y" +{ + } +break; +case 274: +#line 1730 "ns_parser.y" +{ + /* nothing */ + } +break; +case 275: +#line 1734 "ns_parser.y" +{ + /* nothing */ + } +break; +case 276: +#line 1739 "ns_parser.y" +{ + /* name flags proto alg key */ + set_trusted_key(yyvsp[-4].cp, yyvsp[-3].num, yyvsp[-2].num, yyvsp[-1].num, yyvsp[0].cp); + } +break; +case 277: +#line 1744 "ns_parser.y" +{ + /* name flags proto alg key */ + char *endp; + int flags = (int) strtol(yyvsp[-3].cp, &endp, 0); + if (*endp != '\0') + ns_panic(ns_log_parser, 1, + "Invalid flags string: %s", yyvsp[-3].cp); + set_trusted_key(yyvsp[-4].cp, flags, yyvsp[-2].num, yyvsp[-1].num, yyvsp[0].cp); + } +break; +case 278: +#line 1760 "ns_parser.y" { if (yyvsp[0].num < 0 || yyvsp[0].num > 65535) { parser_warning(0, @@ -2315,7 +3089,7 @@ case 207: yyval.us_int = htons(yyvsp[0].num); } break; -#line 2319 "y.tab.c" +#line 3093 "y.tab.c" } yystk.ssp -= yym; yystate = *yystk.ssp; diff --git a/contrib/bind/bin/named/ns_parser.h b/contrib/bind/bin/named/ns_parser.h index 1d23613..571fb47 100644 --- a/contrib/bind/bin/named/ns_parser.h +++ b/contrib/bind/bin/named/ns_parser.h @@ -20,81 +20,114 @@ #define T_LISTEN_ON 275 #define T_PORT 276 #define T_ADDRESS 277 -#define T_DATASIZE 278 -#define T_STACKSIZE 279 -#define T_CORESIZE 280 -#define T_DEFAULT 281 -#define T_UNLIMITED 282 -#define T_FILES 283 -#define T_HOSTSTATS 284 -#define T_DEALLOC_ON_EXIT 285 -#define T_TRANSFERS_IN 286 -#define T_TRANSFERS_OUT 287 -#define T_TRANSFERS_PER_NS 288 -#define T_TRANSFER_FORMAT 289 -#define T_MAX_TRANSFER_TIME_IN 290 -#define T_ONE_ANSWER 291 -#define T_MANY_ANSWERS 292 -#define T_NOTIFY 293 -#define T_AUTH_NXDOMAIN 294 -#define T_MULTIPLE_CNAMES 295 -#define T_CLEAN_INTERVAL 296 -#define T_INTERFACE_INTERVAL 297 -#define T_STATS_INTERVAL 298 -#define T_LOGGING 299 -#define T_CATEGORY 300 -#define T_CHANNEL 301 -#define T_SEVERITY 302 -#define T_DYNAMIC 303 -#define T_FILE 304 -#define T_VERSIONS 305 -#define T_SIZE 306 -#define T_SYSLOG 307 -#define T_DEBUG 308 -#define T_NULL_OUTPUT 309 -#define T_PRINT_TIME 310 -#define T_PRINT_CATEGORY 311 -#define T_PRINT_SEVERITY 312 -#define T_TOPOLOGY 313 -#define T_SERVER 314 -#define T_LONG_AXFR 315 -#define T_BOGUS 316 -#define T_TRANSFERS 317 -#define T_KEYS 318 -#define T_ZONE 319 -#define T_IN 320 -#define T_CHAOS 321 -#define T_HESIOD 322 -#define T_TYPE 323 -#define T_MASTER 324 -#define T_SLAVE 325 -#define T_STUB 326 -#define T_RESPONSE 327 -#define T_HINT 328 -#define T_MASTERS 329 -#define T_TRANSFER_SOURCE 330 -#define T_ALSO_NOTIFY 331 -#define T_ACL 332 -#define T_ALLOW_UPDATE 333 -#define T_ALLOW_QUERY 334 -#define T_ALLOW_TRANSFER 335 -#define T_SEC_KEY 336 -#define T_ALGID 337 -#define T_SECRET 338 -#define T_CHECK_NAMES 339 -#define T_WARN 340 -#define T_FAIL 341 -#define T_IGNORE 342 -#define T_FORWARD 343 -#define T_FORWARDERS 344 -#define T_ONLY 345 -#define T_FIRST 346 -#define T_IF_NO_ANSWER 347 -#define T_IF_NO_DOMAIN 348 -#define T_YES 349 -#define T_TRUE 350 -#define T_NO 351 -#define T_FALSE 352 +#define T_RRSET_ORDER 278 +#define T_ORDER 279 +#define T_NAME 280 +#define T_CLASS 281 +#define T_CONTROLS 282 +#define T_INET 283 +#define T_UNIX 284 +#define T_PERM 285 +#define T_OWNER 286 +#define T_GROUP 287 +#define T_ALLOW 288 +#define T_DATASIZE 289 +#define T_STACKSIZE 290 +#define T_CORESIZE 291 +#define T_DEFAULT 292 +#define T_UNLIMITED 293 +#define T_FILES 294 +#define T_VERSION 295 +#define T_HOSTSTATS 296 +#define T_DEALLOC_ON_EXIT 297 +#define T_TRANSFERS_IN 298 +#define T_TRANSFERS_OUT 299 +#define T_TRANSFERS_PER_NS 300 +#define T_TRANSFER_FORMAT 301 +#define T_MAX_TRANSFER_TIME_IN 302 +#define T_SERIAL_QUERIES 303 +#define T_ONE_ANSWER 304 +#define T_MANY_ANSWERS 305 +#define T_NOTIFY 306 +#define T_AUTH_NXDOMAIN 307 +#define T_MULTIPLE_CNAMES 308 +#define T_USE_IXFR 309 +#define T_MAINTAIN_IXFR_BASE 310 +#define T_CLEAN_INTERVAL 311 +#define T_INTERFACE_INTERVAL 312 +#define T_STATS_INTERVAL 313 +#define T_MAX_LOG_SIZE_IXFR 314 +#define T_HEARTBEAT 315 +#define T_USE_ID_POOL 316 +#define T_MAX_NCACHE_TTL 317 +#define T_HAS_OLD_CLIENTS 318 +#define T_RFC2308_TYPE1 319 +#define T_LAME_TTL 320 +#define T_MIN_ROOTS 321 +#define T_TREAT_CR_AS_SPACE 322 +#define T_LOGGING 323 +#define T_CATEGORY 324 +#define T_CHANNEL 325 +#define T_SEVERITY 326 +#define T_DYNAMIC 327 +#define T_FILE 328 +#define T_VERSIONS 329 +#define T_SIZE 330 +#define T_SYSLOG 331 +#define T_DEBUG 332 +#define T_NULL_OUTPUT 333 +#define T_PRINT_TIME 334 +#define T_PRINT_CATEGORY 335 +#define T_PRINT_SEVERITY 336 +#define T_SORTLIST 337 +#define T_TOPOLOGY 338 +#define T_SERVER 339 +#define T_LONG_AXFR 340 +#define T_BOGUS 341 +#define T_TRANSFERS 342 +#define T_KEYS 343 +#define T_SUPPORT_IXFR 344 +#define T_ZONE 345 +#define T_IN 346 +#define T_CHAOS 347 +#define T_HESIOD 348 +#define T_TYPE 349 +#define T_MASTER 350 +#define T_SLAVE 351 +#define T_STUB 352 +#define T_RESPONSE 353 +#define T_HINT 354 +#define T_MASTERS 355 +#define T_TRANSFER_SOURCE 356 +#define T_PUBKEY 357 +#define T_ALSO_NOTIFY 358 +#define T_DIALUP 359 +#define T_FILE_IXFR 360 +#define T_IXFR_TMP 361 +#define T_TRUSTED_KEYS 362 +#define T_ACL 363 +#define T_ALLOW_UPDATE 364 +#define T_ALLOW_QUERY 365 +#define T_ALLOW_TRANSFER 366 +#define T_ALLOW_RECURSION 367 +#define T_BLACKHOLE 368 +#define T_SEC_KEY 369 +#define T_ALGID 370 +#define T_SECRET 371 +#define T_CHECK_NAMES 372 +#define T_WARN 373 +#define T_FAIL 374 +#define T_IGNORE 375 +#define T_FORWARD 376 +#define T_FORWARDERS 377 +#define T_ONLY 378 +#define T_FIRST 379 +#define T_IF_NO_ANSWER 380 +#define T_IF_NO_DOMAIN 381 +#define T_YES 382 +#define T_TRUE 383 +#define T_NO 384 +#define T_FALSE 385 typedef union { char * cp; int s_int; @@ -104,7 +137,9 @@ typedef union { 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; } YYSTYPE; extern YYSTYPE yylval; 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 +#include +#include #include #include @@ -32,6 +34,7 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include #include +#include #include #include #include @@ -41,6 +44,8 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include #include +#include + #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 in_port %type maybe_port +%type maybe_zero_port %type maybe_wild_port %type 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 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 category_name channel_name facility_name %type maybe_syslog_facility +/* Items used for the "sortlist" statement: */ +%token T_SORTLIST + /* Items used for the "topology" statement: */ %token T_TOPOLOGY +%type ordering_class +%type ordering_type +%type ordering_name +%type rrset_ordering_list +%type rrset_ordering_element + /* ip_match_list */ %type address_match_simple address_match_element address_name %type 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(¤t_controls); + ns_ctl_install(¤t_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(¤t_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(¤t_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 +#include +#include #include #include @@ -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 #include #include +#include #include #include @@ -123,6 +124,8 @@ static char rcsid[] = "$Id: ns_req.c,v 8.46 1998/03/27 00:21:03 halley Exp $"; #include #include +#include + #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 #include #include +#include #include #include @@ -122,6 +123,8 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.56 1998/03/16 19:40:07 halley Exp $"; #include #include +#include + #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); + + if (qp->q_tsig != NULL) + memput(msg, oldlen + TSIG_BUF_SIZE); + 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]; +static int +root_server_p(ns_class class) { + struct zoneinfo *zp = find_zone("", class); - 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 (zp != NULL && + (zp->z_type == z_master || zp->z_type == z_slave)); } -#endif void -prime_cache() { - struct qinfo *qp; +prime_cache(void) { + int root = root_server_p(ns_c_in); - /* - * 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) { + 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); + + if (qp != NULL) { + qp->q_flags |= (Q_SYSTEM | Q_PRIMING); priming++; - if (!(qp = sysquery("", C_IN, T_NS, NULL, 0, QUERY))) - priming = 0; - else - qp->q_flags |= (Q_SYSTEM | Q_PRIMING); } } needs_prime_cache = 0; - return; } -#ifdef BIND_NOTIFY -/* - * sysnotify(dname, class, type) - * cause a NOTIFY request to be sysquery()'d to each secondary server - * of the zone that "dname" is within. - */ -void -sysnotify(const char *dname, int class, int type) { - const char *zname, *fname; - int nns, na, zn, n; - struct zoneinfo *zp; - struct hashbuf *htp; - struct namebuf *np; - struct databuf *dp; - - ns_debug(ns_log_notify, 3, "sysnotify(%s, %s, %s)", - dname, p_class(class), p_type(type)); - htp = hashtab; - np = nlookup(dname, &htp, &fname, 0); - if (np == NULL) { - ns_warning(ns_log_notify, "sysnotify: can't find \"%s\"", - dname); - return; - } - zn = findMyZone(np, class); - if (zn == DB_Z_CACHE) { - ns_warning(ns_log_notify, "sysnotify: not auth for zone %s", - dname); - return; - } - zp = &zones[zn]; - if (zp->z_notify == znotify_no || - (zp->z_notify == znotify_use_default && - NS_OPTION_P(OPTION_NONOTIFY))) - return; - if (zp->z_type != z_master && zp->z_type != z_slave) { - ns_warning(ns_log_notify, "sysnotify: %s not master or slave", - dname); - return; - } - zname = zp->z_origin; - nns = na = 0; - if (zp->z_type == z_master) - sysnotify_slaves(dname, zname, class, zn, &nns, &na); - if (zp->z_notify_count != 0) { - struct in_addr *also_addr = zp->z_also_notify; - int i; - - for (i = 0; i < zp->z_notify_count; i++) { - sysquery(dname, class, T_SOA, also_addr, 1, - NS_NOTIFY_OP); - also_addr++; - } - nns += zp->z_notify_count; - na += zp->z_notify_count; - } - if (nns != 0 || na != 0) - ns_info(ns_log_notify, - "Sent NOTIFY for \"%s %s %s\" (%s); %d NS, %d A", - dname, p_class(class), p_type(type), zname, nns, na); -} - -static void -sysnotify_slaves(const char *dname, const char *zname, int class, int zn, - int *nns, int *na) -{ - const char *mname, *fname; - struct hashbuf *htp; - struct namebuf *np; - struct databuf *dp; - - /* - * Master. - */ - htp = hashtab; - np = nlookup(zname, &htp, &fname, 0); - if (!np) { - ns_warning(ns_log_notify, - "sysnotify: found name \"%s\" but not zone", - dname); - return; - } - mname = NULL; - for (dp = np->n_data; dp; dp = dp->d_next) { - if (dp->d_zone == DB_Z_CACHE || !match(dp, class, T_SOA)) - continue; - if (mname) { - ns_notice(ns_log_notify, - "multiple SOA's for zone \"%s\"?", - zname); - return; - } - mname = (char *) dp->d_data; - } - if (mname == NULL) { - ns_notice(ns_log_notify, "no SOA found for zone \"%s\"", - zname); - return; - } - for (dp = np->n_data; dp != NULL; dp = dp->d_next) { - if (dp->d_zone == DB_Z_CACHE || !match(dp, class, T_NS)) - continue; - if (strcasecmp((char*)dp->d_data, mname) == 0) - continue; - sysnotify_ns(dname, (char *)dp->d_data, class, zn, nns, na); - } -} - -static void -sysnotify_ns(const char *dname, const char *aname, - int class, int zn, int *nns, int *na) -{ - struct databuf *adp; - struct namebuf *anp; - const char *fname; - struct in_addr nss[NSMAX]; - struct hashbuf *htp; - int is_us, nsc; - - htp = hashtab; - anp = nlookup(aname, &htp, &fname, 0); - nsc = 0; - is_us = 0; - if (anp != NULL) - for (adp = anp->n_data; adp; adp = adp->d_next) { - struct in_addr ina; - - if (!match(adp, class, T_A)) - continue; - ina = ina_get(adp->d_data); - if (aIsUs(ina)) { - is_us = 1; - continue; - } - if (nsc < NSMAX) - nss[nsc++] = ina; - } /*next A*/ - if (nsc == 0) { - if (!is_us) { - struct qinfo *qp; - - qp = sysquery(aname, class, T_A, 0, 0, QUERY); - if (qp != NULL) - qp->q_notifyzone = zn; - } - return; - } - (void) sysquery(dname, class, T_SOA, nss, nsc, NS_NOTIFY_OP); - (*nns)++; - *na += nsc; -} -#endif /*BIND_NOTIFY*/ - struct qinfo * sysquery(const char *dname, int class, int type, - struct in_addr *nss, int nsc, int opcode) + struct 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 +#include +#include +#include +#include +#include +#include +#ifdef SVR4 /* XXX */ +# include +#else +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 #include +#include +#include #include #include #include #include +#include #include #include #include @@ -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 #include #include +#include #include #include 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 * */ @@ -31,6 +51,7 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" #include #include #include +#include #include #include @@ -40,6 +61,7 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" #include #include #include +#include #include #include #include @@ -52,10 +74,14 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" #include #include +#include + #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 #include #include +#include #include #include @@ -32,26 +33,26 @@ static char rcsid[] = "$Id: ns_xfr.c,v 8.25 1998/03/25 18:47:34 halley Exp $"; #include #include #include +#include #include #include #include #include #include +#include #include #include #include +#include + #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 +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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/commands.c b/contrib/bind/bin/nslookup/commands.c index 5564b28..fead60f 100644 --- a/contrib/bind/bin/nslookup/commands.c +++ b/contrib/bind/bin/nslookup/commands.c @@ -317,10 +317,10 @@ static yyconst int yy_ec[256] = 6, 7, 8, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 1, 9, 1, 1, 6, 1, 10, 4, 4, 11, + 1, 9, 1, 1, 10, 1, 11, 4, 4, 12, - 12, 13, 14, 15, 16, 4, 4, 17, 18, 19, - 20, 21, 4, 22, 23, 24, 4, 25, 26, 27, + 13, 14, 15, 16, 17, 4, 4, 18, 19, 20, + 21, 22, 4, 23, 24, 25, 4, 26, 27, 28, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -338,38 +338,38 @@ static yyconst int yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst int yy_meta[28] = +static yyconst int yy_meta[29] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1 + 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst short int yy_base[203] = { 0, - 491, 0, 493, 611, 611, 489, 27, 611, 54, 56, - 63, 51, 48, 46, 54, 56, 60, 479, 611, 0, - 611, 446, 77, 0, 61, 70, 62, 64, 74, 76, - 103, 611, 439, 91, 611, 80, 94, 97, 113, 75, - 95, 104, 140, 149, 96, 112, 106, 158, 107, 108, - 73, 126, 110, 166, 611, 173, 182, 142, 0, 152, - 150, 168, 195, 202, 161, 191, 160, 226, 197, 235, - 198, 611, 244, 611, 184, 205, 611, 207, 611, 253, - 213, 219, 236, 237, 611, 237, 264, 273, 282, 291, - 255, 0, 275, 294, 302, 311, 299, 268, 320, 611, - - 327, 266, 611, 336, 345, 322, 611, 354, 611, 363, - 463, 372, 381, 304, 390, 398, 611, 405, 330, 611, - 414, 423, 432, 435, 611, 442, 451, 611, 460, 469, - 478, 481, 611, 488, 497, 338, 0, 347, 611, 500, - 507, 510, 517, 520, 611, 527, 536, 365, 611, 545, - 374, 548, 555, 564, 383, 567, 611, 574, 583, 400, - 0, 592, 601, 407, 611, 416, 611, 425, 611, 611, - 463, 454, 447, 446, 445, 435, 428, 419, 410, 403, - 393, 386, 377, 368, 357, 350, 341, 314, 296, 285, - 278, 240, 229, 222, 218, 191, 177, 145, 137, 129, - - 117, 98 + 504, 0, 497, 626, 626, 484, 28, 626, 56, 58, + 65, 52, 49, 47, 55, 57, 61, 477, 626, 0, + 626, 451, 79, 0, 62, 71, 63, 67, 73, 75, + 103, 626, 450, 94, 626, 90, 74, 96, 113, 95, + 94, 107, 141, 150, 100, 106, 105, 159, 108, 104, + 72, 128, 110, 168, 626, 175, 184, 137, 0, 144, + 160, 152, 193, 200, 153, 187, 185, 225, 195, 235, + 202, 626, 244, 626, 186, 204, 626, 215, 626, 254, + 218, 237, 245, 257, 626, 241, 273, 282, 291, 301, + 263, 0, 284, 265, 312, 322, 283, 277, 331, 626, + + 338, 268, 626, 347, 356, 275, 626, 365, 626, 375, + 466, 384, 393, 314, 402, 411, 626, 418, 333, 626, + 427, 436, 445, 448, 626, 455, 464, 626, 474, 483, + 493, 496, 626, 503, 512, 341, 0, 349, 626, 515, + 522, 525, 532, 535, 626, 542, 551, 358, 626, 560, + 377, 563, 570, 579, 386, 582, 626, 589, 598, 395, + 0, 607, 616, 413, 626, 420, 626, 429, 626, 626, + 460, 459, 458, 448, 441, 440, 439, 432, 423, 416, + 405, 398, 389, 380, 368, 361, 352, 336, 325, 306, + 294, 287, 267, 247, 240, 228, 209, 207, 198, 173, + + 162, 144 } ; static yyconst short int yy_def[203] = @@ -399,152 +399,156 @@ static yyconst short int yy_def[203] = 170, 170 } ; -static yyconst short int yy_nxt[639] = +static yyconst short int yy_nxt[655] = { 0, 6, 7, 8, 9, 6, 6, 6, 10, 9, 9, - 9, 11, 12, 9, 13, 9, 14, 9, 9, 9, - 9, 15, 16, 9, 17, 9, 9, 18, 20, 21, - 22, 18, 18, 18, 23, 22, 22, 22, 24, 25, - 22, 26, 22, 27, 22, 22, 22, 22, 28, 29, - 22, 30, 22, 22, 18, 31, 32, 34, 35, 38, - 18, 18, 18, 18, 31, 32, 37, 41, 39, 18, - 18, 18, 33, 40, 33, 42, 37, 33, 34, 35, - 33, 38, 33, 40, 39, 41, 33, 33, 33, 36, - 33, 42, 34, 35, 50, 45, 33, 67, 163, 33, - - 33, 33, 33, 18, 31, 32, 33, 18, 18, 44, - 18, 18, 46, 47, 48, 53, 51, 162, 52, 60, - 33, 33, 33, 33, 49, 61, 62, 68, 65, 160, - 33, 66, 33, 33, 33, 69, 33, 158, 33, 33, - 18, 54, 55, 71, 72, 153, 18, 18, 18, 18, - 57, 19, 33, 73, 74, 59, 18, 18, 18, 48, - 32, 75, 64, 18, 44, 18, 18, 54, 55, 76, - 77, 86, 70, 18, 54, 55, 33, 146, 33, 18, - 18, 18, 18, 57, 19, 83, 33, 33, 18, 18, - 18, 143, 84, 85, 33, 18, 78, 79, 89, 71, - - 72, 18, 18, 18, 19, 93, 76, 77, 78, 79, - 33, 81, 81, 94, 95, 19, 81, 33, 141, 81, - 96, 19, 136, 33, 81, 82, 18, 68, 32, 134, - 88, 88, 44, 18, 18, 18, 90, 19, 84, 85, - 131, 92, 18, 18, 18, 73, 74, 97, 18, 18, - 44, 18, 18, 18, 78, 79, 106, 107, 98, 18, - 18, 18, 33, 33, 18, 99, 100, 102, 103, 115, - 18, 18, 18, 18, 102, 103, 108, 109, 129, 18, - 18, 18, 18, 89, 32, 126, 105, 105, 44, 18, - 18, 18, 90, 19, 33, 110, 123, 18, 18, 18, - - 111, 33, 18, 95, 19, 130, 18, 18, 18, 18, - 18, 18, 96, 19, 121, 18, 18, 18, 18, 18, - 114, 99, 100, 106, 107, 33, 70, 18, 99, 100, - 33, 119, 120, 18, 18, 18, 18, 116, 117, 148, - 149, 105, 18, 18, 18, 18, 119, 120, 138, 139, - 118, 18, 18, 18, 18, 108, 109, 113, 18, 18, - 122, 18, 18, 18, 110, 19, 148, 149, 112, 18, - 18, 18, 18, 124, 125, 150, 19, 104, 18, 18, - 18, 18, 127, 128, 154, 19, 88, 18, 18, 18, - 18, 115, 32, 101, 18, 18, 44, 18, 18, 116, - - 117, 164, 165, 91, 70, 18, 116, 117, 164, 165, - 87, 18, 18, 18, 18, 132, 133, 166, 167, 80, - 18, 18, 18, 18, 135, 19, 168, 169, 63, 137, - 18, 18, 18, 138, 139, 58, 124, 125, 18, 18, - 18, 140, 18, 124, 125, 56, 43, 33, 18, 18, - 18, 18, 127, 128, 18, 18, 18, 142, 18, 18, - 18, 127, 128, 4, 110, 33, 18, 18, 18, 18, - 130, 32, 33, 18, 18, 44, 18, 18, 18, 144, - 145, 19, 132, 133, 18, 18, 18, 147, 18, 132, - 133, 19, 170, 5, 18, 18, 18, 18, 135, 19, - - 170, 150, 19, 18, 18, 18, 151, 18, 152, 128, - 170, 154, 19, 18, 18, 18, 155, 18, 156, 157, - 170, 144, 145, 18, 18, 18, 70, 18, 144, 145, - 170, 170, 170, 18, 18, 18, 18, 159, 19, 170, - 170, 170, 161, 18, 18, 18, 150, 19, 170, 152, - 128, 18, 18, 18, 142, 18, 152, 128, 170, 170, - 170, 18, 18, 18, 18, 154, 19, 170, 156, 157, - 18, 18, 18, 70, 18, 156, 157, 170, 170, 170, - 18, 18, 18, 18, 159, 19, 170, 170, 170, 18, - 18, 18, 18, 166, 167, 170, 170, 170, 18, 18, - - 18, 18, 168, 169, 170, 170, 170, 18, 18, 18, - 3, 170, 170, 170, 170, 170, 170, 170, 170, 170, + 9, 9, 11, 12, 9, 13, 9, 14, 9, 9, + 9, 9, 15, 16, 9, 17, 9, 9, 18, 20, + 21, 22, 18, 18, 18, 23, 22, 22, 22, 22, + 24, 25, 22, 26, 22, 27, 22, 22, 22, 22, + 28, 29, 22, 30, 22, 22, 18, 31, 32, 34, + 35, 38, 18, 18, 18, 18, 31, 32, 37, 41, + 39, 18, 18, 18, 33, 40, 33, 42, 37, 33, + 34, 35, 33, 38, 33, 41, 39, 40, 33, 33, + 33, 42, 36, 46, 33, 34, 35, 67, 33, 33, + + 33, 33, 33, 18, 31, 32, 45, 18, 18, 44, + 18, 18, 18, 47, 48, 50, 51, 33, 52, 53, + 61, 33, 33, 33, 60, 49, 62, 33, 66, 68, + 65, 33, 33, 33, 33, 33, 69, 33, 71, 72, + 33, 18, 54, 55, 163, 73, 74, 18, 18, 18, + 18, 57, 19, 76, 77, 33, 59, 18, 18, 18, + 48, 32, 162, 64, 18, 44, 18, 18, 18, 54, + 55, 33, 75, 160, 70, 18, 54, 55, 83, 33, + 33, 18, 18, 18, 18, 57, 19, 33, 84, 85, + 18, 18, 18, 18, 78, 79, 89, 86, 158, 18, + + 18, 18, 19, 71, 72, 76, 77, 153, 93, 146, + 81, 81, 33, 33, 33, 81, 78, 79, 81, 95, + 19, 94, 33, 81, 82, 18, 68, 32, 143, 88, + 88, 44, 18, 18, 88, 18, 90, 19, 96, 19, + 141, 92, 18, 18, 18, 73, 74, 136, 18, 18, + 44, 18, 18, 18, 18, 78, 79, 97, 84, 85, + 18, 18, 18, 98, 106, 107, 110, 134, 33, 102, + 103, 111, 33, 18, 99, 100, 106, 107, 115, 18, + 18, 18, 18, 102, 103, 108, 109, 131, 18, 18, + 18, 18, 89, 32, 129, 105, 105, 44, 18, 18, + + 105, 18, 90, 19, 33, 114, 126, 18, 18, 18, + 33, 33, 18, 95, 19, 130, 18, 18, 18, 18, + 18, 18, 18, 96, 19, 123, 18, 18, 18, 18, + 18, 18, 99, 100, 119, 120, 121, 70, 18, 99, + 100, 33, 148, 149, 18, 18, 18, 18, 116, 117, + 138, 139, 105, 18, 18, 18, 18, 119, 120, 148, + 149, 118, 18, 18, 18, 18, 108, 109, 113, 18, + 18, 122, 18, 18, 18, 18, 110, 19, 150, 19, + 112, 18, 18, 18, 18, 124, 125, 154, 19, 104, + 18, 18, 18, 18, 127, 128, 164, 165, 88, 18, + + 18, 18, 18, 115, 32, 101, 18, 18, 44, 18, + 18, 18, 116, 117, 164, 165, 91, 70, 18, 116, + 117, 166, 167, 87, 18, 18, 18, 18, 132, 133, + 168, 169, 80, 18, 18, 18, 18, 135, 19, 63, + 58, 56, 137, 18, 18, 18, 138, 139, 43, 124, + 125, 18, 18, 18, 140, 18, 124, 125, 33, 18, + 4, 18, 18, 18, 18, 127, 128, 110, 18, 18, + 142, 18, 18, 18, 18, 127, 128, 33, 33, 19, + 18, 18, 18, 18, 130, 32, 19, 18, 18, 44, + 18, 18, 18, 18, 144, 145, 170, 132, 133, 18, + + 18, 18, 147, 18, 132, 133, 5, 170, 170, 18, + 18, 18, 18, 135, 19, 170, 150, 19, 18, 18, + 18, 151, 18, 152, 128, 170, 154, 19, 18, 18, + 18, 155, 18, 156, 157, 170, 144, 145, 18, 18, + 18, 70, 18, 144, 145, 170, 170, 170, 18, 18, + 18, 18, 159, 19, 170, 170, 170, 161, 18, 18, + 18, 150, 19, 170, 152, 128, 18, 18, 18, 142, + 18, 152, 128, 170, 170, 170, 18, 18, 18, 18, + 154, 19, 170, 156, 157, 18, 18, 18, 70, 18, + 156, 157, 170, 170, 170, 18, 18, 18, 18, 159, + + 19, 170, 170, 170, 18, 18, 18, 18, 166, 167, + 170, 170, 170, 18, 18, 18, 18, 168, 169, 170, + 170, 170, 18, 18, 18, 3, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, - 170, 170, 170, 170, 170, 170, 170, 170 + 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 170, 170, 170 } ; -static yyconst short int yy_chk[639] = +static yyconst short int yy_chk[655] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, + 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 9, 9, 9, 10, 10, 13, - 9, 9, 9, 11, 11, 11, 12, 16, 14, 11, - 11, 11, 14, 15, 13, 17, 25, 12, 23, 23, - 15, 26, 16, 28, 27, 29, 17, 25, 27, 11, - 28, 30, 34, 34, 40, 36, 26, 51, 202, 51, - - 29, 40, 30, 31, 31, 31, 36, 31, 31, 31, - 31, 31, 37, 38, 39, 42, 41, 201, 41, 45, - 37, 41, 45, 38, 39, 46, 47, 52, 49, 200, - 42, 50, 47, 49, 50, 53, 53, 199, 46, 39, - 43, 43, 43, 58, 58, 198, 43, 43, 43, 44, - 44, 44, 52, 60, 60, 44, 44, 44, 48, 48, - 48, 61, 48, 48, 48, 48, 48, 54, 54, 62, - 62, 67, 54, 56, 56, 56, 61, 197, 60, 56, - 56, 56, 57, 57, 57, 65, 67, 65, 57, 57, - 57, 196, 66, 66, 62, 63, 63, 63, 69, 71, - - 71, 63, 63, 63, 64, 75, 76, 76, 78, 78, - 75, 64, 64, 78, 81, 81, 64, 66, 195, 64, - 82, 82, 194, 69, 64, 64, 68, 68, 68, 193, - 68, 68, 68, 68, 68, 70, 70, 70, 84, 84, - 192, 70, 70, 70, 73, 73, 73, 83, 73, 73, - 73, 73, 73, 80, 80, 80, 91, 91, 86, 80, - 80, 80, 83, 86, 87, 87, 87, 102, 102, 98, - 87, 87, 87, 88, 88, 88, 93, 93, 191, 88, - 88, 88, 89, 89, 89, 190, 89, 89, 89, 89, - 89, 90, 90, 90, 98, 94, 189, 90, 90, 90, - - 94, 93, 95, 95, 95, 114, 95, 95, 95, 95, - 95, 96, 96, 96, 188, 96, 96, 96, 96, 96, - 97, 99, 99, 106, 106, 97, 99, 101, 101, 101, - 114, 119, 119, 101, 101, 101, 104, 104, 104, 136, - 136, 187, 104, 104, 104, 105, 105, 105, 138, 138, - 186, 105, 105, 105, 108, 108, 108, 185, 108, 108, - 108, 108, 108, 110, 110, 110, 148, 148, 184, 110, - 110, 110, 112, 112, 112, 151, 151, 183, 112, 112, - 112, 113, 113, 113, 155, 155, 182, 113, 113, 113, - 115, 115, 115, 181, 115, 115, 115, 115, 115, 116, - - 116, 160, 160, 180, 116, 118, 118, 118, 164, 164, - 179, 118, 118, 118, 121, 121, 121, 166, 166, 178, - 121, 121, 121, 122, 122, 122, 168, 168, 177, 122, - 122, 122, 123, 123, 123, 176, 124, 124, 123, 123, - 123, 124, 126, 126, 126, 175, 174, 173, 126, 126, - 126, 127, 127, 127, 172, 127, 127, 127, 127, 127, - 129, 129, 129, 171, 111, 33, 129, 129, 129, 130, - 130, 130, 22, 130, 130, 130, 130, 130, 131, 131, - 131, 18, 132, 132, 131, 131, 131, 132, 134, 134, - 134, 6, 3, 1, 134, 134, 134, 135, 135, 135, - - 0, 140, 140, 135, 135, 135, 140, 141, 141, 141, - 0, 142, 142, 141, 141, 141, 142, 143, 143, 143, - 0, 144, 144, 143, 143, 143, 144, 146, 146, 146, - 0, 0, 0, 146, 146, 146, 147, 147, 147, 0, - 0, 0, 147, 147, 147, 150, 150, 150, 0, 152, - 152, 150, 150, 150, 152, 153, 153, 153, 0, 0, - 0, 153, 153, 153, 154, 154, 154, 0, 156, 156, - 154, 154, 154, 156, 158, 158, 158, 0, 0, 0, - 158, 158, 158, 159, 159, 159, 0, 0, 0, 159, - 159, 159, 162, 162, 162, 0, 0, 0, 162, 162, - - 162, 163, 163, 163, 0, 0, 0, 163, 163, 163, + 7, 7, 7, 7, 7, 7, 9, 9, 9, 10, + 10, 13, 9, 9, 9, 11, 11, 11, 12, 16, + 14, 11, 11, 11, 14, 15, 13, 17, 25, 12, + 23, 23, 15, 26, 16, 29, 27, 28, 17, 25, + 27, 30, 11, 37, 28, 34, 34, 51, 26, 51, + + 29, 37, 30, 31, 31, 31, 36, 31, 31, 31, + 31, 31, 31, 38, 39, 40, 41, 36, 41, 42, + 46, 41, 40, 38, 45, 39, 47, 45, 50, 52, + 49, 50, 47, 46, 42, 49, 53, 53, 58, 58, + 39, 43, 43, 43, 202, 60, 60, 43, 43, 43, + 44, 44, 44, 62, 62, 52, 44, 44, 44, 48, + 48, 48, 201, 48, 48, 48, 48, 48, 48, 54, + 54, 60, 61, 200, 54, 56, 56, 56, 65, 62, + 65, 56, 56, 56, 57, 57, 57, 61, 66, 66, + 57, 57, 57, 63, 63, 63, 69, 67, 199, 63, + + 63, 63, 64, 71, 71, 76, 76, 198, 75, 197, + 64, 64, 67, 75, 66, 64, 78, 78, 64, 81, + 81, 78, 69, 64, 64, 68, 68, 68, 196, 68, + 68, 68, 68, 68, 68, 70, 70, 70, 82, 82, + 195, 70, 70, 70, 73, 73, 73, 194, 73, 73, + 73, 73, 73, 73, 80, 80, 80, 83, 84, 84, + 80, 80, 80, 86, 91, 91, 94, 193, 86, 102, + 102, 94, 83, 87, 87, 87, 106, 106, 98, 87, + 87, 87, 88, 88, 88, 93, 93, 192, 88, 88, + 88, 89, 89, 89, 191, 89, 89, 89, 89, 89, + + 89, 90, 90, 90, 98, 97, 190, 90, 90, 90, + 97, 93, 95, 95, 95, 114, 95, 95, 95, 95, + 95, 95, 96, 96, 96, 189, 96, 96, 96, 96, + 96, 96, 99, 99, 119, 119, 188, 99, 101, 101, + 101, 114, 136, 136, 101, 101, 101, 104, 104, 104, + 138, 138, 187, 104, 104, 104, 105, 105, 105, 148, + 148, 186, 105, 105, 105, 108, 108, 108, 185, 108, + 108, 108, 108, 108, 108, 110, 110, 110, 151, 151, + 184, 110, 110, 110, 112, 112, 112, 155, 155, 183, + 112, 112, 112, 113, 113, 113, 160, 160, 182, 113, + + 113, 113, 115, 115, 115, 181, 115, 115, 115, 115, + 115, 115, 116, 116, 164, 164, 180, 116, 118, 118, + 118, 166, 166, 179, 118, 118, 118, 121, 121, 121, + 168, 168, 178, 121, 121, 121, 122, 122, 122, 177, + 176, 175, 122, 122, 122, 123, 123, 123, 174, 124, + 124, 123, 123, 123, 124, 126, 126, 126, 173, 172, + 171, 126, 126, 126, 127, 127, 127, 111, 127, 127, + 127, 127, 127, 127, 129, 129, 129, 33, 22, 18, + 129, 129, 129, 130, 130, 130, 6, 130, 130, 130, + 130, 130, 130, 131, 131, 131, 3, 132, 132, 131, + + 131, 131, 132, 134, 134, 134, 1, 0, 0, 134, + 134, 134, 135, 135, 135, 0, 140, 140, 135, 135, + 135, 140, 141, 141, 141, 0, 142, 142, 141, 141, + 141, 142, 143, 143, 143, 0, 144, 144, 143, 143, + 143, 144, 146, 146, 146, 0, 0, 0, 146, 146, + 146, 147, 147, 147, 0, 0, 0, 147, 147, 147, + 150, 150, 150, 0, 152, 152, 150, 150, 150, 152, + 153, 153, 153, 0, 0, 0, 153, 153, 153, 154, + 154, 154, 0, 156, 156, 154, 154, 154, 156, 158, + 158, 158, 0, 0, 0, 158, 158, 158, 159, 159, + + 159, 0, 0, 0, 159, 159, 159, 162, 162, 162, + 0, 0, 0, 162, 162, 162, 163, 163, 163, 0, + 0, 0, 163, 163, 163, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, - 170, 170, 170, 170, 170, 170, 170, 170 + 170, 170, 170, 170 } ; static yy_state_type yy_last_accepting_state; @@ -662,6 +666,7 @@ static char sccsid[] = "@(#)commands.l 5.13 (Berkeley) 7/24/90"; extern char rootServerName[]; extern void PrintHelp(); +extern void ViewList(char *); /* Macros after this point can all be overridden by user definitions in @@ -816,7 +821,7 @@ YY_DECL register char *yy_cp, *yy_bp; register int yy_act; -#line 109 "commands.l" +#line 110 "commands.l" if ( yy_init ) @@ -875,7 +880,7 @@ yy_match: yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 611 ); + while ( yy_base[yy_current_state] != 626 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -906,7 +911,7 @@ case 1: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 110 "commands.l" +#line 111 "commands.l" { /* * 0 == use current server to find @@ -923,7 +928,7 @@ case 2: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 120 "commands.l" +#line 121 "commands.l" { SetDefaultServer(yytext, 1); return(1); @@ -934,7 +939,7 @@ case 3: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 124 "commands.l" +#line 125 "commands.l" { return(0); } @@ -944,7 +949,7 @@ case 4: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 127 "commands.l" +#line 128 "commands.l" { SetDefaultServer(rootServerName, 1); return(1); @@ -955,7 +960,7 @@ case 5: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 131 "commands.l" +#line 132 "commands.l" { /* * 2nd arg. @@ -971,7 +976,7 @@ case 6: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 140 "commands.l" +#line 141 "commands.l" { Finger(yytext, 0); return(1); @@ -982,9 +987,9 @@ case 7: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 144 "commands.l" +#line 145 "commands.l" { - ViewList(yytext); + ViewList((char *)yytext); return(1); } YY_BREAK @@ -993,7 +998,7 @@ case 8: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 148 "commands.l" +#line 149 "commands.l" { /* * 2nd arg. @@ -1009,7 +1014,7 @@ case 9: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 157 "commands.l" +#line 158 "commands.l" { ListHosts(yytext, 0); return(1); @@ -1020,7 +1025,7 @@ case 10: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 161 "commands.l" +#line 162 "commands.l" { /* * 2nd arg. @@ -1036,7 +1041,7 @@ case 11: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 170 "commands.l" +#line 171 "commands.l" { ListHostsByType(yytext, 0); return(1); @@ -1047,7 +1052,7 @@ case 12: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 174 "commands.l" +#line 175 "commands.l" { SetOption(yytext); return(1); @@ -1058,7 +1063,7 @@ case 13: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 178 "commands.l" +#line 179 "commands.l" { PrintHelp(); return(1); @@ -1069,7 +1074,7 @@ case 14: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 182 "commands.l" +#line 183 "commands.l" { extern void PrintHelp(); @@ -1082,7 +1087,7 @@ case 15: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 188 "commands.l" +#line 189 "commands.l" { /* * 0 == output to stdout @@ -1097,7 +1102,7 @@ case 16: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 196 "commands.l" +#line 197 "commands.l" { LookupHost(yytext, 0); return(1); @@ -1108,7 +1113,7 @@ case 17: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 200 "commands.l" +#line 201 "commands.l" { /* * 0 == output to stdout @@ -1123,7 +1128,7 @@ case 18: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 208 "commands.l" +#line 209 "commands.l" { LookupHostWithServer(yytext, 0); return(1); @@ -1131,14 +1136,14 @@ YY_RULE_SETUP YY_BREAK case 19: YY_RULE_SETUP -#line 212 "commands.l" +#line 213 "commands.l" { return(1); } YY_BREAK case 20: YY_RULE_SETUP -#line 215 "commands.l" +#line 216 "commands.l" { printf("Unrecognized command: %s", yytext); @@ -1147,12 +1152,12 @@ YY_RULE_SETUP YY_BREAK case 21: YY_RULE_SETUP -#line 220 "commands.l" +#line 221 "commands.l" { ; } YY_BREAK case 22: YY_RULE_SETUP -#line 221 "commands.l" +#line 222 "commands.l" ECHO; YY_BREAK case YY_STATE_EOF(INITIAL): @@ -2032,5 +2037,5 @@ int main() return 0; } #endif -#line 221 "commands.l" +#line 222 "commands.l" diff --git a/contrib/bind/bin/nslookup/commands.l b/contrib/bind/bin/nslookup/commands.l index c3a220a..286ae95 100644 --- a/contrib/bind/bin/nslookup/commands.l +++ b/contrib/bind/bin/nslookup/commands.l @@ -100,10 +100,11 @@ static char sccsid[] = "@(#)commands.l 5.13 (Berkeley) 7/24/90"; extern char rootServerName[]; extern void PrintHelp(); +extern void ViewList(char *); %} WS [ \t] -FLET [A-Za-z0-9.*\\] +FLET [A-Za-z0-9.*\\_] LET [A-Za-z0-9.*] NAME [A-Za-z0-9.*=_/-] %% @@ -142,7 +143,7 @@ NAME [A-Za-z0-9.*=_/-] return(1); } ^{WS}*view{WS}+{NAME}+{WS}*$ { - ViewList(yytext); + ViewList((char *)yytext); return(1); } ^{WS}*ls{WS}+(("-a"|"-d"|"-h"|"-m"|"-s"){WS}+)?{LET}{NAME}*{WS}+>>?{WS}+{NAME}+{WS}*$ { diff --git a/contrib/bind/bin/nslookup/debug.c b/contrib/bind/bin/nslookup/debug.c index 76260e0..2448381 100644 --- a/contrib/bind/bin/nslookup/debug.c +++ b/contrib/bind/bin/nslookup/debug.c @@ -52,8 +52,8 @@ */ #ifndef lint -static char sccsid[] = "@(#)debug.c 5.26 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: debug.c,v 8.11 1998/03/19 19:30:54 halley Exp $"; +static const char sccsid[] = "@(#)debug.c 5.26 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: debug.c,v 8.15 1999/10/13 16:39:16 vixie Exp $"; #endif /* not lint */ /* @@ -88,7 +88,6 @@ static char rcsid[] = "$Id: debug.c,v 8.11 1998/03/19 19:30:54 halley Exp $"; /* * Imported from res_debug.c */ -extern char *_res_resultcodes[]; extern char *_res_opcodes[]; /* @@ -119,11 +118,11 @@ Fprint_query(const u_char *msg, const u_char *eom, int printHeader, FILE *file) */ hp = (HEADER *)msg; cp = msg + HFIXEDSZ; - if (printHeader || (_res.options & RES_DEBUG2)) { + if (printHeader || (res.options & RES_DEBUG2)) { fprintf(file," HEADER:\n"); fprintf(file,"\topcode = %s", _res_opcodes[hp->opcode]); fprintf(file,", id = %d", ntohs(hp->id)); - fprintf(file,", rcode = %s\n", _res_resultcodes[hp->rcode]); + fprintf(file,", rcode = %s\n", p_rcode(hp->rcode)); fprintf(file,"\theader flags: "); if (hp->qr) { fprintf(file," response"); @@ -280,9 +279,9 @@ Print_rr(const u_char *ocp, const u_char *msg, const u_char *eom, FILE *file) { NS_GET16(dlen, cp); BOUNDS_CHECK(cp, dlen); - debug = _res.options & (RES_DEBUG|RES_DEBUG2); + debug = res.options & (RES_DEBUG|RES_DEBUG2); if (debug) { - if (_res.options & RES_DEBUG2) + if (res.options & RES_DEBUG2) fprintf(file,"\n\ttype = %s, class = %s, dlen = %d", p_type(type), p_class(class), dlen); if (type == T_SOA) @@ -622,8 +621,9 @@ Print_rr(const u_char *ocp, const u_char *msg, const u_char *eom, FILE *file) { default: { char buf[2048]; /* XXX need to malloc/realloc. */ - if (ns_sprintrrf(msg, eom - msg, "?", class, type, rrttl, - cp1, dlen, NULL, NULL, buf, sizeof buf) < 0) { + if (ns_sprintrrf(msg, eom - msg, "?", (ns_class)class, + (ns_type)type, rrttl, cp1, dlen, NULL, NULL, + buf, sizeof buf) < 0) { perror("ns_sprintrrf"); } else { fprintf(file, @@ -633,7 +633,7 @@ Print_rr(const u_char *ocp, const u_char *msg, const u_char *eom, FILE *file) { cp += dlen; } } - if (_res.options & RES_DEBUG && type != T_SOA) { + if (res.options & RES_DEBUG && type != T_SOA) { fprintf(file,"\tttl = %lu (%s)\n", rrttl, p_time(rrttl)); } if (cp != cp1 + dlen) { diff --git a/contrib/bind/bin/nslookup/getinfo.c b/contrib/bind/bin/nslookup/getinfo.c index 20601e5..6f4ecff 100644 --- a/contrib/bind/bin/nslookup/getinfo.c +++ b/contrib/bind/bin/nslookup/getinfo.c @@ -52,8 +52,8 @@ */ #ifndef lint -static char sccsid[] = "@(#)getinfo.c 5.26 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: getinfo.c,v 8.11 1998/03/19 19:30:55 halley Exp $"; +static const char sccsid[] = "@(#)getinfo.c 5.26 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: getinfo.c,v 8.15 1999/10/13 16:39:16 vixie Exp $"; #endif /* not lint */ /* @@ -82,12 +82,12 @@ static char rcsid[] = "$Id: getinfo.c,v 8.11 1998/03/19 19:30:55 halley Exp $"; #include #include #include +#include #include "port_after.h" #include "res.h" -extern char *_res_resultcodes[]; extern char *res_skip(); static char *addr_list[MAXADDRS + 1]; @@ -108,7 +108,7 @@ ServerTable server[MAXSERVERS]; typedef union { HEADER qb1; - u_char qb2[PACKETSZ*2]; + u_char qb2[64*1024]; } querybuf; typedef union { @@ -161,10 +161,10 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) int numAliases = 0; int numAddresses = 0; int n, i, j; - int len; int dlen; int status; int numServers; + size_t s; Boolean haveAnswer; Boolean printedAnswers = FALSE; @@ -178,7 +178,7 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) sizeof(answer), &n); if (status != SUCCESS) { - if (_res.options & RES_DEBUG2) + if (res.options & RES_DEBUG2) printf("SendRequest failed\n"); return (status); } @@ -267,11 +267,11 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) continue; } *aliasPtr++ = (char *)bp; - n = strlen((char *)bp) + 1; - host_aliases_len[numAliases] = n; + s = strlen((char *)bp) + 1; + host_aliases_len[numAliases] = s; numAliases++; - bp += n; - buflen -= n; + bp += s; + buflen -= s; continue; } else if (type == T_PTR) { /* @@ -283,9 +283,9 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) continue; } cp += n; - len = strlen((char *)bp) + 1; - hostPtr->name = Calloc(1, len); - memcpy(hostPtr->name, bp, len); + s = strlen((char *)bp) + 1; + hostPtr->name = Calloc(1, s); + memcpy(hostPtr->name, bp, s); haveAnswer = TRUE; break; } else if (type != T_A) { @@ -315,14 +315,14 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) hostPtr->addrLen = dlen; origClass = class; hostPtr->addrType = (class == C_IN) ? AF_INET : AF_UNSPEC; - len = strlen((char *)bp) + 1; - hostPtr->name = Calloc(1, len); - memcpy(hostPtr->name, bp, len); + s = strlen((char *)bp) + 1; + hostPtr->name = Calloc(1, s); + memcpy(hostPtr->name, bp, s); } bp += (((u_int32_t)bp) % sizeof(align)); if (bp + dlen >= &hostbuf[sizeof(hostbuf)]) { - if (_res.options & RES_DEBUG) { + if (res.options & RES_DEBUG) { printf("Size (%d) too big\n", dlen); } break; @@ -416,9 +416,9 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) return(ERROR); } cp += n; - len = strlen((char *)bp) + 1; - dnamePtr = Calloc(1, len); /* domain name */ - memcpy(dnamePtr, bp, len); + s = strlen((char *)bp) + 1; + dnamePtr = Calloc(1, s); /* domain name */ + memcpy(dnamePtr, bp, s); if (cp + 3 * INT16SZ + INT32SZ > eom) return (ERROR); @@ -439,9 +439,9 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) return(ERROR); } cp += n; - len = strlen((char *)bp) + 1; - namePtr = Calloc(1, len); /* server host name */ - memcpy(namePtr, bp, len); + s = strlen((char *)bp) + 1; + namePtr = Calloc(1, s); /* server host name */ + memcpy(namePtr, bp, s); /* * Store the information keyed by the server host name. @@ -578,10 +578,10 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) * Retrieves host name, address and alias information * for a domain. * -* Algorithm from res_search(). +* Algorithm from res_nsearch(). * * Results: -* ERROR - res_mkquery failed. +* ERROR - res_nmkquery failed. * + return values from GetAnswer() * ******************************************************************************* @@ -603,6 +603,7 @@ GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer) Boolean got_nodata = FALSE; struct in_addr ina; Boolean tried_as_is = FALSE; + char tmp[NS_MAXDNAME]; /* Catch explicit addresses */ if ((queryType == T_A) && IsAddr(name, &ina)) { @@ -623,7 +624,7 @@ GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer) for (cp = name, n = 0; *cp; cp++) if (*cp == '.') n++; - if (n == 0 && (cp = hostalias(name))) { + if (n == 0 && (cp = res_hostalias(&res, name, tmp, sizeof tmp))) { printf("Aliased to \"%s\"\n\n", cp); return (GetHostDomain(nsAddrPtr, queryClass, queryType, cp, (char *)NULL, hostPtr, isServer)); @@ -633,7 +634,7 @@ GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer) * If there are dots in the name already, let's just give it a try * 'as is'. The threshold can be set with the "ndots" option. */ - if (n >= (int)_res.ndots) { + if (n >= (int)res.ndots) { result = GetHostDomain(nsAddrPtr, queryClass, queryType, name, (char *)NULL, hostPtr, isServer); if (result == SUCCESS) @@ -649,9 +650,9 @@ GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer) * - there is at least one dot, there is no trailing dot, * and RES_DNSRCH is set. */ - if ((n == 0 && _res.options & RES_DEFNAMES) || - (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH)) - for (domain = _res.dnsrch; *domain; domain++) { + if ((n == 0 && res.options & RES_DEFNAMES) || + (n != 0 && *--cp != '.' && res.options & RES_DNSRCH)) + for (domain = res.dnsrch; *domain; domain++) { result = GetHostDomain(nsAddrPtr, queryClass, queryType, name, *domain, hostPtr, isServer); /* @@ -671,7 +672,7 @@ GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer) if (result == NO_INFO) got_nodata++; if ((result != NXDOMAIN && result != NO_INFO) || - (_res.options & RES_DNSRCH) == 0) + (res.options & RES_DNSRCH) == 0) break; } /* if we have not already tried the name "as is", do that now. @@ -721,11 +722,11 @@ GetHostDomain(nsAddrPtr, queryClass, queryType, name, domain, hostPtr, isServer) MAXDNAME, name, MAXDNAME, domain); longname = nbuf; } - n = res_mkquery(QUERY, longname, queryClass, queryType, - NULL, 0, 0, buf.qb2, sizeof(buf)); + n = res_nmkquery(&res, QUERY, longname, queryClass, queryType, + NULL, 0, 0, buf.qb2, sizeof(buf)); if (n < 0) { - if (_res.options & RES_DEBUG) { - printf("Res_mkquery failed\n"); + if (res.options & RES_DEBUG) { + printf("Res_nmkquery failed\n"); } return (ERROR); } @@ -737,7 +738,8 @@ GetHostDomain(nsAddrPtr, queryClass, queryType, name, domain, hostPtr, isServer) */ if (n == NONAUTH) { if (hostPtr->name == NULL) { - int len = strlen(longname) + 1; + size_t len = strlen(longname) + 1; + hostPtr->name = Calloc(len, sizeof(char)); memcpy(hostPtr->name, longname, len); } @@ -755,7 +757,7 @@ GetHostDomain(nsAddrPtr, queryClass, queryType, name, domain, hostPtr, isServer) * that corresponds to the given address. * * Results: -* ERROR - res_mkquery failed. +* ERROR - res_nmkquery failed. * + return values from GetAnswer() * ******************************************************************************* @@ -777,11 +779,11 @@ GetHostInfoByAddr(nsAddrPtr, address, hostPtr) ((unsigned)p[2] & 0xff), ((unsigned)p[1] & 0xff), ((unsigned)p[0] & 0xff)); - n = res_mkquery(QUERY, qbuf, C_IN, T_PTR, NULL, 0, NULL, - buf.qb2, sizeof buf); + n = res_nmkquery(&res, QUERY, qbuf, C_IN, T_PTR, NULL, 0, NULL, + buf.qb2, sizeof buf); if (n < 0) { - if (_res.options & RES_DEBUG) { - printf("res_mkquery() failed\n"); + if (res.options & RES_DEBUG) { + printf("res_nmkquery() failed\n"); } return (ERROR); } 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/main.c b/contrib/bind/bin/nslookup/main.c index 3c97afe..d36c0f4 100644 --- a/contrib/bind/bin/nslookup/main.c +++ b/contrib/bind/bin/nslookup/main.c @@ -51,15 +51,33 @@ * 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. + */ + #ifndef lint char copyright[] = "@(#) Copyright (c) 1985,1989 Regents of the University of California.\n\ - All rights reserved.\n"; + All rights reserved.\n\ + @(#) Portions Copyright (c) 1996-1999 Internet Software Consortium.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 5.42 (Berkeley) 3/3/91"; -static char rcsid[] = "$Id: main.c,v 8.7 1997/04/25 00:27:18 vixie Exp $"; +static const char sccsid[] = "@(#)main.c 5.42 (Berkeley) 3/3/91"; +static const char rcsid[] = "$Id: main.c,v 8.13 1999/10/13 16:39:19 vixie Exp $"; #endif /* not lint */ /* @@ -113,10 +131,10 @@ static char rcsid[] = "$Id: main.c,v 8.7 1997/04/25 00:27:18 vixie Exp $"; char rootServerName[NAME_LEN] = ROOT_SERVER; /* - * Import the state information from the resolver library. + * Declare a resolver context. */ -extern struct __res_state _res; +struct __res_state res; /* @@ -160,6 +178,13 @@ char *pager; static void CvtAddrToPtr(); static void ReadRC(); +/* + * Forward declarations. + */ +void LocalServer(HostInfo *defaultPtr); +void res_re_init(void); +void res_dnsrch(char *cp); + /* ****************************************************************************** @@ -187,7 +212,7 @@ main(argc, argv) * Initialize the resolver library routines. */ - if (res_init() == -1) { + if (res_ninit(&res) == -1) { fprintf(stderr,"*** Can't initialize resolver.\n"); exit(1); } @@ -245,8 +270,8 @@ main(argc, argv) */ if (inet_aton(*++argv, &addr)) { - _res.nscount = 1; - _res.nsaddr.sin_addr = addr; + res.nscount = 1; + res.nsaddr.sin_addr = addr; } else { hp = gethostbyname(*argv); if (hp == NULL) { @@ -256,33 +281,33 @@ main(argc, argv) fputc('\n', stderr); } else { for (i = 0; i < MAXNS && hp->h_addr_list[i] != NULL; i++) { - memcpy(&_res.nsaddr_list[i].sin_addr, hp->h_addr_list[i], + memcpy(&res.nsaddr_list[i].sin_addr, hp->h_addr_list[i], hp->h_length); } - _res.nscount = i; + res.nscount = i; } } } - if (_res.nscount == 0 || useLocalServer) { + if (res.nscount == 0 || useLocalServer) { LocalServer(defaultPtr); } else { - for (i = 0; i < _res.nscount; i++) { - if (_res.nsaddr_list[i].sin_addr.s_addr == INADDR_ANY) { + for (i = 0; i < res.nscount; i++) { + if (res.nsaddr_list[i].sin_addr.s_addr == INADDR_ANY) { LocalServer(defaultPtr); break; } else { - result = GetHostInfoByAddr(&(_res.nsaddr_list[i].sin_addr), - &(_res.nsaddr_list[i].sin_addr), + result = GetHostInfoByAddr(&(res.nsaddr_list[i].sin_addr), + &(res.nsaddr_list[i].sin_addr), defaultPtr); if (result != SUCCESS) { fprintf(stderr, "*** Can't find server name for address %s: %s\n", - inet_ntoa(_res.nsaddr_list[i].sin_addr), + inet_ntoa(res.nsaddr_list[i].sin_addr), DecodeError(result)); } else { - defaultAddr = _res.nsaddr_list[i].sin_addr; + defaultAddr = res.nsaddr_list[i].sin_addr; break; } } @@ -293,7 +318,7 @@ main(argc, argv) * command line argument to specify an address. */ - if (i == _res.nscount) { + if (i == res.nscount) { fprintf(stderr, "*** Default servers are not available\n"); exit(1); } @@ -304,10 +329,10 @@ main(argc, argv) #ifdef DEBUG #ifdef DEBUG2 - _res.options |= RES_DEBUG2; + res.options |= RES_DEBUG2; #endif - _res.options |= RES_DEBUG; - _res.retry = 2; + res.options |= RES_DEBUG; + res.retry = 2; #endif /* DEBUG */ /* @@ -355,6 +380,7 @@ main(argc, argv) } +void LocalServer(defaultPtr) HostInfo *defaultPtr; { @@ -464,6 +490,7 @@ SetDefaultServer(string, local) char newServer[NAME_LEN]; int result; int i; + int j; /* * Parse the command line. It maybe of the form "server name", @@ -471,13 +498,32 @@ SetDefaultServer(string, local) */ if (local) { - i = sscanf(string, " lserver %s", newServer); + i = matchString (" lserver ", string); + if (i > 0) { + j = pickString(string + i, newServer, sizeof newServer); + if (j == 0) { /* value was too big for newServer variable */ + fprintf(stderr, + "SetDefaultServer: invalid name: %s\n", + string + i); + return(ERROR); + } + } } else { - i = sscanf(string, " server %s", newServer); + i = matchString(" server ", string); + if (i > 0) { + j = pickString(string + i, newServer, sizeof newServer); + if (j == 0) { /* value was too big for newServer variable */ + fprintf(stderr, + "SetDefaultServer: invalid name: %s\n", + string + i); + return(ERROR); + } + } } - if (i != 1) { - i = sscanf(string, " %s", newServer); - if (i != 1) { + + if (i == 0) { + i = pickString(string, newServer, sizeof newServer); + if (i == 0) { /* value was too big for newServer variable */ fprintf(stderr,"SetDefaultServer: invalid name: %s\n", string); return(ERROR); } @@ -667,6 +713,7 @@ LookupHost(string, putToFile) char host[NAME_LEN]; char file[PATH_MAX]; int result; + int i; /* * Invalidate the current host information to prevent Finger @@ -681,11 +728,16 @@ LookupHost(string, putToFile) * */ - sscanf(string, " %s", host); /* removes white space */ + i = pickString(string, host, sizeof host); + if (i == 0) { /* string was too long for host variable */ + fprintf(stderr, "*** invalid name: %s\n", string); + return(ERROR); + } + 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); return(ERROR); @@ -739,14 +791,27 @@ LookupHostWithServer(string, putToFile) char server[NAME_LEN]; int result; static HostInfo serverInfo; + int i; + int j; curHostValid = FALSE; - sscanf(string, " %s %s", host, server); + i = pickString(string, host, sizeof host); + if (i == 0) { /* value was too big for host variable */ + fprintf(stderr, "*** invalid name: %s\n", string); + return(ERROR); + } + + j = pickString(string + i, server, sizeof server); + if (j == 0) { /* value was too big for server variable */ + fprintf(stderr, "*** invalid server name: %s\n", string + i); + return(ERROR); + } + 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); return(ERROR); @@ -823,6 +888,7 @@ SetOption(option) char type[NAME_LEN]; char *ptr; int tmp; + int i; while (isspace(*option)) ++option; @@ -840,28 +906,34 @@ SetOption(option) } else if (strncmp(option, "ALL", 3) == 0) { ShowOptions(); } 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; printf("d2 mode disabled; still in debug mode\n"); } 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, "do", 2) == 0) { /* domain */ ptr = strchr(option, '='); if (ptr != NULL) { - sscanf(++ptr, "%s", _res.defdname); + i = pickString(++ptr, res.defdname, sizeof res.defdname); + if (i == 0) { /* name too long or nothing there */ + fprintf(stderr, "** invalid 'domain' value: %s\n", + ptr) ; + return(ERROR); + } + res_re_init(); } } else if (strncmp(option, "deb", 1) == 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, "ig", 2) == 0) { /* ignore */ - _res.options |= RES_IGNTC; + res.options |= RES_IGNTC; } else if (strncmp(option, "noig", 4) == 0) { - _res.options &= ~RES_IGNTC; + res.options &= ~RES_IGNTC; } else if (strncmp(option, "po", 2) == 0) { /* port */ ptr = strchr(option, '='); if (ptr != NULL) { @@ -869,44 +941,61 @@ SetOption(option) } #ifdef deprecated } else if (strncmp(option, "pri", 3) == 0) { /* primary */ - _res.options |= RES_PRIMARY; + res.options |= RES_PRIMARY; } else if (strncmp(option, "nopri", 5) == 0) { - _res.options &= ~RES_PRIMARY; + res.options &= ~RES_PRIMARY; #endif } else if (strncmp(option, "q", 1) == 0 || /* querytype */ strncmp(option, "ty", 2) == 0) { /* type */ ptr = strchr(option, '='); if (ptr != NULL) { - sscanf(++ptr, "%s", type); + i = pickString(++ptr, type, sizeof type); + if (i == 0) { /* value too big or nothing there */ + fprintf(stderr, "*** invalid type value: %s\n", + ptr) ; + return(ERROR); + } + queryType = StringToType(type, queryType, stderr); } } else if (strncmp(option, "cl", 2) == 0) { /* query class */ ptr = strchr(option, '='); if (ptr != NULL) { - sscanf(++ptr, "%s", type); + i = pickString(++ptr, type, sizeof type); + if (i == 0) { /* value too big or nothing there */ + fprintf(stderr, "*** invalid class : %s\n", + ptr) ; + return(ERROR); + } + queryClass = StringToClass(type, queryClass, stderr); } } 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, "ret", 3) == 0) { /* retry */ ptr = strchr(option, '='); if (ptr != NULL) { sscanf(++ptr, "%d", &tmp); if (tmp >= 0) { - _res.retry = tmp; + res.retry = tmp; } } } else if (strncmp(option, "ro", 2) == 0) { /* root */ ptr = strchr(option, '='); if (ptr != NULL) { - sscanf(++ptr, "%s", rootServerName); + i = pickString(++ptr, rootServerName, sizeof rootServerName); + if (i == 0) { /* value too big or nothing there */ + fprintf(stderr, "*** invalid root server name : %s\n", + ptr) ; + return(ERROR) ; + } } } 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, "srchl", 5) == 0) { /* domain search list */ ptr = strchr(option, '='); if (ptr != NULL) { @@ -917,13 +1006,13 @@ SetOption(option) if (ptr != NULL) { sscanf(++ptr, "%d", &tmp); if (tmp >= 0) { - _res.retrans = tmp; + res.retrans = tmp; } } } 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 { fprintf(stderr, "*** Invalid option: %s\n", option); return(ERROR); @@ -935,45 +1024,45 @@ SetOption(option) /* * Fake a reinitialization when the domain is changed. */ -res_re_init() -{ +void +res_re_init(void) { register char *cp, **pp; int n; /* find components of local domain that might be searched */ - pp = _res.dnsrch; - *pp++ = _res.defdname; - for (cp = _res.defdname, n = 0; *cp; cp++) + pp = res.dnsrch; + *pp++ = res.defdname; + for (cp = res.defdname, n = 0; *cp; cp++) if (*cp == '.') n++; - cp = _res.defdname; - for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH; n--) { + cp = res.defdname; + for (; n >= LOCALDOMAINPARTS && pp < res.dnsrch + MAXDFLSRCH; n--) { cp = strchr(cp, '.'); *pp++ = ++cp; } *pp = 0; - _res.options |= RES_INIT; + res.options |= RES_INIT; } #define SRCHLIST_SEP '/' -res_dnsrch(cp) - register char *cp; -{ - register char **pp; +void +res_dnsrch(char *cp) { + char **pp; int n; - (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); - if ((cp = strchr(_res.defdname, '\n')) != NULL) + (void)strncpy(res.defdname, cp, sizeof(res.defdname) - 1); + res.defdname[sizeof(res.defdname) - 1] = '\0'; + if ((cp = strchr(res.defdname, '\n')) != NULL) *cp = '\0'; /* * Set search list to be blank-separated strings * on rest of line. */ - cp = _res.defdname; - pp = _res.dnsrch; + cp = res.defdname; + pp = res.dnsrch; *pp++ = cp; - for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { + for (n = 0; *cp && pp < res.dnsrch + MAXDNSRCH; cp++) { if (*cp == SRCHLIST_SEP) { *cp = '\0'; n = 1; @@ -1011,24 +1100,24 @@ ShowOptions() } printf("Set options:\n"); - printf(" %sdebug \t", (_res.options & RES_DEBUG) ? "" : "no"); - printf(" %sdefname\t", (_res.options & RES_DEFNAMES) ? "" : "no"); - printf(" %ssearch\t", (_res.options & RES_DNSRCH) ? "" : "no"); - printf(" %srecurse\n", (_res.options & RES_RECURSE) ? "" : "no"); - - printf(" %sd2\t\t", (_res.options & RES_DEBUG2) ? "" : "no"); - printf(" %svc\t\t", (_res.options & RES_USEVC) ? "" : "no"); - printf(" %signoretc\t", (_res.options & RES_IGNTC) ? "" : "no"); + printf(" %sdebug \t", (res.options & RES_DEBUG) ? "" : "no"); + printf(" %sdefname\t", (res.options & RES_DEFNAMES) ? "" : "no"); + printf(" %ssearch\t", (res.options & RES_DNSRCH) ? "" : "no"); + printf(" %srecurse\n", (res.options & RES_RECURSE) ? "" : "no"); + + printf(" %sd2\t\t", (res.options & RES_DEBUG2) ? "" : "no"); + printf(" %svc\t\t", (res.options & RES_USEVC) ? "" : "no"); + printf(" %signoretc\t", (res.options & RES_IGNTC) ? "" : "no"); printf(" port=%u\n", nsport); printf(" querytype=%s\t", p_type(queryType)); printf(" class=%s\t", p_class(queryClass)); - printf(" timeout=%d\t", _res.retrans); - printf(" retry=%d\n", _res.retry); + printf(" timeout=%d\t", res.retrans); + printf(" retry=%d\n", res.retry); printf(" root=%s\n", rootServerName); - printf(" domain=%s\n", _res.defdname); + printf(" domain=%s\n", res.defdname); - cp = _res.dnsrch; + cp = res.dnsrch; if (cp != NULL) { printf(" srchlist=%s", *cp); for (cp++; *cp; cp++) { @@ -1076,7 +1165,7 @@ static void CvtAddrToPtr(name) char *name; { - char *p; + const char *p; int ip[4]; struct in_addr addr; 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 #include + #include #include #include + +#include #include #include #include #include +#include #include #include +#include #include #include +#include #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); +} -- cgit v1.1