diff options
author | peter <peter@FreeBSD.org> | 1999-11-30 02:43:11 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1999-11-30 02:43:11 +0000 |
commit | 4ef23ce6957fc75fc005885496d605fed48213e1 (patch) | |
tree | 7828b08c74ef918938b1b853c98f0cb41edac52c /contrib/bind/bin/named | |
parent | 67e0f3ce71726dc4058c2f80a813341a59244dbd (diff) | |
download | FreeBSD-src-4ef23ce6957fc75fc005885496d605fed48213e1.zip FreeBSD-src-4ef23ce6957fc75fc005885496d605fed48213e1.tar.gz |
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)
Diffstat (limited to 'contrib/bind/bin/named')
46 files changed, 14884 insertions, 4000 deletions
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<<ZONE_BITS)-1) +#define CLASS_MAX ((1<<CLASS_BITS)-1) + /* * Hash table structures. */ @@ -101,17 +114,18 @@ struct databuf { * primary and secondary zones), * d_ttl is the time to live. */ - unsigned d_flags :7; /* see below */ + unsigned d_zone :ZONE_BITS; /* zone number or 0 for the cache */ + unsigned d_class :CLASS_BITS; /* class number (nonstandard limit) */ + unsigned d_flags :4; /* DB_F_{??????} */ + unsigned d_secure :2; /* DB_S_{??????} */ unsigned d_cred :3; /* DB_C_{??????} */ unsigned d_clev :6; - u_int16_t d_zone; /* zone number or 0 for the cache */ - int16_t d_class; /* class number */ + unsigned d_rcode :4; /* rcode for negative caching */ + unsigned d_mark :3; /* place to mark data */ int16_t d_type; /* type number */ int16_t d_size; /* size of data area */ u_int32_t d_rcnt; - unsigned d_rcode :4; /* rcode for negative caching */ - unsigned d_mark :12; /* place to mark data */ - u_int16_t d_nstime; /* NS response time, milliseconds */ + u_int16_t d_nstime; /* NS response time, milliseconds */ u_char d_data[sizeof(void*)]; /* dynamic (padded) */ }; #define DATASIZE(n) (sizeof(struct databuf) - sizeof(void*) + n) @@ -131,6 +145,7 @@ struct databuf { #define DB_F_HINT 0x01 /* databuf belongs to fcachetab */ #define DB_F_ACTIVE 0x02 /* databuf is linked into a cache */ #define DB_F_FREE 0x04 /* databuf has been freed */ +#define DB_F_LAME 0x08 /* databuf may refer to lame server */ /* * d_cred definitions @@ -141,6 +156,13 @@ struct databuf { #define DB_C_ADDITIONAL 1 /* additional data */ #define DB_C_CACHE 0 /* cache - worst */ +/* + * d_secure definitions + */ +#define DB_S_SECURE 2 /* secure (verified) data */ +#define DB_S_INSECURE 1 /* insecure data */ +#define DB_S_FAILED 0 /* data that failed a security check */ + struct namebuf { u_int n_hashval; /* hash value of _n_name */ struct namebuf *n_next; /* linked list */ @@ -162,6 +184,51 @@ struct hashbuf { #define HASHSHIFT 3 #define HASHMASK 0x1f +#define HASHROTATE(v) \ + (((v) << HASHSHIFT) | ((v) >> ((sizeof(v) * 8) - HASHSHIFT))) +#define HASHLOWER(c) ((isascii(c) && isupper(c)) ? tolower(c) : (c)) +#define HASHIMILATE(v,c) ((v) = (HASHROTATE(v)) + (HASHLOWER(c) & HASHMASK)) + +#define TSIG_BUF_SIZE 640 +#define TSIG_SIG_SIZE 20 + +struct tsig_record { + u_int8_t sig[TSIG_SIG_SIZE]; + struct dst_key *key; + int siglen; +}; + +struct sig_record { + u_int16_t sig_type_n; + u_int8_t sig_alg_n, sig_labels_n; + u_int32_t sig_ottl_n, sig_exp_n, sig_time_n; + u_int16_t sig_keyid_n; +}; + +/* This is the wire format size of "struct sig_record", i.e., no padding. */ +#define SIG_HDR_SIZE 18 + +struct dnode { + struct databuf *dp; + struct dnode *dn_next; + int line; + char *file; +}; + +typedef struct dnode * dlist; + +struct db_rrset { + dlist rr_list; + dlist rr_sigs; + char *rr_name; + int16_t rr_class; + int16_t rr_type; + struct db_rrset *rr_next; +}; +#define DBHASHSIZE(s) (sizeof(struct hashbuf) + \ + (s-1) * sizeof(struct db_rrset *)) + +#define SIG_COVERS(dp) (ns_get16(dp->d_data)) /* * Flags to updatedb @@ -172,6 +239,8 @@ struct hashbuf { #define DB_NOTAUTH 0x08 /* must not update authoritative data */ #define DB_NOHINTS 0x10 /* don't reflect update in fcachetab */ #define DB_PRIMING 0x20 /* is this update the result of priming? */ +#define DB_MERGE 0x40 /* make no control on rr in db_update (for ixfr) */ +#define DB_REPLACE 0x80 /* replace data if it exists */ #define DB_Z_CACHE 0 /* cache-zone-only db_dump() */ #define DB_Z_ALL 65535 /* normal db_dump() */ @@ -194,6 +263,8 @@ struct hashbuf { #ifdef BIND_UPDATE #define SERIAL (-11) #endif +#define CNAMEANDOTHER (-12) +#define DNSSECFAIL (-13) /* db_set_update */ /* * getnum() options @@ -203,13 +274,18 @@ struct hashbuf { #define GETNUM_SCALED 0x02 /* permit "k", "m" suffixes, scale result */ /* + * db_load() options + */ +#define ISNOTIXFR 0 +#define ISIXFR 1 +#define ISAXFRIXFR 2 + +/* * Database access abstractions. */ #define foreach_rr(dp, np, ty, cl, zn) \ for ((dp) = (np)->n_data; (dp) != NULL; (dp) = (dp)->d_next) \ - if ((cl) != C_ANY && (cl) != (dp)->d_class) \ - continue; \ - else if ((ty) != T_ANY && (ty) != (dp)->d_type) \ + if (!match(dp, (cl), (ty))) \ continue; \ else if (((zn) == DB_Z_CACHE) \ ? stale(dp) \ diff --git a/contrib/bind/bin/named/db_dump.c b/contrib/bind/bin/named/db_dump.c index 9c15af3..75a59b7 100644 --- a/contrib/bind/bin/named/db_dump.c +++ b/contrib/bind/bin/named/db_dump.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)db_dump.c 4.33 (Berkeley) 3/3/91"; -static char rcsid[] = "$Id: db_dump.c,v 8.24 1998/02/13 19:49:09 halley Exp $"; +static const char sccsid[] = "@(#)db_dump.c 4.33 (Berkeley) 3/3/91"; +static const char rcsid[] = "$Id: db_dump.c,v 8.40 1999/10/13 16:39:01 vixie Exp $"; #endif /* not lint */ /* @@ -82,7 +82,7 @@ static char rcsid[] = "$Id: db_dump.c,v 8.24 1998/02/13 19:49:09 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -104,6 +104,7 @@ static char rcsid[] = "$Id: db_dump.c,v 8.24 1998/02/13 19:49:09 halley Exp $"; #include <sys/param.h> #include <sys/stat.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -141,7 +142,7 @@ doadump() return; gettime(&tt); fprintf(fp, "; Dumped at %s", ctimel(tt.tv_sec)); - if (zones && nzones) + if (zones != NULL && nzones != 0) zt_dump(fp); fputs( "; Note: Cr=(auth,answer,addtnl,cache) tag only shown for non-auth RR's\n", @@ -164,7 +165,7 @@ zt_dump(FILE *fp) { struct zoneinfo *zp; fprintf(fp, ";; ++zone table++\n"); - for (zp = &zones[1]; zp < &zones[nzones]; zp++) { + for (zp = &zones[0]; zp < &zones[nzones]; zp++) { char *pre, buf[64]; u_int cnt; @@ -183,8 +184,8 @@ zt_dump(FILE *fp) { fprintf(fp, ";\trefresh=%u, retry=%u, expire=%u, minimum=%u\n", zp->z_refresh, zp->z_retry, zp->z_expire, zp->z_minimum); - fprintf(fp, ";\tftime=%lu, xaddr=[%s], state=%04x, pid=%d\n", - (u_long)zp->z_ftime, inet_ntoa(zp->z_xaddr), + fprintf(fp, ";\tftime=%lu, xaddrcnt=%d, state=%04x, pid=%d\n", + (u_long)zp->z_ftime, zp->z_xaddrcnt, zp->z_flags, (int)zp->z_xferpid); sprintf(buf, ";\tz_addr[%d]: ", zp->z_addrcnt); pre = buf; @@ -195,7 +196,7 @@ zt_dump(FILE *fp) { if (zp->z_addrcnt) fputc('\n', fp); if (zp->z_axfr_src.s_addr != 0) - fprintf(fp, "; update source [%s]\n", + fprintf(fp, ";\tupdate source [%s]\n", inet_ntoa(zp->z_axfr_src)); } fprintf(fp, ";; --zone table--\n"); @@ -209,13 +210,12 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) { struct namebuf **npp, **nppend; char dname[MAXDNAME]; u_int32_t n; - u_int32_t addr; int j, i, found_data, tab, printed_origin; u_char *cp, *end; const char *proto, *sep; int16_t type; u_int16_t keyflags; - u_char *sigdata; + u_char *sigdata, *certdata; u_char *savecp; char temp_base64[NS_MD5RSA_MAX_BASE64]; @@ -275,11 +275,11 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) { else fprintf(fp, "%d\t", (int)(dp->d_ttl - tt.tv_sec)); - } else if (dp->d_ttl != USE_MINIMUM && - dp->d_ttl != zones[dp->d_zone].z_minimum) + } else if (dp->d_ttl != USE_MINIMUM) fprintf(fp, "%d\t", (int)dp->d_ttl); - else if (tab) - (void) putc('\t', fp); + else + fprintf(fp, "%d\t", + zones[dp->d_zone].z_minimum); fprintf(fp, "%s\t%s\t", p_class(dp->d_class), p_type(dp->d_type)); @@ -538,9 +538,8 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) { fprintf(fp, "%s ", p_type(n)); /* Algorithm id (8-bit decimal) */ fprintf(fp, "%d ", *cp++); - /* Labels (8-bit decimal) (not saved in file) */ - /* FIXME -- check value and print err if bad */ - cp++; + /* Labels (8-bit decimal) */ + fprintf(fp, "%d ", *cp++); /* OTTL (u_long) */ NS_GET32(n, cp); fprintf(fp, "%u ", n); @@ -573,10 +572,28 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) { i = 8 * (dp->d_size - n); /* How many bits? */ for (n = 0; n < (u_int32_t)i; n++) { if (NS_NXT_BIT_ISSET(n, cp)) - fprintf(fp," %s",__p_type(n)); + fprintf(fp," %s", p_type(n)); } break; + case ns_t_cert: + certdata = cp; + NS_GET16(n,cp); + fprintf(fp, "%d ", n); /* cert type */ + + NS_GET16(n,cp); + fprintf(fp, "%d %d ", n, *cp++); /* tag & alg */ + + /* Certificate (base64 of any length) */ + i = b64_ntop(cp, + dp->d_size - (cp - certdata), + temp_base64, sizeof(temp_base64)); + if (i < 0) + fprintf(fp, "; BAD BASE64"); + else + fprintf(fp, "%s", temp_base64); + break; + default: fprintf(fp, "%s?d_type=%d?", sep, dp->d_type); @@ -591,6 +608,17 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) { sep, dp->d_clev); sep = " "; } + if ((dp->d_flags & DB_F_LAME) != 0) { + time_t when; + getname(np, dname, sizeof(dname)); + when = db_lame_find(dname, dp); + if (when != 0 && when > tt.tv_sec) { + fprintf(fp, "%sLAME=%d", + sep, when - tt.tv_sec); + sep = " "; + } + } + eoln: if (dp->d_ns != NULL){ fprintf(fp, "%s[%s]", diff --git a/contrib/bind/bin/named/db_func.h b/contrib/bind/bin/named/db_func.h index 2d4c05b..9ba5299 100644 --- a/contrib/bind/bin/named/db_func.h +++ b/contrib/bind/bin/named/db_func.h @@ -1,4 +1,5 @@ -/* Copyright (c) 1985, 1990 +/* + * Copyright (c) 1985, 1990 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,7 +31,8 @@ * SUCH DAMAGE. */ -/* Portions Copyright (c) 1993 by Digital Equipment Corporation. +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -49,7 +51,8 @@ * SOFTWARE. */ -/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium. +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -65,9 +68,29 @@ * SOFTWARE. */ +/* + * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Check Point Software Technologies Incorporated not be used + * in advertising or publicity pertaining to distribution of the document + * or software without specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + /* db_proc.h - prototypes for functions in db_*.c * - * $Id: db_func.h,v 8.22 1997/12/04 06:47:00 halley Exp $ + * $Id: db_func.h,v 8.40 1999/10/07 08:24:06 vixie Exp $ */ /* ++from db_update.c++ */ @@ -96,19 +119,30 @@ extern void doadump(void); /* --from db_dump.c-- */ /* ++from db_load.c++ */ +extern int makename_ok(char *name, const char *origin, int class, + struct zoneinfo *zp, + enum transport transport, + enum context context, + const char *owner, const char *filename, + int lineno, int size); extern void endline(FILE *); extern int getword(char *, size_t, FILE *, int), + getttl(FILE *, const char *, int, u_int32_t *, int *), getnum(FILE *, const char *, int), - db_load(const char *, const char *, - struct zoneinfo *, const char *); + db_load(const char *, const char *, struct zoneinfo *, + const char *, int); extern int getnonblank(FILE *, const char *), getservices(int, char *, FILE *, const char *); extern char getprotocol(FILE *, const char *); extern int makename(char *, const char *, int); -#ifdef BIND_NOTIFY -extern void notify_after_load(evContext, void *, const void *), - db_cancel_pending_notifies(void); -#endif +extern void db_err(int, char *, int, const char *, int); +extern int parse_sec_rdata(char *inp, int inp_len, int inp_full, + u_char *data, int data_len, + FILE *fp, struct zoneinfo *zp, + char *domain, u_int32_t ttl, + int type, enum context context, + enum transport transport, + char **errmsg); /* --from db_load.c-- */ /* ++from db_glue.c++ */ @@ -119,10 +153,8 @@ extern void buildservicelist(void), getname(struct namebuf *, char *, int); extern int servicenumber(const char *), protocolnumber(const char *), - get_class(const char *), - samedomain(const char *, const char *); -extern u_int dhash(const u_char *, int), - nhash(const char *); + get_class(const char *); +extern u_int nhash(const char *); extern const char *protocolname(int), *servicename(u_int16_t, const char *); #ifndef BSD @@ -137,15 +169,45 @@ extern struct namebuf *rm_name(struct namebuf *, struct namebuf *); extern void rm_hash(struct hashbuf *); extern void db_freedata(struct databuf *); +extern void db_lame_add(char *zone, char *server, time_t when); +extern time_t db_lame_find(char *zone, struct databuf *dp); +extern void db_lame_clean(void); +extern void db_lame_destroy(void); /* --from db_glue.c-- */ /* ++from db_lookup.c++ */ extern struct namebuf *nlookup(const char *, struct hashbuf **, const char **, int); extern struct namebuf *np_parent __P((struct namebuf *)); -extern int match(struct databuf *, int, int); +extern int match(struct databuf *, int, int), + nxtmatch(const char *, struct databuf *, + struct databuf *), + rrmatch(const char *, struct databuf *, + struct databuf *); /* --from db_lookup.c-- */ -/* ++from db_dict.c++ */ -int dict_lookup(const char *, int, int); -/* --from db_dict.c-- */ +/* ++from db_ixfr.c++ */ +struct ns_updrec * ixfr_get_change_list(struct zoneinfo *, u_int32_t, + u_int32_t); +int ixfr_have_log(struct zoneinfo *, u_int32_t, + u_int32_t); +/* --from db_ixfr.c++ */ + +/* ++from db_sec.c++ */ +int add_trusted_key(const char *name, const int flags, + const int proto, const int alg, + const char *str); +int db_set_update(char *name, struct databuf *dp, + void **state, int flags, + struct hashbuf **htp, + struct sockaddr_in from, + int *rrcount, int line, + const char *file); +/* --from db_sec.c-- */ +/* ++from db_tsig.c++ */ +char * tsig_alg_name(int value); +int tsig_alg_value(char *name); +struct dst_key * tsig_key_from_addr(struct in_addr addr); +struct tsig_record * new_tsig(struct dst_key *key, u_char *sig, int siglen); +void free_tsig(struct tsig_record *tsig); +/* --from db_tsig.c-- */ diff --git a/contrib/bind/bin/named/db_glob.h b/contrib/bind/bin/named/db_glob.h index 79d915d..3d11739 100644 --- a/contrib/bind/bin/named/db_glob.h +++ b/contrib/bind/bin/named/db_glob.h @@ -1,9 +1,10 @@ /* * from db.h 4.16 (Berkeley) 6/1/90 - * $Id: db_glob.h,v 8.8 1997/06/09 17:46:51 halley Exp $ + * $Id: db_glob.h,v 8.12 1999/08/08 21:10:01 vixie Exp $ */ -/* Copyright (c) 1985, 1990 +/* + * Copyright (c) 1985, 1990 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,7 +36,8 @@ * SUCH DAMAGE. */ -/* Portions Copyright (c) 1993 by Digital Equipment Corporation. +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -54,7 +56,8 @@ * SOFTWARE. */ -/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium. +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -75,20 +78,26 @@ */ /* ONE_WEEK maximum ttl */ -DECL u_int max_cache_ttl INIT(7*24*60*60); +DECL u_int max_cache_ttl INIT(7*24*60*60); /* no minimum ttl */ -DECL u_int min_cache_ttl INIT(0); +DECL u_int min_cache_ttl INIT(0); /* current line number */ -DECL int lineno; +DECL int lineno INIT(0); /* root hash table */ -DECL struct hashbuf *hashtab INIT(NULL); +DECL struct hashbuf *hashtab INIT(NULL); /* hash table of cache read from file */ -DECL struct hashbuf *fcachetab INIT(NULL); +DECL struct hashbuf *fcachetab INIT(NULL); + + /* state of ns_reload() and ns_reconfig(). */ +DECL int reloading INIT(0); +DECL int reconfiging INIT(0); -#ifdef FORCED_RELOAD -DECL int reloading INIT(0); -#endif /* FORCED_RELOAD */ +DECL const int hashsizes[] +#ifdef MAIN_PROGRAM + = { 2, 11, 113, 337, 977, 2053, 4073, 8011, 16001, 99887, 0 } +#endif + ; diff --git a/contrib/bind/bin/named/db_glue.c b/contrib/bind/bin/named/db_glue.c index bc6aed4..f1fae69 100644 --- a/contrib/bind/bin/named/db_glue.c +++ b/contrib/bind/bin/named/db_glue.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)db_glue.c 4.4 (Berkeley) 6/1/90"; -static char rcsid[] = "$Id: db_glue.c,v 8.27 1998/02/14 00:41:39 halley Exp $"; +static const char sccsid[] = "@(#)db_glue.c 4.4 (Berkeley) 6/1/90"; +static const char rcsid[] = "$Id: db_glue.c,v 8.39 1999/10/15 19:48:57 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: db_glue.c,v 8.27 1998/02/14 00:41:39 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -79,6 +79,8 @@ static char rcsid[] = "$Id: db_glue.c,v 8.27 1998/02/14 00:41:39 halley Exp $"; #include <sys/uio.h> #include <sys/param.h> #include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -147,6 +149,7 @@ destroyservicelist() { freestr(slp->proto); memput(slp, sizeof *slp); } + servicelist = NULL; } void @@ -183,6 +186,7 @@ destroyprotolist() { freestr(plp->name); memput(plp, sizeof *plp); } + protolist = NULL; } static int @@ -451,29 +455,11 @@ getname(struct namebuf *np, char *buf, int buflen) { *cp = '\0'; } -/* - * Compute hash value from data. - */ -u_int -dhash(const u_char *dp, int dlen) { - u_char *cp; - u_int hval; - int n; - - n = dlen; - if (n > 8) - n = 8; - hval = 0; - while (--n >= 0) { - hval <<= 1; - hval += *dp++; - } - return (hval % INVHASHSZ); -} - /* u_int * nhash(name) * compute hash for this name and return it; ignore case differences + * note: + * this logic is intended to produce the same result as nlookup()'s. */ u_int nhash(const char *name) { @@ -481,136 +467,190 @@ nhash(const char *name) { u_int hval; hval = 0; - while ((ch = (u_char)*name++) != (u_char)'\0') { - if (isascii(ch) && isupper(ch)) - ch = tolower(ch); - hval <<= 1; - hval += ch; - } - return (hval % INVHASHSZ); + while ((ch = (u_char)*name++) != (u_char)'\0') + HASHIMILATE(hval, ch); + return (hval); } -/* -** SAMEDOMAIN -- Check whether a name belongs to a domain -** ------------------------------------------------------ -** -** Returns: -** TRUE if the given name lies in the domain. -** FALSE otherwise. -** -** Trailing dots are first removed from name and domain. -** Always compare complete subdomains, not only whether the -** domain name is the trailing string of the given name. -** -** "host.foobar.top" lies in "foobar.top" and in "top" and in "" -** but NOT in "bar.top" -*/ +void +db_freedata(struct databuf *dp) { + int bytes = DATASIZE(dp->d_size); -int -samedomain(const char *a, const char *b) { - size_t la, lb; - int diff, i, escaped; - const char *cp; - - la = strlen(a); - lb = strlen(b); - - /* ignore a trailing label separator (i.e. an unescaped dot) in 'a' */ - if (la && a[la-1] == '.') { - escaped = 0; - /* note this loop doesn't get executed if la==1 */ - for (i = la - 2; i >= 0; i--) - if (a[i] == '\\') { - if (escaped) - escaped = 0; - else - escaped = 1; - } else { - break; - } - if (!escaped) - la--; - } - /* ignore a trailing label separator (i.e. an unescaped dot) in 'b' */ - if (lb && b[lb-1] == '.') { - escaped = 0; - /* note this loop doesn't get executed if lb==1 */ - for (i = lb - 2; i >= 0; i--) - if (b[i] == '\\') { - if (escaped) - escaped = 0; - else - escaped = 1; - } else { - break; - } - if (!escaped) - lb--; - } + if (dp->d_rcnt != 0) + panic("db_freedata: d_rcnt != 0", NULL); + if ((dp->d_flags & (DB_F_ACTIVE|DB_F_FREE)) != 0) + panic("db_freedata: %s set", + (dp->d_flags & DB_F_FREE) != 0 ? "DB_F_FREE" : + "DB_F_ACTIVE"); + if (dp->d_next != NULL) + panic("db_free: d_next != NULL", NULL); + dp->d_flags |= DB_F_FREE; + memput(dp, bytes); +} - /* lb==0 means 'b' is the root domain, so 'a' must be in 'b'. */ - if (lb == 0) - return (1); +struct lame_hash { + struct lame_hash *next; + char *zone; + char *server; + time_t when; + unsigned int hval; +} **lame_hash = NULL; - /* 'b' longer than 'a' means 'a' can't be in 'b'. */ - if (lb > la) - return (0); +static int lame_hash_size = 0; +static int lame_hash_cnt = 0; - /* We use strncasecmp because we might be trying to - * ignore a trailing dot. */ - if (lb == la) - return (strncasecmp(a, b, lb) == 0); +void +db_lame_add(char *zone, char *server, time_t when) { + unsigned int hval = nhash(zone); + struct lame_hash *last, *this; + struct lame_hash **new; + int n; + int newsize; + + db_lame_clean(); + + /* grow / initalise hash table */ + if (lame_hash_cnt >= lame_hash_size) { + if (lame_hash_size == 0) + newsize = hashsizes[0]; + else { + for (n = 0; (newsize = hashsizes[n++]) != 0; (void)NULL) + if (lame_hash_size == newsize) { + newsize = hashsizes[n]; + break; + } + if (newsize == 0) + newsize = lame_hash_size * 2 + 1; + } + new = memget(newsize * sizeof this); + if (new == NULL) + return; + memset(new, 0, newsize * sizeof this); + for (n = 0 ; n < lame_hash_size; n++) { + this = lame_hash[n]; + while (this) { + last = this; + this = this->next; + last->next = new[hval%newsize]; + new[hval%newsize] = last; + } + } + if (lame_hash != NULL) + memput(lame_hash, lame_hash_size * sizeof this); + lame_hash = new; + lame_hash_size = newsize; + } - /* Ok, we know la > lb. */ + last = NULL; + this = lame_hash[hval%lame_hash_size]; + while (this) { + if ((ns_samename(this->server, server) == 1) && + (ns_samename(this->zone, zone) == 1)) { + this->when = when; + return; + } + last = this; + this = this->next; + } + this = memget(sizeof *this); + if (this == NULL) + return; + this->server = savestr(server, 0); + this->zone = savestr(zone, 0); + if (this->server == NULL || this->zone == NULL) { + if (this->server != NULL) + freestr(this->server); + if (this->zone != NULL) + freestr(this->zone); + memput(this, sizeof *this); + return; + } + this->when = when; + this->hval = hval; + this->next = NULL; + if (last != NULL) + last->next = this; + else + lame_hash[hval%lame_hash_size] = this; + lame_hash_cnt++; +} - diff = la - lb; +time_t +db_lame_find(char *zone, struct databuf *dp) { + unsigned int hval = nhash(zone); + struct lame_hash *this; - /* If 'a' is only 1 character longer than 'b', then it can't be - a subdomain of 'b' (because of the need for the '.' label - separator). */ - if (diff < 2) + if (lame_hash_size == 0) { + /* db_lame_destroy() must have been called. */ + dp->d_flags &= ~DB_F_LAME; return (0); + } - /* If the character before the last 'lb' characters of 'b' - isn't '.', then it can't be a match (this lets us avoid - having "foobar.com" match "bar.com"). */ - if (a[diff-1] != '.') - return (0); + db_lame_clean(); /* Remove expired record so that we can + * clear DB_F_LAME when there are no + * additions. */ - /* We're not sure about that '.', however. It could be escaped - and thus not a really a label separator. */ - escaped=0; - for (i = diff-2; i >= 0; i--) - if (a[i] == '\\') { - if (escaped) - escaped = 0; - else - escaped = 1; - } - else - break; - if (escaped) - return (0); - - /* We use strncasecmp because we might be trying to - * ignore trailing dots. */ - cp = a + diff; - return (strncasecmp(cp, b, lb) == 0); + this = lame_hash[hval % lame_hash_size]; + while (this) { + if ((ns_samename(this->server, (char*)dp->d_data) == 1) && + (ns_samename(this->zone, zone) == 1)) + return (this->when); + this = this->next; + } + dp->d_flags &= ~DB_F_LAME; + return (0); } void -db_freedata(struct databuf *dp) { - int bytes = (dp->d_type == T_NS) ? - DATASIZE(dp->d_size)+INT32SZ : DATASIZE(dp->d_size); +db_lame_clean(void) { + int i; + struct lame_hash *last, *this; + + for (i = 0 ; i < lame_hash_size; i++) { + last = NULL; + this = lame_hash[i]; + while (this != NULL) { + if (this->when < tt.tv_sec) { + freestr(this->zone); + freestr(this->server); + if (last != NULL) { + last->next = this->next; + memput(this, sizeof *this); + this = last->next; + } else { + lame_hash[i] = this->next; + memput(this, sizeof *this); + this = lame_hash[i]; + } + lame_hash_cnt--; + } else { + last = this; + this = this->next; + } + } + } +} - if (dp->d_rcnt != 0) - panic("db_freedata: d_rcnt != 0", NULL); - if ((dp->d_flags & (DB_F_ACTIVE|DB_F_FREE)) != 0) - panic("db_freedata: %s set", - (dp->d_flags & DB_F_FREE) != 0 ? "DB_F_FREE" : - "DB_F_ACTIVE"); - if (dp->d_next != NULL) - panic("db_free: d_next != NULL", NULL); - dp->d_flags |= DB_F_FREE; - memput(dp, bytes); +void +db_lame_destroy(void) { + int i; + struct lame_hash *last, *this; + + if (lame_hash_size == 0) + return; + + for (i = 0 ; i < lame_hash_size; i++) { + this = lame_hash[i]; + while (this != NULL) { + last = this; + this = this->next; + freestr(last->zone); + freestr(last->server); + memput(last, sizeof *this); + } + } + memput(lame_hash, lame_hash_size * sizeof this); + lame_hash_cnt = 0; + lame_hash_size = 0; + lame_hash = NULL; } diff --git a/contrib/bind/bin/named/db_ixfr.c b/contrib/bind/bin/named/db_ixfr.c new file mode 100644 index 0000000..a009f4d --- /dev/null +++ b/contrib/bind/bin/named/db_ixfr.c @@ -0,0 +1,861 @@ +#if !defined(lint) && !defined(SABER) +static char rcsid[] = "$Id: db_ixfr.c,v 8.18 1999/10/15 19:48:57 vixie Exp $"; +#endif /* not lint */ + +/* + * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Check Point Software Technologies Incorporated not be used + * in advertising or publicity pertaining to distribution of the document + * or software without specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Manage ixfr transaction log + */ + +#include "port_before.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <resolv.h> +#include <res_update.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <time.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> + +#include "port_after.h" + +#include "named.h" + +#define DBIXFR_ERROR -1 +#define DBIXFR_FOUND_RR 2 +#define DBIXFR_END 3 + +static int ixfr_getrr(struct zoneinfo *, FILE *, const char *, char *, + ns_updrec **, u_int32_t *, u_int32_t *); + +ns_updrec * +ixfr_get_change_list(struct zoneinfo *zp, + u_int32_t from_serial, u_int32_t to_serial) +{ + FILE * fp; + u_int32_t old_serial, new_serial; + char origin[MAXDNAME]; + struct namebuf *np, *listnp, *finlistnp; + LIST(ns_updrec) listuprec; + int ret, mode; + ns_updrec *uprec; + + if (SEQ_GT(from_serial, to_serial)) + return (NULL); + listnp = finlistnp = NULL; + INIT_LIST(listuprec); + if ((fp = fopen(zp->z_ixfr_base, "r")) == NULL) { + ns_warning(ns_log_db, "%s: %s", + zp->z_ixfr_base, strerror(errno)); + return (NULL); + } + strcpy(origin, zp->z_origin); + lineno = 1; + np = NULL; + mode = 0; + old_serial = new_serial = 0; + for (;;) { + ret = ixfr_getrr(zp, fp, zp->z_ixfr_base, origin, &uprec, + &old_serial, &new_serial); + switch (ret) { + case DBIXFR_ERROR: + (void) my_fclose(fp); + ns_warning(ns_log_db, "Logical error in %s line %d", + zp->z_ixfr_base, lineno); + return (NULL); + case DBIXFR_FOUND_RR: + if (EMPTY(listuprec)) { + /* skip updates prior to the one we want */ + if (uprec->r_zone != from_serial) { + while (uprec != NULL) { + ns_updrec *prev; + + if (uprec->r_dp != NULL) + db_freedata(uprec->r_dp); + uprec->r_dp = NULL; + prev = PREV(uprec, r_link); + res_freeupdrec(uprec); + uprec = prev; + } + break; + } + } + APPEND(listuprec, uprec, r_link); + /* continue; */ + break; + case DBIXFR_END: + (void) my_fclose(fp); + return (HEAD(listuprec)); + default: + (void) my_fclose(fp); + return (NULL); + } + } +} + +/* + * int ixfr_have_log(struct zoneinfo *zp,u_int32_t from_serial, + * u_int32_t to_serial) + * + * verify that ixfr transaction log contains changes + * from from_serial to to_serial + * + * returns: + * 0 = serial number is up to date + * 1 = transision is possible + * -1 = error while opening the ixfr transaction log + * -2 = error in parameters + * -3 = logical error in the history file + */ +int +ixfr_have_log(struct zoneinfo *zp, u_int32_t from_serial, u_int32_t to_serial) +{ + FILE *fp; + u_int32_t old_serial = 0, new_serial = 0; + char buf[BUFSIZ]; + char *cp; + struct stat st; + int nonempty_lineno = -1, prev_pktdone = 0, cont = 0, + inside_next = 0; + int err; + int id, rcode = NOERROR; + + if (SEQ_GT(from_serial, to_serial)) + return (-2); + if (from_serial == to_serial) + return (0); + /* If there is no log file, just return. */ + if (zp->z_ixfr_base == NULL || zp->z_updatelog == NULL) + return (-1); + if (stat(zp->z_ixfr_base, &st) < 0) { + if (errno != ENOENT) + ns_error(ns_log_db, + "unexpected stat(%s) failure: %s", + zp->z_ixfr_base, strerror(errno)); + return (-1); + } + if ((fp = fopen(zp->z_ixfr_base, "r")) == NULL) { + ns_warning(ns_log_db, "%s: %s", + zp->z_ixfr_base, strerror(errno)); + return (-1); + } + if (fgets(buf, sizeof(buf), fp) == NULL) { + ns_error(ns_log_update, "fgets() from %s failed: %s", + zp->z_updatelog, strerror(errno)); + fclose(fp); + return (-1); + } + if (strcmp(buf, LogSignature) != 0) { + ns_error(ns_log_update, "invalid log file %s", + zp->z_updatelog); + fclose(fp); + return (-3); + } + lineno = 1; + for (;;) { + if (getword(buf, sizeof buf, fp, 0)) { + nonempty_lineno = lineno; + } else { + if (lineno == (nonempty_lineno + 1)) + continue; + inside_next = 0; + prev_pktdone = 1; + cont = 1; + } + if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") || + !strcasecmp(buf, "[IXFR_UPDATE]")) { + err = 0; + rcode = NOERROR; + cp = fgets(buf, sizeof buf, fp); + if (cp != NULL) + lineno++; + if (cp == NULL || !sscanf((char *) cp, "id %d", &id)) + id = -1; + inside_next = 1; + prev_pktdone = 1; + cont = 1; + } else if (!strcasecmp(buf, "serial")) { + cp = fgets(buf, sizeof buf, fp); + if (cp != NULL) + lineno++; + if (sscanf((char *) cp, "%u", &old_serial)) { + if (from_serial >= old_serial) { + fclose(fp); + return (1); + } else { + fclose(fp); + return (-1); + } + } + prev_pktdone = 1; + cont = 1; + } else if (!strcasecmp(buf, "[INCR_SERIAL]")) { + /* XXXRTH not enough error checking here */ + cp = fgets(buf, sizeof buf, fp); + if (cp != NULL) + lineno++; + if (cp == NULL || + sscanf((char *) cp, "from %u to %u", + &old_serial, &new_serial) != 2) { + fclose(fp); + return (-3); + } else if (from_serial >= old_serial) { + fclose(fp); + return (1); + } + fclose(fp); + return (-1); + } + if (prev_pktdone) { + prev_pktdone = 0; + if (feof(fp)) + break; + } + } + fclose(fp); + return (0); +} + +/* from db_load.c */ + +static struct map m_section[] = { + {"zone", S_ZONE}, + {"prereq", S_PREREQ}, + {"update", S_UPDATE}, + {"reserved", S_ADDT}, +}; +#define M_SECTION_CNT (sizeof(m_section) / sizeof(struct map)) + +/* from ns_req.c */ + +static struct map m_opcode[] = { + {"nxdomain", NXDOMAIN}, + {"yxdomain", YXDOMAIN}, + {"nxrrset", NXRRSET}, + {"yxrrset", YXRRSET}, + {"delete", DELETE}, + {"add", ADD}, +}; +#define M_OPCODE_CNT (sizeof(m_opcode) / sizeof(struct map)) + +/* XXXRTH workaround map difficulties */ +#define M_CLASS_CNT m_class_cnt +#define M_TYPE_CNT m_type_cnt + +/* + * int + * ixfr_getrr(struct zoneinfo *zp, FILE *fp, + * const char *filename, char *origin, struct namebuf **np, + * u_int32_t *old_serial, u_int32_t *new_serial) + * + * read a line from the historic of a zone. + * + * returns: + * + * DBIXFR_ERROR = an error occured + * DBIXFR_FOUND_RR = a rr encountered + * DBIXFR_END = end of file + */ +static int +ixfr_getrr(struct zoneinfo *zp, FILE *fp, const char *filename, char *origin, + ns_updrec **uprec, u_int32_t *old_serial, + u_int32_t *new_serial) +{ + static int read_soa, read_ns, rrcount; + + char data[MAXDATA], dnbuf[MAXDNAME], sclass[3]; + const char *errtype = "Database"; + char *dname, *cp, *cp1; + char buf[MAXDATA]; + u_int32_t serial, ttl; + int nonempty_lineno = -1, prev_pktdone = 0, cont = 0, + inside_next = 0; + int id, rcode = NOERROR; + int i, c, section, opcode, matches, zonenum, err, multiline; + int type, class; + u_int32_t n; + enum transport transport; + struct map *mp; + int zonelist[MAXDNAME]; + struct databuf *dp; + struct in_addr ina; + struct sockaddr_in empty_from; + int datasize; + ns_updque listuprec; + ns_updrec * rrecp; + u_long l; + +#define ERRTO(msg) if (1) { errtype = msg; goto err; } else (void)NULL + + err = 0; + transport = primary_trans; + lineno = 1; + INIT_LIST(listuprec); + for (;;) { + if (!getword(buf, sizeof buf, fp, 0)) { + if (lineno == (nonempty_lineno + 1) && !(feof(fp))) { + /* + * End of a nonempty line inside an update + * packet or not inside an update packet. + */ + continue; + } + /* + * Empty line or EOF. + * + * Marks completion of current update packet. + */ + inside_next = 0; + prev_pktdone = 1; + cont = 1; + } else { + nonempty_lineno = lineno; + } + + if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") || + !strcasecmp(buf, "[IXFR_UPDATE]")) { + err = 0; + rcode = NOERROR; + cp = fgets(buf, sizeof buf, fp); + if (cp != NULL) + lineno++; + if (cp == NULL || !sscanf((char *) cp, "id %d", &id)) + id = -1; + inside_next = 1; + prev_pktdone = 1; + cont = 1; + } else if (!strcasecmp(buf, "[INCR_SERIAL]")) { + /* XXXRTH not enough error checking here */ + cp = fgets(buf, sizeof buf, fp); + if (cp != NULL) + lineno++; + if (cp == NULL || + sscanf((char *) cp, "from %u to %u", + old_serial, new_serial) != 2) { + ns_error(ns_log_update, + "incr_serial problem with %s", + zp->z_updatelog); + } else { + serial = get_serial(zp); + } + cont = 1; + } else if (!strcasecmp(buf, "[END_DELTA]")) { + prev_pktdone = 1; + cont = 1; + lineno++; + } + if (prev_pktdone) { + if (!EMPTY(listuprec)) { + n++; + *uprec = TAIL(listuprec); + return (DBIXFR_FOUND_RR); + } + prev_pktdone = 0; + if (feof(fp)) + break; + } + if (cont) { + cont = 0; + continue; + } + if (!inside_next) + continue; + /* + * inside the same update packet, continue accumulating + * records. + */ + section = -1; + n = strlen(buf); + if (buf[n - 1] == ':') + buf[--n] = '\0'; + for (mp = m_section; mp < m_section + M_SECTION_CNT; mp++) + if (!strcasecmp(buf, mp->token)) { + section = mp->val; + break; + } + ttl = 0; + type = -1; + class = zp->z_class; + n = 0; + data[0] = '\0'; + switch (section) { + case S_ZONE: + cp = fgets(buf, sizeof buf, fp); + if (!cp) + *buf = '\0'; + n = sscanf(cp, "origin %s class %s serial %ul", + origin, sclass, &serial); + if (n != 3 || ns_samename(origin, zp->z_origin) != 1) + err++; + if (cp) + lineno++; + if (!err && inside_next) { + int success; + + dname = origin; + type = T_SOA; + class = sym_ston(__p_class_syms, sclass, + &success); + if (!success) { + err++; + break; + } + matches = findzone(dname, class, 0, + zonelist, MAXDNAME); + if (matches) + zonenum = zonelist[0]; + else + err++; + } + break; + case S_PREREQ: + case S_UPDATE: + /* Operation code. */ + if (!getword(buf, sizeof buf, fp, 0)) { + err++; + break; + } + opcode = -1; + if (buf[0] == '{') { + n = strlen(buf); + for (i = 0; (u_int32_t) i < n; i++) + buf[i] = buf[i + 1]; + if (buf[n - 2] == '}') + buf[n - 2] = '\0'; + } + for (mp = m_opcode; mp < m_opcode + M_OPCODE_CNT; mp++) + if (!strcasecmp(buf, mp->token)) { + opcode = mp->val; + break; + } + if (opcode == -1) { + err++; + break; + } + /* Owner's domain name. */ + if (!getword((char *) dnbuf, sizeof dnbuf, fp, 0)) { + err++; + break; + } + n = strlen((char *) dnbuf) - 1; + if (dnbuf[n] == '.') + dnbuf[n] = '\0'; + dname = dnbuf; + ttl = 0; + type = -1; + class = zp->z_class; + n = 0; + data[0] = '\0'; + (void) getword(buf, sizeof buf, fp, 1); + if (isdigit(buf[0])) { /* ttl */ + if (ns_parse_ttl(buf, &l) < 0) { + err++; + break; + } + ttl = l; + (void) getword(buf, sizeof buf, fp, 1); + } + /* possibly class */ + if (buf[0] != '\0') { + int success; + int maybe_class; + + maybe_class = sym_ston(__p_class_syms, + buf, &success); + if (success) { + class = maybe_class; + (void) getword(buf, sizeof buf, fp, 1); + } + } + /* possibly type */ + if (buf[0] != '\0') { + int success; + int maybe_type; + + maybe_type = sym_ston(__p_type_syms, + buf, &success); + + if (success) { + type = maybe_type; + (void) getword(buf, sizeof buf, fp, 1); + } + } + if (buf[0] != '\0') /* possibly rdata */ + /* + * Convert the ascii data 'buf' to the proper + * format based on the type and pack into + * 'data'. + * + * XXX - same as in db_load(), consolidation + * needed + */ + switch (type) { + case T_A: + if (!inet_aton(buf, &ina)) { + err++; + break; + } + n = ntohl(ina.s_addr); + cp = data; + PUTLONG(n, cp); + n = INT32SZ; + break; + case T_HINFO: + case T_ISDN: + n = strlen(buf); + data[0] = n; + memcpy(data + 1, buf, n); + n++; + if (!getword(buf, sizeof buf, fp, 0)) { + i = 0; + } else { + endline(fp); + i = strlen(buf); + } + data[n] = i; + n++; + memcpy(data + n + 1, buf, i); + n += i; + break; + case T_SOA: + case T_MINFO: + case T_RP: + (void) strcpy(data, buf); + cp = data + strlen(data) + 1; + if (!getword((char *) cp, + sizeof data - (cp - data), + fp, 1)) { + err++; + break; + } + cp += strlen((char *) cp) + 1; + if (type != T_SOA) { + n = cp - data; + break; + } + if (class != zp->z_class || + ns_samename(dname, zp->z_origin) != 1) { + err++; + break; + } + c = getnonblank(fp, zp->z_updatelog); + if (c == '(') { + multiline = 1; + } else { + multiline = 0; + ungetc(c, fp); + } + n = getnum(fp, zp->z_updatelog, GETNUM_SERIAL); + if (getnum_error) { + err++; + break; + } + if (opcode == ADD && i == 0) + *new_serial = n; + PUTLONG(n, cp); + for (i = 0; i < 4; i++) { + if (!getword(buf, sizeof buf, fp, 1)) { + err++; + break; + } + if (ns_parse_ttl(buf, &l) < 0) { + err++; + break; + } + n = l; + PUTLONG(n, cp); + } + if (multiline && + getnonblank(fp, zp->z_updatelog) != ')') + { + err++; + break; + } + endline(fp); + n = cp - data; + break; + case T_WKS: + if (!inet_aton(buf, &ina)) { + err++; + break; + } + n = ntohl(ina.s_addr); + cp = data; + PUTLONG(n, cp); + *cp = (char) getprotocol(fp, zp->z_updatelog); + n = INT32SZ + sizeof(char); + n = getservices((int) n, data, + fp, zp->z_updatelog); + break; + case T_NS: + case T_CNAME: + case T_MB: + case T_MG: + case T_MR: + case T_PTR: + (void) strcpy(data, buf); + if (makename(data, origin, + sizeof(data)) == -1) { + err++; + break; + } + n = strlen(data) + 1; + break; + case T_MX: + case T_AFSDB: + case T_RT: + n = 0; + cp = buf; + while (isdigit(*cp)) + n = n * 10 + (*cp++ - '0'); + /* catch bad values */ + cp = data; + PUTSHORT((u_int16_t) n, cp); + if (!getword(buf, sizeof(buf), fp, 1)) { + err++; + break; + } + (void) strcpy((char *) cp, buf); + if (makename((char *) cp, origin, + sizeof(data) - (cp - data)) == -1) + { + err++; + break; + } + /* advance pointer to end of data */ + cp += strlen((char *) cp) + 1; + /* now save length */ + n = (cp - data); + break; + case T_PX: + n = 0; + data[0] = '\0'; + cp = buf; + while (isdigit(*cp)) + n = n * 10 + (*cp++ - '0'); + cp = data; + PUTSHORT((u_int16_t) n, cp); + for (i = 0; i < 2; i++) { + if (!getword(buf, sizeof(buf), fp, 0)) + { + err++; + break; + } + (void) strcpy((char *) cp, buf); + cp += strlen((char *) cp) + 1; + } + n = cp - data; + break; + case T_TXT: + case T_X25: + i = strlen(buf); + cp = data; + datasize = sizeof data; + cp1 = buf; + while (i > MAXCHARSTRING) { + if (datasize <= MAXCHARSTRING) { + ns_error(ns_log_update, + "record too big"); + return (-1); + } + datasize -= MAXCHARSTRING; + *cp++ = (char)MAXCHARSTRING; + memcpy(cp, cp1, MAXCHARSTRING); + cp += MAXCHARSTRING; + cp1 += MAXCHARSTRING; + i -= MAXCHARSTRING; + } + if (datasize < i + 1) { + ns_error(ns_log_update, + "record too big"); + return (-1); + } + *cp++ = i; + memcpy(cp, cp1, i); + cp += i; + n = cp - data; + endline(fp); + /* XXXVIX: segmented texts 4.9.5 */ + break; + case T_NSAP: + n = inet_nsap_addr(buf, (u_char *) data, + sizeof data); + endline(fp); + break; + case T_LOC: + cp = buf + (n = strlen(buf)); + *cp = ' '; + cp++; + while ((i = getc(fp), *cp = i, i != EOF) + && *cp != '\n' && (n < MAXDATA)) + { + cp++; + n++; + } + if (*cp == '\n') + ungetc(*cp, fp); + *cp = '\0'; + n = loc_aton(buf, (u_char *) data); + if (n == 0) { + err++; + break; + } + endline(fp); + break; + case ns_t_sig: + case ns_t_nxt: + case ns_t_key: + case ns_t_cert:{ + char *errmsg = NULL; + + n = parse_sec_rdata(buf, sizeof(buf), 1, + (u_char *) data, + sizeof(data), + fp, zp, dname, ttl, + type, domain_ctx, + transport, &errmsg); + if (errmsg) { + err++; + endline(fp); + n = 0; + } + break; + } + default: + err++; + } + if (section == S_PREREQ) { + ttl = 0; + if (opcode == NXDOMAIN) { + class = C_NONE; + type = T_ANY; + n = 0; + } else if (opcode == YXDOMAIN) { + class = C_ANY; + type = T_ANY; + n = 0; + } else if (opcode == NXRRSET) { + class = C_NONE; + n = 0; + } else if (opcode == YXRRSET) { + if (n == 0) + class = C_ANY; + } + } else {/* section == S_UPDATE */ + if (opcode == DELETE) { + if (n == 0) { + class = C_ANY; + if (type == -1) + type = T_ANY; + } else { + class = zp->z_class; + } + } + } + break; + case S_ADDT: + default: + ns_debug(ns_log_update, 1, + "cannot interpret section: %d", section); + inside_next = 0; + err++; + } + if (err) { + inside_next = 0; + ns_debug(ns_log_update, 1, + "merge of update id %d failed due to error at line %d", + id, lineno); + memset(&empty_from, 0, sizeof empty_from); + free_rrecp(&listuprec, rcode, empty_from); + continue; + } + rrecp = res_mkupdrec(section, dname, class, type, ttl); + if (section != S_ZONE) { + dp = savedata(class, type, ttl, (u_char *) data, n); + dp->d_zone = zonenum; + dp->d_cred = DB_C_ZONE; + dp->d_clev = nlabels(zp->z_origin); + rrecp->r_dp = dp; + rrecp->r_opcode = opcode; + } else { + rrecp->r_zone = zonenum; + rrecp->r_opcode = opcode; + } + + /* remove add/delete pairs */ + if (section == S_UPDATE) { + ns_updrec *arp; + int foundmatch; + + arp = TAIL(listuprec); + foundmatch = 0; + while (arp) { + if (arp->r_section == S_UPDATE && + ((arp->r_opcode == DELETE && + opcode == ADD) || + (opcode == DELETE && + arp->r_opcode == ADD)) && + arp->r_dp->d_type == dp->d_type && + arp->r_dp->d_class == dp->d_class && + arp->r_dp->d_ttl == dp->d_ttl && + ns_samename(arp->r_dname, dname) == 1 && + db_cmp(arp->r_dp, dp) == 0) { + db_freedata(dp); + db_freedata(arp->r_dp); + UNLINK(listuprec, arp, r_link); + res_freeupdrec(arp); + res_freeupdrec(rrecp); + foundmatch = 1; + break; + } + arp = PREV(arp, r_link); + } + if (foundmatch) + continue; + } + + APPEND(listuprec, rrecp, r_link); + /* Override zone number with current zone serial number */ + rrecp->r_zone = serial; + } + + if (err) + return (DBIXFR_ERROR); + + return (DBIXFR_END); +} diff --git a/contrib/bind/bin/named/db_load.c b/contrib/bind/bin/named/db_load.c index d05a969..9b6fedb 100644 --- a/contrib/bind/bin/named/db_load.c +++ b/contrib/bind/bin/named/db_load.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)db_load.c 4.38 (Berkeley) 3/2/91"; -static char rcsid[] = "$Id: db_load.c,v 8.41 1998/02/13 20:02:28 halley Exp $"; +static const char sccsid[] = "@(#)db_load.c 4.38 (Berkeley) 3/2/91"; +static const char rcsid[] = "$Id: db_load.c,v 8.97 1999/10/30 03:21:35 vixie Exp $"; #endif /* not lint */ /* @@ -82,7 +82,7 @@ static char rcsid[] = "$Id: db_load.c,v 8.41 1998/02/13 20:02:28 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -110,6 +110,7 @@ static char rcsid[] = "$Id: db_load.c,v 8.41 1998/02/13 20:02:28 halley Exp $"; #include <sys/param.h> #include <sys/stat.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -137,27 +138,28 @@ static char rcsid[] = "$Id: db_load.c,v 8.41 1998/02/13 20:02:28 halley Exp $"; /* Forward. */ static int gettoken(FILE *, const char *); -static int getttl(FILE *, const char *, int, u_int32_t *, int *); static int getcharstring(char *, char *, int, int, int, FILE *, const char *); -static int makename_ok(char *name, const char *origin, int class, - struct zoneinfo *zp, - enum transport transport, - enum context context, - const char *owner, const char *filename, - int lineno, int size); +static int genname(char *, int, const char *, char *, int); static int getmlword(char *, size_t, FILE *, int); static int getallwords(char *, size_t, FILE *, int); static u_int32_t wordtouint32(char *); -static int datepart(const char *, int, int, int, int *); -static u_int32_t datetosecs(const char *, int *); -static int get_nxt_types(u_char *, FILE *, const char *); static void fixup_soa(const char *fn, struct zoneinfo *zp); -#ifdef BIND_NOTIFY -static void notify_after_delay(evContext ctx, void *uap, - struct timespec due, - struct timespec inter); -#endif +static int get_nxt_types(u_char *, FILE *, const char *); + +static int parse_sig_rr(char *, int, u_char *, int, FILE *, + struct zoneinfo *, char *, u_int32_t , + enum context , enum transport , char **); +static int parse_key_rr(char *, int, u_char *, int, FILE *, + struct zoneinfo *, char *, enum context, + enum transport, char **); + +static int parse_cert_rr(char *, int, u_char *, int, FILE *, char **); +static int parse_nxt_rr(char *, int, u_char *, int, FILE *, + struct zoneinfo *, char *, enum context, + enum transport, char **); + + static int wordtouint32_error = 0; static int empty_token = 0; static int getmlword_nesting = 0; @@ -166,37 +168,50 @@ static int getmlword_nesting = 0; static int clev; /* a zone deeper in a hierarchy has more credibility */ -#ifdef BIND_NOTIFY -static notify_info_list pending_notifies; -#endif - /* * Parser token values */ -#define CURRENT 1 -#define DOT 2 -#define AT 3 -#define DNAME 4 -#define INCLUDE 5 -#define ORIGIN 6 -#define ERROR 7 +#define CURRENT 1 +#define DOT 2 +#define AT 3 +#define DNAME 4 +#define INCLUDE 5 +#define ORIGIN 6 +#define GENERATE 7 +#define DEFAULTTTL 8 +#define ERRTOK 9 #define MAKENAME_OK(N) \ do { \ if (!makename_ok(N, origin, class, zp, \ - transport, context, \ + transport, context, \ domain, filename, lineno, \ - sizeof(data) - ((u_char*)N - data))) { \ + data_size - ((u_char*)N - data))) { \ + errs++; \ + sprintf(buf, "bad name \"%s\"", N); \ + goto err; \ + } \ + } while (0) + +#define MAKENAME_OKZP(N, SI) \ + do { \ + if (!makename_ok(N, zp->z_origin, zp->z_class, zp, \ + transport, context, \ + domain, zp->z_source, lineno, \ + SI - ((u_char*)N - data))) { \ errs++; \ sprintf(buf, "bad name \"%s\"", N); \ goto err; \ } \ } while (0) +#define RANGE(x, min, max) \ + (((x) > (max)) ? (max) : (((x) < (min)) ? (min) : (x))) + /* Public. */ /* int - * db_load(filename, in_origin, zp, def_domain) + * db_load(filename, in_origin, zp, def_domain, isixfr) * load a database from `filename' into zone `zp'. append `in_origin' * to all nonterminal domain names in the file. `def_domain' is the * default domain for include files or NULL for zone base files. @@ -207,18 +222,24 @@ static notify_info_list pending_notifies; */ int db_load(const char *filename, const char *in_origin, - struct zoneinfo *zp, const char *def_domain) + struct zoneinfo *zp, const char *def_domain, int isixfr) { static int read_soa, read_ns, rrcount; + static u_int32_t default_ttl, default_warn; + static struct filenames { + struct filenames *next; + char *name; + } *filenames, *fn; const char *errtype = "Database"; char *cp; char domain[MAXDNAME], origin[MAXDNAME], tmporigin[MAXDNAME]; char buf[MAXDATA]; + char genlhs[MAXDNAME], genrhs[MAXDNAME]; u_char data[MAXDATA]; - const char *op; - int c, someclass, class, type, dbflags, dataflags, multiline; - int slineno, i, errs, didinclude, escape, success, dateerror; + int data_size = sizeof(data); + int c, someclass, class, type, dbflags, dataflags, multiline = 0; + int slineno, i, errs, didinclude, ininclude, escape, success; u_int32_t ttl, n, serial; u_long tmplong; struct databuf *dp; @@ -227,9 +248,10 @@ db_load(const char *filename, const char *in_origin, struct in_addr ina; enum transport transport; enum context context; - u_int32_t sig_type; - u_int32_t keyflags; struct sockaddr_in empty_from; + int genstart, genend, genstep; + char *thisfile; + void *state = NULL; empty_from.sin_family = AF_INET; empty_from.sin_addr.s_addr = htonl(INADDR_ANY); @@ -241,40 +263,57 @@ db_load(const char *filename, const char *in_origin, * and complains. */ #define ERRTO(msg) do { if (1) { errtype = msg; goto err; } } while (0) +#define ERRTOZ(msg) do { if (1) { errtype = msg; buf[0] = '\0'; goto err; } } while (0) switch (zp->z_type) { case Z_PRIMARY: - case Z_CACHE: + case Z_HINT: transport = primary_trans; break; case Z_SECONDARY: case Z_STUB: transport = secondary_trans; break; + case Z_CACHE: + transport = response_trans; + break; default: transport = response_trans; /*guessing*/ break; } errs = 0; didinclude = 0; - if (!def_domain) { - /* This is not the result of a $INCLUDE. */ + ininclude = (def_domain != NULL); + if (!ininclude) { rrcount = 0; read_soa = 0; read_ns = 0; + default_ttl = USE_MINIMUM; + default_warn = 1; clev = nlabels(in_origin); + filenames = NULL; } + ttl = default_ttl; - ns_debug(ns_log_load, 1, "db_load(%s, %s, %d, %s)", + ns_debug(ns_log_load, 1, "db_load(%s, %s, %d, %s, %s)", filename, in_origin, zp - zones, - def_domain ? def_domain : "Nil"); + def_domain ? def_domain : "Nil", isixfr ? "IXFR" : "Normal"); + + fn = (struct filenames *)memget(sizeof *filenames); + if (fn == NULL) + ns_panic(ns_log_db, 0, "db_load: memget failed"); + thisfile = fn->name = savestr(filename, 1); + fn->next = filenames; + filenames = fn; strcpy(origin, in_origin); if ((fp = fopen(filename, "r")) == NULL) { - ns_warning(ns_log_load, "%s: %s", filename, strerror(errno)); + ns_warning(ns_log_load, "db_load could not open: %s: %s", + filename, strerror(errno)); + zp->z_ftime = 0; return (-1); } - if (zp->z_type == Z_CACHE) { + if (zp->z_type == Z_HINT) { dbflags = DB_NODATA | DB_NOHINTS; dataflags = DB_F_HINT; #ifdef STUBS @@ -288,7 +327,8 @@ db_load(const char *filename, const char *in_origin, } gettime(&tt); if (fstat(fileno(fp), &sb) < 0) { - ns_warning(ns_log_load, "%s: %s", filename, strerror(errno)); + ns_warning(ns_log_load, "fstat failed: %s: %s", + filename, strerror(errno)); sb.st_mtime = (int)tt.tv_sec; } slineno = lineno; @@ -302,6 +342,10 @@ db_load(const char *filename, const char *in_origin, while ((c = gettoken(fp, filename)) != EOF) { switch (c) { case INCLUDE: + if (isixfr) { + c = ERRTOK; + break; + } if (!getword(buf, sizeof buf, fp, 0)) /* file name*/ break; @@ -309,12 +353,12 @@ db_load(const char *filename, const char *in_origin, strcpy(tmporigin, origin); else { if (makename(tmporigin, origin, - sizeof(tmporigin)) == -1) + sizeof(tmporigin)) == -1) ERRTO("$INCLUDE makename failed"); endline(fp); } didinclude = 1; - errs += db_load(buf, tmporigin, zp, domain); + errs += db_load(buf, tmporigin, zp, domain, ISNOTIXFR); continue; case ORIGIN: @@ -329,6 +373,123 @@ db_load(const char *filename, const char *in_origin, origin); continue; + case GENERATE: + if (!getword(buf, sizeof(buf), fp, 0)) + ERRTOZ("$GENERATE missing RANGE"); + n = sscanf(buf, "%d-%d/%d", &genstart, &genend, + &genstep); + if (n != 2 && n != 3) + ERRTO("$GENERATE invalid range"); + if (n == 2) + genstep = 1; + if ((genend < genstart) || (genstart < 0) || + (genstep < 0)) + ERRTO("$GENERATE invalid range"); + if (!getword(genlhs, sizeof(genlhs), fp, 2)) + ERRTOZ("$GENERATE missing LHS"); + if (!getword(buf, sizeof(buf), fp, 0)) + ERRTOZ("GENERATE missing TYPE"); + type = sym_ston(__p_type_syms, buf, &success); + if (success == 0 || type == ns_t_any) { + ns_info(ns_log_load, + "%s: Line %d: $GENERATE unknown type: %s.", + filename, lineno, buf); + errs++; + endline(fp); + continue; + } + switch (type) { + case ns_t_ns: + case ns_t_ptr: + case ns_t_cname: + case ns_t_a: + case ns_t_aaaa: + break; + default: + ERRTO("$GENERATE unsupported type"); + } + if (!getword(genrhs, sizeof(genrhs), fp, 2)) + ERRTOZ("$GENERATE missing RHS"); + for (i = genstart; i <= genend; i += genstep) { + if (genname(genlhs, i, origin, domain, + sizeof domain) == -1) + ERRTOZ("$GENERATE genname LHS failed"); + context = ns_ownercontext(type, transport); + if (!ns_nameok(NULL, domain, class, zp, transport, + context, domain, inaddr_any)) { + strcpy(buf, domain); + ERRTO("$GENERATE owner name error"); + } + switch (type) { + case ns_t_ns: + case ns_t_ptr: + case ns_t_cname: + if (genname(genrhs, i, origin, (char *)data, + sizeof data) == -1) + ERRTOZ("$GENERATE genname RHS failed"); + switch (type) { + case ns_t_ns: + context = hostname_ctx; + break; + case ns_t_ptr: + context = ns_ptrcontext(domain); + break; + case ns_t_cname: + context = domain_ctx; + break; + } + if (!ns_nameok(NULL, (char *)data, class, zp, + transport, context, + domain, inaddr_any)) { + strncpy(buf, domain, sizeof(buf)); + buf[sizeof(buf)-1] = '\0'; + ERRTO("$GENERATE name error"); + } + n = strlen((char *)data) + 1; + break; + case ns_t_a: + case ns_t_aaaa: + if (genname(genrhs, i, NULL, (char *)data, + sizeof data) == -1) + ERRTOZ("$GENERATE genname RHS failed"); + strncpy(buf, (char*)data, sizeof(buf)); + buf[sizeof(buf)-1] = '\0'; + switch (type) { + case ns_t_a: + if (!inet_aton(buf, &ina)) + ERRTO("IP Address"); + (void) ina_put(ina, data); + n = NS_INT32SZ; + break; + case ns_t_aaaa: + if (inet_pton(AF_INET6, buf, data) <= 0) + ERRTO("IPv6 Address"); + n = NS_IN6ADDRSZ; + break; + } + break; + default: + ERRTOZ("$GENERATE unsupported context"); + } + dp = savedata(class, type, (u_int32_t)ttl, + (u_char *)data, (int)n); + dp->d_zone = zp - zones; + dp->d_flags = dataflags; + dp->d_cred = DB_C_ZONE; + dp->d_clev = clev; + c = db_set_update(domain, dp, &state, dbflags, + (dataflags & DB_F_HINT) != 0 ? + &fcachetab : &hashtab, + empty_from, &rrcount, lineno, + filename); + if (c != OK) { + if (c == CNAMEANDOTHER) + errs++; + } + } + endline(fp); + continue; + case DNAME: if (!getword(domain, sizeof(domain), fp, 1)) break; @@ -336,6 +497,14 @@ db_load(const char *filename, const char *in_origin, ERRTO("ownername makename failed"); goto gotdomain; + case DEFAULTTTL: + if (getttl(fp, filename, lineno, &n, + &multiline) <= 0 || n > MAXIMUM_TTL) { + ERRTO("$TTL bad TTL value"); + } + ttl = default_ttl = n; + continue; + case AT: (void) strcpy(domain, origin); goto gotdomain; @@ -350,10 +519,19 @@ db_load(const char *filename, const char *in_origin, continue; break; } - if (ns_parse_ttl(buf, &tmplong) < 0) - ttl = USE_MINIMUM; - else { - ttl = (u_int32_t)tmplong; + if (ns_parse_ttl(buf, &tmplong) < 0) { + if (zp->z_type == z_master && + default_warn && + (default_ttl == USE_MINIMUM)) { + ns_warning(ns_log_load, + "Zone \"%s\" (file %s): %s", + zp->z_origin, filename, + "No default TTL set using SOA minimum instead"); + default_warn = 0; + } + ttl = (u_int32_t)default_ttl; + } else { + ttl = tmplong; if (ttl > MAXIMUM_TTL) { ns_info(ns_log_load, "%s: Line %d: TTL > %u; converted to 0", @@ -375,6 +553,14 @@ db_load(const char *filename, const char *in_origin, /* Parse class (IN, etc) */ someclass = sym_ston(__p_class_syms, buf, &success); + if (success && someclass != zp->z_class) { + ns_info(ns_log_load, + "%s: Line %d: wrong class: %s.", + filename, lineno, + p_class(someclass)); + errs++; + break; + } if (success && someclass != C_ANY) { class = someclass; (void) getword(buf, sizeof buf, fp, 0); @@ -389,9 +575,10 @@ db_load(const char *filename, const char *in_origin, errs++; break; } - + if (ttl == USE_MINIMUM) + ttl = zp->z_minimum; context = ns_ownercontext(type, transport); - if (!ns_nameok(domain, class, zp, transport, context, + if (!ns_nameok(NULL, domain, class, zp, transport, context, domain, inaddr_any)) { errs++; ns_notice(ns_log_load, @@ -404,6 +591,7 @@ db_load(const char *filename, const char *in_origin, case ns_t_key: case ns_t_sig: case ns_t_nxt: + case ns_t_cert: /* * Don't do anything here for these types -- * they read their own input separately later. @@ -451,7 +639,7 @@ db_load(const char *filename, const char *in_origin, /* FALLTHROUGH */ soa_rp_minfo: (void) strcpy((char *)data, buf); - + MAKENAME_OK((char *)data); cp = (char *)(data + strlen((char *)data) + 1); if (!getword(cp, @@ -469,13 +657,7 @@ db_load(const char *filename, const char *in_origin, n = cp - (char *)data; break; } - if (class != zp->z_class) { - errs++; - ns_info(ns_log_load, "%s:%d: %s", - filename, lineno, - "SOA class not same as zone's"); - } - if (strcasecmp(zp->z_origin, domain) != 0) { + if (ns_samename(zp->z_origin, domain) != 1) { errs++; ns_error(ns_log_load, "%s:%d: SOA for \"%s\" not at zone top \"%s\"", @@ -509,9 +691,10 @@ db_load(const char *filename, const char *in_origin, n = INIT_REFRESH; } PUTLONG(n, cp); - zp->z_refresh = MAX(n, MIN_REFRESH); + zp->z_refresh = RANGE(n, MIN_REFRESH, + MAX_REFRESH); if (zp->z_type == Z_SECONDARY -#if defined(STUBS) +#if defined(STUBS) || zp->z_type == Z_STUB #endif ) { @@ -520,7 +703,7 @@ db_load(const char *filename, const char *in_origin, sched_zone_maint(zp); } #ifdef BIND_UPDATE - if ((zp->z_type == Z_PRIMARY) && + if ((zp->z_type == Z_PRIMARY) && (zp->z_flags & Z_DYNAMIC)) if ((u_int32_t)zp->z_soaincrintvl > zp->z_refresh/3) { @@ -537,14 +720,15 @@ db_load(const char *filename, const char *in_origin, n = INIT_REFRESH; } PUTLONG(n, cp); - zp->z_retry = MAX(n, MIN_RETRY); + zp->z_retry = RANGE(n, MIN_RETRY, MAX_RETRY); if (getttl(fp, filename, lineno, - &zp->z_expire, &multiline) <= 0) { + &n, &multiline) <= 0) { errs++; - zp->z_expire = INIT_REFRESH; + n = INIT_REFRESH; } - n = zp->z_expire; PUTLONG(n, cp); + zp->z_expire = RANGE(n, zp->z_refresh, + MAX_EXPIRE); if (getttl(fp, filename, lineno, &n, &multiline) <= 0) { errs++; @@ -556,8 +740,10 @@ db_load(const char *filename, const char *in_origin, "%s: Line %d: SOA minimum TTL > %u; converted to 0", filename, lineno, MAXIMUM_TTL); zp->z_minimum = 0; - } else + } else zp->z_minimum = n; + if (default_ttl == USE_MINIMUM) + ttl = n; n = cp - (char *)data; if (multiline) { buf[0] = getnonblank(fp, filename); @@ -584,7 +770,7 @@ db_load(const char *filename, const char *in_origin, break; case ns_t_ns: - if (strcasecmp(zp->z_origin, domain) == 0) + if (ns_samename(zp->z_origin, domain) == 1) read_ns++; context = hostname_ctx; goto cname_etc; @@ -625,22 +811,28 @@ db_load(const char *filename, const char *in_origin, if (!getword(buf, sizeof buf, fp, 0)) ERRTO("NAPTR Flags"); n = strlen(buf); + if (n > 255) + ERRTO("NAPTR Flags too big"); *cp++ = n; memcpy(cp, buf, (int)n); cp += n; - + /* Service Classes */ if (!getword(buf, sizeof buf, fp, 0)) ERRTO("NAPTR Service Classes"); n = strlen(buf); + if (n > 255) + ERRTO("NAPTR Service Classes too big"); *cp++ = n; memcpy(cp, buf, (int)n); cp += n; - + /* Pattern */ if (!getword(buf, sizeof buf, fp, 0)) ERRTO("NAPTR Pattern"); n = strlen(buf); + if (n > 255) + ERRTO("NAPTR Pattern too big"); *cp++ = n; memcpy(cp, buf, (int)n); cp += n; @@ -648,6 +840,9 @@ db_load(const char *filename, const char *in_origin, /* Replacement */ if (!getword(buf, sizeof buf, fp, 1)) ERRTO("NAPTR Replacement"); + n = strlen(buf); + if (n > data_size - ((u_char *)cp - data)) + ERRTO("NAPTR Replacement too big"); (void) strcpy((char *)cp, buf); context = domain_ctx; MAKENAME_OK(cp); @@ -771,422 +966,31 @@ db_load(const char *filename, const char *in_origin, endline(fp); break; - case ns_t_key: { - /* The KEY record looks like this in the db file: - * Name Cl KEY Flags Proto Algid PublicKeyData - * where: - * Name,Cl per usual - * KEY RR type - * Flags 4 digit hex value (unsigned_16) - * Proto 8 bit u_int - * Algid 8 bit u_int - * PublicKeyData - * a string of base64 digits, - * skipping any embedded whitespace. - */ - u_int32_t al, pr; - int nk, klen; - char *expstart; - u_int expbytes, modbytes; - - i = 0; - data[i] = '\0'; - cp = (char *)data; - getmlword_nesting = 0; /* KLUDGE err recov. */ - /*>>> Flags (unsigned_16) */ - if (!getmlword((char*)buf, sizeof buf, fp, 0)) - ERRTO("KEY Flags Field"); - keyflags = wordtouint32(buf); - if (wordtouint32_error || 0xFFFF < keyflags) + case ns_t_nxt: + case ns_t_key: + case ns_t_cert: + case ns_t_sig: { + char *errmsg = NULL; + int ret = parse_sec_rdata(buf, sizeof(buf), 0, + data, sizeof(data), + fp, zp, domain, ttl, + type, domain_ctx, + transport, &errmsg); + if (ret < 0) { + errtype = errmsg; goto err; - if (keyflags & NS_KEY_RESERVED_BITMASK) - ERRTO("KEY Reserved Flag Bit"); - PUTSHORT(keyflags, cp); - - /*>>> Protocol (8-bit decimal) */ - if (!getmlword((char*)buf, sizeof buf, fp, 0)) - ERRTO("KEY Protocol Field"); - pr = wordtouint32(buf); - if (wordtouint32_error || 255 < pr) - ERRTO("KEY Protocol Field"); - *cp++ = (u_char) pr; - - /*>>> Algorithm id (8-bit decimal) */ - if (!getmlword((char*)buf, sizeof buf, fp, 0)) - ERRTO("KEY Algorithm ID"); - al = wordtouint32(buf); - if (wordtouint32_error || - 0 == al || 255 == al || 255 < al) - ERRTO("KEY Algorithm ID"); - *cp++ = (u_char) al; - - /*>>> Public Key data is in BASE64. - * We don't care what algorithm it uses or what - * the internal structure of the BASE64 data is. - */ - if (!getallwords(buf, MAXDATA, fp, 0)) - klen = 0; - else { - /* Convert from BASE64 to binary. */ - klen = b64_pton(buf, (u_char*)cp, - sizeof data - - (cp - (char *)data)); - if (klen < 0) - ERRTO("KEY Public Key"); } - - /* set total length */ - n = cp + klen - (char *)data; - - /* - * Now check for valid key flags & algs & etc, - * from the RFC. - */ - - if (keyflags & (NS_KEY_ZONEKEY | NS_KEY_IPSEC - | NS_KEY_EMAIL)) - pr |= 1; /* A nonzero proto. */ - if (NS_KEY_TYPE_NO_KEY == - (keyflags & NS_KEY_TYPEMASK)) - nk = 1; /* No-key */ else - nk = 0; /* have a key */ - - if ((keyflags & NS_KEY_ZONEKEY) && - (NS_KEY_TYPE_CONF_ONLY == - (keyflags & NS_KEY_TYPEMASK))) - /* Zone key must have Auth bit set. */ - ERRTO("KEY Zone Key Auth. bit"); - - if (al == 0 && nk == 0) - ERRTO("KEY Algorithm"); - if (al != 0 && pr == 0) - ERRTO("KEY Protocols"); - - if (nk == 1 && klen != 0) - ERRTO("KEY No-Key Flags Set"); - - if (nk == 0 && klen == 0) - ERRTO("KEY Type Spec'd"); - - /* Check algorithm-ID and key structure, for - the algorithm-ID's that we know about. */ - switch (al) { - case NS_ALG_MD5RSA: - if (klen == 0) - break; - expstart = cp; - expbytes = *expstart++; - if (expbytes == 0) - GETSHORT(expbytes, expstart); - - if (expbytes < 1) - ERRTO("Exponent too short"); - if (expbytes > - (NS_MD5RSA_MAX_BITS + 7) / 8 - ) - ERRTO("Exponent too long"); - if (*expstart == 0) - ERRTO("Exponent w/ 0"); - - modbytes = klen - - (expbytes + (expstart - cp)); - if (modbytes < - (NS_MD5RSA_MIN_BITS + 7) / 8 - ) - ERRTO("Modulus too short"); - if (modbytes > - (NS_MD5RSA_MAX_BITS + 7) / 8 - ) - ERRTO("Modulus too long"); - if (*(expstart+expbytes) == 0) - ERRTO("Modulus starts w/ 0"); - break; - - case NS_ALG_EXPIRE_ONLY: - if (klen != 0) - ERRTO( - "Key provided for expire-only algorithm" - ); - break; - case NS_ALG_PRIVATE_OID: - if (klen == 0) - ERRTO("No ObjectID in key"); - break; - } - - endline(fp); /* flush the rest of the line */ + n = ret; break; - } /*T_KEY*/ - - case ns_t_sig: - { - /* The SIG record looks like this in the db file: - Name Cl SIG RRtype Algid [OTTL] Texp Tsig Kfoot Signer Sig - - where: Name and Cl are as usual - SIG is a keyword - RRtype is a char string - ALGid is 8 bit u_int - OTTL is 32 bit u_int (optionally present) - Texp is YYYYMMDDHHMMSS - Tsig is YYYYMMDDHHMMSS - Kfoot is 16-bit unsigned decimal integer - Signer is a char string - Sig is 64 to 319 base-64 digits - A missing OTTL is detected by the magnitude of the Texp value - that follows it, which is larger than any u_int. - The Labels field in the binary RR does not appear in the - text RR. - - It's too crazy to run these pages of SIG code at the right - margin. I'm exdenting them for readability. - */ - int siglen; - u_int32_t al; - u_int32_t signtime, exptime, timetilexp; - u_int32_t origTTL; - time_t now; - - /* The TTL gets checked against the Original TTL, - and bounded by the signature expiration time, which - are both under the signature. We can't let TTL drift - based on the SOA record. If defaulted, fix it now. - (It's not clear to me why USE_MINIMUM isn't eliminated - before putting ALL RR's into the database. -gnu@toad.com) */ - if (ttl == USE_MINIMUM) - ttl = zp->z_minimum; - - i = 0; - data[i] = '\0'; - getmlword_nesting = 0; /* KLUDGE err recovery */ - - /* RRtype (char *) */ - if (!getmlword((char*)buf, sizeof buf, fp, 0)) - ERRTO("SIG record doesn't specify type"); - sig_type = sym_ston(__p_type_syms, buf, &success); - if (!success || sig_type == ns_t_any) { - /* - * We'll also accept a numeric RR type, - * for signing RR types that this version - * of named doesn't yet understand. - * In the ns_t_any case, we rely on wordtouint32 - * to fail when scanning the string "ANY". - */ - sig_type = wordtouint32 (buf); - if (wordtouint32_error || sig_type > 0xFFFF) - ERRTO("Unknown RR type in SIG record"); - } - cp = (char *)&data[i]; - PUTSHORT((u_int16_t)sig_type, cp); - i += 2; - - /* Algorithm id (8-bit decimal) */ - if (!getmlword(buf, sizeof buf, fp, 0)) - ERRTO("Missing algorithm ID"); - al = wordtouint32(buf); - if (0 == al || wordtouint32_error || 255 <= al) - goto err; - data[i] = (u_char) al; - i++; - - /* - * Labels (8-bit decimal) - * Not given in the file. Must compute. - */ - n = dn_count_labels(domain); - if (0 >= n || 255 < n) - ERRTO("SIG label count invalid"); - data[i] = (u_char) n; - i++; - - /* - * OTTL (optional u_int32_t) and - * Texp (u_int32_t date) - */ - if (!getmlword(buf, sizeof buf, fp, 0)) - ERRTO("OTTL and expiration time missing"); - /* - * See if OTTL is missing and this is a date. - * This relies on good, silent error checking - * in datetosecs. - */ - exptime = datetosecs(buf, &dateerror); - if (!dateerror) { - /* Output TTL as OTTL */ - origTTL = ttl; - cp = (char *)&data[i]; - PUTLONG (origTTL, cp); - i += 4; - } else { - /* Parse and output OTTL; scan TEXP */ - origTTL = wordtouint32(buf); - if (0 >= origTTL || wordtouint32_error || - (origTTL > 0x7fffffff)) - goto err; - cp = (char *)&data[i]; - PUTLONG(origTTL, cp); - i += 4; - if (!getmlword(buf, sizeof buf, fp, 0)) - ERRTO("Expiration time missing"); - exptime = datetosecs(buf, &dateerror); - } - if (dateerror || exptime > 0x7fffffff || exptime <= 0) - ERRTO("Invalid expiration time"); - cp = (char *)&data[i]; - PUTLONG(exptime, cp); - i += 4; - - /* Tsig (u_int32_t) */ - if (!getmlword(buf, sizeof buf, fp, 0)) - ERRTO("Missing signature time"); - signtime = datetosecs(buf, &dateerror); - if (0 == signtime || dateerror) - ERRTO("Invalid signature time"); - cp = (char *)&data[i]; - PUTLONG(signtime, cp); - i += 4; - - /* Kfootprint (unsigned_16) */ - if (!getmlword(buf, sizeof buf, fp, 0)) - ERRTO("Missing key footprint"); - n = wordtouint32(buf); - if (wordtouint32_error || n >= 0x0ffff) - ERRTO("Invalid key footprint"); - cp = (char *)&data[i]; - PUTSHORT((u_int16_t)n, cp); - i += 2; - - /* Signer's Name */ - if (!getmlword((char*)buf, sizeof buf, fp, 0)) - ERRTO("Missing signer's name"); - cp = (char *)&data[i]; - strcpy(cp,buf); - context = domain_ctx; - MAKENAME_OK(cp); - i += strlen(cp) + 1; - - /* - * Signature (base64 of any length) - * We don't care what algorithm it uses or what - * the internal structure of the BASE64 data is. - */ - if (!getallwords(buf, sizeof buf, fp, 0)) { - siglen = 0; - } else { - cp = (char *)&data[i]; - siglen = b64_pton(buf, (u_char*)cp, sizeof data - i); - if (siglen < 0) - goto err; - } - - /* set total length and we're done! */ - n = i + siglen; - - /* - * Check signature time, expiration, and adjust TTL. Note - * that all time values are in GMT (UTC), *not* local time. - */ - - now = time (0); - - /* Don't let bogus name servers increase the signed TTL */ - if (ttl > origTTL) - ERRTO("TTL is greater than signed original TTL"); - - /* Don't let bogus signers "sign" in the future. */ - if (signtime > (u_int32_t)now) - ERRTO("signature time is in the future"); - - /* Ignore received SIG RR's that are already expired. */ - if (exptime <= (u_int32_t)now) - ERRTO("expiration time is in the past"); - - /* Lop off the TTL at the expiration time. */ - timetilexp = exptime - now; - if (timetilexp < ttl) { - ns_debug(ns_log_load, 1, - "shrinking expiring %s SIG TTL from %d to %d", - p_secstodate(exptime), ttl, timetilexp); - ttl = timetilexp; - } - - /* - * Check algorithm-ID and key structure, for - * the algorithm-ID's that we know about. - */ - switch (al) { - case NS_ALG_MD5RSA: - if (siglen == 0) - ERRTO("No key for RSA algorithm"); - if (siglen < 1) - ERRTO("Signature too short"); - if (siglen > (NS_MD5RSA_MAX_BITS + 7) / 8) - ERRTO("Signature too long"); - /* We rely on cp from parse */ - if (*cp == 0) - ERRTO("Signature starts with zeroes"); - break; - - case NS_ALG_EXPIRE_ONLY: - if (siglen != 0) - ERRTO( - "Signature supplied to expire-only algorithm"); - break; - case NS_ALG_PRIVATE_OID: - if (siglen == 0) - ERRTO("No ObjectID in key"); - break; - } - - /* Should we complain about algorithm-ID's that we - don't understand? It may help debug some obscure - cases, but in general we should accept any RR whether - we could cryptographically process it or not; it - may be being published for some newer DNS clients - to validate themselves. */ - - endline(fp); /* flush the rest of the line */ + } - break; /* Accept this RR. */ - } - - case ns_t_nxt: - /* The NXT record looks like: - Name Cl NXT nextname RRT1 RRT2 MX A SOA ... - - where: Name and Cl are as usual - NXT is a keyword - nextname is the next valid name in - the zone after "Name". All - names between the two are - known to be nonexistent. - RRT's... are a series of RR type - names, which indicate that - RR's of these types are - published for "Name", and - that no RR's of any other - types are published for - "Name". - - When a NXT record is cryptographically - signed, it proves the nonexistence of an - RR (actually a whole set of RR's). */ - - getmlword_nesting = 0; /* KLUDGE err recov. */ - if (!getmlword(buf, sizeof buf, fp, 1)) - goto err; - (void) strcpy((char *)data, buf); - MAKENAME_OK((char *)data); - n = strlen((char *)data) + 1; - cp = n + (char *)data; - n += get_nxt_types((u_char *)cp, fp, filename); - break; case ns_t_loc: cp = buf + (n = strlen(buf)); *cp = ' '; cp++; + n++; while ((i = getc(fp), *cp = i, i != EOF) && *cp != '\n' && (n < MAXDATA)) { @@ -1202,6 +1006,7 @@ db_load(const char *filename, const char *in_origin, endline(fp); break; + default: goto err; } @@ -1209,7 +1014,7 @@ db_load(const char *filename, const char *in_origin, * Ignore data outside the zone. */ if (zp->z_type != Z_CACHE && - !samedomain(domain, zp->z_origin)) + !ns_samedomain(domain, zp->z_origin)) { ns_info(ns_log_load, "%s:%d: data \"%s\" outside zone \"%s\" (ignored)", @@ -1223,42 +1028,44 @@ db_load(const char *filename, const char *in_origin, dp->d_flags = dataflags; dp->d_cred = DB_C_ZONE; dp->d_clev = clev; - if ((c = db_update(domain, dp, dp, NULL, dbflags, - (dataflags & DB_F_HINT) - ? fcachetab - : hashtab, empty_from)) - != OK) { - if (c != DATAEXISTS) - ns_debug(ns_log_load, 1, - "update failed %s %d", - domain, type); - db_freedata(dp); - } else { - rrcount++; - } + c = db_set_update(domain, dp, &state, dbflags, + (dataflags & DB_F_HINT) != 0 ? + &fcachetab : &hashtab, + empty_from, &rrcount, lineno, + filename); + if (c == CNAMEANDOTHER) + errs++; continue; - case ERROR: + case ERRTOK: break; } err: errs++; - ns_notice(ns_log_load, "%s:%d: %s error (%s)", + ns_notice(ns_log_load, "%s:%d: %s error near (%s)", filename, empty_token ? (lineno - 1) : lineno, errtype, buf); if (!empty_token) endline(fp); } + c = db_set_update(NULL, NULL, &state, dbflags, + (dataflags & DB_F_HINT) ? &fcachetab : &hashtab, + empty_from, &rrcount, lineno, filename); + if (c != OK) { + if (c == CNAMEANDOTHER) + errs++; + } + (void) my_fclose(fp); lineno = slineno; - if (!def_domain) { + if (!ininclude) { if (didinclude) { zp->z_flags |= Z_INCLUDE; zp->z_ftime = 0; } else zp->z_ftime = sb.st_mtime; zp->z_lastupdate = sb.st_mtime; - if (zp->z_type != Z_CACHE) { + if (zp->z_type != Z_CACHE && zp->z_type != Z_HINT) { const char *msg = NULL; if (read_soa == 0) @@ -1276,62 +1083,45 @@ db_load(const char *filename, const char *in_origin, zp->z_origin, filename, msg); } } - } - if (!def_domain) { - if (errs) + while (filenames) { + fn = filenames; + filenames = filenames->next; + freestr(fn->name); + memput(fn, sizeof *fn); + } + if (errs != 0) ns_warning(ns_log_load, "%s zone \"%s\" (%s) rejected due to errors (serial %u)", - zoneTypeString(zp), zp->z_origin, + zoneTypeString(zp->z_type), zp->z_origin, p_class(zp->z_class), zp->z_serial); else ns_info(ns_log_load, "%s zone \"%s\" (%s) loaded (serial %u)", - zoneTypeString(zp), zp->z_origin, + zoneTypeString(zp->z_type), zp->z_origin, p_class(zp->z_class), zp->z_serial); } - if (errs) { + if (errs != 0) { zp->z_flags |= Z_DB_BAD; zp->z_ftime = 0; } #ifdef BIND_NOTIFY - if (!errs && !def_domain && - (zp->z_type == z_master || zp->z_type == z_slave)) { - static const char no_room[] = - "%s failed, cannot notify for zone %s"; - notify_info ni; - - ni = memget(sizeof *ni); - if (ni == NULL) - ns_info(ns_log_load, no_room, "memget", zp->z_origin); - else { - ni->name = savestr(zp->z_origin, 0); - if (ni->name == NULL) { - memput(ni, sizeof *ni); - ns_info(ns_log_load, no_room, - "memget", zp->z_origin); - } else { - ni->class = zp->z_class; - ni->state = notify_info_waitfor; - if (evWaitFor(ev, - (const void *)notify_after_load, - notify_after_load, ni, - &ni->wait_id) < 0) { - ns_error(ns_log_load, - "evWaitFor() failed: %s", - strerror(errno)); - freestr(ni->name); - memput(ni, sizeof *ni); - } else { - APPEND(pending_notifies, ni, link); - ns_need(MAIN_NEED_NOTIFY); - } - } - } - } + if (errs == 0 && (!ininclude) && + (zp->z_type == z_master || zp->z_type == z_slave)) + ns_notify(zp->z_origin, zp->z_class, ns_t_soa); #endif return (errs); } +void +db_err(int err, char *domain, int type, const char *filename, int lineno) { + if (filename != NULL && err == CNAMEANDOTHER) + ns_notice(ns_log_load, "%s:%d:%s: CNAME and OTHER data error", + filename, lineno, domain); + if (err != DATAEXISTS) + ns_debug(ns_log_load, 1, "update failed %s %d", + domain, type); +} + static int gettoken(FILE *fp, const char *src) { int c; @@ -1350,11 +1140,15 @@ gettoken(FILE *fp, const char *src) { return (INCLUDE); if (!strcasecmp("origin", op)) return (ORIGIN); + if (!strcasecmp("generate", op)) + return (GENERATE); + if (!strcasecmp("ttl", op)) + return (DEFAULTTTL); } ns_notice(ns_log_db, "%s:%d: Unknown $ option: $%s", src, lineno, op); - return (ERROR); + return (ERRTOK); case ';': while ((c = getc(fp)) != EOF && c != '\n') @@ -1375,6 +1169,10 @@ gettoken(FILE *fp, const char *src) { lineno++; continue; + case '\r': + if (NS_OPTION_P(OPTION_TREAT_CR_AS_SPACE) != 0) + return (CURRENT); + default: (void) ungetc(c, fp); return (DNAME); @@ -1391,6 +1189,7 @@ gettoken(FILE *fp, const char *src) { * size - of destination * fp - file to read from * preserve - should we preserve \ before \\ and \.? + * if preserve == 2, then keep all \ * return value: * 0 = no word; perhaps EOL or EOF; lineno was incremented. * 1 = word was read @@ -1398,10 +1197,12 @@ gettoken(FILE *fp, const char *src) { int getword(char *buf, size_t size, FILE *fp, int preserve) { char *cp = buf; - int c, spaceok; + int c, spaceok, once; empty_token = 0; /* XXX global side effect. */ + once = 0; while ((c = getc(fp)) != EOF) { + once++; if (c == ';') { /* Comment. Skip to end of line. */ while ((c = getc(fp)) != EOF && c != '\n') @@ -1427,6 +1228,9 @@ getword(char *buf, size_t size, FILE *fp, int preserve) { c = '\\'; if (preserve) switch (c) { + default: + if (preserve == 1) + break; case '\\': case '.': case '0': @@ -1474,6 +1278,9 @@ getword(char *buf, size_t size, FILE *fp, int preserve) { c = '\\'; if (preserve) switch (c) { + default: + if (preserve == 1) + break; case '\\': case '.': case '0': @@ -1510,6 +1317,8 @@ getword(char *buf, size_t size, FILE *fp, int preserve) { *cp = '\0'; if (cp == buf) empty_token = 1; + if (!once) + lineno++; return (cp != buf); } @@ -1524,7 +1333,7 @@ getword(char *buf, size_t size, FILE *fp, int preserve) { * side effects: * *ttl is written if the return value is to be 1. */ -static int +int getttl(FILE *fp, const char *fn, int lineno, u_int32_t *ttl, int *multiline) { char buf[MAXDATA]; u_long tmp; @@ -1748,6 +1557,103 @@ getnonblank(FILE *fp, const char *src) { } /* + * Replace all single "$"'s in "name" with "it". + * ${delta} will add delta to "it" before printing. + * ${delta,width} will change print width as well, zero fill is implied + * ${delta,width,radix} will change radix as well, can be d, o, x, X. + * i.e. ${0,2,X} will produce a two digit hex (upper case) with zero fill. + * Append "origin" to name if required and validate result with makename. + * To get a "$" or "{" in the output use \ before it. + * Return 0 on no error or -1 on error. + * Resulting name stored in "buf". + */ + +static int +genname(char *name, int it, const char *origin, char *buf, int size) { + char *bp = buf; + char *eom = buf + size; + char *cp; + char numbuf[32]; + char fmt[32]; + int delta = 0; + int width; + + while (*name) { + if (*name == '$') { + if (*(++name) == '$') { + /* should be deprecated. how? */ + if (bp >= eom) + return (-1); + *bp++ = *name++; + } else { + strcpy(fmt, "%d"); + if (*name == '{') { + switch (sscanf(name, "{%d,%d,%1[doxX]}", &delta, &width, numbuf)) { + case 1: + break; + case 2: + sprintf(fmt, "%%0%dd", width); + break; + case 3: + sprintf(fmt, "%%0%d%c", width, numbuf[0]); + break; + default: + return (-1); + } + while (*name && *name++ != '}') { + continue; + } + } + sprintf(numbuf, fmt, it + delta); + cp = numbuf; + while (*cp) { + if (bp >= eom) + return (-1); + *bp++ = *cp++; + } + } + } else if (*name == '\\') { + if (*(++name) == '\0') { + if (bp >= eom) + return (-1); + *bp++ = '\\'; + } else { + switch (*name) { + case '\\': + case '.': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (bp >= eom) + return (-1); + *bp++ = '\\'; + default: + if (bp >= eom) + return (-1); + *bp++ = *name++; + } + } + } else { + if (bp >= eom) + return (-1); + *bp++ = *name++; + } + } + if (bp >= eom) + return (-1); + *bp = '\0'; + return (origin == NULL ? 0 : makename(buf, origin, size)); +} + + +/* * Take name and fix it according to following rules: * "." means root. * "@" means current origin. @@ -1786,7 +1692,7 @@ makename(char *name, const char *origin, int size) { return (0); } -static int +int makename_ok(char *name, const char *origin, int class, struct zoneinfo *zp, enum transport transport, enum context context, const char *owner, const char *filename, int lineno, int size) @@ -1798,7 +1704,7 @@ makename_ok(char *name, const char *origin, int class, struct zoneinfo *zp, filename, lineno); return (0); } - if (!ns_nameok(name, class, zp, transport, context, owner, + if (!ns_nameok(NULL, name, class, zp, transport, context, owner, inaddr_any)) { ns_info(ns_log_db, "%s:%d: database naming error", filename, lineno); @@ -1928,91 +1834,6 @@ wordtouint32(buf) return (res2); } - -/* - * Parse part of a date. Set error flag if any error. - * Don't reset the flag if there is no error. - */ -static int -datepart(const char *buf, int size, int min, int max, int *errp) { - int result = 0; - int i; - - for (i = 0; i < size; i++) { - if (!isdigit(buf[i])) - *errp = 1; - result = (result * 10) + buf[i] - '0'; - } - if (result < min) - *errp = 1; - if (result > max) - *errp = 1; - return (result); -} - - -/* Convert a date in ASCII into the number of seconds since - 1 January 1970 (GMT assumed). Format is yyyymmddhhmmss, all - digits required, no spaces allowed. */ - -static u_int32_t -datetosecs(const char *cp, int *errp) { - struct tm time; - u_int32_t result; - int mdays, i; - static const int days_per_month[12] = - {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - - if (strlen(cp) != 14) { - *errp = 1; - return 0; - } - *errp = 0; - - memset(&time, 0, sizeof time); - time.tm_year = datepart(cp + 0, 4, 1990, 9999, errp) - 1900; - time.tm_mon = datepart(cp + 4, 2, 01, 12, errp) - 1; - time.tm_mday = datepart(cp + 6, 2, 01, 31, errp); - time.tm_hour = datepart(cp + 8, 2, 00, 23, errp); - time.tm_min = datepart(cp + 10, 2, 00, 59, errp); - time.tm_sec = datepart(cp + 12, 2, 00, 59, errp); - if (*errp) /* Any parse errors? */ - return (0); - - /* - * OK, now because timegm() is not available in all environments, - * we will do it by hand. Roll up sleeves, curse the gods, begin! - */ - -#define SECS_PER_DAY ((u_int32_t)24*60*60) -#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) - - result = time.tm_sec; /* Seconds */ - result += time.tm_min * 60; /* Minutes */ - result += time.tm_hour * (60*60); /* Hours */ - result += (time.tm_mday - 1) * SECS_PER_DAY; /* Days */ - - /* Months are trickier. Look without leaping, then leap */ - mdays = 0; - for (i = 0; i < time.tm_mon; i++) - mdays += days_per_month[i]; - result += mdays * SECS_PER_DAY; /* Months */ - if (time.tm_mon > 1 && isleap (1900+time.tm_year)) - result += SECS_PER_DAY; /* Add leapday for this year */ - - /* First figure years without leapdays, then add them in. */ - /* The loop is slow, FIXME, but simple and accurate. */ - result += (time.tm_year - 70) * (SECS_PER_DAY*365); /* Years */ - for (i = 70; i < time.tm_year; i++) - if (isleap (1900+i)) - result += SECS_PER_DAY; /* Add leapday for prev year */ - - return (result); -} - - -#define MAXCHARSTRING 255 - static int getcharstring(char *buf, char *data, int type, int minfields, int maxfields, @@ -2029,7 +1850,7 @@ getcharstring(char *buf, char *data, int type, if (type == ns_t_txt || type == ns_t_x25) { while (i > MAXCHARSTRING && n + MAXCHARSTRING + 1 < MAXDATA) { - data[n] = MAXCHARSTRING; + data[n] = (char)MAXCHARSTRING; memmove(data + n + 1, b, MAXCHARSTRING); n += MAXCHARSTRING + 1; b += MAXCHARSTRING; @@ -2040,13 +1861,13 @@ getcharstring(char *buf, char *data, int type, if (i > MAXCHARSTRING) { ns_info(ns_log_db, "%s:%d: RDATA field %d too long", - src, lineno, nfield); + src, lineno -1, nfield); return (0); } if (n + i + 1 > MAXDATA) { ns_info(ns_log_db, "%s:%d: total RDATA too long", - src, lineno); + src, lineno -1); return (0); } data[n] = i; @@ -2058,7 +1879,7 @@ getcharstring(char *buf, char *data, int type, if (nfield < minfields) { ns_info(ns_log_db, "%s:%d: expected %d RDATA fields, only saw %d", - src, lineno, minfields, nfield); + src, lineno -1, minfields, nfield); return (0); } @@ -2083,18 +1904,18 @@ getcharstring(char *buf, char *data, int type, static int get_nxt_types(u_char *data, FILE *fp, const char *filename) { char b[MAXLABEL]; /* Not quite the right size, but good enough */ - int maxtype=0; + int maxtype=0; int success; int type; int errs = 0; - memset(data, 0, ns_t_any/NS_NXT_BITS+1); + memset(data, 0, NS_NXT_MAX/NS_NXT_BITS+1); while (getmlword(b, sizeof(b), fp, 0)) { if (feof(fp) || ferror(fp)) - break; + break; if (strlen(b) == 0 || b[0] == '\n') - continue; + continue; /* Parse RR type (A, MX, etc) */ type = sym_ston(__p_type_syms, (char *)b, &success); @@ -2106,7 +1927,7 @@ get_nxt_types(u_char *data, FILE *fp, const char *filename) { continue; } NS_NXT_BIT_SET(type, data); - if (type > maxtype) + if (type > maxtype) maxtype = type; } if (errs) @@ -2157,62 +1978,623 @@ fixup_soa(const char *fn, struct zoneinfo *zp) { fn, zp->z_refresh, zp->z_retry); } -#ifdef BIND_NOTIFY -static void -free_notify_info(notify_info ni) { - if (ni->state == notify_info_waitfor) - evUnwait(ev, ni->wait_id); - else if (ni->state == notify_info_delay) - evClearTimer(ev, ni->timer_id); - freestr(ni->name); - memput(ni, sizeof *ni); -} +/* this function reads in the sig record rdata from the input file and + * returns the following codes + * > 0 length of the recrod + * ERR_EOF end of file + * + */ -void -notify_after_load(evContext ctx, void *uap, const void *tag) { - int delay, max_delay; - notify_info ni = uap; +static int +parse_sig_rr(char *buf, int buf_len, u_char *data, int data_size, + FILE *fp, struct zoneinfo *zp, char *domain, u_int32_t ttl, + enum context domain_ctx, enum transport transport, char **errmsg) +{ +/* The SIG record looks like this in the db file: + Name Cl SIG RRtype Algid [OTTL] Texp Tsig Kfoot Signer Sig + + where: Name and Cl are as usual + SIG is a keyword + RRtype is a char string + ALGid is 8 bit u_int + Labels is 8 bit u_int + OTTL is 32 bit u_int (optionally present) + Texp is YYYYMMDDHHMMSS + Tsig is YYYYMMDDHHMMSS + Kfoot is 16-bit unsigned decimal integer + Signer is a char string + Sig is 64 to 319 base-64 digits + A missing OTTL is detected by the magnitude of the Texp value + that follows it, which is larger than any u_int. + The Labels field in the binary RR does not appear in the + text RR. + + It's too crazy to run these pages of SIG code at the right + margin. I'm exdenting them for readability. +*/ + u_int32_t sig_type; + int dateerror; + int siglen, success; + u_char *cp; + u_int32_t al, la, n; + u_int32_t signtime, exptime, timetilexp; + u_int32_t origTTL; + enum context context; + time_t now; + char *errtype = "SIG error"; + int i, my_buf_size = MAXDATA, errs = 0; + + + /* The TTL gets checked against the Original TTL, + and bounded by the signature expiration time, which + are both under the signature. We can't let TTL drift + based on the SOA record. If defaulted, fix it now. + (It's not clear to me why USE_MINIMUM isn't eliminated + before putting ALL RR's into the database. -gnu@toad.com) */ + if (ttl == USE_MINIMUM) + ttl = zp->z_minimum; + + i = 0; + data[i] = '\0'; + + getmlword_nesting = 0; /* KLUDGE err recovery */ - INSIST(tag == (const void *)notify_after_load); - - /* delay notification for from five seconds up to fifteen minutes */ - max_delay = MIN(nzones/5, 895); - max_delay = MAX(max_delay, 25); - delay = 5 + (rand() % max_delay); - ns_debug(ns_log_notify, 3, "notify_after_load: uap %p tag %p delay %d", - uap, tag, delay); - if (evSetTimer(ctx, notify_after_delay, ni, - evAddTime(evNowTime(), evConsTime(delay, 0)), - evConsTime(0, 0), &ni->timer_id) < 0) { - ns_error(ns_log_notify, "evSetTimer() failed: %s", - strerror(errno)); - UNLINK(pending_notifies, ni, link); - ni->state = notify_info_error; - free_notify_info(ni); + /* RRtype (char *) + * if old style inp will contain the next token + *copy that into buffer, otherwise read from file + */ + if (buf && buf_len == 0) + if (!getmlword((char*)buf, my_buf_size, fp, 0)) + ERRTO("SIG record doesn't specify type"); + sig_type = sym_ston(__p_type_syms, buf, &success); + if (!success || sig_type == ns_t_any) { + /* + * We'll also accept a numeric RR type, + * for signing RR types that this version + * of named doesn't yet understand. + * In the ns_t_any case, we rely on wordtouint32 + * to fail when scanning the string "ANY". + */ + sig_type = wordtouint32 (buf); + if (wordtouint32_error || sig_type > 0xFFFF) + ERRTO("Unknown RR type in SIG record"); + } + cp = &data[i]; + PUTSHORT((u_int16_t)sig_type, cp); + i += 2; + + /* Algorithm id (8-bit decimal) */ + if (!getmlword(buf, my_buf_size, fp, 0)) + ERRTO("Missing algorithm ID"); + al = wordtouint32(buf); + if (0 == al || wordtouint32_error || 255 <= al) + ERRTO("Bad algorithm number"); + data[i] = (u_char) al; + i++; + + /* + * Labels (8-bit decimal) + */ + if (!getmlword(buf, my_buf_size, fp, 0)) + ERRTO("Missing label count"); + la = wordtouint32(buf); + if (0 == la || wordtouint32_error || 255 <= la) + ERRTO("Bad label count number"); + data[i] = (u_char) la; + i++; + + /* + * OTTL (optional u_int32_t) and + * Texp (u_int32_t date) + */ + if (!getmlword(buf, my_buf_size, fp, 0)) + ERRTO("OTTL and expiration time missing"); + /* + * See if OTTL is missing and this is a date. + * This relies on good, silent error checking + * in ns_datetosecs. + */ + exptime = ns_datetosecs(buf, &dateerror); + if (!dateerror) { + /* Output TTL as OTTL */ + origTTL = ttl; + cp = &data[i]; + PUTLONG (origTTL, cp); + i += 4; + } else { + /* Parse and output OTTL; scan TEXP */ + origTTL = wordtouint32(buf); + if (0 >= origTTL || wordtouint32_error || + (origTTL > 0x7fffffff)) + ERRTO("Original TTL value bad"); + cp = &data[i]; + PUTLONG(origTTL, cp); + i += 4; + if (!getmlword(buf, my_buf_size, fp, 0)) + ERRTO("Expiration time missing"); + exptime = ns_datetosecs(buf, &dateerror); } - ni->state = notify_info_delay; + if (dateerror || exptime > 0x7fffffff || exptime <= 0) + ERRTO("Invalid expiration time"); + cp = &data[i]; + PUTLONG(exptime, cp); + i += 4; + + /* Tsig (u_int32_t) */ + if (!getmlword(buf, my_buf_size, fp, 0)) + ERRTO("Missing signature time"); + signtime = ns_datetosecs(buf, &dateerror); + if (0 == signtime || dateerror) + ERRTO("Invalid signature time"); + cp = &data[i]; + PUTLONG(signtime, cp); + i += 4; + + /* Kfootprint (unsigned_16) */ + if (!getmlword(buf, my_buf_size, fp, 0)) + ERRTO("Missing key footprint"); + n = wordtouint32(buf); + if (wordtouint32_error || n >= 0x0ffff) + ERRTO("Invalid key footprint"); + cp = &data[i]; + PUTSHORT((u_int16_t)n, cp); + i += 2; + + /* Signer's Name */ + if (!getmlword((char*)buf, my_buf_size, fp, 0)) + ERRTO("Missing signer's name"); + cp = &data[i]; + strcpy((char *)cp, buf); + context = domain_ctx; + MAKENAME_OKZP((char *)cp, data_size); + i += strlen((char *)cp) + 1; + + /* + * Signature (base64 of any length) + * We don't care what algorithm it uses or what + * the internal structure of the BASE64 data is. + */ + if (!getallwords(buf, my_buf_size, fp, 0)) { + siglen = 0; + } else { + cp = &data[i]; + siglen = b64_pton(buf, (u_char*)cp, data_size - i); + if (siglen < 0) + ERRTO("Signature block bad"); + } + + /* set total length and we're done! */ + n = i + siglen; + + /* + * Check signature time, expiration, and adjust TTL. Note + * that all time values are in GMT (UTC), *not* local time. + */ + + now = time (0); /* need to find a better place for this XXX ogud */ + /* Don't let bogus name servers increase the signed TTL */ + if (ttl > origTTL) + ERRTO("TTL is greater than signed original TTL"); + + /* Don't let bogus signers "sign" in the future. */ + if (signtime > (u_int32_t)now) + ERRTO("signature time is in the future"); + + /* Ignore received SIG RR's that are already expired. */ + if (exptime <= (u_int32_t)now) + ERRTO("expiration time is in the past"); + + /* Lop off the TTL at the expiration time. */ + timetilexp = exptime - now; + if (timetilexp < ttl) { + ns_debug(ns_log_load, 1, + "shrinking expiring %s SIG TTL from %d to %d", + p_secstodate(exptime), ttl, timetilexp); + ttl = timetilexp; + } + + /* + * Check algorithm-ID and key structure, for + * the algorithm-ID's that we know about. + */ + switch (al) { + case NS_ALG_MD5RSA: + if (siglen == 0) + ERRTO("No key for RSA algorithm"); + if (siglen < 1) + ERRTO("Signature too short"); + if (siglen > (NS_MD5RSA_MAX_BITS + 7) / 8) + ERRTO("Signature too long"); + break; + + case NS_ALG_DH: + if (siglen < 1) + ERRTO("DH Signature too short"); + break; /* need more tests here */ + + case NS_ALG_DSA: + if (siglen < NS_DSA_SIG_SIZE) + ERRTO("DSS Signature too short"); + else if (siglen > NS_DSA_SIG_SIZE) + ERRTO("DSS Signature too long "); + break; /* need more tests here */ + + case NS_ALG_EXPIRE_ONLY: + if (siglen != 0) + ERRTO( + "Signature supplied to expire-only algorithm"); + break; + case NS_ALG_PRIVATE_OID: + if (siglen == 0) + ERRTO("No ObjectID in key"); + break; + default: + ERRTO("UNKOWN SIG algorithm"); + } + + /* Should we complain about algorithm-ID's that we + don't understand? It may help debug some obscure + cases, but in general we should accept any RR whether + we could cryptographically process it or not; it + may be being published for some newer DNS clients + to validate themselves. */ + + endline(fp); /* flush the rest of the line */ + + return (n); + err: + *errmsg = errtype; + return (-1); } -static void -notify_after_delay(evContext ctx, void *uap, - struct timespec due, - struct timespec inter) +static int +parse_nxt_rr(char *buf, int buf_len, u_char *data, int data_size, + FILE *fp, struct zoneinfo *zp, char *domain, enum context context, + enum transport transport, char **errmsg) { - notify_info ni = uap; + + /* The NXT record looks like: + Name Cl NXT nextname RRT1 RRT2 MX A SOA ... + + where: Name and Cl are as usual + NXT is a keyword + nextname is the next valid name in the zone after "Name". + All names between the two are known to be nonexistent. + RRT's... are a series of RR type names, which indicate that + RR's of these types are published for "Name", and + that no RR's of any other types are published for "Name". + + When a NXT record is cryptographically signed, it proves the + nonexistence of an RR (actually a whole set of RR's). + */ + int n, errs = 0, i; + u_char *cp; +/* char *origin = zp->z_origin; + int class = zp->z_class; */ + *errmsg = "NXT name error"; + + (void) strcpy((char *)data, buf); + MAKENAME_OKZP((char *)data, data_size); + n = strlen((char *)data) + 1; + cp = n + data; + i = get_nxt_types(cp, fp, zp->z_source); + if( i > 0) + return (n + i); + *errmsg = "NXT type error"; + err: + return (-1); +} - UNLINK(pending_notifies, ni, link); - ni->state = notify_info_done; - sysnotify(ni->name, ni->class, ns_t_soa); - free_notify_info(ni); + +static int +parse_cert_rr(char *buf, int buf_len, u_char *data, int data_size, + FILE *fp, char **errmsg) +{ + /* Cert record looks like: + * Type Key_tag Alg Cert + * Type: certification type number (16) + * Key_tag: tag of corresponding KEY RR (16) + * Alg: algorithm of the KEY RR (8) + * Cert: base64 enocded block + */ + u_char *cp; + u_int32_t cert_type, key_tag, alg; + char *errtype = "CERT parse error"; + int certlen, i, n, success; + + i = 0; + cp = &data[i]; + cert_type = sym_ston(__p_cert_syms, buf, &success); + if (!success) { + cert_type = wordtouint32(buf); + if (wordtouint32_error || cert_type > 0xFFFF) + ERRTO("CERT type out of range"); + } + PUTSHORT((u_int16_t)cert_type, cp); + i += INT16SZ; + + if (!getmlword((char*)buf, buf_len, fp, 0)) + ERRTO("CERT doesn't specify type"); + + key_tag = wordtouint32(buf); + if (wordtouint32_error || key_tag > 0xFFFF) + ERRTO("CERT KEY tag out of range"); + + PUTSHORT((u_int16_t)key_tag, cp); + i += INT16SZ; + + if (!getmlword(buf, buf_len, fp, 0)) + ERRTO("CERT missing algorithm ID"); + + alg = sym_ston(__p_key_syms, buf, &success); + if (!success) { + alg = wordtouint32(buf); + if (wordtouint32_error || alg > 0xFF) + ERRTO("CERT KEY alg out of range"); + } + + data[i++] = (u_char)alg; + + if (!getallwords(buf, buf_len, fp, 0)) { + certlen = 0; + } + else { + cp = &data[i]; + certlen = b64_pton(buf, (u_char*)cp, sizeof(data) - i); + if (certlen < 0) + ERRTO("CERT blob has encoding error"); + } + /* set total length */ + n = i + certlen; + return (n); + err: + *errmsg = errtype; + return (-1); + } -void -db_cancel_pending_notifies(void) { - notify_info ni, ni_next; - for (ni = HEAD(pending_notifies); ni != NULL; ni = ni_next) { - ni_next = NEXT(ni, link); - free_notify_info(ni); +static int +parse_key_rr(char *buf, int buf_len, u_char *data, int data_size, + FILE *fp, struct zoneinfo *zp, char *domain, enum context context, + enum transport transport, char **errmsg) +{ + /* The KEY record looks like this in the db file: + * Name Cl KEY Flags Proto Algid PublicKeyData + * where: + * Name,Cl per usual + * KEY RR type + * Flags 4 digit hex value (unsigned_16) + * Proto 8 bit u_int + * Algid 8 bit u_int + * PublicKeyData + * a string of base64 digits, + * skipping any embedded whitespace. + */ + u_int32_t al, pr; + int nk, klen,i, n; + u_int32_t keyflags; + char *errtype = "KEY error"; + u_char *cp, *expstart; + u_int expbytes, modbytes; + + i = n = 0; + data[i] = '\0'; + cp = data; + getmlword_nesting = 0; /* KLUDGE err recov. */ + + /*>>> Flags (unsigned_16) */ + keyflags = wordtouint32(buf); + if (wordtouint32_error || 0xFFFF < keyflags) + ERRTO("KEY flags error"); + if (keyflags & NS_KEY_RESERVED_BITMASK) + ERRTO("KEY Reserved Flag Bit"); + PUTSHORT(keyflags, cp); + + /*>>> Protocol (8-bit decimal) */ + if (!getmlword((char*)buf, buf_len, fp, 0)) + ERRTO("KEY Protocol Field"); + pr = wordtouint32(buf); + if (wordtouint32_error || 255 < pr) + ERRTO("KEY Protocol Field"); + *cp++ = (u_char) pr; + + /*>>> Algorithm id (8-bit decimal) */ + if (!getmlword((char*)buf, buf_len, fp, 0)) + ERRTO("KEY Algorithm ID"); + al = wordtouint32(buf); + if (wordtouint32_error || 0 == al || 255 == al || 255 < al) + ERRTO("KEY Algorithm ID"); + *cp++ = (u_char) al; + + /*>>> Extended KEY flag field in bytes 5 and 6 */ + if (NS_KEY_EXTENDED_FLAGS & keyflags) { + u_int32_t keyflags2; + + if (!getmlword((char*)buf, buf_len, fp, 0)) + ERRTO("KEY Flags Field"); + keyflags2 = wordtouint32(buf); + if (wordtouint32_error || 0xFFFF < keyflags2) + ERRTO("Extended key flags error"); + if (keyflags2 & NS_KEY_RESERVED_BITMASK2) + ERRTO("KEY Reserved Flag2 Bit"); + PUTSHORT(keyflags2, cp); + } + + /*>>> Public Key data is in BASE64. + * We don't care what algorithm it uses or what + * the internal structure of the BASE64 data is. + */ + if (!getallwords(buf, MAXDATA, fp, 0)) + klen = 0; + else { + /* Convert from BASE64 to binary. */ + klen = b64_pton(buf, (u_char*)cp, + data_size - (cp - data)); + if (klen < 0) + ERRTO("KEY Public Key"); + } + + /* set total length */ + n = klen + (cp - data); + + /* + * Now check for valid key flags & algs & etc, from the RFC. + */ + + if (NS_KEY_TYPE_NO_KEY == (keyflags & NS_KEY_TYPEMASK)) + nk = 1; /* No-key */ + else + nk = 0; /* have a key */ + + if ((keyflags & (NS_KEY_NAME_TYPE | NS_KEY_TYPEMASK)) == + (NS_KEY_NAME_ZONE | NS_KEY_TYPE_CONF_ONLY)) + /* Zone key must have Auth bit set. */ + ERRTO("KEY Zone Key Auth. bit"); + + if (al == 0 && nk == 0) + ERRTO("KEY Algorithm"); + if (al != 0 && pr == 0) + ERRTO("KEY Protocols"); + + if (nk == 1 && klen != 0) + ERRTO("KEY No-Key Flags Set"); + + if (nk == 0 && klen == 0) + ERRTO("KEY Type Spec'd"); + + /* + * Check algorithm-ID and key structure, for the algorithm-ID's + * that we know about. + */ + switch (al) { + case NS_ALG_MD5RSA: + if (klen == 0) + break; + expstart = cp; + expbytes = *expstart++; + if (expbytes == 0) + GETSHORT(expbytes, expstart); + + if (expbytes < 1) + ERRTO("Exponent too short"); + if (expbytes > (NS_MD5RSA_MAX_BITS + 7) / 8) + ERRTO("Exponent too long"); + if (*expstart == 0) + ERRTO("Exponent w/ 0"); + + modbytes = klen - (expbytes + (expstart - cp)); + if (modbytes < (NS_MD5RSA_MIN_BITS + 7) / 8) + ERRTO("Modulus too short"); + if (modbytes > (NS_MD5RSA_MAX_BITS + 7) / 8) + ERRTO("Modulus too long"); + if (*(expstart+expbytes) == 0) + ERRTO("Modulus starts w/ 0"); + break; + + case NS_ALG_DH: { + u_char *dh_cp; + u_int16_t dh_len, plen, glen, ulen; + + dh_cp = (u_char *)cp; + GETSHORT(plen, dh_cp); + if(plen < 16) + ERRTO("DH short plen"); + dh_len = 2 + plen; + if(dh_len > klen) + ERRTO("DH plen > klen"); + + GETSHORT(glen, dh_cp); + if(glen <= 0 || glen > plen) + ERRTO("DH glen bad"); + dh_len = 2 + glen; + if(dh_len > klen) + ERRTO("DH glen > klen"); + + GETSHORT(ulen, dh_cp); + if(ulen <= 0 || ulen > plen) + ERRTO("DH ulen bad"); + dh_len = 2 + ulen; + if(dh_len > klen) + ERRTO("DH ulen > klen"); + else if (dh_len < klen) + ERRTO("DH *len < klen"); + break; } - INIT_LIST(pending_notifies); + + case NS_ALG_DSA: { + u_int8_t t; + + if ( klen == 0) + break; + t = *cp; + if (t > 8) + ERRTO("DSA T value"); + if (klen != (1 + 20 + 3 *(64+8*t))) + ERRTO("DSA length"); + break; + } + + case NS_ALG_PRIVATE_OID: + if (klen == 0) + ERRTO("No ObjectID in key"); + break; + default: + ERRTO("Unknown Key algorithm"); + } + + endline(fp); /* flush the rest of the line */ + return (n); + err: + *errmsg = errtype; + return (-1); +} /*T_KEY*/ + +/* + * function to invoke DNSSEC specific parsing routines. + * this is simpler than copying these complicated blocks into the + * multiple souce files that read files (ixfr, nsupdate etc..). + * this code should be in a library rather than in this file but + * what the heck for now (ogud@tislabs.com) + */ +int +parse_sec_rdata(char *buf, int buf_len, int buf_full, u_char *data, + int data_size, FILE *fp, struct zoneinfo *zp, + char *domain, u_int32_t ttl, int type, enum context context, + enum transport transport, char **errmsg) +{ + int ret = -1; + + getmlword_nesting = 0; /* KLUDGE err recov. */ + if (!buf_full && buf && buf_len != 0) /* check if any data in buf */ + if (!getmlword(buf, buf_len, fp, 1)) { + *errmsg = "unexpected end of input"; + goto err; + } + + switch (type) { + case ns_t_sig: + ret = parse_sig_rr(buf, buf_len, data, data_size, fp, zp, + domain, ttl, context, transport, errmsg); + break; + case ns_t_key: + ret = parse_key_rr(buf, buf_len, data, data_size, fp, zp, + domain, context, transport, errmsg); + break; + case ns_t_nxt: + ret = parse_nxt_rr(buf, buf_len, data, data_size, fp, zp, + domain, context, transport, errmsg); + break; + case ns_t_cert: + ret = parse_cert_rr(buf, buf_len, data, data_size, fp, errmsg); + break; + default: + ret = -1; + *errmsg = "parse_sec_rdata():Unsupported SEC type type"; + goto err; + } + return (ret); + err: + endline(fp); + return (ret); } -#endif + diff --git a/contrib/bind/bin/named/db_lookup.c b/contrib/bind/bin/named/db_lookup.c index ddf17ad..400523e 100644 --- a/contrib/bind/bin/named/db_lookup.c +++ b/contrib/bind/bin/named/db_lookup.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)db_lookup.c 4.18 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: db_lookup.c,v 8.13 1998/02/13 19:52:54 halley Exp $"; +static const char sccsid[] = "@(#)db_lookup.c 4.18 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: db_lookup.c,v 8.24 1999/10/15 19:48:58 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: db_lookup.c,v 8.13 1998/02/13 19:52:54 halley Exp $" */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -82,6 +82,7 @@ static char rcsid[] = "$Id: db_lookup.c,v 8.13 1998/02/13 19:52:54 halley Exp $" #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -139,11 +140,7 @@ nlookup(const char *name, struct hashbuf **htpp, break; } - /* rotate left HASHSHIFT */ - hval = (hval << HASHSHIFT) | - (hval>>((sizeof(hval)*8)-HASHSHIFT)); - hval += ((isascii(c) && isupper(c)) ? tolower(c) : c) - & HASHMASK; + HASHIMILATE(hval, c); if (escaped) escaped = 0; else if (c == '\\') @@ -186,7 +183,7 @@ nlookup(const char *name, struct hashbuf **htpp, np->n_next = htp->h_tab[hval]; htp->h_tab[hval] = np; /* Increase hash table size. */ - if (++htp->h_cnt > htp->h_size * 2) { + if (++htp->h_cnt > (htp->h_size * AVGCH_NLOOKUP)) { *htpp = savehash(htp); if (parent == NULL) { if (htp == hashtab) { @@ -209,12 +206,10 @@ nlookup(const char *name, struct hashbuf **htpp, * This is tricky since the parent of "com" is "" and both are stored * in the same hashbuf. * See also: - * the AXFR wart description in ns_req.c + * the AXFR wart description in ns_axfr.c */ struct namebuf * -np_parent(np) - struct namebuf *np; -{ +np_parent(struct namebuf *np) { struct hashbuf *htp; struct namebuf *np2; @@ -228,19 +223,17 @@ np_parent(np) /* Search the hash chain that np should be part of. */ for (np2 = htp->h_tab[np->n_hashval % htp->h_size]; np2 != NULL; - np2 = np2->n_next) { - + np2 = np2->n_next) + { if (np == np2) { /* found it! */ /* "" hashes into the first bucket */ - for (np = htp->h_tab[0]; np ; np=np->n_next) { + for (np = htp->h_tab[0]; np != NULL; np = np->n_next) { if (NAME(*np)[0] == '\0') /* found the root namebuf */ return (np); } - ns_debug(ns_log_db, 1, - "np_parent(0x%lx) couldn't find root entry", - (u_long) np); - return (NULL); /* XXX shouldn't happen */ + /* there are no RR's with a owner name of "." yet */ + return (NULL); } } /* Try the hints. */ @@ -248,7 +241,7 @@ np_parent(np) htp = fcachetab; goto try_again; } - ns_debug(ns_log_db, 1, "np_parent(0x%lx) couldn't namebuf", + ns_debug(ns_log_db, 1, "np_parent(0x%lx) couldn't find namebuf", (u_long)np); return (NULL); /* XXX shouldn't happen */ } @@ -263,7 +256,76 @@ int match(struct databuf *dp, int class, int type) { if (dp->d_class != class && class != C_ANY) return (0); - if (dp->d_type != type && type != T_ANY) + if (dp->d_type != type && dp->d_type != T_SIG && type != T_ANY) + return (0); + if (type != T_SIG && dp->d_type == T_SIG && SIG_COVERS(dp) != type) return (0); return (1); } + +/* static int + * nxtlower(name, dp) + * Is the NXT/SIG NXT record 'lower'? + * return value: + * boolean + */ +static int +nxtlower(const char *name, struct databuf *dp) { + /* An NXT is a lower NXT iff the SOA bit is set in the bitmap */ + if (dp->d_type == T_NXT) { + u_char *nxtbitmap = dp->d_data + strlen((char *)dp->d_data) + 1; + return (NS_NXT_BIT_ISSET(T_SOA, nxtbitmap) ? 1 : 0); + } + /* If it's not an NXT, it's a SIG NXT. An NXT record must be signed + * by the zone, so the signer name must be the same as the owner. + */ + return (ns_samename(name, (char *)dp->d_data + SIG_HDR_SIZE) != 1 ? 0 : 1); +} + +/* int + * nxtmatch(name, dp1, dp2) + * Do NXT/SIG NXT records `dp1' and `dp2' belong to the same NXT set? + * return value: + * boolean + */ +int +nxtmatch(const char *name, struct databuf *dp1, struct databuf *dp2) { + int dp1_lower, dp2_lower; + + if (dp1->d_type != ns_t_nxt || dp2->d_type != ns_t_nxt) + return (0); + dp1_lower = nxtlower(name, dp1); + dp2_lower = nxtlower(name, dp2); + return (dp1_lower == dp2_lower); +} + +/* int + * rrmatch(name, dp1, dp2) + * Do data records `dp1' and `dp2' match in class and type? + * If both are NXTs, do they belong in the same NXT set? + * If both are SIGs, do the covered types match? + * If both are SIG NXTs, do the covered NXTs belong in the same set? + * Why is DNSSEC so confusing? + * return value: + * boolean + */ +int +rrmatch(const char *name, struct databuf *dp1, struct databuf *dp2) { + if (dp1->d_class != dp2->d_class && + dp1->d_class != C_ANY && dp2->d_class != C_ANY) + return(0); + if (dp1->d_type != dp2->d_type && + dp1->d_type != T_ANY && dp2->d_type != T_ANY) + return(0); + if (dp1->d_type == T_NXT) + return(nxtmatch(name, dp1, dp2)); + if (dp1->d_type != T_SIG) + return(1); + if (SIG_COVERS(dp1) == SIG_COVERS(dp2)) { + if (SIG_COVERS(dp1) == ns_t_nxt) + return(nxtmatch(name, dp1, dp2)); + else + return(1); + } + return(0); +} diff --git a/contrib/bind/bin/named/db_save.c b/contrib/bind/bin/named/db_save.c index a05c40f..c4db46a 100644 --- a/contrib/bind/bin/named/db_save.c +++ b/contrib/bind/bin/named/db_save.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)db_save.c 4.16 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: db_save.c,v 8.15 1998/01/26 22:40:08 halley Exp $"; +static const char sccsid[] = "@(#)db_save.c 4.16 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: db_save.c,v 8.26 1999/10/13 16:39:02 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: db_save.c,v 8.15 1998/01/26 22:40:08 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -82,6 +82,7 @@ static char rcsid[] = "$Id: db_save.c,v 8.15 1998/01/26 22:40:08 halley Exp $"; #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -136,11 +137,13 @@ savedata(class, type, ttl, data, size) int size; { struct databuf *dp; - int bytes = (type == T_NS) ? DATASIZE(size)+INT32SZ : DATASIZE(size); + int bytes = DATASIZE(size); dp = (struct databuf *)memget(bytes); if (dp == NULL) panic("savedata: memget", NULL); + if (class > CLASS_MAX) + panic("savedata: bad class", NULL); memset(dp, 0, bytes); dp->d_next = NULL; dp->d_type = type; @@ -151,6 +154,7 @@ savedata(class, type, ttl, data, size) dp->d_flags = 0; dp->d_cred = 0; dp->d_clev = 0; + dp->d_secure = DB_S_INSECURE; dp->d_rcode = NOERROR; dp->d_ns = NULL; dp->d_nstime = 0; @@ -158,20 +162,6 @@ savedata(class, type, ttl, data, size) return (dp); } -int hashsizes[] = { /* hashtable sizes */ - 2, - 11, - 113, - 337, - 977, - 2053, - 4073, - 8011, - 16001, - 99887, - 0 -}; - /* * Allocate a data buffer & save data. */ diff --git a/contrib/bind/bin/named/db_sec.c b/contrib/bind/bin/named/db_sec.c new file mode 100644 index 0000000..bb31fae --- /dev/null +++ b/contrib/bind/bin/named/db_sec.c @@ -0,0 +1,1097 @@ + +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: db_sec.c,v 8.30 1999/10/15 21:06:49 vixie Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1986, 1990 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include "port_before.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <ctype.h> +#include <resolv.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <time.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> +#include <isc/memcluster.h> +#include <isc/tree.h> + +#include <isc/dst.h> + +#include "port_after.h" + +#include "named.h" + +struct zpubkey { + struct dst_key *zpk_key; /* Should be DST_KEY */ + char *zpk_name; + struct zpubkey *zpk_next; +}; + +typedef struct zpubkey *zpubkey_list; + +static int nxt_match_rrset(struct databuf *dp, struct db_rrset *rrset); + +/* + * A converted databuf is a stripped down databuf after converting the + * data to wire format. + */ +struct converted_databuf { + struct converted_databuf *cd_next; + u_char *cd_data; + int cd_size, cd_alloc; +}; + +/* All of the trusted keys and zone keys */ +static tree *trusted_keys = NULL; + +static int +compare_pubkey (struct zpubkey *zpk1, struct zpubkey *zpk2) { + char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; + + if (ns_makecanon(zpk1->zpk_name, ta, sizeof ta) < 0 || + ns_makecanon(zpk2->zpk_name, tb, sizeof tb) < 0) + return (-1); + return (strcasecmp(ta, tb)); +} + +static struct zpubkey * +tree_srch_pubkey (const char *name) { + struct zpubkey tkey, *key; + + tkey.zpk_name = (char *) name; + if (trusted_keys == NULL) { + tree_init(&trusted_keys); + return (NULL); + } + key = (struct zpubkey *)tree_srch(&trusted_keys, compare_pubkey, + &tkey); + return (key); +} + +static DST_KEY * +find_public_key (const char *name, u_int16_t key_id) { + struct namebuf *knp; + struct hashbuf *htp; + struct databuf *dp; + const char *fname; + DST_KEY *key; + + ns_debug(ns_log_default, 5, "find_public_key(%s, %d)", name, key_id); + + htp = hashtab; + knp = nlookup (name, &htp, &fname, 0); + if (fname != name) + /* The name doesn't exist, so there's no key */ + return (NULL); + + for (dp = knp->n_data; dp != NULL; dp = dp->d_next) { + if (dp->d_type != ns_t_key || dp->d_secure < DB_S_SECURE) + continue; + key = dst_dnskey_to_key(name, dp->d_data, dp->d_size); + /* XXX what about multiple keys with same footprint? */ + if (key) { + if (key->dk_id == ntohs(key_id)) + return (key); + else + dst_free_key(key); + } + } + return (NULL); +} + + +static DST_KEY * +find_trusted_key (const char *name, u_int16_t key_id) { + struct zpubkey *zpk; + zpubkey_list keylist = tree_srch_pubkey (name); + + ns_debug(ns_log_default, 5, "find_trusted_key(%s, %d)", name, key_id); + + for (zpk = keylist; zpk; zpk = zpk->zpk_next) + if (zpk->zpk_key->dk_id == ntohs(key_id)) + return (zpk->zpk_key); + + return (NULL); +} + +int +add_trusted_key (const char *name, const int flags, const int proto, + const int alg, const char *str) +{ + zpubkey_list keylist; + struct zpubkey *zpk; + u_char buf[1024]; + int n; + + keylist = tree_srch_pubkey (name); + + zpk = (struct zpubkey *) memget (sizeof (struct zpubkey)); + if (zpk == NULL) + ns_panic(ns_log_default, 1, + "add_trusted_key: memget failed(%s)", name); + n = b64_pton(str, buf, sizeof(buf)); + if (n < 0) + goto failure; + zpk->zpk_key = dst_buffer_to_key(name, alg, flags, proto, buf, n); + if (zpk->zpk_key == NULL) { + ns_warning(ns_log_default, + "add_trusted_key: dst_buffer_to_key(%s) failed", + name); + goto failure; + } + zpk->zpk_name = zpk->zpk_key->dk_key_name; + zpk->zpk_next = NULL; + + if (keylist == NULL) { + if (tree_add (&trusted_keys, compare_pubkey, zpk, NULL) == NULL) + goto failure; + } + else { + struct zpubkey *tkey = keylist; + while (tkey->zpk_next) + tkey = tkey->zpk_next; + tkey->zpk_next = zpk; + } + + return (1); + failure: + memput(zpk, sizeof (struct zpubkey)); + return (0); +} + +/* Can the signer sign records for this name? This is a heuristic. */ +static int +can_sign(const char *name, const char *signer) { + return (ns_samedomain(name, signer) && + dn_count_labels(name) - dn_count_labels(signer) <= 2); +} + +static int +rrset_set_security(struct db_rrset *rrset, int slev) { + struct dnode *dnp; + + for (dnp = rrset->rr_list; dnp != NULL; dnp = dnp->dn_next) + dnp->dp->d_secure = slev; + for (dnp = rrset->rr_sigs; dnp != NULL; dnp = dnp->dn_next) + dnp->dp->d_secure = slev; + return (slev); +} + +static int +convert_databuf(struct databuf *dp, struct converted_databuf *cdp) { + u_char *bp = cdp->cd_data; + u_char *cp = dp->d_data; + u_char *eob = cdp->cd_data + cdp->cd_alloc; + int len; + u_char buf[MAXDNAME]; + + switch (dp->d_type) { + case ns_t_soa: + case ns_t_minfo: + case ns_t_rp: + if (eob - bp < strlen((char *)cp) + 1) + return (-1); + if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) + return (-1); + len = ns_name_ntol(buf, bp, eob - bp); + if (len < 0) + return (-1); + bp += len; + cp += strlen((char *)cp) + 1; + + if (eob - bp < strlen((char *)cp) + 1) + return (-1); + if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) + return (-1); + len = ns_name_ntol(buf, bp, eob - bp); + if (len < 0) + return (-1); + bp += len; + cp += strlen((char *)cp) + 1; + + if (dp->d_type == ns_t_soa) { + if (eob - bp < 5 * INT32SZ) + return (-1); + memcpy(bp, cp, 5 * INT32SZ); + bp += (5 * INT32SZ); + cp += (5 * INT32SZ); + } + + break; + + case ns_t_ns: + case ns_t_cname: + case ns_t_mb: + case ns_t_mg: + case ns_t_mr: + case ns_t_ptr: + case ns_t_nxt: + if (eob - bp < strlen((char *)cp) + 1) + return (-1); + if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) + return (-1); + len = ns_name_ntol(buf, bp, eob - bp); + if (len < 0) + return (-1); + bp += len; + cp += (len = strlen((char *)cp) + 1); + + if (dp->d_type == ns_t_nxt) { + if (eob - bp < dp->d_size - len) + return (-1); + memcpy(bp, cp, dp->d_size - len); + bp += (dp->d_size - len); + cp += (dp->d_size - len); + } + break; + + case ns_t_srv: + if (eob - bp < 2 * INT16SZ) + return (-1); + memcpy(bp, cp, 2 * INT16SZ); + bp += (2 * INT16SZ); + cp += (2 * INT16SZ); + /* no break */ + case ns_t_rt: + case ns_t_mx: + case ns_t_afsdb: + case ns_t_px: + if (eob - bp < INT16SZ) + return (-1); + memcpy (bp, cp, INT16SZ); + bp += INT16SZ; + cp += INT16SZ; + + if (eob - bp < strlen((char *)cp) + 1) + return (-1); + if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) + return (-1); + len = ns_name_ntol(buf, bp, eob - bp); + if (len < 0) + return (-1); + bp += len; + cp += strlen((char *)cp) + 1; + + if (dp->d_type == ns_t_px) { + if (eob - bp < strlen((char *)cp) + 1) + return (-1); + if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) + return (-1); + len = ns_name_ntol(buf, bp, eob - bp); + if (len < 0) + return (-1); + bp += len; + cp += strlen((char *)cp) + 1; + } + break; + + default: + if (eob - bp < dp->d_size) + return (-1); + memcpy(bp, cp, dp->d_size); + bp += dp->d_size; + } + cdp->cd_size = bp - cdp->cd_data; + return (cdp->cd_size); +} + +static int +digest_rr(char *envelope, int elen, struct converted_databuf *cdp, + char *buffer, int blen) +{ + char *bp = buffer, *eob = buffer + blen; + + if (eob - bp < elen) + return (-1); + memcpy (bp, envelope, elen); + bp += elen; + + if (eob - bp < INT16SZ) + return (-1); + PUTSHORT(cdp->cd_size, bp); + + if (eob - bp < cdp->cd_size) + return (-1); + memcpy (bp, cdp->cd_data, cdp->cd_size); + bp += cdp->cd_size; + + return (bp - buffer); +} + +/* Sorts the converted databuf in the list */ +static void +insert_converted_databuf(struct converted_databuf *cdp, + struct converted_databuf **clist) +{ + struct converted_databuf *tcdp, *next; + int t; + +#define compare_cdatabuf(c1, c2, t) \ + (t = memcmp(c1->cd_data, c2->cd_data, MIN(c1->cd_size, c2->cd_size)), \ + t == 0 ? c1->cd_size - c2->cd_size : t) + + if (*clist == NULL) { + *clist = cdp; + return; + } + + tcdp = *clist; + if (compare_cdatabuf(cdp, tcdp, t) < 0) { + cdp->cd_next = tcdp; + *clist = cdp; + return; + } + + next = tcdp->cd_next; + while (next) { + if (compare_cdatabuf(cdp, next, t) < 0) { + cdp->cd_next = next; + tcdp->cd_next = cdp; + return; + } + tcdp = next; + next = next->cd_next; + } + tcdp->cd_next = cdp; +#undef compare_cdatabuf +} + +static void +free_clist(struct converted_databuf *clist) { + struct converted_databuf *cdp; + + while (clist != NULL) { + cdp = clist; + clist = clist->cd_next; + memput(cdp->cd_data, cdp->cd_alloc); + memput(cdp, sizeof(struct converted_databuf)); + } +} + +/* Removes all empty nodes from an rrset's SIG list. */ +static void +rrset_trim_sigs(struct db_rrset *rrset) { + struct dnode *dnp, *odnp, *ndnp; + + odnp = NULL; + dnp = rrset->rr_sigs; + while (dnp != NULL) { + if (dnp->dp != NULL) { + odnp = dnp; + dnp = dnp->dn_next; + } + else { + if (odnp != NULL) + odnp->dn_next = dnp->dn_next; + else + rrset->rr_sigs = dnp->dn_next; + ndnp = dnp->dn_next; + memput(dnp, sizeof(struct dnode)); + dnp = ndnp; + } + } +} + +int +verify_set(struct db_rrset *rrset) { + DST_KEY *key = NULL; + struct sig_record *sigdata; + struct dnode *sigdn; + struct databuf *sigdp; + time_t now; + char *signer; + u_char name_n[MAXDNAME]; + u_char *sig, *eom; + int trustedkey = 0, siglen, labels, len = 0, ret; + u_char *buffer = NULL, *bp; + u_char envelope[MAXDNAME+32], *ep; + struct dnode *dnp; + int bufsize = 2048; /* Large enough for MAXDNAME + SIG_HDR_SIZE */ + struct converted_databuf *clist = NULL, *cdp; + int dnssec_failed = 0, dnssec_succeeded = 0; + int return_value; + int i; + + if (rrset == NULL || rrset->rr_name == NULL) { + ns_warning (ns_log_default, "verify_set: missing rrset/name"); + return (rrset_set_security(rrset, DB_S_FAILED)); + } + + if (rrset->rr_sigs == NULL) + return (rrset_set_security(rrset, DB_S_INSECURE)); + + ns_debug(ns_log_default, 5, "verify_set(%s, %s, %s)", rrset->rr_name, + p_type(rrset->rr_type), p_class(rrset->rr_class)); + + now = time(NULL); + + for (sigdn = rrset->rr_sigs; sigdn != NULL; sigdn = sigdn->dn_next) { + u_int32_t namefield; + struct sig_record sigrec; + + sigdp = sigdn->dp; + + eom = sigdp->d_data + sigdp->d_size; + if (sigdp->d_size < SIG_HDR_SIZE) { + return_value = DB_S_FAILED; + goto end; + } + memcpy(&sigrec, sigdp->d_data, SIG_HDR_SIZE); + sigdata = &sigrec; + signer = (char *)sigdp->d_data + SIG_HDR_SIZE; + sig = (u_char *)signer + strlen(signer) + 1; + siglen = eom - sig; + + /* + * Don't verify a set if the SIG inception time is in + * the future. This should be fixed before 2038 (BEW) + */ + if (ntohl(sigdata->sig_time_n) > now) + continue; + + /* An expired set is dropped, but the data is not. */ + if (ntohl(sigdata->sig_exp_n) < now) { + db_freedata(sigdp); + sigdn->dp = NULL; + continue; + } + + /* Cleanup from the last iteration if we continue'd */ + if (trustedkey == 0 && key != NULL) + dst_free_key(key); + + key = find_trusted_key(signer, sigdata->sig_keyid_n); + + if (key == NULL) { + trustedkey = 0; + key = find_public_key(signer, sigdata->sig_keyid_n); + } + else + trustedkey = 1; + + /* if we don't have the key, either + * - the data should be considered insecure + * - the sig is not a dnssec signature + */ + if (key == NULL) + continue; + + /* Can a key with this name sign the data? */ + if (!can_sign(rrset->rr_name, signer)) + continue; + + /* Check the protocol and flags of the key */ + if (key->dk_proto != NS_KEY_PROT_DNSSEC && + key->dk_proto != NS_KEY_PROT_ANY) + continue; + if (key->dk_flags & NS_KEY_NO_AUTH) + continue; + namefield = key->dk_flags & NS_KEY_NAME_TYPE; + if (namefield == NS_KEY_NAME_USER || + namefield == NS_KEY_NAME_RESERVED) + continue; + if (namefield == NS_KEY_NAME_ENTITY && + (key->dk_flags & NS_KEY_SIGNATORYMASK == 0)) + continue; + + /* + * If we're still here, we have a non-null key that's either + * a zone key or an entity key with signing authority. + */ + + if (buffer == NULL) { + bp = buffer = memget(bufsize); + if (bp == NULL) { + return_value = DB_S_FAILED; + goto end; + } + } + else + bp = buffer; + + + /* Digest the fixed portion of the SIG record */ + memcpy(bp, (char *) sigdata, SIG_HDR_SIZE); + bp += SIG_HDR_SIZE; + + /* Digest the signer's name, canonicalized */ + if (ns_name_pton(signer, name_n, sizeof name_n) < 0) { + return_value = DB_S_FAILED; + goto end; + } + i = ns_name_ntol(name_n, (u_char *)bp, bufsize - SIG_HDR_SIZE); + if (i < 0) { + return_value = DB_S_FAILED; + goto end; + } + bp += i; + + /* create the dns record envelope: + * <name><type><class><Original TTL> + */ + if (ns_name_pton(rrset->rr_name, name_n, sizeof name_n) < 0 || + ns_name_ntol(name_n, (u_char *)envelope, sizeof envelope) < 0) { + return_value = DB_S_FAILED; + goto end; + } + + labels = dn_count_labels(rrset->rr_name); + if (labels > sigdata->sig_labels_n) { + ep = envelope; + for (i=0; i < (labels - 1 - sigdata->sig_labels_n); i++) + ep += (*ep+1); + i = dn_skipname(ep, envelope + sizeof envelope); + if (i < 0) { + return_value = DB_S_FAILED; + goto end; + } + envelope[0] = '\001'; + envelope[1] = '*'; + memmove(envelope + 2, ep, i); + } + i = dn_skipname(envelope, envelope + sizeof envelope); + if (i < 0) { + return_value = DB_S_FAILED; + goto end; + } + ep = envelope + i; + PUTSHORT (rrset->rr_type, ep); + PUTSHORT (rrset->rr_class, ep); + if (envelope + sizeof(envelope) - ep < INT32SZ) { + return_value = DB_S_FAILED; + goto end; + } + memcpy (ep, &sigdata->sig_ottl_n, INT32SZ); + ep += INT32SZ; + + if (clist == NULL) { + for (dnp = rrset->rr_list; + dnp != NULL; + dnp = dnp->dn_next) + { + struct databuf *dp = dnp->dp; + + cdp = memget(sizeof(struct converted_databuf)); + if (cdp == NULL) { + return_value = DB_S_FAILED; + goto end; + } + memset(cdp, 0, sizeof(*cdp)); + /* Should be large enough... */ + cdp->cd_alloc = dp->d_size + 8; + cdp->cd_data = memget(cdp->cd_alloc); + if (cdp->cd_data == NULL) { + memput(cdp, sizeof(*cdp)); + return_value = DB_S_FAILED; + goto end; + } + while (convert_databuf(dp, cdp) < 0) { + memput(cdp->cd_data, cdp->cd_alloc); + cdp->cd_alloc *= 2; + cdp->cd_data = memget(cdp->cd_alloc); + if (cdp->cd_data == NULL) { + memput(cdp, sizeof(*cdp)); + return_value = DB_S_FAILED; + goto end; + } + } + insert_converted_databuf(cdp, &clist); + } + } + + for (cdp = clist; cdp != NULL; cdp = cdp->cd_next) { + len = digest_rr((char *)envelope, ep-envelope, cdp, + (char *)bp, bufsize - (bp - buffer)); + while (len < 0) { + u_char *newbuf; + + /* Double the buffer size */ + newbuf = memget(bufsize*2); + if (newbuf == NULL) { + return_value = DB_S_FAILED; + goto end; + } + memcpy(newbuf, buffer, bp - buffer); + bp = (bp - buffer) + newbuf; + memput(buffer, bufsize); + buffer = newbuf; + bufsize *= 2; + + len = digest_rr((char *)envelope, ep-envelope, + cdp, (char *)bp, + bufsize - (bp - buffer)); + } + bp += len; + } + + if (len < 0) { + return_value = DB_S_FAILED; + goto end; + } + + ret = dst_verify_data(SIG_MODE_ALL, key, NULL, buffer, + bp - buffer, sig, siglen); + + if (ret < 0) { + dnssec_failed++; + db_freedata(sigdp); + sigdn->dp = NULL; + } + else + dnssec_succeeded++; + } + +end: + if (dnssec_failed > 0) + rrset_trim_sigs(rrset); + if (trustedkey == 0 && key != NULL) + dst_free_key(key); + + if (dnssec_failed > 0 && dnssec_succeeded == 0) { + ns_warning (ns_log_default, + "verify_set(%s, %s, %s) failed", + rrset->rr_name, p_type(rrset->rr_type), + p_class(rrset->rr_class)); + return_value = DB_S_FAILED; + } + else if (dnssec_succeeded > 0) + return_value = DB_S_SECURE; + else + return_value = DB_S_INSECURE; + free_clist(clist); + if (buffer != NULL) + memput(buffer, bufsize); + return (rrset_set_security(rrset, return_value)); +} + +static void +rrset_free_partial(struct db_rrset *rrset, int free_data, struct dnode *start) { + struct dnode *dnp; + int found_start = 0; + + ns_debug(ns_log_default, 5, "rrset_free(%s)", rrset->rr_name); + + if (start == NULL) + found_start = 1; + + while (rrset->rr_list) { + dnp = rrset->rr_list; + if (dnp == start) + found_start = 1; + rrset->rr_list = rrset->rr_list->dn_next; + if (dnp->dp != NULL && free_data == 1 && found_start == 1) + db_freedata(dnp->dp); + memput(dnp, sizeof(struct dnode)); + } + while (rrset->rr_sigs) { + dnp = rrset->rr_sigs; + if (dnp == start) + found_start = 1; + rrset->rr_sigs = rrset->rr_sigs->dn_next; + if (dnp->dp != NULL && free_data == 1 && found_start == 1) + db_freedata(dnp->dp); + memput(dnp, sizeof(struct dnode)); + } +} + +static void +rrset_free(struct db_rrset *rrset, int free_data) { + rrset_free_partial(rrset, free_data, NULL); +} + +/* + * This is called when we have an rrset with SIGs and no other data. + * Returns 1 if we either found the necessary data or if the SIG can be added + * with no other data. 0 indicates that the SIG cannot be added. + */ +static int +attach_data(struct db_rrset *rrset) { + int type, class; + struct databuf *dp, *newdp, *sigdp; + struct dnode *dnp; + struct namebuf *np; + struct hashbuf *htp; + char *signer; + const char *fname; + char *name = rrset->rr_name; + + sigdp = rrset->rr_sigs->dp; + + type = SIG_COVERS(sigdp); + class = sigdp->d_class; + signer = (char *)(sigdp + SIG_HDR_SIZE); + + /* First, see if the signer can sign data for the name. If not, + * it's not a DNSSEC signature, so we can insert it with no + * corresponding data. + */ + if (!can_sign(name, signer)) + return (1); + + htp = hashtab; + np = nlookup (name, &htp, &fname, 0); + if (fname != name) + return (0); + + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + if (dp->d_type == type && dp->d_class == class) { + newdp = savedata(class, type, dp->d_ttl, dp->d_data, + dp->d_size); + dnp = (struct dnode *) memget (sizeof (struct dnode)); + if (dnp == NULL) + ns_panic(ns_log_default, 1, + "attach_data: memget failed"); + dnp->dp = newdp; + dnp->dn_next = rrset->rr_list; + rrset->rr_list = dnp; + } + } + if (rrset->rr_list != NULL) + return (1); + else + return (0); +} + +static int +rrset_db_update(struct db_rrset *rrset, int flags, struct hashbuf **htpp, + struct sockaddr_in from, int *rrcount) +{ + struct dnode *dnp; + struct databuf *dp; + int ret; + + /* If we have any unattached SIG records that are DNSSEC signatures, + * don't cache them unless we already have the corresponding data. + * If we do cache unattached SIGs, we run into problems later if we + * have a SIG X and get a query for type X. + */ + if (rrset->rr_list == NULL) { + if (attach_data(rrset) == 0) { + rrset_free(rrset, 1); + return (OK); + } + + if (rrset->rr_list != NULL && + verify_set(rrset) == DB_S_FAILED) + { + rrset_free(rrset, 1); + return (OK); + } + } + + for (dnp = rrset->rr_list; dnp != NULL; dnp = dnp->dn_next) { + dp = dnp->dp; + ret = db_update(rrset->rr_name, dp, dp, NULL, + flags, (*htpp), from); + if (ret != OK) { + /* XXX Probably should do rollback. */ + db_err(ret, rrset->rr_name, dp->d_type, + dnp->file, dnp->line); + if (ret != DATAEXISTS) { + rrset_free_partial(rrset, 1, dnp); + return (ret); + } + db_freedata(dp); + } + if (rrcount != NULL) + (*rrcount)++; + dnp->dp = NULL; + } + for (dnp = rrset->rr_sigs; dnp != NULL; dnp = dnp->dn_next) { + dp = dnp->dp; + if (dp == NULL) /* verifyset() can remove sigs */ + continue; + ret = db_update(rrset->rr_name, dp, dp, NULL, + flags, (*htpp), from); + if (ret != OK) { + /* XXX Probably should do rollback. */ + db_err(ret, rrset->rr_name, dp->d_type, + dnp->file, dnp->line); + if (ret != DATAEXISTS) { + rrset_free_partial(rrset, 1, dnp); + return (ret); + } + db_freedata(dp); + } + if (rrcount != NULL) + (*rrcount)++; + dnp->dp = NULL; + } + rrset_free(rrset, 0); + return (OK); +} + +static int +rr_in_set(struct databuf *rr, struct dnode *set) { + struct dnode *dnp; + + if (set == NULL) + return (0); + + for(dnp = set; dnp != NULL; dnp = dnp->dn_next) { + if (dnp->dp->d_size == rr->d_size && + memcmp(dnp->dp->d_data, rr->d_data, dnp->dp->d_size) == 0) + return (1); + } + return (0); +} + +static int +add_to_rrset_list(struct db_rrset **rrsets, char *name, struct databuf *dp, + int line, const char *file) +{ + struct db_rrset *rrset = *rrsets; + struct dnode *dnp; + + while (rrset != NULL) { + if (rrset->rr_type != ns_t_nxt || dp->d_type != ns_t_nxt) { + if (dp->d_type == ns_t_sig) { + if (SIG_COVERS(dp) == rrset->rr_type) + break; + } else { + if (dp->d_type == rrset->rr_type) + break; + } + } + else if (nxt_match_rrset(dp, rrset)) + break; + rrset = rrset->rr_next; + } + + if (rrset != NULL) { + if ((dp->d_type == ns_t_sig && rr_in_set(dp, rrset->rr_sigs)) || + (dp->d_type != ns_t_sig && rr_in_set(dp, rrset->rr_list))) + { + db_freedata(dp); + return (DATAEXISTS); + } + } else { + rrset = (struct db_rrset *) memget(sizeof(struct db_rrset)); + if (rrset == NULL) + ns_panic(ns_log_default, 1, + "add_to_rrset_list: memget failed(%s)", name); + memset(rrset, 0, sizeof(struct db_rrset)); + rrset->rr_name = savestr(name, 1); + rrset->rr_class = dp->d_class; + if (dp->d_type == ns_t_sig) + rrset->rr_type = SIG_COVERS(dp); + else + rrset->rr_type = dp->d_type; + rrset->rr_next = *rrsets; + *rrsets = rrset; + } + + dnp = (struct dnode *) memget(sizeof(struct dnode)); + if (dnp == NULL) + ns_panic(ns_log_default, 1, + "add_to_rrset_list: memget failed(%s)", name); + memset(dnp, 0, sizeof(struct dnode)); + dnp->dp = dp; + if (dp->d_type == ns_t_sig) { + if (rrset->rr_sigs != NULL) { + struct dnode *fdnp; + + /* Preserve the order of the RRs */ + /* Add this one to the end of the list */ + for (fdnp = rrset->rr_sigs; + fdnp->dn_next != NULL; + fdnp = fdnp->dn_next) + /* NULL */ ; + fdnp->dn_next = dnp; + } else + rrset->rr_sigs = dnp; + } else { + if (rrset->rr_list != NULL) { + struct dnode *fdnp; + + /* Preserve the order of the RRs */ + /* Add this one to the end of the list */ + for (fdnp = rrset->rr_list; + fdnp->dn_next != NULL; + fdnp = fdnp->dn_next) + /* NULL */ ; + fdnp->dn_next = dnp; + } else + rrset->rr_list = dnp; + } + dnp->file = (char *) file; + dnp->line = line; + return (0); +} + +static int +update_rrset_list(struct db_rrset **rrsets, int flags, struct hashbuf **htpp, + struct sockaddr_in from, int *rrcount) +{ + struct db_rrset *rrset = *rrsets, *next = NULL, *last = NULL; + int result = 0, tresult, cnameandother = 0; + + while (rrset != NULL) { + if (rrset->rr_type == ns_t_key) + break; + last = rrset; + rrset = rrset->rr_next; + } + + if (rrset != NULL && last != NULL) { + last->rr_next = rrset->rr_next; + rrset->rr_next = *rrsets; + *rrsets = rrset; + } + + rrset = *rrsets; + + while (rrset != NULL) { + if (verify_set(rrset) > DB_S_FAILED) { + ns_debug(ns_log_default, 10, + "update_rrset_list(%s, %s): set verified", + rrset->rr_name, p_type(rrset->rr_type)); + tresult = rrset_db_update(rrset, flags, htpp, + from, rrcount); + if (tresult == CNAMEANDOTHER) + cnameandother++; + if (tresult != OK) + result = tresult; + } + else { + rrset_free(rrset, 1); + result = DNSSECFAIL; + } + freestr(rrset->rr_name); + next = rrset->rr_next; + memput(rrset, sizeof(struct db_rrset)); + rrset = next; + } + *rrsets = NULL; + if (cnameandother != 0) + return (CNAMEANDOTHER); + return (result); +} + +int +db_set_update(char *name, struct databuf *dp, void **state, + int flags, struct hashbuf **htpp, struct sockaddr_in from, + int *rrcount, int line, const char *file) +{ + struct db_rrset **rrsets; + struct db_rrset *rrset; + int result = 0; + + ns_debug(ns_log_default, 5, "db_set_update(%s)", + (name == NULL) ? "<NULL>" : (*name == 0) ? "." : name); + + if (state == NULL) + ns_panic(ns_log_default, 1, + "Called db_set_update with state == NULL"); + + rrsets = (struct db_rrset **) state; + + if (*rrsets != NULL) { + rrset = *rrsets; + if (rrset->rr_name != NULL && dp != NULL && + name != NULL && ns_samename(name, rrset->rr_name) == 1 && + dp->d_class == rrset->rr_class) + return (add_to_rrset_list(rrsets, name, dp, + line, file)); + } + + if (*rrsets != NULL) + result = update_rrset_list(rrsets, flags, htpp, from, rrcount); + + if (dp != NULL) { + ns_debug(ns_log_default, 10, + "db_set_update(%s), creating new list", name); + + (void) add_to_rrset_list(rrsets, name, dp, line, file); + } + return (result); +} + +static int +nxt_match_rrset(struct databuf *dp, struct db_rrset *rrset) { + if (rrset->rr_list != NULL) + return (nxtmatch(rrset->rr_name, dp, rrset->rr_list->dp)); + else + return (nxtmatch(rrset->rr_name, dp, rrset->rr_sigs->dp)); +} diff --git a/contrib/bind/bin/named/db_tsig.c b/contrib/bind/bin/named/db_tsig.c new file mode 100644 index 0000000..d95031d --- /dev/null +++ b/contrib/bind/bin/named/db_tsig.c @@ -0,0 +1,158 @@ + +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: db_tsig.c,v 8.5 1999/10/15 19:48:59 vixie Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1986, 1990 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include "port_before.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <ctype.h> +#include <resolv.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <time.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> +#include <isc/memcluster.h> +#include <isc/tree.h> + +#include <isc/dst.h> + +#include "port_after.h" + +#include "named.h" + +typedef struct { + DST_KEY *key; + void *ctx; +} tsig_axfr_state; + +#define TSIG_ALG_MD5 "HMAC-MD5.SIG-ALG.REG.INT" +#define TSIG_ALG_MD5_SHORT "hmac-md5" + +char * +tsig_alg_name(int value) { + if (value == KEY_HMAC_MD5) + return(TSIG_ALG_MD5); + else + return(NULL); +} + +int +tsig_alg_value(char *name) { + if (ns_samename(name, TSIG_ALG_MD5) == 1 || + strcasecmp(name, TSIG_ALG_MD5_SHORT) == 0) + return (KEY_HMAC_MD5); + else + return (-1); +} + +DST_KEY * +tsig_key_from_addr(struct in_addr addr) { + server_info si = si = find_server(addr); + if (si == NULL || si->key_list == NULL || si->key_list->first == NULL) + return(NULL); + return(si->key_list->first->key); +} + +struct tsig_record * +new_tsig(DST_KEY *key, u_char *sig, int siglen) { + struct tsig_record *tsig; + + if (siglen > TSIG_SIG_SIZE) + return(NULL); + tsig = memget(sizeof(struct tsig_record)); + if (tsig == NULL) + return(NULL); + tsig->key = key; + tsig->siglen = siglen; + memcpy(tsig->sig, sig, siglen); + return(tsig); +} + +void +free_tsig(struct tsig_record *tsig) { + if (tsig == NULL) + return; + memput(tsig, sizeof(struct tsig_record)); +} diff --git a/contrib/bind/bin/named/db_update.c b/contrib/bind/bin/named/db_update.c index ab70663..ea0176e 100644 --- a/contrib/bind/bin/named/db_update.c +++ b/contrib/bind/bin/named/db_update.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)db_update.c 4.28 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: db_update.c,v 8.23 1998/02/13 20:01:38 halley Exp $"; +static const char sccsid[] = "@(#)db_update.c 4.28 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: db_update.c,v 8.39 1999/10/15 19:48:59 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: db_update.c,v 8.23 1998/02/13 20:01:38 halley Exp $" */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -78,6 +78,7 @@ static char rcsid[] = "$Id: db_update.c,v 8.23 1998/02/13 20:01:38 halley Exp $" #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -116,7 +117,7 @@ isRefByNS(const char *name, struct hashbuf *htp) { dp->d_class == C_HS) && dp->d_type == T_NS && !dp->d_rcode && - !strcasecmp(name, (char *)dp->d_data)) { + ns_samename(name, (char *)dp->d_data) == 1) { return (1); } } @@ -153,21 +154,18 @@ findMyZone(struct namebuf *np, int class) { * the cache or an authoritative zone, depending). */ for (dp = np->n_data; dp; dp = dp->d_next) - if (match(dp, class, T_SOA)) + if (match(dp, class, T_SOA) && dp->d_type == T_SOA) return (dp->d_zone); /* if we find an NS at some node without having seen an SOA * (above), then we're out in the cache somewhere. */ for (dp = np->n_data; dp; dp = dp->d_next) - if (match(dp, class, T_NS)) + if (match(dp, class, T_NS) && dp->d_type == T_NS) return (DB_Z_CACHE); } - /* getting all the way to the root without finding an NS or SOA - * probably means that we are in deep dip, but we'll treat it as - * being in the cache. (XXX?) - */ + /* The cache has not yet been primed. */ return (DB_Z_CACHE); } @@ -226,12 +224,11 @@ db_update(const char *name, struct namebuf *np; int zn, isHintNS; int check_ttl = 0; + int deleted_something = 0; const char *fname; #ifdef BIND_UPDATE - int i, found_other_ns = 0; + int found_other_ns = 0; struct databuf *tmpdp; - u_char *cp1, *cp2; - u_int32_t dp_serial, newdp_serial; #endif ns_debug(ns_log_db, 3, "db_update(%s, %#x, %#x, %#x, 0%o, %#x)%s", @@ -320,6 +317,7 @@ db_update(const char *name, dp->d_zone = DB_Z_CACHE; dp->d_flags = DB_F_HINT; dp->d_cred = DB_C_CACHE; + dp->d_secure = odp->d_secure; /* BEW - this should be ok */ dp->d_clev = 0; if (db_update(name, dp, dp, NULL, @@ -337,7 +335,7 @@ db_update(const char *name, pdp = NULL; for (dp = np->n_data; dp != NULL; ) { - if (!match(dp, odp->d_class, odp->d_type)) { + if (!rrmatch(name, dp, odp)) { /* {class,type} doesn't match. these are * the aggregation cases. */ @@ -368,6 +366,9 @@ db_update(const char *name, ns_info(ns_log_db, "%s has CNAME and other data (invalid)", name); + if (zones[odp->d_zone].z_type == + Z_PRIMARY) + return (CNAMEANDOTHER); goto skip; } if (!newdp || newdp->d_class != dp->d_class) @@ -394,7 +395,7 @@ db_update(const char *name, return (AUTH); #endif - /* if the new data is authoritative but + /* if the new data is authoritative * but isn't as credible, reject it. */ if (newdp->d_cred == DB_C_ZONE && @@ -406,6 +407,11 @@ db_update(const char *name, * upper zone's file and is therefore * glue. */ + + /* BEW/OG: we see no reason to override + * these rules with new security based + * rules. + */ if (newdp->d_clev < dp->d_clev) { if (!ISVALIDGLUE(newdp)) { ns_info(ns_log_db, @@ -431,7 +437,8 @@ db_update(const char *name, /* process NXDOMAIN */ /* policy */ if (newdp->d_rcode == NXDOMAIN) { - if (dp->d_cred < DB_C_AUTH) + if (dp->d_cred < DB_C_AUTH && + newdp->d_secure >= dp->d_secure) goto delete; else return (DATAEXISTS); @@ -455,24 +462,37 @@ db_update(const char *name, db_cmp(dp, odp)); if (newdp) { ns_debug(ns_log_db, 4, - "credibility for %s is %d(%d) from [%s].%d, is %d(%d) in cache", +"credibility for %s is %d(%d)(sec %d) from [%s].%d, is %d(%d)(sec %d) in cache", *name ? name : ".", newdp->d_cred, newdp->d_clev, + newdp->d_secure, inet_ntoa(from.sin_addr), ntohs(from.sin_port), dp->d_cred, + dp->d_secure, dp->d_clev); - if (newdp->d_cred > dp->d_cred) { - /* better credibility. + if ((newdp->d_secure > dp->d_secure) || + (newdp->d_secure == dp->d_secure && + (newdp->d_cred > dp->d_cred))) + { + /* better credibility / security. * remove the old datum. */ goto delete; } - if (newdp->d_cred < dp->d_cred) { - /* credibility is worse. ignore it. */ + if ((newdp->d_secure < dp->d_secure) || + (newdp->d_secure == dp->d_secure && + (newdp->d_cred < dp->d_cred))) + { + /* credibility / security is worse. + * ignore it. + */ return (AUTH); } + /* BEW/OG: from above, we know the security + * levels are the same. + */ if (newdp->d_cred == DB_C_ZONE && dp->d_cred == DB_C_ZONE ) { /* Both records are from a zone file. @@ -566,8 +586,19 @@ db_update(const char *name, INT32SZ + sizeof(u_char))) goto delete; if (dp->d_type == T_CNAME && - !NS_OPTION_P(OPTION_MULTIPLE_CNAMES)) - goto delete; + !NS_OPTION_P(OPTION_MULTIPLE_CNAMES) && + db_cmp(dp, odp) != 0) + if ((flags & DB_REPLACE) == 0 && + zones[dp->d_zone].z_type == + Z_PRIMARY) { + ns_info(ns_log_db, + "%s has multiple CNAMES", + name); + return (CNAMEANDOTHER); + } else + goto delete; +#if 0 +/* BEW - this _seriously_ breaks DNSSEC. Is it necessary for dynamic update? */ #ifdef BIND_UPDATE if (dp->d_type == T_SIG) /* @@ -576,6 +607,20 @@ db_update(const char *name, */ goto delete; #endif +#endif + if (dp->d_type == T_NXT) { + goto delete; + } + if (dp->d_type == T_SIG && + SIG_COVERS(dp) == T_NXT) { + struct sig_record *sr1, *sr2; + + sr1 = (struct sig_record *) dp->d_data; + sr2 = (struct sig_record *) + newdp->d_data; + if (sr1->sig_alg_n == sr2->sig_alg_n) + goto delete; + } if (check_ttl) { if (newdp->d_ttl != dp->d_ttl) ns_warning(ns_log_db, @@ -621,11 +666,13 @@ db_update(const char *name, goto skip; if (odp->d_clev < dp->d_clev) goto skip; - if (odp->d_cred < dp->d_cred) + if ((odp->d_secure < dp->d_secure) || + ((odp->d_secure == dp->d_secure) && + (odp->d_cred < dp->d_cred))) goto skip; #ifdef BIND_UPDATE - if (!strcasecmp(name, zones[dp->d_zone].z_origin) && - !newdp) { + if (ns_samename(name, zones[dp->d_zone].z_origin) == 1 + && newdp == NULL) { /* do not delete SOA or NS records as a set */ /* XXXRTH isn't testing d_size unnecessary? */ if ((odp->d_size == 0) && @@ -677,6 +724,7 @@ db_update(const char *name, if (savedpp != NULL) foundRR = 1; #endif + deleted_something = 1; dp = rm_datum(dp, np, pdp, savedpp); } else { skip: pdp = dp; @@ -690,10 +738,16 @@ db_update(const char *name, return (NODATA); } } - /* XXX: delete a terminal namebuf also if all databuf's - * underneath of it have been deleted) */ - if (newdp == NULL) + if (newdp == NULL) { + if (deleted_something) { + while (np->n_data == NULL && np->n_hash == NULL) { + np = purge_node(htp, np); + if (np == NULL) + break; + } + } return (OK); + } /* XXX: empty nodes bypass credibility checks above; should check * response source address here if flags&NOTAUTH. */ @@ -790,7 +844,10 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) { case T_MG: case T_MR: /* Only a domain name */ - return (strcasecmp((char *)dp1->d_data, (char *)dp2->d_data)); + if (ns_samename((char *)dp1->d_data, (char *)dp2->d_data) == 1) + return (0); + else + return (1); case T_SIG: /* Binary data, a domain name, more binary data */ @@ -800,8 +857,8 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) { return (1); len = NS_SIG_SIGNER + strlen((char *)dp1->d_data + NS_SIG_SIGNER); - if (strcasecmp((char *)dp1->d_data + NS_SIG_SIGNER, - (char *)dp2->d_data + NS_SIG_SIGNER)) + if (ns_samename((char *)dp1->d_data + NS_SIG_SIGNER, + (char *)dp2->d_data + NS_SIG_SIGNER) != 1) return (1); return (memcmp(dp1->d_data + len, dp2->d_data + len, @@ -809,7 +866,7 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) { case T_NXT: /* First a domain name, then binary data */ - if (strcasecmp((char *)dp1->d_data, (char *)dp2->d_data)) + if (ns_samename((char *)dp1->d_data, (char *)dp2->d_data) != 1) return (1); len = strlen((char *)dp1->d_data)+1; return (memcmp(dp1->d_data + len, @@ -837,14 +894,14 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) { case T_SOA: case T_MINFO: case T_RP: - if (strcasecmp((char *)dp1->d_data, (char *)dp2->d_data)) + if (ns_samename((char *)dp1->d_data, (char *)dp2->d_data) != 1) return (1); cp1 = dp1->d_data + strlen((char *)dp1->d_data) + 1; cp2 = dp2->d_data + strlen((char *)dp2->d_data) + 1; - if (dp1->d_type != T_SOA) - return (strcasecmp((char *)cp1, (char *)cp2)); - if (strcasecmp((char *)cp1, (char *)cp2)) + if (ns_samename((char *)cp1, (char *)cp2) != 1) return (1); + if (dp1->d_type != T_SOA) + return (0); cp1 += strlen((char *)cp1) + 1; cp2 += strlen((char *)cp2) + 1; return (memcmp(cp1, cp2, INT32SZ * 5)); @@ -907,18 +964,22 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) { if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* port */ return (1); } - return (strcasecmp((char *)cp1, (char *)cp2)); + if (ns_samename((char *)cp1, (char *)cp2) != 1) + return (1); + return (0); case T_PX: cp1 = dp1->d_data; cp2 = dp2->d_data; if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* cmp prio */ return (1); - if (strcasecmp((char *)cp1, (char *)cp2)) + if (ns_samename((char *)cp1, (char *)cp2) != 1) return (1); cp1 += strlen((char *)cp1) + 1; cp2 += strlen((char *)cp2) + 1; - return (strcasecmp((char *)cp1, (char *)cp2)); + if (ns_samename((char *)cp1, (char *)cp2) != 1) + return (1); + return (0); case T_TXT: case T_X25: diff --git a/contrib/bind/bin/named/named.conf b/contrib/bind/bin/named/named.conf index ab96666..d423b34 100644 --- a/contrib/bind/bin/named/named.conf +++ b/contrib/bind/bin/named/named.conf @@ -42,6 +42,9 @@ options { // notify on a zone-by-zone // basis in the "zone" statement // see (below) + max-serial-queries 4; // number of parallel SOA queries + // we can have outstanding for master + // zone change testing purposes auth-nxdomain yes; // always set AA on NXDOMAIN. // don't set this to 'no' unless // you know what you're doing -- older @@ -153,6 +156,20 @@ options { // every 'interface-interval' minutes statistics-interval 60; // log statistics every // 'statistics-interval' minutes + /* + * IXFR options + */ + maintain-ixfr-base no; // If yes, keep transaction log file for IXFR + max-ixfr-log-size 20; // Not implemented, maximum size the + // IXFR transaction log file to grow +}; + +/* + * Control listeners, for "ndc". Every nameserver needs at least one. + */ +controls { + inet * port 52 allow { any; }; // a bad idea + unix "/var/run/ndc" perm 0600 owner 0 group 0; // the default }; zone "master.demo.zone" { @@ -174,6 +191,7 @@ zone "master.demo.zone" { zone "slave.demo.zone" { type slave; // what used to be called "secondary" file "slave.demo.zone"; + ixfr-base "slave.demo.zone.ixfr"; // File name for IXFR transaction log file masters { 1.2.3.4; // where to zone transfer from 5.6.7.8; @@ -208,8 +226,14 @@ zone "stub.demo.zone" { zone "." { type hint; // used to be specified w/ "cache" file "cache.db"; + pubkey 257 255 1 "AQP2fHpZ4VMpKo/jc9Fod821uyfY5p8j5h/Am0V/KpBTMZjdXmp9QJe6yFRoIIzkaNCgTIftASdpXGgCwFB2j2KXP/rick6gvEer5VcDEkLR5Q=="; }; +trusted-keys { + . 257 255 1 "AQP2fHpZ4VMpKo/jc9Fod821uyfY5p8j5h/Am0V/KpBTMZjdXmp9QJe6yFRoIIzkaNCgTIftASdpXGgCwFB2j2KXP/rick6gvEer5VcDEkLR5Q=="; +}; + + acl can_query { !1.2.3/24; any; }; // network 1.2.3.0 mask 255.255.255.0 // is disallowed; rest are OK acl can_axfr { 1.2.3.4; can_query; }; // host 1.2.3.4 and any host allowed @@ -226,16 +250,18 @@ zone "non-default-acl.demo.zone" { }; }; -key sample_key { // for TSIG; supported by parser - algorithm hmac-md5; // but not yet implemented in the - secret "your secret here"; // rest of the server +key sample_key { // for TSIG + algorithm hmac-md5; // hmac-md5 is the supported algorithm + secret "abcdefgh"; // base 64 encoded secret }; key key2 { algorithm hmac-md5; - secret "ereh terces rouy"; + secret "87654321"; }; +acl key_acl { key sample_key; }; // a request signed with sample_key + server 1.2.3.4 { bogus no; // if yes, we won't query or listen // to this server @@ -245,9 +271,10 @@ server 1.2.3.4 { // if not specified, the global option // will be used transfers 0; // not implemented - keys { sample_key; key2; }; // for TSIG; supported by the parser - // but not yet implemented in the - // rest of the server + keys { sample_key; key2; }; // for TSIG; sign requests to this + // server with this key + support-ixfr yes; // for IXFR supported by server + // if yes, the listed server talks IXFR }; logging { diff --git a/contrib/bind/bin/named/named.h b/contrib/bind/bin/named/named.h index 57e787b..18f4ac4 100644 --- a/contrib/bind/bin/named/named.h +++ b/contrib/bind/bin/named/named.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,10 +16,10 @@ */ /* - * $Id: named.h,v 8.12 1997/12/04 06:52:27 halley Exp $ + * $Id: named.h,v 8.25 1999/10/13 18:00:19 vixie Exp $ */ -/* Options. Leave these on. */ +/* Options. Change them at your peril. */ #define DEBUG #define ADDAUTH #define STUBS @@ -30,31 +30,27 @@ #define QRYLOG #define YPKLUDGE #define RENICE -#define FORCED_RELOAD #define SLAVE_FORWARD -#define BIND_UPDATE +#define BIND_IXFR #define BIND_NOTIFY +#define BIND_UPDATE #define WANT_PIDFILE #define FWD_LOOP #define DOTTED_SERIAL #define SENSIBLE_DOTS #define ROUND_ROBIN -#define SORT_RESPONSE #define DNS_SECURITY #undef RSAREF #undef BSAFE #define ALLOW_LONG_TXT_RDATA - -#if 0 -#define strdup PLEASE_USE_SAVESTR -#define malloc PLEASE_USE_DB_MEMGET -#define calloc PLEASE_USE_DB_MEMGET -#define realloc PLEASE_USE_DB_MEMGET -#define free PLEASE_USE_DB_MEMPUT -#endif +#define STRICT_RFC2308 +#undef BIND_ZXFR #include <isc/assertions.h> #include <isc/list.h> +#include <isc/ctl.h> + +#include <res_update.h> #include "pathnames.h" diff --git a/contrib/bind/bin/named/ns_config.c b/contrib/bind/bin/named/ns_config.c index 4f95410..67bffbd 100644 --- a/contrib/bind/bin/named/ns_config.c +++ b/contrib/bind/bin/named/ns_config.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_config.c,v 8.35 1998/05/05 19:44:48 halley Exp $"; +static const char rcsid[] = "$Id: ns_config.c,v 8.104 1999/11/08 23:09:42 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,12 +19,33 @@ static char rcsid[] = "$Id: ns_config.c,v 8.35 1998/05/05 19:44:48 halley Exp $" * SOFTWARE. */ +/* + * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Check Point Software Technologies Incorporated not be used + * in advertising or publicity pertaining to distribution of the document + * or software without specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + #include "port_before.h" #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -46,6 +67,8 @@ static char rcsid[] = "$Id: ns_config.c,v 8.35 1998/05/05 19:44:48 halley Exp $" #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #ifdef HAVE_GETRUSAGE /* XXX */ @@ -55,6 +78,8 @@ static char rcsid[] = "$Id: ns_config.c,v 8.35 1998/05/05 19:44:48 halley Exp $" #include "named.h" #include "ns_parseutil.h" +/* Private. */ + static int tmpnum = 0; static int config_initialized = 0; @@ -90,8 +115,7 @@ free_zone_contents(struct zoneinfo *zp, int undefine_sym) { INSIST(zp != NULL); if (undefine_sym) - undefine_symbol(zone_symbol_table, zp->z_origin, - (zp->z_type << 16) | zp->z_class); + undefine_symbol(zone_symbol_table, zp->z_origin, zp->z_class); if (zp->z_flags & Z_TIMER_SET) { free_zone_timerinfo(zp); if (evClearTimer(ev, zp->z_timer) < 0) @@ -102,22 +126,44 @@ free_zone_contents(struct zoneinfo *zp, int undefine_sym) { } if (zp->z_origin != NULL) freestr(zp->z_origin); + zp->z_origin = NULL; if (zp->z_source != NULL) freestr(zp->z_source); + zp->z_source = NULL; + if (zp->z_ixfr_base != NULL) + freestr(zp->z_ixfr_base); + zp->z_ixfr_base = NULL; + if (zp->z_ixfr_tmp != NULL) + freestr(zp->z_ixfr_tmp); + zp->z_ixfr_tmp = NULL; if (zp->z_update_acl != NULL) free_ip_match_list(zp->z_update_acl); + zp->z_update_acl = NULL; if (zp->z_query_acl != NULL) free_ip_match_list(zp->z_query_acl); + zp->z_query_acl = NULL; if (zp->z_transfer_acl != NULL) free_ip_match_list(zp->z_transfer_acl); + zp->z_transfer_acl = NULL; #ifdef BIND_UPDATE if (zp->z_updatelog != NULL) freestr(zp->z_updatelog); + zp->z_updatelog = NULL; #endif /* BIND_UPDATE */ +#ifdef BIND_NOTIFY + if (zp->z_also_notify != NULL) + memput(zp->z_also_notify, + zp->z_notify_count * sizeof *zp->z_also_notify); + zp->z_also_notify = NULL; +#endif + block_signals(); + if (LINKED(zp, z_reloadlink)) + UNLINK(reloadingzones, zp, z_reloadlink); + unblock_signals(); } static void -free_zone(struct zoneinfo *zp) { +release_zone(struct zoneinfo *zp) { INSIST(zp != NULL); free_zone_contents(zp, 0); @@ -125,16 +171,16 @@ free_zone(struct zoneinfo *zp) { } struct zoneinfo * -find_zone(const char *name, int type, int class) { +find_zone(const char *name, int class) { struct zoneinfo *zp; symbol_value value; - ns_debug(ns_log_config, 3, "find_zone(%s,%d,%d)", name, type, class); - if (lookup_symbol(zone_symbol_table, name, - (type<<16) | class, &value)) { + ns_debug(ns_log_config, 3, "find_zone(%s, %d)", + *name ? name : ".", class); + if (lookup_symbol(zone_symbol_table, name, class, &value)) { INSIST(value.integer >= 0 && value.integer < nzones); - ns_debug(ns_log_config, 3, - "find_zone: existing zone %d", value.integer); + ns_debug(ns_log_config, 3, "find_zone: existing zone %d", + value.integer); zp = &zones[value.integer]; return (zp); } @@ -146,33 +192,11 @@ static struct zoneinfo * new_zone(int class, int type) { struct zoneinfo *zp; - if (zones != NULL) { - if (type == z_hint) { - zp = &zones[0]; - return (zp); - } - - for (zp = &zones[1]; zp < &zones[nzones]; zp++) - if (zp->z_type == z_nil) - return (zp); - } - - /* - * This code assumes that nzones never decreases. - */ - if (nzones % 64 == 0) { - ns_debug(ns_log_config, 1, "Reallocating zones structure"); - zp = (struct zoneinfo *) - memget((64 + nzones) * sizeof(struct zoneinfo)); - if (zp == NULL) - panic("no memory for more zones", NULL); - memcpy(zp, zones, nzones * sizeof(struct zoneinfo)); - memset(&zp[nzones], 0, 64 * sizeof(struct zoneinfo)); - memput(zones, nzones * sizeof(struct zoneinfo)); - zones = zp; - } - zp = &zones[nzones++]; + if (EMPTY(freezones)) + make_new_zones(); + zp = HEAD(freezones); + UNLINK(freezones, zp, z_freelink); return (zp); } @@ -181,7 +205,6 @@ new_zone(int class, int type) { */ static int validate_zone(struct zoneinfo *zp) { - int warnings = 0; char filename[MAXPATHLEN+1]; /* Check name */ @@ -204,7 +227,13 @@ validate_zone(struct zoneinfo *zp) { zp->z_origin); return (0); } - if (zp->z_type == z_hint && strcasecmp(zp->z_origin, "") != 0) { + if (zp->z_type == z_cache && ns_samename(zp->z_origin, "") != 1) { + ns_error(ns_log_config, + "only the root zone may be a cache zone (zone '%s')", + zp->z_origin); + return (0); + } + if (zp->z_type == z_hint && ns_samename(zp->z_origin, "") != 1) { ns_error(ns_log_config, "only the root zone may be a hint zone (zone '%s')", zp->z_origin); @@ -229,12 +258,25 @@ validate_zone(struct zoneinfo *zp) { return (0); } + if (zp->z_ixfr_base != NULL && strlen(zp->z_ixfr_base) > MAXPATHLEN) { + ns_error(ns_log_config, "ixfr filename too long for zone '%s'", + zp->z_origin); + return (0); + } + if (zp->z_ixfr_tmp != NULL && strlen(zp->z_ixfr_tmp) > MAXPATHLEN) { + ns_error(ns_log_config, "tmp ixfr filename too long for zone '%s'", + zp->z_origin); + return (0); + } + /* Check masters */ if (zp->z_addrcnt != 0) { - if (zp->z_type != z_slave && zp->z_type != z_stub) { + if (zp->z_type == z_master || zp->z_type == z_hint || + zp->z_type == z_cache) { ns_error(ns_log_config, "'masters' statement present for %s zone '%s'", - (zp->z_type == z_master) ? "master" : "hint", + (zp->z_type == z_master) ? "master" : + (zp->z_type == z_hint) ? "hint" : "cache", zp->z_origin); return (0); } @@ -247,6 +289,39 @@ validate_zone(struct zoneinfo *zp) { } } + /* Check allow-update and allow-transfer. */ + if (zp->z_update_acl || zp->z_transfer_acl) { + if (zp->z_type != z_master && zp->z_type != z_slave) { + ns_error(ns_log_config, + "'allow-{update,transfer}' option for non-{master,slave} zone '%s'", + zp->z_origin); + return (0); + } + } + + /* Check allow-query. */ + if (zp->z_query_acl) { + if (zp->z_type != z_master && + zp->z_type != z_slave && + zp->z_type != z_stub) { + ns_error(ns_log_config, + "'allow-query' option for non-{master,slave,stub} zone '%s'", + zp->z_origin); + return (0); + } + } + +#ifdef BIND_NOTIFY + /* Check notify */ + if (zp->z_notify != znotify_use_default) { + if (zp->z_type != z_master && zp->z_type != z_slave) { + ns_error(ns_log_config, + "'notify' given for non-master, non-slave zone '%s'", + zp->z_origin); + return (0); + } + } + /* Check also-notify */ if (zp->z_notify_count != 0) { if (zp->z_type != z_master && zp->z_type != z_slave) { @@ -256,9 +331,43 @@ validate_zone(struct zoneinfo *zp) { return (0); } } +#endif #ifdef BIND_UPDATE /* XXX need more checking here */ + if (!zp->z_updatelog && zp->z_source) { + /* XXX OS-specific filename validation here */ + if ((strlen(zp->z_source) + (sizeof ".log" - 1)) > + MAXPATHLEN) { + ns_error(ns_log_config, + "filename too long for dynamic zone '%s'", + zp->z_origin); + return (0); + } + /* this sprintf() is now safe */ + sprintf(filename, "%s.log", zp->z_source); + zp->z_updatelog = savestr(filename, 1); + } + + /* Check forward */ + if (zp->z_optset & OPTION_FORWARD_ONLY) { + if (zp->z_type == z_hint) { + ns_error(ns_log_config, + "'forward' given for hint zone '%s'", + zp->z_origin); + return (0); + } + } + /* Check forwarders */ + if (zp->z_fwdtab) { + if (zp->z_type == z_hint) { + ns_error(ns_log_config, + "'forwarders' given for hint zone '%s'", + zp->z_origin); + return (0); + } + } + if (zp->z_type == z_master) { if (!zp->z_soaincrintvl) zp->z_soaincrintvl = SOAINCRINTVL; @@ -266,22 +375,36 @@ validate_zone(struct zoneinfo *zp) { zp->z_dumpintvl = DUMPINTVL; if (!zp->z_deferupdcnt) zp->z_deferupdcnt = DEFERUPDCNT; - if (!zp->z_updatelog) { - /* XXX OS-specific filename validation here */ - if ((strlen(zp->z_source) + (sizeof ".log" - 1)) > - MAXPATHLEN) { - ns_error(ns_log_config, - "filename too long for dynamic zone '%s'", - zp->z_origin); - return (0); - } - /* this sprintf() is now safe */ - sprintf(filename, "%s.log", zp->z_source); - zp->z_updatelog = savestr(filename, 1); - } } #endif /* BIND_UPDATE */ + if (!zp->z_ixfr_base && zp->z_source) { + /* XXX OS-specific filename validation here */ + if ((strlen(zp->z_source) + (sizeof ".ixfr" - 1)) > + MAXPATHLEN) { + ns_error(ns_log_config, + "filename too long for dynamic zone '%s'", + zp->z_origin); + return (0); + } + /* this sprintf() is now safe */ + sprintf(filename, "%s.ixfr", zp->z_source); + zp->z_ixfr_base = savestr(filename, 1); + } + if (!zp->z_ixfr_tmp && zp->z_source) { + /* XXX OS-specific filename validation here */ + if ((strlen(zp->z_source) + (sizeof ".ixfr.tmp" - 1)) > + MAXPATHLEN) { + ns_error(ns_log_config, + "filename too long for dynamic zone '%s'", + zp->z_origin); + return (0); + } + /* this sprintf() is now safe */ + sprintf(filename, "%s.ixfr.tmp", zp->z_source); + zp->z_ixfr_tmp = savestr(filename, 1); + } + return (1); } @@ -308,6 +431,12 @@ begin_zone(char *name, int class) { zp->z_origin = name; zp->z_class = class; zp->z_checknames = not_set; + zp->z_log_size_ixfr = 0; + if (server_options->flags & OPTION_MAINTAIN_IXFR_BASE) + zp->z_maintain_ixfr_base = 1; + else + zp->z_maintain_ixfr_base = 0; + zp->z_max_log_size_ixfr = server_options->max_log_size_ixfr; zh.opaque = zp; return (zh); } @@ -318,7 +447,6 @@ begin_zone(char *name, int class) { */ static void update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { - struct stat f_time; char buf[MAXPATHLEN+1]; int i; @@ -337,7 +465,7 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { if ((zp->z_flags & Z_DYNAMIC) && !(new_zp->z_flags & Z_DYNAMIC) && ((zp->z_flags & Z_NEED_SOAUPDATE) || (zp->z_flags & Z_NEED_DUMP))) - (void)zonedump(zp); + (void) zonedump(zp, ISNOTIXFR); #endif /* @@ -348,6 +476,9 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { freestr(zp->z_origin); zp->z_origin = new_zp->z_origin; new_zp->z_origin = NULL; + zp->z_maintain_ixfr_base = new_zp->z_maintain_ixfr_base; + zp->z_max_log_size_ixfr = new_zp->z_max_log_size_ixfr; + zp->z_log_size_ixfr = new_zp->z_log_size_ixfr; zp->z_class = new_zp->z_class; zp->z_type = new_zp->z_type; zp->z_checknames = new_zp->z_checknames; @@ -368,11 +499,28 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { zp->z_transfer_acl = new_zp->z_transfer_acl; new_zp->z_transfer_acl = NULL; zp->z_max_transfer_time_in = new_zp->z_max_transfer_time_in; - +#ifdef BIND_NOTIFY zp->z_notify = new_zp->z_notify; - for (i = 0; i < new_zp->z_notify_count; i++) - zp->z_also_notify[i] = new_zp->z_also_notify[i]; + if (zp->z_also_notify) + memput(zp->z_also_notify, + zp->z_notify_count * sizeof *zp->z_also_notify); + zp->z_also_notify = new_zp->z_also_notify; zp->z_notify_count = new_zp->z_notify_count; + new_zp->z_also_notify = NULL; + new_zp->z_notify_count = 0; +#endif + if ((new_zp->z_flags & Z_FORWARD_SET) != 0) + zp->z_flags |= Z_FORWARD_SET; + else + zp->z_flags &= ~Z_FORWARD_SET; + if (zp->z_fwdtab != NULL) + free_forwarders(zp->z_fwdtab); + zp->z_fwdtab = new_zp->z_fwdtab; + new_zp->z_fwdtab = NULL; + + zp->z_dialup = new_zp->z_dialup; + zp->z_options = new_zp->z_options; + zp->z_optset = new_zp->z_optset; #ifdef BIND_UPDATE if (new_zp->z_flags & Z_DYNAMIC) @@ -387,24 +535,21 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { zp->z_updatelog = new_zp->z_updatelog; new_zp->z_updatelog = NULL; #endif /* BIND_UPDATE */ + zp->z_port = new_zp->z_port; /* - * now deal with files + * Now deal with files. */ switch (zp->z_type) { + case z_cache: + ns_panic(ns_log_config, 1, "impossible condition"); + break; case z_hint: ns_debug(ns_log_config, 1, "source = %s", new_zp->z_source); zp->z_refresh = 0; /* No dumping. */ - /* - * If we've loaded this file, and the file has - * not been modified and contains no $include, - * then there's no need to reload. - */ - if (zp->z_source && - !strcmp(new_zp->z_source, zp->z_source) && - !(zp->z_flags & Z_INCLUDE) && - stat(zp->z_source, &f_time) != -1 && - zp->z_ftime == f_time.st_mtime) { + if (zp->z_source != NULL && + strcmp(new_zp->z_source, zp->z_source) == 0 && + (reconfiging || !zonefile_changed_p(zp))) { ns_debug(ns_log_config, 1, "cache is up to date"); break; } @@ -412,28 +557,37 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { /* File has changed, or hasn't been loaded yet. */ if (zp->z_source) { freestr(zp->z_source); - clean_cache(fcachetab, 1); + purge_zone(zp->z_origin, fcachetab, zp->z_class); } zp->z_source = new_zp->z_source; new_zp->z_source = NULL; - ns_debug(ns_log_config, 1, "reloading zone"); - (void) db_load(zp->z_source, zp->z_origin, zp, NULL); + + if (zp->z_ixfr_base) + freestr(zp->z_ixfr_base); + zp->z_ixfr_base = new_zp->z_ixfr_base; + new_zp->z_ixfr_base = NULL; + + if (zp->z_ixfr_tmp) + freestr(zp->z_ixfr_tmp); + zp->z_ixfr_tmp = new_zp->z_ixfr_tmp; + new_zp->z_ixfr_tmp = NULL; + + ns_debug(ns_log_config, 1, "reloading hint zone"); + (void) db_load(zp->z_source, zp->z_origin, zp, NULL, + ISNOTIXFR); break; case z_master: ns_debug(ns_log_config, 1, "source = %s", new_zp->z_source); /* - * If we've loaded this file, and the file has - * not been modified and contains no $include, + * If we've loaded this file, and the file hasn't changed * then there's no need to reload. */ - if (zp->z_source && - !strcmp(new_zp->z_source, zp->z_source) && - !(zp->z_flags & Z_INCLUDE) && - stat(zp->z_source, &f_time) != -1 && - zp->z_ftime == f_time.st_mtime) { + if (zp->z_source != NULL && + strcmp(new_zp->z_source, zp->z_source) == 0 && + (reconfiging || !zonefile_changed_p(zp))) { ns_debug(ns_log_config, 1, "zone is up to date"); - break; /* zone is already up to date */ + break; } #ifdef BIND_UPDATE if (zp->z_source && (zp->z_flags & Z_DYNAMIC)) @@ -447,41 +601,27 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { freestr(zp->z_source); zp->z_source = new_zp->z_source; new_zp->z_source = NULL; - zp->z_flags &= ~Z_AUTH; - ns_stopxfrs(zp); - purge_zone(zp->z_origin, hashtab, zp->z_class); - ns_debug(ns_log_config, 1, "reloading zone"); -#ifdef BIND_UPDATE - if (zp->z_flags & Z_DYNAMIC) { - struct stat sb; - if (stat(zp->z_source, &sb) < 0) - ns_error(ns_log_config, "stat(%s) failed: %s", - zp->z_source, strerror(errno)); - else { - if (sb.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) - ns_warning(ns_log_config, - "dynamic zone file '%s' is writable", - zp->z_source); - } - } -#endif - if (!db_load(zp->z_source, zp->z_origin, zp, NULL)) - zp->z_flags |= Z_AUTH; - zp->z_refresh = 0; /* no maintenance needed */ - zp->z_time = 0; -#ifdef BIND_UPDATE - zp->z_lastupdate = 0; - if (zp->z_flags & Z_DYNAMIC) + if (zp->z_ixfr_base != NULL) + freestr(zp->z_ixfr_base); + zp->z_ixfr_base = new_zp->z_ixfr_base; + new_zp->z_ixfr_base = NULL; + + if (zp->z_ixfr_tmp != NULL) + freestr(zp->z_ixfr_tmp); + zp->z_ixfr_tmp = new_zp->z_ixfr_tmp; + new_zp->z_ixfr_tmp = NULL; + + if (reload_master(zp) == 1) { /* * Note that going to primary_reload * unconditionally reloads the zone. */ - if (merge_logs(zp) == 1) { - new_zp->z_source = savestr(zp->z_source, 1); - goto primary_reload; - } -#endif + new_zp->z_source = savestr(zp->z_source, 1); + new_zp->z_ixfr_base = savestr(zp->z_ixfr_base, 1); + new_zp->z_ixfr_tmp = savestr(zp->z_ixfr_tmp, 1); + goto primary_reload; + } break; case z_slave: @@ -505,10 +645,9 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { * current zone contents, try again now in case * we have a new server on the list. */ - if (zp->z_source && - (strcmp(new_zp->z_source, zp->z_source) || - (stat(zp->z_source, &f_time) == -1 || - (zp->z_ftime != f_time.st_mtime)))) { + if (zp->z_source != NULL && + (strcmp(new_zp->z_source, zp->z_source) != 0 || + ((!reconfiging) && zonefile_changed_p(zp)))) { ns_debug(ns_log_config, 1, "backup file changed or missing"); freestr(zp->z_source); @@ -516,42 +655,60 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { zp->z_serial = 0; /* force xfer */ ns_stopxfrs(zp); /* - * We only need to do_reload if we have + * We only need to reload if we have ever * successfully transferred the zone. */ - if (zp->z_flags & Z_AUTH) { + if ((zp->z_flags & Z_AUTH) != 0) { zp->z_flags &= ~Z_AUTH; /* - * Purge old data and reload parent so that - * NS records are present during the zone - * transfer. + * Purge old data and mark the parent for + * reloading so that NS records are present + * during the zone transfer. */ do_reload(zp->z_origin, zp->z_type, - zp->z_class); + zp->z_class, 1); } } if (zp->z_source == NULL) { zp->z_source = new_zp->z_source; new_zp->z_source = NULL; } - if (!(zp->z_flags & Z_AUTH)) + + if (zp->z_ixfr_base != NULL) + freestr(zp->z_ixfr_base); + zp->z_ixfr_base = new_zp->z_ixfr_base; + new_zp->z_ixfr_base = NULL; + + if (zp->z_ixfr_tmp != NULL) + freestr(zp->z_ixfr_tmp); + zp->z_ixfr_tmp = new_zp->z_ixfr_tmp; + new_zp->z_ixfr_tmp = NULL; + + if ((zp->z_flags & Z_AUTH) == 0) zoneinit(zp); -#ifdef FORCED_RELOAD else { /* ** Force secondary to try transfer soon ** after SIGHUP. */ - if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) - && reloading) { + if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0 && + reloading && !reconfiging) { qserial_retrytime(zp, tt.tv_sec); sched_zone_maint(zp); } } -#endif /* FORCED_RELOAD */ + break; + case z_forward: + /* + * We don't know if the forwarder's list has changed + * so just purge the cache. In the future we may want + * see if the forwarders list has changed and only + * do this then. + */ + clean_cache_from(zp->z_origin, hashtab); break; } - if ((zp->z_flags & Z_FOUND) && /* already found? */ + if ((zp->z_flags & Z_FOUND) != 0 && /* already found? */ (zp - zones) != DB_Z_CACHE) /* cache never sets Z_FOUND */ ns_error(ns_log_config, "Zone \"%s\" declared more than once", zp->z_origin); @@ -582,40 +739,43 @@ end_zone(zone_config zh, int should_install) { should_install); if (!should_install) { - free_zone(new_zp); + release_zone(new_zp); return; } if (!validate_zone(new_zp)) { ns_error(ns_log_config, "zone '%s' did not validate, skipping", zname); - free_zone(new_zp); + release_zone(new_zp); return; } - zp = find_zone(new_zp->z_origin, new_zp->z_type, new_zp->z_class); + zp = find_zone(new_zp->z_origin, new_zp->z_class); + if (zp != NULL && zp->z_type != new_zp->z_type) { + remove_zone(zp, "redefined"); + zp = NULL; + } if (zp == NULL) { zp = new_zone(new_zp->z_class, new_zp->z_type); INSIST(zp != NULL); value.integer = (zp - zones); define_symbol(zone_symbol_table, savestr(new_zp->z_origin, 1), - (new_zp->z_type << 16) | new_zp->z_class, - value, SYMBOL_FREE_KEY); + new_zp->z_class, value, SYMBOL_FREE_KEY); } ns_debug(ns_log_config, 5, "zone '%s', type = %d, class = %d", zname, new_zp->z_type, new_zp->z_class); if (new_zp->z_source != NULL) ns_debug(ns_log_config, 5, " file = %s", new_zp->z_source); ns_debug(ns_log_config, 5, " checknames = %d", new_zp->z_checknames); - if (new_zp->z_addrcnt) { + if (new_zp->z_addrcnt != 0) { int i; ns_debug(ns_log_config, 5, " masters:"); - for (i=0; i<new_zp->z_addrcnt; i++) + for (i = 0; i < new_zp->z_addrcnt; i++) ns_debug(ns_log_config, 5, " %s", inet_ntoa(new_zp->z_addr[i])); } update_zone_info(zp, new_zp); - free_zone(new_zp); + release_zone(new_zp); zh.opaque = NULL; } @@ -662,7 +822,63 @@ set_zone_checknames(zone_config zh, enum severity s) { } int +set_zone_ixfr_file(zone_config zh, char *filename) { + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + + /* Fail if filename already set for this zone */ + if (zp->z_ixfr_base != NULL) + return (0); + zp->z_ixfr_base = filename; + if (zp->z_ixfr_tmp == NULL) { + int len = strlen(zp->z_ixfr_base) + (sizeof ".tmp" - 1); + char *str = (char *) memget(len); + + sprintf(str, "%s.tmp", zp->z_ixfr_base); + zp->z_ixfr_tmp = savestr(str, 1); + memput(str, len); + } + + return (1); +} + +int +set_zone_ixfr_tmp(zone_config zh, char *filename) { + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + + /* Fail if filename already set for this zone */ + if (zp->z_ixfr_tmp != NULL) + return (0); + zp->z_ixfr_tmp = filename; + return (1); +} + +int +set_zone_dialup(zone_config zh, int value) { + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + + if (value) { + zp->z_dialup = zdialup_yes; +#ifdef BIND_NOTIFY + zp->z_notify = znotify_yes; +#endif + } else + zp->z_dialup = zdialup_no; + + return (1); +} + +int set_zone_notify(zone_config zh, int value) { +#ifdef BIND_NOTIFY struct zoneinfo *zp; zp = zh.opaque; @@ -672,6 +888,17 @@ set_zone_notify(zone_config zh, int value) { zp->z_notify = znotify_yes; else zp->z_notify = znotify_no; +#endif + return (1); +} + +int +set_zone_maintain_ixfr_base(zone_config zh, int value) { + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + zp->z_maintain_ixfr_base = value; return (1); } @@ -683,7 +910,7 @@ set_zone_update_acl(zone_config zh, ip_match_list iml) { zp = zh.opaque; INSIST(zp != NULL); - /* Fail if checknames already set for this zone */ + /* Fail if update_acl already set for this zone */ if (zp->z_update_acl != NULL) return (0); zp->z_update_acl = iml; @@ -712,6 +939,14 @@ set_zone_query_acl(zone_config zh, ip_match_list iml) { } int +set_zone_master_port(zone_config zh, u_short port) { + struct zoneinfo *zp = zh.opaque; + + zp->z_port = port; + return (1); +} + +int set_zone_transfer_source(zone_config zh, struct in_addr ina) { struct zoneinfo *zp = zh.opaque; @@ -748,6 +983,37 @@ set_zone_transfer_time_in(zone_config zh, long max_time) { } int +set_zone_max_log_size_ixfr(zone_config zh, int size) { + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + + zp->z_max_log_size_ixfr = size; + return (0); +} + +int +set_zone_pubkey(zone_config zh, const int flags, const int proto, + const int alg, const char *str) +{ + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + + INSIST(zp != NULL && zp->z_origin != NULL); + return (add_trusted_key(zp->z_origin, flags, proto, alg, str)); +} + +int +set_trusted_key(const char *name, const int flags, const int proto, + const int alg, const char *str) { + INSIST(name != NULL); + return (add_trusted_key(name, flags, proto, alg, str)); +} + +int add_zone_master(zone_config zh, struct in_addr address) { struct zoneinfo *zp; @@ -766,18 +1032,51 @@ add_zone_master(zone_config zh, struct in_addr address) { int add_zone_notify(zone_config zh, struct in_addr address) { +#ifdef BIND_NOTIFY struct zoneinfo *zp; + int i; zp = zh.opaque; INSIST(zp != NULL); - zp->z_also_notify[zp->z_notify_count] = address; - zp->z_notify_count++; - if (zp->z_notify_count >= NSMAX) { - ns_warning(ns_log_config, "also-notify set full for zone '%s'", - zp->z_origin); - zp->z_notify_count = NSMAX - 1; + /* Check for duplicates. */ + + for (i = 0; i < zp->z_notify_count; i++) { + if (memcmp(zp->z_also_notify + i, + &address, sizeof address) == 0) { + ns_warning(ns_log_config, + "duplicate also-notify address ignored [%s] for zone '%s'", + inet_ntoa(address), zp->z_origin); + return (1); + } } + i = 0; + + if (zp->z_also_notify == NULL) { + zp->z_also_notify = memget(sizeof *zp->z_also_notify); + if (zp->z_also_notify == NULL) + i = 1; + } else { + register size_t size; + register struct in_addr *an_tmp; + size = zp->z_notify_count * sizeof *zp->z_also_notify; + an_tmp = memget(size + sizeof *zp->z_also_notify); + if (an_tmp == NULL) { + i = 1; + } else { + memcpy(an_tmp, zp->z_also_notify, size); + memput(zp->z_also_notify, size); + zp->z_also_notify = an_tmp; + } + } + if (i == 0) { + zp->z_also_notify[zp->z_notify_count] = address; + zp->z_notify_count++; + } else { + ns_warning(ns_log_config, "also-notify add failed (memget) [%s] for zone '%s'", + inet_ntoa(address), zp->z_origin); + } +#endif return (1); } @@ -786,13 +1085,12 @@ add_zone_notify(zone_config zh, struct in_addr address) { options new_options() { options op; - ip_match_list iml; - ip_match_element ime; op = (options)memget(sizeof (struct options)); if (op == NULL) panic("memget failed in new_options()", NULL); + op->version = savestr(ShortVersion, 1); op->directory = savestr(".", 1); op->pid_filename = savestr(_PATH_PIDFILE, 1); op->named_xfer = savestr(_PATH_XFER, 1); @@ -803,21 +1101,24 @@ new_options() { op->transfers_in = DEFAULT_XFERS_RUNNING; op->transfers_per_ns = DEFAULT_XFERS_PER_NS; op->transfers_out = 0; + op->serial_queries = MAXQSERIAL; op->transfer_format = axfr_one_answer; op->max_transfer_time_in = MAX_XFER_TIME; memset(&op->query_source, 0, sizeof op->query_source); op->query_source.sin_family = AF_INET; op->query_source.sin_addr.s_addr = htonl(INADDR_ANY); op->query_source.sin_port = htons(0); /* INPORT_ANY */ + op->axfr_src.s_addr = 0; +#ifdef BIND_NOTIFY + op->notify_count = 0; + op->also_notify = NULL; +#endif + op->blackhole_acl = NULL; op->query_acl = NULL; op->transfer_acl = NULL; - /* default topology is { localhost; localnets; } */ - iml = new_ip_match_list(); - ime = new_ip_match_localhost(); - add_to_ip_match_list(iml, ime); - ime = new_ip_match_localnets(); - add_to_ip_match_list(iml, ime); - op->topology = iml; + op->recursion_acl = NULL; + op->sortlist = NULL; + op->topology = NULL; op->data_size = 0UL; /* use system default */ op->stack_size = 0UL; /* use system default */ op->core_size = 0UL; /* use system default */ @@ -831,6 +1132,12 @@ new_options() { op->clean_interval = 3600; op->interface_interval = 3600; op->stats_interval = 3600; + op->ordering = NULL; + op->max_ncache_ttl = DEFAULT_MAX_NCACHE_TTL; + op->lame_ttl = NTTL; + op->heartbeat_interval = 3600; + op->max_log_size_ixfr = 20; + op->minroots = MINROOTS; return (op); } @@ -838,6 +1145,8 @@ void free_options(options op) { INSIST(op != NULL); + if (op->version) + freestr(op->version); if (op->directory) freestr(op->directory); if (op->pid_filename) @@ -850,10 +1159,22 @@ free_options(options op) { freestr(op->stats_filename); if (op->memstats_filename) freestr(op->memstats_filename); +#ifdef BIND_NOTIFY + if (op->also_notify) + free_also_notify(op); +#endif + if (op->blackhole_acl) + free_ip_match_list(op->blackhole_acl); if (op->query_acl) free_ip_match_list(op->query_acl); + if (op->recursion_acl) + free_ip_match_list(op->recursion_acl); if (op->transfer_acl) free_ip_match_list(op->transfer_acl); + if (op->sortlist) + free_ip_match_list(op->sortlist); + if (op->ordering) + free_rrset_order_list(op->ordering); if (op->topology) free_ip_match_list(op->topology); if (op->listen_list) @@ -863,9 +1184,9 @@ free_options(options op) { memput(op, sizeof *op); } -void -set_boolean_option(options op, int bool_opt, int value) { - INSIST(op != NULL); +static void +set_boolean_option(u_int *op_flags, int bool_opt, int value) { + INSIST(op_flags != NULL); switch (bool_opt) { case OPTION_NORECURSE: @@ -875,18 +1196,45 @@ set_boolean_option(options op, int bool_opt, int value) { case OPTION_NONOTIFY: case OPTION_NONAUTH_NXDOMAIN: case OPTION_MULTIPLE_CNAMES: + case OPTION_USE_IXFR: + case OPTION_MAINTAIN_IXFR_BASE: case OPTION_HOSTSTATS: case OPTION_DEALLOC_ON_EXIT: + case OPTION_USE_ID_POOL: + case OPTION_NORFC2308_TYPE1: + case OPTION_NODIALUP: + case OPTION_TREAT_CR_AS_SPACE: if (value) - op->flags |= bool_opt; + *op_flags |= bool_opt; else - op->flags &= ~bool_opt; + *op_flags &= ~bool_opt; break; default: panic("unexpected option in set_boolean_option", NULL); } } +void +set_global_boolean_option(options op, int bool_opt, int value) { + + INSIST(op != NULL); + + set_boolean_option(&op->flags, bool_opt, value); +} + +void +set_zone_boolean_option(zone_config zh, int bool_opt, int value) { + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + + set_boolean_option(&zp->z_options, bool_opt, value); + + /* Flag that zone option overrides corresponding global option */ + zp->z_optset |= bool_opt; +} + #ifdef HAVE_GETRUSAGE enum limit { Datasize, Stacksize, Coresize, Files }; @@ -897,6 +1245,8 @@ static struct rlimit initial_num_files; static void get_initial_limits() { + int fdlimit = evHighestFD(ev) + 1; + # ifdef RLIMIT_DATA if (getrlimit(RLIMIT_DATA, &initial_data_size) < 0) ns_warning(ns_log_config, "getrlimit(DATA): %s", @@ -916,6 +1266,19 @@ get_initial_limits() { if (getrlimit(RLIMIT_NOFILE, &initial_num_files) < 0) ns_warning(ns_log_config, "getrlimit(NOFILE): %s", strerror(errno)); + else if (initial_num_files.rlim_cur > fdlimit) { + initial_num_files.rlim_cur = fdlimit; + if (initial_num_files.rlim_cur > initial_num_files.rlim_max) + initial_num_files.rlim_max = fdlimit; + if (setrlimit(RLIMIT_NOFILE, &initial_num_files) < 0) { + ns_warning(ns_log_config, "setrlimit(files): %s", + strerror(errno)); + } else { + ns_warning(ns_log_config, + "limit files set to fdlimit (%d)", + fdlimit); + } + } # endif } @@ -923,13 +1286,14 @@ static void ns_rlimit(enum limit limit, u_long limit_value) { struct rlimit limits, old_limits; int rlimit = -1; + int fdlimit = evHighestFD(ev) + 1; char *name; rlimit_type value; if (limit_value == ULONG_MAX) { #ifndef RLIMIT_FILE_INFINITY if (limit == Files) - value = MAX((rlimit_type)sysconf(_SC_OPEN_MAX), + value = MIN((rlimit_type)evHighestFD(ev) + 1, initial_num_files.rlim_max); else #endif @@ -970,7 +1334,8 @@ ns_rlimit(enum limit limit, u_long limit_value) { name = "max number of open files"; if (value == 0) limits = initial_num_files; - /* XXX check < FD_SETSIZE? */ + if (value > fdlimit) + limits.rlim_cur = limits.rlim_max = value = fdlimit; break; default: name = NULL; /* Make gcc happy. */ @@ -994,8 +1359,7 @@ ns_rlimit(enum limit limit, u_long limit_value) { return; } else { if (value == 0) - ns_debug(ns_log_config, 3, "%s is default", - name); + ns_debug(ns_log_config, 3, "%s is default", name); else if (value == RLIM_INFINITY) ns_debug(ns_log_config, 3, "%s is unlimited", name); else @@ -1155,7 +1519,7 @@ periodic_getnetconf(evContext ctx, void *uap, struct timespec due, { getnetconf(1); } - + static void set_interval_timer(int which_timer, int interval) { evTimerID *tid = NULL; @@ -1174,6 +1538,10 @@ set_interval_timer(int which_timer, int interval) { tid = &stats_timer; func = ns_logstats; break; + case HEARTBEAT_TIMER: + tid = &heartbeat_timer; + func = ns_heartbeat; + break; default: ns_panic(ns_log_config, 1, "set_interval_timer: unknown timer %d", which_timer); @@ -1215,7 +1583,6 @@ set_interval_timer(int which_timer, int interval) { */ void set_options(options op, int is_default) { - listen_info li; INSIST(op != NULL); if (op->listen_list == NULL) { @@ -1231,6 +1598,18 @@ set_options(options op, int is_default) { add_to_ip_match_list(iml, ime); add_listen_on(op, htons(NS_DEFAULTPORT), iml); } + if (op->topology == NULL) { + ip_match_list iml; + ip_match_element ime; + + /* default topology is { localhost; localnets; } */ + iml = new_ip_match_list(); + ime = new_ip_match_localhost(); + add_to_ip_match_list(iml, ime); + ime = new_ip_match_localnets(); + add_to_ip_match_list(iml, ime); + op->topology = iml; + } if (server_options != NULL) free_options(server_options); server_options = op; @@ -1263,6 +1642,14 @@ set_options(options op, int is_default) { /* XXX currently transfers_out is not used */ + if (!op->max_ncache_ttl) + op->max_ncache_ttl = DEFAULT_MAX_NCACHE_TTL; + else if (op->max_ncache_ttl > max_cache_ttl) + op->max_ncache_ttl = max_cache_ttl; + + if (op->lame_ttl > (3 * NTTL)) + op->lame_ttl = 3 * NTTL; + /* * Limits */ @@ -1276,7 +1663,6 @@ set_options(options op, int is_default) { ns_info(ns_log_config, "cannot set resource limits on this system"); #endif - /* * Timers */ @@ -1284,6 +1670,8 @@ set_options(options op, int is_default) { set_interval_timer(INTERFACE_TIMER, server_options->interface_interval); set_interval_timer(STATS_TIMER, server_options->stats_interval); + set_interval_timer(HEARTBEAT_TIMER, + server_options->heartbeat_interval); options_installed = 1; default_options_installed = is_default; @@ -1295,6 +1683,129 @@ use_default_options() { } /* + * rrset order types + */ +static struct res_sym order_table [] = { + { unknown_order, " unknown " }, /* can't match */ + { fixed_order, "fixed" }, + { cyclic_order, "cyclic" }, + { random_order, "random" }, + { unknown_order, NULL } +}; + +/* + * Return the print name of the ordering value. + */ +const char * +p_order(int order) { + return (__sym_ntos(order_table, order, (int *)0)); +} + +/* + * Lookup the ordering by name and return the matching enum value. + */ +enum ordering +lookup_ordering(const char *name) { + int i; + + for (i = 0; order_table[i].name != NULL; i++) + if (strcasecmp(name,order_table[i].name) == 0) + return ((enum ordering)order_table[i].number); + return (unknown_order); +} + +/* + * rrset-order Lists + */ +rrset_order_list +new_rrset_order_list() { + rrset_order_list rol ; + + rol = (rrset_order_list)memget(sizeof (struct rrset_order_list)); + if (rol == NULL) + panic("memget failed in new_rrset_order_list", NULL); + rol->first = NULL; + rol->last = NULL; + + return (rol); +} + +void +free_rrset_order_list(rrset_order_list rol) { + rrset_order_element roe, next_element; + + for (roe = rol->first; roe != NULL; roe = next_element) { + next_element = roe->next; + freestr(roe->name); + memput(roe, sizeof (*roe)); + } + memput(rol, sizeof (*rol)); +} + + +void +add_to_rrset_order_list(rrset_order_list rol, rrset_order_element roe) { + INSIST(rol != NULL); + INSIST(roe != NULL); + + if (rol->last != NULL) + rol->last->next = roe; + roe->next = NULL; + rol->last = roe; + if (rol->first == NULL) + rol->first = roe; +} + +/* XXX this isn't being used yet, but it probably should be. Where? */ +void +dprint_rrset_order_list(int category, rrset_order_list rol, int indent, + char *allow, char *deny) { + rrset_order_element roe ; + char spaces[40+1]; + + INSIST(rol != NULL); + + if (indent > 40) + indent = 40; + if (indent) + memset(spaces, ' ', indent); + spaces[indent] = '\0'; + + for (roe = rol->first; roe != NULL; roe = roe->next) { + ns_debug(category, 7, "%sclass %s type %s name %s order %s", + spaces, p_class(roe->class), p_type(roe->type), + roe->name, p_order(roe->order)); + } +} + + +rrset_order_element +new_rrset_order_element(int class, int type, char *name, enum ordering order) +{ + rrset_order_element roe; + int i ; + + roe = (rrset_order_element)memget(sizeof (struct rrset_order_element)); + if (roe == NULL) + panic("memget failed in new_rrset_order_element", NULL); + roe->class = class ; + roe->type = type ; + roe->name = name; + roe->order = order; + + i = strlen(roe->name) - 1; + INSIST (i >= 0); + if (roe->name[i - 1] == '.') { + /* We compare from right to left so we don't need a dot on + the end. */ + roe->name[i - 1] = '\0' ; + } + + return roe ; +} + + +/* * IP Matching Lists */ @@ -1390,6 +1901,19 @@ new_ip_match_indirect(ip_match_list iml) { } ip_match_element +new_ip_match_key(DST_KEY *dst_key) { + ip_match_element ime; + + ime = (ip_match_element)memget(sizeof (struct ip_match_element)); + if (ime == NULL) + panic("memget failed in new_ip_match_key", NULL); + ime->type = ip_match_key; + ime->flags = 0; + ime->u.key.key = dst_key; + return (ime); +} + +ip_match_element new_ip_match_localhost() { ip_match_element ime; @@ -1445,7 +1969,6 @@ dprint_ip_match_list(int category, ip_match_list iml, int indent, char spaces[40+1]; char addr_text[sizeof "255.255.255.255"]; char mask_text[sizeof "255.255.255.255"]; - char *tmp; INSIST(iml != NULL); @@ -1488,6 +2011,11 @@ dprint_ip_match_list(int category, ip_match_list iml, int indent, ime->u.indirect.list, indent+2, allow, deny); break; + case ip_match_key: + ns_debug(category, 7, "%s%skey %s", spaces, + (ime->flags & IP_MATCH_NEGATE) ? deny : allow, + ime->u.key.key->dk_key_name); + break; default: panic("unexpected ime type in dprint_ip_match_list()", NULL); @@ -1496,7 +2024,9 @@ dprint_ip_match_list(int category, ip_match_list iml, int indent, } int -ip_match_address(ip_match_list iml, struct in_addr address) { +ip_match_addr_or_key(ip_match_list iml, struct in_addr address, + DST_KEY *key) +{ ip_match_element ime; int ret; int indirect; @@ -1518,13 +2048,25 @@ ip_match_address(ip_match_list iml, struct in_addr address) { ime->u.indirect.list = local_networks; indirect = 1; break; + case ip_match_key: + if (key == NULL) { + indirect = 0; + break; + } + else { + if (ns_samename(ime->u.key.key->dk_key_name, + key->dk_key_name) == 1) + return (1); + else + continue; + } default: - indirect = 0; /* Make gcc happy. */ - panic("unexpected ime type in ip_match_address()", + panic("unexpected ime type in ip_match_addr_or_key()", NULL); } if (indirect) { - ret = ip_match_address(ime->u.indirect.list, address); + ret = ip_match_addr_or_key(ime->u.indirect.list, + address, key); if (ret >= 0) { if (ime->flags & IP_MATCH_NEGATE) ret = (ret) ? 0 : 1; @@ -1544,18 +2086,30 @@ ip_match_address(ip_match_list iml, struct in_addr address) { } int -ip_address_allowed(ip_match_list iml, struct in_addr address) { +ip_match_address(ip_match_list iml, struct in_addr address) { + return ip_match_addr_or_key(iml, address, NULL); +} + +int +ip_addr_or_key_allowed(ip_match_list iml, struct in_addr address, + DST_KEY *key) +{ int ret; if (iml == NULL) return (0); - ret = ip_match_address(iml, address); + ret = ip_match_addr_or_key(iml, address, key); if (ret < 0) ret = 0; return (ret); } int +ip_address_allowed(ip_match_list iml, struct in_addr address) { + return(ip_addr_or_key_allowed(iml, address, NULL)); +} + +int ip_match_network(ip_match_list iml, struct in_addr address, struct in_addr mask) { ip_match_element ime; @@ -1579,6 +2133,9 @@ ip_match_network(ip_match_list iml, struct in_addr address, ime->u.indirect.list = local_networks; indirect = 1; break; + case ip_match_key: + indirect = 0; + break; default: indirect = 0; /* Make gcc happy. */ panic("unexpected ime type in ip_match_network()", @@ -1630,6 +2187,9 @@ distance_of_address(ip_match_list iml, struct in_addr address) { ime->u.indirect.list = local_networks; indirect = 1; break; + case ip_match_key: + indirect = 0; + return (-1); default: indirect = 0; /* Make gcc happy. */ panic("unexpected ime type in distance_of_address()", @@ -1666,14 +2226,14 @@ int ip_match_is_none(ip_match_list iml) { ip_match_element ime; - if (iml == NULL) + if ((iml == NULL) || (iml->first == NULL)) return (1); ime = iml->first; if (ime->type == ip_match_indirect) { if (ime->flags & IP_MATCH_NEGATE) return (0); iml = ime->u.indirect.list; - if (iml == NULL) + if ((iml == NULL) || (iml->first == NULL)) return (0); ime = iml->first; } @@ -1694,30 +2254,13 @@ ip_match_is_none(ip_match_list iml) { * forward zones. */ -void -add_forwarder(options op, struct in_addr address) { - struct fwdinfo *fip = NULL, *ftp = NULL; - -#ifdef SLAVE_FORWARD - int forward_count = 0; -#endif - - INSIST(op != NULL); +static void +add_forwarder(struct fwdinfo **fipp, struct in_addr address) { + struct fwdinfo *fip = *fipp, *ftp = NULL; /* On multiple forwarder lines, move to end of the list. */ -#ifdef SLAVE_FORWARD - if (op->fwdtab != NULL) { - forward_count++; - for (fip = op->fwdtab; fip->next != NULL; fip = fip->next) - forward_count++; - } -#else - if (op->fwdtab != NULL) { - for (fip = op->fwdtab; fip->next != NULL; fip = fip->next) { - ; - } - } -#endif /* SLAVE_FORWARD */ + while (fip != NULL && fip->next != NULL) + fip = fip->next; ftp = (struct fwdinfo *)memget(sizeof(struct fwdinfo)); if (!ftp) @@ -1733,19 +2276,95 @@ add_forwarder(options op, struct in_addr address) { return; } #endif /* FWD_LOOP */ - ns_debug(ns_log_config, 2, "added forwarder %s", inet_ntoa(address)); ftp->next = NULL; - if (op->fwdtab == NULL) - op->fwdtab = ftp; /* First time only */ + if (fip == NULL) + *fipp = ftp; /* First time only */ else fip->next = ftp; +} + +void +free_also_notify(options op) { +#ifdef BIND_NOTIFY + memput(op->also_notify, op->notify_count * sizeof *op->also_notify); + op->also_notify = NULL; + op->notify_count = 0; +#endif +} + +int +add_global_also_notify(options op, struct in_addr address) { +#ifdef BIND_NOTIFY + int i; + + INSIST(op != NULL); + + ns_debug(ns_log_config, 2, "adding global notify %s", + inet_ntoa(address)); + + /* Check for duplicates. */ + + for (i = 0; i < op->notify_count; i++) { + if (memcmp(op->also_notify + i, + &address, sizeof address) == 0) { + ns_warning(ns_log_config, + "duplicate global also-notify address ignored [%s]", + inet_ntoa(address)); + return (1); + } + } + i = 0; + + if (op->also_notify == NULL) { + op->also_notify = memget(sizeof *op->also_notify); + if (op->also_notify == NULL) + i = 1; + } else { + register size_t size; + register struct in_addr *an_tmp; + size = op->notify_count * sizeof *op->also_notify; + an_tmp = memget(size + sizeof *op->also_notify); + if (an_tmp == NULL) { + i = 1; + } else { + memcpy(an_tmp, op->also_notify, size); + memput(op->also_notify, size); + op->also_notify = an_tmp; + } + } + if (i == 0) { + op->also_notify[op->notify_count] = address; + op->notify_count++; + } else { + ns_warning(ns_log_config, + "global also-notify add failed (memget) [%s]", + inet_ntoa(address)); + } +#endif + return (1); +} + +void +add_global_forwarder(options op, struct in_addr address) { #ifdef SLAVE_FORWARD - forward_count++; + struct fwdinfo *fip; + int forward_count; +#endif + + INSIST(op != NULL); + + ns_debug(ns_log_config, 2, "adding default forwarder %s", + inet_ntoa(address)); + add_forwarder(&op->fwdtab, address); + +#ifdef SLAVE_FORWARD /* ** Set the slave retry time to 60 seconds total divided ** between each forwarder */ + for (forward_count = 0, fip = op->fwdtab; fip != NULL; fip = fip->next) + forward_count++; if (forward_count != 0) { slave_retry = (int) (60 / forward_count); if(slave_retry <= 0) @@ -1755,6 +2374,32 @@ add_forwarder(options op, struct in_addr address) { } void +set_zone_forward(zone_config zh) { + struct zoneinfo *zp; + zp = zh.opaque; + + zp->z_flags |= Z_FORWARD_SET; + set_zone_boolean_option(zh, OPTION_FORWARD_ONLY, 0); +} + +void +add_zone_forwarder(zone_config zh, struct in_addr address) { + struct zoneinfo *zp; + char *zname; + + zp = zh.opaque; + INSIST(zp != NULL); + + zname = (zp->z_origin[0] == '\0') ? "." : zp->z_origin; + ns_debug(ns_log_config, 2, "adding forwarder %s for zone zone '%s'", + inet_ntoa(address), zname); + + zp->z_flags |= Z_FORWARD_SET; + + add_forwarder(&zp->z_fwdtab, address); +} + +void free_forwarders(struct fwdinfo *fwdtab) { struct fwdinfo *ftp, *fnext; @@ -1762,13 +2407,13 @@ free_forwarders(struct fwdinfo *fwdtab) { fnext = ftp->next; memput(ftp, sizeof *ftp); } + fwdtab = NULL; } /* * Servers */ - static server_info new_server(struct in_addr address) { server_info si; @@ -1782,7 +2427,11 @@ new_server(struct in_addr address) { si->transfer_format = axfr_use_default; si->key_list = NULL; si->next = NULL; - return si; + if (server_options->flags & OPTION_MAINTAIN_IXFR_BASE) + si->flags |= SERVER_INFO_SUPPORT_IXFR; + else + si->flags &= ~SERVER_INFO_SUPPORT_IXFR; + return (si); } static void @@ -1839,6 +2488,14 @@ free_nameserver_info() { } } +static void +free_secretkey_info() { + if (secretkey_info != NULL) { + free_key_info_list(secretkey_info); + secretkey_info = NULL; + } +} + server_config begin_server(struct in_addr address) { server_config sc; @@ -1872,6 +2529,7 @@ set_server_option(server_config sc, int bool_opt, int value) { switch (bool_opt) { case SERVER_INFO_BOGUS: + case SERVER_INFO_SUPPORT_IXFR: if (value) si->flags |= bool_opt; else @@ -1908,7 +2566,7 @@ set_server_transfer_format(server_config sc, } void -add_server_key_info(server_config sc, key_info ki) { +add_server_key_info(server_config sc, DST_KEY *dst_key) { server_info si; si = sc.opaque; @@ -1917,44 +2575,75 @@ add_server_key_info(server_config sc, key_info ki) { if (si->key_list == NULL) si->key_list = new_key_info_list(); - add_to_key_info_list(si->key_list, ki); + add_to_key_info_list(si->key_list, dst_key); } /* * Keys */ -key_info +DST_KEY * new_key_info(char *name, char *algorithm, char *secret) { - key_info ki; + DST_KEY *dst_key; + int alg, blen; + u_char buffer[1024]; INSIST(name != NULL); INSIST(algorithm != NULL); INSIST(secret != NULL); - ki = (key_info)memget(sizeof (struct key_info)); - if (ki == NULL) - panic("memget failed in new_key_info", NULL); - ki->name = name; - ki->algorithm = algorithm; - ki->secret = secret; - return (ki); + alg = tsig_alg_value(algorithm); + if (alg == -1) { + ns_warning(ns_log_config, "Unsupported TSIG algorithm %s", + algorithm); + return (NULL); + } + + blen = b64_pton(secret, buffer, sizeof(buffer)); + if (blen < 0) { + ns_warning(ns_log_config, "Invalid TSIG secret \"%s\"", secret); + return (NULL); + } + dst_key = dst_buffer_to_key(name, alg, + NS_KEY_TYPE_AUTH_ONLY|NS_KEY_NAME_ENTITY, + NS_KEY_PROT_ANY, buffer, blen); + if (dst_key == NULL) + ns_warning(ns_log_config, + "dst_buffer_to_key failed in new_key_info"); + return (dst_key); } void -free_key_info(key_info ki) { - INSIST(ki != NULL); - freestr(ki->name); - freestr(ki->algorithm); - freestr(ki->secret); - memput(ki, sizeof *ki); +free_key_info(DST_KEY *dst_key) { + INSIST(dst_key != NULL); + dst_free_key(dst_key); +} + +DST_KEY * +find_key(char *name, char *algorithm) { + key_list_element ke; + + if (secretkey_info == NULL) + return (NULL); + + for (ke = secretkey_info->first; ke != NULL; ke = ke->next) { + DST_KEY *dst_key = ke->key; + + if (ns_samename(name, dst_key->dk_key_name) != 1) + continue; + if (algorithm == NULL || + dst_key->dk_alg == tsig_alg_value(algorithm)) + break; + } + if (ke == NULL) + return (NULL); + return (ke->key); } void -dprint_key_info(key_info ki) { - INSIST(ki != NULL); - ns_debug(ns_log_config, 7, "key %s", ki->name); - ns_debug(ns_log_config, 7, " algorithm %s", ki->algorithm); - ns_debug(ns_log_config, 7, " secret %s", ki->secret); +dprint_key_info(DST_KEY *dst_key) { + INSIST(dst_key != NULL); + ns_debug(ns_log_config, 7, "key %s", dst_key->dk_key_name); + ns_debug(ns_log_config, 7, " algorithm %d", dst_key->dk_alg); } key_info_list @@ -1983,16 +2672,16 @@ free_key_info_list(key_info_list kil) { } void -add_to_key_info_list(key_info_list kil, key_info ki) { +add_to_key_info_list(key_info_list kil, DST_KEY *dst_key) { key_list_element kle; INSIST(kil != NULL); - INSIST(ki != NULL); + INSIST(dst_key != NULL); kle = (key_list_element)memget(sizeof (struct key_list_element)); if (kle == NULL) panic("memget failed in add_to_key_info_list()", NULL); - kle->info = ki; + kle->key = dst_key; if (kil->last != NULL) kil->last->next = kle; kle->next = NULL; @@ -2008,7 +2697,7 @@ dprint_key_info_list(key_info_list kil) { INSIST(kil != NULL); for (kle = kil->first; kle != NULL; kle = kle->next) - dprint_key_info(kle->info); + dprint_key_info(kle->key); } /* @@ -2098,7 +2787,6 @@ open_special_channels() { void set_logging(log_config log_cfg, int is_default) { log_context lc; - int skip_debug = 0; INSIST(log_cfg != NULL); lc = log_cfg->log_ctx; @@ -2203,7 +2891,6 @@ use_default_logging() { static void init_default_log_channels() { - FILE *null_stream; u_int flags; char *name; FILE *stream; @@ -2244,9 +2931,8 @@ shutdown_default_log_channels() { log_free_channel(null_channel); } -void +void init_logging() { - int i; int size; const struct ns_sym *s; char category_name[256]; @@ -2266,7 +2952,7 @@ init_logging() { use_default_logging(); } -void +void shutdown_logging() { int size; const struct ns_sym *s; @@ -2279,6 +2965,7 @@ shutdown_logging() { freestr(logging_categories[s->number]); size = ns_log_max_category * (sizeof (char *)); memput(logging_categories, size); + logging_categories = NULL; } /* @@ -2297,6 +2984,7 @@ init_configuration() { zone_symbol_table = new_symbol_table(ZONE_SYM_TABLE_SIZE, NULL); use_default_options(); parser_initialize(); + ns_ctl_initialize(); config_initialized = 1; } @@ -2304,6 +2992,7 @@ void shutdown_configuration() { REQUIRE(config_initialized); + ns_ctl_shutdown(); if (server_options != NULL) { free_options(server_options); server_options = NULL; @@ -2311,6 +3000,7 @@ shutdown_configuration() { if (current_pid_filename != NULL) freestr(current_pid_filename); free_nameserver_info(); + free_secretkey_info(); free_symbol_table(zone_symbol_table); parser_shutdown(); config_initialized = 0; @@ -2329,6 +3019,7 @@ load_configuration(const char *filename) { * global data structures we'll be updating. */ free_nameserver_info(); + free_secretkey_info(); bogus_nameservers = new_ip_match_list(); options_installed = 0; diff --git a/contrib/bind/bin/named/ns_ctl.c b/contrib/bind/bin/named/ns_ctl.c new file mode 100644 index 0000000..259093b --- /dev/null +++ b/contrib/bind/bin/named/ns_ctl.c @@ -0,0 +1,866 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ns_ctl.c,v 8.28 1999/10/13 16:39:04 vixie Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1997-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* Extern. */ + +#include "port_before.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <time.h> +#include <unistd.h> +#include <fcntl.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> +#include <isc/memcluster.h> + +#include "port_after.h" + +#include "named.h" + +/* Defs. */ + +#define CONTROL_FOUND 0x0001 /* for mark and sweep. */ +#define MAX_STR_LEN 500 + +struct control { + LINK(struct control) link; + enum { t_dead, t_inet, t_unix } type; + struct ctl_sctx *sctx; + u_int flags; + union { + struct { + struct sockaddr_in in; + ip_match_list allow; + } v_inet; + struct { + struct sockaddr_un un; + mode_t mode; + uid_t owner; + gid_t group; + } v_unix; + } var; +}; + +/* Forward. */ + +static struct ctl_sctx *mksrvr(control, const struct sockaddr *, size_t); +static control new_control(void); +static void free_control(controls *, control); +static void free_controls(controls *); +static int match_control(control, control); +static control find_control(controls, control); +static void propagate_changes(const control, control); +static void install(control); +static void install_inet(control); +static void install_unix(control); +static void logger(enum ctl_severity, const char *fmt, ...); +static void verb_connect(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_getpid(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void getpid_closure(struct ctl_sctx *, struct ctl_sess *, + void *); +static void verb_status(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void status_closure(struct ctl_sctx *, struct ctl_sess *, + void *); +static void verb_stop(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_exec(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_reload(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_reconfig(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_dumpdb(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_stats(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_trace(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void trace_closure(struct ctl_sctx *, struct ctl_sess *, + void *); +static void verb_notrace(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_querylog(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_help(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_quit(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); + +/* Private data. */ + +static controls server_controls; + +static struct ctl_verb verbs[] = { + { "", verb_connect, ""}, + { "getpid", verb_getpid, "getpid"}, + { "status", verb_status, "status"}, + { "stop", verb_stop, "stop"}, + { "exec", verb_exec, "exec"}, + { "reload", verb_reload, "reload [zone] ..."}, + { "reconfig", verb_reconfig, "reconfig (just sees new/gone zones)"}, + { "dumpdb", verb_dumpdb, "dumpdb"}, + { "stats", verb_stats, "stats"}, + { "trace", verb_trace, "trace [level]"}, + { "notrace", verb_notrace, "notrace"}, + { "querylog", verb_querylog, "querylog"}, + { "qrylog", verb_querylog, "qrylog"}, + { "help", verb_help, "help"}, + { "quit", verb_quit, "quit"}, + { NULL, NULL, NULL} +}; + +/* Public functions. */ + +void +ns_ctl_initialize(void) { + INIT_LIST(server_controls); +} + +void +ns_ctl_shutdown(void) { + if (!EMPTY(server_controls)) + free_controls(&server_controls); +} + +void +ns_ctl_defaults(controls *list) { + ns_ctl_add(list, ns_ctl_new_unix(_PATH_NDCSOCK, 0600, 0, 0)); +} + +void +ns_ctl_add(controls *list, control new) { + if (!find_control(*list, new)) + APPEND(*list, new, link); +} + +control +ns_ctl_new_inet(struct in_addr saddr, u_int sport, ip_match_list allow) { + control new = new_control(); + + INIT_LINK(new, link); + new->type = t_inet; + memset(&new->var.v_inet.in, 0, sizeof new->var.v_inet.in); + new->var.v_inet.in.sin_family = AF_INET; + new->var.v_inet.in.sin_addr = saddr; + new->var.v_inet.in.sin_port = sport; + new->var.v_inet.allow = allow; + return (new); +} + +control +ns_ctl_new_unix(char *path, mode_t mode, uid_t owner, gid_t group) { + control new = new_control(); + + INIT_LINK(new, link); + new->type = t_unix; + memset(&new->var.v_unix.un, 0, sizeof new->var.v_unix.un); + new->var.v_unix.un.sun_family = AF_UNIX; + strncpy(new->var.v_unix.un.sun_path, path, + sizeof new->var.v_unix.un.sun_path - 1); + new->var.v_unix.mode = mode; + new->var.v_unix.owner = owner; + new->var.v_unix.group = group; + return (new); +} + +void +ns_ctl_install(controls *new) { + control ctl, old, next; + + /* Find all the controls which aren't new or deleted. */ + for (ctl = HEAD(server_controls); ctl != NULL; ctl = NEXT(ctl, link)) + ctl->flags &= ~CONTROL_FOUND; + for (ctl = HEAD(*new); ctl != NULL; ctl = next) { + next = NEXT(ctl, link); + old = find_control(server_controls, ctl); + if (old != NULL) { + old->flags |= CONTROL_FOUND; + propagate_changes(ctl, old); + if (old->sctx == NULL) + free_control(&server_controls, old); + free_control(new, ctl); + } + } + + /* Destroy any old controls which weren't found. */ + for (ctl = HEAD(server_controls); ctl != NULL; ctl = next) { + next = NEXT(ctl, link); + if ((ctl->flags & CONTROL_FOUND) == 0) + free_control(&server_controls, ctl); + } + + /* Add any new controls which were found. */ + for (ctl = HEAD(*new); ctl != NULL; ctl = next) { + next = NEXT(ctl, link); + APPEND(server_controls, ctl, link); + install(ctl); + if (ctl->sctx == NULL) + free_control(&server_controls, ctl); + } +} + +/* Private functions. */ + +static struct ctl_sctx * +mksrvr(control ctl, const struct sockaddr *sa, size_t salen) { + return (ctl_server(ev, sa, salen, verbs, 500, 222, + 600, 5, 10, logger, ctl)); +} + +static control +new_control(void) { + control new = memget(sizeof *new); + + if (new == NULL) + panic("memget failed in new_control()", NULL); + new->type = t_dead; + new->sctx = NULL; + return (new); +} + +static void +free_control(controls *list, control this) { + int was_live = 0; + struct stat sb; + + if (this->sctx != NULL) { + ctl_endserver(this->sctx); + this->sctx = NULL; + was_live = 1; + } + switch (this->type) { + case t_inet: + if (this->var.v_inet.allow != NULL) { + free_ip_match_list(this->var.v_inet.allow); + this->var.v_inet.allow = NULL; + } + break; + case t_unix: + /* XXX Race condition. */ + if (was_live && + stat(this->var.v_unix.un.sun_path, &sb) == 0 && + (S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) { + /* XXX Race condition. */ + unlink(this->var.v_unix.un.sun_path); + } + break; + default: + panic("impossible type in free_control", NULL); + /* NOTREACHED */ + } + UNLINK(*list, this, link); + memput(this, sizeof *this); +} + +static void +free_controls(controls *list) { + control ctl, next; + + for (ctl = HEAD(*list); ctl != NULL; ctl = next) { + next = NEXT(ctl, link); + free_control(list, ctl); + } + INIT_LIST(*list); +} + +static int +match_control(control l, control r) { + int match = 1; + + if (l->type != r->type) + match = 0; + else + switch (l->type) { + case t_inet: + if (l->var.v_inet.in.sin_family != + r->var.v_inet.in.sin_family || + l->var.v_inet.in.sin_port != + r->var.v_inet.in.sin_port || + l->var.v_inet.in.sin_addr.s_addr != + r->var.v_inet.in.sin_addr.s_addr) + match = 0; + break; + case t_unix: + if (l->var.v_unix.un.sun_family != + r->var.v_unix.un.sun_family || + strcmp(l->var.v_unix.un.sun_path, + r->var.v_unix.un.sun_path) != 0) + match = 0; + break; + default: + panic("impossible type in match_control", NULL); + /* NOTREACHED */ + } + ns_debug(ns_log_config, 20, "match_control(): %d", match); + return (match); +} + +static control +find_control(controls list, control new) { + control ctl; + + for (ctl = HEAD(list); ctl != NULL; ctl = NEXT(ctl, link)) + if (match_control(ctl, new)) + return (ctl); + return (NULL); +} + +static void +propagate_changes(const control diff, control base) { + int need_install = 0; + + switch (base->type) { + case t_inet: + if (base->var.v_inet.allow != NULL) + free_ip_match_list(base->var.v_inet.allow); + base->var.v_inet.allow = diff->var.v_inet.allow; + diff->var.v_inet.allow = NULL; + need_install++; + break; + case t_unix: + if (base->var.v_unix.mode != diff->var.v_unix.mode) { + base->var.v_unix.mode = diff->var.v_unix.mode; + need_install++; + } + if (base->var.v_unix.owner != diff->var.v_unix.owner) { + base->var.v_unix.owner = diff->var.v_unix.owner; + need_install++; + } + if (base->var.v_unix.group != diff->var.v_unix.group) { + base->var.v_unix.group = diff->var.v_unix.group; + need_install++; + } + break; + default: + panic("impossible type in ns_ctl::propagate_changes", NULL); + /* NOTREACHED */ + } + if (need_install) + install(base); +} + +static void +install(control ctl) { + switch (ctl->type) { + case t_inet: + install_inet(ctl); + break; + case t_unix: + install_unix(ctl); + break; + default: + panic("impossible type in ns_ctl::install", NULL); + /* NOTREACHED */ + } +} + +static void +install_inet(control ctl) { + if (ctl->sctx == NULL) { + ctl->sctx = mksrvr(ctl, + (struct sockaddr *)&ctl->var.v_inet.in, + sizeof ctl->var.v_inet.in); + } +} + +/* + * Unattach an old unix domain socket if it exists. + */ +static void +unattach(control ctl) { + int s; + struct stat sb; + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + ns_warning(ns_log_config, + "unix control \"%s\" socket failed: %s", + ctl->var.v_unix.un.sun_path, + strerror(errno)); + return; + } + + if (stat(ctl->var.v_unix.un.sun_path, &sb) < 0) { + switch (errno) { + case ENOENT: /* We exited cleanly last time */ + break; + default: + ns_warning(ns_log_config, + "unix control \"%s\" stat failed: %s", + ctl->var.v_unix.un.sun_path, + strerror(errno)); + break; + } + goto cleanup; + } + + if (!(S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) { + ns_warning(ns_log_config, "unix control \"%s\" not socket", + ctl->var.v_unix.un.sun_path); + goto cleanup; + } + + if (connect(s, (struct sockaddr *)&ctl->var.v_unix.un, + sizeof ctl->var.v_unix.un) < 0) { + switch (errno) { + case ECONNREFUSED: + case ECONNRESET: + if (unlink(ctl->var.v_unix.un.sun_path) < 0) + ns_warning(ns_log_config, + "unix control \"%s\" unlink failed: %s", + ctl->var.v_unix.un.sun_path, + strerror(errno)); + break; + default: + ns_warning(ns_log_config, + "unix control \"%s\" connect failed: %s", + ctl->var.v_unix.un.sun_path, + strerror(errno)); + break; + } + } + cleanup: + close(s); +} + +static void +install_unix(control ctl) { + if (ctl->sctx == NULL) { + unattach(ctl); + ctl->sctx = mksrvr(ctl, + (struct sockaddr *)&ctl->var.v_unix.un, + sizeof ctl->var.v_unix.un); + } + if (ctl->sctx != NULL) { + /* XXX Race condition. */ + if (chmod(ctl->var.v_unix.un.sun_path, + ctl->var.v_unix.mode) < 0) { + ns_warning(ns_log_config, "chmod(\"%s\", 0%03o): %s", + ctl->var.v_unix.un.sun_path, + ctl->var.v_unix.mode, + strerror(errno)); + } + if (chown(ctl->var.v_unix.un.sun_path, + ctl->var.v_unix.owner, + ctl->var.v_unix.group) < 0) { + ns_warning(ns_log_config, "chown(\"%s\", %d, %d): %s", + ctl->var.v_unix.un.sun_path, + ctl->var.v_unix.owner, + ctl->var.v_unix.group, + strerror(errno)); + } + } +} + +static void +logger(enum ctl_severity ctlsev, const char *format, ...) { + va_list args; + int logsev; + + switch (ctlsev) { + case ctl_debug: logsev = log_debug(5); break; + case ctl_warning: logsev = log_warning; break; + case ctl_error: logsev = log_error; break; + default: panic("invalid ctlsev in logger", NULL); + } + if (!log_ctx_valid) + return; + va_start(args, format); + log_vwrite(log_ctx, ns_log_control, logsev, format, args); + va_end(args); +} + +static void +verb_connect(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + const struct sockaddr *sa = (struct sockaddr *)respctx; + control nsctl = (control)uctx; + + if (sa->sa_family == AF_INET) { + const struct sockaddr_in *in = (struct sockaddr_in *)sa; + const ip_match_list acl = nsctl->var.v_inet.allow; + + if (!ip_address_allowed(acl, in->sin_addr)) { + ctl_response(sess, 502, "Permission denied.", + CTL_EXIT, NULL, NULL, NULL, NULL, 0); + return; + } + } + ctl_response(sess, 220, server_options->version, 0, NULL, NULL, NULL, + NULL, 0); +} + +static void +verb_getpid(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + char *msg = memget(MAX_STR_LEN); + + if (msg == NULL) { + ctl_response(sess, 503, "(out of memory)", 0, + NULL, NULL, NULL, NULL, 0); + return; + } + sprintf(msg, "my pid is <%ld>", (long)getpid()); + ctl_response(sess, 250, msg, 0, NULL, getpid_closure, msg, NULL, 0); +} + +static void +getpid_closure(struct ctl_sctx *sctx, struct ctl_sess *sess, void *uap) { + char *msg = uap; + + memput(msg, MAX_STR_LEN); +} + +enum state { + e_version = 0, + e_nzones, + e_debug, + e_xfersrun, + e_xfersdfr, + e_qserials, + e_qrylog, + e_priming, + e_loading, + e_finito +}; + +struct pvt_status { + enum state state; + char text[MAX_STR_LEN]; +}; + +static void +verb_status(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct pvt_status *pvt = ctl_getcsctx(sess); + + if (pvt == NULL) { + pvt = memget(sizeof *pvt); + if (pvt == NULL) { + ctl_response(sess, 505, "(out of memory)", + 0, NULL, NULL, NULL, NULL, 0); + return; + } + pvt->state = e_version; + (void)ctl_setcsctx(sess, pvt); + } + switch (pvt->state++) { + case e_version: + strncpy(pvt->text, Version, sizeof pvt->text); + pvt->text[sizeof pvt->text - 1] = '\0'; + break; + case e_nzones: + sprintf(pvt->text, "number of zones allocated: %d", nzones); + break; + case e_debug: + sprintf(pvt->text, "debug level: %d", debug); + break; + case e_xfersrun: + sprintf(pvt->text, "xfers running: %d", xfers_running); + break; + case e_xfersdfr: + sprintf(pvt->text, "xfers deferred: %d", xfers_deferred); + break; + case e_qserials: + sprintf(pvt->text, "soa queries in progress: %d", + qserials_running); + break; + case e_qrylog: + sprintf(pvt->text, "query logging is %s", + qrylog ? "ON" : "OFF"); + break; + case e_priming: + sprintf(pvt->text, "server is %s priming", + priming ? "STILL" : "DONE"); + break; + case e_loading: + sprintf(pvt->text, "server %s loading its configuration", + loading ? "IS" : "IS NOT"); + break; + case e_finito: + return; + } + ctl_response(sess, 250, pvt->text, + (pvt->state == e_finito) ? 0 : CTL_MORE, + NULL, status_closure, NULL, NULL, 0); +} + +static void +status_closure(struct ctl_sctx *sctx, struct ctl_sess *sess, void *uap) { + struct pvt_status *pvt = ctl_getcsctx(sess); + + memput(pvt, sizeof *pvt); + ctl_setcsctx(sess, NULL); +} + +static void +verb_stop(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + ns_need(main_need_exit); + ctl_response(sess, 250, "Shutdown initiated.", 0, NULL, NULL, NULL, + NULL, 0); +} + +static void +verb_exec(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct stat sb; + + if (rest != NULL && *rest != '\0') { + if (stat(rest, &sb) < 0) { + ctl_response(sess, 503, strerror(errno), + 0, NULL, NULL, NULL, NULL, 0); + return; + } + saved_argv[0] = savestr(rest, 1); /* Never strfreed. */ + } + + if (stat(saved_argv[0], &sb) < 0) { + const char *save = strerror(errno); + + ns_warning(ns_log_default, "can't exec, %s: %s", + saved_argv[0], save); + ctl_response(sess, 502, save, 0, NULL, NULL, NULL, + NULL, 0); + } else { + ns_need(main_need_restart); + ctl_response(sess, 250, "Restart initiated.", 0, NULL, + NULL, NULL, NULL, 0); + } +} + +static void +verb_reload(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + static const char spaces[] = " \t"; + struct zoneinfo *zp; + char *tmp = NULL, *x; + const char *msg; + int class, code, success; + + /* If there are no args, this is a classic reload of the config. */ + if (rest == NULL || *rest == '\0') { + ns_need(main_need_reload); + code = 250; + msg = "Reload initiated."; + goto respond; + } + + /* Look for optional zclass argument. Default is "in". */ + tmp = savestr(rest, 1); + x = tmp + strcspn(tmp, spaces); + if (*x != '\0') { + *x++ = '\0'; + x += strspn(x, spaces); + } + if (x == NULL || *x == '\0') + x = "in"; + class = sym_ston(__p_class_syms, x, &success); + if (!success) { + code = 507; + msg = "unrecognized class"; + goto respond; + } + + /* Look for the zone, and do the right thing to it. */ + zp = find_zone(tmp, class); + if (zp == NULL) { + code = 506; + msg = "Zone not found."; + goto respond; + } + switch (zp->z_type) { + case z_master: + ns_stopxfrs(zp); + /*FALLTHROUGH*/ + case z_hint: + block_signals(); + code = 251; + msg = deferred_reload_unsafe(zp); + unblock_signals(); + break; + case z_slave: + case z_stub: + ns_stopxfrs(zp); + addxfer(zp); + code = 251; + msg = "Slave transfer queued."; + goto respond; + case z_forward: + case z_cache: + default: + msg = "Non reloadable zone."; + code = 507; + break; + } + + respond: + ctl_response(sess, code, msg, 0, NULL, NULL, NULL, NULL, 0); + if (tmp != NULL) + freestr(tmp); +} + +static void +verb_reconfig(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + ns_need(main_need_reconfig); + ctl_response(sess, 250, "Reconfig initiated.", + 0, NULL, NULL, NULL, NULL, 0); +} + +static void +verb_dumpdb(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + ns_need(main_need_dump); + ctl_response(sess, 250, "Database dump initiated.", 0, NULL, + NULL, NULL, NULL, 0); +} + +static void +verb_stats(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + ns_need(main_need_statsdump); + ctl_response(sess, 250, "Statistics dump initiated.", + 0, NULL, NULL, NULL, NULL, 0); +} + +static void +verb_trace(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + int i = atoi(rest); + char *msg = memget(MAX_STR_LEN); + + if (msg == NULL) { + ctl_response(sess, 503, "(out of memory)", 0, + NULL, NULL, NULL, NULL, 0); + return; + } + if (i > 0) + desired_debug = i; + else + desired_debug++; + ns_need(main_need_debug); + sprintf(msg, "Debug level: %d", desired_debug); + ctl_response(sess, 250, msg, 0, NULL, trace_closure, msg, NULL, 0); +} + +static void +trace_closure(struct ctl_sctx *sctx, struct ctl_sess *sess, void *uap) { + char *msg = uap; + + memput(msg, MAX_STR_LEN); +} + +static void +verb_notrace(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + desired_debug = 0; + ns_need(main_need_debug); + ctl_response(sess, 250, "Debugging turned off.", + 0, NULL, NULL, NULL, NULL, 0); +} + +static void +verb_querylog(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + static const char on[] = "Query logging is now on.", + off[] = "Query logging is now off."; + + toggle_qrylog(); + ctl_response(sess, 250, qrylog ? on : off, + 0, NULL, NULL, NULL, NULL, 0); +} + +static void +verb_help(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + ctl_sendhelp(sess, 214); +} + +static void +verb_quit(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + ctl_response(sess, 221, "End of control session.", CTL_EXIT, NULL, + NULL, NULL, NULL, 0); +} diff --git a/contrib/bind/bin/named/ns_defs.h b/contrib/bind/bin/named/ns_defs.h index 8d4bba7..801e5a9 100644 --- a/contrib/bind/bin/named/ns_defs.h +++ b/contrib/bind/bin/named/ns_defs.h @@ -1,6 +1,6 @@ /* * from ns.h 4.33 (Berkeley) 8/23/90 - * $Id: ns_defs.h,v 8.39 1998/04/14 00:35:09 halley Exp $ + * $Id: ns_defs.h,v 8.89 1999/10/07 08:24:08 vixie Exp $ */ /* @@ -36,7 +36,8 @@ * SUCH DAMAGE. */ -/* Portions Copyright (c) 1993 by Digital Equipment Corporation. +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -56,7 +57,7 @@ */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -73,6 +74,26 @@ */ /* + * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Check Point Software Technologies Incorporated not be used + * in advertising or publicity pertaining to distribution of the document + * or software without specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* * Global definitions for the name server. */ @@ -92,6 +113,7 @@ * dies out in a little more than a minute. * (sequence RETRYBASE, 2*RETRYBASE, 4*RETRYBASE... for MAXRETRY) */ +#define NEWZONES 64 /* must be a power of two. */ #define MINROOTS 2 /* min number of root hints */ #define NSMAX 16 /* max number of NS addrs to try ([0..255]) */ #define RETRYBASE 4 /* base time between retries */ @@ -107,6 +129,11 @@ /* every MIN_REFRESH seconds */ #define MIN_RETRY 1 /* never retry more frequently than once */ /* every MIN_RETRY seconds */ +#define MAX_REFRESH 2419200 /* perform a refresh query at least */ + /* every 4 weeks*/ +#define MAX_RETRY 1209600 /* perform a retry after no more than 2 weeks */ +#define MAX_EXPIRE 31536000 /* expire a zone if we have not talked to */ + /* the primary in 1 year */ #define NADDRECS 20 /* max addt'l rr's per resp */ #define XFER_TIMER 120 /* named-xfer's connect timeout */ @@ -117,35 +144,53 @@ #define DEFAULT_XFERS_PER_NS 2 /* default # of xfers per peer nameserver */ #define XFER_BUFSIZE (16*1024) /* arbitrary but bigger than most MTU's */ + /* maximum time to cache negative answers */ +#define DEFAULT_MAX_NCACHE_TTL (3*60*60) + #define ALPHA 0.7 /* How much to preserve of old response time */ #define BETA 1.2 /* How much to penalize response time on failure */ #define GAMMA 0.98 /* How much to decay unused response times */ /* What maintainance operations need to be performed sometime soon? */ -#define MAIN_NEED_RELOAD 0x0001 /* db_reload() needed. */ -#define MAIN_NEED_MAINT 0x0002 /* ns_maint() needed. */ -#define MAIN_NEED_ENDXFER 0x0004 /* endxfer() needed. */ -#define MAIN_NEED_ZONELOAD 0x0008 /* loadxfer() needed. */ -#define MAIN_NEED_DUMP 0x0010 /* doadump() needed. */ -#define MAIN_NEED_STATSDUMP 0x0020 /* ns_stats() needed. */ -#define MAIN_NEED_EXIT 0x0040 /* exit() needed. */ -#define MAIN_NEED_QRYLOG 0x0080 /* toggle_qrylog() needed. */ -#define MAIN_NEED_DEBUG 0x0100 /* use_desired_debug() needed. */ -#define MAIN_NEED_NOTIFY 0x0200 /* do_notify_after_load() needed */ +typedef enum need { + main_need_zreload = 0, /* ns_zreload() needed. */ + main_need_reload, /* ns_reload() needed. */ + main_need_reconfig, /* ns_reconfig() needed. */ + main_need_endxfer, /* endxfer() needed. */ + main_need_zoneload, /* loadxfer() needed. */ + main_need_dump, /* doadump() needed. */ + main_need_statsdump, /* ns_stats() needed. */ + main_need_exit, /* exit() needed. */ + main_need_qrylog, /* toggle_qrylog() needed. */ + main_need_debug, /* use_desired_debug() needed. */ + main_need_restart, /* exec() needed. */ + main_need_reap, /* need to reap dead children */ + main_need_num /* number of needs, used for array bound. */ +} main_need; /* What global options are set? */ #define OPTION_NORECURSE 0x0001 /* Don't recurse even if asked. */ #define OPTION_NOFETCHGLUE 0x0002 /* Don't fetch missing glue. */ #define OPTION_FORWARD_ONLY 0x0004 /* Don't use NS RR's, just forward. */ #define OPTION_FAKE_IQUERY 0x0008 /* Fake up bogus response to IQUERY. */ +#ifdef BIND_NOTIFY #define OPTION_NONOTIFY 0x0010 /* Turn off notify */ +#endif #define OPTION_NONAUTH_NXDOMAIN 0x0020 /* Generate non-auth NXDOMAINs? */ #define OPTION_MULTIPLE_CNAMES 0x0040 /* Allow a name to have multiple * CNAME RRs */ #define OPTION_HOSTSTATS 0x0080 /* Maintain per-host statistics? */ #define OPTION_DEALLOC_ON_EXIT 0x0100 /* Deallocate everything on exit? */ +#define OPTION_USE_IXFR 0x0110 /* Use by delault ixfr in zone transfer */ +#define OPTION_MAINTAIN_IXFR_BASE 0x0120 +#define OPTION_NODIALUP 0x0200 /* Turn off dialup support */ +#define OPTION_NORFC2308_TYPE1 0x0400 /* Prevent type1 respones (RFC 2308) + * to cached negative respones */ +#define OPTION_USE_ID_POOL 0x0800 /* Use the memory hogging query ID */ +#define OPTION_TREAT_CR_AS_SPACE 0x1000 /* Treat CR in zone files as space */ -#define DEFAULT_OPTION_FLAGS 0 +#define DEFAULT_OPTION_FLAGS (OPTION_NODIALUP|OPTION_NONAUTH_NXDOMAIN|\ + OPTION_USE_ID_POOL|OPTION_NORFC2308_TYPE1) #ifdef BIND_UPDATE #define SOAINCRINTVL 300 /* default value for the time after which @@ -165,6 +210,7 @@ #define CLEAN_TIMER 0x01 #define INTERFACE_TIMER 0x02 #define STATS_TIMER 0x04 +#define HEARTBEAT_TIMER 0x08 /* IP address accessor, network byte order. */ #define ina_ulong(ina) (ina.s_addr) @@ -186,6 +232,13 @@ (panic(panic_msg_no_options, NULL), 0) : \ ((server_options->flags & option) != 0)) +#define NS_ZOPTION_P(zp, option) \ + (((zp) != NULL && (((zp)->z_optset & option) != 0)) ? \ + (((zp)->z_options & option) != 0) : NS_OPTION_P(option)) + +#define NS_ZFWDTAB(zp) (((zp) == NULL) ? \ + server_options->fwdtab : (zp)->z_fwdtab) + #define NS_INCRSTAT(addr, which) \ do { \ if ((int)which >= (int)nssLast) \ @@ -204,7 +257,11 @@ enum severity { ignore, warn, fail, not_set }; +#ifdef BIND_NOTIFY enum znotify { znotify_use_default=0, znotify_yes, znotify_no }; +#endif + +enum zdialup { zdialup_use_default=0, zdialup_yes, zdialup_no }; enum axfr_format { axfr_use_default=0, axfr_one_answer, axfr_many_answers }; @@ -217,8 +274,12 @@ struct ip_match_indirect { struct ip_match_list *list; }; +struct ip_match_key { + struct dst_key *key; +}; + typedef enum { ip_match_pattern, ip_match_indirect, ip_match_localhost, - ip_match_localnets } ip_match_type; + ip_match_localnets, ip_match_key } ip_match_type; typedef struct ip_match_element { ip_match_type type; @@ -226,6 +287,7 @@ typedef struct ip_match_element { union { struct ip_match_direct direct; struct ip_match_indirect indirect; + struct ip_match_key key; } u; struct ip_match_element *next; } *ip_match_element; @@ -259,12 +321,15 @@ struct zoneinfo { char *z_source; /* source location of data */ time_t z_ftime; /* modification time of source file */ struct in_addr z_axfr_src; /* bind() the axfr socket to this */ - struct in_addr z_xaddr; /* override server for next xfer */ struct in_addr z_addr[NSMAX]; /* list of master servers for zone */ u_char z_addrcnt; /* number of entries in z_addr[] */ + struct in_addr z_xaddr[NSMAX]; /* list of master servers for xfer */ + u_char z_xaddrcnt; /* number of entries in z_xaddr[] */ u_char z_type; /* type of zone; see below */ - u_int16_t z_flags; /* state bits; see below */ + u_int32_t z_flags; /* state bits; see below */ pid_t z_xferpid; /* xfer child pid */ + u_int z_options; /* options set specific to this zone */ + u_int z_optset; /* which opts override global opts */ int z_class; /* class of zone */ int z_numxfrs; /* Ref count of concurrent xfrs. */ enum severity z_checknames; /* How to handle non-RFC-compliant names */ @@ -286,60 +351,87 @@ struct zoneinfo { ip_match_list z_transfer_acl; /* sites that may get a zone transfer from us */ long z_max_transfer_time_in; /* max num seconds for AXFR */ +#ifdef BIND_NOTIFY enum znotify z_notify; /* Notify mode */ - struct in_addr z_also_notify[NSMAX]; /* More nameservers to notify */ + struct in_addr *z_also_notify; /* More nameservers to notify */ int z_notify_count; +#endif + enum zdialup z_dialup; /* secondaries over a dialup link */ + char *z_ixfr_base; /* where to find the history of the zone */ + char *z_ixfr_tmp; /* tmp file for the ixfr */ + int z_maintain_ixfr_base; + int z_log_size_ixfr; + int z_max_log_size_ixfr; evTimerID z_timer; /* maintenance timer */ ztimer_info z_timerinfo; /* UAP associated with timer */ time_t z_nextmaint; /* time of next maintenance */ + u_int16_t z_port; /* perform AXFR to this port */ + struct fwdinfo *z_fwdtab; /* zone-specific forwarders */ + LINK(struct zoneinfo) z_freelink; /* if it's on the free list. */ + LINK(struct zoneinfo) z_reloadlink; /* if it's on the reload list. */ }; /* zone types (z_type) */ -enum zonetype { z_nil, z_master, z_slave, z_hint, z_stub, z_any }; +enum zonetype { z_nil, z_master, z_slave, z_hint, z_stub, z_forward, + z_cache, z_any }; #define Z_NIL z_nil /* XXX */ #define Z_MASTER z_master /* XXX */ #define Z_PRIMARY z_master /* XXX */ #define Z_SLAVE z_slave /* XXX */ #define Z_SECONDARY z_slave /* XXX */ #define Z_HINT z_hint /* XXX */ -#define Z_CACHE z_hint /* XXX */ +#define Z_CACHE z_cache /* XXX */ #define Z_STUB z_stub /* XXX */ +#define Z_FORWARD z_forward /* XXX */ #define Z_ANY z_any /* XXX*2 */ - /* zone state bits (16 bits) */ -#define Z_AUTH 0x0001 /* zone is authoritative */ -#define Z_NEED_XFER 0x0002 /* waiting to do xfer */ -#define Z_XFER_RUNNING 0x0004 /* asynch. xfer is running */ -#define Z_NEED_RELOAD 0x0008 /* waiting to do reload */ -#define Z_SYSLOGGED 0x0010 /* have logged timeout */ -#define Z_QSERIAL 0x0020 /* sysquery()'ing for serial number */ -#define Z_FOUND 0x0040 /* found in boot file when reloading */ -#define Z_INCLUDE 0x0080 /* set if include used in file */ -#define Z_DB_BAD 0x0100 /* errors when loading file */ -#define Z_TMP_FILE 0x0200 /* backup file for xfer is temporary */ + /* zone state bits (32 bits) */ +#define Z_AUTH 0x00000001 /* zone is authoritative */ +#define Z_NEED_XFER 0x00000002 /* waiting to do xfer */ +#define Z_XFER_RUNNING 0x00000004 /* asynch. xfer is running */ +#define Z_NEED_RELOAD 0x00000008 /* waiting to do reload */ +#define Z_SYSLOGGED 0x00000010 /* have logged timeout */ +#define Z_QSERIAL 0x00000020 /* sysquery()'ing for serial number */ +#define Z_FOUND 0x00000040 /* found in boot file when reloading */ +#define Z_INCLUDE 0x00000080 /* set if include used in file */ +#define Z_DB_BAD 0x00000100 /* errors when loading file */ +#define Z_TMP_FILE 0x00000200 /* backup file for xfer is temporary */ #ifdef BIND_UPDATE -#define Z_DYNAMIC 0x0400 /* allow dynamic updates */ -#define Z_NEED_DUMP 0x0800 /* zone has changed, needs a dump */ -#define Z_NEED_SOAUPDATE 0x1000 /* soa serial number needs increment */ +#define Z_DYNAMIC 0x00000400 /* allow dynamic updates */ +#define Z_NEED_DUMP 0x00000800 /* zone has changed, needs a dump */ +#define Z_NEED_SOAUPDATE 0x00001000 /* soa serial number needs increment */ #endif /* BIND_UPDATE */ -#define Z_XFER_ABORTED 0x2000 /* zone transfer has been aborted */ -#define Z_XFER_GONE 0x4000 /* zone transfer process is gone */ -#define Z_TIMER_SET 0x8000 /* z_timer contains a valid id */ +#define Z_XFER_ABORTED 0x00002000 /* zone transfer has been aborted */ +#define Z_XFER_GONE 0x00004000 /* zone transfer process is gone */ +#define Z_TIMER_SET 0x00008000 /* z_timer contains a valid id */ +#ifdef BIND_NOTIFY +#define Z_NOTIFY 0x00010000 /* has an outbound notify executing */ +#endif +#define Z_NEED_QSERIAL 0x00020000 /* we need to re-call qserial() */ +#define Z_PARENT_RELOAD 0x00040000 /* we need to reload this as parent */ +#define Z_FORWARD_SET 0x00080000 /* has forwarders been set */ /* named_xfer exit codes */ #define XFER_UPTODATE 0 /* zone is up-to-date */ #define XFER_SUCCESS 1 /* performed transfer successfully */ #define XFER_TIMEOUT 2 /* no server reachable/xfer timeout */ #define XFER_FAIL 3 /* other failure, has been logged */ +#define XFER_SUCCESSAXFR 4 /* named-xfr recived a xfr */ +#define XFER_SUCCESSIXFR 5 /* named-xfr recived a ixfr */ +#define XFER_SUCCESSAXFRIXFRFILE 6 /* named-xfr received AXFR for IXFR */ +#define XFER_ISAXFR -1 /* the last XFR is AXFR */ +#define XFER_ISIXFR -2 /* the last XFR is IXFR */ +#define XFER_ISAXFRIXFR -3 /* the last XFR is AXFR but we must create IXFR base */ -/* XXX - "struct qserv" is deprecated in favor of "struct nameser" */ struct qserv { struct sockaddr_in ns_addr; /* address of NS */ struct databuf *ns; /* databuf for NS record */ struct databuf *nsdata; /* databuf for server address */ struct timeval stime; /* time first query started */ - int nretry; /* # of times addr retried */ + unsigned int forwarder:1; /* this entry is for a forwarder */ + unsigned int nretry:31; /* # of times addr retried */ + u_int32_t serial; /* valid if Q_ZSERIAL */ }; /* @@ -357,7 +449,6 @@ struct qinfo { q_cmsglen, /* len of cname message */ q_cmsgsize; /* allocated size of cname message */ int16_t q_dfd; /* UDP file descriptor */ - struct fwdinfo *q_fwd; /* last forwarder used */ time_t q_time; /* time to retry */ time_t q_expire; /* time to expire */ struct qinfo *q_next; /* rexmit list (sorted by time) */ @@ -375,15 +466,18 @@ struct qinfo { int16_t q_nqueries; /* # of queries required */ struct qstream *q_stream; /* TCP stream, null if UDP */ struct zoneinfo *q_zquery; /* Zone query is about (Q_ZSERIAL) */ + struct zoneinfo *q_fzone; /* Forwarding zone, if any */ char *q_domain; /* domain of most enclosing zone cut */ char *q_name; /* domain of query */ u_int16_t q_class; /* class of query */ u_int16_t q_type; /* type of query */ #ifdef BIND_NOTIFY - int q_notifyzone; /* zone which needs a sysnotify() + int q_notifyzone; /* zone which needs another znotify() * when the reply to this comes in. */ #endif + struct tsig_record *q_tsig; /* forwarded query's TSIG record */ + struct tsig_record *q_nstsig; /* forwarded query's TSIG record */ }; /* q_flags bits (8 bits) */ @@ -392,9 +486,7 @@ struct qinfo { #define Q_ZSERIAL 0x04 /* getting zone serial for xfer test */ #define Q_USEVC 0x08 /* forward using tcp not udp */ -#define Q_NEXTADDR(qp,n) \ - (((qp)->q_fwd == (struct fwdinfo *)0) ? \ - &(qp)->q_addr[n].ns_addr : &(qp)->q_fwd->fwdaddr) +#define Q_NEXTADDR(qp,n) (&(qp)->q_addr[n].ns_addr) #define RETRY_TIMEOUT 45 @@ -464,17 +556,27 @@ struct qstream { u_int flags; /* see below */ struct qstream_xfr { enum { s_x_base, s_x_firstsoa, s_x_zone, - s_x_lastsoa, s_x_done } + s_x_lastsoa, s_x_done, s_x_adding, + s_x_deleting, s_x_addsoa, s_x_deletesoa } state; /* state of transfer. */ u_char *msg, /* current assembly message. */ *cp, /* where are we in msg? */ *eom, /* end of msg. */ *ptrs[128]; /* ptrs for dn_comp(). */ int class, /* class of an XFR. */ + type, /* type of XFR. */ id, /* id of an XFR. */ opcode; /* opcode of an XFR. */ u_int zone; /* zone being XFR'd. */ - struct namebuf *top; /* top np of an XFR. */ + union { + struct namebuf *axfr; /* top np of an AXFR. */ + struct ns_updrec *ixfr; /* top udp of an IXFR. */ + } top; + int ixfr_zone; + u_int32_t serial; /* serial number requested in IXFR */ + ns_tcp_tsig_state *tsig_state; /* used by ns_sign_tcp */ + int tsig_skip; /* skip calling ns_sign_tcp + * during the next flush */ struct qs_x_lev { /* decompose the recursion. */ enum {sxl_ns, sxl_all, sxl_sub} state; /* what's this level doing? */ @@ -500,6 +602,7 @@ struct qstream { #define STREAM_CONNECT_EV 0x08 #define STREAM_DONE_CLOSE 0x10 #define STREAM_AXFR 0x20 +#define STREAM_AXFRIXFR 0x22 #define ALLOW_NETS 0x0001 #define ALLOW_HOSTS 0x0002 @@ -549,7 +652,8 @@ struct nameser { u_int8_t xfers; /* #/xfers running right now */ }; -enum transport { primary_trans, secondary_trans, response_trans, num_trans }; +enum transport { primary_trans, secondary_trans, response_trans, update_trans, + num_trans }; /* types used by the parser or config routines */ @@ -573,8 +677,31 @@ typedef struct listen_info_list { #endif typedef RLIMIT_TYPE rlimit_type; +struct control; +typedef struct control *control; +typedef LIST(struct control) controls; + +enum ordering { unknown_order, fixed_order, cyclic_order, random_order }; + +#define DEFAULT_ORDERING cyclic_order + +typedef struct rrset_order_element { + int class; + int type; + char *name; + enum ordering order; + struct rrset_order_element *next; +} *rrset_order_element ; + +typedef struct rrset_order_list { + rrset_order_element first; + rrset_order_element last; +} *rrset_order_list; + + typedef struct options { u_int flags; + char *version; char *directory; char *dump_filename; char *pid_filename; @@ -584,12 +711,22 @@ typedef struct options { int transfers_in; int transfers_per_ns; int transfers_out; + int serial_queries; + int max_log_size_ixfr; enum axfr_format transfer_format; long max_transfer_time_in; struct sockaddr_in query_source; + struct in_addr axfr_src; +#ifdef BIND_NOTIFY + int notify_count; + struct in_addr *also_notify; +#endif ip_match_list query_acl; + ip_match_list recursion_acl; ip_match_list transfer_acl; + ip_match_list blackhole_acl; ip_match_list topology; + ip_match_list sortlist; enum severity check_names[num_trans]; u_long data_size; u_long stack_size; @@ -601,16 +738,15 @@ typedef struct options { int clean_interval; int interface_interval; int stats_interval; + rrset_order_list ordering; + int heartbeat_interval; + u_int max_ncache_ttl; + u_int lame_ttl; + int minroots; } *options; -typedef struct key_info { - char *name; - char *algorithm; - char *secret; /* XXX should be u_char? */ -} *key_info; - typedef struct key_list_element { - key_info info; + struct dst_key *key; struct key_list_element *next; } *key_list_element; @@ -647,6 +783,7 @@ typedef struct server_config { } server_config; #define SERVER_INFO_BOGUS 0x01 +#define SERVER_INFO_SUPPORT_IXFR 0x02 typedef struct server_info { struct in_addr address; @@ -686,7 +823,9 @@ typedef enum ns_logging_categories { ns_log_db, ns_log_eventlib, ns_log_packet, +#ifdef BIND_NOTIFY ns_log_notify, +#endif ns_log_cname, ns_log_security, ns_log_os, @@ -694,6 +833,7 @@ typedef enum ns_logging_categories { ns_log_maint, ns_log_load, ns_log_resp_checks, + ns_log_control, ns_log_max_category } ns_logging_categories; @@ -709,9 +849,9 @@ struct map { int val; }; -#define NOERROR_NODATA 6 /* only used internally by the server, used for - * -ve $ing non-existence of records. 6 is not - * a code used as yet anyway. anant@isi.edu +#define NOERROR_NODATA 15 /* only used internally by the server, used for + * -ve $ing non-existence of records. 15 is not + * a code used as yet anyway. */ #define NTTL 600 /* ttl for negative data: 10 minutes? */ @@ -722,24 +862,6 @@ struct map { enum req_action { Finish, Refuse, Return }; #endif -#ifdef BIND_NOTIFY -typedef enum { - notify_info_waitfor, notify_info_delay, notify_info_error, - notify_info_done -} notify_info_state; - -typedef struct notify_info { - char *name; - int class; - notify_info_state state; - evWaitID wait_id; - evTimerID timer_id; - LINK(struct notify_info) link; -} *notify_info; - -typedef LIST(struct notify_info) notify_info_list; -#endif /* BIND_NOTIFY */ - #ifdef INIT error "INIT already defined, check system include files" #endif diff --git a/contrib/bind/bin/named/ns_forw.c b/contrib/bind/bin/named/ns_forw.c index 9c72825..3a4e488 100644 --- a/contrib/bind/bin/named/ns_forw.c +++ b/contrib/bind/bin/named/ns_forw.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_forw.c 4.32 (Berkeley) 3/3/91"; -static char rcsid[] = "$Id: ns_forw.c,v 8.34 1998/02/24 01:02:40 halley Exp $"; +static const char sccsid[] = "@(#)ns_forw.c 4.32 (Berkeley) 3/3/91"; +static const char rcsid[] = "$Id: ns_forw.c,v 8.68 1999/10/13 16:39:07 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_forw.c,v 8.34 1998/02/24 01:02:40 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -78,6 +78,7 @@ static char rcsid[] = "$Id: ns_forw.c,v 8.34 1998/02/24 01:02:40 halley Exp $"; #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -95,6 +96,8 @@ static char rcsid[] = "$Id: ns_forw.c,v 8.34 1998/02/24 01:02:40 halley Exp $"; #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" @@ -122,14 +125,20 @@ int ns_forw(struct databuf *nsp[], u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp, int dfd, struct qinfo **qpp, const char *dname, int class, int type, - struct namebuf *np, int use_tcp) + struct namebuf *np, int use_tcp, struct tsig_record *in_tsig) { struct qinfo *qp; char tmpdomain[MAXDNAME]; struct sockaddr_in *nsa; HEADER *hp; u_int16_t id; - int n; + int sendto_errno = 0; + int n, has_tsig, oldqlen; + u_char *oldqbuf; + u_char *smsg; + int smsglen, smsgsize, siglen; + u_char sig[TSIG_SIG_SIZE]; + DST_KEY *key; ns_debug(ns_log_default, 3, "ns_forw()"); @@ -155,23 +164,32 @@ ns_forw(struct databuf *nsp[], u_char *msg, int msglen, getname(np, tmpdomain, sizeof tmpdomain); qp->q_domain = savestr(tmpdomain, 1); qp->q_from = from; /* nslookup wants to know this */ - n = nslookup(nsp, qp, dname, "ns_forw"); + if (NS_ZFWDTAB(qp->q_fzone)) + nsfwdadd(qp, NS_ZFWDTAB(qp->q_fzone)); + if (NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) + n = 0; + else + n = nslookup(nsp, qp, dname, "ns_forw"); if (n < 0) { - ns_debug(ns_log_default, 2, "forw: nslookup reports danger"); + if (n == -1) + ns_debug(ns_log_default, 2, + "forw: nslookup reports danger"); ns_freeqry(qp); return (FW_SERVFAIL); } - if (n == 0 && !server_options->fwdtab) { + if (n == 0 && !NS_ZFWDTAB(qp->q_fzone)) { ns_debug(ns_log_default, 2, "forw: no nameservers found"); ns_freeqry(qp); return (FW_NOSERVER); } qp->q_stream = qsp; qp->q_curaddr = 0; - qp->q_fwd = server_options->fwdtab; qp->q_dfd = dfd; qp->q_id = id; qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2; + if (in_tsig != NULL) + qp->q_tsig = new_tsig(in_tsig->key, in_tsig->sig, + in_tsig->siglen); if (use_tcp) qp->q_flags |= Q_USEVC; hp->id = qp->q_nsid = htons(nsid_next()); @@ -186,17 +204,16 @@ ns_forw(struct databuf *nsp[], u_char *msg, int msglen, } qp->q_msgsize = msglen; memcpy(qp->q_msg, msg, qp->q_msglen = msglen); - if (!qp->q_fwd) { - hp->rd = 0; - qp->q_addr[0].stime = tt; - } + hp = (HEADER *) qp->q_msg; + hp->rd = (qp->q_addr[0].forwarder ? 1 : 0); + qp->q_addr[0].stime = tt; #ifdef SLAVE_FORWARD - if (NS_OPTION_P(OPTION_FORWARD_ONLY)) + if (NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) schedretry(qp, (time_t)slave_retry); else #endif /* SLAVE_FORWARD */ - schedretry(qp, qp->q_fwd ?(2*RETRYBASE) :retrytime(qp)); + schedretry(qp, retrytime(qp)); nsa = Q_NEXTADDR(qp, 0); ns_debug(ns_log_default, 1, @@ -208,10 +225,44 @@ ns_forw(struct databuf *nsp[], u_char *msg, int msglen, ? qp->q_addr[0].nsdata->d_nstime : -1, (int)(qp->q_time - tt.tv_sec)); + #ifdef DEBUG if (debug >= 10) - fp_nquery(msg, msglen, log_get_stream(packet_channel)); + res_pquery(&res, msg, msglen, log_get_stream(packet_channel)); #endif + key = tsig_key_from_addr(nsa->sin_addr); + if (key != NULL) { + smsgsize = qp->q_msglen + TSIG_BUF_SIZE; + smsg = memget(smsgsize); + if (smsg == NULL) + ns_panic(ns_log_default, 1, "ns_forw: memget failed"); + smsglen = qp->q_msglen; + siglen = sizeof(sig); + memcpy(smsg, qp->q_msg, qp->q_msglen); + n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0, + sig, &siglen, 0); + if (n == 0) { + oldqbuf = qp->q_msg; + oldqlen = qp->q_msglen; + qp->q_msglen = smsglen; + qp->q_msg = smsg; + hp = (HEADER *) qp->q_msg; + has_tsig = 1; + qp->q_nstsig = new_tsig(key, sig, siglen); + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + INSIST(0); + } + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + } + if (qp->q_flags & Q_USEVC) { if (tcp_send(qp) != NOERROR) { if (!haveComplained(ina_ulong(nsa->sin_addr), @@ -220,20 +271,37 @@ ns_forw(struct databuf *nsp[], u_char *msg, int msglen, "ns_forw: tcp_send(%s) failed: %s", sin_ntoa(*nsa), strerror(errno)); } - } else if (sendto(ds, (char *)msg, msglen, 0, (struct sockaddr *)nsa, + } else if (sendto(ds, (char *)qp->q_msg, qp->q_msglen, 0, + (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { + sendto_errno = errno; if (!haveComplained(ina_ulong(nsa->sin_addr), (u_long)sendtoStr)) ns_info(ns_log_default, "ns_forw: sendto(%s): %s", sin_ntoa(*nsa), strerror(errno)); nameserIncr(nsa->sin_addr, nssSendtoErr); } + if (has_tsig == 1) { + memput(qp->q_msg, smsgsize); + qp->q_msg = oldqbuf; + qp->q_msglen = oldqlen; + hp = (HEADER *) qp->q_msg; + } + if (NS_OPTION_P(OPTION_HOSTSTATS)) nameserIncr(from.sin_addr, nssRcvdFwdQ); nameserIncr(nsa->sin_addr, nssSentFwdQ); if (qpp) *qpp = qp; hp->rd = 1; + switch (sendto_errno) { + case ENETDOWN: + case ENETUNREACH: + case EHOSTDOWN: + case EHOSTUNREACH: + unsched(qp); + schedretry(qp, (time_t) 0); + } return (0); } @@ -313,8 +381,6 @@ nslookupComplain(const char *sysloginfo, const char *queryname, ns_debug(ns_log_default, 2, "NS '%s' %s", dname, complaint); if (sysloginfo && queryname && !haveComplained((u_long)queryname, (u_long)complaint)) { - char buf[999]; - a = ns = (char *)NULL; print_a = (a_rr->d_type == T_A); a_type = p_type(a_rr->d_type); @@ -395,13 +461,13 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, struct hashbuf *tmphtp; char *dname; const char *fname; - int oldn, naddr, class, found_arr, potential_ns; + int oldn, naddr, class, found_arr, potential_ns, lame_ns; time_t curtime; ns_debug(ns_log_default, 3, "nslookup(nsp=%#x, qp=%#x, \"%s\")", nsp, qp, syslogdname); - potential_ns = 0; + lame_ns = potential_ns = 0; naddr = n = qp->q_naddr; curtime = (u_long) tt.tv_sec; while ((nsdp = *nsp++) != NULL) { @@ -421,8 +487,20 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, } } + /* skip lame servers */ + if ((nsdp->d_flags & DB_F_LAME) != 0) { + time_t when; + when = db_lame_find(qp->q_domain, nsdp); + if (when != 0 && when > tt.tv_sec) { + ns_debug(ns_log_default, 3, + "skipping lame NS"); + lame_ns++; + goto skipserver; + } + } + tmphtp = ((nsdp->d_flags & DB_F_HINT) ?fcachetab :hashtab); - np = nlookup(dname, &tmphtp, &fname, 1); + np = nlookup(dname, &tmphtp, &fname, 0); if (np == NULL) { ns_debug(ns_log_default, 3, "%s: not found %s %#x", dname, fname, np); @@ -430,45 +508,14 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, goto need_sysquery; } if (fname != dname) { - if (findMyZone(np, class) == DB_Z_CACHE) { - /* - * lifted from findMyZone() - * We really need to know if the NS - * is the bottom of one of our zones - * to see if we've got missing glue - */ - for (; np; np = np_parent(np)) - for (dp = np->n_data; dp; dp = dp->d_next) - if (match(dp, class, T_NS)) { - if (dp->d_rcode) - break; - if (dp->d_zone) { - static char *complaint = - "Glue A RR missing"; - nslookupComplain(sysloginfo, - syslogdname, - complaint, - dname, dp, - nsdp); - goto skipserver; - } else { - found_arr = 0; - goto need_sysquery; - } - } - /* shouldn't happen, but ... */ - found_arr = 0; - goto need_sysquery; - } else { - /* Authoritative A RR missing. */ - continue; - } + found_arr = 0; + goto need_sysquery; } found_arr = 0; oldn = n; /* look for name server addresses */ - delete_stale(np); + (void)delete_stale(np); for (dp = np->n_data; dp != NULL; dp = dp->d_next) { struct in_addr nsa; @@ -484,10 +531,7 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, if (dp->d_type != T_A || dp->d_class != class) continue; if (dp->d_rcode) { - static const char *complaint = - "A RR negative cache entry"; - nslookupComplain(sysloginfo, syslogdname, - complaint, dname, dp, nsdp); + /* Negative caching element. */ goto skipserver; } if (ina_hlong(ina_get(dp->d_data)) == INADDR_ANY) { @@ -553,6 +597,7 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, qs->ns_addr.sin_addr = nsa; qs->ns = nsdp; qs->nsdata = dp; + qs->forwarder = 0; qs->nretry = 0; /* * If this A RR has no RTT, initialize its RTT to a @@ -616,6 +661,10 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, if (ip_match_address(bogus_nameservers, nsa) > 0) goto skipserver; #endif + if (server_options->blackhole_acl != NULL && + ip_match_address(server_options->blackhole_acl, + nsa) == 1) + continue; n++; if (n >= NSMAX) @@ -629,7 +678,7 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, potential_ns++; if (!(qp->q_flags & Q_SYSTEM)) (void) sysquery(dname, class, T_A, NULL, 0, - QUERY); + ns_port, QUERY); } skipserver: (void)NULL; @@ -637,15 +686,17 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, out: ns_debug(ns_log_default, 3, "nslookup: %d ns addrs total", n); qp->q_naddr = n; - if (n == 0 && potential_ns == 0 && !server_options->fwdtab) { + if (n == 0 && potential_ns == 0 && !NS_ZFWDTAB(qp->q_fzone)) { static char *complaint = "No possible A RRs"; + if (lame_ns != 0) + complaint = "All possible A RR's lame"; if (sysloginfo && syslogdname && !haveComplained((u_long)syslogdname, (u_long)complaint)) { ns_info(ns_log_default, "%s: query(%s) %s", sysloginfo, syslogdname, complaint); } - return(-1); + return ((lame_ns == 0) ? -1 : -2); } /* Update the refcounts before the sort. */ for (i = naddr; i < (u_int)n; i++) { @@ -846,14 +897,20 @@ retrytimer(evContext ctx, void *uap, struct timespec due, */ void retry(struct qinfo *qp) { - int n; + int n, has_tsig, oldqlen; HEADER *hp; struct sockaddr_in *nsa; + int sendto_errno = 0; + u_char *oldqbuf; + u_char *smsg; + int smsglen, smsgsize, siglen; + u_char sig[TSIG_SIG_SIZE]; + DST_KEY *key; ns_debug(ns_log_default, 3, "retry(%#lx) id=%d", (u_long)qp, ntohs(qp->q_id)); - if (qp->q_msg == NULL) { /* XXX - why? */ + if (qp->q_msg == NULL) { qremove(qp); return; } @@ -864,29 +921,25 @@ retry(struct qinfo *qp) { (u_long)qp, (u_long)qp->q_expire, (int)(tt.tv_sec - qp->q_expire), (u_long)tt.tv_sec); - if (qp->q_stream || (qp->q_flags & Q_PRIMING)) - goto fail; - qremove(qp); - return; + goto fail; } - /* try next address */ + /* Try next address. */ n = qp->q_curaddr; - if (qp->q_fwd != NULL) { - qp->q_fwd = qp->q_fwd->next; - if (qp->q_fwd != NULL) - goto found; - /* Out of forwarders, try direct queries. */ - } if (qp->q_naddr > 0) { ++qp->q_addr[n].nretry; - if (!NS_OPTION_P(OPTION_FORWARD_ONLY)) { - do { - if (++n >= (int)qp->q_naddr) - n = 0; - if (qp->q_addr[n].nretry < MAXRETRY) - goto found; - } while (n != qp->q_curaddr); + do { + if (++n >= (int)qp->q_naddr) + n = 0; + if ((qp->q_flags & Q_ZSERIAL) != 0 && + qp->q_addr[n].serial != 0) + continue; + if (qp->q_addr[n].nretry < MAXRETRY) + goto found; + } while (n != qp->q_curaddr); + if ((qp->q_flags & Q_ZSERIAL) != 0) { + qremove(qp); + return; } } fail: @@ -894,7 +947,7 @@ retry(struct qinfo *qp) { * Give up. Can't reach destination. */ hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg); - if (qp->q_flags & Q_PRIMING) { + if ((qp->q_flags & Q_PRIMING) != 0) { /* Can't give up priming */ if (qp->q_expire < tt.tv_sec) { /* @@ -903,7 +956,6 @@ retry(struct qinfo *qp) { */ hp->rcode = NOERROR; hp->qr = hp->aa = 0; - qp->q_fwd = server_options->fwdtab; for (n = 0; n < (int)qp->q_naddr; n++) qp->q_addr[n].nretry = 0; n = 0; @@ -920,36 +972,40 @@ retry(struct qinfo *qp) { return; } ns_debug(ns_log_default, 5, "give up"); - n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen); - hp->id = qp->q_id; - hp->qr = 1; - hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0); - hp->rd = 1; - hp->rcode = SERVFAIL; + if ((qp->q_flags & Q_SYSTEM) == 0) { + n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen); + hp->id = qp->q_id; + hp->qr = 1; + hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0); + hp->rd = 1; + hp->rcode = SERVFAIL; #ifdef DEBUG - if (debug >= 10) - fp_nquery(qp->q_msg, n, log_get_stream(packet_channel)); + if (debug >= 10) + res_pquery(&res, qp->q_msg, n, + log_get_stream(packet_channel)); #endif - if (send_msg((u_char *)hp, n, qp)) { - ns_debug(ns_log_default, 1, - "gave up retry(%#lx) nsid=%d id=%d", - (u_long)qp, ntohs(qp->q_nsid), ntohs(qp->q_id)); + if (send_msg((u_char *)hp, n, qp)) { + ns_debug(ns_log_default, 1, + "gave up retry(%#lx) nsid=%d id=%d", + (u_long)qp, + ntohs(qp->q_nsid), ntohs(qp->q_id)); + } + if (NS_OPTION_P(OPTION_HOSTSTATS)) + nameserIncr(qp->q_from.sin_addr, nssSentFail); } - if (NS_OPTION_P(OPTION_HOSTSTATS)) - nameserIncr(qp->q_from.sin_addr, nssSentFail); qremove(qp); return; found: - if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0) + if (qp->q_addr[n].nretry == 0) qp->q_addr[n].stime = tt; qp->q_curaddr = n; hp = (HEADER *)qp->q_msg; - hp->rd = (qp->q_fwd ? 1 : 0); + hp->rd = (qp->q_addr[n].forwarder ? 1 : 0); nsa = Q_NEXTADDR(qp, n); ns_debug(ns_log_default, 1, "%s(addr=%d n=%d) -> [%s].%d ds=%d nsid=%d id=%d %dms", - (qp->q_fwd ? "reforw" : "resend"), + (qp->q_addr[n].forwarder ? "reforw" : "resend"), n, qp->q_addr[n].nretry, inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port), ds, @@ -959,9 +1015,38 @@ retry(struct qinfo *qp) { : (-1)); #ifdef DEBUG if (debug >= 10) - fp_nquery(qp->q_msg, qp->q_msglen, + res_pquery(&res, qp->q_msg, qp->q_msglen, log_get_stream(packet_channel)); #endif + key = tsig_key_from_addr(nsa->sin_addr); + if (key != NULL) { + smsgsize = qp->q_msglen + TSIG_BUF_SIZE; + smsg = memget(smsgsize); + smsglen = qp->q_msglen; + siglen = sizeof(sig); + memcpy(smsg, qp->q_msg, qp->q_msglen); + n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0, + sig, &siglen, 0); + if (n == 0) { + oldqbuf = qp->q_msg; + oldqlen = qp->q_msglen; + qp->q_msglen = smsglen; + qp->q_msg = smsg; + has_tsig = 1; + qp->q_nstsig = new_tsig(key, sig, siglen); + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + INSIST(0); + } + } else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + } + if (qp->q_flags & Q_USEVC) { if (tcp_send(qp) != NOERROR) ns_debug(ns_log_default, 3, @@ -971,18 +1056,32 @@ retry(struct qinfo *qp) { (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { + sendto_errno = errno; ns_debug(ns_log_default, 3, "error resending msg: %s", strerror(errno)); } + if (has_tsig == 1) { + memput(qp->q_msg, smsgsize); + qp->q_msg = oldqbuf; + qp->q_msglen = oldqlen; + } hp->rd = 1; /* leave set to 1 for dup detection */ nameserIncr(nsa->sin_addr, nssSentDupQ); unsched(qp); + switch (sendto_errno) { + case ENETDOWN: + case ENETUNREACH: + case EHOSTDOWN: + case EHOSTUNREACH: + schedretry(qp, (time_t) 0); + return; + } #ifdef SLAVE_FORWARD - if (NS_OPTION_P(OPTION_FORWARD_ONLY)) + if (NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) schedretry(qp, (time_t)slave_retry); else #endif /* SLAVE_FORWARD */ - schedretry(qp, qp->q_fwd ? (2*RETRYBASE) : retrytime(qp)); + schedretry(qp, retrytime(qp)); } /* @@ -1020,16 +1119,10 @@ qflush() { void qremove(struct qinfo *qp) { - struct sockaddr_in empty_from; - - empty_from.sin_family = AF_INET; - empty_from.sin_addr.s_addr = htonl(INADDR_ANY); - empty_from.sin_port = htons(0); - ns_debug(ns_log_default, 3, "qremove(%#lx)", (u_long)qp); - if (qp->q_flags & Q_ZSERIAL) - qserial_answer(qp, 0, empty_from); + if ((qp->q_flags & Q_ZSERIAL) != 0) + qserial_answer(qp); unsched(qp); ns_freeqry(qp); } @@ -1049,10 +1142,12 @@ qfindid(u_int16_t id) { struct qinfo * qnew(const char *name, int class, int type) { struct qinfo *qp; + const char *s; + int escape = 0; qp = (struct qinfo *)memget(sizeof *qp); if (qp == NULL) - panic("qnew: memget failed", NULL); + ns_panic(ns_log_default, 1, "qnew: memget failed"); memset(qp, 0, sizeof *qp); ns_debug(ns_log_default, 5, "qnew(%#lx)", (u_long)qp); #ifdef BIND_NOTIFY @@ -1064,6 +1159,21 @@ qnew(const char *name, int class, int type) { qp->q_class = (u_int16_t)class; qp->q_type = (u_int16_t)type; qp->q_flags = 0; + s = name; + for (;;) { /* find forwarding zone, if any */ + if ((qp->q_fzone = find_zone(s, class)) != NULL && + (qp->q_fzone->z_flags & Z_FORWARD_SET) != 0) + break; + qp->q_fzone = NULL; + if (*s == '\0') + break; + while (*s != '\0' && (escape || *s != '.')) { + escape = escape ? 0 : (*s == '\\'); + s++; + } + if (*s != '\0') + s++; + } return (qp); } @@ -1101,7 +1211,6 @@ ns_freeqns(struct qinfo *qp, char *where) { void ns_freeqry(struct qinfo *qp) { struct qinfo *np; - struct databuf *dp; ns_debug(ns_log_default, 3, "ns_freeqry(%#lx)", (u_long)qp); if (qp->q_next) @@ -1115,6 +1224,10 @@ ns_freeqry(struct qinfo *qp) { freestr(qp->q_domain); if (qp->q_name != NULL) freestr(qp->q_name); + if (qp->q_tsig != NULL) + memput(qp->q_tsig, sizeof(struct tsig_record)); + if (qp->q_nstsig != NULL) + memput(qp->q_nstsig, sizeof(struct tsig_record)); ns_freeqns(qp, "ns_freeqry"); if (nsqhead == qp) nsqhead = qp->q_link; @@ -1130,3 +1243,27 @@ ns_freeqry(struct qinfo *qp) { } memput(qp, sizeof *qp); } + +void +nsfwdadd(struct qinfo *qp, struct fwdinfo *fwd) { + int i, n; + struct qserv *qs; + + n = qp->q_naddr; + while (fwd != NULL && n < MAXNS) { + qs = qp->q_addr; + for (i = 0; i < (u_int)n; i++, qs++) + if (ina_equal(qs->ns_addr.sin_addr, + fwd->fwdaddr.sin_addr)) + goto nextfwd; + qs->ns_addr = fwd->fwdaddr; + qs->ns = NULL; + qs->nsdata = NULL; + qs->forwarder = 1; + qs->nretry = 0; + n++; + nextfwd: + fwd = fwd->next; + } + qp->q_naddr = n; +} diff --git a/contrib/bind/bin/named/ns_func.h b/contrib/bind/bin/named/ns_func.h index bf58528..88c181ca 100644 --- a/contrib/bind/bin/named/ns_func.h +++ b/contrib/bind/bin/named/ns_func.h @@ -1,4 +1,5 @@ -/* Copyright (c) 1985, 1990 +/* + * Copyright (c) 1985, 1990 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,7 +31,8 @@ * SUCH DAMAGE. */ -/* Portions Copyright (c) 1993 by Digital Equipment Corporation. +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -49,7 +51,8 @@ * SOFTWARE. */ -/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium. +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -65,14 +68,35 @@ * SOFTWARE. */ +/* + * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Check Point Software Technologies Incorporated not be used + * in advertising or publicity pertaining to distribution of the document + * or software without specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + /* ns_func.h - declarations for ns_*.c's externally visible functions * - * $Id: ns_func.h,v 8.43 1998/03/20 00:53:44 halley Exp $ + * $Id: ns_func.h,v 8.90 1999/10/11 18:22:20 vixie Exp $ */ /* ++from ns_glue.c++ */ extern struct in_addr ina_get(const u_char *data); extern const char *sin_ntoa(struct sockaddr_in); +extern int ns_wouldlog(int category, int level); extern void ns_debug(int, int, const char *, ...), ns_info(int, const char *, ...), ns_notice(int, const char *, ...), @@ -92,6 +116,9 @@ extern char *__newstr(size_t, int), *__savestr(const char *, int), *checked_ctime(const time_t *t), *ctimel(long); +extern void __freestr_record(char *, char *, int); +extern char *__newstr_record(size_t, int, char *, int); +extern char *__savestr_record(const char *, int, char *, int); extern u_char *ina_put(struct in_addr ina, u_char *data), *savebuf(const u_char *, size_t, int); extern void dprintf(int level, const char *format, ...); @@ -103,21 +130,34 @@ extern void debug_freestr(char *, const char *, int); #define savestr(s, n) debug_savestr((s), (n), __FILE__, __LINE__) #define freestr(s) debug_freestr((s), __FILE__, __LINE__) #else +#ifdef RECORD_STRINGS +#define newstr(l, n) __newstr_record((l), (n), __FILE__, __LINE__) +#define savestr(s, n) __savestr_record((s), (n), __FILE__, __LINE__) +#define freestr(s) __freestr_record((s), __FILE__, __LINE__) +#else #define newstr(l, n) __newstr((l), (n)) #define savestr(s, n) __savestr((s), (n)) #define freestr(s) __freestr((s)) +#endif #endif /* DEBUG_STRINGS */ +int movefile(const char *, const char *); /* --from ns_glue.c-- */ +/* ++from ns_notify.c++ */ +#ifdef BIND_NOTIFY +void ns_notify(const char *, ns_class, ns_type); +void ns_unnotify(void); +#endif +/* --from ns_notify.c-- */ + /* ++from ns_resp.c++ */ extern void ns_resp(u_char *, int, struct sockaddr_in, struct qstream *), prime_cache(void), - delete_all(struct namebuf *, int, int), - delete_stale(struct namebuf *); + delete_all(struct namebuf *, int, int); +extern int delete_stale(struct namebuf *); extern struct qinfo *sysquery(const char *, int, int, - struct in_addr *, int, int); -extern void sysnotify(const char *, int, int); + struct in_addr *, int, u_int16_t, int); extern int doupdate(u_char *, u_char *, struct databuf **, int, int, int, u_int, struct sockaddr_in), send_msg(u_char *, int, struct qinfo *), @@ -125,7 +165,6 @@ extern int doupdate(u_char *, u_char *, struct databuf **, struct databuf **, int *, int), finddata(struct namebuf *, int, int, HEADER *, char **, int *, int *), - wanted(const struct databuf *, int, int), add_data(struct namebuf *, struct databuf **, u_char *, int, int *), @@ -142,7 +181,7 @@ extern void ns_req(u_char *, int, int, extern int stale(struct databuf *), make_rr(const char *, struct databuf *, u_char *, int, int, - u_char **, u_char **), + u_char **, u_char **, int), doaddinfo(HEADER *, u_char *, int), doaddauth(HEADER *, u_char *, int, struct namebuf *, @@ -154,13 +193,33 @@ extern int findZonePri(const struct zoneinfo *, /* --from ns_req.c-- */ /* ++from ns_xfr.c++ */ -extern void ns_xfr(struct qstream *qsp, struct namebuf *znp, +void ns_xfr(struct qstream *qsp, struct namebuf *znp, int zone, int class, int type, - int id, int opcode), + int id, int opcode, u_int32_t serial_ixfr, + struct tsig_record *in_tsig), ns_stopxfrs(struct zoneinfo *), - ns_freexfr(struct qstream *); + ns_freexfr(struct qstream *), + sx_newmsg(struct qstream *qsp), + sx_sendlev(struct qstream *qsp), + sx_sendsoa(struct qstream *qsp); /* --from ns_xfr.c-- */ +/* ++from ns_ctl.c++ */ +void ns_ctl_initialize(void); +void ns_ctl_shutdown(void); +void ns_ctl_defaults(controls *); +void ns_ctl_add(controls *, control); +control ns_ctl_new_inet(struct in_addr, u_int, ip_match_list); +#ifndef WINNT +control ns_ctl_new_unix(char *, mode_t, uid_t, gid_t); +#endif +void ns_ctl_install(controls *); +/* --from ns_ctl.c-- */ + +/* ++from ns_ixfr.c++ */ +void sx_send_ixfr(struct qstream *qsp); +/* --from ns_ixfr.c-- */ + /* ++from ns_forw.c++ */ extern time_t retrytime(struct qinfo *); extern int ns_forw(struct databuf *nsp[], @@ -174,7 +233,8 @@ extern int ns_forw(struct databuf *nsp[], int class, int type, struct namebuf *np, - int use_tcp), + int use_tcp, + struct tsig_record *in_tsig), haveComplained(u_long, u_long), nslookup(struct databuf *nsp[], struct qinfo *qp, @@ -191,7 +251,8 @@ extern void schedretry(struct qinfo *, time_t), qremove(struct qinfo *), ns_freeqns(struct qinfo *, char *), ns_freeqry(struct qinfo *), - freeComplaints(void); + freeComplaints(void), + nsfwdadd(struct qinfo *, struct fwdinfo *); extern struct qinfo *qfindid(u_int16_t), *qnew(const char *, int, int); /* --from ns_forw.c-- */ @@ -209,59 +270,82 @@ extern void sq_remove(struct qstream *), nsid_init(void), ns_setoption(int option), writestream(struct qstream *, const u_char *, int), - ns_need(int need), - opensocket_f(void); + ns_need_unsafe(enum need), + ns_need(enum need), + opensocket_f(void), + nsid_hash(u_char *, size_t); extern u_int16_t nsid_next(void); extern int sq_openw(struct qstream *, int), sq_writeh(struct qstream *, sq_closure), sq_write(struct qstream *, const u_char *, int), - ns_need_p(int option), tcp_send(struct qinfo *), aIsUs(struct in_addr); /* --from ns_main.c-- */ /* ++from ns_maint.c++ */ -extern void ns_maint(void), - zone_maint(struct zoneinfo *), +extern void zone_maint(struct zoneinfo *), sched_zone_maint(struct zoneinfo *), ns_cleancache(evContext ctx, void *uap, struct timespec due, struct timespec inter), + clean_cache_from(char *dname, struct hashbuf *htp), + remove_zone(struct zoneinfo *, const char *), purge_zone(const char *, struct hashbuf *, int), loadxfer(void), qserial_retrytime(struct zoneinfo *, time_t), qserial_query(struct zoneinfo *), - qserial_answer(struct qinfo *, u_int32_t, - struct sockaddr_in), + qserial_answer(struct qinfo *), #ifdef DEBUG printzoneinfo(int, int, int), #endif endxfer(void), - ns_reload(void); + addxfer(struct zoneinfo *), + ns_zreload(void), + ns_reload(void), + ns_reconfig(void); +#if 0 +extern int reload_all_unsafe(void); +#endif +extern int zonefile_changed_p(struct zoneinfo *); +int reload_master(struct zoneinfo *); +extern const char * deferred_reload_unsafe(struct zoneinfo *); +extern struct namebuf * purge_node(struct hashbuf *htp, struct namebuf *np); extern int clean_cache(struct hashbuf *, int); -extern void reapchild(evContext, void *, int); -extern const char * zoneTypeString(const struct zoneinfo *); +extern void reapchild(void); +extern const char * zoneTypeString(unsigned int); +extern void ns_heartbeat(evContext ctx, void *uap, + struct timespec, struct timespec); +extern void make_new_zones(void); +extern void free_zone(struct zoneinfo *); +extern struct zoneinfo *find_auth_zone(const char *, ns_class); /* --from ns_maint.c-- */ +/* ++from ns_sort.c++ */ +extern void sort_response(u_char *, u_char *, int, + struct sockaddr_in *); +/* --from ns_sort.c-- */ + /* ++from ns_init.c++ */ -extern void ns_refreshtime(struct zoneinfo *, time_t), - ns_retrytime(struct zoneinfo *, time_t), - ns_init(const char *); +extern void ns_refreshtime(struct zoneinfo *, time_t); +extern void ns_retrytime(struct zoneinfo *, time_t); +extern void ns_init(const char *); +extern void purgeandload(struct zoneinfo *zp); extern enum context ns_ptrcontext(const char *owner); extern enum context ns_ownercontext(int type, enum transport); -extern int ns_nameok(const char *name, int class, - struct zoneinfo *zp, +extern int ns_nameok(const struct qinfo *qry, const char *name, + int class, struct zoneinfo *zp, enum transport, enum context, const char *owner, struct in_addr source); extern int ns_wildcard(const char *name); -extern void zoneinit(struct zoneinfo *), - do_reload(const char *, int, int), - ns_shutdown(void); +extern void zoneinit(struct zoneinfo *); +extern void do_reload(const char *, int, int, int); +extern void ns_shutdown(void); /* --from ns_init.c-- */ /* ++from ns_ncache.c++ */ -extern void cache_n_resp(u_char *, int, struct sockaddr_in); +extern void cache_n_resp(u_char *, int, struct sockaddr_in, + const char *, int, int); /* --from ns_ncache.c-- */ /* ++from ns_udp.c++ */ @@ -280,42 +364,56 @@ extern struct nameser *nameserFind(struct in_addr addr, int flags); /* --from ns_stats.c-- */ /* ++from ns_update.c++ */ -u_char *findsoaserial(u_char *data); +void free_rrecp(ns_updque *, int rcode, struct sockaddr_in); +int findzone(const char *, int, int, int *, int); +u_char * findsoaserial(u_char *data); u_int32_t get_serial_unchecked(struct zoneinfo *zp); u_int32_t get_serial(struct zoneinfo *zp); void set_serial(struct zoneinfo *zp, u_int32_t serial); int schedule_soa_update(struct zoneinfo *, int); int schedule_dump(struct zoneinfo *); int incr_serial(struct zoneinfo *zp); -int merge_logs(struct zoneinfo *zp); -int zonedump(struct zoneinfo *zp); +int merge_logs(struct zoneinfo *zp, char *logname); +int zonedump(struct zoneinfo *zp, int isixfr); void dynamic_about_to_exit(void); enum req_action req_update(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, struct qstream *qsp, - int dfd, struct sockaddr_in from); + int dfd, struct sockaddr_in from, + struct tsig_record *in_tsig); void rdata_dump(struct databuf *dp, FILE *fp); /* --from ns_update.c-- */ /* ++from ns_config.c++ */ void free_zone_timerinfo(struct zoneinfo *); void free_zone_contents(struct zoneinfo *, int); -struct zoneinfo *find_zone(const char *, int, int); +struct zoneinfo * find_zone(const char *, int); zone_config begin_zone(char *, int); void end_zone(zone_config, int); int set_zone_type(zone_config, int); int set_zone_filename(zone_config, char *); int set_zone_checknames(zone_config, enum severity); +#ifdef BIND_NOTIFY int set_zone_notify(zone_config, int value); +#endif +int set_zone_maintain_ixfr_base(zone_config, int value); int set_zone_update_acl(zone_config, ip_match_list); int set_zone_query_acl(zone_config, ip_match_list); int set_zone_transfer_acl(zone_config, ip_match_list); int set_zone_transfer_source(zone_config, struct in_addr); +int set_zone_pubkey(zone_config, const int, const int, + const int, const char *); int set_zone_transfer_time_in(zone_config, long); int add_zone_master(zone_config, struct in_addr); +#ifdef BIND_NOTIFY int add_zone_notify(zone_config, struct in_addr); +#endif +void set_zone_forward(zone_config); +void add_zone_forwarder(zone_config, struct in_addr); +void set_zone_boolean_option(zone_config, int, int); options new_options(void); void free_options(options); -void set_boolean_option(options, int, int); +void free_rrset_order_list(rrset_order_list); +void set_global_boolean_option(options, int, int); listen_info_list new_listen_info_list(void); void free_listen_info_list(listen_info_list); void add_listen_on(options, u_int16_t, ip_match_list); @@ -323,11 +421,15 @@ FILE * write_open(char *filename); void update_pid_file(void); void set_options(options, int); void use_default_options(void); +enum ordering lookup_ordering(const char *); +rrset_order_list new_rrset_order_list(void); +rrset_order_element new_rrset_order_element(int, int, char *, enum ordering); ip_match_list new_ip_match_list(void); void free_ip_match_list(ip_match_list); ip_match_element new_ip_match_pattern(struct in_addr, u_int); ip_match_element new_ip_match_mask(struct in_addr, struct in_addr); ip_match_element new_ip_match_indirect(ip_match_list); +ip_match_element new_ip_match_key(struct dst_key *dst_key); ip_match_element new_ip_match_localhost(void); ip_match_element new_ip_match_localnets(void); void ip_match_negate(ip_match_element); @@ -335,12 +437,22 @@ void add_to_ip_match_list(ip_match_list, ip_match_element); void dprint_ip_match_list(int, ip_match_list, int, char *, char *); int ip_match_address(ip_match_list, struct in_addr); +int ip_match_addr_or_key(ip_match_list, struct in_addr, + struct dst_key *key); int ip_address_allowed(ip_match_list, struct in_addr); +int ip_addr_or_key_allowed(ip_match_list iml, + struct in_addr, + struct dst_key *key); int ip_match_network(ip_match_list, struct in_addr, struct in_addr); +int ip_match_key_name(ip_match_list iml, char *name); int distance_of_address(ip_match_list, struct in_addr); int ip_match_is_none(ip_match_list); -void add_forwarder(options, struct in_addr); +#ifdef BIND_NOTIFY +void free_also_notify(options); +int add_global_also_notify(options, struct in_addr); +#endif +void add_global_forwarder(options, struct in_addr); void free_forwarders(struct fwdinfo *); server_info find_server(struct in_addr); server_config begin_server(struct in_addr); @@ -349,13 +461,14 @@ void set_server_option(server_config, int, int); void set_server_transfers(server_config, int); void set_server_transfer_format(server_config, enum axfr_format); -void add_server_key_info(server_config, key_info); -key_info new_key_info(char *, char *, char *); -void free_key_info(key_info); -void dprint_key_info(key_info); +void add_server_key_info(server_config, struct dst_key *); +struct dst_key *new_key_info(char *, char *, char *); +void free_key_info(struct dst_key *); +struct dst_key *find_key(char *name, char *algorithm); +void dprint_key_info(struct dst_key *); key_info_list new_key_info_list(void); void free_key_info_list(key_info_list); -void add_to_key_info_list(key_info_list, key_info); +void add_to_key_info_list(key_info_list, struct dst_key *); void dprint_key_info_list(key_info_list); log_config begin_logging(void); void add_log_channel(log_config, int, log_channel); @@ -372,9 +485,14 @@ void load_configuration(const char *); /* ++from parser.y++ */ ip_match_list lookup_acl(char *); void define_acl(char *, ip_match_list); -key_info lookup_key(char *); -void define_key(char *, key_info); +struct dst_key *lookup_key(char *); +void define_key(char *, struct dst_key *); void parse_configuration(const char *); void parser_initialize(void); void parser_shutdown(void); /* --from parser.y-- */ +/* ++from ns_signal.c++ */ +void init_signals(void); +void block_signals(void); +void unblock_signals(void); +/* --from ns_signal.c-- */ diff --git a/contrib/bind/bin/named/ns_glob.h b/contrib/bind/bin/named/ns_glob.h index 8f39c84..b977f7b 100644 --- a/contrib/bind/bin/named/ns_glob.h +++ b/contrib/bind/bin/named/ns_glob.h @@ -1,9 +1,10 @@ /* * from ns.h 4.33 (Berkeley) 8/23/90 - * $Id: ns_glob.h,v 8.35 1998/05/05 19:44:20 halley Exp $ + * $Id: ns_glob.h,v 8.51 1999/10/15 21:53:32 vixie Exp $ */ -/* Copyright (c) 1986 +/* + * Copyright (c) 1986 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,7 +36,8 @@ * SUCH DAMAGE. */ -/* Portions Copyright (c) 1993 by Digital Equipment Corporation. +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -54,7 +56,8 @@ * SOFTWARE. */ -/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium. +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -74,6 +77,9 @@ * Global variables for the name server. */ + /* original argv[] from main() */ +DECL char **saved_argv; + #ifdef DEBUG DECL int debug INIT(0); DECL int desired_debug INIT(0); @@ -82,6 +88,9 @@ DECL int desired_debug INIT(0); /* global event context */ DECL evContext ev; + /* global resolver context. */ +DECL struct __res_state res; + /* list of open streams */ DECL struct qstream *streamq; @@ -117,17 +126,23 @@ DECL time_t resettime; DECL struct qinfo *retryqp; /* default configuration file */ -DECL char *conffile INIT(NULL); +DECL char *conffile; /* default debug output file */ -DECL const char *debugfile INIT(_PATH_DEBUG); +DECL char *debugfile; /* zone information */ DECL struct zoneinfo *zones; - /* number of zones in use */ + /* number of zones allocated */ DECL int nzones; + /* free list of unused zones[] elements. */ +DECL LIST(struct zoneinfo) freezones; + + /* list of zones that have a reload pending. */ +DECL LIST(struct zoneinfo) reloadingzones; + /* set if we need a priming */ DECL int needs_prime_cache; @@ -192,8 +207,9 @@ DECL struct in_addr inaddr_any; /* Inits to 0.0.0.0 */ DECL options server_options INIT(NULL); DECL server_info nameserver_info INIT(NULL); +DECL key_info_list secretkey_info INIT(NULL); - /* These will disappear some day in favour of "struct nameser". */ +DECL int main_needs_exit INIT(0); DECL ip_match_list bogus_nameservers INIT(NULL); DECL log_context log_ctx; @@ -210,7 +226,6 @@ DECL ip_match_list local_addresses INIT(NULL); DECL ip_match_list local_networks INIT(NULL); /* are we running in no-fork mode? */ - DECL int foreground INIT(0); DECL const struct ns_sym logging_constants[] @@ -281,7 +296,9 @@ DECL const struct ns_sym category_constants[] { ns_log_db, "db" }, { ns_log_eventlib, "eventlib" }, { ns_log_packet, "packet" }, +#ifdef BIND_NOTIFY { ns_log_notify, "notify" }, +#endif { ns_log_cname, "cname" }, { ns_log_security, "security" }, { ns_log_os, "os" }, @@ -289,6 +306,7 @@ DECL const struct ns_sym category_constants[] { ns_log_maint, "maintenance" }, { ns_log_load, "load" }, { ns_log_resp_checks, "response-checks" }, + { ns_log_control, "control" }, { 0, NULL } } #endif @@ -308,6 +326,7 @@ DECL u_long globalStats[nssLast]; DECL evTimerID clean_timer; DECL evTimerID interface_timer; DECL evTimerID stats_timer; +DECL evTimerID heartbeat_timer; DECL int active_timers INIT(0); DECL uid_t user_id; @@ -317,3 +336,7 @@ DECL char * group_name INIT(NULL); DECL char * chroot_dir INIT(NULL); DECL int loading INIT(0); + +DECL int xfers_running INIT(0); +DECL int xfers_deferred INIT(0); +DECL int qserials_running INIT(0); diff --git a/contrib/bind/bin/named/ns_glue.c b/contrib/bind/bin/named/ns_glue.c index 460b64d..4b7972c 100644 --- a/contrib/bind/bin/named/ns_glue.c +++ b/contrib/bind/bin/named/ns_glue.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_glue.c,v 8.7 1998/02/13 19:51:45 halley Exp $"; +static const char rcsid[] = "$Id: ns_glue.c,v 8.14 1999/10/19 02:06:26 gson Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,6 +24,7 @@ static char rcsid[] = "$Id: ns_glue.c,v 8.7 1998/02/13 19:51:45 halley Exp $"; #include <sys/param.h> #include <sys/socket.h> #include <sys/uio.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -88,6 +89,13 @@ sin_ntoa(struct sockaddr_in sin) { * Logging Support */ +int +ns_wouldlog(int category, int level) { + if (log_ctx_valid) + return (log_check(log_ctx, category, level)); + return (0); +} + void ns_debug(int category, int level, const char *format, ...) { va_list args; @@ -279,7 +287,7 @@ my_fclose(FILE *fp) { s = fclose(fp); if (s < 0) - ns_info(ns_log_default, "fclose(%d) failed: %m", fd, + ns_info(ns_log_default, "fclose(%d) failed: %s", fd, strerror(errno)); else ns_debug(ns_log_default, 3, "fclose(%d) succeeded", fd); @@ -303,6 +311,21 @@ savebuf(const u_char *buf, size_t len, int needpanic) { return (bp); } +char * +__newstr(size_t len, int needpanic) { + return (__newstr_record(len, needpanic, __FILE__, __LINE__)); +} + +char * +__savestr(const char *str, int needpanic) { + return (__savestr_record(str, needpanic, __FILE__, __LINE__)); +} + +void +__freestr(char *str) { + __freestr_record(str, __FILE__, __LINE__); +} + #ifdef DEBUG_STRINGS char * debug_newstr(size_t len, int needpanic, const char *file, int line) { @@ -310,7 +333,7 @@ debug_newstr(size_t len, int needpanic, const char *file, int line) { size = len + 3; /* 2 length bytes + NUL. */ printf("%s:%d: newstr %d\n", file, line, size); - return (__newstr(len, needpanic)); + return (__newstr_record(len, needpanic, file, line)); } char * @@ -320,7 +343,7 @@ debug_savestr(const char *str, int needpanic, const char *file, int line) { len = strlen(str); len += 3; /* 2 length bytes + NUL. */ printf("%s:%d: savestr %d %s\n", file, line, len, str); - return (__savestr(str, needpanic)); + return (__savestr_record(str, needpanic, file, line)); } void @@ -333,7 +356,7 @@ debug_freestr(char *str, const char *file, int line) { NS_GET16(len, bp); len += 3; /* 2 length bytes + NUL. */ printf("%s:%d: freestr %d %s\n", file, line, len, str); - __freestr(str); + __freestr_record(str, file, line); return; } #endif /* DEBUG_STRINGS */ @@ -342,12 +365,12 @@ debug_freestr(char *str, const char *file, int line) { * Return a counted string buffer big enough for a string of length 'len'. */ char * -__newstr(size_t len, int needpanic) { +__newstr_record(size_t len, int needpanic, char *file, int line) { u_char *buf, *bp; REQUIRE(len <= 65536); - buf = (u_char *)memget(2/*Len*/ + len + 1/*Nul*/); + buf = (u_char *)__memget_record(2/*Len*/ + len + 1/*Nul*/, file, line); if (buf == NULL) { if (needpanic) panic("savestr: memget failed (%s)", strerror(errno)); @@ -363,7 +386,7 @@ __newstr(size_t len, int needpanic) { * Save a NUL terminated string and return a pointer to it. */ char * -__savestr(const char *str, int needpanic) { +__savestr_record(const char *str, int needpanic, char *file, int line) { char *buf; size_t len; @@ -375,20 +398,20 @@ __savestr(const char *str, int needpanic) { else return (NULL); } - buf = __newstr(len, needpanic); + buf = __newstr_record(len, needpanic, file, line); memcpy(buf, str, len + 1); return (buf); } void -__freestr(char *str) { +__freestr_record(char *str, char *file, int line) { u_char *buf, *bp; size_t len; buf = (u_char *)str - 2/*Len*/; bp = buf; NS_GET16(len, bp); - memput(buf, 2/*Len*/ + len + 1/*Nul*/); + __memput_record(buf, 2/*Len*/ + len + 1/*Nul*/, file, line); } char * @@ -414,3 +437,14 @@ ctimel(long l) { return (checked_ctime(&t)); } + +/* + * rename() is lame (can't overwrite an existing file) on some systems. + * use movefile() instead, and let lame OS ports do what they need to. + */ +#ifndef HAVE_MOVEFILE +int +movefile(const char *oldname, const char *newname) { + return (rename(oldname, newname)); +} +#endif diff --git a/contrib/bind/bin/named/ns_init.c b/contrib/bind/bin/named/ns_init.c index 920bfeb..cc95ce6 100644 --- a/contrib/bind/bin/named/ns_init.c +++ b/contrib/bind/bin/named/ns_init.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_init.c 4.38 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: ns_init.c,v 8.40 1998/04/07 18:11:58 halley Exp $"; +static const char sccsid[] = "@(#)ns_init.c 4.38 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: ns_init.c,v 8.63 1999/10/15 19:49:04 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_init.c,v 8.40 1998/04/07 18:11:58 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -79,6 +79,7 @@ static char rcsid[] = "$Id: ns_init.c,v 8.40 1998/04/07 18:11:58 halley Exp $"; #include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -97,6 +98,8 @@ static char rcsid[] = "$Id: ns_init.c,v 8.40 1998/04/07 18:11:58 halley Exp $"; #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" @@ -138,25 +141,37 @@ ns_init(const char *conffile) { gettime(&tt); if (loads == 0) { - zones = (struct zoneinfo *)memget(64 * sizeof *zones); - if (zones == NULL) - ns_panic(ns_log_config, 0, - "Not enough memory to allocate initial zones array"); - memset(zones, 0, 64 * sizeof *zones); - nzones = 1; /* zone zero is cache data */ - /* allocate cache hash table, formerly the root hash table. */ + /* Init zone data. */ + zones = NULL; + INIT_LIST(freezones); + INIT_LIST(reloadingzones); + nzones = 0; + make_new_zones(); + + /* Init cache. */ + zones[0].z_type = z_cache; + zones[0].z_origin = savestr("", 1); + + /* Allocate cache hash table, formerly the root hash table. */ hashtab = savehash((struct hashbuf *)NULL); - /* allocate root-hints/file-cache hash table */ + /* Allocate root-hints/file-cache hash table. */ fcachetab = savehash((struct hashbuf *)NULL); - /* init zone data */ - zones[0].z_type = Z_CACHE; - zones[0].z_origin = savestr("", 1); + + /* Init other misc stuff. */ + dst_init(); init_configuration(); } else { /* Mark previous zones as not yet found in boot file. */ + block_signals(); for (zp = &zones[1]; zp < &zones[nzones]; zp++) - zp->z_flags &= ~Z_FOUND; + if (zp->z_type != z_nil) { + zp->z_flags &= ~Z_FOUND; + if (LINKED(zp, z_reloadlink)) + UNLINK(reloadingzones, zp, + z_reloadlink); + } + unblock_signals(); } #ifdef DEBUG @@ -169,26 +184,20 @@ ns_init(const char *conffile) { load_configuration(conffile); /* Erase all old zones that were not found. */ - for (zp = &zones[1]; zp < &zones[nzones]; zp++) { - if (zp->z_type && (zp->z_flags & Z_FOUND) == 0) { -#ifdef BIND_UPDATE - /* - * A dynamic zone might have changed, so we - * need to dump it before removing it. - */ - if ((zp->z_flags & Z_DYNAMIC) && - ((zp->z_flags & Z_NEED_SOAUPDATE) || - (zp->z_flags & Z_NEED_DUMP))) - (void)zonedump(zp); -#endif - ns_stopxfrs(zp); - do_reload(zp->z_origin, zp->z_type, zp->z_class); - ns_notice(ns_log_config, - "%s zone \"%s\" (%s) removed", - zoneTypeString(zp), zp->z_origin, - p_class(zp->z_class)); - free_zone_contents(zp, 1); - memset(zp, 0, sizeof(*zp)); + for (zp = &zones[0]; zp < &zones[nzones]; zp++) { + if (zp->z_type == z_cache) + continue; + if (zp->z_type != z_nil && (zp->z_flags & Z_FOUND) == 0) + remove_zone(zp, "removed"); + } + /* Reload parent zones of zones removed */ + for (zp = &zones[0]; zp < &zones[nzones]; zp++) { + if (zp->z_type == z_cache) + continue; + if (zp->z_type != z_nil && + (zp->z_flags & Z_PARENT_RELOAD) != 0) { + zp->z_flags &= ~Z_PARENT_RELOAD; + purgeandload(zp); } } @@ -215,20 +224,22 @@ zoneinit(struct zoneinfo *zp) { * we will refresh the zone from a primary * immediately. */ - if (!zp->z_source) + if (zp->z_source == NULL) return; result = stat(zp->z_source, &sb); if (result != -1) { ns_stopxfrs(zp); purge_zone(zp->z_origin, hashtab, zp->z_class); } - if (result == -1 || db_load(zp->z_source, zp->z_origin, zp, NULL)) { + if (result == -1 || + db_load(zp->z_source, zp->z_origin, zp, NULL, ISNOTIXFR)) + { /* * Set zone to be refreshed immediately. */ zp->z_refresh = INIT_REFRESH; zp->z_retry = INIT_REFRESH; - if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))) { + if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0) { zp->z_time = tt.tv_sec; sched_zone_maint(zp); } @@ -240,12 +251,17 @@ zoneinit(struct zoneinfo *zp) { } } +/* + * Purge the zone and reload all parent zones. This needs to be done when + * we unload a zone, since the child zone will have stomped the parent's + * delegation to that child when it was first loaded. + */ void -do_reload(const char *domain, int type, int class) { +do_reload(const char *domain, int type, int class, int mark) { struct zoneinfo *zp; - ns_debug(ns_log_config, 1, "do_reload: %s %d %d", - *domain ? domain : ".", type, class); + ns_debug(ns_log_config, 1, "do_reload: %s %d %d %d", + *domain ? domain : ".", type, class, mark); /* * Check if the zone has changed type. If so, we might not need to @@ -259,15 +275,11 @@ do_reload(const char *domain, int type, int class) { * * NOTE: we take care not to match ourselves. */ - if ((type != z_master && - find_zone(domain, z_master, class) != NULL) || - (type != z_slave && - (zp = find_zone(domain, z_slave, class)) != NULL && - zp->z_serial != 0) || - (type != z_stub && - (zp = find_zone(domain, z_stub, class)) != NULL && - zp->z_serial != 0) - ) + zp = find_zone(domain, class); + if (zp != NULL && + (type != z_master && zp->z_type == z_master) || + (type != z_slave && zp->z_type == z_slave && zp->z_serial != 0) || + (type != z_stub && zp->z_type == z_stub && zp->z_serial != 0)) return; /* @@ -301,49 +313,51 @@ do_reload(const char *domain, int type, int class) { else domain = ""; /* root zone */ - if ((zp = find_zone(domain, Z_STUB, class)) || - (zp = find_zone(domain, Z_CACHE, class)) || - (zp = find_zone(domain, Z_PRIMARY, class)) || - (zp = find_zone(domain, Z_SECONDARY, class))) { - + zp = find_zone(domain, class); + if (zp != NULL) { ns_debug(ns_log_config, 1, "do_reload: matched %s", *domain ? domain : "."); - - if (zp->z_type == Z_CACHE) - purge_zone(zp->z_origin, fcachetab, - zp->z_class); + if (mark) + zp->z_flags |= Z_PARENT_RELOAD; else - purge_zone(zp->z_origin, hashtab, zp->z_class); - - zp->z_flags &= ~Z_AUTH; - - switch (zp->z_type) { - case Z_SECONDARY: - case Z_STUB: - zoneinit(zp); - break; - case Z_PRIMARY: - if (db_load(zp->z_source, zp->z_origin, zp, 0) - == 0) - zp->z_flags |= Z_AUTH; - break; - case Z_CACHE: - (void)db_load(zp->z_source, zp->z_origin, zp, - 0); - break; - } + purgeandload(zp); break; } } } +void +purgeandload(struct zoneinfo *zp) { + if (zp->z_type == Z_HINT) + purge_zone(zp->z_origin, fcachetab, zp->z_class); + else + purge_zone(zp->z_origin, hashtab, zp->z_class); + + zp->z_flags &= ~Z_AUTH; + + switch (zp->z_type) { + case Z_SECONDARY: + case Z_STUB: + zoneinit(zp); + break; + case Z_PRIMARY: + if (db_load(zp->z_source, zp->z_origin, zp, 0, ISNOTIXFR) == 0) + zp->z_flags |= Z_AUTH; + break; + case Z_HINT: + case Z_CACHE: + (void)db_load(zp->z_source, zp->z_origin, zp, 0, ISNOTIXFR); + break; + } +} + #ifdef DEBUG /* prints out the content of zones */ static void content_zone(int end, int level) { int i; - for (i = 1; i <= end; i++) { + for (i = 0; i <= end; i++) { printzoneinfo(i, ns_log_config, level); } } @@ -353,7 +367,8 @@ enum context ns_ptrcontext(owner) const char *owner; { - if (samedomain(owner, "in-addr.arpa") || samedomain(owner, "ip6.int")) + if (ns_samedomain(owner, "in-addr.arpa") || + ns_samedomain(owner, "ip6.int")) return (hostname_ctx); return (domain_ctx); } @@ -370,6 +385,7 @@ ns_ownercontext(type, transport) case T_WKS: case T_MX: switch (transport) { + case update_trans: case primary_trans: case secondary_trans: context = owner_ctx; @@ -394,8 +410,8 @@ ns_ownercontext(type, transport) } int -ns_nameok(const char *name, int class, struct zoneinfo *zp, - enum transport transport, +ns_nameok(const struct qinfo *qry, const char *name, int class, + struct zoneinfo *zp, enum transport transport, enum context context, const char *owner, struct in_addr source) @@ -428,19 +444,45 @@ ns_nameok(const char *name, int class, struct zoneinfo *zp, "unexpected context %d in ns_nameok", (int)context); } if (!ok) { - char *s, *o; + char *q, *s, *o; if (source.s_addr == INADDR_ANY) s = savestr(transport_strings[transport], 0); else { s = newstr(strlen(transport_strings[transport]) + - sizeof " from [000.000.000.000]", 0); + sizeof " from [000.000.000.000] for [000.000.000.000]", 0); if (s) - sprintf(s, "%s from [%s]", + if ( (transport == response_trans) && + (qry != NULL) ) { + + if ( qry->q_flags & Q_PRIMING ) { + sprintf(s, "%s from [%s] for priming", + transport_strings[transport], + inet_ntoa(source)); + } else if ( qry->q_flags & Q_ZSERIAL ) { + sprintf(s, "%s from [%s] for soacheck", transport_strings[transport], inet_ntoa(source)); + } else if ( qry->q_flags & Q_SYSTEM ) { + sprintf(s, "%s from [%s] for sysquery", + transport_strings[transport], + inet_ntoa(source)); + } else { + q=strdup(inet_ntoa(qry->q_from.sin_addr)); + sprintf(s, "%s from [%s] for [%s]", + transport_strings[transport], + inet_ntoa(source), + q != NULL ? q : "memget failed"); + free(q); + } + + } else { + sprintf(s, "%s from [%s]", + transport_strings[transport], + inet_ntoa(source)); + } } - if (strcasecmp(owner, name) == 0) + if (ns_samename(owner, name) == 1) o = savestr("", 0); else { const char *t = (*owner == '\0') ? "." : owner; @@ -454,8 +496,11 @@ ns_nameok(const char *name, int class, struct zoneinfo *zp, * the message formatting and arguments. */ log_write(log_ctx, ns_log_default, - (transport == response_trans) ? - log_info : log_notice, + (transport != response_trans) || + (o == NULL) || (s == NULL) || + ( (qry != NULL) && + (qry->q_flags & (Q_PRIMING|Q_ZSERIAL)) ) ? + log_warning : log_info, "%s name \"%s\"%s %s (%s) is invalid - %s", context_strings[context], name, o != NULL ? o : "[memget failed]", @@ -484,29 +529,36 @@ void ns_shutdown() { struct zoneinfo *zp; +#ifdef BIND_NOTIFY + ns_unnotify(); +#endif /* Erase zones. */ for (zp = &zones[0]; zp < &zones[nzones]; zp++) { if (zp->z_type) { - if (zp->z_type != z_hint) { + if (zp->z_type != z_hint && zp->z_type != z_cache) { ns_stopxfrs(zp); purge_zone(zp->z_origin, hashtab, zp->z_class); - } + } else if (zp->z_type == z_hint) + purge_zone(zp->z_origin, fcachetab, + zp->z_class); free_zone_contents(zp, 1); } } - memput(zones, ((nzones / 64) + 1) * 64 * sizeof *zones); /* Erase the cache. */ clean_cache(hashtab, 1); hashtab->h_cnt = 0; /* ??? */ rm_hash(hashtab); + hashtab = NULL; clean_cache(fcachetab, 1); fcachetab->h_cnt = 0; /* ??? */ rm_hash(fcachetab); + fcachetab = NULL; + + if (zones != NULL) + memput(zones, nzones * sizeof *zones); + zones = NULL; -#ifdef BIND_NOTIFY - db_cancel_pending_notifies(); -#endif freeComplaints(); shutdown_configuration(); } diff --git a/contrib/bind/bin/named/ns_ixfr.c b/contrib/bind/bin/named/ns_ixfr.c new file mode 100644 index 0000000..76dbe6e --- /dev/null +++ b/contrib/bind/bin/named/ns_ixfr.c @@ -0,0 +1,563 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ns_ixfr.c,v 8.17 1999/11/05 04:48:28 vixie Exp $"; +#endif /* not lint */ + +/* + * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Check Point Software Technologies Incorporated not be used + * in advertising or publicity pertaining to distribution of the document + * or software without specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "port_before.h" + +#include <sys/param.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <fcntl.h> +#include <resolv.h> +#include <res_update.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <time.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> +#include <isc/memcluster.h> + +#include "port_after.h" + +#include "named.h" + +static void sx_new_ixfrmsg(struct qstream * qsp); +void sx_send_ixfr(struct qstream * qsp); + +static int sx_flush(struct qstream * qsp), + sx_addrr(struct qstream * qsp, + const char *dname, + struct databuf * dp); +extern void sx_sendsoa(struct qstream * qsp); + +/* + * u_char * sx_new_ixfrmsg(msg) init the header of a message, reset the + * compression pointers, and reset the write pointer to the first byte + * following the header. + */ +static void +sx_new_ixfrmsg(struct qstream *qsp) { + HEADER * hp = (HEADER *) qsp->xfr.msg; + ns_updrec * up; + + memset(hp, 0, HFIXEDSZ); + hp->id = htons(qsp->xfr.id); + hp->opcode = qsp->xfr.opcode; + hp->qr = 1; + hp->aa = 1; + hp->rcode = NOERROR; + + qsp->xfr.ptrs[0] = qsp->xfr.msg; + qsp->xfr.ptrs[1] = NULL; + + qsp->xfr.cp = qsp->xfr.msg + HFIXEDSZ; + if (qsp->xfr.ixfr_zone == 0) { + int count, n; + int buflen; + struct namebuf *np; + struct hashbuf *htp; + struct zoneinfo *zp; + struct databuf *dp; + const char * fname; + u_char ** edp = qsp->xfr.ptrs + + sizeof qsp->xfr.ptrs / sizeof(u_char *); + + qsp->xfr.ixfr_zone = qsp->xfr.zone; + zp = &zones[qsp->xfr.zone]; + up = qsp->xfr.top.ixfr; + n = dn_comp(zp->z_origin, qsp->xfr.cp, + XFER_BUFSIZE - (qsp->xfr.cp - qsp->xfr.msg), NULL, NULL); + qsp->xfr.cp += n; + PUTSHORT((u_int16_t) T_IXFR, qsp->xfr.cp); + PUTSHORT((u_int16_t) zp->z_class, qsp->xfr.cp); + hp->qdcount = htons(ntohs(hp->qdcount) + 1); + count = qsp->xfr.cp - qsp->xfr.msg; + htp = hashtab; + np = nlookup(zp->z_origin, &htp, &fname, 0); + buflen = XFER_BUFSIZE; + foreach_rr(dp, np, T_SOA, qsp->xfr.class, qsp->xfr.zone) { + n = make_rr(zp->z_origin, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp, 0, qsp->xfr.ptrs, edp, 0); + qsp->xfr.cp += n; + hp->ancount = htons(ntohs(hp->ancount) + 1); + } + } +} + +/* + * int sx_flush(qsp) flush the intermediate buffer out to the stream IO + * system. return: passed through from sq_write(). + */ +static int +sx_flush(struct qstream *qsp) { + int ret; + +#ifdef DEBUG + if (debug >= 10) + fp_nquery(qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg, + log_get_stream(packet_channel)); +#endif + ret = sq_write(qsp, qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg); + if (ret >= 0) + qsp->xfr.cp = NULL; + return (ret); +} + +/* + * int sx_addrr(qsp, name, dp) add name/dp's RR to the current assembly + * message. if it won't fit, write current message out, renew the message, + * and then RR should fit. return: -1 = the sq_write() failed so we could not + * queue the full message. 0 = one way or another, everything is fine. side + * effects: on success, the ANCOUNT is incremented and the pointers are + * advanced. + */ +static int +sx_addrr(struct qstream *qsp, const char *dname, struct databuf *dp) { + HEADER *hp = (HEADER *) qsp->xfr.msg; + u_char **edp = qsp->xfr.ptrs + sizeof qsp->xfr.ptrs / sizeof(u_char *); + int n; + + if (qsp->xfr.cp != NULL) { + if (qsp->xfr.transfer_format == axfr_one_answer && + sx_flush(qsp) < 0) + return (-1); + } + if (qsp->xfr.cp == NULL) + sx_new_ixfrmsg(qsp); + n = make_rr(dname, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp, + 0, qsp->xfr.ptrs, edp, 0); + if (n < 0) { + if (sx_flush(qsp) < 0) + return (-1); + if (qsp->xfr.cp == NULL) + sx_new_ixfrmsg(qsp); + n = make_rr(dname, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp, + 0, qsp->xfr.ptrs, edp, 0); + INSIST(n >= 0); + } + hp->ancount = htons(ntohs(hp->ancount) + 1); + qsp->xfr.cp += n; + return (0); +} + +void +sx_send_ixfr(struct qstream *qsp) { + char * cp; + u_int32_t serial = 0; + struct zoneinfo *zp = NULL; + struct databuf *soa_dp; + struct databuf *old_soadp; + ns_updrec * rp; + ns_updrec * trp; + int foundsoa; + + zp = &zones[qsp->xfr.zone]; + soa_dp = (struct databuf *) findzonesoa(zp); + if (soa_dp == NULL) { + /* XXX should be more graceful */ + ns_panic(ns_log_update, 1, + "sx_send_ixfr: unable to locate soa"); + } + old_soadp = memget(DATASIZE(soa_dp->d_size)); + memcpy(old_soadp, soa_dp, DATASIZE(soa_dp->d_size)); + + again: + switch (qsp->xfr.state) { + case s_x_firstsoa: + /* + * The current SOA has been emited already. + * It would be cleaner if the first one was emited here... + * + * if (sx_addrr(qsp, zp->z_origin, soa_dp) < 0) + * goto cleanup; + */ + qsp->xfr.state = s_x_deletesoa; + /* FALLTHROUGH */ + case s_x_deletesoa: + if (qsp->xfr.top.ixfr) { + foundsoa = 0; + rp = qsp->xfr.top.ixfr; + while (PREV(rp, r_link) != NULL) + rp = PREV(rp, r_link); + while (rp != NULL) { + if (rp->r_opcode == DELETE && + rp->r_dp != NULL && + rp->r_dp->d_type == T_SOA) { + if (sx_addrr(qsp, rp->r_dname, + rp->r_dp) < 0) + goto cleanup; + db_freedata(rp->r_dp); + rp->r_dp = NULL; + foundsoa = 1; + break; + } + trp = rp; + rp = NEXT(rp, r_link); + } + + if (!foundsoa) { + cp = (char *)findsoaserial(old_soadp->d_data); + PUTLONG(qsp->xfr.top.ixfr->r_zone, cp); + + if (sx_addrr(qsp, zp->z_origin, old_soadp) < 0) + goto cleanup; + } + } + qsp->xfr.state = s_x_deleting; + /* FALLTHROUGH */ + case s_x_deleting: + if (qsp->xfr.top.ixfr) { + /* + * The order s important here. + * Go to start of this update via PREV(r_link) + * then extract all deletions. + */ + rp = qsp->xfr.top.ixfr; + while (PREV(rp, r_link) != NULL) + rp = PREV(rp, r_link); + while (rp != NULL) { + if (rp->r_opcode == DELETE && + rp->r_dp != NULL) { + /* + * Drop any SOA deletes + */ + if (rp->r_dp->d_type != T_SOA && + sx_addrr(qsp, rp->r_dname, + rp->r_dp) < 0) + goto cleanup; + db_freedata(rp->r_dp); + rp->r_dp = NULL; + } + trp = rp; + rp = NEXT(rp, r_link); + } + } + qsp->xfr.state = s_x_addsoa; + /* FALLTHROUGH */ + case s_x_addsoa: + if (qsp->xfr.top.ixfr) { + foundsoa = 0; + rp = qsp->xfr.top.ixfr; + while (PREV(rp, r_link) != NULL) + rp = PREV(rp, r_link); + while (rp != NULL) { + if (rp->r_opcode == ADD && + rp->r_dp != NULL && + rp->r_dp->d_type == T_SOA) { + if (sx_addrr(qsp, rp->r_dname, + rp->r_dp) < 0) + goto cleanup; + db_freedata(rp->r_dp); + rp->r_dp = NULL; + foundsoa = 1; + break; + } + trp = rp; + rp = NEXT(rp, r_link); + } + + if (!foundsoa) { + cp = (char *)findsoaserial(old_soadp->d_data); + if (NEXT(qsp->xfr.top.ixfr, r_link) != NULL) { + trp = qsp->xfr.top.ixfr; + PUTLONG(NEXT(trp, r_link)->r_zone, cp); + if (sx_addrr(qsp, zp->z_origin, + old_soadp) < 0) + goto cleanup; + } else { + if (sx_addrr(qsp, zp->z_origin, + soa_dp) < 0) + goto cleanup; + } + } + } + qsp->xfr.state = s_x_adding; + /* FALLTHROUGH */ + case s_x_adding: + if (qsp->xfr.top.ixfr) { + /* see s_x_deleting */ + rp = qsp->xfr.top.ixfr; + while (PREV(rp, r_link) != NULL) + rp = PREV(rp, r_link); + while (rp != NULL) { + if (rp->r_opcode == ADD && + rp->r_dp != NULL && + rp->r_dp->d_type != T_SOA) { + if (sx_addrr(qsp, rp->r_dname, + rp->r_dp) < 0) + goto cleanup; + db_freedata(rp->r_dp); + rp->r_dp = NULL; + } + trp = rp; + rp = NEXT(rp, r_link); + } + /* move to next update */ + rp = qsp->xfr.top.ixfr; + qsp->xfr.top.ixfr = NEXT(rp, r_link); + PREV(rp, r_link) = NULL; + + /* clean up old update */ + while (rp != NULL) { + trp = PREV(rp, r_link); + if (rp->r_dp != NULL) { + db_freedata(rp->r_dp); + rp->r_dp = NULL; + } + res_freeupdrec(rp); + rp = trp; + } + } + qsp->xfr.state = s_x_lastsoa; + /* FALLTHROUGH */ + case s_x_lastsoa: + if (qsp->xfr.ixfr_zone != 0) { + sx_addrr(qsp, zp->z_origin, soa_dp); + } + break; + } + qsp->xfr.state = s_x_done; + sx_flush(qsp); + sq_writeh(qsp, sq_flushw); + cleanup: + memput(old_soadp, DATASIZE(old_soadp->d_size)); +} + + +#ifndef MAXBSIZE +#define MAXBSIZE 8192 +#endif + + +int ixfr_log_maint(struct zoneinfo *zp) { + int fd, rcount, wcount, rval; + int found = 0, seek = 0; + FILE *to_fp, *from_fp, *db_fp; + static char *tmpname; + struct stat db_sb; + struct stat sb; + static char buf[MAXBSIZE]; + + ns_debug(ns_log_default, 3, "ixfr_log_maint(%s)", zp->z_origin); + + tmpname = memget(strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1); + if (!tmpname) { + ns_warning(ns_log_default, "memget failed"); + return (-1); + } +#ifdef SHORT_FNAMES + filenamecpy(tmpname, zp->z_ixfr_base); +#else + (void) strcpy(tmpname, zp->z_ixfr_base); +#endif /* SHORT_FNAMES */ + + (void) strcat(tmpname, ".XXXXXX"); + if ((fd = mkstemp(tmpname)) == -1) { + ns_warning(ns_log_db, "can't make tmpfile (%s): %s", + strerror(errno)); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + if ((to_fp = fdopen(fd, "r+")) == NULL) { + ns_warning(ns_log_db, "%s: %s", + tmpname, strerror(errno)); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + (void) close(fd); + return (-1); + } + /* find out how big the zone db file is */ + if ((db_fp = fopen(zp->z_source, "r")) == NULL) { + ns_warning(ns_log_db, "%s: %s", + zp->z_source, strerror(errno)); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + (void) my_fclose(to_fp); + (void) close(fd); + return (-1); + } + if (fstat(fileno(db_fp), &db_sb) < 0) { + ns_warning(ns_log_db, "%s: %s", + zp->z_source, strerror(errno)); + (void) my_fclose(to_fp); + (void) my_fclose(db_fp); + (void) close(fd); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + (void) my_fclose(db_fp); + ns_debug(ns_log_default, 3, "%s, size %d blk %d", + zp->z_source, db_sb.st_size, + db_sb.st_size); + + /* open up the zone ixfr log */ + if ((from_fp = fopen(zp->z_ixfr_base, "r")) == NULL) { + ns_warning(ns_log_db, "%s: %s", + zp->z_ixfr_base, strerror(errno)); + (void) my_fclose(to_fp); + (void) close(fd); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + + if (fstat(fileno(from_fp), &sb) < 0) { + ns_warning(ns_log_db, "%s: %s", + zp->z_ixfr_base, strerror(errno)); + (void) my_fclose(to_fp); + (void) close(fd); + (void) unlink(tmpname); + (void) my_fclose(from_fp); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + ns_debug(ns_log_default, 3, "%s, size %d log_s %d max %d\n", + zp->z_ixfr_base, + sb.st_size, + zp->z_log_size_ixfr, + zp->z_max_log_size_ixfr); + if (zp->z_max_log_size_ixfr) { + if (sb.st_size > zp->z_max_log_size_ixfr) + seek = sb.st_size - (zp->z_max_log_size_ixfr + (zp->z_max_log_size_ixfr *.10)); + else + seek = 0; + } else { + if (sb.st_size > (db_sb.st_size * .50)) + seek = sb.st_size - ((db_sb.st_size * .50) + + ((db_sb.st_size * zp->z_max_log_size_ixfr) *.10)); + else + seek = 0; + } + ns_debug(ns_log_default, 3, "seek: %d", seek); + if (seek < 1) + { + ns_debug(ns_log_default, 3, "%s does not need to be reduced", + zp->z_ixfr_base); + (void) my_fclose(to_fp); + (void) close(fd); + (void) unlink(tmpname); + (void) my_fclose(from_fp); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + + + if (fgets(buf, sizeof(buf), from_fp) == NULL) { + ns_error(ns_log_update, "fgets() from %s failed: %s", + zp->z_ixfr_base, strerror(errno)); + (void) my_fclose(from_fp); + (void) my_fclose(to_fp); + (void) close(fd); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + if (strcmp(buf, LogSignature) != 0) { + ns_error(ns_log_update, "invalid log file %s", + zp->z_ixfr_base); + (void) my_fclose(from_fp); + (void) my_fclose(to_fp); + (void) close(fd); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-3); + } + + if (fseek( from_fp, seek, 0) < 0) { + (void) my_fclose(from_fp); + (void) my_fclose(to_fp); + (void) close(fd); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + + found = 0; + for (;;) { + if (getword(buf, sizeof buf, from_fp, 0)) { + if (strcasecmp(buf, "[END_DELTA]") == 0) { + if (!(fgets(buf, 2, from_fp) == NULL)) /* eat <cr><lf> */ + found = 1; + break; + } + } + if (feof(from_fp)) + break; + } + if (found) { + ns_debug(ns_log_default, 1, "ixfr_log_maint(): found [END_DELTA]"); + + while ((rcount = fread(buf, sizeof(char), MAXBSIZE, from_fp)) > 0) { + wcount = fwrite(buf, sizeof(char), rcount, to_fp); + if (rcount != wcount || wcount == -1) { + ns_warning(ns_log_default, "ixfr_log_maint: error in writting copy"); + rval = 1; + break; + } + } + if (rcount < 0) { + ns_warning(ns_log_default, "ixfr_log_maint: error in reading copy"); + rval = 1; + } + } + (void) my_fclose(to_fp); + (void) close(fd); + (void) my_fclose(from_fp); + if (rename(tmpname, zp->z_ixfr_base) == -1) { + ns_warning(ns_log_default, "can not rename %s to %s :%s", + tmpname, zp->z_ixfr_base, strerror(errno)); + } + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + if ((from_fp = fopen(zp->z_ixfr_base, "r")) == NULL) { + ns_warning(ns_log_db, "%s: %s", + zp->z_ixfr_base, strerror(errno)); + return (-1); + } + if (fstat(fileno(from_fp), &sb) < 0) { + ns_warning(ns_log_db, "%s: %s", + zp->z_ixfr_base, strerror(errno)); + (void) my_fclose(from_fp); + return (-1); + } + if (sb.st_size <= 0) + (void) unlink(zp->z_ixfr_base); + (void) my_fclose(from_fp); + + ns_debug(ns_log_default, 3, "%s, size %d log_s %d max %d\n", + zp->z_ixfr_base, + sb.st_size, + zp->z_log_size_ixfr, + zp->z_max_log_size_ixfr); + return (0); +} diff --git a/contrib/bind/bin/named/ns_lexer.c b/contrib/bind/bin/named/ns_lexer.c index fe319fa..244d5f6 100644 --- a/contrib/bind/bin/named/ns_lexer.c +++ b/contrib/bind/bin/named/ns_lexer.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_lexer.c,v 8.12 1997/12/04 08:11:52 halley Exp $"; +static const char rcsid[] = "$Id: ns_lexer.c,v 8.19 1999/10/13 16:39:08 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -22,6 +22,8 @@ static char rcsid[] = "$Id: ns_lexer.c,v 8.12 1997/12/04 08:11:52 halley Exp $"; #include "port_before.h" #include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -52,6 +54,7 @@ typedef enum lexer_state { } LexerState; #define LEX_EOF 0x01 +#define LEXER_MAX_PUSHBACK 2 typedef struct lexer_file_context { const char * name; @@ -61,6 +64,8 @@ typedef struct lexer_file_context { u_int flags; int warnings; int errors; + u_int pushback_count; + char pushback[LEXER_MAX_PUSHBACK]; struct lexer_file_context * next; } *LexerFileContext; @@ -216,21 +221,29 @@ static struct keyword keywords[] = { {"acl", T_ACL}, {"address", T_ADDRESS}, {"algorithm", T_ALGID}, + {"allow", T_ALLOW}, {"allow-query", T_ALLOW_QUERY}, + {"allow-recursion", T_ALLOW_RECURSION}, {"allow-transfer", T_ALLOW_TRANSFER}, {"allow-update", T_ALLOW_UPDATE}, +#ifdef BIND_NOTIFY {"also-notify", T_ALSO_NOTIFY}, +#endif {"auth-nxdomain", T_AUTH_NXDOMAIN}, + {"blackhole", T_BLACKHOLE}, {"bogus", T_BOGUS}, {"category", T_CATEGORY}, + {"class", T_CLASS}, {"channel", T_CHANNEL}, {"check-names", T_CHECK_NAMES}, {"cleaning-interval", T_CLEAN_INTERVAL}, + {"controls", T_CONTROLS}, {"coresize", T_CORESIZE}, {"datasize", T_DATASIZE}, {"deallocate-on-exit", T_DEALLOC_ON_EXIT}, {"debug", T_DEBUG}, {"default", T_DEFAULT}, + {"dialup", T_DIALUP}, {"directory", T_DIRECTORY}, {"dump-file", T_DUMP_FILE}, {"dynamic", T_DYNAMIC}, @@ -243,47 +256,70 @@ static struct keyword keywords[] = { {"first", T_FIRST}, {"forward", T_FORWARD}, {"forwarders", T_FORWARDERS}, + {"group", T_GROUP}, + {"has-old-clients", T_HAS_OLD_CLIENTS}, + {"heartbeat-interval", T_HEARTBEAT}, {"hint", T_HINT}, {"host-statistics", T_HOSTSTATS}, {"if-no-answer", T_IF_NO_ANSWER}, {"if-no-domain", T_IF_NO_DOMAIN}, {"ignore", T_IGNORE}, {"include", T_INCLUDE}, + {"inet", T_INET}, {"interface-interval", T_INTERFACE_INTERVAL}, + {"ixfr-base", T_FILE_IXFR}, + {"ixfr-tmp-file", T_IXFR_TMP}, {"key", T_SEC_KEY}, {"keys", T_KEYS}, + {"lame-ttl", T_LAME_TTL}, {"listen-on", T_LISTEN_ON}, {"logging", T_LOGGING}, + {"maintain-ixfr-base", T_MAINTAIN_IXFR_BASE}, {"many-answers", T_MANY_ANSWERS}, {"master", T_MASTER}, {"masters", T_MASTERS}, + {"max-ixfr-log-size", T_MAX_LOG_SIZE_IXFR}, + {"max-ncache-ttl", T_MAX_NCACHE_TTL}, {"max-transfer-time-in", T_MAX_TRANSFER_TIME_IN}, {"memstatistics-file", T_MEMSTATS_FILE}, + {"min-roots", T_MIN_ROOTS}, {"multiple-cnames", T_MULTIPLE_CNAMES}, + {"name", T_NAME}, {"named-xfer", T_NAMED_XFER}, {"no", T_NO}, +#ifdef BIND_NOTIFY {"notify", T_NOTIFY}, +#endif {"null", T_NULL_OUTPUT}, {"one-answer", T_ONE_ANSWER}, {"only", T_ONLY}, + {"order", T_ORDER}, {"options", T_OPTIONS}, + {"owner", T_OWNER}, + {"perm", T_PERM}, {"pid-file", T_PIDFILE}, {"port", T_PORT}, {"print-category", T_PRINT_CATEGORY}, {"print-severity", T_PRINT_SEVERITY}, {"print-time", T_PRINT_TIME}, + {"pubkey", T_PUBKEY}, {"query-source", T_QUERY_SOURCE}, + {"rfc2308-type1", T_RFC2308_TYPE1}, + {"rrset-order", T_RRSET_ORDER}, {"recursion", T_RECURSION}, {"response", T_RESPONSE}, {"secret", T_SECRET}, + {"serial-queries", T_SERIAL_QUERIES}, {"server", T_SERVER}, {"severity", T_SEVERITY}, {"size", T_SIZE}, {"slave", T_SLAVE}, + {"sortlist", T_SORTLIST}, {"stacksize", T_STACKSIZE}, {"statistics-file", T_STATS_FILE}, {"statistics-interval", T_STATS_INTERVAL}, {"stub", T_STUB}, + {"support-ixfr", T_SUPPORT_IXFR}, {"syslog", T_SYSLOG}, {"topology", T_TOPOLOGY}, {"transfer-format", T_TRANSFER_FORMAT}, @@ -292,9 +328,15 @@ static struct keyword keywords[] = { {"transfers-in", T_TRANSFERS_IN}, {"transfers-out", T_TRANSFERS_OUT}, {"transfers-per-ns", T_TRANSFERS_PER_NS}, + {"treat-cr-as-space", T_TREAT_CR_AS_SPACE}, {"true", T_TRUE}, + {"trusted-keys", T_TRUSTED_KEYS}, {"type", T_TYPE}, + {"unix", T_UNIX}, {"unlimited", T_UNLIMITED}, + {"use-id-pool", T_USE_ID_POOL}, + {"use-ixfr", T_USE_IXFR}, + {"version", T_VERSION}, {"versions", T_VERSIONS}, {"warn", T_WARN}, {"yes", T_YES}, @@ -351,6 +393,7 @@ lexer_begin_file(const char *filename, FILE *stream) { lf->flags = 0; lf->warnings = 0; lf->errors = 0; + lf->pushback_count = 0; lf->next = current_file; current_file = lf; } @@ -370,14 +413,29 @@ lexer_end_file(void) { * Character Input */ +#define LEXER_GETC(c, cf) \ + do { \ + if ((cf)->pushback_count > 0) { \ + (cf)->pushback_count--; \ + (c) = (cf)->pushback[(cf)->pushback_count]; \ + } else \ + (c) = getc((cf)->stream); \ + } while (0); + +#define LEXER_UNGETC(c, cf) \ + do { \ + INSIST((cf)->pushback_count < LEXER_MAX_PUSHBACK); \ + (cf)->pushback[(cf)->pushback_count++] = (c); \ + } while (0); + static void scan_to_comment_end(int c_plus_plus_style) { - int c, nc; + int c; int done = 0; int prev_was_star = 0; while (!done) { - c = getc(current_file->stream); + LEXER_GETC(c, current_file); switch (c) { case EOF: if (!c_plus_plus_style) @@ -399,7 +457,7 @@ scan_to_comment_end(int c_plus_plus_style) { we want it to be a delimiter for anything before the comment started */ - ungetc(c, current_file->stream); + LEXER_UNGETC(c, current_file); done = 1; } else { current_file->line_number++; @@ -419,7 +477,7 @@ get_next_char(int comment_ok) { if (current_file->flags & LEX_EOF) return (EOF); - c = getc(current_file->stream); + LEXER_GETC(c, current_file); if (comment_ok) { while (c == '/' || c == '#') { @@ -427,9 +485,9 @@ get_next_char(int comment_ok) { scan_to_comment_end(1); if (current_file->flags & LEX_EOF) return (EOF); - c = getc(current_file->stream); + LEXER_GETC(c, current_file); } else { - nc = getc(current_file->stream); + LEXER_GETC(nc, current_file); switch (nc) { case EOF: current_file->flags |= LEX_EOF; @@ -439,10 +497,10 @@ get_next_char(int comment_ok) { scan_to_comment_end((nc == '/')); if (current_file->flags & LEX_EOF) return (EOF); - c = getc(current_file->stream); + LEXER_GETC(c, current_file); break; default: - ungetc((nc), current_file->stream); + LEXER_UNGETC(nc, current_file); return ('/'); } } @@ -461,7 +519,7 @@ put_back_char(int c) { if (c == EOF) current_file->flags |= LEX_EOF; else { - ungetc((c), current_file->stream); + LEXER_UNGETC(c, current_file); if (c == '\n') current_file->line_number--; } @@ -504,7 +562,7 @@ add_to_identifier(LexerIdentifier id, int c) { parser_error(0, "identifier too long"); current_file->state = scan; /* discard chars until we hit a non-identifier char */ - while (identifier_char(c)) { + while (c != EOF && identifier_char(c)) { c = get_next_char(1); } put_back_char(c); @@ -526,7 +584,7 @@ add_to_identifier(LexerIdentifier id, int c) { */ int yylex() { - int c, i; + int c; int comment_ok = 1; int token = -1; symbol_value value; @@ -581,7 +639,7 @@ yylex() { break; case number: - if (identifier_char(c)) { + if (c != EOF && identifier_char(c)) { if (!isdigit(c)) current_file->state = (c == '.') ? ipv4 : identifier; @@ -590,13 +648,13 @@ yylex() { put_back_char(c); current_file->state = scan; finish_identifier(id); - yylval.num = atoi(id->buffer); + yylval.num = strtol(id->buffer, (char**)0, 0); token = L_NUMBER; } break; case identifier: - if (identifier_char(c)) { + if (c != EOF && identifier_char(c)) { add_to_identifier(id, c); } else { put_back_char(c); @@ -615,7 +673,7 @@ yylex() { break; case ipv4: - if (identifier_char(c)) { + if (c != EOF && identifier_char(c)) { if (!isdigit(c)) { if (c != '.' || (id->flags & LEX_CONSECUTIVE_DOTS)) @@ -725,7 +783,7 @@ lexer_initialize() { special_chars['*'] = 1; id = (LexerIdentifier)memget(sizeof (struct lexer_identifier)); if (id == NULL) - panic("memget failed in init_once", NULL); + panic("memget failed in lexer_initialize", NULL); init_keywords(); import_all_constants(); lexer_initialized = 1; @@ -746,5 +804,6 @@ lexer_shutdown(void) { free_symbol_table(keyword_table); free_symbol_table(constants); memput(id, sizeof (struct lexer_identifier)); + id = NULL; lexer_initialized = 0; } diff --git a/contrib/bind/bin/named/ns_lexer.h b/contrib/bind/bin/named/ns_lexer.h index 3491df3..66c19f2 100644 --- a/contrib/bind/bin/named/ns_lexer.h +++ b/contrib/bind/bin/named/ns_lexer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,8 +15,8 @@ * SOFTWARE. */ -#ifndef NS_LEXER_H -#define NS_LEXER_H +#ifndef _NS_LEXER_H +#define _NS_LEXER_H /* * Note: <stdio.h> and "ns_parseutil.h" must be included @@ -42,4 +42,4 @@ void lexer_shutdown(void); extern symbol_table constants; -#endif /* NS_LEXER_H */ +#endif /* !_NS_LEXER_H */ diff --git a/contrib/bind/bin/named/ns_main.c b/contrib/bind/bin/named/ns_main.c index 194d368..1377098 100644 --- a/contrib/bind/bin/named/ns_main.c +++ b/contrib/bind/bin/named/ns_main.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_main.c 4.55 (Berkeley) 7/1/91"; -static char rcsid[] = "$Id: ns_main.c,v 8.67 1998/04/28 19:17:46 halley Exp $"; +static const char sccsid[] = "@(#)ns_main.c 4.55 (Berkeley) 7/1/91"; +static const char rcsid[] = "$Id: ns_main.c,v 8.117 1999/11/08 23:01:38 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_main.c,v 8.67 1998/04/28 19:17:46 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -75,10 +75,11 @@ static char rcsid[] = "$Id: ns_main.c,v 8.67 1998/04/28 19:17:46 halley Exp $"; #if !defined(lint) && !defined(SABER) char copyright[] = -"@(#) Copyright (c) 1986, 1989, 1990 The Regents of the University of California.\n\ - portions Copyright (c) 1993 Digital Equipment Corporation\n\ - portions Copyright (c) 1995, 1996, 1997 Internet Software Consortium\n\ - All rights reserved.\n"; +"@(#) Copyright (c) 1986, 1989, 1990 The Regents of the University of California.\n" +"portions Copyright (c) 1993 Digital Equipment Corporation\n" +"portions Copyright (c) 1995-1999 Internet Software Consortium\n" +"portions Copyright (c) 1999 Check Point Software Technologies\n" +"All rights reserved.\n"; #endif /* not lint */ /* @@ -94,6 +95,7 @@ char copyright[] = #include <sys/wait.h> #include <sys/ioctl.h> #include <sys/socket.h> +#include <sys/un.h> #ifdef SVR4 /* XXX */ # include <sys/sockio.h> #else @@ -139,21 +141,32 @@ char copyright[] = /* list of interfaces */ static LIST(struct _interface) iflist; static int iflist_initialized = 0; +static int iflist_dont_rescan = 0; - -static const int drbufsize = 8 * 1024, /* UDP rcv buf size */ - dsbufsize = 16 * 1024, /* UDP snd buf size */ - sbufsize = 16 * 1024; /* TCP snd buf size */ +static const int drbufsize = 32 * 1024, /* UDP rcv buf size */ + dsbufsize = 48 * 1024, /* UDP snd buf size */ + sbufsize = 16 * 1024, /* TCP snd buf size */ + nudptrans = 20, /* #/udps per select */ + listenmax = 50; static u_int16_t nsid_state; -static int needs; +static u_int16_t *nsid_pool; /* optional query id pool */ +static u_int16_t *nsid_vtable; /* optional shuffle table */ +static u_int32_t nsid_hash_state; +static u_int16_t nsid_a1, nsid_a2, nsid_a3; +static u_int16_t nsid_c1, nsid_c2, nsid_c3; +static u_int16_t nsid_state2; +static int nsid_algorithm; + +typedef void (*handler)(void); +static int needs = 0; +static handler handlers[main_need_num]; static struct qstream *sq_add(void); static int opensocket_d(interface *), opensocket_s(interface *); static void sq_query(struct qstream *), - dq_remove(interface *), - ns_handle_needs(void); + dq_remove(interface *); static int sq_dowrite(struct qstream *); static void use_desired_debug(void); static void stream_write(evContext, void *, int, int); @@ -162,7 +175,8 @@ static interface * if_find(struct in_addr, u_int16_t port); static int sq_here(struct qstream *); -static void stream_accept(evContext, void *, int, +static void deallocate_everything(void), + stream_accept(evContext, void *, int, const void *, int, const void *, int), stream_getlen(evContext, void *, int, int), @@ -175,14 +189,20 @@ static void stream_accept(evContext, void *, int, static void stream_send(evContext, void *, int, const void *, int, const void *, int); -static void init_signals(void); -static void set_signal_handler(int, SIG_FN (*)()); static int only_digits(const char *); +static void init_needs(void), + handle_need(void); + +#ifndef HAVE_CUSTOM +static void custom_init(void), + custom_shutdown(void); +#endif + static void usage() { fprintf(stderr, -"Usage: named [-d #] [-q] [-r] [-f] [-p port] [[-b|-c] configfile]\n"); +"Usage: named [-d #] [-q] [-r] [-v] [-f] [-p port] [[-b|-c] configfile]\n"); #ifdef CAN_CHANGE_ID fprintf(stderr, " [-u (username|uid)] [-g (groupname|gid)]\n"); @@ -202,20 +222,16 @@ static char bad_directory[] = "chdir failed for directory '%s': %s"; /*ARGSUSED*/ int main(int argc, char *argv[], char *envp[]) { - int n, udpcnt; - char *arg; - struct qstream *sp; - interface *ifp; - const int on = 1; - int rfd, size, len, debug_option; - char **argp, *p; + int n; + char *p; int ch; - FILE *fp; /* file descriptor for pid file */ struct passwd *pw; struct group *gr; -#ifdef HAVE_GETRUSAGE - struct rlimit rl; + +#ifdef _AUX_SOURCE + set42sig(); #endif + debugfile = savestr(_PATH_DEBUG, 1); user_id = getuid(); group_id = getgid(); @@ -231,7 +247,17 @@ main(int argc, char *argv[], char *envp[]) { (void) umask(022); - while ((ch = getopt(argc, argv, "b:c:d:g:p:t:u:w:qrf")) != EOF) { + /* Save argv[] before getopt() destroys it -- needed for execvp(). */ + saved_argv = malloc(sizeof(char *) * (argc + 1)); + INSIST(saved_argv != NULL); + for (n = 0; n < argc; n++) { + saved_argv[n] = strdup(argv[n]); + INSIST(saved_argv[n] != NULL); + } + saved_argv[argc] = NULL; + /* XXX we need to free() this for clean shutdowns. */ + + while ((ch = getopt(argc, argv, "b:c:d:g:p:t:u:vw:qrf")) != -1) { switch (ch) { case 'b': case 'c': @@ -291,6 +317,10 @@ main(int argc, char *argv[], char *envp[]) { chroot_dir = savestr(optarg, 1); break; + case 'v': + fprintf(stderr, "%s\n", Version); + exit(1); + #ifdef CAN_CHANGE_ID case 'u': user_name = savestr(optarg, 1); @@ -390,6 +420,10 @@ main(int argc, char *argv[], char *envp[]) { /* Establish global event context. */ evCreate(&ev); + /* Establish global resolver context. */ + res_ninit(&res); + res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE); + /* * Set up logging. */ @@ -416,14 +450,14 @@ main(int argc, char *argv[], char *envp[]) { use_desired_debug(); #endif + /* Perform system-dependent initialization */ + custom_init(); + + init_needs(); init_signals(); ns_notice(ns_log_default, "starting. %s", Version); - _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE); - - nsid_init(); - /* * Initialize and load database. */ @@ -434,6 +468,8 @@ main(int argc, char *argv[], char *envp[]) { time(&boottime); resettime = boottime; + nsid_init(); + /* * Fork and go into background now that * we've done any slow initialization @@ -477,21 +513,46 @@ main(int argc, char *argv[], char *envp[]) { ns_panic(ns_log_security, 1, "setuid(%s): %s", user_name, strerror(errno)); ns_info(ns_log_security, "user = %s", user_name); + if (user_id != 0) + iflist_dont_rescan++; } #endif /* CAN_CHANGE_ID */ ns_notice(ns_log_default, "Ready to answer queries."); gettime(&tt); prime_cache(); - for (;;) { + while (!main_needs_exit) { evEvent event; - if (needs) - ns_handle_needs(); - INSIST_ERR(evGetNext(ev, &event, EV_WAIT) != -1); - INSIST_ERR(evDispatch(ev, event) != -1); + ns_debug(ns_log_default, 15, "main loop"); + if (needs != 0) { + /* Drain outstanding events; handlers ~block~. */ + while (evGetNext(ev, &event, EV_POLL) != -1) + INSIST_ERR(evDispatch(ev, event) != -1); + INSIST_ERR(errno == EINTR || errno == EWOULDBLOCK); + handle_need(); + } else if (evGetNext(ev, &event, EV_WAIT) != -1) { + INSIST_ERR(evDispatch(ev, event) != -1); + } else { + INSIST_ERR(errno == EINTR); + } } - /* NOTREACHED */ + ns_info(ns_log_default, "named shutting down"); +#ifdef BIND_UPDATE + dynamic_about_to_exit(); +#endif + if (server_options && server_options->pid_filename) + (void)unlink(server_options->pid_filename); + ns_logstats(ev, NULL, evNowTime(), evConsTime(0, 0)); + + if (NS_OPTION_P(OPTION_DEALLOC_ON_EXIT)) + deallocate_everything(); + else + shutdown_configuration(); + + /* Cleanup for system-dependent stuff */ + custom_shutdown(); + return (0); } @@ -508,7 +569,7 @@ stream_accept(evContext lev, void *uap, int rfd, interface *ifp = uap; struct qstream *sp; struct iovec iov; - int n, len; + int len, n; const int on = 1; #ifdef IP_OPTIONS /* XXX */ u_char ip_opts[IP_OPT_BUF_SIZE]; @@ -594,21 +655,6 @@ stream_accept(evContext lev, void *uap, int rfd, /* Condition the socket. */ -/* XXX clean up */ -#if 0 - if ((n = fcntl(rfd, F_GETFL, 0)) == -1) { - ns_info(ns_log_default, "fcntl(rfd, F_GETFL): %s", - strerror(errno)); - (void) close(rfd); - return; - } - if (fcntl(rfd, F_SETFL, n|PORT_NONBLOCK) == -1) { - ns_info(ns_log_default, "fcntl(rfd, NONBLOCK): %s", - strerror(errno)); - (void) close(rfd); - return; - } -#endif #ifndef CANNOT_SET_SNDBUF if (setsockopt(rfd, SOL_SOCKET, SO_SNDBUF, (char*)&sbufsize, sizeof sbufsize) < 0) { @@ -626,6 +672,19 @@ stream_accept(evContext lev, void *uap, int rfd, return; } + if ((n = fcntl(rfd, F_GETFL, 0)) == -1) { + ns_info(ns_log_default, "fcntl(rfd, F_GETFL): %s", + strerror(errno)); + (void) close(rfd); + return; + } + if (fcntl(rfd, F_SETFL, n|PORT_NONBLOCK) == -1) { + ns_info(ns_log_default, "fcntl(rfd, NONBLOCK): %s", + strerror(errno)); + (void) close(rfd); + return; + } + /* * We don't like IP options. Turn them off if the connection came in * with any. log this event since it usually indicates a security @@ -685,20 +744,23 @@ tcp_send(struct qinfo *qp) { ns_debug(ns_log_default, 1, "tcp_send"); if ((sp = sq_add()) == NULL) { - return(SERVFAIL); + return (SERVFAIL); } if ((sp->s_rfd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) == -1) { sq_remove(sp); - return(SERVFAIL); + return (SERVFAIL); + } + if (sp->s_rfd > evHighestFD(ev)) { + sq_remove(sp); + return (SERVFAIL); } - if (sq_openw(sp, qp->q_msglen + INT16SZ) == -1) { sq_remove(sp); - return(SERVFAIL); + return (SERVFAIL); } if (sq_write(sp, qp->q_msg, qp->q_msglen) == -1) { sq_remove(sp); - return(SERVFAIL); + return (SERVFAIL); } if (setsockopt(sp->s_rfd, SOL_SOCKET, SO_KEEPALIVE, @@ -711,17 +773,14 @@ tcp_send(struct qinfo *qp) { sp->s_time = tt.tv_sec; /* last transaction time */ sp->s_refcnt = 1; sp->flags |= STREAM_DONE_CLOSE; - if (qp->q_fwd) - sp->s_from = qp->q_fwd->fwdaddr; - else - sp->s_from = qp->q_addr[qp->q_curaddr].ns_addr; + sp->s_from = qp->q_addr[qp->q_curaddr].ns_addr; if (evConnect(ev, sp->s_rfd, &sp->s_from, sizeof(sp->s_from), stream_send, sp, &sp->evID_c) == -1) { sq_remove(sp); return (SERVFAIL); } sp->flags |= STREAM_CONNECT_EV; - return(NOERROR); + return (NOERROR); } static void @@ -763,7 +822,8 @@ stream_write(evContext ctx, void *uap, int fd, int evmask) { if (sp->s_wbuf) { memput(sp->s_wbuf, sp->s_wbuf_end - sp->s_wbuf); - sp->s_wbuf = NULL; + sp->s_wbuf_send = sp->s_wbuf_free = NULL; + sp->s_wbuf_end = sp->s_wbuf = NULL; } (void) evDeselectFD(ev, sp->evID_w); sp->flags &= ~STREAM_WRITE_EV; @@ -811,6 +871,13 @@ stream_getlen(evContext lev, void *uap, int fd, int bytes) { */ sp->s_size = ns_get16(sp->s_temp); ns_debug(ns_log_default, 5, "stream message: %d bytes", sp->s_size); + if (sp->s_size < HFIXEDSZ) { + ns_error(ns_log_default, + "stream_getlen(%s): request too small", + sin_ntoa(sp->s_from)); + sq_remove(sp); + return; + } if (!(sp->flags & STREAM_MALLOC)) { sp->s_bufsize = 64*1024-1; /* maximum tcp message size */ @@ -834,7 +901,6 @@ stream_getlen(evContext lev, void *uap, int fd, int bytes) { static void stream_getmsg(evContext lev, void *uap, int fd, int bytes) { struct qstream *sp = uap; - int buflen, n; sp->flags &= ~STREAM_READ_EV; if (bytes == -1) { @@ -847,10 +913,12 @@ stream_getmsg(evContext lev, void *uap, int fd, int bytes) { gettime(&tt); sp->s_time = tt.tv_sec; - ns_debug(ns_log_default, 5, "sp %#x rfd %d size %d time %d next %#x", - sp, sp->s_rfd, sp->s_size, sp->s_time, sp->s_next); - ns_debug(ns_log_default, 5, "\tbufsize %d bytes %d", sp->s_bufsize, - bytes); + if (ns_wouldlog(ns_log_default,5)) { + ns_debug(ns_log_default, 5, "sp %#x rfd %d size %d time %d next %#x", + sp, sp->s_rfd, sp->s_size, sp->s_time, sp->s_next); + ns_debug(ns_log_default, 5, "\tbufsize %d bytes %d", sp->s_bufsize, + bytes); + } /* * Do we have enough memory for the query? If not, and if we have a @@ -882,12 +950,16 @@ datagram_read(evContext lev, void *uap, int fd, int evmask) { interface *ifp = uap; struct sockaddr_in from; int from_len = sizeof from; - int n; + int n, nudp; union { HEADER h; /* Force alignment of 'buf'. */ u_char buf[PACKETSZ+1]; } u; + tt = evTimeVal(evNowTime()); + nudp = 0; + + more: n = recvfrom(fd, (char *)u.buf, sizeof u.buf, 0, (struct sockaddr *)&from, &from_len); @@ -911,15 +983,6 @@ datagram_read(evContext lev, void *uap, int fd, int evmask) { * ignore them. */ return; - case EBADF: - case ENOTCONN: - case ENOTSOCK: - case EFAULT: - /* - * If one these happens, we're broken. - */ - ns_panic(ns_log_default, 1, "recvfrom: %s", - strerror(errno)); default: /* * An error we don't expect. Log it and press @@ -931,14 +994,14 @@ datagram_read(evContext lev, void *uap, int fd, int evmask) { } } -#ifndef BSD /* Handle bogosity on systems that need it. */ if (n == 0) return; -#endif - ns_debug(ns_log_default, 1, "datagram from %s, fd %d, len %d", - sin_ntoa(from), fd, n); + if (ns_wouldlog(ns_log_default, 1)) { + ns_debug(ns_log_default, 1, "datagram from %s, fd %d, len %d", + sin_ntoa(from), fd, n); + } if (n > PACKETSZ) { /* @@ -949,8 +1012,9 @@ datagram_read(evContext lev, void *uap, int fd, int evmask) { ns_debug(ns_log_default, 1, "truncated oversize UDP packet"); } - gettime(&tt); /* Keep 'tt' current. */ dispatch_message(u.buf, n, PACKETSZ, NULL, from, fd, ifp); + if (++nudp < nudptrans) + goto more; } static void @@ -961,8 +1025,35 @@ dispatch_message(u_char *msg, int msglen, int buflen, struct qstream *qsp, if (msglen < HFIXEDSZ) { ns_debug(ns_log_default, 1, "dropping undersize message"); + if (qsp) { + qsp->flags |= STREAM_DONE_CLOSE; + sq_done(qsp); + } return; } + + if (server_options->blackhole_acl != NULL && + ip_match_address(server_options->blackhole_acl, + from.sin_addr) == 1) { + ns_debug(ns_log_default, 1, + "dropping blackholed %s from %s", + hp->qr ? "response" : "query", + sin_ntoa(from)); + if (qsp) { + qsp->flags |= STREAM_DONE_CLOSE; + sq_done(qsp); + } + return; + } + + /* Drop UDP packets from port zero. They are invariable forged. */ + if (qsp == NULL && ntohs(from.sin_port) == 0) { + ns_notice(ns_log_security, + "dropping source port zero packet from %s", + sin_ntoa(from)); + return; + } + if (hp->qr) { ns_resp(msg, msglen, from, qsp); if (qsp) @@ -976,6 +1067,10 @@ dispatch_message(u_char *msg, int msglen, int buflen, struct qstream *qsp, ns_notice(ns_log_security, "refused query on non-query socket from %s", sin_ntoa(from)); + if (qsp) { + qsp->flags |= STREAM_DONE_CLOSE; + sq_done(qsp); + } /* XXX Send refusal here. */ } } @@ -986,17 +1081,24 @@ getnetconf(int periodic_scan) { struct ifreq ifreq; struct in_addr ina; interface *ifp; - char buf[32768], *cp, *cplim; - u_int32_t nm; + char *buf, *cp, *cplim; + static int bufsiz = 4095; time_t my_generation = time(NULL); - int s, cpsize; + int s, cpsize, n; int found; listen_info li; - u_int16_t port; ip_match_element ime; u_char *mask_ptr; struct in_addr mask; + if (iflist_initialized) { + if (iflist_dont_rescan) + return; + } else { + INIT_LIST(iflist); + iflist_initialized = 1; + } + ns_debug(ns_log_default, 1, "getnetconf(generation %lu)", (u_long)my_generation); @@ -1010,11 +1112,6 @@ getnetconf(int periodic_scan) { return; } - if (!iflist_initialized) { - INIT_LIST(iflist); - iflist_initialized = 1; - } - if (local_addresses != NULL) free_ip_match_list(local_addresses); local_addresses = new_ip_match_list(); @@ -1022,11 +1119,46 @@ getnetconf(int periodic_scan) { free_ip_match_list(local_networks); local_networks = new_ip_match_list(); - ifc.ifc_len = sizeof buf; - ifc.ifc_buf = buf; - if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) - ns_panic(ns_log_default, 1, "get interface configuration: %s", - strerror(errno)); + for (;;) { + buf = memget(bufsiz); + if (!buf) + ns_panic(ns_log_default, 1, + "memget(interface)", NULL); + ifc.ifc_len = bufsiz; + ifc.ifc_buf = buf; +#ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF + /* + * This is a fix for IRIX OS in which the call to ioctl with + * the flag SIOCGIFCONF may not return an entry for all the + * interfaces like most flavors of Unix. + */ + if (emul_ioctl(&ifc) >= 0) + break; +#else + if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) { + /* + * Some OS's just return what will fit rather + * than set EINVAL if the buffer is too small + * to fit all the interfaces in. If + * ifc.ifc_len is too near to the end of the + * buffer we will grow it just in case and + * retry. + */ + if (ifc.ifc_len + 2 * sizeof(ifreq) < bufsiz) + break; + } +#endif + if ((n == -1) && errno != EINVAL) + ns_panic(ns_log_default, 1, + "get interface configuration: %s", + strerror(errno)); + + if (bufsiz > 1000000) + ns_panic(ns_log_default, 1, + "get interface configuration: maximum buffer size exceeded"); + memput(buf, bufsiz); + bufsiz += 4096; + } ns_debug(ns_log_default, 2, "getnetconf: SIOCGIFCONF: ifc_len = %d", ifc.ifc_len); @@ -1035,7 +1167,7 @@ getnetconf(int periodic_scan) { cplim = buf + ifc.ifc_len; /* skip over if's with big ifr_addr's */ for (cp = buf; cp < cplim; cp += cpsize) { memcpy(&ifreq, cp, sizeof ifreq); -#if defined HAVE_SA_LEN +#ifdef HAVE_SA_LEN #ifdef FIX_ZERO_SA_LEN if (ifreq.ifr_addr.sa_len == 0) ifreq.ifr_addr.sa_len = 16; @@ -1228,6 +1360,7 @@ getnetconf(int periodic_scan) { } } close(s); + memput(buf, bufsiz); ns_debug(ns_log_default, 7, "local addresses:"); dprint_ip_match_list(ns_log_default, local_addresses, 2, "", ""); @@ -1270,6 +1403,23 @@ opensocket_d(interface *ifp) { strerror(errno)); return (-1); } + if (ifp->dfd > evHighestFD(ev)) { + ns_error(ns_log_default, "socket too high: %d", ifp->dfd); + close(ifp->dfd); + return (-1); + } + if ((n = fcntl(ifp->dfd, F_GETFL, 0)) == -1) { + ns_info(ns_log_default, "fcntl(ifp->dfd, F_GETFL): %s", + strerror(errno)); + (void) close(ifp->dfd); + return (-1); + } + if (fcntl(ifp->dfd, F_SETFL, n|PORT_NONBLOCK) == -1) { + ns_info(ns_log_default, "fcntl(ifp->dfd, NONBLOCK): %s", + strerror(errno)); + (void) close(ifp->dfd); + return (-1); + } #ifdef F_DUPFD /* XXX */ /* * Leave a space for stdio to work in. @@ -1350,6 +1500,11 @@ opensocket_s(interface *ifp) { strerror(errno)); return (-1); } + if (ifp->sfd > evHighestFD(ev)) { + ns_error(ns_log_default, "socket too high: %d", ifp->sfd); + close(ifp->sfd); + return (-1); + } #ifdef F_DUPFD /* XXX */ /* * Leave a space for stdio to work in. @@ -1386,7 +1541,7 @@ opensocket_s(interface *ifp) { sleep(30); goto again; } - if (evListen(ev, ifp->sfd, 5/*XXX*/, stream_accept, ifp, &ifp->evID_s) + if (evListen(ev, ifp->sfd, listenmax, stream_accept, ifp, &ifp->evID_s) == -1) { ns_error(ns_log_default, "evListen(sfd=%d): %s", ifp->sfd, strerror(errno)); @@ -1460,6 +1615,8 @@ opensocket_f() { if ((ds = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ns_panic(ns_log_default, 1, "socket(SOCK_DGRAM): %s", strerror(errno)); + if (ds > evHighestFD(ev)) + ns_panic(ns_log_default, 1, "socket too high: %d", ds); if (setsockopt(ds, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on) != 0) { ns_notice(ns_log_default, "setsockopt(REUSEADDR): %s", @@ -1468,7 +1625,7 @@ opensocket_f() { } if (bind(ds, (struct sockaddr *)&server_options->query_source, sizeof server_options->query_source) < 0) - ns_panic(ns_log_default, 1, "opensocket_f: bind(%s): %s", + ns_panic(ns_log_default, 0, "opensocket_f: bind(%s): %s", sin_ntoa(server_options->query_source), strerror(errno)); @@ -1513,56 +1670,6 @@ setdebug(int new_debug) { #endif } -static SIG_FN -onhup(int sig) { - ns_need(MAIN_NEED_RELOAD); -} - -static SIG_FN -onintr(int sig) { - ns_need(MAIN_NEED_EXIT); -} - -static SIG_FN -setdumpflg(int sig) { - ns_need(MAIN_NEED_DUMP); -} - -#ifdef DEBUG -static SIG_FN -setIncrDbgFlg(int sig) { - desired_debug++; - ns_need(MAIN_NEED_DEBUG); -} - -static SIG_FN -setNoDbgFlg(int sig) { - desired_debug = 0; - ns_need(MAIN_NEED_DEBUG); -} -#endif /*DEBUG*/ - -#if defined(QRYLOG) && defined(SIGWINCH) -static SIG_FN -setQrylogFlg(int sig) { - ns_need(MAIN_NEED_QRYLOG); -} -#endif /*QRYLOG && SIGWINCH*/ - -static SIG_FN -setstatsflg(int sig) { - ns_need(MAIN_NEED_STATSDUMP); -} - -static SIG_FN -discard_pipe(int sig) { -#ifdef SIGPIPE_ONE_SHOT - int saved_errno = errno; - set_signal_handler(SIGPIPE, discard_pipe); - errno = saved_errno; -#endif -} - /* ** Routines for managing stream queue */ @@ -1601,7 +1708,8 @@ sq_remove(struct qstream *qp) { if (qp->s_wbuf != NULL) { memput(qp->s_wbuf, qp->s_wbuf_end - qp->s_wbuf); - qp->s_wbuf = NULL; + qp->s_wbuf_send = qp->s_wbuf_free = NULL; + qp->s_wbuf_end = qp->s_wbuf = NULL; } if (qp->flags & STREAM_MALLOC) memput(qp->s_buf, qp->s_bufsize); @@ -1655,7 +1763,7 @@ sq_flush(struct qstream *allbut) { */ int sq_openw(struct qstream *qs, int buflen) { -#ifdef SO_LINGER /* XXX */ +#ifdef DO_SO_LINGER /* XXX */ static const struct linger ll = { 1, 120 }; #endif @@ -1666,7 +1774,7 @@ sq_openw(struct qstream *qs, int buflen) { qs->s_wbuf_send = qs->s_wbuf; qs->s_wbuf_free = qs->s_wbuf; qs->s_wbuf_end = qs->s_wbuf + buflen; -#ifdef SO_LINGER /* XXX */ +#ifdef DO_SO_LINGER /* XXX */ /* kernels that map pages for IO end up failing if the pipe is full * at exit and we take away the final buffer. this is really a kernel * bug but it's harmless on systems that are not broken, so... @@ -1685,6 +1793,7 @@ sq_dowrite(struct qstream *qs) { if (qs->s_wbuf_free > qs->s_wbuf_send) { int n = write(qs->s_rfd, qs->s_wbuf_send, qs->s_wbuf_free - qs->s_wbuf_send); + INSIST(qs->s_wbuf != NULL); if (n < 0) { if (errno != EINTR && errno != EAGAIN #if (EWOULDBLOCK != EAGAIN) @@ -1831,8 +1940,10 @@ sq_done(struct qstream *sp) { struct iovec iov; if (sp->s_wbuf != NULL) { + INSIST(sp->s_wbuf_send == sp->s_wbuf_free); memput(sp->s_wbuf, sp->s_wbuf_end - sp->s_wbuf); - sp->s_wbuf = NULL; + sp->s_wbuf_send = sp->s_wbuf_free = NULL; + sp->s_wbuf_end = sp->s_wbuf = NULL; } if (sp->flags & STREAM_AXFR) ns_freexfr(sp); @@ -1950,7 +2061,6 @@ net_mask(struct in_addr ina) { */ int aIsUs(struct in_addr addr) { - interface *ifp; if (ina_hlong(addr) == INADDR_ANY || if_find(addr, 0) != NULL) return (1); @@ -1982,22 +2092,397 @@ if_find(struct in_addr addr, u_int16_t port) { * allocation scheme to make it a little harder to predict them. Note * that the resolver will need the same protection so the cleverness * should be put there rather than here; this is just an interface layer. + * + * This is true but ... most clients only send out a few queries, they + * use varying port numbers, and the queries aren't sent to the outside + * world which we know is full of spoofers. Doing a good job of randomizing + * ids may also be to expensive for each client. Queries forwarded by the + * server always come from the same port (unless you let 8.x pick a port + * and restart it periodically - maybe it should open several and use + * them randomly). The server sends out lots more queries, and if it's + * cache is corrupted, it has the potential to affect more clients. + * NOTE: - randomizing the ID or source port doesn't help a bit if the + * queries can be sniffed. + * -- DL + */ + +/* + * Allow the user to pick one of two ID randomization algorithms. + * + * The first algorithm is an adaptation of the sequence shuffling + * algorithm discovered by Carter Bays and S. D. Durham [ACM Trans. Math. + * Software 2 (1976), 59-64], as documented as Algorithm B in Chapter + * 3.2.2 in Volume 2 of Knuth's "The Art of Computer Programming". We use + * a randomly selected linear congruential random number generator with a + * modulus of 2^16, whose increment is a randomly picked odd number, and + * whose multiplier is picked from a set which meets the following + * criteria: + * Is of the form 8*n+5, which ensures "high potency" according to + * principle iii in the summary chapter 3.6. This form also has a + * gcd(a-1,m) of 4 which is good according to principle iv. + * + * Is between 0.01 and 0.99 times the modulus as specified by + * principle iv. + * + * Passes the spectral test "with flying colors" (ut >= 1) in + * dimensions 2 through 6 as calculated by Algorithm S in Chapter + * 3.3.4 and the ratings calculated by formula 35 in section E. + * + * Of the multipliers that pass this test, pick the set that is + * best according to the theoretical bounds of the serial + * correlation test. This was calculated using a simplified + * version of Knuth's Theorem K in Chapter 3.3.3. + * + * These criteria may not be important for this use, but we might as well + * pick from the best generators since there are so many possible ones and + * we don't have that many random bits to do the picking. + * + * We use a modulus of 2^16 instead of something bigger so that we will + * tend to cycle through all the possible IDs before repeating any, + * however the shuffling will perturb this somewhat. Theoretically there + * is no minimimum interval between two uses of the same ID, but in + * practice it seems to be >64000. + * + * Our adaptatation of Algorithm B mixes the hash state which has + * captured various random events into the shuffler to perturb the + * sequence. + * + * One disadvantage of this algorithm is that if the generator parameters + * were to be guessed, it would be possible to mount a limited brute force + * attack on the ID space since the IDs are only shuffled within a limited + * range. + * + * The second algorithm uses the same random number generator to populate + * a pool of 65536 IDs. The hash state is used to pick an ID from a window + * of 4096 IDs in this pool, then the chosen ID is swapped with the ID + * at the beginning of the window and the window position is advanced. + * This means that the interval between uses of the ID will be no less + * than 65536-4096. The ID sequence in the pool will become more random + * over time. + * + * For both algorithms, two more linear congruential random number generators + * are selected. The ID from the first part of algorithm is used to seed + * the first of these generators, and its output is used to seed the second. + * The strategy is use these generators as 1 to 1 hashes to obfuscate the + * properties of the generator used in the first part of either algorithm. + * + * The first algorithm may be suitable for use in a client resolver since + * its memory requirements are fairly low and it's pretty random out of + * the box. It is somewhat succeptible to a limited brute force attack, + * so the second algorithm is probably preferable for a longer running + * program that issues a large number of queries and has time to randomize + * the pool. + */ + +#define NSID_SHUFFLE_TABLE_SIZE 100 /* Suggested by Knuth */ +/* + * Pick one of the next 4096 IDs in the pool. + * There is a tradeoff here between randomness and how often and ID is reused. + */ +#define NSID_LOOKAHEAD 4096 /* Must be a power of 2 */ +#define NSID_SHUFFLE_ONLY 1 /* algorithm 1 */ +#define NSID_USE_POOL 2 /* algorithm 2 */ + +/* + * Keep a running hash of various bits of data that we'll use to + * stir the ID pool or perturb the ID generator + */ +void +nsid_hash(u_char *data, size_t len) { + /* + * Hash function similar to the one we use for hashing names. + * We don't fold case or toss the upper bit here, though. + * This hash doesn't do much interesting when fed binary zeros, + * so there may be a better hash function. + * This function doesn't need to be very strong since we're + * only using it to stir the pool, but it should be reasonably + * fast. + */ + while (len-- > 0) { + HASHROTATE(nsid_hash_state); + nsid_hash_state += *data++; + } +} + +/* + * Table of good linear congruential multipliers for modulus 2^16 + * in order of increasing serial correlation bounds (so trim from + * the end). */ +static const u_int16_t nsid_multiplier_table[] = { + 17565, 25013, 11733, 19877, 23989, 23997, 24997, 25421, + 26781, 27413, 35901, 35917, 35973, 36229, 38317, 38437, + 39941, 40493, 41853, 46317, 50581, 51429, 53453, 53805, + 11317, 11789, 12045, 12413, 14277, 14821, 14917, 18989, + 19821, 23005, 23533, 23573, 23693, 27549, 27709, 28461, + 29365, 35605, 37693, 37757, 38309, 41285, 45261, 47061, + 47269, 48133, 48597, 50277, 50717, 50757, 50805, 51341, + 51413, 51581, 51597, 53445, 11493, 14229, 20365, 20653, + 23485, 25541, 27429, 29421, 30173, 35445, 35653, 36789, + 36797, 37109, 37157, 37669, 38661, 39773, 40397, 41837, + 41877, 45293, 47277, 47845, 49853, 51085, 51349, 54085, + 56933, 8877, 8973, 9885, 11365, 11813, 13581, 13589, + 13613, 14109, 14317, 15765, 15789, 16925, 17069, 17205, + 17621, 17941, 19077, 19381, 20245, 22845, 23733, 24869, + 25453, 27213, 28381, 28965, 29245, 29997, 30733, 30901, + 34877, 35485, 35613, 36133, 36661, 36917, 38597, 40285, + 40693, 41413, 41541, 41637, 42053, 42349, 45245, 45469, + 46493, 48205, 48613, 50861, 51861, 52877, 53933, 54397, + 55669, 56453, 56965, 58021, 7757, 7781, 8333, 9661, + 12229, 14373, 14453, 17549, 18141, 19085, 20773, 23701, + 24205, 24333, 25261, 25317, 27181, 30117, 30477, 34757, + 34885, 35565, 35885, 36541, 37957, 39733, 39813, 41157, + 41893, 42317, 46621, 48117, 48181, 49525, 55261, 55389, + 56845, 7045, 7749, 7965, 8469, 9133, 9549, 9789, + 10173, 11181, 11285, 12253, 13453, 13533, 13757, 14477, + 15053, 16901, 17213, 17269, 17525, 17629, 18605, 19013, + 19829, 19933, 20069, 20093, 23261, 23333, 24949, 25309, + 27613, 28453, 28709, 29301, 29541, 34165, 34413, 37301, + 37773, 38045, 38405, 41077, 41781, 41925, 42717, 44437, + 44525, 44613, 45933, 45941, 47077, 50077, 50893, 52117, + 5293, 55069, 55989, 58125, 59205, 6869, 14685, 15453, + 16821, 17045, 17613, 18437, 21029, 22773, 22909, 25445, + 25757, 26541, 30709, 30909, 31093, 31149, 37069, 37725, + 37925, 38949, 39637, 39701, 40765, 40861, 42965, 44813, + 45077, 45733, 47045, 50093, 52861, 52957, 54181, 56325, + 56365, 56381, 56877, 57013, 5741, 58101, 58669, 8613, + 10045, 10261, 10653, 10733, 11461, 12261, 14069, 15877, + 17757, 21165, 23885, 24701, 26429, 26645, 27925, 28765, + 29197, 30189, 31293, 39781, 39909, 40365, 41229, 41453, + 41653, 42165, 42365, 47421, 48029, 48085, 52773, 5573, + 57037, 57637, 58341, 58357, 58901, 6357, 7789, 9093, + 10125, 10709, 10765, 11957, 12469, 13437, 13509, 14773, + 15437, 15773, 17813, 18829, 19565, 20237, 23461, 23685, + 23725, 23941, 24877, 25461, 26405, 29509, 30285, 35181, + 37229, 37893, 38565, 40293, 44189, 44581, 45701, 47381, + 47589, 48557, 4941, 51069, 5165, 52797, 53149, 5341, + 56301, 56765, 58581, 59493, 59677, 6085, 6349, 8293, + 8501, 8517, 11597, 11709, 12589, 12693, 13517, 14909, + 17397, 18085, 21101, 21269, 22717, 25237, 25661, 29189, + 30101, 31397, 33933, 34213, 34661, 35533, 36493, 37309, + 40037, 4189, 42909, 44309, 44357, 44389, 4541, 45461, + 46445, 48237, 54149, 55301, 55853, 56621, 56717, 56901, + 5813, 58437, 12493, 15365, 15989, 17829, 18229, 19341, + 21013, 21357, 22925, 24885, 26053, 27581, 28221, 28485, + 30605, 30613, 30789, 35437, 36285, 37189, 3941, 41797, + 4269, 42901, 43293, 44645, 45221, 46893, 4893, 50301, + 50325, 5189, 52109, 53517, 54053, 54485, 5525, 55949, + 56973, 59069, 59421, 60733, 61253, 6421, 6701, 6709, + 7101, 8669, 15797, 19221, 19837, 20133, 20957, 21293, + 21461, 22461, 29085, 29861, 30869, 34973, 36469, 37565, + 38125, 38829, 39469, 40061, 40117, 44093, 47429, 48341, + 50597, 51757, 5541, 57629, 58405, 59621, 59693, 59701, + 61837, 7061, 10421, 11949, 15405, 20861, 25397, 25509, + 25893, 26037, 28629, 28869, 29605, 30213, 34205, 35637, + 36365, 37285, 3773, 39117, 4021, 41061, 42653, 44509, + 4461, 44829, 4725, 5125, 52269, 56469, 59085, 5917, + 60973, 8349, 17725, 18637, 19773, 20293, 21453, 22533, + 24285, 26333, 26997, 31501, 34541, 34805, 37509, 38477, + 41333, 44125, 46285, 46997, 47637, 48173, 4925, 50253, + 50381, 50917, 51205, 51325, 52165, 52229, 5253, 5269, + 53509, 56253, 56341, 5821, 58373, 60301, 61653, 61973, + 62373, 8397, 11981, 14341, 14509, 15077, 22261, 22429, + 24261, 28165, 28685, 30661, 34021, 34445, 39149, 3917, + 43013, 43317, 44053, 44101, 4533, 49541, 49981, 5277, + 54477, 56357, 57261, 57765, 58573, 59061, 60197, 61197, + 62189, 7725, 8477, 9565, 10229, 11437, 14613, 14709, + 16813, 20029, 20677, 31445, 3165, 31957, 3229, 33541, + 36645, 3805, 38973, 3965, 4029, 44293, 44557, 46245, + 48917, 4909, 51749, 53709, 55733, 56445, 5925, 6093, + 61053, 62637, 8661, 9109, 10821, 11389, 13813, 14325, + 15501, 16149, 18845, 22669, 26437, 29869, 31837, 33709, + 33973, 34173, 3677, 3877, 3981, 39885, 42117, 4421, + 44221, 44245, 44693, 46157, 47309, 5005, 51461, 52037, + 55333, 55693, 56277, 58949, 6205, 62141, 62469, 6293, + 10101, 12509, 14029, 17997, 20469, 21149, 25221, 27109, + 2773, 2877, 29405, 31493, 31645, 4077, 42005, 42077, + 42469, 42501, 44013, 48653, 49349, 4997, 50101, 55405, + 56957, 58037, 59429, 60749, 61797, 62381, 62837, 6605, + 10541, 23981, 24533, 2701, 27333, 27341, 31197, 33805, + 3621, 37381, 3749, 3829, 38533, 42613, 44381, 45901, + 48517, 51269, 57725, 59461, 60045, 62029, 13805, 14013, + 15461, 16069, 16157, 18573, 2309, 23501, 28645, 3077, + 31541, 36357, 36877, 3789, 39429, 39805, 47685, 47949, + 49413, 5485, 56757, 57549, 57805, 58317, 59549, 62213, + 62613, 62853, 62933, 8909, 12941, 16677, 20333, 21541, + 24429, 26077, 26421, 2885, 31269, 33381, 3661, 40925, + 42925, 45173, 4525, 4709, 53133, 55941, 57413, 57797, + 62125, 62237, 62733, 6773, 12317, 13197, 16533, 16933, + 18245, 2213, 2477, 29757, 33293, 35517, 40133, 40749, + 4661, 49941, 62757, 7853, 8149, 8573, 11029, 13421, + 21549, 22709, 22725, 24629, 2469, 26125, 2669, 34253, + 36709, 41013, 45597, 46637, 52285, 52333, 54685, 59013, + 60997, 61189, 61981, 62605, 62821, 7077, 7525, 8781, + 10861, 15277, 2205, 22077, 28517, 28949, 32109, 33493, + 3685, 39197, 39869, 42621, 44997, 48565, 5221, 57381, + 61749, 62317, 63245, 63381, 23149, 2549, 28661, 31653, + 33885, 36341, 37053, 39517, 42805, 45853, 48997, 59349, + 60053, 62509, 63069, 6525, 1893, 20181, 2365, 24893, + 27397, 31357, 32277, 33357, 34437, 36677, 37661, 43469, + 43917, 50997, 53869, 5653, 13221, 16741, 17893, 2157, + 28653, 31789, 35301, 35821, 61613, 62245, 12405, 14517, + 17453, 18421, 3149, 3205, 40341, 4109, 43941, 46869, + 48837, 50621, 57405, 60509, 62877, 8157, 12933, 12957, + 16501, 19533, 3461, 36829, 52357, 58189, 58293, 63053, + 17109, 1933, 32157, 37701, 59005, 61621, 13029, 15085, + 16493, 32317, 35093, 5061, 51557, 62221, 20765, 24613, + 2629, 30861, 33197, 33749, 35365, 37933, 40317, 48045, + 56229, 61157, 63797, 7917, 17965, 1917, 1973, 20301, + 2253, 33157, 58629, 59861, 61085, 63909, 8141, 9221, + 14757, 1581, 21637, 26557, 33869, 34285, 35733, 40933, + 42517, 43501, 53653, 61885, 63805, 7141, 21653, 54973, + 31189, 60061, 60341, 63357, 16045, 2053, 26069, 33997, + 43901, 54565, 63837, 8949, 17909, 18693, 32349, 33125, + 37293, 48821, 49053, 51309, 64037, 7117, 1445, 20405, + 23085, 26269, 26293, 27349, 32381, 33141, 34525, 36461, + 37581, 43525, 4357, 43877, 5069, 55197, 63965, 9845, + 12093, 2197, 2229, 32165, 33469, 40981, 42397, 8749, + 10853, 1453, 18069, 21693, 30573, 36261, 37421, 42533 +}; +#define NSID_MULT_TABLE_SIZE \ + ((sizeof nsid_multiplier_table)/(sizeof nsid_multiplier_table[0])) void -nsid_init() { - nsid_state = res_randomid(); +nsid_init(void) { + struct timeval now; + pid_t mypid; + u_int16_t a1ndx, a2ndx, a3ndx, c1ndx, c2ndx, c3ndx; + int i; + + if (nsid_algorithm != 0) + return; + + gettimeofday(&now, NULL); + mypid = getpid(); + + /* Initialize the state */ + nsid_hash_state = 0; + nsid_hash((u_char *)&now, sizeof now); + nsid_hash((u_char *)&mypid, sizeof mypid); + + /* + * Select our random number generators and initial seed. + * We could really use more random bits at this point, + * but we'll try to make a silk purse out of a sows ear ... + */ + /* generator 1 */ + a1ndx = ((u_long) NSID_MULT_TABLE_SIZE * + (nsid_hash_state & 0xFFFF)) >> 16; + nsid_a1 = nsid_multiplier_table[a1ndx]; + c1ndx = (nsid_hash_state >> 9) & 0x7FFF; + nsid_c1 = 2*c1ndx + 1; + /* generator 2, distinct from 1 */ + a2ndx = ((u_long) (NSID_MULT_TABLE_SIZE - 1) * + ((nsid_hash_state >> 10) & 0xFFFF)) >> 16; + if (a2ndx >= a1ndx) + a2ndx++; + nsid_a2 = nsid_multiplier_table[a2ndx]; + c2ndx = nsid_hash_state % 32767; + if (c2ndx >= c1ndx) + c2ndx++; + nsid_c2 = 2*c2ndx + 1; + /* generator 3, distinct from 1 and 2 */ + a3ndx = ((u_long) (NSID_MULT_TABLE_SIZE - 2) * + ((nsid_hash_state >> 20) & 0xFFFF)) >> 16; + if (a3ndx >= a1ndx || a3ndx >= a2ndx) + a3ndx++; + if (a3ndx >= a1ndx && a3ndx >= a2ndx) + a3ndx++; + nsid_a3 = nsid_multiplier_table[a3ndx]; + c3ndx = nsid_hash_state % 32766; + if (c3ndx >= c1ndx || c3ndx >= c2ndx) + c3ndx++; + if (c3ndx >= c1ndx && c3ndx >= c2ndx) + c3ndx++; + nsid_c3 = 2*c3ndx + 1; + + nsid_state = ((nsid_hash_state >> 16) ^ (nsid_hash_state)) & 0xFFFF; + + /* Do the algorithm specific initialization */ + INSIST(server_options != NULL); + if (NS_OPTION_P(OPTION_USE_ID_POOL) == 0) { + /* Algorithm 1 */ + nsid_algorithm = NSID_SHUFFLE_ONLY; + nsid_vtable = memget(NSID_SHUFFLE_TABLE_SIZE * + (sizeof(u_int16_t)) ); + if (!nsid_vtable) + ns_panic(ns_log_default, 1, "memget(nsid_vtable)", + NULL); + for (i = 0; i < NSID_SHUFFLE_TABLE_SIZE; i++) { + nsid_vtable[i] = nsid_state; + nsid_state = (((u_long) nsid_a1 * nsid_state) + nsid_c1) + & 0xFFFF; + } + nsid_state2 = nsid_state; + } else { + /* Algorithm 2 */ + nsid_algorithm = NSID_USE_POOL; + nsid_pool = memget(0x10000 * (sizeof(u_int16_t))); + if (!nsid_pool) + ns_panic(ns_log_default, 1, "memget(nsid_pool)", NULL); + for (i = 0; ; i++) { + nsid_pool[i] = nsid_state; + nsid_state = (((u_long) nsid_a1 * nsid_state) + nsid_c1) & 0xFFFF; + if (i == 0xFFFF) + break; + } + } } +#define NSID_RANGE_MASK (NSID_LOOKAHEAD - 1) + +#define NSID_POOL_MASK 0xFFFF /* used to wrap the pool index */ + u_int16_t nsid_next() { - if (nsid_state == 65535) - nsid_state = 0; - else - nsid_state++; - return (nsid_state); + u_int16_t id, compressed_hash; + + compressed_hash = ((nsid_hash_state >> 16) ^ (nsid_hash_state)) & + 0xFFFF; + if (nsid_algorithm == NSID_SHUFFLE_ONLY) { + u_int16_t j; + + /* + * This is the original Algorithm B + * j = ((u_long) NSID_SHUFFLE_TABLE_SIZE * nsid_state2) + * >> 16; + * + * We'll perturb it with some random stuff ... + */ + j = ((u_long) NSID_SHUFFLE_TABLE_SIZE * + (nsid_state2 ^ compressed_hash)) >> 16; + nsid_state2 = id = nsid_vtable[j]; + nsid_state = (((u_long) nsid_a1 * nsid_state) + nsid_c1) & + 0xFFFF; + nsid_vtable[j] = nsid_state; + } else if (nsid_algorithm == NSID_USE_POOL) { + u_int16_t pick; + + pick = compressed_hash & NSID_RANGE_MASK; + id = nsid_pool[(nsid_state + pick) & NSID_POOL_MASK]; + if (pick != 0) { + /* Swap two IDs to stir the pool */ + nsid_pool[(nsid_state + pick) & NSID_POOL_MASK] = + nsid_pool[nsid_state]; + nsid_pool[nsid_state] = id; + } + + /* increment the base pointer into the pool */ + if (nsid_state == 65535) + nsid_state = 0; + else + nsid_state++; + } else + ns_panic(ns_log_default, 1, "Unknown ID algorithm", NULL); + + /* Now lets obfuscate ... */ + id = (((u_long) nsid_a2 * id) + nsid_c2) & 0xFFFF; + id = (((u_long) nsid_a3 * id) + nsid_c3) & 0xFFFF; + + return (id); } +/* Note: this function CAN'T deallocate the saved_argv[]. */ static void deallocate_everything(void) { FILE *f; @@ -2010,6 +2495,7 @@ deallocate_everything(void) { free_addinfo(); ns_shutdown(); dq_remove_all(); + db_lame_destroy(); if (local_addresses != NULL) free_ip_match_list(local_addresses); if (local_networks != NULL) @@ -2020,12 +2506,23 @@ deallocate_everything(void) { evDestroy(ev); if (conffile != NULL) freestr(conffile); + conffile = NULL; + if (debugfile != NULL) + freestr(debugfile); + debugfile = NULL; if (user_name != NULL) freestr(user_name); + user_name = NULL; if (group_name != NULL) freestr(group_name); + group_name = NULL; if (chroot_dir != NULL) freestr(chroot_dir); + chroot_dir = NULL; + if (nsid_pool != NULL) + memput(nsid_pool, 0x10000 * (sizeof(u_int16_t))); + nsid_pool = NULL; + irs_destroy(); if (f != NULL) { memstats(f); (void)fclose(f); @@ -2034,7 +2531,12 @@ deallocate_everything(void) { static void ns_exit(void) { - ns_info(ns_log_default, "named shutting down"); + main_needs_exit++; +} + +static void +ns_restart(void) { + ns_info(ns_log_default, "named restarting"); #ifdef BIND_UPDATE dynamic_about_to_exit(); #endif @@ -2043,16 +2545,18 @@ ns_exit(void) { ns_logstats(ev, NULL, evNowTime(), evConsTime(0, 0)); if (NS_OPTION_P(OPTION_DEALLOC_ON_EXIT)) deallocate_everything(); - exit(0); + else + shutdown_configuration(); + execvp(saved_argv[0], saved_argv); + abort(); } static void use_desired_debug(void) { #ifdef DEBUG sigset_t set; - int bad; - /* protect against race conditions by blocking debugging signals */ + /* Protect against race conditions by blocking debugging signals. */ if (sigemptyset(&set) < 0) { ns_error(ns_log_os, @@ -2086,73 +2590,76 @@ use_desired_debug(void) { #endif } -static void +void toggle_qrylog(void) { qrylog = !qrylog; ns_notice(ns_log_default, "query log %s\n", qrylog ?"on" :"off"); } -#ifdef BIND_NOTIFY static void -do_notify_after_load(void) { - evDo(ev, (const void *)notify_after_load); +wild(void) { + ns_panic(ns_log_default, 1, "wild need", NULL); } -#endif - + /* * This is a functional interface to the global needs and options. */ -static const struct need_handler { - int need; - void (*handler)(void); - } need_handlers[] = { - { MAIN_NEED_RELOAD, ns_reload }, - { MAIN_NEED_MAINT, ns_maint }, - { MAIN_NEED_ENDXFER, endxfer }, - { MAIN_NEED_ZONELOAD, loadxfer }, - { MAIN_NEED_DUMP, doadump }, - { MAIN_NEED_STATSDUMP, ns_stats }, - { MAIN_NEED_EXIT, ns_exit }, - { MAIN_NEED_QRYLOG, toggle_qrylog }, - { MAIN_NEED_DEBUG, use_desired_debug }, -#ifdef BIND_NOTIFY - { MAIN_NEED_NOTIFY, do_notify_after_load }, -#endif - { 0, NULL } - }; +static void +init_needs(void) { + int need; + + for (need = 0; need < main_need_num; need++) + handlers[need] = wild; + handlers[main_need_zreload] = ns_zreload; + handlers[main_need_reload] = ns_reload; + handlers[main_need_reconfig] = ns_reconfig; + handlers[main_need_endxfer] = endxfer; + handlers[main_need_zoneload] = loadxfer; + handlers[main_need_dump] = doadump; + handlers[main_need_statsdump] = ns_stats; + handlers[main_need_exit] = ns_exit; + handlers[main_need_qrylog] = toggle_qrylog; + handlers[main_need_debug] = use_desired_debug; + handlers[main_need_restart] = ns_restart; + handlers[main_need_reap] = reapchild; +} -void -ns_setoption(int option) { - ns_warning(ns_log_default, "used obsolete ns_setoption(%d)", option); +static void +handle_need(void) { + int need; + + ns_debug(ns_log_default, 15, "handle_need()"); + for (need = 0; need < main_need_num; need++) + if ((needs & (1 << need)) != 0) { + /* Turn off flag first, handlers ~turn~ it back on. */ + block_signals(); + needs &= ~(1 << need); + unblock_signals(); + (handlers[need])(); + return; + } + ns_panic(ns_log_default, 1, "handle_need() found no needs", NULL); } void -ns_need(int need) { - needs |= need; +ns_need(enum need need) { + block_signals(); + ns_need_unsafe(need); + unblock_signals(); } -int -ns_need_p(int need) { - return ((needs & need) != 0); +/* Note: this function should only be called with signals blocked. */ +void +ns_need_unsafe(enum need need) { + needs |= (1 << need); } -static void -ns_handle_needs() { - const struct need_handler *nhp; - - for (nhp = need_handlers; nhp->need && nhp->handler; nhp++) { - if ((needs & nhp->need) != 0) { - /* - * Turn off flag first, handler might turn it back on. - */ - needs &= ~nhp->need; - (*nhp->handler)(); - } - } +void +ns_setoption(int option) { + ns_warning(ns_log_default, "used obsolete ns_setoption(%d)", option); } - void writestream(struct qstream *sp, const u_char *msg, int msglen) { if (sq_openw(sp, msglen + INT16SZ) == -1) { @@ -2166,45 +2673,6 @@ writestream(struct qstream *sp, const u_char *msg, int msglen) { sq_writeh(sp, sq_flushw); } -static void -set_signal_handler(int sig, SIG_FN (*handler)()) { - struct sigaction sa; - - memset(&sa, 0, sizeof sa); - sa.sa_handler = handler; - if (sigemptyset(&sa.sa_mask) < 0) { - ns_error(ns_log_os, - "sigemptyset failed in set_signal_handler(%d): %s", - sig, strerror(errno)); - return; - } - if (sigaction(sig, &sa, NULL) < 0) - ns_error(ns_log_os, - "sigaction failed in set_signal_handler(%d): %s", - sig, strerror(errno)); -} - -static void -init_signals() { - set_signal_handler(SIGINT, setdumpflg); - set_signal_handler(SIGILL, setstatsflg); -#ifdef DEBUG - set_signal_handler(SIGUSR1, setIncrDbgFlg); - set_signal_handler(SIGUSR2, setNoDbgFlg); -#endif - set_signal_handler(SIGHUP, onhup); -#if defined(SIGWINCH) && defined(QRYLOG) /* XXX */ - set_signal_handler(SIGWINCH, setQrylogFlg); -#endif - set_signal_handler(SIGCHLD, reapchild); - set_signal_handler(SIGPIPE, discard_pipe); - set_signal_handler(SIGTERM, onintr); -#if defined(SIGXFSZ) /* XXX */ - /* Wierd DEC Hesiodism, harmless. */ - set_signal_handler(SIGXFSZ, onhup); -#endif -} - static int only_digits(const char *s) { if (*s == '\0') @@ -2216,3 +2684,54 @@ only_digits(const char *s) { } return (1); } +#if defined(__GNUC__) && defined(__BOUNDS_CHECKING_ON) + /* Use bounds checking malloc, etc. */ +void * +memget(size_t len) { + return (malloc(len)); +} + +void +memput(void *addr, size_t len) { + free(addr); +} + +int +meminit(size_t init_max_size, size_t target_size) { + return (0); +} + +void * +memget_debug(size_t size, const char *file, int line) { + void *ptr; + ptr = __memget(size); + fprintf(stderr, "%s:%d: memget(%lu) -> %p\n", file, line, + (u_long)size, ptr); + return (ptr); +} + +void +memput_debug(void *ptr, size_t size, const char *file, int line) { + fprintf(stderr, "%s:%d: memput(%p, %lu)\n", file, line, ptr, + (u_long)size); + __memput(ptr, size); +} + +void +memstats(FILE *out) { + fputs("No memstats\n", out); +} +#endif + +#ifndef HAVE_CUSTOM +/* Standard implementation has nothing here */ +static void +custom_init(void) { + /* Noop. */ +} + +static void +custom_shutdown(void) { + /* Noop. */ +} +#endif diff --git a/contrib/bind/bin/named/ns_maint.c b/contrib/bind/bin/named/ns_maint.c index 75568ff..69a8fc3 100644 --- a/contrib/bind/bin/named/ns_maint.c +++ b/contrib/bind/bin/named/ns_maint.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_maint.c 4.39 (Berkeley) 3/2/91"; -static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $"; +static const char sccsid[] = "@(#)ns_maint.c 4.39 (Berkeley) 3/2/91"; +static const char rcsid[] = "$Id: ns_maint.c,v 8.95 1999/10/13 16:39:09 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -73,6 +73,26 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $"; * SOFTWARE. */ +/* + * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Check Point Software Technologies Incorporated not be used + * in advertising or publicity pertaining to distribution of the document + * or software without specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + #include "port_before.h" #include <sys/param.h> @@ -80,11 +100,13 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $"; #include <sys/socket.h> #include <sys/wait.h> #include <sys/stat.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> +#include <assert.h> #include <errno.h> #include <signal.h> #include <resolv.h> @@ -99,25 +121,25 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $"; #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" -static int xfers_running, /* # of xfers running */ - xfers_deferred, /* # of needed xfers not run yet */ - qserials_running, - nxfers(struct zoneinfo *, int), +static int nxfers(struct zoneinfo *, int), bottom_of_zone(struct databuf *, int); static void startxfer(struct zoneinfo *), abortxfer(struct zoneinfo *), - addxfer(struct zoneinfo *), tryxfer(void), purge_z_2(struct hashbuf *, int); -#define qserial_qfull() (qserials_running == MAXQSERIAL) +#ifndef HAVE_SPAWNXFER +static pid_t spawnxfer(char **, struct zoneinfo *); +#endif -static time_t stats_time; +static time_t stats_time; /* Redundant ??? XXX ogud */ /* State of all running zone transfers */ static struct { @@ -132,23 +154,6 @@ static struct { /* - * Perform maintenance on all zones that need it. - */ -void -ns_maint() { - struct zoneinfo *zp; - int zonenum, deleted; - - gettime(&tt); - - ns_debug(ns_log_maint, 1, "ns_maint()"); - - for (zp = zones, zonenum = 0; zp < &zones[nzones]; zp++, zonenum++) - zone_maint(zp); - ns_debug(ns_log_maint, 1, "exit ns_maint()"); -} - -/* * Perform routine zone maintenance. */ void @@ -173,10 +178,16 @@ zone_maint(struct zoneinfo *zp) { #endif if (zp->z_serial != 0 && ((zp->z_lastupdate+zp->z_expire) < (u_int32_t)tt.tv_sec)) { + /* calls purge_zone */ + do_reload(zp->z_origin, zp->z_type, zp->z_class, 0); + /* reset zone state */ + zp->z_flags &= ~Z_AUTH; + zp->z_refresh = INIT_REFRESH; + zp->z_retry = INIT_REFRESH; zp->z_serial = 0; - /* XXX should we clear Z_AUTH here? */ } - if (zp->z_flags & (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL)) { + if ((zp->z_flags & (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL)) != 0) + { ns_retrytime(zp, tt.tv_sec); break; } @@ -190,12 +201,26 @@ zone_maint(struct zoneinfo *zp) { zp->z_time = tt.tv_sec + 30; break; } - qserial_query(zp); + /* + * If we don't have the zone loaded or dialup is off + * or we attempted a qserial_query before and the queue was + * full attempt to verify / load the zone. + */ + if ((zp->z_serial == 0) || (zp->z_flags & Z_NEED_QSERIAL) || + (zp->z_dialup == zdialup_no) || + (zp->z_dialup == zdialup_use_default && + NS_OPTION_P(OPTION_NODIALUP))) + qserial_query(zp); + else { + ns_info(ns_log_default, "Suppressed qserial_query(%s)", + *(zp->z_origin) ? zp->z_origin : "."); + ns_refreshtime(zp, tt.tv_sec); + } break; #ifdef BIND_UPDATE case Z_PRIMARY: - if (! (zp->z_flags & Z_DYNAMIC)) + if ((zp->z_flags & Z_DYNAMIC) == 0) break; if (tt.tv_sec >= zp->z_soaincrtime && zp->z_soaincrintvl > 0 && @@ -214,7 +239,7 @@ zone_maint(struct zoneinfo *zp) { if (tt.tv_sec >= zp->z_dumptime && zp->z_dumpintvl > 0 && zp->z_flags & Z_NEED_DUMP) { - if (zonedump(zp) < 0) { + if (zonedump(zp, ISNOTIXFR) < 0) { /* Try again later. */ ns_error(ns_log_maint, "zone dump for '%s' failed, rescheduling", @@ -222,6 +247,8 @@ zone_maint(struct zoneinfo *zp) { zp->z_dumptime = 0; (void)schedule_dump(zp); } + if (zp->z_maintain_ixfr_base) + ixfr_log_maint(zp); } break; #endif /* BIND_UPDATE */ @@ -249,11 +276,18 @@ do_zone_maint(evContext ctx, void *uap, struct timespec due, ns_debug(ns_log_maint, 1, "do_zone_maint for zone %s (class %s)", zti->name, p_class(zti->class)); - zp = find_zone(zti->name, zti->type, zti->class); + zp = find_zone(zti->name, zti->class); if (zp == NULL) { ns_error(ns_log_maint, "do_zone_maint: %s zone '%s' (class %s) is not authoritative", - zoneTypeString(zp), zti->name, + zoneTypeString(zti->type), zti->name, + p_class(zti->class)); + return; + } + if (zp->z_type != zti->type) { + ns_error(ns_log_maint, + "do_zone_maint: %s zone '%s' (class %s) has changed its type", + zoneTypeString(zti->type), zti->name, p_class(zti->class)); return; } @@ -270,13 +304,12 @@ do_zone_maint(evContext ctx, void *uap, struct timespec due, void sched_zone_maint(struct zoneinfo *zp) { time_t next_maint = (time_t)0; - char *zone_name; ztimer_info zti; if (zp->z_time != 0) next_maint = zp->z_time; #ifdef BIND_UPDATE - if (zp->z_type == z_master && (zp->z_flags & Z_DYNAMIC)) { + if (zp->z_type == z_master && (zp->z_flags & Z_DYNAMIC) != 0) { if (zp->z_soaincrintvl > 0 && (next_maint == 0 || next_maint > zp->z_soaincrtime)) next_maint = zp->z_soaincrtime; @@ -363,10 +396,46 @@ ns_cleancache(evContext ctx, void *uap, gettime(&tt); INSIST(uap == NULL); deleted = clean_cache(hashtab, 0); - ns_info(ns_log_maint, "Cleaned cache of %d RR%s", + ns_info(ns_log_maint, "Cleaned cache of %d RRset%s", deleted, (deleted==1) ? "" : "s"); } +void +ns_heartbeat(evContext ctx, void *uap, struct timespec due, + struct timespec inter) +{ + struct zoneinfo *zp; + + gettime(&tt); + INSIST(uap == NULL); + + for (zp = zones; zp < &zones[nzones]; zp++) { + enum zonetype zt = zp->z_type; + + if ((zt == z_nil) || + (zp->z_dialup == zdialup_no) || + (zp->z_dialup == zdialup_use_default && + NS_OPTION_P(OPTION_NODIALUP))) + continue; +#ifdef BIND_NOTIFY + if ((zp->z_notify == znotify_no) || + ((zp->z_notify == znotify_use_default) && + NS_OPTION_P(OPTION_NONOTIFY))) + continue; +#endif + if ((zt == z_slave || zt == z_stub) && + (zp->z_flags & + (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL|Z_XFER_RUNNING) + ) == 0) { + ns_info(ns_log_default, + "Heartbeat: qserial \"%s\"", + *(zp->z_origin) ? zp->z_origin : "."); + qserial_query(zp); + } + } +} + + /* * Mark a zone "up to date" after named-xfer tells us this or we * discover it through the qserial_*() logic. @@ -418,57 +487,131 @@ qserial_query(struct zoneinfo *zp) { ns_debug(ns_log_default, 1, "qserial_query(%s)", zp->z_origin); - if (qserial_qfull()) { + if (qserials_running >= server_options->serial_queries) { qserial_retrytime(zp, tt.tv_sec); + zp->z_flags |= Z_NEED_QSERIAL; return; } qp = sysquery(zp->z_origin, zp->z_class, T_SOA, - zp->z_addr, zp->z_addrcnt, QUERY); - if (!qp) { - ns_info(ns_log_default, "qserial_query(%s): sysquery FAILED", - zp->z_origin); + zp->z_addr, zp->z_addrcnt, + ntohs(zp->z_port) ? zp->z_port : ns_port, + QUERY); + if (qp == NULL) { + ns_debug(ns_log_default, 1, + "qserial_query(%s): sysquery FAILED", + zp->z_origin); /* XXX - this is bad, we should do something */ qserial_retrytime(zp, tt.tv_sec); + zp->z_flags |= Z_NEED_QSERIAL; return; } qp->q_flags |= Q_ZSERIAL; qp->q_zquery = zp; zp->z_flags |= Z_QSERIAL; - zp->z_xaddr = inaddr_any; + zp->z_flags &= ~Z_NEED_QSERIAL; + zp->z_xaddrcnt = 0; ns_refreshtime(zp, tt.tv_sec); qserials_running++; ns_debug(ns_log_default, 1, "qserial_query(%s) QUEUED", zp->z_origin); } +static int +qserv_compare(const void *a, const void *b) { + const struct qserv *qs1 = a, *qs2 = b; + u_int32_t s1 = qs1->serial, s2 = qs2->serial; + + /* Note that we sort the "best" serial numbers to the front. */ + if (s1 == s2) + return (0); + if (s1 == 0) + return (-1); + if (s2 == 0) + return (1); + if (!SEQ_GT(s1, s2)) + return (1); + assert(SEQ_GT(s1, s2)); + return (-1); +} + void -qserial_answer(struct qinfo *qp, u_int32_t serial, struct sockaddr_in from) { +qserial_answer(struct qinfo *qp) { struct zoneinfo *zp = qp->q_zquery; + struct qserv *qs = NULL; + u_int32_t serial = 0; + int n, cnt = 0; - ns_debug(ns_log_default, 1, "qserial_answer(%s, %u)", zp->z_origin, - serial); + /* Take this query out of the global quotas. */ zp->z_flags &= ~Z_QSERIAL; qp->q_flags &= ~Q_ZSERIAL; /* keeps us from being called twice */ qserials_running--; + + /* Find best serial among those returned. */ + for (n = 0; n < qp->q_naddr; n++) { + qs = &qp->q_addr[n]; + ns_debug(ns_log_default, 1, "qserial_answer(%s): [%s] -> %lu", + zp->z_origin, inet_ntoa(qs->ns_addr.sin_addr), + qs->serial); + /* Don't consider serials which weren't set by a response. */ + if (qs->serial == 0) + continue; + /* Count valid answers. */ + cnt++; + /* Remove from consideration serials which aren't "better." */ + if (zp->z_serial != 0 && !SEQ_GT(qs->serial, zp->z_serial)) { + if (serial == 0 && qs->serial == zp->z_serial) + serial = qs->serial; + + if (qs->serial != zp->z_serial) + ns_notice(ns_log_xfer_in, + "Zone \"%s\" (%s) SOA serial# (%lu) rcvd from [%s] is < ours (%lu)%s", + zp->z_origin, p_class(zp->z_class), + qs->serial, + inet_ntoa(qs->ns_addr.sin_addr), + zp->z_serial, qp->q_naddr != 1 ? + ": skipping" : ""); + qs->serial = 0; + continue; + } + if (serial == 0 || SEQ_GT(qs->serial, serial)) + serial = qs->serial; + } + + /* If we have an existing serial number, then sort by "better." */ + if (zp->z_serial != 0) { + qsort(qp->q_addr, qp->q_naddr, sizeof(struct qserv), + qserv_compare); + for (n = 0; n < qp->q_naddr; n++) { + qs = &qp->q_addr[n]; + ns_debug(ns_log_default, 1, + "qserial_answer after sort: [%s] -> %lu", + inet_ntoa(qs->ns_addr.sin_addr), + qs->serial); + } + } + + /* Now see about kicking off an inbound transfer. */ if (serial == 0) { - /* An error occurred, or the query timed out. */ - ns_info(ns_log_default, "Err/TO getting serial# for \"%s\"", - zp->z_origin); + /* An error occurred, or the all queries timed out. */ + if (qp->q_naddr != cnt) + ns_info(ns_log_xfer_in, + "Err/TO getting serial# for \"%s\"", + zp->z_origin); addxfer(zp); - } else if (SEQ_GT(serial, zp->z_serial) || !zp->z_serial) { - ns_debug(ns_log_default, 1, + } else if (zp->z_serial == 0 || SEQ_GT(serial, zp->z_serial)) { + ns_debug(ns_log_xfer_in, 1, "qserial_answer: zone is out of date"); - zp->z_xaddr = from.sin_addr; /* don't use qp->q_from */ - addxfer(zp); - } else if (SEQ_GT(zp->z_serial, serial)) { - if (!haveComplained((u_long)zp, (u_long)"went backward")) { - ns_notice(ns_log_default, - "Zone \"%s\" (class %d) SOA serial# (%u) rcvd from [%s] is < ours (%u)", - zp->z_origin, zp->z_class, serial, - inet_ntoa(from.sin_addr), zp->z_serial); + /* Use all servers whose serials are better than ours. */ + zp->z_xaddrcnt = 0; + for (n = 0; n < qp->q_naddr; n++) { + qs = &qp->q_addr[n]; + if (qs->serial != 0) + zp->z_xaddr[zp->z_xaddrcnt++] = + qs->ns_addr.sin_addr; } - } else { - ns_debug(ns_log_default, 1, + addxfer(zp); + } else if (zp->z_serial == serial) { + ns_debug(ns_log_xfer_in, 1, "qserial_answer: zone serial is still OK"); markUpToDate(zp); sched_zone_maint(zp); @@ -476,34 +619,86 @@ qserial_answer(struct qinfo *qp, u_int32_t serial, struct sockaddr_in from) { } /* - * Start an asynchronous zone transfer for a zone. - * Depends on current time being in tt. - * Caller must do sched_zone_maint(zp) after startxfer returns. + * Writes TSIG key info for an address to a file, optionally opening it first. + */ +static int +write_tsig_info(struct in_addr addr, char *name, int *fd, int creat_failed) { + server_info si; + DST_KEY *dst_key; + int tsig_fd = *fd; + char tsig_str[1024], secret_buf64[172]; + u_char secret_buf[128]; + int secret_len; + + si = find_server(addr); + if (si == NULL || si->key_list == NULL || si->key_list->first == NULL) + return(0); + dst_key = si->key_list->first->key; + if (tsig_fd < 0 && creat_failed == 0) { + *fd = tsig_fd = creat(name, S_IRUSR); + if (tsig_fd < 0) { + ns_warning(ns_log_default, + "write_tsig_info: creat(%s) for TSIG info failed", + name); + return(-1); + } + } + if (creat_failed != 0) + return(-1); + memset(secret_buf, 0, sizeof(secret_buf)); + secret_len = dst_key_to_buffer(dst_key, secret_buf, sizeof(secret_buf)); + b64_ntop(secret_buf, secret_len, secret_buf64, sizeof(secret_buf64)); + sprintf(tsig_str, "%s\n%s\n%d\n%s\n", + inet_ntoa(addr), dst_key->dk_key_name, dst_key->dk_alg, + secret_buf64); + write(tsig_fd, tsig_str, strlen(tsig_str)); + return (0); +} + +/* + * Start an asynchronous zone transfer for a zone. Depends on current time + * being in tt. Caller must do a sched_zone_maint(zp) after we return. */ static void startxfer(struct zoneinfo *zp) { - char *argv[NSMAX + 20], argv_ns[NSMAX][MAXDNAME]; - int argc = 0, argc_ns = 0, pid, i; + char *argv[NSMAX*2 + 20], argv_ns[NSMAX][MAXDNAME]; + int argc = 0, argc_ns = 0, i; + pid_t pid; u_int cnt; char debug_str[10]; char serial_str[10]; char port_str[10]; char class_str[10]; char src_str[20]; + int tsig_fd = -1; + char tsig_name[MAXPATHLEN+1], *s; + int tsig_ret = 0; - ns_debug(ns_log_default, 1, "startxfer() %s", zp->z_origin); + ns_debug(ns_log_default, 1, "startxfer() %s", + zp->z_origin[0] != '\0' ? zp->z_origin : "."); argv[argc++] = server_options->named_xfer; argv[argc++] = "-z"; argv[argc++] = zp->z_origin; argv[argc++] = "-f"; argv[argc++] = zp->z_source; - argv[argc++] = "-s"; - sprintf(serial_str, "%u", zp->z_serial); - argv[argc++] = serial_str; - if (zp->z_axfr_src.s_addr != 0) { +#ifdef BIND_IXFR + if (zp->z_ixfr_tmp) { + argv[argc++] = "-i"; + argv[argc++] = zp->z_ixfr_tmp; + } +#endif + if (zp->z_serial != 0) { + argv[argc++] = "-s"; + sprintf(serial_str, "%u", zp->z_serial); + argv[argc++] = serial_str; + } + if (zp->z_axfr_src.s_addr != 0 || + server_options->axfr_src.s_addr != 0) { argv[argc++] = "-x"; - argv[argc++] = strcpy(src_str, inet_ntoa(zp->z_axfr_src)); + argv[argc++] = strcpy(src_str, inet_ntoa( + (zp->z_axfr_src.s_addr != 0) ? zp->z_axfr_src : + server_options->axfr_src)); } argv[argc++] = "-C"; sprintf(class_str, "%d", zp->z_class); @@ -511,8 +706,14 @@ startxfer(struct zoneinfo *zp) { if (zp->z_flags & Z_SYSLOGGED) argv[argc++] = "-q"; argv[argc++] = "-P"; - sprintf(port_str, "%d", ns_port); + sprintf(port_str, "%d", ntohs(zp->z_port) != 0 ? zp->z_port : ns_port); argv[argc++] = port_str; + argv[argc++] = "-T"; + sprintf(tsig_name, "%s.%d", zp->z_origin, getpid()); + s = tsig_name; + while ((s = strchr(s, '/')) != NULL) + *s = '_'; + argv[argc++] = tsig_name; #ifdef STUBS if (zp->z_type == Z_STUB) argv[argc++] = "-S"; @@ -531,40 +732,45 @@ startxfer(struct zoneinfo *zp) { } #endif - if (ina_hlong(zp->z_xaddr) != INADDR_ANY) { - /* - * Address was specified by the qserial logic, use it - * first. - */ - if (aIsUs(zp->z_xaddr) && - !haveComplained((u_long)zp, (u_long)startxfer)) { - ns_notice(ns_log_default, - "attempted to fetch zone %s from self (%s)", - zp->z_origin, inet_ntoa(zp->z_xaddr)); - } else - argv[argc++] = strcpy(argv_ns[argc_ns++], - inet_ntoa(zp->z_xaddr)); + if (zp->z_xaddrcnt == 0) { + for (zp->z_xaddrcnt = 0; + zp->z_xaddrcnt < zp->z_addrcnt; + zp->z_xaddrcnt++) + zp->z_xaddr[zp->z_xaddrcnt] = + zp->z_addr[zp->z_xaddrcnt]; } /* * Copy the server ip addresses into argv, after converting - * to ascii and saving the static inet_ntoa result. Skip zp->z_xaddr - * if seen. + * to ascii and saving the static inet_ntoa result. + * Also, send TSIG key info into a file for the child. */ - for (cnt = 0; cnt < zp->z_addrcnt; cnt++) { + for (cnt = 0; cnt < zp->z_xaddrcnt; cnt++) { struct in_addr a; - a = zp->z_addr[cnt]; - if (ina_equal(a, zp->z_xaddr)) - continue; - if (aIsUs(a) && - !haveComplained((u_long)zp, (u_long)startxfer)) { - ns_notice(ns_log_default, - "attempted to fetch zone %s from self (%s)", - zp->z_origin, inet_ntoa(a)); + a = zp->z_xaddr[cnt]; + if (aIsUs(a) && ns_port == zp->z_port) { + if (!haveComplained((u_long)zp, (u_long)startxfer)) + ns_notice(ns_log_default, + "attempted to fetch zone %s from self (%s)", + zp->z_origin, inet_ntoa(a)); continue; } argv[argc++] = strcpy(argv_ns[argc_ns++], inet_ntoa(a)); +#ifdef BIND_IXFR + if (zp->z_ixfr_tmp != NULL) { + server_info si = find_server(a); + + if (si != NULL && + (si->flags & SERVER_INFO_SUPPORT_IXFR) != 0) + argv[argc++] = "ixfr"; + else + argv[argc++] = "axfr"; + } +#endif + tsig_ret = write_tsig_info(a, tsig_name, &tsig_fd, tsig_ret); } + if (tsig_fd > 0) + close(tsig_fd); argv[argc] = NULL; @@ -594,26 +800,21 @@ startxfer(struct zoneinfo *zp) { #endif /* DEBUG */ gettime(&tt); - for (i = 0; i < MAX_XFERS_RUNNING; i++) { - if (xferstatus[i].xfer_pid == 0) { - xferstatus[i].xfer_state = XFER_RUNNING; + for (i = 0; i < MAX_XFERS_RUNNING; i++) + if (xferstatus[i].xfer_pid == 0) break; - } - } - if ((pid = vfork()) == -1) { - ns_error(ns_log_default, "xfer vfork: %s", strerror(errno)); + if (i == MAX_XFERS_RUNNING) { + ns_warning(ns_log_default, + "startxfer: too many xfers running"); zp->z_time = tt.tv_sec + 10; + (void)nxfers(zp, -1); return; } - - if (pid == 0) { - /* Child. */ - execv(server_options->named_xfer, argv); - ns_error(ns_log_default, "can't exec %s: %s", - server_options->named_xfer, strerror(errno)); - _exit(XFER_FAIL); /* Avoid duplicate buffer flushes. */ - } - /* Parent. */ + + if ((pid = spawnxfer(argv, zp)) == -1) + unlink(tsig_name); + + xferstatus[i].xfer_state = XFER_RUNNING; xferstatus[i].xfer_pid = pid; /* XXX - small race condition here if we * can't hold signals */ ns_debug(ns_log_default, 1, "started xfer child %d", pid); @@ -628,18 +829,20 @@ startxfer(struct zoneinfo *zp) { } const char * -zoneTypeString(const struct zoneinfo *zp) { +zoneTypeString(u_int type) { static char ret[sizeof "(4294967296?)"]; /* 2^32 */ - switch (zp->z_type) { + switch (type) { case Z_MASTER: return ("master"); case Z_SLAVE: return ("slave"); #ifdef STUBS case Z_STUB: return ("stub"); #endif + case Z_HINT: return ("hint"); case Z_CACHE: return ("cache"); + case Z_FORWARD: return ("forward"); default: - sprintf(ret, "(%u?)", (u_int32_t)zp->z_type); + sprintf(ret, "(%u?)", type); return (ret); } } @@ -660,7 +863,7 @@ printzoneinfo(int zonenum, int category, int level) { ns_debug(category, level, "zone %d: %s, class %s, type %s", zonenum, zp->z_origin[0] ? zp->z_origin : ".", - p_class(zp->z_class), zoneTypeString(zp)); + p_class(zp->z_class), zoneTypeString(zp->z_type)); if (zp->z_source) ns_debug(category, level, "\tsource %s", zp->z_source); ns_debug(category, level, "\tflags %lx, serial %u, minimum %u", @@ -674,7 +877,7 @@ printzoneinfo(int zonenum, int category, int level) { else ns_debug(category, level, "\tz_time %lu", zp->z_time); #ifdef BIND_UPDATE - if (zp->z_type == z_master && zp->z_flags & Z_DYNAMIC) { + if (zp->z_type == z_master && (zp->z_flags & Z_DYNAMIC) != 0) { ns_debug(category, level, "\tdumpintvl %lu, soaincrintvl %lu deferupdcnt %lu", zp->z_dumpintvl, zp->z_soaincrintvl, @@ -700,13 +903,58 @@ printzoneinfo(int zonenum, int category, int level) { } #endif /* DEBUG */ +/* + * Remove all cached data below dname, class independent. + */ +void +clean_cache_from(char *dname, struct hashbuf *htp) { + const char *fname; + struct databuf *dp, *pdp; + struct namebuf *np; + struct hashbuf *phtp = htp; + int root_zone = 0; + + ns_debug(ns_log_default, 1, "clean_cache_from(%s)", dname); + if ((np = nlookup(dname, &phtp, &fname, 0)) && dname == fname && + !ns_wildcard(NAME(*np))) { + for (pdp = NULL, dp = np->n_data; dp != NULL; (void)NULL) { + if (dp->d_zone == DB_Z_CACHE) + dp = rm_datum(dp, np, pdp, NULL); + else { + pdp = dp; + dp = dp->d_next; + } + } + + if (*dname == '\0') + root_zone = 1; + + if (np->n_hash != NULL || root_zone) { + struct hashbuf *h; + + if (root_zone) + h = htp; + else + h = np->n_hash; + (void)clean_cache(h, 1); + if (h->h_cnt == 0 && !root_zone) { + rm_hash(np->n_hash); + np->n_hash = NULL; + } + } + + if (!root_zone && np->n_hash == NULL && np->n_data == NULL) + (void) purge_node(htp, np); + } +} + /* clean_cache(htp, all) * Scan the entire cache looking for expired TTL's on nonauthoritative * data, and remove it. if `all' is true, ignore TTL and rm everything. * notes: * this should be lazy and eventlib driven. * return: - * number of deleted RRs. + * number of deleted RRs (all=1) or RRsets (all=0). */ int clean_cache(struct hashbuf *htp, int all) { @@ -718,12 +966,17 @@ clean_cache(struct hashbuf *htp, int all) { nppend = htp->h_tab + htp->h_size; for (npp = htp->h_tab; npp < nppend; npp++) { for (pnp = NULL, np = *npp; np != NULL; np = npn) { + again: for (pdp = NULL, dp = np->n_data; dp != NULL; (void)NULL) { - if (dp->d_zone == DB_Z_CACHE && - (stale(dp) || all)) { + if (all && dp->d_zone == DB_Z_CACHE) { dp = rm_datum(dp, np, pdp, NULL); deleted++; + } else if (dp->d_zone == DB_Z_CACHE && + stale(dp)) { + delete_all(np, dp->d_class, dp->d_type); + deleted++; + goto again; } else { pdp = dp; dp = dp->d_next; @@ -753,6 +1006,78 @@ clean_cache(struct hashbuf *htp, int all) { return (deleted); } +/* struct namebuf * + * purge_node(htp, np) + * Remove entry from cache. + * Prerequisites: + * Node is empty and has no children. + * Paramters: + * htp - root of recursive hash table this node is part of. + * np - the node to be deleted. + * Return: + * pointer to parent. + */ +struct namebuf * +purge_node(struct hashbuf *htp, struct namebuf *np) { + struct namebuf **npp, **nppend; + struct namebuf *npn, *pnp, *nnp, *parent; + struct hashbuf *phtp; + + ns_debug(ns_log_default, 3, "purge_node: cleaning cache"); + INSIST(np->n_hash == NULL && np->n_data == NULL); + + /* Walk parent hashtable looking for ourself. */ + parent = np->n_parent; + if (parent != NULL) + phtp = parent->n_hash; + else + phtp = htp; + + if (phtp == NULL) { + /* XXX why shouldn't we panic? */ + } else { + nppend = phtp->h_tab + phtp->h_size; + for (npp = phtp->h_tab; npp < nppend; npp++) { + for (pnp = NULL, nnp = *npp; nnp != NULL; nnp = npn) { + if (nnp == np) { + ns_debug(ns_log_default, 3, + "purge_node: found ourself"); + npn = rm_name(nnp, npp, pnp); + phtp->h_cnt--; + } else { + npn = nnp->n_next; + pnp = nnp; + } + } + } + } + return (parent); +} + +void +remove_zone(struct zoneinfo *zp, const char *verb) { +#ifdef BIND_UPDATE + /* + * A dynamic zone might have changed, so we + * need to dump it before removing it. + */ + if ((zp->z_flags & Z_DYNAMIC) != 0 && + ((zp->z_flags & Z_NEED_SOAUPDATE) != 0 || + (zp->z_flags & Z_NEED_DUMP) != 0)) + (void) zonedump(zp, ISNOTIXFR); +#endif + ns_stopxfrs(zp); + do_reload(zp->z_origin, zp->z_type, zp->z_class, 1); + ns_notice(ns_log_config, "%s zone \"%s\" (%s) %s", + zoneTypeString(zp->z_type), zp->z_origin, + p_class(zp->z_class), verb); + free_zone_contents(zp, 1); + memset(zp, 0, sizeof(*zp)); + zp->z_type = z_nil; /* Pedantic; memset() did it. */ + INIT_LINK(zp, z_reloadlink); + free_zone(zp); +} + void purge_zone(const char *dname, struct hashbuf *htp, int class) { const char *fname; @@ -783,7 +1108,6 @@ purge_zone(const char *dname, struct hashbuf *htp, int class) { h = htp; else h = np->n_hash; - purge_z_2(h, class); if (h->h_cnt == 0 && !root_zone) { rm_hash(np->n_hash); @@ -791,39 +1115,8 @@ purge_zone(const char *dname, struct hashbuf *htp, int class) { } } - /* remove entry from cache, if required */ - if (np->n_hash == NULL && np->n_data == NULL) { - struct namebuf **npp, **nppend; - struct namebuf *npn, *pnp, *nnp; - - ns_debug(ns_log_default, 3, - "purge_zone: cleaning cache"); - - /* Walk parent hashtable looking for ourself. */ - if (np->n_parent) - phtp = np->n_parent->n_hash; - else - phtp = htp; /* top / root zone */ - - if (phtp) { - nppend = phtp->h_tab + phtp->h_size; - for (npp = phtp->h_tab; npp < nppend; npp++) { - for (pnp = NULL, nnp = *npp; - nnp != NULL; - nnp = npn) { - if (nnp == np) { - ns_debug(ns_log_default, 3, - "purge_zone: found our selves"); - npn = rm_name(nnp,npp,pnp); - phtp->h_cnt--; - } else { - npn = nnp->n_next; - pnp = nnp; - } - } - } - } - } + if (!root_zone && np->n_hash == NULL && np->n_data == NULL) + (void) purge_node(htp, np); } } @@ -903,12 +1196,12 @@ nxfers(struct zoneinfo *zp, int delta) { struct nameser *nsp; int ret; - if (ina_hlong(zp->z_xaddr) != INADDR_ANY) - nsa = zp->z_xaddr; /* qserial overrode address */ - else if (!zp->z_addrcnt) - return (-1); - else + if (zp->z_xaddrcnt != 0) + nsa = zp->z_xaddr[0]; /* first ns holds zone's xfer limit */ + else if (zp->z_addrcnt != 0) nsa = zp->z_addr[0]; /* first ns holds zone's xfer limit */ + else + return (-1); if (!(nsp = nameserFind(nsa, NS_F_INSERT))) return (-1); /* probably ENOMEM */ @@ -976,27 +1269,25 @@ pid %lu - forgetting, processes may accumulate", } /* - * SIGCHLD signal handler: process exit of xfer's. + * Process exit of xfer's. */ void -reapchild(evContext ctx, void *uap, int sig) { - int pid, i; +reapchild(void) { + int i; + pid_t pid; WAIT_T status; - int saved_errno = errno; gettime(&tt); - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { + while ((pid = (pid_t)waitpid(-1, &status, WNOHANG)) > 0) { for (i = 0; i < MAX_XFERS_RUNNING; i++) { if (xferstatus[i].xfer_pid == pid) { xferstatus[i].xfer_status = status; xferstatus[i].xfer_state = XFER_DONE; - ns_need(MAIN_NEED_ENDXFER); + ns_need(main_need_endxfer); break; } } } - - errno = saved_errno; } /* @@ -1005,7 +1296,8 @@ reapchild(evContext ctx, void *uap, int sig) { void endxfer() { struct zoneinfo *zp; - int exitstatus, pid, i; + int exitstatus, i; + pid_t pid; WAIT_T status; gettime(&tt); @@ -1045,11 +1337,43 @@ endxfer() { sched_zone_maint(zp); break; - case XFER_SUCCESS: + case XFER_SUCCESSAXFR: + case XFER_SUCCESSAXFRIXFRFILE: + zp->z_xferpid = XFER_ISAXFR; + if (exitstatus == XFER_SUCCESSAXFRIXFRFILE) { + zp->z_xferpid = XFER_ISAXFRIXFR; + } + movefile(zp->z_ixfr_tmp, zp->z_source); /* XXX should incorporate loadxfer() */ zp->z_flags |= Z_NEED_RELOAD; zp->z_flags &= ~Z_SYSLOGGED; - ns_need(MAIN_NEED_ZONELOAD); + ns_need(main_need_zoneload); + break; + + case XFER_SUCCESSIXFR: + zp->z_xferpid = XFER_ISIXFR; + zp->z_log_size_ixfr++; + ns_notice(ns_log_default, + "IXFR Success %s", + zp->z_ixfr_tmp); + if (merge_logs(zp, zp->z_ixfr_tmp) >= 0) { + ns_notice(ns_log_default, + "IXFR Merge success %s", + zp->z_ixfr_tmp); + + (void)unlink(zp->z_updatelog); + (void)unlink(zp->z_ixfr_base); + movefile(zp->z_ixfr_tmp, + zp->z_ixfr_base); + (void)unlink(zp->z_ixfr_tmp); + if (zonedump(zp, ISIXFR) < 0) + ns_warning(ns_log_db, + "error in write ixfr updates to zone file %s", + zp ->z_source); + } else + ns_notice(ns_log_default, + "IXFR Merge failed %s", + zp->z_ixfr_tmp); break; case XFER_TIMEOUT: @@ -1157,8 +1481,11 @@ tryxfer() { * Reload zones whose transfers have completed. */ void -loadxfer() { +loadxfer(void) { struct zoneinfo *zp; + u_int32_t old_serial,new_serial; + char *tmpnom; + int isixfr; gettime(&tt); for (zp = zones; zp < &zones[nzones]; zp++) { @@ -1166,11 +1493,35 @@ loadxfer() { ns_debug(ns_log_default, 1, "loadxfer() \"%s\"", zp->z_origin[0] ? zp->z_origin : "."); zp->z_flags &= ~(Z_NEED_RELOAD|Z_AUTH); -/* XXX this is bad, should be done in ns_reload() for primary changes. */ +/* XXX this is bad, should be done in ns_zreload() for primary changes. */ ns_stopxfrs(zp); - purge_zone(zp->z_origin, hashtab, zp->z_class); - if (!db_load(zp->z_source, zp->z_origin, zp, NULL)) + old_serial = zp->z_serial; + if (zp->z_xferpid == XFER_ISIXFR) { + tmpnom = zp->z_ixfr_tmp; + isixfr = ISIXFR; + } else { + tmpnom = zp->z_source; + purge_zone(zp->z_origin, hashtab, zp->z_class); + isixfr = ISNOTIXFR; + } + if (zp->z_xferpid == XFER_ISAXFRIXFR) { + tmpnom= zp->z_source; + purge_zone(zp->z_origin, hashtab, zp->z_class); + isixfr = ISNOTIXFR; + } + + if (!db_load(tmpnom, zp->z_origin, zp, NULL, isixfr)) { zp->z_flags |= Z_AUTH; + if (isixfr == ISIXFR) { + new_serial= zp ->z_serial; + ns_warning(ns_log_db, "ISIXFR"); + ns_warning(ns_log_db, "error in updating ixfr data base file %s from %s", zp -> z_ixfr_base, zp ->z_ixfr_tmp); + if (zonedump(zp,ISIXFR)<0) + ns_warning(ns_log_db, "error in write ixfr updates to zone file %s", zp ->z_source); + + } + } + zp->z_xferpid = 0; if (zp->z_flags & Z_TMP_FILE) (void) unlink(zp->z_source); sched_zone_maint(zp); @@ -1181,7 +1532,7 @@ loadxfer() { /* * Add this zone to the set of those needing transfers. */ -static void +void addxfer(struct zoneinfo *zp) { if (!(zp->z_flags & Z_NEED_XFER)) { zp->z_flags |= Z_NEED_XFER; @@ -1191,21 +1542,203 @@ addxfer(struct zoneinfo *zp) { } /* - * Flush and reload data base. + * Mark one zone as requiring a reload. + * Note that it should be called with signals blocked, + * and should not allocate memory (since it can be called from a sighandler). + */ +const char * +deferred_reload_unsafe(struct zoneinfo *zp) { + INSIST(zp->z_type != z_nil); + if (!zonefile_changed_p(zp)) + return ("Zone file has not changed."); + if (LINKED(zp, z_reloadlink)) + return ("Zone is already scheduled for reloading."); + APPEND(reloadingzones, zp, z_reloadlink); + ns_need_unsafe(main_need_zreload); + return ("Zone is now scheduled for reloading."); +} + +/* + * If we've loaded this file, and the file has not been modified and contains + * no $INCLUDE, then there's no need to reload. + */ +int +zonefile_changed_p(struct zoneinfo *zp) { + struct stat sb; + + INSIST(zp->z_type != z_nil); + return ((zp->z_flags & Z_INCLUDE) != 0 || + stat(zp->z_source, &sb) == -1 || + zp->z_ftime != sb.st_mtime); +} + +int +reload_master(struct zoneinfo *zp) { + INSIST(zp->z_type == z_master); + zp->z_flags &= ~Z_AUTH; + ns_stopxfrs(zp); + /* XXX what about parent zones? */ + purge_zone(zp->z_origin, hashtab, zp->z_class); + ns_debug(ns_log_config, 1, "reloading zone"); +#ifdef BIND_UPDATE + if ((zp->z_flags & Z_DYNAMIC) != 0) { + struct stat sb; + + if (stat(zp->z_source, &sb) < 0) + ns_error(ns_log_config, "stat(%s) failed: %s", + zp->z_source, strerror(errno)); + else { + if ((sb.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) != 0) + ns_warning(ns_log_config, + "dynamic zone file '%s' is writable", + zp->z_source); + } + } +#endif + if (!db_load(zp->z_source, zp->z_origin, zp, NULL, ISNOTIXFR)) + zp->z_flags |= Z_AUTH; + zp->z_refresh = 0; /* no maintenance needed */ + zp->z_time = 0; +#ifdef BIND_UPDATE + zp->z_lastupdate = 0; + if ((zp->z_flags & Z_DYNAMIC) != 0) + if (merge_logs(zp, zp->z_updatelog) == 1) + return (1); +#endif + return (0); +} + +/* + * Called by main() when main_need_zreload has been set. Should pull one + * zone off of the reloadingzones list and reload it, then if the list is + * not then empty, should turn main_need_zreload on again for the next call. + * It is not an error to call this when the reloadingzones list is empty. + */ +void +ns_zreload(void) { + struct zoneinfo *zp; + + block_signals(); + if (EMPTY(reloadingzones)) { + unblock_signals(); + return; + } + zp = HEAD(reloadingzones); + UNLINK(reloadingzones, zp, z_reloadlink); + unblock_signals(); + + reload_master(zp); + + block_signals(); + if (!EMPTY(reloadingzones)) + ns_need_unsafe(main_need_zreload); + unblock_signals(); +} + +/* + * Flush and reload configuration file and data base. */ void -ns_reload() { +ns_reload(void) { ns_notice(ns_log_default, "reloading nameserver"); + INSIST(reloading == 0); qflush(); sq_flush(NULL); -#ifdef FORCED_RELOAD - reloading = 1; /* to force transfer if secondary and backing up */ -#endif + reloading++; /* To force transfer if secondary and backing up. */ ns_init(conffile); time(&resettime); -#ifdef FORCED_RELOAD - reloading = 0; -#endif /* FORCED_RELOAD */ + reloading--; ns_notice(ns_log_default, "Ready to answer queries."); } + +/* + * Reload configuration, look for new or deleted zones, not changed ones. + */ +void +ns_reconfig(void) { + INSIST(reconfiging == 0); + reconfiging++; /* To ignore zones which aren't new or deleted. */ + ns_reload(); + reconfiging--; +} + +void +make_new_zones(void) { + struct zoneinfo *zp; + int n; + + ns_debug(ns_log_config, 1, "Adding %d template zones", NEWZONES); + zp = (struct zoneinfo *) + memget((nzones + NEWZONES) * sizeof(struct zoneinfo)); + if (zp == NULL) + panic("no memory for more zones", NULL); + memset(zp, 0, (nzones + NEWZONES) * sizeof(struct zoneinfo)); + if (zones != NULL) { + memcpy(zp, zones, nzones * sizeof(struct zoneinfo)); + memput(zones, nzones * sizeof(struct zoneinfo)); + } + zones = zp; + block_signals(); + for (n = 0; n < NEWZONES; n++) { + INIT_LINK(&zones[nzones], z_reloadlink); + if (nzones != 0) + free_zone(&zones[nzones]); + nzones++; + } + unblock_signals(); +} + +void +free_zone(struct zoneinfo *zp) { + if (LINKED(zp, z_reloadlink)) + panic("freeing reloading zone", NULL); + if (zp->z_type != z_nil) + panic("freeing unfree zone", NULL); + APPEND(freezones, zp, z_freelink); +} + +#ifndef HAVE_SPAWNXFER +static pid_t +spawnxfer(char **argv, struct zoneinfo *zp) { + pid_t pid = (pid_t)vfork(); + + if (pid == -1) { + ns_error(ns_log_default, "xfer vfork: %s", strerror(errno)); + zp->z_time = tt.tv_sec + 10; + return (pid); + } + if (pid == 0) { + /* Child. */ + execv(server_options->named_xfer, argv); + ns_error(ns_log_default, "can't exec %s: %s", + server_options->named_xfer, strerror(errno)); + (void)nxfers(zp, -1); + _exit(XFER_FAIL); /* Avoid duplicate buffer flushes. */ + } + return (pid); +} +#endif + +struct zoneinfo * +find_auth_zone(const char *zname, ns_class zclass) { + struct zoneinfo *zp; + struct hashbuf *htp; + struct namebuf *np; + const char *fname; + int zn; + + zp = find_zone(zname, zclass); + if (zp != NULL && + (zp->z_type == z_slave || + zp->z_type == z_master || + zp->z_type == z_stub)) + return (zp); + + htp = hashtab; + np = nlookup(zname, &htp, &fname, 0); + if (np != NULL && (zn = findMyZone(np, zclass)) != DB_Z_CACHE) + return (&zones[zn]); + + return (NULL); +} diff --git a/contrib/bind/bin/named/ns_ncache.c b/contrib/bind/bin/named/ns_ncache.c index 413ccc6..437072c 100644 --- a/contrib/bind/bin/named/ns_ncache.c +++ b/contrib/bind/bin/named/ns_ncache.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_ncache.c,v 8.17 1998/03/20 01:12:01 halley Exp $"; +static const char rcsid[] = "$Id: ns_ncache.c,v 8.26 1999/10/13 16:39:10 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,6 +25,7 @@ static char rcsid[] = "$Id: ns_ncache.c,v 8.17 1998/03/20 01:12:01 halley Exp $" #include <sys/param.h> #include <sys/socket.h> #include <sys/file.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -51,44 +52,77 @@ static char rcsid[] = "$Id: ns_ncache.c,v 8.17 1998/03/20 01:12:01 halley Exp $" } while (0) void -cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from) { +cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from, + const char *qname, int qclass, int qtype) +{ struct databuf *dp; HEADER *hp; u_char *cp, *eom, *rdatap; char dname[MAXDNAME]; - int n; - int type, class; - int Vcode; - int flags; - u_int16_t ancount; - u_int dlen; + int n, type, class, flags; + u_int ancount, nscount, dlen; +#ifdef RETURNSOA + u_int32_t ttl; + u_int16_t atype; + u_char *sp, *cp1; + u_char data[MAXDATA]; + size_t len = sizeof data; +#endif nameserIncr(from.sin_addr, nssRcvdNXD); hp = (HEADER *)msg; - cp = msg+HFIXEDSZ; + cp = msg + HFIXEDSZ; eom = msg + msglen; - - n = dn_expand(msg, eom, cp, dname, sizeof dname); - if (n < 0) { - ns_debug(ns_log_ncache, 1, - "Query expand name failed: cache_n_resp"); + + switch (ntohs(hp->qdcount)) { + case 0: + dname[sizeof dname - 1] = '\0'; + strncpy(dname, qname, sizeof dname); + if (dname[sizeof dname - 1] != '\0') { + ns_debug(ns_log_ncache, 1, + "qp->qname too long (%d)", strlen(qname)); + hp->rcode = FORMERR; + return; + } + class = qclass; + type = qtype; + break; + case 1: + n = dn_expand(msg, eom, cp, dname, sizeof dname); + if (n < 0) { + ns_debug(ns_log_ncache, 1, + "Query expand name failed: cache_n_resp"); + hp->rcode = FORMERR; + return; + } + cp += n; + BOUNDS_CHECK(cp, 2 * INT16SZ); + GETSHORT(type, cp); + GETSHORT(class, cp); + if (class > CLASS_MAX) { + ns_debug(ns_log_ncache, 1, + "bad class in cache_n_resp"); + hp->rcode = FORMERR; + return; + } + break; + default: + ns_debug(ns_log_ncache, 1, + "QDCOUNT>1 (%d) in cache_n_resp", ntohs(hp->qdcount)); hp->rcode = FORMERR; return; } - cp += n; - BOUNDS_CHECK(cp, 2 * INT16SZ); - GETSHORT(type, cp); - GETSHORT(class, cp); ns_debug(ns_log_ncache, 1, "ncache: dname %s, type %d, class %d", dname, type, class); ancount = ntohs(hp->ancount); + nscount = ntohs(hp->nscount); while (ancount--) { u_int32_t ttl; - u_int16_t atype; - u_int16_t aclass; + u_int atype, aclass; + n = dn_skipname(cp, eom); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: form error"); @@ -99,7 +133,9 @@ cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from) { GETSHORT(atype, cp); GETSHORT(aclass, cp); if (atype != T_CNAME || aclass != class) { - ns_debug(ns_log_ncache, 3, "ncache: form error"); + ns_debug(ns_log_ncache, 3, + "ncache: not CNAME (%s) or wrong class (%s)", + p_type(atype), p_class(aclass)); return; } GETLONG(ttl, cp); @@ -108,84 +144,81 @@ cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from) { rdatap = cp; n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname); if (n < 0) { - ns_debug(ns_log_ncache, 3, "ncache: form error"); + ns_debug(ns_log_ncache, 3, "ncache: bad cname target"); return; } cp += n; if (cp != rdatap + dlen) { - ns_debug(ns_log_ncache, 3, "ncache: form error"); + ns_debug(ns_log_ncache, 3, "ncache: bad cname rdata"); return; } } + dp = NULL; #ifdef RETURNSOA - if (hp->nscount) { - u_int32_t ttl; - u_int16_t atype; - u_char *tp = cp; - u_char *cp1; - u_char data[MAXDATA]; - size_t len = sizeof data; + while (nscount--) { + sp = cp; /* we store NXDOMAIN as T_SOA regardless of the query type */ if (hp->rcode == NXDOMAIN) type = T_SOA; /* store ther SOA record */ - n = dn_skipname(tp, msg + msglen); + n = dn_skipname(cp, msg + msglen); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: form error"); return; } - tp += n; + cp += n; - BOUNDS_CHECK(tp, 3 * INT16SZ + INT32SZ); - GETSHORT(atype, tp); /* type */ + BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); + GETSHORT(atype, cp); /* type */ + cp += INT16SZ; /* class */ + GETLONG(ttl, cp); /* ttl */ + GETSHORT(dlen, cp); /* dlen */ + BOUNDS_CHECK(cp, dlen); if (atype != T_SOA) { ns_debug(ns_log_ncache, 3, "ncache: type (%d) != T_SOA", atype); - goto no_soa; + cp += dlen; + continue; } - tp += INT16SZ; /* class */ - GETLONG(ttl, tp); /* ttl */ - GETSHORT(dlen, tp); /* dlen */ - BOUNDS_CHECK(tp, dlen); - rdatap = tp; + rdatap = cp; /* origin */ - n = dn_expand(msg, msg + msglen, tp, (char*)data, len); + n = dn_expand(msg, msg + msglen, cp, (char*)data, len); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: origin form error"); return; } - tp += n; + cp += n; n = strlen((char*)data) + 1; cp1 = data + n; len -= n; /* mail */ - n = dn_expand(msg, msg + msglen, tp, (char*)cp1, len); + n = dn_expand(msg, msg + msglen, cp, (char*)cp1, len); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: mail form error"); return; } - tp += n; + cp += n; n = strlen((char*)cp1) + 1; cp1 += n; len -= n; n = 5 * INT32SZ; - BOUNDS_CHECK(tp, n); - memcpy(cp1, tp, n); + BOUNDS_CHECK(cp, n); + memcpy(cp1, cp, n); /* serial, refresh, retry, expire, min */ cp1 += n; len -= n; - tp += n; - if (tp != rdatap + dlen) { + cp += n; + if (cp != rdatap + dlen) { ns_debug(ns_log_ncache, 3, "ncache: form error"); return; } /* store the zone of the soa record */ - n = dn_expand(msg, msg + msglen, cp, (char*)cp1, len); + n = dn_expand(msg, msg + msglen, sp, (char*)cp1, len); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: form error 2"); return; @@ -193,17 +226,28 @@ cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from) { n = strlen((char*)cp1) + 1; cp1 += n; - dp = savedata(class, type, MIN(ttl, NTTL) + tt.tv_sec, data, + /* + * we only want to store these long enough so that + * ns_resp can find it. + */ + if (qtype == T_SOA && hp->rcode == NXDOMAIN) + ttl = 0; + dp = savedata(class, type, + MIN(ttl, server_options->max_ncache_ttl) + + tt.tv_sec, data, cp1 - data); - } else { - no_soa: -#endif - dp = savedata(class, type, NTTL + tt.tv_sec, NULL, 0); -#ifdef RETURNSOA + break; } #endif + if (dp == NULL) +#ifdef STRICT_RFC2308 + dp = savedata(class, type, tt.tv_sec, NULL, 0); +#else + dp = savedata(class, type, NTTL + tt.tv_sec, NULL, 0); +#endif dp->d_zone = DB_Z_CACHE; dp->d_cred = hp->aa ? DB_C_AUTH : DB_C_ANSWER; + dp->d_secure = DB_S_INSECURE; /* BEW - should be UNCHECKED */ dp->d_clev = 0; if(hp->rcode == NXDOMAIN) { dp->d_rcode = NXDOMAIN; diff --git a/contrib/bind/bin/named/ns_notify.c b/contrib/bind/bin/named/ns_notify.c new file mode 100644 index 0000000..ac03732e --- /dev/null +++ b/contrib/bind/bin/named/ns_notify.c @@ -0,0 +1,379 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ns_notify.c,v 8.4 1999/10/15 19:49:04 vixie Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1994-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* Import. */ + +#include "port_before.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/un.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <limits.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <time.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> +#include <isc/memcluster.h> + +#include <isc/dst.h> + +#include "port_after.h" + +#include "named.h" + +#ifdef BIND_NOTIFY + +/* Types. */ + +struct notify { + char * name; + ns_class class; + ns_type type; + evTimerID timer; + LINK(struct notify) link; +}; + +/* Forward. */ + +static void sysnotify(const char *, ns_class, ns_type); +static void sysnotify_slaves(const char *, const char *, + ns_class, ns_type, int, int *, int *); +static void sysnotify_ns(const char *, const char *, + ns_class, ns_type, int, int *, int *); +static void free_notify(struct notify *); +static void notify_timer(evContext, void *, + struct timespec, struct timespec); + +/* Local. */ + +static LIST(struct notify) pending_notifies; + +/* Public. */ + +/* + * ns_notify(dname, class, type) + * call this when a zone has changed and its slaves need to know. + */ +void +ns_notify(const char *dname, ns_class class, ns_type type) { + static const char no_room[] = "%s failed, cannot notify for zone %s"; + int delay, max_delay; + struct zoneinfo *zp; + struct notify *ni; + + zp = find_auth_zone(dname, class); + if (zp == NULL) { + ns_warning(ns_log_notify, + "no zone found for notify (\"%s\" %s %s)", + (dname && *dname) ? dname : ".", + p_class(class), p_type(type)); + return; + } + if ((zp->z_flags & Z_NOTIFY) != 0) { + ns_info(ns_log_notify, + "suppressing duplicate notify (\"%s\" %s %s)", + (dname && *dname) ? dname : ".", + p_class(class), p_type(type)); + return; + } + ni = memget(sizeof *ni); + if (ni == NULL) { + ns_info(ns_log_notify, no_room, "memget", dname); + return; + } + ni->name = savestr(dname, 0); + if (ni->name == NULL) { + memput(ni, sizeof *ni); + ni = NULL; + ns_info(ns_log_notify, no_room, "memget", dname); + return; + } + ni->class = class; + ni->type = type; + evInitID(&ni->timer); + + /* Delay notification for from five seconds up to fifteen minutes. */ + max_delay = MIN(nzones/5, 895); + max_delay = MAX(max_delay, 25); + delay = 5 + (rand() % max_delay); + if (evSetTimer(ev, notify_timer, ni, + evAddTime(evNowTime(), evConsTime(delay, 0)), + evConsTime(0, 0), &ni->timer) < 0) { + ns_error(ns_log_notify, "evSetTimer() failed: %s", + strerror(errno)); + freestr(ni->name); + memput(ni, sizeof *ni); + return; + } + + zp->z_flags |= Z_NOTIFY; + APPEND(pending_notifies, ni, link); + ns_debug(ns_log_notify, 3, + "ns_notify(%s, %s, %s): ni %p, zp %p, delay %d", + (dname && *dname) ? dname : ".", + p_class(class), p_type(type), + ni, zp, delay); +} + +/* + * ns_unnotify() + * call this when all pending notifies are now considered junque. + */ +void +ns_unnotify(void) { + while (!EMPTY(pending_notifies)) { + struct notify *ni = HEAD(pending_notifies); + + INSIST(LINKED(ni, link)); + UNLINK(pending_notifies, ni, link); + free_notify(ni); + } +} + +/* Private. */ + +/* + * sysnotify(dname, class, type) + * cause a NOTIFY request to be sysquery()'d to each slave server + * of the zone that "dname" is within. + */ +static void +sysnotify(const char *dname, ns_class class, ns_type type) { + const char *zname, *fname; + int nns, na, i; + struct zoneinfo *zp; + struct in_addr *also_addr; + + ns_debug(ns_log_notify, 3, "sysnotify(%s, %s, %s)", + dname, p_class(class), p_type(type)); + zp = find_auth_zone(dname, class); + if (zp == NULL) { + ns_warning(ns_log_notify, "sysnotify: can't find \"%s\" (%s)", + dname, p_class(class)); + return; + } + if (ns_samename(dname, zp->z_origin) != 1) { + ns_warning(ns_log_notify, "sysnotify: not auth for zone %s", + dname); + return; + } + if (zp->z_notify == znotify_no || + (zp->z_notify == znotify_use_default && + NS_OPTION_P(OPTION_NONOTIFY))) + return; + if (zp->z_type != z_master && zp->z_type != z_slave) { + ns_warning(ns_log_notify, "sysnotify: %s not master or slave", + dname); + return; + } + zname = zp->z_origin; + nns = na = 0; + if (zp->z_type == z_master) + sysnotify_slaves(dname, zname, class, type, + zp - zones, &nns, &na); + + /* + * Handle any global or zone-specific also-notify clauses + */ + if (zp->z_notify_count != 0) { + /* zone-specific also notify */ + + ns_debug(ns_log_notify, 3, "zone notify ns = %d", + zp->z_notify_count); + + also_addr = zp->z_also_notify; + for (i = 0; i < zp->z_notify_count; i++) { + ns_debug(ns_log_notify, 4, "notifying %s", + inet_ntoa(*also_addr)); + sysquery(dname, class, type, also_addr, 1, ns_port, + NS_NOTIFY_OP); + also_addr++; + } + nns += zp->z_notify_count; + na += zp->z_notify_count; + } else if (server_options->notify_count != 0) { + ns_debug(ns_log_notify, 4, "global notify ns = %d", + server_options->notify_count); + also_addr = server_options->also_notify; + for (i = 0; i < server_options->notify_count; i++) { + ns_debug(ns_log_notify, 3, "notifying %s", + inet_ntoa(*also_addr)); + sysquery(dname, class, type, also_addr, + 1, ns_port, ns_o_notify); + also_addr++; + } + nns += server_options->notify_count; + na += server_options->notify_count; + } + + if (nns != 0 || na != 0) + ns_info(ns_log_notify, + "Sent NOTIFY for \"%s %s %s\" (%s); %d NS, %d A", + dname, p_class(class), p_type(type), zname, nns, na); +} + +static void +sysnotify_slaves(const char *dname, const char *zname, + ns_class class, ns_type type, + int zn, int *nns, int *na) +{ + const char *mname, *fname; + struct hashbuf *htp; + struct namebuf *np; + struct databuf *dp; + + /* + * Master. + */ + htp = hashtab; + np = nlookup(zname, &htp, &fname, 0); + if (np == NULL) { + ns_warning(ns_log_notify, + "sysnotify: found name \"%s\" but not zone", + dname); + return; + } + mname = NULL; + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + if (dp->d_zone == DB_Z_CACHE || !match(dp, class, ns_t_soa)) + continue; + if (dp->d_type == ns_t_sig) + continue; + if (mname) { + ns_notice(ns_log_notify, + "multiple SOA's for zone \"%s\"?", + zname); + return; + } + mname = (char *) dp->d_data; + } + if (mname == NULL) { + ns_notice(ns_log_notify, "no SOA found for zone \"%s\"", + zname); + return; + } + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + if (dp->d_zone == DB_Z_CACHE || !match(dp, class, ns_t_ns)) + continue; + if (dp->d_type == ns_t_sig) + continue; + if (ns_samename((char*)dp->d_data, mname) == 1) + continue; + sysnotify_ns(dname, (char *)dp->d_data, class, type, + zn, nns, na); + } +} + +static void +sysnotify_ns(const char *dname, const char *aname, + ns_class class, ns_type type, + int zn, int *nns, int *na) +{ + struct databuf *adp; + struct namebuf *anp; + const char *fname; + struct in_addr nss[NSMAX]; + struct hashbuf *htp; + int is_us, nsc; + + htp = hashtab; + anp = nlookup(aname, &htp, &fname, 0); + nsc = 0; + is_us = 0; + if (anp != NULL) + for (adp = anp->n_data; adp; adp = adp->d_next) { + struct in_addr ina; + + if (!match(adp, class, T_A)) + continue; + if (adp->d_type == ns_t_sig) + continue; + ina = ina_get(adp->d_data); + if (aIsUs(ina)) { + is_us = 1; + continue; + } + if (nsc < NSMAX) + nss[nsc++] = ina; + } /*next A*/ + if (nsc == 0) { + if (!is_us) { + struct qinfo *qp; + + qp = sysquery(aname, class, ns_t_a, 0, 0, ns_port, + ns_o_query); + if (qp != NULL) + qp->q_notifyzone = zn; + } + return; + } + sysquery(dname, class, type, nss, nsc, ns_port, ns_o_notify); + (*nns)++; + *na += nsc; +} + +static void +free_notify(struct notify *ni) { + struct zoneinfo *zp; + + INSIST(!LINKED(ni, link)); + zp = find_auth_zone(ni->name, ni->class); + if (zp != NULL) { + INSIST((zp->z_flags & Z_NOTIFY) != 0); + zp->z_flags &= ~Z_NOTIFY; + } + if (evTestID(ni->timer)) { + evClearTimer(ev, ni->timer); + evInitID(&ni->timer); + } + freestr(ni->name); + memput(ni, sizeof *ni); +} + +static void +notify_timer(evContext ctx, void *uap, + struct timespec due, + struct timespec inter) +{ + struct notify *ni = uap; + + INSIST(evTestID(ni->timer)); + evInitID(&ni->timer); + INSIST(LINKED(ni, link)); + UNLINK(pending_notifies, ni, link); + sysnotify(ni->name, ni->class, ni->type); + free_notify(ni); +} + +#endif /*BIND_NOTIFY*/ diff --git a/contrib/bind/bin/named/ns_parser.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 <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -45,6 +47,7 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include <ctype.h> #include <limits.h> +#include <resolv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -54,6 +57,8 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include <isc/eventlib.h> #include <isc/logging.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" @@ -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,230 +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, 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, 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, -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, - 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, - 0, -277, 0, 0, 0, 0, 0, 188, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 57, 0, 0, -162, -53, 56, 193, -118, 60, 104, - 0, 59, 63, -25, 0, 0, 0, 69, 0, -188, - -188, -11, -7, 203, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 16, -20, -16, -9, 0, 0, - 0, 0, 73, 0, 209, 210, 0, 0, 0, 0, - -143, 0, 77, 0, 0, 78, -53, 75, -184, 215, - -36, 216, 217, 218, 232, -277, -10, 99, 0, 0, - 0, 0, 113, 114, 0, 0, 0, -1, 0, 0, - 0, 0, 236, 73, 123, -214, -222, 0, 0, 0, - -81, 124, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 121, 0, 125, 16, 16, 16, 0, 0, 130, - 0, 0, 0, 0, 0, 131, 0, 0, 0, -104, - 132, 0, -202, 129, -221, 0, -53, -53, -53, -100, - 0, 0, 134, 0, 136, 0, 0, -96, 138, 0, - 271, 125, 141, 3, 8, 12, 0, 0, 0, 142, - 0, 0, 143, 0, 0, -89, 0, 0, 0, 0, - 0, 0, 0, 0, 144, 0, 0, 0, 146, 0, - 0, 147, 0, 0, 0, 0, 0, 0, -185, -190, - 76, 100, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 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, 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, 282, 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, 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, 159, 160, 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 +466,214 @@ 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, 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, 295, 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, 299, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 168, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 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, 301, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 171, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 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, - 173, 174, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; short yygindex[] = { 0, - 311, 0, 0, 211, 266, 0, 0, 357, 0, 0, - 350, 95, 0, -80, 0, 0, 0, 253, 255, -58, - 0, 212, -43, -8, 0, 438, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 369, 0, 0, 0, 0, - 0, 0, 331, 333, 0, 199, 0, 0, 367, 0, - 0, 0, 0, 0, 105, 108, 0, 0, 0, 156, - 170, 0, 0, 283, 0, 201, 0, 0, 0, 0, - 0, 226, 0, 0, 157, 0, 152, + -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_boolean_option(current_options, OPTION_NONAUTH_NXDOMAIN, + set_global_boolean_option(current_options, OPTION_USE_IXFR, yyvsp[0].num); + } +break; +case 36: +#line 372 "ns_parser.y" +{ + 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,140 +1623,386 @@ 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" +{ + 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 52: +#line 469 "ns_parser.y" +{ + 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 53: +#line 478 "ns_parser.y" +{ + 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 55: +#line 488 "ns_parser.y" +{ + 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 56: +#line 497 "ns_parser.y" +{ + 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 57: +#line 506 "ns_parser.y" { /* To get around the $$ = $1 default rule. */ } break; -case 45: -#line 383 "ns_parser.y" +case 59: +#line 511 "ns_parser.y" { current_options->transfer_format = yyvsp[0].axfr_fmt; } break; -case 46: -#line 387 "ns_parser.y" +case 60: +#line 515 "ns_parser.y" { current_options->max_transfer_time_in = yyvsp[0].num * 60; } break; -case 47: -#line 391 "ns_parser.y" +case 61: +#line 519 "ns_parser.y" +{ + current_options->serial_queries = yyvsp[0].num; + } +break; +case 62: +#line 523 "ns_parser.y" { current_options->clean_interval = yyvsp[0].num * 60; } break; -case 48: -#line 395 "ns_parser.y" +case 63: +#line 527 "ns_parser.y" { current_options->interface_interval = yyvsp[0].num * 60; } break; -case 49: -#line 399 "ns_parser.y" +case 64: +#line 531 "ns_parser.y" { current_options->stats_interval = yyvsp[0].num * 60; } break; -case 51: -#line 406 "ns_parser.y" +case 65: +#line 535 "ns_parser.y" +{ + current_options->max_log_size_ixfr = yyvsp[0].num; + } +break; +case 66: +#line 539 "ns_parser.y" +{ + current_options->max_ncache_ttl = yyvsp[0].num; + } +break; +case 67: +#line 543 "ns_parser.y" +{ + current_options->lame_ttl = yyvsp[0].num; + } +break; +case 68: +#line 547 "ns_parser.y" +{ + current_options->heartbeat_interval = yyvsp[0].num * 60; + } +break; +case 69: +#line 551 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_NODIALUP, !yyvsp[0].num); + } +break; +case 70: +#line 556 "ns_parser.y" +{ + if (current_options->ordering) + free_rrset_order_list(current_options->ordering); + current_options->ordering = yyvsp[-1].rol; + } +break; +case 71: +#line 562 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_TREAT_CR_AS_SPACE, yyvsp[0].num); + } +break; +case 72: +#line 567 "ns_parser.y" +{ + if (yyvsp[0].num >= 1) + current_options->minroots = yyvsp[0].num; + } +break; +case 78: +#line 587 "ns_parser.y" +{ + ns_ctl_add(¤t_controls, ns_ctl_new_inet(yyvsp[-6].ip_addr, yyvsp[-4].us_int, yyvsp[-1].iml)); + } +break; +case 79: +#line 591 "ns_parser.y" +{ + 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 598 "ns_parser.y" +{ + 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 609 "ns_parser.y" +{ + 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 618 "ns_parser.y" +{ + yyval.s_int = C_ANY; + } +break; +case 84: +#line 622 "ns_parser.y" +{ + symbol_value value; + + if (lookup_symbol(constants, yyvsp[0].cp, SYM_CLASS, &value)) + yyval.s_int = value.integer; + else { + parser_error(0, "unknown class '%s'; using ANY", yyvsp[0].cp); + yyval.s_int = C_ANY; + } + freestr(yyvsp[0].cp); + } +break; +case 85: +#line 636 "ns_parser.y" +{ + yyval.s_int = ns_t_any; + } +break; +case 86: +#line 640 "ns_parser.y" +{ + 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 658 "ns_parser.y" +{ + yyval.cp = savestr("*", 1); + } +break; +case 88: +#line 662 "ns_parser.y" +{ + 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 674 "ns_parser.y" +{ + 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 697 "ns_parser.y" { yyval.axfr_fmt = axfr_one_answer; } break; -case 52: -#line 410 "ns_parser.y" +case 91: +#line 701 "ns_parser.y" { yyval.axfr_fmt = axfr_many_answers; } break; -case 53: -#line 415 "ns_parser.y" +case 92: +#line 706 "ns_parser.y" { yyval.ip_addr = yyvsp[0].ip_addr; } break; -case 54: -#line 416 "ns_parser.y" +case 93: +#line 707 "ns_parser.y" { yyval.ip_addr.s_addr = htonl(INADDR_ANY); } break; -case 55: -#line 419 "ns_parser.y" +case 94: +#line 710 "ns_parser.y" { yyval.us_int = yyvsp[0].us_int; } break; -case 56: -#line 420 "ns_parser.y" +case 95: +#line 711 "ns_parser.y" { yyval.us_int = htons(0); } break; -case 57: -#line 424 "ns_parser.y" +case 96: +#line 715 "ns_parser.y" { current_options->query_source.sin_addr = yyvsp[0].ip_addr; } break; -case 58: -#line 430 "ns_parser.y" +case 97: +#line 721 "ns_parser.y" { current_options->query_source.sin_port = yyvsp[0].us_int; } break; -case 63: -#line 441 "ns_parser.y" +case 102: +#line 732 "ns_parser.y" { yyval.us_int = htons(NS_DEFAULTPORT); } break; -case 64: -#line 442 "ns_parser.y" +case 103: +#line 733 "ns_parser.y" { yyval.us_int = yyvsp[0].us_int; } break; -case 65: -#line 446 "ns_parser.y" +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 66: -#line 450 "ns_parser.y" +case 107: +#line 746 "ns_parser.y" { yyval.num = 1; } break; -case 67: -#line 454 "ns_parser.y" +case 108: +#line 750 "ns_parser.y" { yyval.num = 0; } break; -case 68: -#line 458 "ns_parser.y" +case 109: +#line 754 "ns_parser.y" { yyval.num = 0; } break; -case 69: -#line 462 "ns_parser.y" +case 110: +#line 758 "ns_parser.y" { if (yyvsp[0].num == 1 || yyvsp[0].num == 0) { yyval.num = yyvsp[0].num; @@ -1463,92 +2013,94 @@ case 69: } } break; -case 70: -#line 474 "ns_parser.y" +case 111: +#line 770 "ns_parser.y" { yyval.s_int = primary_trans; } break; -case 71: -#line 478 "ns_parser.y" +case 112: +#line 774 "ns_parser.y" { yyval.s_int = secondary_trans; } break; -case 72: -#line 482 "ns_parser.y" +case 113: +#line 778 "ns_parser.y" { yyval.s_int = response_trans; } break; -case 73: -#line 488 "ns_parser.y" +case 114: +#line 784 "ns_parser.y" { yyval.s_int = warn; } break; -case 74: -#line 492 "ns_parser.y" +case 115: +#line 788 "ns_parser.y" { yyval.s_int = fail; } break; -case 75: -#line 496 "ns_parser.y" +case 116: +#line 792 "ns_parser.y" { yyval.s_int = ignore; } break; -case 76: -#line 502 "ns_parser.y" +case 117: +#line 798 "ns_parser.y" { - set_boolean_option(current_options, OPTION_FORWARD_ONLY, 1); + set_global_boolean_option(current_options, + OPTION_FORWARD_ONLY, 1); } break; -case 77: -#line 506 "ns_parser.y" +case 118: +#line 803 "ns_parser.y" { - set_boolean_option(current_options, OPTION_FORWARD_ONLY, 0); + set_global_boolean_option(current_options, + OPTION_FORWARD_ONLY, 0); } break; -case 78: -#line 510 "ns_parser.y" +case 119: +#line 808 "ns_parser.y" { parser_warning(0, "forward if-no-answer is unimplemented"); } break; -case 79: -#line 514 "ns_parser.y" +case 120: +#line 812 "ns_parser.y" { parser_warning(0, "forward if-no-domain is unimplemented"); } break; -case 80: -#line 520 "ns_parser.y" +case 121: +#line 818 "ns_parser.y" { current_options->data_size = yyvsp[0].ul_int; } break; -case 81: -#line 524 "ns_parser.y" +case 122: +#line 822 "ns_parser.y" { current_options->stack_size = yyvsp[0].ul_int; } break; -case 82: -#line 528 "ns_parser.y" +case 123: +#line 826 "ns_parser.y" { current_options->core_size = yyvsp[0].ul_int; } break; -case 83: -#line 532 "ns_parser.y" +case 124: +#line 830 "ns_parser.y" { current_options->files = yyvsp[0].ul_int; } break; -case 84: -#line 538 "ns_parser.y" +case 125: +#line 836 "ns_parser.y" { u_long result; @@ -1562,89 +2114,107 @@ case 84: freestr(yyvsp[0].cp); } break; -case 85: -#line 551 "ns_parser.y" +case 126: +#line 849 "ns_parser.y" { yyval.ul_int = (u_long)yyvsp[0].num; } break; -case 86: -#line 555 "ns_parser.y" +case 127: +#line 853 "ns_parser.y" { yyval.ul_int = 0; } break; -case 87: -#line 559 "ns_parser.y" +case 128: +#line 857 "ns_parser.y" { yyval.ul_int = ULONG_MAX; } break; -case 88: -#line 565 "ns_parser.y" +case 129: +#line 863 "ns_parser.y" { current_options->transfers_in = (u_long) yyvsp[0].num; } break; -case 89: -#line 569 "ns_parser.y" +case 130: +#line 867 "ns_parser.y" { current_options->transfers_out = (u_long) yyvsp[0].num; } break; -case 90: -#line 573 "ns_parser.y" +case 131: +#line 871 "ns_parser.y" { current_options->transfers_per_ns = (u_long) yyvsp[0].num; } break; -case 93: -#line 583 "ns_parser.y" +case 134: +#line 881 "ns_parser.y" { /* nothing */ } break; -case 94: -#line 587 "ns_parser.y" +case 135: +#line 885 "ns_parser.y" { /* nothing */ } break; -case 95: -#line 593 "ns_parser.y" +case 136: +#line 891 "ns_parser.y" { - add_forwarder(current_options, yyvsp[0].ip_addr); + add_global_forwarder(current_options, yyvsp[0].ip_addr); } break; -case 96: -#line 603 "ns_parser.y" +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 <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -32,6 +34,7 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include <ctype.h> #include <limits.h> +#include <resolv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -41,6 +44,8 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include <isc/eventlib.h> #include <isc/logging.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" @@ -61,11 +66,13 @@ static symbol_table symtab; static symbol_table authtab = NULL; static zone_config current_zone; -static int seen_zone; +static int should_install; static options current_options; static int seen_options; +static controls current_controls; + static topology_config current_topology; static int seen_topology; @@ -90,7 +97,7 @@ static void define_channel(char *, log_channel); static char *canonical_name(char *); int yyparse(); - + %} %union { @@ -102,7 +109,9 @@ int yyparse(); struct in_addr ip_addr; ip_match_element ime; ip_match_list iml; - key_info keyi; + rrset_order_list rol; + rrset_order_element roe; + struct dst_key * keyi; enum axfr_format axfr_fmt; } @@ -121,22 +130,29 @@ int yyparse(); %token T_OPTIONS %token T_DIRECTORY T_PIDFILE T_NAMED_XFER %token T_DUMP_FILE T_STATS_FILE T_MEMSTATS_FILE -%token T_FAKE_IQUERY T_RECURSION T_FETCH_GLUE +%token T_FAKE_IQUERY T_RECURSION T_FETCH_GLUE %token T_QUERY_SOURCE T_LISTEN_ON T_PORT T_ADDRESS +%token T_RRSET_ORDER T_ORDER T_NAME T_CLASS +%token T_CONTROLS T_INET T_UNIX T_PERM T_OWNER T_GROUP T_ALLOW %type <us_int> in_port %type <us_int> maybe_port +%type <us_int> maybe_zero_port %type <us_int> maybe_wild_port %type <ip_addr> maybe_wild_addr %token T_DATASIZE T_STACKSIZE T_CORESIZE %token T_DEFAULT T_UNLIMITED -%token T_FILES +%token T_FILES T_VERSION %token T_HOSTSTATS T_DEALLOC_ON_EXIT %token T_TRANSFERS_IN T_TRANSFERS_OUT T_TRANSFERS_PER_NS %token T_TRANSFER_FORMAT T_MAX_TRANSFER_TIME_IN -%token T_ONE_ANSWER T_MANY_ANSWERS +%token T_SERIAL_QUERIES T_ONE_ANSWER T_MANY_ANSWERS %type <axfr_fmt> transfer_format -%token T_NOTIFY T_AUTH_NXDOMAIN T_MULTIPLE_CNAMES -%token T_CLEAN_INTERVAL T_INTERFACE_INTERVAL T_STATS_INTERVAL +%token T_NOTIFY T_AUTH_NXDOMAIN T_MULTIPLE_CNAMES T_USE_IXFR T_MAINTAIN_IXFR_BASE +%token T_CLEAN_INTERVAL T_INTERFACE_INTERVAL T_STATS_INTERVAL T_MAX_LOG_SIZE_IXFR +%token T_HEARTBEAT T_USE_ID_POOL +%token T_MAX_NCACHE_TTL T_HAS_OLD_CLIENTS T_RFC2308_TYPE1 +%token T_LAME_TTL T_MIN_ROOTS +%token T_TREAT_CR_AS_SPACE /* Items used for the "logging" statement: */ %token T_LOGGING T_CATEGORY T_CHANNEL T_SEVERITY T_DYNAMIC @@ -147,9 +163,18 @@ int yyparse(); %type <cp> category_name channel_name facility_name %type <s_int> maybe_syslog_facility +/* Items used for the "sortlist" statement: */ +%token T_SORTLIST + /* Items used for the "topology" statement: */ %token T_TOPOLOGY +%type <s_int> ordering_class +%type <s_int> ordering_type +%type <cp> ordering_name +%type <rol> rrset_ordering_list +%type <roe> rrset_ordering_element + /* ip_match_list */ %type <ime> address_match_simple address_match_element address_name %type <iml> address_match_list @@ -160,6 +185,7 @@ int yyparse(); %token T_BOGUS %token T_TRANSFERS %token T_KEYS +%token T_SUPPORT_IXFR /* Items used for "zone" statements: */ %token T_ZONE @@ -170,11 +196,20 @@ int yyparse(); %token T_MASTER T_SLAVE T_STUB T_RESPONSE %token T_HINT %token T_MASTERS T_TRANSFER_SOURCE +%token T_PUBKEY %token T_ALSO_NOTIFY +%token T_DIALUP +%token T_FILE_IXFR +%token T_IXFR_TMP + +/* Items used for "trusted-keys" statements: */ +%token T_TRUSTED_KEYS /* Items used for access control lists and "allow" clauses: */ %token T_ACL %token T_ALLOW_UPDATE T_ALLOW_QUERY T_ALLOW_TRANSFER +%token T_ALLOW_RECURSION +%token T_BLACKHOLE /* Items related to the "key" statement: */ %token T_SEC_KEY T_ALGID T_SECRET @@ -204,7 +239,9 @@ int yyparse(); %% config_file: statement_list { - /* nothing */ + if (EMPTY(current_controls)) + ns_ctl_defaults(¤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 <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -178,7 +180,7 @@ define_symbol(symbol_table st, char *key, int type, symbol_value value, void undefine_symbol(symbol_table st, char *key, int type) { int hash; - symbol_entry prev_ste, ste, next_ste; + symbol_entry prev_ste, ste; hash = symbol_hash(key, st->size); for (prev_ste = NULL, ste = st->table[hash]; diff --git a/contrib/bind/bin/named/ns_parseutil.h b/contrib/bind/bin/named/ns_parseutil.h index d241bea..78356f8 100644 --- a/contrib/bind/bin/named/ns_parseutil.h +++ b/contrib/bind/bin/named/ns_parseutil.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,8 +15,8 @@ * SOFTWARE. */ -#ifndef NS_PARSEUTIL_H -#define NS_PARSEUTIL_H +#ifndef _NS_PARSEUTIL_H +#define _NS_PARSEUTIL_H /* * Symbol Table @@ -62,4 +62,4 @@ void undefine_symbol(symbol_table, char *, int type); int unit_to_ulong(char *, u_long *); -#endif /* !NS_PARSEUTIL_H */ +#endif /* !_NS_PARSEUTIL_H */ diff --git a/contrib/bind/bin/named/ns_req.c b/contrib/bind/bin/named/ns_req.c index ee60ce4..d7ee0b5 100644 --- a/contrib/bind/bin/named/ns_req.c +++ b/contrib/bind/bin/named/ns_req.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_req.c 4.47 (Berkeley) 7/1/91"; -static char rcsid[] = "$Id: ns_req.c,v 8.46 1998/03/27 00:21:03 halley Exp $"; +static const char sccsid[] = "@(#)ns_req.c 4.47 (Berkeley) 7/1/91"; +static const char rcsid[] = "$Id: ns_req.c,v 8.104 1999/10/15 19:49:04 vixie Exp $"; #endif /* not lint */ /* @@ -82,7 +82,7 @@ static char rcsid[] = "$Id: ns_req.c,v 8.46 1998/03/27 00:21:03 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -105,6 +105,7 @@ static char rcsid[] = "$Id: ns_req.c,v 8.46 1998/03/27 00:21:03 halley Exp $"; #include <sys/uio.h> #include <sys/file.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -123,6 +124,8 @@ static char rcsid[] = "$Id: ns_req.c,v 8.46 1998/03/27 00:21:03 halley Exp $"; #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" @@ -131,7 +134,8 @@ struct addinfo { char *a_dname; /* domain name */ char *a_rname; /* referred by */ u_int16_t a_rtype; /* referred by */ - u_int16_t a_class; /* class for address */ + u_int16_t a_type; /* type for data */ + u_int16_t a_class; /* class for data */ }; #ifndef BIND_UPDATE @@ -140,14 +144,15 @@ enum req_action { Finish, Refuse, Return }; static struct addinfo addinfo[NADDRECS]; static void addname(const char *, const char *, - u_int16_t, u_int16_t); + u_int16_t, u_int16_t, u_int16_t); static void copyCharString(u_char **, const char *); static enum req_action req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, int *buflenp, int *msglenp, - u_char *msg, int dfd, - struct sockaddr_in from); + u_char *msg, int dfd, int *ra, + struct sockaddr_in from, + struct tsig_record *in_tsig); static enum req_action req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, u_char *msg, @@ -168,14 +173,89 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp, HEADER *hp = (HEADER *) msg; u_char *cp, *eom; enum req_action action; - int n; + int n, ra, has_tsig, msglen_orig, tsig_size, siglen, sig2len; + u_char *tsigstart; + u_char sig[TSIG_SIG_SIZE], sig2[TSIG_SIG_SIZE]; + struct tsig_record *in_tsig = NULL; + int error = NOERROR; + DST_KEY *key; + time_t tsig_time; #ifdef DEBUG if (debug > 3) { ns_debug(ns_log_packet, 3, "ns_req(from %s)", sin_ntoa(from)); - fp_nquery(msg, msglen, log_get_stream(packet_channel)); + res_pquery(&res, msg, msglen, log_get_stream(packet_channel)); } #endif + msglen_orig = msglen; + siglen = sizeof(sig); + + tsigstart = ns_find_tsig(msg, msg + msglen); + if (tsigstart == NULL) + has_tsig = 0; + else { + char buf[MAXDNAME]; + + has_tsig = 1; + ns_name_ntop(tsigstart, buf, sizeof(buf)); + key = find_key(buf, NULL); + if (key == NULL) { + error = ns_r_badkey; + ns_debug(ns_log_default, 1, + "ns_req: TSIG verify failed - unknown key %s", + buf); + } + } + if (has_tsig && key != NULL) { + n = ns_verify(msg, &msglen, key, NULL, 0, sig, &siglen, + &tsig_time, 0); + if (n != 0) { + hp->rcode = ns_r_notauth; + /* A query should never have an error code set */ + if (n == ns_r_badsig || n == ns_r_badkey || + n == ns_r_badtime) { + ns_debug(ns_log_default, 1, + "ns_req: TSIG verify failed - query had error %s (%d) set", + p_rcode(n), n); + error = n; + action = Return; + } + /* If there's a processing error just respond */ + else if (n == -ns_r_badsig || n == -ns_r_badkey || + n == -ns_r_badtime) { + n = -n; + ns_debug(ns_log_default, 1, + "ns_req: TSIG verify failed - %s (%d)", + p_rcode(n), n); + error = n; + } else { + ns_debug(ns_log_default, 1, + "ns_req: TSIG verify failed - FORMERR"); + error = ns_r_formerr; + } + action = Finish; + } + in_tsig = memget(sizeof(struct tsig_record)); + if (in_tsig == NULL) + ns_panic(ns_log_default, 1, "memget failed"); + in_tsig->key = key; + in_tsig->siglen = siglen; + memcpy(in_tsig->sig, sig, siglen); + tsig_size = msglen_orig - msglen; + } else if (has_tsig) { + action = Finish; + in_tsig = memget(sizeof(struct tsig_record)); + if (in_tsig == NULL) + ns_panic(ns_log_default, 1, "memget failed"); + in_tsig->key = NULL; + in_tsig->siglen = 0; + tsig_size = msg + msglen - tsigstart; + msglen = tsigstart - msg; + } + + /* Hash some stuff so it's nice and random */ + nsid_hash((u_char *)&tt, sizeof(tt)); + nsid_hash(msg, (msglen > 512) ? 512 : msglen); /* * It's not a response so these bits have no business @@ -184,8 +264,10 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp, * comes in. */ hp->aa = hp->ra = 0; + ra = (NS_OPTION_P(OPTION_NORECURSE) == 0); - hp->rcode = NOERROR; + if (error == NOERROR) + hp->rcode = ns_r_noerror; cp = msg + HFIXEDSZ; eom = msg + msglen; buflen -= HFIXEDSZ; @@ -193,49 +275,58 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp, free_addinfo(); /* sets addcount to zero */ dnptrs[0] = NULL; - switch (hp->opcode) { - case ns_o_query: - action = req_query(hp, &cp, eom, qsp, - &buflen, &msglen, - msg, dfd, from); - break; + if (error == NOERROR) { + switch (hp->opcode) { + case ns_o_query: + action = req_query(hp, &cp, eom, qsp, + &buflen, &msglen, + msg, dfd, &ra, from, in_tsig); + break; - case ns_o_iquery: - action = req_iquery(hp, &cp, eom, &buflen, msg, from); - break; + case ns_o_iquery: + action = req_iquery(hp, &cp, eom, &buflen, msg, from); + break; #ifdef BIND_NOTIFY - case ns_o_notify: - action = req_notify(hp, &cp, eom, msg, from); - break; + case ns_o_notify: + action = req_notify(hp, &cp, eom, msg, from); + break; #endif #ifdef BIND_UPDATE - case ns_o_update: - action = req_update(hp, cp, eom, msg, qsp, dfd, from); - break; + case ns_o_update: + action = req_update(hp, cp, eom, msg, qsp, dfd, from, + in_tsig); + break; #endif /* BIND_UPDATE */ - default: - ns_debug(ns_log_default, 1, - "ns_req: Opcode %d not implemented", hp->opcode); - /* XXX - should syslog, limited by haveComplained */ - hp->qdcount = htons(0); - hp->ancount = htons(0); - hp->nscount = htons(0); - hp->arcount = htons(0); - hp->rcode = NOTIMP; - action = Finish; + default: + ns_debug(ns_log_default, 1, + "ns_req: Opcode %d not implemented", + hp->opcode); + /* XXX - should syslog, limited by haveComplained */ + hp->qdcount = htons(0); + hp->ancount = htons(0); + hp->nscount = htons(0); + hp->arcount = htons(0); + hp->rcode = ns_r_notimpl; + action = Finish; + } + } + + if (in_tsig != NULL) { + memput(in_tsig, sizeof(struct tsig_record)); + in_tsig = NULL; } /* - * vector via internal opcode. (yes, it was even uglier before.) + * Vector via internal opcode. */ switch (action) { case Return: return; case Refuse: - hp->rcode = REFUSED; + hp->rcode = ns_r_refused; cp = eom; /*FALLTHROUGH*/ case Finish: @@ -247,22 +338,73 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp, } /* - * apply final polish + * Apply final polish. */ hp->qr = 1; /* set Response flag */ - hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0); + hp->ra = ra; /* init above, may be modified by req_query */ - n = doaddinfo(hp, cp, buflen); - cp += n; - buflen -= n; + if (!hp->tc && has_tsig > 0 && buflen < tsig_size) + hp->tc = 1; + + /* + * If there was a format error, then we don't know what the msg has. + */ + if (hp->rcode == ns_r_formerr) { + hp->qdcount = htons(0); + hp->ancount = htons(0); + hp->nscount = htons(0); + hp->arcount = htons(0); + } + + /* + * If the query had a TSIG and the message is truncated or there was + * a TSIG error, build a new message with no data and a TSIG. + */ + if ((hp->tc || error != NOERROR) && has_tsig > 0) { + hp->ancount = htons(0); + hp->nscount = htons(0); + hp->arcount = htons(0); + cp = msg + HFIXEDSZ; + cp += ns_skiprr(cp, msg + msglen, ns_s_qd, ntohs(hp->qdcount)); + sig2len = sizeof(sig2); + buflen += (msglen - (cp - msg)); + msglen = cp - msg; + n = ns_sign(msg, &msglen, msglen + buflen, error, key, + sig, siglen, sig2, &sig2len, tsig_time); + if (n != 0) { + INSIST(0); + } + cp = msg + msglen; + + } + /* Either the message is not truncated or there was no TSIG */ + else { + if (has_tsig > 0) + buflen -= tsig_size; + n = doaddinfo(hp, cp, buflen); + cp += n; + buflen -= n; + if (has_tsig > 0) { + buflen += tsig_size; + sig2len = sizeof(sig2); + msglen = cp - msg; + n = ns_sign(msg, &msglen, msglen + buflen, error, key, + sig, siglen, sig2, &sig2len, tsig_time); + if (n != 0) { + INSIST(0); + } + cp = msg + msglen; + } + } #ifdef DEBUG ns_debug(ns_log_default, 1, - "ns_req: answer -> %s fd=%d id=%d size=%d", + "ns_req: answer -> %s fd=%d id=%d size=%d rc=%d", sin_ntoa(from), (qsp == NULL) ? dfd : qsp->s_rfd, - ntohs(hp->id), cp - msg); + ntohs(hp->id), cp - msg, hp->rcode); if (debug >= 10) - fp_nquery(msg, cp - msg, log_get_stream(packet_channel)); + res_pquery(&res, msg, cp - msg, + log_get_stream(packet_channel)); #endif /*DEBUG*/ if (qsp == NULL) { if (sendto(dfd, (char*)msg, cp - msg, 0, @@ -276,7 +418,7 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp, nameserIncr(from.sin_addr, nssSendtoErr); } nameserIncr(from.sin_addr, nssSentAns); - if (hp->rcode == NXDOMAIN) + if (hp->rcode == ns_r_nxdomain) nameserIncr(from.sin_addr, nssSentNXD); if (!hp->aa) nameserIncr(from.sin_addr, nssSentNaAns); @@ -307,22 +449,13 @@ req_notify(HEADER *hp, u_char **cpp, u_char *eom, u_char *msg, { int n, type, class, zn; char dnbuf[MAXDNAME]; - struct namebuf *np; - const char *fname; - struct hashbuf *htp = hashtab; /* lookup relative to root */ + struct zoneinfo *zp; - /* valid notify's have one question and zero answers */ - if ((ntohs(hp->qdcount) != 1) - || ntohs(hp->ancount) != 0 - || ntohs(hp->nscount) != 0 - || ntohs(hp->arcount) != 0) { + /* valid notify's have one question */ + if (ntohs(hp->qdcount) != 1) { ns_debug(ns_log_notify, 1, "FORMERR Notify header counts wrong"); - hp->qdcount = htons(0); - hp->ancount = htons(0); - hp->nscount = htons(0); - hp->arcount = htons(0); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } @@ -330,14 +463,14 @@ req_notify(HEADER *hp, u_char **cpp, u_char *eom, u_char *msg, if (n < 0) { ns_debug(ns_log_notify, 1, "FORMERR Query expand name failed"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } *cpp += n; if (*cpp + 2 * INT16SZ > eom) { ns_debug(ns_log_notify, 1, "FORMERR notify too short"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } GETSHORT(type, *cpp); @@ -347,76 +480,95 @@ req_notify(HEADER *hp, u_char **cpp, u_char *eom, u_char *msg, /* XXX - when answers are allowed, we'll need to do compression * correctly here, and we will need to check for packet underflow. */ - np = nlookup(dnbuf, &htp, &fname, 0); - if (!np) { + /* Find the zone this NOTIFY refers to. */ + zp = find_auth_zone(dnbuf, class); + if (zp == NULL) { ns_info(ns_log_notify, - "rcvd NOTIFY for \"%s\", name not in cache", + "rcvd NOTIFY for \"%s\", name not one of our zones", dnbuf); - hp->rcode = SERVFAIL; + hp->rcode = ns_r_servfail; return (Finish); } - zn = findMyZone(np, class); - if (zn == DB_Z_CACHE || zones[zn].z_type != z_slave) { - /* this can come if a user did an AXFR of some zone somewhere - * and that zone's server now wants to tell us that the SOA - * has changed. AXFR's always come from nonpriv ports so it - * isn't possible to know whether it was the server or just - * "dig". this condition can be avoided by using secure zones - * since that way only real secondaries can AXFR from you. - */ - ns_info(ns_log_notify, - "NOTIFY for non-secondary name (%s), from %s", - dnbuf, sin_ntoa(from)); - goto refuse; - } - if (findZonePri(&zones[zn], from) == -1) { - ns_info(ns_log_notify, - "NOTIFY from non-master server (zone %s), from %s", - zones[zn].z_origin, sin_ntoa(from)); - goto refuse; - } + /* Access control. */ switch (type) { case T_SOA: - if (strcasecmp(dnbuf, zones[zn].z_origin) != 0) { + if (zp->z_type != z_slave) { + /* + * This can come if a user did an AXFR of some zone + * somewhere and that zone's server now wants to + * tell us that the SOA has changed. AXFR's always + * come from nonpriv ports so it isn't possible to + * know whether it was the server or just "dig". + * This condition can be avoided by using secure + * zones since that way only real secondaries can + * AXFR from you. + */ + ns_info(ns_log_notify, + "NOTIFY(SOA) for non-secondary name (%s), from %s", + dnbuf, sin_ntoa(from)); + goto refuse; + } + if (ns_samename(dnbuf, zp->z_origin) != 1) { ns_info(ns_log_notify, "NOTIFY(SOA) for non-origin (%s), from %s", dnbuf, sin_ntoa(from)); goto refuse; } - if (zones[zn].z_flags & + if (findZonePri(zp, from) == -1) { + ns_info(ns_log_notify, + "NOTIFY(SOA) from non-master server (zone %s), from %s", + zp->z_origin, sin_ntoa(from)); + goto refuse; + } + break; + default: + /* No access requirements defined for other types. */ + break; + } + /* The work occurs here. */ + switch (type) { + case T_SOA: + if (zp->z_flags & (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL|Z_XFER_RUNNING)) { ns_info(ns_log_notify, "NOTIFY(SOA) for zone already xferring (%s)", dnbuf); goto noerror; } - zones[zn].z_time = tt.tv_sec; - qserial_query(&zones[zn]); - sched_zone_maint(&zones[zn]); + zp->z_time = tt.tv_sec; + qserial_query(zp); + sched_zone_maint(zp); break; default: - /* unimplemented, but it's not a protocol error, just + /* + * Unimplemented, but it's not a protocol error, just * something to be ignored. */ - break; + hp->rcode = ns_r_notimpl; + return (Finish); } noerror: - hp->rcode = NOERROR; + hp->rcode = ns_r_noerror; return (Finish); refuse: - hp->rcode = REFUSED; + hp->rcode = ns_r_refused; return (Finish); } #endif /*BIND_NOTIFY*/ static enum req_action req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, - int *buflenp, int *msglenp, u_char *msg, int dfd, - struct sockaddr_in from) + int *buflenp, int *msglenp, u_char *msg, int dfd, int *ra, + struct sockaddr_in from, struct tsig_record *in_tsig) { int n, class, type, count, zone, foundname, founddata, omsglen, cname; + int recursion_blocked_by_acl; u_int16_t id; - u_char **dpp, *omsg, *answers; + u_int32_t serial_ixfr; + int ixfr_found; + int ixfr_error = 0; + char dnbuf2[MAXDNAME]; + u_char **dpp, *omsg, *answers, *afterq; char dnbuf[MAXDNAME], *dname; const char *fname; struct hashbuf *htp; @@ -425,6 +577,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, struct qinfo *qp; struct zoneinfo *zp; struct databuf *dp; + DST_KEY *in_key = (in_tsig != NULL) ? in_tsig->key : NULL; nameserIncr(from.sin_addr, nssRcvdQ); @@ -438,19 +591,15 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, omsglen = 0; omsg = NULL; id = 0; + recursion_blocked_by_acl = 0; /* valid queries have one question and zero answers */ if ((ntohs(hp->qdcount) != 1) || ntohs(hp->ancount) != 0 - || ntohs(hp->nscount) != 0 || ntohs(hp->arcount) != 0) { ns_debug(ns_log_default, 1, "FORMERR Query header counts wrong"); - hp->qdcount = htons(0); - hp->ancount = htons(0); - hp->nscount = htons(0); - hp->arcount = htons(0); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } @@ -464,35 +613,101 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, if (n < 0) { ns_debug(ns_log_default, 1, "FORMERR Query expand name failed"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } *cpp += n; + answers = *cpp; if (*cpp + 2 * INT16SZ > eom) { ns_debug(ns_log_default, 1, "FORMERR Query message length short"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } GETSHORT(type, *cpp); GETSHORT(class, *cpp); - if (*cpp < eom) { + if (*cpp < eom && type != ns_t_ixfr) { ns_debug(ns_log_default, 6, "message length > received message"); *msglenp = *cpp - msg; } + if (((ntohs(hp->nscount) != 0) && (type != ns_t_ixfr)) || + ((ntohs(hp->nscount) != 1) && (type == ns_t_ixfr))) + { + ns_debug(ns_log_default, 1, "FORMERR Query nscount wrong"); + hp->rcode = ns_r_formerr; + return (Finish); + } + + afterq = *cpp; qtypeIncr(type); /* * Process query. */ - if (type == T_AXFR) { + if (type == ns_t_ixfr) { + hp->nscount = htons(0); + hp->rd = 0; /* Force IXFR queries to be non recursive. */ + n = dn_expand(msg, eom, *cpp, dnbuf2, sizeof dnbuf2); + if (n < 0) { + ns_debug(ns_log_default, 1, + "FORMERR Query expand name failed"); + hp->rcode = ns_r_formerr; + return (Finish); + } + *cpp += n; + if (*cpp + 3 * INT16SZ + INT32SZ > eom) { + ns_debug(ns_log_default, 1, + "ran out of data in IXFR query"); + hp->rcode = ns_r_formerr; + return (Finish); + } + GETSHORT(n, *cpp); + if (n != ns_t_soa || ns_samename(dnbuf, dnbuf2) != 1) { + ns_debug(ns_log_default, 1, + "FORMERR SOA record expected"); + hp->rcode = ns_r_formerr; + return (Finish); + } + *cpp += INT32SZ + INT16SZ * 2; /* skip class, ttl, dlen */ + if (0 >= (n = dn_skipname(*cpp, eom))) { + ns_debug(ns_log_default, 1, + "FORMERR Query expand name failed"); + hp->rcode = ns_r_formerr; + return (Finish); + } + *cpp += n; /* mname */ + if (0 >= (n = dn_skipname(*cpp, eom))) { + ns_debug(ns_log_default, 1, + "FORMERR Query expand name failed"); + hp->rcode = ns_r_formerr; + return (Finish); + } + *cpp += n; /* rname */ + if (*cpp + 5 * INT32SZ > eom) { + ns_debug(ns_log_default, 1, + "ran out of data in IXFR query"); + hp->rcode = ns_r_formerr; + return (Finish); + } + GETLONG(serial_ixfr, *cpp); + /* ignore other soa counters */ + if ((*cpp + (4 * INT32SZ)) < eom) + ns_debug(ns_log_default, 6, + "ixfr: message length > received message"); + /* Reset msglenp to cover just the question. */ + *msglenp = afterq - msg; + } + *cpp = afterq; + + if (!ns_t_udp_p(type)) { /* Refuse request if not a TCP connection. */ if (qsp == NULL) { ns_info(ns_log_default, - "rejected UDP AXFR from %s for \"%s\"", - sin_ntoa(from), *dnbuf ? dnbuf : "."); + "rejected UDP %s from %s for \"%s\"", + p_type(type), sin_ntoa(from), + *dnbuf ? dnbuf : "."); return (Refuse); } /* The position of this is subtle. */ @@ -507,10 +722,11 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, #ifdef QRYLOG if (qrylog) { - ns_info(ns_log_queries, "XX /%s/%s/%s", + ns_info(ns_log_queries, "%s/%s/%s/%s/%s", + (hp->rd) ? "XX+" : "XX ", inet_ntoa(from.sin_addr), (dname[0] == '\0') ? "." : dname, - p_type(type)); + p_type(type), p_class(class)); } #endif /*QRYLOG*/ @@ -542,7 +758,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, struct in_addr ina; if (inet_aton(dname, &ina)) { - hp->rcode = NXDOMAIN; + hp->rcode = ns_r_nxdomain; hp->aa = 1; ns_debug(ns_log_default, 3, "ypkludge: hit as '%s'", dname); @@ -582,10 +798,42 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, zp = &zones[zone]; + ixfr_found = 0; + if (type == ns_t_ixfr && zone != DB_Z_CACHE) { + if (SEQ_GT(serial_ixfr, zp->z_serial)) + ixfr_found = 0; + else { + ixfr_error = ixfr_have_log(zp, serial_ixfr, zp->z_serial); + if (ixfr_error < 0) { + ns_debug(ns_log_default, + 1, "ixfr_have_log(%d %d) failed %d", + serial_ixfr, zp->z_serial, ixfr_error); + ixfr_found = 0; + /* Refuse IXFR and send AXFR */ + type = ns_t_axfr; + } else + ixfr_found = 1; + } + } + /* + * If recursion is turned on, we need to check recursion ACL + * if it exists - and return result to caller. + */ + { + ip_match_list recursion_acl; + + recursion_acl = server_options->recursion_acl; + if (!NS_OPTION_P(OPTION_NORECURSE) && recursion_acl != NULL + && !ip_address_allowed(recursion_acl, from.sin_addr)) { + recursion_blocked_by_acl = 1; + *ra = 0; + } + } + /* * Are queries allowed from this host? */ - if (type != T_AXFR) { + if (!ns_t_xfr_p(type)) { ip_match_list query_acl; if (zp->z_query_acl != NULL) @@ -594,7 +842,52 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, query_acl = server_options->query_acl; if (query_acl != NULL - && !ip_address_allowed(query_acl, from.sin_addr)) { + && !ip_addr_or_key_allowed(query_acl, from.sin_addr, + in_key)) + { + /* + * If this is *not* a zone acl and we would not + * have recursed and we have some answer return + * what we have with a referral. + */ + if ((zp->z_query_acl == NULL) && + (!hp->rd || NS_OPTION_P(OPTION_NORECURSE) || + recursion_blocked_by_acl) && + (ntohs(hp->ancount) != 0)) { + goto fetchns; + } + + /* + * See if we would have made a referral from + * an enclosing zone if we are actually in the + * cache. + */ + if (zp->z_type == z_cache && np != NULL) { + struct namebuf *access_np; + + zone = DB_Z_CACHE; + for (access_np = np; access_np != NULL; + access_np = np_parent(access_np)) { + dp = access_np->n_data; + while (dp && (dp->d_class != class || + dp->d_zone == DB_Z_CACHE)) + dp = dp->d_next; + if (dp != NULL) { + zone = dp->d_zone; + np = access_np; + break; + } + } + zp = &zones[zone]; + if (zp->z_type != z_cache && + zp->z_query_acl != NULL && + ip_addr_or_key_allowed(zp->z_query_acl, + from.sin_addr, in_key) && + (!hp->rd || recursion_blocked_by_acl || + NS_OPTION_P(OPTION_NORECURSE))) { + goto fetchns; + } + } ns_notice(ns_log_security, "unapproved query from %s for \"%s\"", sin_ntoa(from), *dname ? dname : "."); @@ -611,10 +904,23 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, transfer_acl = server_options->transfer_acl; if (transfer_acl != NULL - && !ip_address_allowed(transfer_acl, from.sin_addr)) { + && !ip_addr_or_key_allowed(transfer_acl, from.sin_addr, + in_key)) + { ns_notice(ns_log_security, - "unapproved AXFR from %s for \"%s\" (acl)", - sin_ntoa(from), *dname ? dname : "."); + "unapproved %s from %s for \"%s\" (acl)", + p_type(type), sin_ntoa(from), + *dname ? dname : "."); + return (Refuse); + } + + /* Are we master or slave? */ + + if (zp->z_type != z_master && zp->z_type != z_slave) { + ns_notice(ns_log_security, + "unapproved %s from %s for \"%s\" (not master/slave)", + p_type(type), sin_ntoa(from), + *dname ? dname : "."); return (Refuse); } @@ -622,39 +928,40 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, if ((zp->z_flags & Z_AUTH) == 0) { ns_notice(ns_log_security, - "unapproved AXFR from %s for \"%s\" (not auth)", - sin_ntoa(from), *dname ? dname : "."); + "unapproved %s from %s for \"%s\" (not authoritative)", + p_type(type), sin_ntoa(from), + *dname ? dname : "."); return (Refuse); } /* Is the name at a zone cut? */ - if (strcasecmp(zp->z_origin, dname) != 0) { + if (ns_samename(zp->z_origin, dname) != 1) { ns_notice(ns_log_security, - "unapproved AXFR from %s for \"%s\" (not zone top)", - sin_ntoa(from), *dname ? dname : "."); + "unapproved %s from %s for \"%s\" (not zone top)", + p_type(type), sin_ntoa(from), + *dname ? dname : "."); return (Refuse); } - ns_info(ns_log_security, "approved AXFR from %s for \"%s\"", - sin_ntoa(from), *dname ? dname : "."); + ns_info(ns_log_security, "approved %s from %s for \"%s\"", + p_type(type), sin_ntoa(from), *dname ? dname : "."); } /* * End Access Control Point */ - /* * Yow! */ - if (!strcasecmp(dnbuf, "VERSION.BIND") && - class == C_CHAOS && type == T_TXT) { + if (class == ns_c_chaos && type == ns_t_txt && + ns_samename(dnbuf, "VERSION.BIND") == 1) { u_char *tp; hp->ancount = htons(1); hp->nscount = htons(0); hp->arcount = htons(0); - hp->rcode = NOERROR; + hp->rcode = ns_r_noerror; hp->aa = 1; hp->ra = 0; copyCharString(cpp, "VERSION"); /* Name */ @@ -665,7 +972,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, PUTLONG(0, *cpp); /* TTL */ tp = *cpp; /* Temp RdLength */ PUTSHORT(0, *cpp); - copyCharString(cpp, ShortVersion); + copyCharString(cpp, server_options->version); PUTSHORT((*cpp) - (tp + INT16SZ), tp); /* Real RdLength */ *msglenp = *cpp - msg; /* Total message length */ return (Finish); @@ -682,11 +989,14 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, answers = *cpp; count = *cpp - msg; + /* The response is authoritative until we add insecure data */ + hp->ad = 1; + /* Look for NXDOMAIN record with appropriate class * if found return immediately */ for (dp = np->n_data; dp; dp = dp->d_next) { - if (!stale(dp) && (dp->d_rcode == NXDOMAIN) && + if (!stale(dp) && (dp->d_rcode == ns_r_nxdomain) && (dp->d_class == class)) { #ifdef RETURNSOA n = finddata(np, class, T_SOA, hp, &dname, @@ -700,12 +1010,14 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, } if (hp->rcode == NOERROR_NODATA) { /* this should not occur */ - hp->rcode = NOERROR; + hp->rcode = ns_r_noerror; return (Finish); } } +#else + count = 0; #endif - hp->rcode = NXDOMAIN; + hp->rcode = ns_r_nxdomain; /* * XXX forcing AA all the time isn't right, but * we have to work that way by default @@ -715,7 +1027,10 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, hp->aa = 1; ns_debug(ns_log_default, 3, "NXDOMAIN aa = %d", hp->aa); - return (Finish); + if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1)) + return (Finish); + founddata = 1; + goto fetchns; } } @@ -727,19 +1042,19 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, n = finddata(np, class, type, hp, &dname, buflenp, &count); if (n == 0) { /* - * NO data available. Refuse AXFR requests, or + * NO data available. Refuse transfer requests, or * look for better servers for other requests. */ - if (type == T_AXFR) { + if (ns_t_xfr_p(type)) { ns_debug(ns_log_default, 1, - "T_AXFR refused: no data"); + "transfer refused: no data"); return (Refuse); } goto fetchns; } if (hp->rcode == NOERROR_NODATA) { - hp->rcode = NOERROR; + hp->rcode = ns_r_noerror; #ifdef RETURNSOA if (count) { *cpp += n; @@ -749,7 +1064,10 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, } #endif founddata = 1; - return (Finish); + ns_debug(ns_log_default, 1, "count = %d", count); + if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1)) + return (Finish); + goto fetchns; } *cpp += n; @@ -760,7 +1078,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, if (cname++ >= MAXCNAMES) { ns_debug(ns_log_default, 3, "resp: leaving, MAXCNAMES exceeded"); - hp->rcode = SERVFAIL; + hp->rcode = ns_r_servfail; return (Finish); } goto try_again; @@ -770,11 +1088,46 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, "req: foundname=%d, count=%d, founddata=%d, cname=%d", foundname, count, founddata, cname); - if (type == T_AXFR) { - ns_xfr(qsp, np, zone, class, type, hp->opcode, ntohs(hp->id)); + if (ns_t_xfr_p(type)) { +#ifdef BIND_UPDATE + if ((zp->z_flags & Z_NEED_SOAUPDATE) != 0) + if (incr_serial(zp) < 0) + ns_error(ns_log_default, + "error updating serial number for %s from %d", + zp->z_origin, zp->z_serial); +#endif + /* + * Just return SOA if "up to date". + */ + if (type == ns_t_ixfr) { + hp->aa = 1; + if ((SEQ_GT(serial_ixfr, zp->z_serial) || + serial_ixfr == zp->z_serial)) + return (Finish); + } + + /* + * We don't handle UDP based IXFR queries (yet). + * Tell client to retry with TCP by returning SOA. + */ + if (qsp == NULL) + return (Finish); + else { + if (!ixfr_found) { + qsp->flags |= STREAM_AXFRIXFR; + hp->qdcount = htons(1); + } + ns_xfr(qsp, np, zone, class, type, + hp->opcode, ntohs(hp->id), + serial_ixfr, in_tsig); + } return (Return); } + if (count > 1 && type == T_A && !NS_OPTION_P(OPTION_NORECURSE) && + hp->rd) + sort_response(answers, *cpp, count, &from); + fetchns: /* * If we're already out of room in the response, we're done. @@ -782,6 +1135,9 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, if (hp->tc) return (Finish); + if (hp->ancount == 0) + hp->ad = 0; + /* * Look for name servers to refer to and fill in the authority * section or record the address for forwarding the query @@ -794,7 +1150,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, case NXDOMAIN: /* We are authoritative for this np. */ if (!foundname) - hp->rcode = NXDOMAIN; + hp->rcode = ns_r_nxdomain; ns_debug(ns_log_default, 3, "req: leaving (%s, rcode %d)", dname, hp->rcode); if (class != C_ANY) { @@ -838,21 +1194,29 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, case SERVFAIL: /* We're authoritative but the zone isn't loaded. */ if (!founddata && - !(NS_OPTION_P(OPTION_FORWARD_ONLY) && - server_options->fwdtab)) { - hp->rcode = SERVFAIL; + !(NS_ZOPTION_P(zp, OPTION_FORWARD_ONLY) && + NS_ZFWDTAB(zp))) { + hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } } + if (!founddata && hp->rd && recursion_blocked_by_acl) { + ns_notice(ns_log_security, + "unapproved recursive query from %s for %s", + sin_ntoa(from), *dname ? dname : "."); + } + /* * If we successfully found the answer in the cache, * or this is not a recursive query, or we are purposely - * never recursing, then add the nameserver references - * ("authority section") here and we're done. + * never recursing, or recursion is prohibited by ACL, then + * add the nameserver references("authority section") here + * and we're done. */ - if (founddata || !hp->rd || NS_OPTION_P(OPTION_NORECURSE)) { + if (founddata || !hp->rd || NS_OPTION_P(OPTION_NORECURSE) + || recursion_blocked_by_acl) { /* * If the qtype was NS, and the np of the authority is * the same as the np of the data, we don't need to add @@ -867,7 +1231,8 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, } *cpp += n; *buflenp -= n; - hp->nscount = htons((u_int16_t)count); + hp->nscount = htons(ntohs(hp->nscount) + + (u_int16_t)count); } free_nsp(nsp); @@ -886,29 +1251,31 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, omsg = (u_char *)memget((unsigned) *msglenp); if (omsg == NULL) { ns_info(ns_log_default, "ns_req: Out Of Memory"); - hp->rcode = SERVFAIL; + hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } id = hp->id; omsglen = *msglenp; memcpy(omsg, msg, omsglen); - n = res_mkquery(QUERY, dname, class, type, - NULL, 0, NULL, msg, - *msglenp + *buflenp); + n = res_nmkquery(&res, QUERY, dname, class, type, + NULL, 0, NULL, msg, + *msglenp + *buflenp); if (n < 0) { ns_info(ns_log_default, "res_mkquery(%s) failed", dname); - hp->rcode = SERVFAIL; + hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } *msglenp = n; } n = ns_forw(nsp, msg, *msglenp, from, qsp, dfd, &qp, - dname, class, type, np, 0); - if (n != FW_OK && cname) + dname, class, type, np, 0, in_tsig); + if (n != FW_OK && cname) { memput(omsg, omsglen); + omsg = NULL; + } switch (n) { case FW_OK: if (cname) { @@ -931,7 +1298,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, if (NAME(*np)[0] == '\0') { ns_notice(ns_log_default, "ns_req: no address for root server"); - hp->rcode = SERVFAIL; + hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } @@ -961,7 +1328,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, goto fetchns; /* Try again. */ case FW_SERVFAIL: do_servfail: - hp->rcode = SERVFAIL; + hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } @@ -984,11 +1351,7 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, || ntohs(hp->arcount) != 0) { ns_debug(ns_log_default, 1, "FORMERR IQuery header counts wrong"); - hp->qdcount = htons(0); - hp->ancount = htons(0); - hp->nscount = htons(0); - hp->arcount = htons(0); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } @@ -998,14 +1361,14 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, if ((n = dn_skipname(*cpp, eom)) < 0) { ns_debug(ns_log_default, 1, "FORMERR IQuery packet name problem"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } *cpp += n; if (*cpp + 3 * INT16SZ + INT32SZ > eom) { ns_debug(ns_log_default, 1, "FORMERR IQuery message too short"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } GETSHORT(type, *cpp); @@ -1016,7 +1379,7 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, if (*cpp != eom) { ns_debug(ns_log_default, 1, "FORMERR IQuery message length off"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } @@ -1025,10 +1388,18 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, */ switch (type) { case T_A: - if (!NS_OPTION_P(OPTION_FAKE_IQUERY) || dlen != INT32SZ) + if (!NS_OPTION_P(OPTION_FAKE_IQUERY) || dlen != INT32SZ) { + if (dlen != INT32SZ) + ns_warning(ns_log_security, + "bad iquery from %s", + inet_ntoa(from.sin_addr)); return (Refuse); + } break; default: + ns_warning(ns_log_security, + "unsupported iquery type from %s", + inet_ntoa(from.sin_addr)); return (Refuse); } ns_debug(ns_log_default, 1, @@ -1036,8 +1407,12 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, fname = (char *)msg + HFIXEDSZ; alen = (char *)*cpp - fname; - if ((size_t)alen > sizeof anbuf) + if ((size_t)alen > sizeof anbuf) { + ns_warning(ns_log_security, + "bad iquery from %s", + inet_ntoa(from.sin_addr)); return (Refuse); + } memcpy(anbuf, fname, alen); data = anbuf + alen - dlen; *cpp = (u_char *)fname; @@ -1124,7 +1499,7 @@ stale(struct databuf *dp) { zp->z_origin); } zp->z_flags &= ~Z_AUTH; - if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))) { + if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0) { zp->z_time = tt.tv_sec; sched_zone_maint(zp); } @@ -1137,7 +1512,7 @@ stale(struct databuf *dp) { zp->z_origin); } zp->z_flags &= ~Z_AUTH; - if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))) { + if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0) { zp->z_time = tt.tv_sec; sched_zone_maint(zp); } @@ -1146,6 +1521,7 @@ stale(struct databuf *dp) { return (0); case z_hint: + case z_cache: if (dp->d_flags & DB_F_HINT || dp->d_ttl >= (u_int32_t)tt.tv_sec) return (0); @@ -1169,7 +1545,8 @@ stale(struct databuf *dp) { */ int make_rr(const char *name, struct databuf *dp, u_char *buf, - int buflen, int doadd, u_char **comp_ptrs, u_char **edp) + int buflen, int doadd, u_char **comp_ptrs, u_char **edp, + int use_minimum) { u_char *cp; u_char *cp1, *sp; @@ -1177,20 +1554,13 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, int32_t n; int16_t type = dp->d_type; u_int32_t ttl; -#ifdef BIND_UPDATE - u_int32_t serial; -#endif ns_debug(ns_log_default, 5, "make_rr(%s, %lx, %lx, %d, %d) %d zone %d ttl %lu", name, (u_long)dp, (u_long)buf, buflen, doadd, dp->d_size, dp->d_zone, (u_long)dp->d_ttl); - if (dp->d_rcode -#ifdef RETURNSOA - && dp->d_size == 0 -#endif - ) + if (dp->d_rcode && dp->d_size == 0) panic("make_rr: impossible d_rcode value", NULL); zp = &zones[dp->d_zone]; @@ -1202,7 +1572,7 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, } else ttl = dp->d_ttl - (u_int32_t) tt.tv_sec; } else { - if (dp->d_ttl != USE_MINIMUM) + if (dp->d_ttl != USE_MINIMUM && !use_minimum) ttl = dp->d_ttl; else ttl = zp->z_minimum; /* really default */ @@ -1251,9 +1621,11 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, return (-1); PUTSHORT((u_int16_t)n, sp); cp += n; - if (doadd) + if (doadd) { addname((char*)dp->d_data, name, - type, dp->d_class); + type, T_A, dp->d_class); + addname(name, name, type, T_KEY, dp->d_class); + } break; case T_SOA: @@ -1284,6 +1656,8 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, n = 5 * INT32SZ; memcpy(cp, cp1, n); cp += n; + if (doadd) + addname(name, name, type, T_KEY, dp->d_class); } n = (u_int16_t)((cp - sp) - INT16SZ); PUTSHORT((u_int16_t)n, sp); @@ -1389,7 +1763,9 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, cp1 += INT16SZ*2; } - n = dn_comp((char *)cp1, cp, buflen, comp_ptrs, edp); + n = dn_comp((char *)cp1, cp, buflen, + (type == ns_t_mx) ? comp_ptrs : NULL, + (type == ns_t_mx) ? edp : NULL); if (n < 0) return (-1); cp += n; @@ -1398,7 +1774,7 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, n = (u_int16_t)((cp - sp) - INT16SZ); PUTSHORT((u_int16_t)n, sp); if (doadd) - addname((char*)cp1, name, type, dp->d_class); + addname((char*)cp1, name, type, T_A, dp->d_class); break; case T_PX: @@ -1461,7 +1837,32 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, PUTSHORT((u_int16_t)n, sp); break; + case T_NXT: + cp1 = dp->d_data; + n = dn_comp((char *)cp1, cp, buflen, NULL, NULL); + if (n < 0) + return (-1); + + cp += n; + buflen -=n; + cp1 += strlen((char *)cp1) + 1; + + /* copy nxt bit map */ + n = dp->d_size - (u_int16_t)((cp1 - dp->d_data)); + if (n > buflen) + return (-1); /* out of room! */ + memcpy(cp, cp1, n); + cp += n; + buflen -= n; + + n = (u_int16_t)((cp - sp) - INT16SZ); + PUTSHORT((u_int16_t)n, sp); + + break; + default: + if ((type == T_A || type == T_AAAA) && doadd) + addname(name, name, type, T_KEY, dp->d_class); if (dp->d_size > buflen) return (-1); memcpy(cp, dp->d_data, dp->d_size); @@ -1473,13 +1874,13 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, static void addname(const char *dname, const char *rname, - u_int16_t rtype, u_int16_t class) + u_int16_t rtype, u_int16_t type, u_int16_t class) { struct addinfo *ap; int n; for (ap = addinfo, n = addcount; --n >= 0; ap++) - if (strcasecmp(ap->a_dname, dname) == 0) + if (ns_samename(ap->a_dname, dname) == 1 && ap->a_type == type) return; /* add domain name to additional section */ @@ -1488,28 +1889,36 @@ addname(const char *dname, const char *rname, ap->a_dname = savestr(dname, 1); ap->a_rname = savestr(rname, 1); ap->a_rtype = rtype; + ap->a_type = type; ap->a_class = class; } } /* - * Lookup addresses for names in addinfo and put into the message's + * Lookup addresses/keys for names in addinfo and put into the message's * additional section. */ int doaddinfo(HEADER *hp, u_char *msg, int msglen) { - struct namebuf *np; - struct databuf *dp; - struct addinfo *ap; - u_char *cp; + register struct namebuf *np; + register struct databuf *dp; + register struct addinfo *ap; + register u_char *cp; struct hashbuf *htp; const char *fname; - int n, count; + register int n, count; + register int ns_logging; + int finishedA = 0; + int save_addcount = addcount; if (!addcount) return (0); - ns_debug(ns_log_default, 3, "doaddinfo() addcount = %d", addcount); + ns_logging = ns_wouldlog(ns_log_default, 3); + + if (ns_logging) + ns_debug(ns_log_default, 3, + "doaddinfo() addcount = %d", addcount); if (hp->tc) { ns_debug(ns_log_default, 4, @@ -1519,6 +1928,7 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) { count = 0; cp = msg; +loop: for (ap = addinfo; --addcount >= 0; ap++) { int foundany = 0, foundcname = 0, @@ -1526,37 +1936,50 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) { save_msglen = msglen; u_char *save_cp = cp; - ns_debug(ns_log_default, 3, - "do additional \"%s\" (from \"%s\")", - ap->a_dname, ap->a_rname); + if ((finishedA == 1 && ap->a_type == T_A) || + (finishedA == 0 && ap->a_type == T_KEY)) + continue; + if (ns_logging) + ns_debug(ns_log_default, 3, + "do additional \"%s\" (from \"%s\")", + ap->a_dname, ap->a_rname); htp = hashtab; /* because "nlookup" stomps on arg. */ np = nlookup(ap->a_dname, &htp, &fname, 0); if (np == NULL || fname != ap->a_dname) goto next_rr; - ns_debug(ns_log_default, 3, "found it"); + if (ns_logging) + ns_debug(ns_log_default, 3, "found it"); /* look for the data */ - delete_stale(np); + (void)delete_stale(np); for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (dp->d_rcode) continue; - if (match(dp, (int)ap->a_class, T_CNAME) || - match(dp, C_IN, T_CNAME)) { + if ((match(dp, (int)ap->a_class, T_CNAME) && + dp->d_type == T_CNAME) || + (match(dp, C_IN, T_CNAME) && + dp->d_type == T_CNAME)) { foundcname++; break; } - if (!match(dp, (int)ap->a_class, T_A) && + if (ap->a_type == T_A && + !match(dp, (int)ap->a_class, T_A) && !match(dp, C_IN, T_A) && !match(dp, (int)ap->a_class, T_AAAA) && !match(dp, C_IN, T_AAAA)) { continue; } + if (ap->a_type == T_KEY && + !match(dp, (int)ap->a_class, T_KEY) && + !match(dp, C_IN, T_KEY)) + continue; + foundany++; /* * Should be smart and eliminate duplicate * data here. XXX */ if ((n = make_rr(ap->a_dname, dp, cp, msglen, 0, - dnptrs, dnptrs_end)) < 0) { + dnptrs, dnptrs_end, 0)) < 0) { /* truncation in the additional-data section * is not all that serious. we do not set TC, * since the answer and authority sections are @@ -1583,10 +2006,11 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) { } next_rr: if (!NS_OPTION_P(OPTION_NOFETCHGLUE) && - !foundcname && !foundany) { + !foundcname && !foundany && + (ap->a_type == T_A || ap->a_type == T_AAAA)) { /* ask a real server for this info */ - (void) sysquery(ap->a_dname, (int)ap->a_class, T_A, - NULL, 0, QUERY); + (void) sysquery(ap->a_dname, (int)ap->a_class, + ap->a_type, NULL, 0, ns_port, QUERY); } if (foundcname) { if (!haveComplained(nhash(ap->a_dname), @@ -1600,6 +2024,11 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) { freestr(ap->a_dname); freestr(ap->a_rname); } + if (finishedA == 0) { + finishedA = 1; + addcount = save_addcount; + goto loop; /* now do the KEYs... */ + } hp->arcount = htons((u_int16_t)count); return (cp - msg); } @@ -1618,7 +2047,7 @@ doaddauth(HEADER *hp, u_char *cp, int buflen, dnbuf, buflen); return (0); } - n = make_rr(dnbuf, dp, cp, buflen, 1, dnptrs, dnptrs_end); + n = make_rr(dnbuf, dp, cp, buflen, 1, dnptrs, dnptrs_end, 1); if (n <= 0) { ns_debug(ns_log_default, 1, "doaddauth: can't add oversize '%s' (%d) (n=%d)", @@ -1628,6 +2057,8 @@ doaddauth(HEADER *hp, u_char *cp, int buflen, } return (0); } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; hp->nscount = htons(ntohs(hp->nscount) + 1); return (n); } diff --git a/contrib/bind/bin/named/ns_resp.c b/contrib/bind/bin/named/ns_resp.c index 012f89e..d20b1ef 100644 --- a/contrib/bind/bin/named/ns_resp.c +++ b/contrib/bind/bin/named/ns_resp.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_resp.c 4.65 (Berkeley) 3/3/91"; -static char rcsid[] = "$Id: ns_resp.c,v 8.56 1998/03/16 19:40:07 halley Exp $"; +static const char sccsid[] = "@(#)ns_resp.c 4.65 (Berkeley) 3/3/91"; +static const char rcsid[] = "$Id: ns_resp.c,v 8.133 1999/11/05 04:40:57 vixie Exp $"; #endif /* not lint */ /* @@ -82,7 +82,7 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.56 1998/03/16 19:40:07 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -104,6 +104,7 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.56 1998/03/16 19:40:07 halley Exp $"; #include <sys/param.h> #include <sys/socket.h> #include <sys/file.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -122,6 +123,8 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.56 1998/03/16 19:40:07 halley Exp $"; #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" @@ -164,23 +167,27 @@ struct flush_set { static void rrsetadd(struct flush_set *, const char *, struct databuf *), rrsetupdate(struct flush_set *, int flags, - struct sockaddr_in), + struct sockaddr_in, int), flushrrset(struct flush_set *, struct sockaddr_in), - free_flushset(struct flush_set *, int); -static int rrsetcmp(char *, struct db_list *), + free_flushset(struct flush_set *, int), + check_hints(struct flush_set *); +static int rrsetcmp(char *, struct db_list *, struct hashbuf *), check_root(void), check_ns(void), + wanted(const struct databuf *, int, int), + wantedsig(const struct databuf *, int, int), rrextract(u_char *, int, u_char *, struct databuf **, char *, int, struct sockaddr_in, char **); -static void sysnotify_slaves(const char *, const char *, - int, int, int *, int *); -static void sysnotify_ns(const char *, const char *, - int, int, int *, int *); +static void mark_bad(struct qinfo *qp, struct sockaddr_in from); +static void mark_lame(struct qinfo *qp, struct sockaddr_in from); +static void fast_retry(struct qinfo *qp, struct sockaddr_in from); static void add_related_additional(char *); static void free_related_additional(void); static int related_additional(char *); static void freestr_maybe(char **); +static enum ordering match_order(const struct namebuf *, int, int); +static int match_name(const struct namebuf *, const char *, size_t); #define MAX_RELATED 100 @@ -266,18 +273,19 @@ learntFrom(struct qinfo *qp, struct sockaddr_in *server) { } void -ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { +ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) +{ struct qinfo *qp; HEADER *hp; - struct qserv *qs; + struct qserv *qs = NULL; struct databuf *ns, *ns2; - u_char *cp; - u_char *eom = msg + msglen; + u_char *cp, *answers, *eom = msg + msglen; struct flush_set *flushset = NULL; int flushset_size = 0; struct sockaddr_in *nsa; struct databuf *nsp[NSMAX]; int i, c, n, qdcount, ancount, aucount, nscount, arcount, arfirst; + int soacount; u_int qtype, qclass; int restart; /* flag for processing cname response */ int validanswer, dbflags; @@ -286,7 +294,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { int buflen; int newmsglen; char name[MAXDNAME], qname[MAXDNAME], aname[MAXDNAME]; - char msgbuf[MAXDNAME]; + char msgbuf[MAXDNAME+100]; char *dname, tmpdomain[MAXDNAME]; const char *fname; const char *formerrmsg = "brain damage"; @@ -299,6 +307,14 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { struct databuf *dp; int forcecmsg = 0; char *tname = NULL; + int sendto_errno = 0; + int has_tsig, oldqlen; + u_char *oldqbuf; + u_char *smsg; + int smsglen, smsgsize, siglen; + u_char sig[TSIG_SIG_SIZE]; + time_t tsig_time; + DST_KEY *key; nameserIncr(from.sin_addr, nssRcvdR); nsp[0] = NULL; @@ -310,18 +326,39 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { return; } - ns_debug(ns_log_default, 2, "Response (%s %s %s) nsid=%d id=%d", - (qp->q_flags & Q_SYSTEM) ?"SYSTEM" :"USER", - (qp->q_flags & Q_PRIMING) ?"PRIMING" :"NORMAL", - (qp->q_flags & Q_ZSERIAL) ?"ZSERIAL" :"-", - ntohs(qp->q_nsid), ntohs(qp->q_id)); + if (ns_wouldlog(ns_log_default, 2)) { + ns_debug(ns_log_default, 2, "Response (%s %s %s) nsid=%d id=%d", + (qp->q_flags & Q_SYSTEM) ?"SYSTEM" :"USER", + (qp->q_flags & Q_PRIMING) ?"PRIMING" :"NORMAL", + (qp->q_flags & Q_ZSERIAL) ?"ZSERIAL" :"-", + ntohs(qp->q_nsid), ntohs(qp->q_id)); + } + + if (qp->q_nstsig == NULL) + has_tsig = 0; + else { + int ret; + + ret = ns_verify(msg, &msglen, qp->q_nstsig->key, + qp->q_nstsig->sig, qp->q_nstsig->siglen, + NULL, NULL, &tsig_time, 0); + if (ret == 0) + has_tsig = 1; + else { + if (hp->rcode == NOERROR) + hp->rcode = NOTAUTH; + ns_debug(ns_log_default, 1, + "resp: error bad tsig, record dropped"); + return; + } + } /* * Here we handle high level formatting problems by parsing the header. */ qdcount = ntohs(hp->qdcount); ancount = ntohs(hp->ancount); - aucount = ntohs(hp->nscount); /* !!! */ + aucount = ntohs(hp->nscount); arcount = ntohs(hp->arcount); free_addinfo(); /* sets addcount to zero */ cp = msg + HFIXEDSZ; @@ -343,7 +380,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { } GETSHORT(qtype, cp); GETSHORT(qclass, cp); - if (!ns_nameok(qname, qclass, NULL, response_trans, + if (!ns_nameok(qp, qname, qclass, NULL, response_trans, ns_ownercontext(qtype, response_trans), qname, from.sin_addr)) { formerrmsg = badNameFound; @@ -362,7 +399,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { formerrmsg = msgbuf; goto formerr; } - if (strcasecmp(qp->q_name, qname) != 0 || + if (ns_samename(qp->q_name, qname) != 1 || qp->q_class != qclass || qp->q_type != qtype) { formerrmsg = wrongQuestion; @@ -405,20 +442,11 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { nameserIncr(from.sin_addr, nssRcvdErr); break; } - /* mark server as bad */ - if (!qp->q_fwd) - for (i = 0; i < (int)qp->q_naddr; i++) - if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, - from.sin_addr)) - qp->q_addr[i].nretry = MAXRETRY; - /* - * XXX: doesn't handle responses sent from the wrong - * interface on a multihomed server. - */ - if (qp->q_fwd || - ina_equal(qp->q_addr[qp->q_curaddr].ns_addr.sin_addr, - from.sin_addr)) - retry(qp); + if (ns_samename(qp->q_name, qp->q_domain) == 1 && + hp->rcode == SERVFAIL && hp->opcode == QUERY) + mark_lame(qp, from); + mark_bad(qp, from); + fast_retry(qp, from); return; } @@ -434,7 +462,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { * might have forwarded the query will be dropped. * XXX - should put this in STATS somewhere. */ - for (fwd = server_options->fwdtab; fwd; fwd = fwd->next) + for (fwd = NS_ZFWDTAB(qp->q_fzone); fwd; fwd = fwd->next) if (ina_equal(fwd->fwdaddr.sin_addr, from.sin_addr)) break; /* @@ -451,9 +479,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { if (fwd == NULL) { struct timeval *stp; - for (n = 0, qs = qp->q_addr; - (u_int)n < qp->q_naddr; - n++, qs++) + for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; n++, qs++) if (ina_equal(qs->ns_addr.sin_addr, from.sin_addr)) break; if ((u_int)n >= qp->q_naddr) { @@ -472,7 +498,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { stp = &qs->stime; /* Handle response from different (untried) interface. */ - if ((qs->ns != NULL) && (stp->tv_sec == 0)) { + if (qs->ns != NULL && stp->tv_sec == 0) { ns = qs->ns; while (qs > qp->q_addr && (qs->stime.tv_sec == 0 || qs->ns != ns)) @@ -498,11 +524,13 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { (tt.tv_usec - stp->tv_usec) / 1000); } - ns_debug(ns_log_default, 3, - "stime %lu/%lu now %lu/%lu rtt %ld", - (u_long)stp->tv_sec, (u_long)stp->tv_usec, - (u_long)tt.tv_sec, (u_long)tt.tv_usec, - (long)rtrip); + if (ns_wouldlog(ns_log_default,3)) { + ns_debug(ns_log_default, 3, + "stime %lu/%lu now %lu/%lu rtt %ld", + (u_long)stp->tv_sec, (u_long)stp->tv_usec, + (u_long)tt.tv_sec, (u_long)tt.tv_usec, + (long)rtrip); + } /* prevent floating point overflow, limit to 1000 sec */ if (rtrip > 1000000) { @@ -534,9 +562,11 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { */ if (ns && qs->ns && (qp->q_nusedns < NSMAX)) { qp->q_usedns[qp->q_nusedns++] = qs->ns; - ns_debug(ns_log_default, 2, - "NS #%d addr %s used, rtt %d", - n, sin_ntoa(qs->ns_addr), ns->d_nstime); + if (ns_wouldlog(ns_log_default,2)) { + ns_debug(ns_log_default, 2, + "NS #%d addr %s used, rtt %d", + n, sin_ntoa(qs->ns_addr), ns->d_nstime); + } } /* @@ -573,9 +603,11 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { if (t > 65535) t = 65535; ns2->d_nstime = (u_int16_t)t; - ns_debug(ns_log_default, 2, "NS #%d %s rtt now %d", n, - sin_ntoa(qs->ns_addr), - ns2->d_nstime); + if (ns_wouldlog(ns_log_default,2)) { + ns_debug(ns_log_default, 2, "NS #%d %s rtt now %d", n, + sin_ntoa(qs->ns_addr), + ns2->d_nstime); + } } } @@ -586,11 +618,91 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { * a NOTIFY-QR is to remove it from the query queue. */ if (hp->opcode == NS_NOTIFY_OP) { + ns_info(ns_log_notify, + "Received NOTIFY answer from %s for \"%s %s %s\"", + inet_ntoa(from.sin_addr), + *(qp->q_name) ? qp->q_name : ".", + p_class(qp->q_class), p_type(qp->q_type)); qremove(qp); return; } #endif + if ((qp->q_flags & Q_ZSERIAL) != 0) { + if (hp->aa && ancount > 0 && hp->rcode == NOERROR && + qtype == T_SOA && (qclass == C_IN || qclass == C_HS)) + { + int n; + u_int type, class, dlen; + u_int32_t serial; + u_char *tp = cp; + u_char *rdatap; + + n = dn_expand(msg, eom, tp, name, sizeof name); + if (n < 0) { + formerrmsg = expandFailedAnswer; + goto formerr; + } + tp += n; /* name */ + if (tp + 3 * INT16SZ + INT32SZ > eom) { + formerrmsg = outofDataAnswer; + goto formerr; + } + GETSHORT(type, tp); /* type */ + GETSHORT(class, tp); /* class */ + tp += INT32SZ; /* ttl */ + GETSHORT(dlen, tp); /* dlen */ + rdatap = tp; /* start of rdata */ + if (!ns_nameok(qp, name, class, NULL, response_trans, + ns_ownercontext(type, response_trans), + name, from.sin_addr)) { + formerrmsg = badNameFound; + goto refused; + } + if (ns_samename(qname, name) != 1 || + qtype != type || qclass != class) { + sprintf(msgbuf, + "qserial answer mismatch (%s %s %s)", + name, p_class(class), p_type(type)); + formerrmsg = msgbuf; + goto formerr; + } + if (0 >= (n = dn_skipname(tp, eom))) { + formerrmsg = skipnameFailedAnswer; + goto formerr; + } + tp += n; /* mname */ + if (0 >= (n = dn_skipname(tp, eom))) { + formerrmsg = skipnameFailedAnswer; + goto formerr; + } + tp += n; /* rname */ + if (tp + 5 * INT32SZ > eom) { + formerrmsg = dlenUnderrunAnswer; + goto formerr; + } + GETLONG(serial, tp); + tp += 4 * INT32SZ; /* Skip rest of SOA. */ + if ((u_int)(tp - rdatap) != dlen) { + formerrmsg = dlenOverrunAnswer; + goto formerr; + } + for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; + n++, qs++) + if (ina_equal(qs->ns_addr.sin_addr, + from.sin_addr)) + break; + if (n == qp->q_naddr) { + qserial_answer(qp); + qremove(qp); + return; + } + qs->serial = serial; + } + retry(qp); + return; + } + /* * Non-authoritative, no answer, no error, with referral. */ @@ -603,7 +715,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { int type, class; #ifdef DEBUG if (debug > 0) - fp_nquery(msg, msglen, log_get_stream(packet_channel)); + res_pquery(&res, msg, msglen, + log_get_stream(packet_channel)); #endif /* * Since there is no answer section (ancount == 0), @@ -622,7 +735,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { } GETSHORT(type, tp); GETSHORT(class, tp); - if (!ns_nameok(name, class, NULL, response_trans, + if (!ns_nameok(qp, name, class, NULL, response_trans, ns_ownercontext(type, response_trans), name, from.sin_addr)) { formerrmsg = badNameFound; @@ -638,14 +751,10 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { * classes tend to not have good strong delegation graphs). */ - if (type == T_NS && samedomain(qp->q_domain, name)) { + if (type == T_NS && ns_samedomain(qp->q_domain, name)) { nameserIncr(from.sin_addr, nssRcvdLDel); - /* mark server as bad */ - if (!qp->q_fwd) - for (i = 0; i < (int)qp->q_naddr; i++) - if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, - from.sin_addr)) - qp->q_addr[i].nretry = MAXRETRY; + mark_lame(qp, from); + mark_bad(qp, from); if (class == C_IN && !haveComplained(ina_ulong(from.sin_addr), nhash(qp->q_domain))) { @@ -661,92 +770,21 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { freestr(learnt_from); } - /* XXX - doesn't handle responses sent from the wrong - * interface on a multihomed server - */ - if (qp->q_fwd || - ina_equal(qp->q_addr[qp->q_curaddr].ns_addr.sin_addr, - from.sin_addr)) - retry(qp); + fast_retry(qp, from); return; } } - if (qp->q_flags & Q_ZSERIAL) { - if (hp->aa && ancount > 0 && hp->rcode == NOERROR && - qtype == T_SOA && ((qclass == C_IN) || (qclass == C_HS))) - { - int n; - u_int type, class, dlen; - u_int32_t serial; - u_char *tp = cp; - u_char *rdatap; - - n = dn_expand(msg, eom, tp, name, sizeof name); - if (n < 0) { - formerrmsg = expandFailedAnswer; - goto formerr; - } - tp += n; /* name */ - if (tp + 3 * INT16SZ + INT32SZ > eom) { - formerrmsg = outofDataAnswer; - goto formerr; - } - GETSHORT(type, tp); /* type */ - GETSHORT(class, tp); /* class */ - tp += INT32SZ; /* ttl */ - GETSHORT(dlen, tp); /* dlen */ - rdatap = tp; /* start of rdata */ - if (!ns_nameok(name, class, NULL, response_trans, - ns_ownercontext(type, response_trans), - name, from.sin_addr)) { - formerrmsg = badNameFound; - goto refused; - } - if (strcasecmp(qname, name) || - qtype != type || - qclass != class) { - sprintf(msgbuf, - "qserial answer mismatch (%s %s %s)", - name, p_class(class), p_type(type)); - formerrmsg = msgbuf; - goto formerr; - } - if (0 >= (n = dn_skipname(tp, eom))) { - formerrmsg = skipnameFailedAnswer; - goto formerr; - } - tp += n; /* mname */ - if (0 >= (n = dn_skipname(tp, eom))) { - formerrmsg = skipnameFailedAnswer; - goto formerr; - } - tp += n; /* rname */ - if (tp + 5 * INT32SZ > eom) { - formerrmsg = dlenUnderrunAnswer; - goto formerr; - } - GETLONG(serial, tp); - tp += 4 * INT32SZ; /* Skip rest of SOA. */ - if ((u_int)(tp - rdatap) != dlen) { - formerrmsg = dlenOverrunAnswer; - goto formerr; - } - - qserial_answer(qp, serial, from); - qremove(qp); - } else { - retry(qp); - } - return; - } - /* * Add the info received in the response to the data base. */ arfirst = ancount + aucount; c = arfirst + arcount; + /* Don't return if it's a TSIG signed truncated message */ + if (has_tsig > 0 && hp->tc) + goto tcp_retry; + /* -ve $ing non-existence of record, must handle non-authoritative * NOERRORs with c == 0. */ @@ -769,11 +807,47 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { count -= ancount; /* things are pretty grim */ } +tcp_retry: /* retry using tcp provided this was not a tcp query */ if (!(qp->q_flags & Q_USEVC)) { qp->q_flags |= Q_USEVC; unsched(qp); schedretry(qp, 60); + + nsa = Q_NEXTADDR(qp, 0); + + key = tsig_key_from_addr(nsa->sin_addr); + if (key != NULL) { + smsgsize = qp->q_msglen + TSIG_BUF_SIZE; + smsg = memget(smsgsize); + smsglen = qp->q_msglen; + siglen = sizeof(sig); + memcpy(smsg, qp->q_msg, qp->q_msglen); + n = ns_sign(smsg, &smsglen, smsgsize, + NOERROR, key, NULL, 0, + sig, &siglen, 0); + if (n == 0) { + oldqbuf = qp->q_msg; + oldqlen = qp->q_msglen; + qp->q_msglen = smsglen; + qp->q_msg = smsg; + has_tsig = 1; + qp->q_nstsig = new_tsig(key, sig, + siglen); + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + INSIST(0); + } + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + } + if (tcp_send(qp) != NOERROR) /* * We're probably in trouble if tcp_send @@ -781,6 +855,12 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { * there isn't anything else to do. */ retry(qp); + + if (has_tsig == 1) { + memput(qp->q_msg, smsgsize); + qp->q_msg = oldqbuf; + qp->q_msglen = oldqlen; + } return; } else if (!qsp) { /* outstanding udp response */ @@ -789,15 +869,11 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { /* XXX truncated tcp response */ ns_error(ns_log_default, - "ns_resp: TCP truncated: \"%s\" %s %s", - qname, p_class(qclass), p_type(qtype)); + "ns_resp: TCP truncated: \"%s\" %s %s from %s", + qname, p_class(qclass), p_type(qtype), + sin_ntoa(from)); /* mark this server as bad */ - if (!qp->q_fwd) - for (i = 0; i < (int)qp->q_naddr; i++) - if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, - from.sin_addr)) - qp->q_addr[i].nretry = MAXRETRY; - + mark_bad(qp, from); /* try another server, it may have a bigger write buffer */ retry(qp); return; @@ -808,6 +884,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { restart = 0; validanswer = 0; nscount = 0; + soacount = 0; cname = 0; lastwascname = 0; externalcname = 0; @@ -854,7 +931,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { type = dp->d_type; if (i < ancount) { /* Answer section. */ - if (externalcname || strcasecmp(name, aname) != 0) { + if (externalcname || ns_samename(name, aname) != 1) { if (!externalcname) ns_info(ns_log_resp_checks, "wrong ans. name (%s != %s)", @@ -870,7 +947,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { if (type == T_CNAME && qtype != T_CNAME && qtype != T_ANY) { strcpy(aname, (char *)dp->d_data); - if (!samedomain(aname, qp->q_domain)) + if (!ns_samedomain(aname, qp->q_domain)) externalcname = 1; cname++; lastwascname = 1; @@ -884,7 +961,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { tname = NULL; } - dp->d_cred = (hp->aa && !strcasecmp(name, qname)) + dp->d_cred = (hp->aa && ns_samename(name, qname) == 1) ? DB_C_AUTH : DB_C_ANSWER; } else { @@ -900,14 +977,14 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { switch (type) { case T_NS: case T_SOA: - if (!samedomain(aname, name)){ + if (!ns_samedomain(aname, name)) { ns_info(ns_log_resp_checks, "bad referral (%s !< %s)", aname[0] ? aname : ".", name[0] ? name : "."); db_freedata(dp); continue; - } else if (!samedomain(name, + } else if (!ns_samedomain(name, qp->q_domain)) { if (!externalcname) ns_info(ns_log_resp_checks, @@ -923,6 +1000,9 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { add_related_additional(tname); tname = NULL; } + if (type == T_SOA) { + soacount++; + } break; case T_NXT: /* XXX check */ @@ -939,13 +1019,17 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { db_freedata(dp); continue; } + dp->d_cred = (hp->aa && (cname == 0)) ? + DB_C_AUTH : (qp->q_flags & Q_PRIMING) + ? DB_C_ANSWER + : DB_C_ADDITIONAL; } else { /* Additional section. */ switch (type) { case T_A: case T_AAAA: if (externalcname || - !samedomain(name, qp->q_domain)) { + !ns_samedomain(name, qp->q_domain)) { ns_debug(ns_log_resp_checks, 3, "ignoring additional info '%s' type %s", name, p_type(type)); @@ -980,21 +1064,29 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { db_freedata(dp); continue; } + dp->d_cred = (qp->q_flags & Q_PRIMING) + ? DB_C_ANSWER + : DB_C_ADDITIONAL; } - dp->d_cred = (qp->q_flags & Q_PRIMING) - ? DB_C_ANSWER - : DB_C_ADDITIONAL; } rrsetadd(flushset, name, dp); } free_related_additional(); freestr_maybe(&tname); if (flushset != NULL) { - rrsetupdate(flushset, dbflags, from); + if ((qp->q_flags & Q_SYSTEM) && (qp->q_flags & Q_PRIMING)) { + check_hints(flushset); /* before rrsetupdate */ + rrsetupdate(flushset, dbflags, from, 1); + } else + rrsetupdate(flushset, dbflags, from, 0); free_flushset(flushset, flushset_size); } if (lastwascname && !externalcname) - ns_info(ns_log_cname, "%s (%s)", danglingCname, aname); + ns_debug(ns_log_cname, 3, "%s (%s) q(%s %s %s) %s qd(%s)", + danglingCname, aname, + (qname && *qname) ? qname : ".", + p_class(qclass), p_type(qtype), + sin_ntoa(from), qp->q_domain); if (cp > eom) { formerrmsg = outofDataAFinal; @@ -1004,18 +1096,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { if ((qp->q_flags & Q_SYSTEM) && ancount) { if ((qp->q_flags & Q_PRIMING) && !check_root()) { /* mark server as bad */ - if (!qp->q_fwd) - for (i = 0; i < (int)qp->q_naddr; i++) - if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, - from.sin_addr)) - qp->q_addr[i].nretry = MAXRETRY; - /* XXX - doesn't handle responses sent from - * the wronginterface on a multihomed server - */ - if (qp->q_fwd || - qp->q_addr[qp->q_curaddr].ns_addr.sin_addr.s_addr - == from.sin_addr.s_addr) - retry(qp); + mark_bad(qp, from); + fast_retry(qp, from); return; } ns_debug(ns_log_default, 3, @@ -1024,9 +1106,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { if (qp->q_notifyzone != DB_Z_CACHE) { struct zoneinfo *zp = &zones[qp->q_notifyzone]; - /* Clear this first since sysnotify() might set it. */ qp->q_notifyzone = DB_Z_CACHE; - sysnotify(zp->z_origin, zp->z_class, ns_t_soa); + ns_notify(zp->z_origin, zp->z_class, ns_t_soa); } #endif qremove(qp); @@ -1052,6 +1133,9 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { restart = 1; } + if (!restart && !qp->q_cmsglen && ancount > 1 && qtype == T_A) + sort_response(tp, eom, ancount, &qp->q_from); + /* * An answer to a T_ANY query or a successful answer to a * regular query with no indirection, then just return answer. @@ -1068,11 +1152,19 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { * if ancount != 0 and rcode == NOERROR we cannot determine if the * CNAME chain has been processed to completion or not, so just * restart the query. DNS needs a NODATA return code! + * + * As some servers incorrectly return a NODATA indication when + * there is a CNAME chain instead of NXDOMAIN, we requery to get + * a definitive answer. */ - if (((hp->rcode == NXDOMAIN) && (cname == ancount)) || - ((hp->rcode == NOERROR) && (ancount == 0) && (nscount == 0))) + if ((hp->rcode == NXDOMAIN && cname == ancount) || + (hp->rcode == NOERROR && ancount == 0 && + (nscount == 0 || soacount != 0) + ) + ) { - cache_n_resp(msg, msglen, from); + cache_n_resp(msg, msglen, from, qp->q_name, + qp->q_class, qp->q_type); if (!qp->q_cmsglen) { ns_debug(ns_log_default, 3, @@ -1153,6 +1245,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { goto fetch_ns; foundname++; + answers = cp; count = cp - newmsg; /* * Look for NXDOMAIN record. @@ -1175,6 +1268,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { goto return_newmsg; } } +#else + count = 0; #endif hp->rcode = NXDOMAIN; /* @@ -1186,7 +1281,10 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { hp->aa = 1; ns_debug(ns_log_default, 3, "resp: NXDOMAIN aa = %d", hp->aa); - goto return_newmsg; + if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1)) + goto return_newmsg; + founddata = 1; + goto fetch_ns; } } n = finddata(np, qclass, qtype, hp, &dname, &buflen, &count); @@ -1202,7 +1300,10 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { hp->nscount = htons((u_int16_t)count); } #endif - goto return_newmsg; + if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1)) + goto return_newmsg; + founddata = 1; + goto fetch_ns; } cp += n; buflen -= n; @@ -1217,6 +1318,9 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { "resp: foundname=%d, count=%d, founddata=%d, cname=%d", foundname, count, founddata, cname); + if (count > 1 && qtype == T_A) + sort_response(answers, cp, count, &qp->q_from); + fetch_ns: if (hp->tc) goto return_newmsg; @@ -1256,7 +1360,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { } cp += n; buflen -= n; - hp->nscount = htons((u_int16_t)count); + hp->nscount = htons((u_int16_t)count + ntohs(hp->nscount)); goto return_newmsg; } @@ -1279,17 +1383,20 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { ns_freeqns(qp, "ns_resp"); qp->q_naddr = 0; qp->q_curaddr = 0; - qp->q_fwd = server_options->fwdtab; + nsfwdadd(qp, NS_ZFWDTAB(qp->q_fzone)); if (qp->q_domain != NULL) freestr(qp->q_domain); getname(np, tmpdomain, sizeof tmpdomain); qp->q_domain = savestr(tmpdomain, 1); - if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) { + if (NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) + n = 0; + else if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) { if (n < 0) { - ns_debug(ns_log_default, 3, - "resp: nslookup reports danger"); + if (n == -1) + ns_debug(ns_log_default, 3, + "resp: nslookup reports danger"); if (cname) /* a remote CNAME that does not have data */ goto return_newmsg; goto servfail; @@ -1316,8 +1423,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { } for (n = 0; (u_int)n < qp->q_naddr; n++) qp->q_addr[n].stime.tv_sec = 0; - if (!qp->q_fwd) - qp->q_addr[0].stime = tt; + qp->q_addr[0].stime = tt; if (cname) { if (qp->q_cname++ == MAXCNAMES) { ns_debug(ns_log_default, 3, @@ -1339,8 +1445,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { goto servfail; } qp->q_msgsize = PACKETSZ; - n = res_mkquery(QUERY, dname, qclass, qtype, - NULL, 0, NULL, qp->q_msg, PACKETSZ); + n = res_nmkquery(&res, QUERY, dname, qclass, qtype, + NULL, 0, NULL, qp->q_msg, PACKETSZ); if (n < 0) { ns_info(ns_log_default, "resp: res_mkquery(%s) failed", dname); @@ -1355,23 +1461,55 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { } else hp = (HEADER *) qp->q_msg; hp->id = qp->q_nsid = htons(nsid_next()); - if (qp->q_fwd) + if (qp->q_addr[0].forwarder) hp->rd = 1; unsched(qp); schedretry(qp, retrytime(qp)); nsa = Q_NEXTADDR(qp, 0); - ns_debug(ns_log_default, 1, - "resp: forw -> %s ds=%d nsid=%d id=%d %dms", - sin_ntoa(*nsa), ds, - ntohs(qp->q_nsid), ntohs(qp->q_id), - (qp->q_addr[0].nsdata != NULL) - ? qp->q_addr[0].nsdata->d_nstime - : -1); + if (ns_wouldlog(ns_log_default,1)) { + ns_debug(ns_log_default, 1, + "resp: forw -> %s ds=%d nsid=%d id=%d %dms", + sin_ntoa(*nsa), ds, + ntohs(qp->q_nsid), ntohs(qp->q_id), + (qp->q_addr[0].nsdata != NULL) + ? qp->q_addr[0].nsdata->d_nstime + : -1); + } #ifdef DEBUG if (debug >= 10) - fp_nquery(qp->q_msg, qp->q_msglen, - log_get_stream(packet_channel)); + res_pquery(&res, qp->q_msg, qp->q_msglen, + log_get_stream(packet_channel)); #endif + key = tsig_key_from_addr(nsa->sin_addr); + if (key != NULL) { + smsgsize = qp->q_msglen + TSIG_BUF_SIZE; + smsg = memget(smsgsize); + smsglen = qp->q_msglen; + siglen = sizeof(sig); + memcpy(smsg, qp->q_msg, qp->q_msglen); + n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0, + sig, &siglen, 0); + if (n == 0) { + oldqbuf = qp->q_msg; + oldqlen = qp->q_msglen; + qp->q_msglen = smsglen; + qp->q_msg = smsg; + has_tsig = 1; + qp->q_nstsig = new_tsig(key, sig, siglen); + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + INSIST(0); + } + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + } + if (qp->q_flags & Q_USEVC) { if (tcp_send(qp) != NOERROR) { if (!haveComplained(ina_ulong(nsa->sin_addr), @@ -1384,23 +1522,38 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { + sendto_errno = errno; if (!haveComplained(ina_ulong(nsa->sin_addr), (u_long)sendtoStr)) ns_info(ns_log_default, "ns_resp: sendto(%s): %s", sin_ntoa(*nsa), strerror(errno)); nameserIncr(nsa->sin_addr, nssSendtoErr); } + if (has_tsig == 1) { + memput(qp->q_msg, smsgsize); + qp->q_msg = oldqbuf; + qp->q_msglen = oldqlen; + } hp->rd = 0; /* leave set to 0 for dup detection */ nameserIncr(nsa->sin_addr, nssSentFwdR); nameserIncr(qp->q_from.sin_addr, nssRcvdFwdR); ns_debug(ns_log_default, 3, "resp: Query sent."); free_nsp(nsp); + switch (sendto_errno) { + case ENETDOWN: + case ENETUNREACH: + case EHOSTDOWN: + case EHOSTUNREACH: + unsched(qp); + schedretry(qp, (time_t) 0); + } return; formerr: if (!haveComplained(ina_ulong(from.sin_addr), (u_long)formerrmsg)) ns_info(ns_log_resp_checks, "Malformed response from %s (%s)", sin_ntoa(from), formerrmsg); + fast_retry(qp, from); free_nsp(nsp); return; @@ -1487,7 +1640,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, { u_char *cp, *eom, *rdatap; u_int class, type, dlen; - int n, n1; + int n, n1, n2; u_int32_t ttl; u_char *cp1, data[MAXDATA*2]; HEADER *hp = (HEADER *)msg; @@ -1507,6 +1660,11 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); GETSHORT(type, cp); GETSHORT(class, cp); + if (class > CLASS_MAX) { + ns_debug(ns_log_default, 3, "bad class in rrextract"); + hp->rcode = FORMERR; + return (-1); + } GETLONG(ttl, cp); if (ttl > MAXIMUM_TTL) { ns_debug(ns_log_default, 5, "%s: converted TTL > %u to 0", @@ -1516,7 +1674,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, GETSHORT(dlen, cp); BOUNDS_CHECK(cp, dlen); rdatap = cp; - if (!ns_nameok(dname, class, NULL, response_trans, + if (!ns_nameok(NULL, dname, class, NULL, response_trans, ns_ownercontext(type, response_trans), dname, from.sin_addr)) { hp->rcode = REFUSED; @@ -1558,6 +1716,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, case T_AAAA: case T_LOC: case T_KEY: + case ns_t_cert: cp1 = cp; n = dlen; cp += n; @@ -1574,7 +1733,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, hp->rcode = FORMERR; return (-1); } - if (!ns_nameok((char *)data, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)data, class, NULL, response_trans, type == T_PTR ?ns_ptrcontext(dname) :domain_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; @@ -1600,7 +1759,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, hp->rcode = FORMERR; return (-1); } - if (!ns_nameok((char *)data, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)data, class, NULL, response_trans, context, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); @@ -1623,7 +1782,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, context = domain_ctx; else context = mailname_ctx; - if (!ns_nameok((char *)cp1, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, context, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); @@ -1679,7 +1838,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, hp->rcode = FORMERR; return (-1); } - if (!ns_nameok((char *)cp1, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, hostname_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); @@ -1718,7 +1877,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, hp->rcode = FORMERR; return (-1); } - if (!ns_nameok((char *)cp1, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, hostname_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); @@ -1749,7 +1908,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, hp->rcode = FORMERR; return (-1); } - if (!ns_nameok((char *)cp1, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, domain_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); @@ -1766,7 +1925,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, hp->rcode = FORMERR; return (-1); } - if (!ns_nameok((char *)cp1, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, domain_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); @@ -1779,13 +1938,16 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, case T_SIG: { u_long origTTL, exptime, signtime, timetilexp, now; + u_int8_t alg; /* Check signature time, expiration, and adjust TTL. */ /* This code is similar to that in db_load.c. */ - /* Skip coveredType, alg, labels */ + /* Skip coveredType, save alg, skip labels */ BOUNDS_CHECK(cp, INT16SZ + 1 + 1 + 3*INT32SZ); - cp1 = cp + INT16SZ + 1 + 1; + cp1 = cp + INT16SZ; + alg = *cp1++; + cp1++; GETLONG(origTTL, cp1); GETLONG(exptime, cp1); GETLONG(signtime, cp1); @@ -1836,7 +1998,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, /* then the signer's name */ n = dn_expand(msg, eom, cp, (char *)cp1, (sizeof data) - 18); - if (n < 0) { + if (n < 0 || n + NS_SIG_SIGNER > dlen) { hp->rcode = FORMERR; return (-1); } @@ -1845,15 +2007,31 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, /* finally, we copy over the variable-length signature. Its size is the total data length, minus what we copied. */ - if (18 + (u_int)n > dlen) { - hp->rcode = FORMERR; - return (-1); - } - n = dlen - (18 + n); - if (n > ((int)(sizeof data) - (int)(cp1 - (u_char *)data))) { + n = dlen - (NS_SIG_SIGNER + n); + + if (n > (sizeof data) - (cp1 - (u_char *)data)) { hp->rcode = FORMERR; return (-1); /* out of room! */ } + + switch (alg) { + case NS_ALG_MD5RSA: + if (n < NS_MD5RSA_MIN_SIZE || n > NS_MD5RSA_MAX_SIZE) + hp->rcode = FORMERR; + break; + + case NS_ALG_DSA: + if (n != NS_DSA_SIG_SIZE) + hp->rcode = FORMERR; + break; + + default: + break; + } + + if (hp->rcode == FORMERR) + return (-1); + memcpy(cp1, cp, n); cp += n; cp1 += n; @@ -1864,6 +2042,63 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, break; } + case T_NXT: + n = dn_expand(msg, eom, cp, (char *)data, sizeof data); + /* + * By testing if n >= dlen, we are requiring that the type + * bitmap be at least one octet. This is reasonable + * because we always have to look at the 0 bit to see if + * this is a "different format" NXT or not. + */ + if (n < 0 || n >= dlen) { + hp->rcode = FORMERR; + return (-1); + } + if (!ns_nameok(NULL, (char *)data, class, NULL, response_trans, + domain_ctx, dname, from.sin_addr)) { + hp->rcode = FORMERR; + return (-1); + } + cp += n; + n1 = strlen((char *)data) + 1; + cp1 = data + n1; + /* + * We don't need to BOUNDS_CHECK() cp here because we've + * previously checked that 'dlen' bytes are in bounds, and + * we know that n < dlen. + */ + n2 = dlen - n; + /* + * The first bit of the first octet determines the format + * of the NXT record. A format for types >= 128 has not + * yet been defined, so if bit zero is set, we just copy + * what's there because we don't understand it. + */ + if ((*cp & 0x80) == 0) { + /* + * Bit zero is not set; this is an ordinary NXT + * record. The bitmap must be at least 4 octets + * because the NXT bit should be set. It should be + * less than or equal to 16 octets because this NXT + * format is only defined for types < 128. + */ + if (n2 < 4 || n2 > 16) { + hp->rcode = FORMERR; + return (-1); + } + } + if (n2 > sizeof data - n1) { + hp->rcode = FORMERR; + return (-1); + } + memcpy(cp1, cp, n2); + cp += n2; + + /* compute size of data */ + n = cp1 - (u_char *)data; + cp1 = (u_char *)data; + break; + default: ns_debug(ns_log_default, 3, "unknown type %d", type); return ((cp - rrp) + dlen); @@ -1895,17 +2130,25 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, int send_msg(u_char *msg, int msglen, struct qinfo *qp) { + HEADER *hp = (HEADER *) msg; + u_char *oldmsg; + int oldlen; + int msgsize; + int ret; + if (qp->q_flags & Q_SYSTEM) return (1); if (!qp->q_stream && (msglen > PACKETSZ)) msglen = trunc_adjust(msg, msglen, PACKETSZ); - ns_debug(ns_log_default, 1, "send_msg -> %s (%s %d) id=%d", - sin_ntoa(qp->q_from), - qp->q_stream == NULL ? "UDP" : "TCP", - qp->q_stream == NULL ? qp->q_dfd : qp->q_stream->s_rfd, - ntohs(qp->q_id)); + if (ns_wouldlog(ns_log_default, 1)) { + ns_debug(ns_log_default, 1, "send_msg -> %s (%s %d) id=%d", + sin_ntoa(qp->q_from), + qp->q_stream == NULL ? "UDP" : "TCP", + qp->q_stream == NULL ? qp->q_dfd : qp->q_stream->s_rfd, + ntohs(qp->q_id)); + } #ifdef DEBUG - if (debug > 4) { + if (ns_wouldlog(ns_log_default, 4)) { struct qinfo *tqp; for (tqp = nsqhead; tqp != NULL; tqp = tqp->q_link) { @@ -1922,9 +2165,44 @@ send_msg(u_char *msg, int msglen, struct qinfo *qp) { } } if (debug >= 6) - fp_nquery(msg, msglen, log_get_stream(packet_channel)); + res_pquery(&res, msg, msglen, log_get_stream(packet_channel)); #endif /* DEBUG */ + + if (qp->q_tsig != NULL) { + u_char sig[TSIG_SIG_SIZE]; + int siglen = sizeof(sig); + + oldmsg = msg; + oldlen = msglen; + + msgsize = msglen + TSIG_BUF_SIZE; + msg = memget(msgsize); + memcpy(msg, oldmsg, oldlen); + + ret = ns_sign(msg, &msglen, msgsize, NOERROR, qp->q_tsig->key, + qp->q_tsig->sig, qp->q_tsig->siglen, + sig, &siglen, 0); + + if (ret != 0) { + INSIST(0); + } + } + if (qp->q_stream == NULL) { + /* + * Don't send FORMERR to these well known ports + * (loop avoidance). + */ + switch (ntohs(qp->q_from.sin_port)) { + case 7: /* echo */ + case 13: /* daytime */ + case 19: /* chargen */ + case 37: /* time */ + if (hp->rcode == FORMERR) + return (-1); + default: + break; + } if (sendto(qp->q_dfd, (char*)msg, msglen, 0, (struct sockaddr *)&qp->q_from, sizeof(qp->q_from)) < 0) { @@ -1942,232 +2220,78 @@ send_msg(u_char *msg, int msglen, struct qinfo *qp) { } } else writestream(qp->q_stream, (u_char*)msg, msglen); - return (0); -} -#ifdef notdef -/* i don't quite understand this but the only ref to it is notdef'd --vix */ -prime(class, type, oqp) - int class, type; - struct qinfo *oqp; -{ - char dname[MAXDNAME]; + if (qp->q_tsig != NULL) + memput(msg, oldlen + TSIG_BUF_SIZE); - if (oqp->q_msg == NULL) - return; - if (dn_expand((u_char *)oqp->q_msg, - (u_char *)oqp->q_msg + oqp->q_msglen, - (u_char *)oqp->q_msg + HFIXEDSZ, (u_char *)dname, - sizeof(dname)) < 0) - return; - ns_debug(ns_log_default, 2, "prime: %s", dname); - (void) sysquery(dname, class, type, NULL, 0, QUERY); + return (0); } -#endif -void -prime_cache() { - struct qinfo *qp; +static int +root_server_p(ns_class class) { + struct zoneinfo *zp = find_zone("", class); - /* - * XXX - should this always be skipped if OPTION_FORWARD_ONLY - * or should it be another option? What about when we are - * doing selective forwarding? - */ - if (!NS_OPTION_P(OPTION_FORWARD_ONLY)) { - ns_debug(ns_log_default, 1, "prime_cache: priming = %d", - priming); - if (!priming && fcachetab->h_tab[0] != NULL) { - priming++; - if (!(qp = sysquery("", C_IN, T_NS, NULL, 0, QUERY))) - priming = 0; - else - qp->q_flags |= (Q_SYSTEM | Q_PRIMING); - } - } - needs_prime_cache = 0; - return; + return (zp != NULL && + (zp->z_type == z_master || zp->z_type == z_slave)); } -#ifdef BIND_NOTIFY -/* - * sysnotify(dname, class, type) - * cause a NOTIFY request to be sysquery()'d to each secondary server - * of the zone that "dname" is within. - */ void -sysnotify(const char *dname, int class, int type) { - const char *zname, *fname; - int nns, na, zn, n; - struct zoneinfo *zp; - struct hashbuf *htp; - struct namebuf *np; - struct databuf *dp; - - ns_debug(ns_log_notify, 3, "sysnotify(%s, %s, %s)", - dname, p_class(class), p_type(type)); - htp = hashtab; - np = nlookup(dname, &htp, &fname, 0); - if (np == NULL) { - ns_warning(ns_log_notify, "sysnotify: can't find \"%s\"", - dname); - return; - } - zn = findMyZone(np, class); - if (zn == DB_Z_CACHE) { - ns_warning(ns_log_notify, "sysnotify: not auth for zone %s", - dname); - return; - } - zp = &zones[zn]; - if (zp->z_notify == znotify_no || - (zp->z_notify == znotify_use_default && - NS_OPTION_P(OPTION_NONOTIFY))) - return; - if (zp->z_type != z_master && zp->z_type != z_slave) { - ns_warning(ns_log_notify, "sysnotify: %s not master or slave", - dname); - return; - } - zname = zp->z_origin; - nns = na = 0; - if (zp->z_type == z_master) - sysnotify_slaves(dname, zname, class, zn, &nns, &na); - if (zp->z_notify_count != 0) { - struct in_addr *also_addr = zp->z_also_notify; - int i; - - for (i = 0; i < zp->z_notify_count; i++) { - sysquery(dname, class, T_SOA, also_addr, 1, - NS_NOTIFY_OP); - also_addr++; - } - nns += zp->z_notify_count; - na += zp->z_notify_count; - } - if (nns != 0 || na != 0) - ns_info(ns_log_notify, - "Sent NOTIFY for \"%s %s %s\" (%s); %d NS, %d A", - dname, p_class(class), p_type(type), zname, nns, na); -} - -static void -sysnotify_slaves(const char *dname, const char *zname, int class, int zn, - int *nns, int *na) -{ - const char *mname, *fname; - struct hashbuf *htp; - struct namebuf *np; - struct databuf *dp; - - /* - * Master. - */ - htp = hashtab; - np = nlookup(zname, &htp, &fname, 0); - if (!np) { - ns_warning(ns_log_notify, - "sysnotify: found name \"%s\" but not zone", - dname); - return; - } - mname = NULL; - for (dp = np->n_data; dp; dp = dp->d_next) { - if (dp->d_zone == DB_Z_CACHE || !match(dp, class, T_SOA)) - continue; - if (mname) { - ns_notice(ns_log_notify, - "multiple SOA's for zone \"%s\"?", - zname); - return; - } - mname = (char *) dp->d_data; - } - if (mname == NULL) { - ns_notice(ns_log_notify, "no SOA found for zone \"%s\"", - zname); - return; - } - for (dp = np->n_data; dp != NULL; dp = dp->d_next) { - if (dp->d_zone == DB_Z_CACHE || !match(dp, class, T_NS)) - continue; - if (strcasecmp((char*)dp->d_data, mname) == 0) - continue; - sysnotify_ns(dname, (char *)dp->d_data, class, zn, nns, na); - } -} +prime_cache(void) { + int root = root_server_p(ns_c_in); -static void -sysnotify_ns(const char *dname, const char *aname, - int class, int zn, int *nns, int *na) -{ - struct databuf *adp; - struct namebuf *anp; - const char *fname; - struct in_addr nss[NSMAX]; - struct hashbuf *htp; - int is_us, nsc; - - htp = hashtab; - anp = nlookup(aname, &htp, &fname, 0); - nsc = 0; - is_us = 0; - if (anp != NULL) - for (adp = anp->n_data; adp; adp = adp->d_next) { - struct in_addr ina; - - if (!match(adp, class, T_A)) - continue; - ina = ina_get(adp->d_data); - if (aIsUs(ina)) { - is_us = 1; - continue; - } - if (nsc < NSMAX) - nss[nsc++] = ina; - } /*next A*/ - if (nsc == 0) { - if (!is_us) { - struct qinfo *qp; + ns_debug(ns_log_default, 1, "prime_cache: priming = %d, root = %d", + priming, root); + if (!priming && !root) { + struct qinfo *qp = sysquery("", ns_c_in, ns_t_ns, + NULL, 0, ns_port, ns_o_query); - qp = sysquery(aname, class, T_A, 0, 0, QUERY); - if (qp != NULL) - qp->q_notifyzone = zn; + if (qp != NULL) { + qp->q_flags |= (Q_SYSTEM | Q_PRIMING); + priming++; } - return; } - (void) sysquery(dname, class, T_SOA, nss, nsc, NS_NOTIFY_OP); - (*nns)++; - *na += nsc; + needs_prime_cache = 0; } -#endif /*BIND_NOTIFY*/ struct qinfo * sysquery(const char *dname, int class, int type, - struct in_addr *nss, int nsc, int opcode) + struct in_addr *nss, int nsc, u_int16_t port, int opcode) { struct qinfo *qp, *oqp; HEADER *hp; char tmpdomain[MAXDNAME]; - struct namebuf *np; + struct namebuf *np = NULL; struct databuf *nsp[NSMAX]; - struct hashbuf *htp; + struct hashbuf *htp1; + struct hashbuf *htp2; + struct hashbuf *htp3; struct sockaddr_in *nsa; const char *fname; int n, count; + int sendto_errno = 0; + u_char *oldqbuf; + int oldqlen, has_tsig; + u_char *smsg; + int smsglen, smsgsize, siglen; + u_char sig[TSIG_SIG_SIZE]; + DST_KEY *key; nsp[0] = NULL; - ns_debug(ns_log_default, 3, "sysquery(%s, %d, %d, %#x, %d)", - dname, class, type, nss, nsc); + ns_debug(ns_log_default, 3, "sysquery(%s, %d, %d, %#x, %d, %d)", + dname, class, type, nss, nsc, ntohs(port)); qp = qnew(dname, class, type); - if (nss && nsc) + if (nss != NULL && nsc != 0) np = NULL; - else { - htp = hashtab; + else if (!NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) { + htp1 = hashtab; + htp2 = hashtab; + htp3 = fcachetab; if (priming && dname[0] == '\0') { np = NULL; - } else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) { + } else if (((np = nlookup(dname, &htp1, &fname, 0)) == NULL) && + ((np = nlookup("", &htp2, &fname, 0)) == NULL) && + ((np = nlookup("", &htp3, &fname, 0)) == NULL)) { ns_info(ns_log_default, "sysquery: nlookup error on %s?", dname); @@ -2190,13 +2314,11 @@ sysquery(const char *dname, int class, int type, } } - /* build new qinfo struct */ + /* Build new qinfo struct. */ qp->q_cmsg = qp->q_msg = NULL; qp->q_dfd = ds; - if (nss && nsc) - qp->q_fwd = NULL; - else - qp->q_fwd = server_options->fwdtab; + if (nss == NULL || nsc == 0) + nsfwdadd(qp, NS_ZFWDTAB(qp->q_fzone)); qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2; qp->q_flags |= Q_SYSTEM; @@ -2208,9 +2330,9 @@ sysquery(const char *dname, int class, int type, goto err2; } qp->q_msgsize = PACKETSZ; - n = res_mkquery(opcode, dname, class, - type, NULL, 0, NULL, - qp->q_msg, PACKETSZ); + n = res_nmkquery(&res, opcode, dname, class, + type, NULL, 0, NULL, + qp->q_msg, PACKETSZ); if (n < 0) { ns_info(ns_log_default, "sysquery: res_mkquery(%s) failed", dname); @@ -2219,9 +2341,9 @@ sysquery(const char *dname, int class, int type, qp->q_msglen = n; hp = (HEADER *) qp->q_msg; hp->id = qp->q_nsid = htons(nsid_next()); - hp->rd = (qp->q_fwd ? 1 : 0); + hp->rd = (qp->q_addr[qp->q_curaddr].forwarder ? 1 : 0); - /* First check for an already pending query for this data */ + /* First check for an already pending query for this data. */ for (oqp = nsqhead; oqp != NULL; oqp = oqp->q_link) { if ((oqp != qp) && (oqp->q_msglen == qp->q_msglen) @@ -2242,30 +2364,30 @@ sysquery(const char *dname, int class, int type, } } - if (nss && nsc) { + if (nss != NULL && nsc != 0) { int i; struct qserv *qs; - for (i = 0, qs = qp->q_addr; - i < nsc; - i++, qs++) { + for (i = 0, qs = qp->q_addr; i < nsc; i++, qs++) { qs->ns_addr.sin_family = AF_INET; qs->ns_addr.sin_addr = nss[i]; - qs->ns_addr.sin_port = ns_port; + qs->ns_addr.sin_port = port; qs->ns = NULL; qs->nsdata = NULL; qs->stime = tt; + qs->forwarder = 0; qs->nretry = 0; } qp->q_naddr = nsc; - } else { + } else if (!NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) { fetch_a: count = nslookup(nsp, qp, dname, "sysquery"); if (count <= 0) { if (count < 0) { - ns_info(ns_log_default, + if (n == -1) + ns_info(ns_log_default, "sysquery: nslookup reports danger (%s)", - dname); + dname); goto err2; } else if (np && NAME(*np)[0] == '\0') { /* @@ -2303,6 +2425,10 @@ sysquery(const char *dname, int class, int type, n, dname); goto err2; } + getname(np, tmpdomain, sizeof tmpdomain); + if (qp->q_domain != NULL) + freestr(qp->q_domain); + qp->q_domain = savestr(tmpdomain, 1); goto fetch_a; } goto err2; @@ -2310,8 +2436,7 @@ sysquery(const char *dname, int class, int type, } schedretry(qp, retrytime(qp)); - if (qp->q_fwd == NULL) - qp->q_addr[0].stime = tt; /* XXX - why not every? */ + qp->q_addr[0].stime = tt; /* XXX - why not every? */ nsa = Q_NEXTADDR(qp, 0); ns_debug(ns_log_default, 1, @@ -2321,20 +2446,67 @@ sysquery(const char *dname, int class, int type, (long)qp->q_time); #ifdef DEBUG if (debug >= 10) - fp_nquery(qp->q_msg, qp->q_msglen, - log_get_stream(packet_channel)); + res_pquery(&res, qp->q_msg, qp->q_msglen, + log_get_stream(packet_channel)); #endif + + key = tsig_key_from_addr(nsa->sin_addr); + if (key != NULL) { + smsgsize = qp->q_msglen + TSIG_BUF_SIZE; + smsg = memget(smsgsize); + smsglen = qp->q_msglen; + siglen = sizeof(sig); + memcpy(smsg, qp->q_msg, qp->q_msglen); + n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0, + sig, &siglen, 0); + if (n == 0) { + oldqbuf = qp->q_msg; + oldqlen = qp->q_msglen; + qp->q_msglen = smsglen; + qp->q_msg = smsg; + has_tsig = 1; + qp->q_nstsig = new_tsig(key, sig, siglen); /* BEW? */ + + } + else { + INSIST(0); + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + } + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + } + if (sendto(qp->q_dfd, (char*)qp->q_msg, qp->q_msglen, 0, (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { + sendto_errno = errno; if (!haveComplained(ina_ulong(nsa->sin_addr), (u_long)sendtoStr)) ns_info(ns_log_default, "sysquery: sendto(%s): %s", sin_ntoa(*nsa), strerror(errno)); nameserIncr(nsa->sin_addr, nssSendtoErr); } + if (has_tsig == 1) { + memput(qp->q_msg, smsgsize); + qp->q_msg = oldqbuf; + qp->q_msglen = oldqlen; + } + nameserIncr(nsa->sin_addr, nssSentSysQ); free_nsp(nsp); + switch (sendto_errno) { + case ENETDOWN: + case ENETUNREACH: + case EHOSTDOWN: + case EHOSTUNREACH: + unsched(qp); + schedretry(qp, (time_t) 0); + } return (qp); } @@ -2360,7 +2532,7 @@ check_root() { if (dp->d_type == T_NS) count++; ns_debug(ns_log_default, 1, "%d root servers", count); - if (count < MINROOTS) { + if (count < server_options->minroots) { ns_notice(ns_log_default, "check_root: %d root servers after query to root server < min", count); @@ -2429,12 +2601,12 @@ check_ns() { "check_ns: %s: not found %s %#lx", dname, fname, (u_long)tnp); sysquery(dname, dp->d_class, T_A, NULL, - 0, QUERY); + 0, ns_port, QUERY); continue; } /* look for name server addresses */ found_arr = 0; - delete_stale(tnp); + (void)delete_stale(tnp); for (tdp = tnp->n_data; tdp != NULL; tdp = tdp->d_next) { @@ -2463,7 +2635,7 @@ check_ns() { NAME(*np), NAME(*tnp)); else sysquery(dname, dp->d_class, T_A, NULL, - 0, QUERY); + 0, ns_port, QUERY); } } @@ -2530,7 +2702,7 @@ findns(struct namebuf **npp, int class, if (dp->d_zone != DB_Z_CACHE && ((zones[dp->d_zone].z_type == Z_PRIMARY) || (zones[dp->d_zone].z_type == Z_SECONDARY)) && - match(dp, class, T_SOA)) { + match(dp, class, T_SOA) && dp->d_type == T_SOA) { ns_debug(ns_log_default, 3, "findns: SOA found"); if (zones[dp->d_zone].z_flags & Z_AUTH) { @@ -2552,7 +2724,7 @@ findns(struct namebuf **npp, int class, /* If no SOA records, look for NS records. */ nspp = &nsp[0]; *nspp = NULL; - delete_stale(np); + (void)delete_stale(np); for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!match(dp, class, T_NS)) continue; @@ -2630,46 +2802,48 @@ finddata(struct namebuf *np, int class, int type, struct databuf *dp; char *cp; int buflen, n, count = 0; + char *new_dnamep = NULL; + int defer = 0, found_count = 0, choice, i; + struct databuf **found = NULL; + struct databuf **tmpfound = NULL; + int foundcname; + int stalecount; + int ret = 0; + + stalecount = delete_stale(np); + + /* We don't want to return cached SIG records when asked for SIGs, + * since we may have an incomplete set. + */ + if (type == T_SIG && findMyZone(np, class) == DB_Z_CACHE) + return(0); - delete_stale(np); - -#ifdef ROUND_ROBIN - if (type != T_ANY && type != T_PTR) { - /* cycle order of RRs, for a load balancing effect... */ - - struct databuf **dpp; - - for (dpp = &np->n_data; (dp = *dpp) != NULL; - dpp = &dp->d_next) { - if (dp->d_next && wanted(dp, class, type)) { - struct databuf *lp; - - *dpp = lp = dp->d_next; - dp->d_next = NULL; - - for (dpp = &lp->d_next; - *dpp; - dpp = &lp->d_next) - lp = *dpp; - *dpp = dp; - break; - } - } + if (type != T_ANY && type != T_PTR && type != T_NXT) { + found = memget((stalecount + 1) * sizeof *found); + tmpfound = memget((stalecount + 1) * sizeof *tmpfound); + if (found == NULL || tmpfound == NULL) + ns_panic(ns_log_default, 1, "finddata: out of memory"); + defer = 1; } -#endif /*ROUND_ROBIN*/ buflen = *lenp; + #ifdef DEBUG if (buflen > PACKETSZ) ns_debug(ns_log_default, 1, "finddata(): buflen=%d", buflen); #endif cp = ((char *)hp) + *countp; + foundcname = 0; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!wanted(dp, class, type)) { if (type == T_CNAME && class == dp->d_class) { /* any data means no CNAME exists */ - *countp = 0; - return 0; + if (dp->d_type != T_NXT && + dp->d_type != T_KEY && + dp->d_type != T_SIG) { + ret = 0; + goto done; + } } continue; } @@ -2706,8 +2880,8 @@ finddata(struct namebuf *np, int class, int type, continue; hp->rcode = NOERROR_NODATA; if (dp->d_size == 0) { /* !RETURNSOA */ - *countp = 0; - return 1; /* XXX - we have to report success */ + ret = 1; + goto done; } } if (dp->d_rcode == NXDOMAIN) { @@ -2722,8 +2896,8 @@ finddata(struct namebuf *np, int class, int type, } hp->rcode = NXDOMAIN; if (dp->d_size == 0) { /* !RETURNSOA */ - *countp = 0; - return 1; /* XXX - we have to report success */ + ret = 1; + goto done; } } @@ -2733,49 +2907,285 @@ finddata(struct namebuf *np, int class, int type, (!((dp->d_type == T_SIG) || (dp->d_type == T_KEY))) ) continue; - if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1, - dnptrs, dnptrs_end)) < 0) { - hp->tc = 1; - *countp = count; - return (*lenp - buflen); - } + if (!defer) { + if (foundcname != 0 && dp->d_type == T_CNAME) + continue; - cp += n; - buflen -= n; - count++; -#ifdef notdef - /* this isn't right for glue records, aa is set in ns_req */ - if (dp->d_zone != DB_Z_CACHE && - (zones[dp->d_zone].z_flags & Z_AUTH) != 0 && - class != C_ANY) - hp->aa = 1; /* XXX */ -#endif - if (dp->d_type == T_CNAME) { + if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1, + dnptrs, dnptrs_end, 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + + if (dp->d_type == T_CNAME) { + foundcname = 1; +#define FOLLOWCNAME(type) \ + (type != T_KEY) && (type != T_SIG) && (type != T_NXT) && (type != T_ANY) /* don't alias if querying for key, sig, nxt, or any */ - if ((type != T_KEY) && - (type != T_SIG) && - (type != T_NXT) && - (type != T_ANY)) { /* or T_NS? */ - *dnamep = (caddr_t) dp->d_data; + + if (FOLLOWCNAME(type)) + new_dnamep = (char *)dp->d_data; } - break; + } else { + if (dp->d_type == T_CNAME) + foundcname = 1; + found[found_count++] = dp; } } + + if (found_count == 0 && count == 0) { + ret = 0; + goto done; + } + /* - * Cache invalidate the other RR's of same type - * if some have timed out + * If the query type was SIG or ANY we will have returned the SIG + * records already. */ + if (type != T_SIG && type != T_ANY) { + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + if (!wantedsig(dp, class, type)) + continue; + if (dp->d_cred == DB_C_ADDITIONAL) { +#ifdef NOADDITIONAL + continue; +#else + /* we want to expire additional data very + * quickly. current strategy is to cut 5% + * off each time it is accessed. this makes + * stale(dp) true earlier when this datum is + * used often. + */ + dp->d_ttl = tt.tv_sec + + + 0.95 * (int) (dp->d_ttl - tt.tv_sec); +#endif + } + if (!defer) { + if ((n = make_rr(*dnamep, dp, (u_char *)cp, + buflen, 1, dnptrs, dnptrs_end, + 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + } else + found[found_count++] = dp; + } + } + + if (defer && found_count > 0) { + int first_sig; + int non_sig_count; + int sig_count; /* number of SIG records in found */ + int idx, jdx; + enum ordering order; + + order = match_order(np, class, foundcname ? T_CNAME : type); + + /* shuffle the SIG records down to the bottom of the array + * as we need to make sure they get packed last, no matter + * what the ordering is. We're sure to maintain the + * original ordering within the two sets of records (so + * that fixed_order can work). + * First we pack the non-SIG records into the temp array. + */ + for (idx = jdx = 0 ; idx < found_count ; idx++) { + if (found[idx]->d_type != T_SIG) { + tmpfound[jdx++] = found[idx]; + } + } + non_sig_count = jdx; + sig_count = found_count - jdx; + first_sig = jdx ; + + /* now shift the SIG records down to the end of the array + * and copy in the non-SIG records + */ + for (i = idx = found_count - 1 ; idx >= 0 ; idx--) { + if (i < non_sig_count) { + found[i] = tmpfound[i]; + i--; + } else if (found[idx]->d_type == T_SIG) { + found[i--] = found[idx] ; + } + } + + foundcname = 0; + switch (order) { + case fixed_order: + for (i = 0; i < found_count; i++) { + dp = found[i]; + if (foundcname != 0 && dp->d_type == T_CNAME) + continue; + if (dp->d_type == T_CNAME) { + foundcname = 1; + if (FOLLOWCNAME(type)) { + new_dnamep = (char *)dp->d_data; + } + } + if ((n = make_rr(*dnamep, dp, (u_char *)cp, + buflen, 1, + dnptrs, dnptrs_end, 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + } + break; + + case random_order: { + /* first we shuffle the non-SIG records */ + int iters = non_sig_count; + for (i = 0; i < iters; i++) { + choice = ((u_int)rand()>>3) % non_sig_count; + non_sig_count--; + dp = found[choice]; + found[choice] = found[non_sig_count]; + if (foundcname != 0 && dp->d_type == T_CNAME) + continue; + if (dp->d_type == T_CNAME) { + foundcname = 1; + if (FOLLOWCNAME(type)) { + new_dnamep = (char *)dp->d_data; + } + } + if ((n = make_rr(*dnamep, dp, (u_char *)cp, + buflen, 1, + dnptrs, dnptrs_end, 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + } + + /* now shuffle the SIG records */ + iters = sig_count; + for (i = 0; i < iters; i++) { + choice = ((u_int)rand()>>3) % sig_count; + choice += first_sig; + sig_count--; + dp = found[choice]; + found[choice] = found[sig_count + first_sig]; + if ((n = make_rr(*dnamep, dp, (u_char *)cp, + buflen, 1, + dnptrs, dnptrs_end, 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + } + break; + } + + case cyclic_order: + /* first we do the non-SIG records */ + choice = ((u_int)rand()>>3) % non_sig_count; + for (i = 0; i < non_sig_count ; i++) { + dp = found[(i + choice) % non_sig_count]; + if (foundcname != 0 && dp->d_type == T_CNAME) + continue; + if (dp->d_type == T_CNAME) { + foundcname = 1; + if (FOLLOWCNAME(type)) { + new_dnamep = (char *)dp->d_data; + } + } + if ((n = make_rr(*dnamep, dp, (u_char *)cp, + buflen, 1, + dnptrs, dnptrs_end, 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + } + + /* now do the SIG record rotation. */ + if (sig_count > 0) { + choice = ((u_int)rand()>>3) % sig_count; + choice += first_sig; + i = choice; + do { + dp = found[i]; + if ((n = make_rr(*dnamep, dp, + (u_char *)cp, + buflen, 1, + dnptrs, + dnptrs_end, 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + i++; + if (i >= found_count) + i = first_sig; + } while (i != choice); + } + + break; + + default: + ns_warning(ns_log_default, "finddata: unknown ordering: %d", + order); + break; + } + } + + if (new_dnamep != NULL) + *dnamep = new_dnamep; + ns_debug(ns_log_default, 3, "finddata: added %d class %d type %d RRs", count, class, type); + ret = *lenp - buflen; + done: + if (found != NULL) + memput(found, (stalecount + 1) * sizeof *found); + if (tmpfound != NULL) + memput(tmpfound, (stalecount + 1) * sizeof *tmpfound); *countp = count; - return (*lenp - buflen); + return (ret); } /* * Do we want this data record based on the class and type? - * (We always return found unexpired SIG RR's that cover the wanted rrtype.) */ -int +static int wanted(const struct databuf *dp, int class, int type) { const u_char *cp; int coveredType; @@ -2818,7 +3228,7 @@ wanted(const struct databuf *dp, int class, int type) { cp += INT16SZ + INT32SZ; /* skip alg, labels, & orig TTL */ GETLONG(expiration,cp); - if (type == T_ANY || type == T_SIG || type == coveredType) { + if (type == T_ANY || type == T_SIG) { if (expiration > time(0)) return (1); /* Unexpired matching SIG */ } @@ -2833,11 +3243,9 @@ wanted(const struct databuf *dp, int class, int type) { break; } /* OK, now look at the type of query. */ - switch (type) { - case T_ANY: + if (type == ns_t_any) return (1); - - case T_MAILB: + else if (type == ns_t_mailb) switch (dp->d_type) { case T_MR: case T_MB: @@ -2845,14 +3253,57 @@ wanted(const struct databuf *dp, int class, int type) { case T_MINFO: return (1); } - break; - - case T_AXFR: - /* T_AXFR needs an authoritative SOA */ - if (dp->d_type == T_SOA && dp->d_zone != DB_Z_CACHE + else if (ns_t_xfr_p(type)) { + /* + * This is used to validate transfer requests, not + * generate transfer responses. Is there an SOA? + */ + if (dp->d_type == ns_t_soa && dp->d_zone != DB_Z_CACHE && (zones[dp->d_zone].z_flags & Z_AUTH)) return (1); - break; + } + return (0); +} + +static int +wantedsig(const struct databuf *dp, int class, int type) { + const u_char *cp; + int coveredType; + time_t expiration; +#ifdef DEBUG + char pclass[15], ptype[15]; +#endif + +#ifdef DEBUG + strcpy(pclass, p_class(class)); + strcpy(ptype, p_type(type)); + ns_debug(ns_log_default, 3, "wantedtsig(%#x, %s %s) [%s %s]", + dp, pclass, ptype, + p_class(dp->d_class), p_type(dp->d_type)); +#endif + + if (dp->d_class != class && class != C_ANY) + return (0); + if (dp->d_type != T_SIG || dp->d_rcode != 0) + return (0); + + cp = dp->d_data; + GETSHORT(coveredType, cp); + cp += INT16SZ + INT32SZ; /* skip alg, labels, & orig TTL */ + GETLONG(expiration,cp); + if (expiration < time(0)) + return (0); + + if (type == T_ANY || type == T_SIG || type == coveredType) + return (1); + if (type == ns_t_mailb) { + switch (coveredType) { + case T_MR: + case T_MB: + case T_MG: + case T_MINFO: + return (1); + } } return (0); } @@ -2879,7 +3330,7 @@ add_data(struct namebuf *np, struct databuf **dpp, if (dp->d_rcode) continue; if ((n = make_rr(dname, dp, cp, buflen, 1, - dnptrs, dnptrs_end)) < 0) + dnptrs, dnptrs_end, 0)) < 0) return (-bytes); /* Truncation */ cp += n; buflen -= n; @@ -2895,7 +3346,7 @@ rrsetadd(struct flush_set *flushset, const char *name, struct databuf *dp) { struct db_list *dbl; while (fs->fs_name && ( - strcasecmp(fs->fs_name,name) || + ns_samename(fs->fs_name,name) != 1 || (fs->fs_class != dp->d_class) || (fs->fs_type != dp->d_type) || (fs->fs_cred != dp->d_cred))) { @@ -2989,14 +3440,19 @@ ttlcheck(const char *name, struct db_list *dbl, int update) { return(1); } +/* + * lookup rrset in table and compare to dbl + * tri state result + * -1: lookup failed + * 0: rrsets same + * 1: rrsets differ + */ + static int -rrsetcmp(name, dbl) - char *name; - struct db_list *dbl; -{ +rrsetcmp(char * name, struct db_list * dbl, struct hashbuf * table) { int type = dbl->db_dp->d_type; int class = dbl->db_dp->d_class; - struct hashbuf *htp = hashtab; + struct hashbuf *htp = table; const char *fname; struct namebuf *np; struct db_list *dbp = dbl; @@ -3013,8 +3469,9 @@ rrsetcmp(name, dbl) /* check that all entries in dbl are in the cache */ while (dbp) { for (dp = np->n_data; dp != NULL; dp = dp->d_next) { - if (match(dp, class, type)) - exists++; + if (!match(dp, class, type)) + continue; + exists = 1; if (!db_cmp(dp, dbp->db_dp) #ifdef NOADDITIONAL && ((dp->d_cred == dbp->db_dp->d_cred) || @@ -3056,38 +3513,130 @@ rrsetcmp(name, dbl) return (0); } +/* + * verify incoming answer against what we already have in the hints + * issue warnings / errors if differences detected. + */ + static void -rrsetupdate(struct flush_set * flushset, int flags, struct sockaddr_in from) { +check_hints(struct flush_set * flushset) { + struct zoneinfo *zp; + struct flush_set *fs; + struct db_list *dbp; + + /* We don't use hints when in forward only mode */ + if (NS_OPTION_P(OPTION_FORWARD_ONLY)) + return; + + /* find "." NS rrset and hence class */ + for (fs = flushset; fs->fs_name != NULL; fs++) { + if ((fs->fs_name[0] != '\0') || (fs->fs_type != ns_t_ns)) + continue; + + /* see if we are a root server */ + zp = find_zone(fs->fs_name, fs->fs_class); + if (zp != NULL && + (zp->z_type == z_master || zp->z_type == z_slave)) + return; + switch (rrsetcmp(fs->fs_name, fs->fs_list, fcachetab)) { + case -1: + ns_error(ns_log_default, + "check_hints: no NS records for class %d in hints", + fs->fs_class); + break; + case 1: + ns_warning(ns_log_default, + "check_hints: root NS list in hints for class %d does not match root NS list", + fs->fs_class); + break; + case 0: + break; + default: + ns_error(ns_log_default, + "check_hints: unexpected response from rrsetcmp"); + break; + } + break; + } + + if (fs->fs_name == NULL) /* no root NS records */ + return; + + dbp = fs->fs_list; + while (dbp) { + /* for each NS find A rrset in answer and check */ + for (fs = flushset; fs->fs_name != NULL; fs++) { + if (ns_samename(fs->fs_name, (char *)dbp->db_dp->d_data) != 1 + || fs->fs_type != ns_t_a) + continue; + switch (rrsetcmp(fs->fs_name, fs->fs_list, fcachetab)) { + case -1: + ns_error(ns_log_default, + "check_hints: no A records for %s class %d in hints", + fs->fs_name[0] ? fs->fs_name : ".", + fs->fs_class); + break; + case 1: + ns_warning(ns_log_default, + "check_hints: A records for %s class %d do not match hint records", + fs->fs_name[0] ? fs->fs_name : ".", + fs->fs_class); + break; + case 0: + break; + default: + ns_error(ns_log_default, + "check_hints: unexpected response from rrsetcmp"); + break; + } + break; + } + + if (fs->fs_name == NULL) + ns_debug(ns_log_default, 2, + "check_hints: no A records for %s", + dbp->db_dp->d_data); + + dbp = dbp->db_next; + } +} + +static void +rrsetupdate(struct flush_set * flushset, int flags, struct sockaddr_in from, + int updatettl) { struct flush_set *fs = flushset; struct db_list *dbp, *odbp; int n; + void *state = NULL; while (fs->fs_name) { ns_debug(ns_log_default, 2, "rrsetupdate: %s", fs->fs_name[0] ? fs->fs_name : "."); - if ((n = rrsetcmp(fs->fs_name, fs->fs_list)) && + if ((n = rrsetcmp(fs->fs_name, fs->fs_list, hashtab)) && ttlcheck(fs->fs_name, fs->fs_list, 0)) { if (n > 0) flushrrset(fs, from); dbp = fs->fs_list; while (dbp) { - n = db_update(fs->fs_name, dbp->db_dp, - dbp->db_dp, NULL, flags, - hashtab, from); + n = db_set_update(fs->fs_name, dbp->db_dp, + &state, flags, + &hashtab, from, NULL, + 0, NULL); ns_debug(ns_log_default, 3, "rrsetupdate: %s %d", fs->fs_name[0] ? fs->fs_name : ".", n); - if (n != OK) - db_freedata(dbp->db_dp); odbp = dbp; dbp = dbp->db_next; memput(odbp, sizeof *odbp); } + ns_debug(ns_log_default, 3, + "rrsetupdate: %s %d", + fs->fs_name[0] ? fs->fs_name : ".", n); } else { - if (n == 0) - (void)ttlcheck(fs->fs_name,fs->fs_list, 1); + if ((n == 0) && updatettl) + (void)ttlcheck(fs->fs_name,fs->fs_list, 1); dbp = fs->fs_list; while (dbp) { db_freedata(dbp->db_dp); @@ -3099,6 +3648,8 @@ rrsetupdate(struct flush_set * flushset, int flags, struct sockaddr_in from) { fs->fs_list = NULL; fs++; } + n = db_set_update(NULL, NULL, &state, flags, &hashtab, from, + NULL, 0, NULL); } static void @@ -3161,22 +3712,26 @@ delete_all(struct namebuf *np, int class, int type) { * arguments: * np = pointer to namebuf to be cleaned. * returns: - * void. + * number of RRs associated with this name. * side effects: * delete_all() can be called, freeing memory and relinking chains. */ -void +int delete_stale(np) struct namebuf *np; { struct databuf *dp; - again: + int count; + again: + count = 0; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (dp->d_zone == DB_Z_CACHE && stale(dp)) { delete_all(np, dp->d_class, dp->d_type); goto again; } + count++; } + return (count); } @@ -3256,6 +3811,44 @@ trunc_adjust(u_char *msg, int msglen, int outlen) { return (cp - msg); } +/* + * mark the server "from" bad in the qp structure so it won't be retried. + */ +static void +mark_bad(struct qinfo *qp, struct sockaddr_in from) { + int i; + + for (i = 0; i < (int)qp->q_naddr; i++) + if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, from.sin_addr)) + qp->q_addr[i].nretry = MAXRETRY; +} + +static void +mark_lame(struct qinfo *qp, struct sockaddr_in from) { + int i; + + for (i = 0; i < (int)qp->q_naddr; i++) + if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, from.sin_addr) && + qp->q_addr[i].ns != NULL) { + qp->q_addr[i].ns->d_flags |= DB_F_LAME; + db_lame_add(qp->q_domain, + (char*)qp->q_addr[i].ns->d_data, + tt.tv_sec + server_options->lame_ttl); + } +} + +/* + * Retry the message if and only if from matches where the query was + * last sent to. The code does not handle responses sent from the + * wrong interface an a multihomed server. + */ +static void +fast_retry(struct qinfo *qp, struct sockaddr_in from) { + if (ina_equal(qp->q_addr[qp->q_curaddr].ns_addr.sin_addr, + from.sin_addr)) + retry(qp); +} + static void add_related_additional(char *name) { int i; @@ -3263,7 +3856,7 @@ add_related_additional(char *name) { if (num_related >= MAX_RELATED - 1) return; for (i = 0; i < num_related; i++) - if (strcasecmp(name, related[i]) == 0) { + if (ns_samename(name, related[i]) == 1) { freestr(name); return; } @@ -3284,7 +3877,7 @@ related_additional(char *name) { int i; for (i = 0; i < num_related; i++) - if (strcasecmp(name, related[i]) == 0) + if (ns_samename(name, related[i]) == 1) return (1); return (0); } @@ -3296,3 +3889,87 @@ freestr_maybe(char **tname) { freestr(*tname); *tname = NULL; } + +/* + * Match a request namebuf against the configured rrset-order info. First + * match wins. There is an implicit '*.' at the front to the ordering names. + */ +static enum ordering +match_order(const struct namebuf *np, int class, int type) { + rrset_order_list orders = server_options->ordering; + rrset_order_element roe; + + if (orders == NULL) + return (DEFAULT_ORDERING); + + for (roe = orders->first ; roe != NULL ; roe = roe->next) { + if (roe->class != C_ANY && roe->class != class) + continue; + if (roe->type != T_ANY && roe->type != type) + continue; + + if (match_name(np, roe->name, strlen(roe->name)) == 0) { + return (roe->order); + } + } + + /* none matched so use default */ + return (DEFAULT_ORDERING); +} + +/* Do a simple compare of the NP data against the given NAME, recursively + * looking at the NP parent if necessary. NAMELEN is the length of the NAME + * that needs to be matched. Matching happen from right to left. Returns -1 + * on failure, on success the index of the first character of the matched + * portion of the string is returned. In the first level call a return + * value of 0 is of interest. + */ +static int +match_name(const struct namebuf *np, const char *name, size_t namelen) +{ + int matched ; + + if (name[0] == '*' && name[1] == '\0') + return 0; + + if (np->n_parent != NULL) { /* recurse to end of np list */ + matched = match_name(np->n_parent,name,namelen); + } else { + matched = namelen; + } + + if (matched > 0) { + int labellen = NAMELEN(*np); + char pch; + const char *start; + + if (labellen > matched) { + return -1; + } else if (labellen < matched) { + /* string is longer than this namebuf's data, so + make sure there's a period before the end of the + match so we don't just match a suffix. */ + start = name + (matched - labellen); + pch = start[-1]; + if (pch != '.') { + return -1; + } + } else { + start = name ; + } + + if (strncasecmp(start, NAME(*np), labellen) == 0) { + /* looking good. tell our caller what portion of + the tail of string has been matched */ + if (start == name) + return (0) ; + else + return (start - name - 1); /* matched '.' too */ + } else { + return (-1); + } + } + + return (matched); +} + diff --git a/contrib/bind/bin/named/ns_signal.c b/contrib/bind/bin/named/ns_signal.c new file mode 100644 index 0000000..4c7c48a --- /dev/null +++ b/contrib/bind/bin/named/ns_signal.c @@ -0,0 +1,264 @@ +#if !defined(lint) && !defined(SABER) +static const char sccsid[] = "@(#)ns_main.c 4.55 (Berkeley) 7/1/91"; +static const char rcsid[] = "$Id: ns_signal.c,v 8.11 1999/10/13 16:39:12 vixie Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1986, 1989, 1990 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* Import. */ + +#include "port_before.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#ifdef SVR4 /* XXX */ +# include <sys/sockio.h> +#else +# include <sys/mbuf.h> +#endif + +#include <netinet/in.h> +#include <net/route.h> +#include <net/if.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <grp.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <netdb.h> +#include <pwd.h> +#include <resolv.h> +#include <string.h> +#include <syslog.h> +#include <time.h> +#include <unistd.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> +#include <isc/memcluster.h> +#include <isc/list.h> + +#include "port_after.h" +#include "named.h" + +/* Forward. */ + +static SIG_FN onhup(int); +static SIG_FN onintr(int); +static SIG_FN setdumpflg(int); +static SIG_FN setIncrDbgFlg(int); +static SIG_FN setNoDbgFlg(int); +static SIG_FN setQrylogFlg(int); +static SIG_FN setstatsflg(int); +static SIG_FN discard_pipe(int); +static SIG_FN setreapflg(int); + +/* Data. */ + +static struct { + int sig; + SIG_FN (*hand)(int); +} sighandlers[] = { +#ifdef DEBUG + { SIGUSR1, setIncrDbgFlg }, + { SIGUSR2, setNoDbgFlg }, +#endif +#if defined(SIGWINCH) && defined(QRYLOG) + { SIGWINCH, setQrylogFlg }, +#endif +#if defined(SIGXFSZ) + { SIGXFSZ, onhup }, /* Wierd DEC Hesiodism, harmless. */ +#endif + { SIGINT, setdumpflg }, + { SIGILL, setstatsflg }, + { SIGHUP, onhup }, + { SIGCHLD, setreapflg }, + { SIGPIPE, discard_pipe }, + { SIGTERM, onintr } +}; + +static sigset_t mask; +static int blocked = 0; + +/* Private. */ + +static SIG_FN +onhup(int sig) { + ns_need_unsafe(main_need_reload); +} + +static SIG_FN +onintr(int sig) { + ns_need_unsafe(main_need_exit); +} + +static SIG_FN +setdumpflg(int sig) { + ns_need_unsafe(main_need_dump); +} + +#ifdef DEBUG +static SIG_FN +setIncrDbgFlg(int sig) { + desired_debug++; + ns_need_unsafe(main_need_debug); +} + +static SIG_FN +setNoDbgFlg(int sig) { + desired_debug = 0; + ns_need_unsafe(main_need_debug); +} +#endif /*DEBUG*/ + +#if defined(QRYLOG) && defined(SIGWINCH) +static SIG_FN +setQrylogFlg(int sig) { + ns_need_unsafe(main_need_qrylog); +} +#endif /*QRYLOG && SIGWINCH*/ + +static SIG_FN +setstatsflg(int sig) { + ns_need_unsafe(main_need_statsdump); +} + +static SIG_FN +discard_pipe(int sig) { +#ifdef SIGPIPE_ONE_SHOT + int saved_errno = errno; + struct sigaction sa; + + memset(&sa, 0, sizeof sa); + sa.sa_mask = mask; + sa.sa_handler = discard_pipe; + if (sigaction(SIGPIPE, &sa, NULL) < 0) + ns_error(ns_log_os, "sigaction failed in discard_pipe: %s", + strerror(errno)); + errno = saved_errno; +#endif +} + +static SIG_FN +setreapflg(int sig) { + ns_need_unsafe(main_need_reap); +} + +/* Public. */ + +void +init_signals(void) { + int sh; + + /* The mask of all our handlers will block all our other handlers. */ + (void)sigemptyset(&mask); + for (sh = 0; sh < sizeof sighandlers / sizeof sighandlers[0]; sh++) + sigaddset(&mask, sighandlers[sh].sig); + + /* Install our signal handlers with that shared mask. */ + for (sh = 0; sh < sizeof sighandlers / sizeof sighandlers[0]; sh++) { + struct sigaction sa; + + memset(&sa, 0, sizeof sa); + sa.sa_mask = mask; + sa.sa_handler = sighandlers[sh].hand; + if (sigaction(sighandlers[sh].sig, &sa, NULL) < 0) + ns_error(ns_log_os, + "sigaction failed in set_signal_handler(%d): %s", + sighandlers[sh].sig, strerror(errno)); + } +} + +void +block_signals(void) { + INSIST(!blocked); + if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) + ns_panic(ns_log_os, 1, "sigblock failed: %s", strerror(errno)); + blocked = 1; +} + +void +unblock_signals(void) { + INSIST(blocked); + if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) + ns_panic(ns_log_os, 1, "sigblock failed: %s", strerror(errno)); + blocked = 0; +} diff --git a/contrib/bind/bin/named/ns_sort.c b/contrib/bind/bin/named/ns_sort.c new file mode 100644 index 0000000..25c74eb --- /dev/null +++ b/contrib/bind/bin/named/ns_sort.c @@ -0,0 +1,410 @@ +#if !defined(lint) && !defined(SABER) +static const char sccsid[] = "@(#)ns_sort.c 4.10 (Berkeley) 3/3/91"; +static const char rcsid[] = "$Id: ns_sort.c,v 8.5 1999/10/13 16:39:12 vixie Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1986, 1990 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Sorting should really be handled by the resolver, but: + * 1) There are too many brain dead resolvers out there that can't be replaced. + * 2) It would be a pain to individually configure all those resolvers anyway. + * + * Here's the scoop: + * + * To enable address sorting in responses, you need to supply the sortlist + * statement in the config file. The sortlist statement takes an + * address match list and interprets it even more specially than the + * topology statement does. + * + * Each top level statement in the sortlist must itself be an explicit + * address match list with one or two elements. The first element + * (which may be an IP address, an IP prefix, an ACL name or nested + * address match list) of each top level list is checked against the + * source address of the query until a match is found. + * + * Once the source address of the query has been matched, if the top level + * statement contains only one element, the actual primitive element that + * matched the source address is used to select the address in the response + * to move to the beginning of the response. If the statement is a list + * of two elements, then the second element is treated like the address + * match list in a topology statement. Each top level element is assigned + * a distance and the address in the response with the minimum distance is + * moved to the beginning of the response. + * + * In the following example, any queries received from any of the addresses + * of the host itself will get responses preferring addresses on any of + * the locally connected networks. Next most preferred are addresses on + * the 192.168.1/24 network, and after that either the 192.168.2/24 or + * 192.168.3/24 network with no preference shown between these two networks. + * Queries received from a host on the 192.168.1/24 network will prefer + * other addresses on that network to the 192.168.2/24 and 192.168.3/24 + * networks. Queries received from a host on the 192.168.4/24 or the + * 192.168.5/24 network will only prefer other addresses on their + * directly connected networks. + * + * sortlist { + * { + * localhost; + * { + * localnets; + * 192.168.1/24; + * { 192,168.2/24; 192.168.3/24; }; + * }; + * }; + * { + * 192.168.1/24; + * { + * 192.168.1/24; + * { 192.168.2/24; 192.168.3/24; }; + * }; + * }; + * { + * 192.168.2/24; + * { + * 192.168.2/24; + * { 192.168.1/24; 192.168.3/24; }; + * }; + * }; + * { + * 192.168.3/24; + * { + * 192.168.3/24; + * { 192.168.1/24; 192.168.2/24; }; + * }; + * }; + * { + * { 192.168.4/24; 192.168.5/24; }; + * }; + * }; + * + * + * The following example will give reasonable behaviour for the local host + * and hosts on directly connected networks. It is similar to the behavior + * of the address sort in BIND 4.9.x. Responses sent to queries from the + * local host will favor any of the directly connected networks. Responses + * sent to queries from any other hosts on a directly connected network will + * prefer addresses on that same network. Responses to other queries will + * not be sorted. + * + * sortlist { + * { localhost; localnets; }; + * { localnets; }; + * }; + * + * XXX - it wouldb e nice to have an ACL called "source" that matched the + * source address of a query so that a host could be configured to + * automatically prefer itself, and an ACL called "sourcenet", that + * would return the primitive IP match element that matched the source + * address so that you could do: + * { localnets; { sourcenet; { other stuff ...}; }; + * and automatically get similar behaviour to what you get with: + * { localnets; }; + * + */ + +#include "port_before.h" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <syslog.h> +#include <resolv.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> + +#include "port_after.h" + +#include "named.h" + +static int sort_rr(u_char *cp, u_char *eom, int ancount, ip_match_list iml); + +static int ip_match_address_elt(ip_match_list, struct in_addr, + ip_match_element *); + +void +sort_response(u_char *cp, u_char *eom, int ancount, struct sockaddr_in *from) { + struct in_addr address; + struct ip_match_element imelement; + ip_match_element imetl, imematch, imeprimitive; + struct ip_match_list imlist; + ip_match_list iml; + int indirect, matched; + + if (server_options->sortlist == NULL) + return; + + if (from->sin_family != AF_INET) + return; + + address = from->sin_addr; + + for (imetl = server_options->sortlist->first; imetl != NULL; + imetl = imetl->next) { + if (imetl->type == ip_match_indirect) + imematch = imetl->u.indirect.list->first; + else + /* + * allow a bare pattern as a top level statement + * and treat it like {pattern;}; + */ + imematch = imetl; + + switch (imematch->type) { + case ip_match_pattern: + indirect = 0; + break; + case ip_match_indirect: + indirect = 1; + break; + case ip_match_localhost: + imematch->u.indirect.list = local_addresses; + indirect = 1; + break; + case ip_match_localnets: + imematch->u.indirect.list = local_networks; + indirect = 1; + break; + default: + panic("unexpected ime type in ip_match_address()", + NULL); + } + if (indirect) { + imeprimitive = NULL; + matched = ip_match_address_elt(imematch->u.indirect.list, + address, &imeprimitive); + if (matched >= 0) { + if (imematch->flags & IP_MATCH_NEGATE) + /* Don't sort */ + return; + } else + continue; + } else { + if (ina_onnet(address, imematch->u.direct.address, + imematch->u.direct.mask)) { + if (imematch->flags & IP_MATCH_NEGATE) + /* Don't sort */ + return; + else + imeprimitive = imematch; + } else + continue; + } + if (imetl != imematch && imematch->next != NULL) { + /* + * Not a bare pattern at the top level, but a two + * element list + */ + switch (imematch->next->type) { + case ip_match_pattern: + case ip_match_localhost: + case ip_match_localnets: + imelement = *(imematch->next); + imelement.next = NULL; + iml = &imlist; + iml->first = iml->last = &imelement; + break; + case ip_match_indirect: + iml = imematch->next->u.indirect.list; + break; + default: + panic("unexpected ime type in ip_match_address()", + NULL); + } + } else if (imeprimitive) { + imelement = *imeprimitive; + imelement.next = NULL; + iml = &imlist; + iml->first = iml->last = &imelement; + } else { + /* Don't sort because we'd just use "any" */ + return; + } + sort_rr(cp, eom, ancount, iml); + break; + } + + return; +} + +static int +sort_rr(u_char *cp, u_char *eom, int ancount, ip_match_list iml) { + int type, class, dlen, n, c, distance, closest; + struct in_addr inaddr; + u_char *rr1 = NULL, *rrbest, *cpstart; + + rr1 = NULL; + cpstart = cp; + for (c = ancount; c > 0; --c) { + n = dn_skipname(cp, eom); + if (n < 0) + return (1); /* bogus, stop processing */ + cp += n; + if (cp + QFIXEDSZ > eom) + return (1); + GETSHORT(type, cp); + GETSHORT(class, cp); + cp += INT32SZ; + GETSHORT(dlen, cp); + if (dlen > eom - cp) + return (1); /* bogus, stop processing */ + switch (type) { + case T_A: + switch (class) { + case C_IN: + case C_HS: + memcpy((char *)&inaddr, cp, INADDRSZ); + /* Find the address with the minimum distance */ + if (rr1 == NULL) { + rr1 = cp; + rrbest = cp; + closest = distance_of_address(iml, inaddr); + } else { + distance = distance_of_address(iml, inaddr); + if (distance < closest) { + rrbest = cp; + closest = distance; + } + } + break; + } + break; + } + cp += dlen; + } + if (rr1 != rrbest && rr1 != NULL) { + memcpy((char *)&inaddr, rrbest, INADDRSZ); + memcpy(rrbest, rr1, INADDRSZ); + memcpy(rr1, (char *)&inaddr, INADDRSZ); + } + return (0); +} + +/* + * Just like ip_match_address(), but also returns a pointer to the primitive + * element that matched. + */ + +static int +ip_match_address_elt(ip_match_list iml, struct in_addr address, + ip_match_element *imep) { + ip_match_element ime; + int ret; + int indirect; + + INSIST(iml != NULL); + for (ime = iml->first; ime != NULL; ime = ime->next) { + switch (ime->type) { + case ip_match_pattern: + indirect = 0; + break; + case ip_match_indirect: + indirect = 1; + break; + case ip_match_localhost: + ime->u.indirect.list = local_addresses; + indirect = 1; + break; + case ip_match_localnets: + ime->u.indirect.list = local_networks; + indirect = 1; + break; + default: + panic("unexpected ime type in ip_match_address()", + NULL); + } + if (indirect) { + ret = ip_match_address_elt(ime->u.indirect.list, + address, imep); + if (ret >= 0) { + if (ime->flags & IP_MATCH_NEGATE) + ret = (ret) ? 0 : 1; + return (ret); + } + } else { + if (ina_onnet(address, ime->u.direct.address, + ime->u.direct.mask)) { + *imep = ime; + if (ime->flags & IP_MATCH_NEGATE) + return (0); + else + return (1); + } + } + } + return (-1); +} diff --git a/contrib/bind/bin/named/ns_stats.c b/contrib/bind/bin/named/ns_stats.c index 5be0257..44552ed 100644 --- a/contrib/bind/bin/named/ns_stats.c +++ b/contrib/bind/bin/named/ns_stats.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_stats.c 4.10 (Berkeley) 6/27/90"; -static char rcsid[] = "$Id: ns_stats.c,v 8.18 1998/02/13 19:50:24 halley Exp $"; +static const char sccsid[] = "@(#)ns_stats.c 4.10 (Berkeley) 6/27/90"; +static const char rcsid[] = "$Id: ns_stats.c,v 8.27 1999/10/13 16:39:12 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_stats.c,v 8.18 1998/02/13 19:50:24 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -77,12 +77,15 @@ static char rcsid[] = "$Id: ns_stats.c,v 8.18 1998/02/13 19:50:24 halley Exp $"; #include <sys/types.h> #include <sys/param.h> +#include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> #include <arpa/inet.h> #include <errno.h> +#include <resolv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -103,39 +106,7 @@ static char rcsid[] = "$Id: ns_stats.c,v 8.18 1998/02/13 19:50:24 halley Exp $"; #include "named.h" -static u_long typestats[T_ANY+1]; -static const char *typenames[T_ANY+1] = { - /* 5 types per line */ - "Unknown", "A", "NS", "invalid(MD)", "invalid(MF)", - "CNAME", "SOA", "MB", "MG", "MR", - "NULL", "WKS", "PTR", "HINFO", "MINFO", - "MX", "TXT", "RP", "AFSDB", "X25", - "ISDN", "RT", "NSAP", "NSAP_PTR", "SIG", - "KEY", "PX", "invalid(GPOS)", "AAAA", "LOC", - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - /* 20 per line */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 100 */ - "UINFO", "UID", "GID", "UNSPEC", 0, 0, 0, 0, 0, 0, - /* 110 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 120 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 200 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 240 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 250 */ - 0, 0, "AXFR", "MAILB", "MAILA", "ANY" -}; - +static u_long typestats[T_ANY+1]; static void nameserStats(FILE *); void @@ -161,25 +132,39 @@ ns_stats() { /* query type statistics */ fprintf(f, "%lu\tUnknown query types\n", (u_long)typestats[0]); - for(i=1; i < T_ANY+1; i++) - if (typestats[i]) { - if (typenames[i] != NULL) - fprintf(f, "%lu\t%s queries\n", - (u_long)typestats[i], typenames[i]); - else - fprintf(f, "%lu\ttype %d queries\n", - (u_long)typestats[i], i); - } + for (i = 1; i < T_ANY+1; i++) + fprintf(f, "%lu\t%s queries\n", typestats[i], p_type(i)); /* name server statistics */ nameserStats(f); + fprintf(f, "--- Statistics Dump --- (%ld) %s", + (long)timenow, checked_ctime(&timenow)); + (void) my_fclose(f); + + /* Now do the memory statistics file */ + if (!(f = fopen(server_options->memstats_filename, "a"))) { + ns_notice(ns_log_statistics, "cannot open memstat file, \"%s\"", + server_options->memstats_filename); + return; + } + + fprintf(f, "+++ Memory Statistics Dump +++ (%ld) %s", + (long)timenow, checked_ctime(&timenow)); + + fprintf(f, "%ld\ttime since boot (secs)\n", + (long)(timenow - boottime)); + fprintf(f, "%ld\ttime since reset (secs)\n", + (long)(timenow - resettime)); + fprintf(f, "++ Memory Statistics ++\n"); memstats(f); fprintf(f, "-- Memory Statistics --\n"); - fprintf(f, "--- Statistics Dump --- (%ld) %s", + + fprintf(f, "--- Memory Statistics Dump --- (%ld) %s", (long)timenow, checked_ctime(&timenow)); (void) my_fclose(f); + ns_notice(ns_log_statistics, "done dumping nameserver stats"); } @@ -370,11 +355,7 @@ ns_logstats(evContext ctx, void *uap, struct timespec due, for (i = 0; i < T_ANY+1; i++) { if (typestats[i]) { - if (typenames[i]) - sprintf(buffer2, " %s=%lu", - typenames[i], typestats[i]); - else - sprintf(buffer2, " %d=%lu", i, typestats[i]); + sprintf(buffer2, " %s=%lu", p_type(i), typestats[i]); if (strlen(buffer) + strlen(buffer2) > sizeof(buffer) - 1) { ns_info(ns_log_statistics, buffer); diff --git a/contrib/bind/bin/named/ns_udp.c b/contrib/bind/bin/named/ns_udp.c index 8b1af5e..95f0438 100644 --- a/contrib/bind/bin/named/ns_udp.c +++ b/contrib/bind/bin/named/ns_udp.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_udp.c,v 8.5 1997/05/21 19:52:26 halley Exp $"; +static const char rcsid[] = "$Id: ns_udp.c,v 8.8 1999/10/13 16:39:13 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -26,6 +26,7 @@ static char rcsid[] = "$Id: ns_udp.c,v 8.5 1997/05/21 19:52:26 halley Exp $"; #include <sys/stat.h> #include <sys/socket.h> #include <sys/file.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> diff --git a/contrib/bind/bin/named/ns_update.c b/contrib/bind/bin/named/ns_update.c index 48db076..4f9817f 100644 --- a/contrib/bind/bin/named/ns_update.c +++ b/contrib/bind/bin/named/ns_update.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $"; +static const char rcsid[] = "$Id: ns_update.c,v 8.68 1999/11/05 04:40:58 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,6 +20,26 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" */ /* + * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Check Point Software Technologies Incorporated not be used + * in advertising or publicity pertaining to distribution of the document + * or software without specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* * Based on the Dynamic DNS reference implementation by Viraj Bais * <viraj_bais@ccm.fm.intel.com> */ @@ -31,6 +51,7 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" #include <sys/file.h> #include <sys/socket.h> #include <sys/stat.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -40,6 +61,7 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" #include <fcntl.h> #include <limits.h> #include <resolv.h> +#include <res_update.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -52,10 +74,14 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" +static ns_updque curupd; + #define WRITEABLE_MASK (S_IWUSR | S_IWGRP | S_IWOTH) /* XXXRTH almost all funcs. in here should be static! @@ -106,14 +132,8 @@ static struct map m_section[] = { }; #define M_SECTION_CNT (sizeof(m_section) / sizeof(struct map)) +/* Forward. */ -/* from ns_req.c */ - -static ns_updrec *rrecp_start = NULL, *rrecp_last = NULL; - - -/* forward */ -static int findzone(const char *, int, int, int *, int); static int rdata_expand(const u_char *, const u_char *, const u_char *, u_int, size_t, u_char *, size_t); @@ -134,6 +154,21 @@ open_transaction_log(struct zoneinfo *zp) { return (fp); } +static FILE * +open_ixfr_log(struct zoneinfo *zp) { + FILE *fp; + + fp = fopen(zp->z_ixfr_base, "a+"); + if (fp == NULL) { + ns_error(ns_log_update, "can't open %s: %s", zp->z_ixfr_base, + strerror(errno)); + return (NULL); + } + if (ftell(fp) == 0L) { + fprintf(fp, "%s", LogSignature); + } + return (fp); +} static int close_transaction_log(struct zoneinfo *zp, FILE *fp) { @@ -155,13 +190,69 @@ close_transaction_log(struct zoneinfo *zp, FILE *fp) { return (0); } +static int +close_ixfr_log(struct zoneinfo *zp, FILE *fp) { + if (fflush(fp) == EOF) { + ns_error(ns_log_update, "fflush() of %s failed: %s", + zp->z_ixfr_base, strerror(errno)); + fclose(fp); + return (-1); + } + if (fsync(fileno(fp)) < 0) { + ns_error(ns_log_update, "fsync() of %s failed: %s", + zp->z_ixfr_base, strerror(errno)); + fclose(fp); + return (-1); + } + if (fclose(fp) == EOF) { + ns_error(ns_log_update, "fclose() of %s failed: %s", + zp->z_ixfr_base, strerror(errno)); + return (-1); + } + return (0); +} + +/* + * return true if 'db' had been added. + */ +static int +was_added(const ns_updque *updlist, struct databuf *dp) { + ns_updrec *rrecp; + + for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) + if (rrecp->r_section == S_UPDATE && rrecp->r_dp == dp) + return (1); + return (0); +} + +/* + * return true if 'db' had been deleted. + */ +static int +was_deleted(const ns_updque *updlist, struct databuf *dp) { + ns_updrec *rrecp; + struct databuf *adp; + + + for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) + if (rrecp->r_section == S_UPDATE && + rrecp->r_deldp != NULL) { + adp = rrecp->r_deldp; + do { + if (adp == dp) + return (1); + } while ((adp = adp->d_next) != NULL); + } + return (0); +} + /* - * printupdatelog(srcaddr, firstp, hp, zp, old_serial) + * printupdatelog(srcaddr, updlist, hp, zp, old_serial) * append an ascii form to the zone's transaction log file. */ static void printupdatelog(struct sockaddr_in srcaddr, - ns_updrec *firstp, + const ns_updque *updlist, HEADER *hp, struct zoneinfo *zp, u_int32_t old_serial) @@ -171,25 +262,35 @@ printupdatelog(struct sockaddr_in srcaddr, ns_updrec *rrecp; int opcode; char time[25]; - FILE *fp; + FILE *fp, *ifp; - if (!firstp) + if (EMPTY(*updlist)) return; fp = open_transaction_log(zp); if (fp == NULL) return; + ifp = open_ixfr_log(zp); + if (ifp == NULL) { + (void) close_transaction_log(zp, fp); + return; + } sprintf(time, "at %lu", (u_long)tt.tv_sec); fprintf(fp, "[DYNAMIC_UPDATE] id %u from %s %s (named pid %ld):\n", - hp->id, sin_ntoa(srcaddr), time, (long)getpid()); - for (rrecp = firstp; rrecp; rrecp = rrecp->r_next) { + ntohs(hp->id), sin_ntoa(srcaddr), time, (long)getpid()); + fprintf(ifp, "[DYNAMIC_UPDATE] id %u from %s %s (named pid %ld):\n", + ntohs(hp->id), sin_ntoa(srcaddr), time, (long)getpid()); + for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) { INSIST(zp == &zones[rrecp->r_zone]); switch (rrecp->r_section) { case S_ZONE: fprintf(fp, "zone:\torigin %s class %s serial %u\n", zp->z_origin, p_class(zp->z_class), old_serial); + fprintf(ifp, "zone:\torigin %s class %s serial %u\n", + zp->z_origin, p_class(zp->z_class), + old_serial); break; case S_PREREQ: opcode = rrecp->r_opcode; @@ -207,6 +308,45 @@ printupdatelog(struct sockaddr_in srcaddr, break; case S_UPDATE: opcode = rrecp->r_opcode; + /* + * Translate all deletes into explict actions by + * looking at what was actually deleted from the + * zone for the ixfr log. + */ + dp = rrecp->r_deldp; + while (dp != NULL) { + if (dp->d_rcode == 0 && + !was_added(updlist, dp)) { + fprintf(ifp, + "update:\t{%s} %s. %u %s %s ", + "delete", + rrecp->r_dname, + dp->d_ttl, + p_class(dp->d_class), + p_type(dp->d_type)); + (void) rdata_dump(dp, ifp); + fprintf(ifp, "\n"); + } + dp = dp->d_next; + } + /* + * Only successful adds should be recorded. + * Don't add changes that are undone later. + * SOA additions performed later. + */ + if (opcode == ADD && (dp = rrecp->r_dp) != NULL && + dp->d_type != T_SOA && + (dp->d_mark & D_MARK_ADDED) != 0 && + !was_deleted(updlist, dp)) { + fprintf(ifp, "update:\t{%s} %s. ", + opcodes[opcode], rrecp->r_dname); + fprintf(ifp, "%u ", rrecp->r_ttl); + fprintf(ifp, "%s ", p_class(zp->z_class)); + fprintf(ifp, "%s ", p_type(rrecp->r_type)); + (void) rdata_dump(dp, ifp); + fprintf(ifp, "\n"); + } + /* Update log. */ fprintf(fp, "update:\t{%s} %s. ", opcodes[opcode], rrecp->r_dname); if (opcode == ADD) @@ -228,8 +368,37 @@ printupdatelog(struct sockaddr_in srcaddr, /*NOTREACHED*/ } } + /* + * SOA additions must be last in this update as they + * (or [INCR_SERIAL]) terminate an IXFR chunk. Only the last SOA + * addition will be emitted for any dynamic update regardless + * of the number of SOA changes in the update. + */ + for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) { + INSIST(zp == &zones[rrecp->r_zone]); + switch (rrecp->r_section) { + case S_UPDATE: + opcode = rrecp->r_opcode; + if (opcode == ADD && (dp = rrecp->r_dp) != NULL && + dp->d_type == T_SOA && + (dp->d_mark & D_MARK_ADDED) != 0 && + !was_deleted(updlist, dp)) { + fprintf(ifp, "update:\t{%s} %s. ", + opcodes[opcode], rrecp->r_dname); + fprintf(ifp, "%u ", rrecp->r_ttl); + fprintf(ifp, "%s ", p_class(zp->z_class)); + fprintf(ifp, "%s ", p_type(rrecp->r_type)); + (void) rdata_dump(dp, ifp); + fprintf(ifp, "\n[END_DELTA]\n"); + } + break; + default: + break; + } + } fprintf(fp, "\n"); (void) close_transaction_log(zp, fp); + (void) close_ixfr_log(zp, ifp); } static void @@ -379,8 +548,15 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { } htp = hashtab; np = nlookup(dname, &htp, &fname, 0); - if (fname != dname) - np = NULL; /* Matching by wildcard not allowed here. */ + /* + * Matching by wildcard not allowed here. + * We need to post check for a wildcard match. + */ + if (fname != dname || + (np != NULL && ns_wildcard(NAME(*np)) && + (dname[0] != '*' || (dname[1] != '.' && dname[1] != '\0')))) + np = NULL; + if (class == C_ANY) { if (rdp->d_size) { ns_debug(ns_log_update, 1, @@ -411,7 +587,8 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { for (dp = np->n_data; dp && !found; dp = dp->d_next) - if (match(dp, class, type)) + if (match(dp, class, type) && + dp->d_type == type) found = 1; if (!found) { ns_debug(ns_log_update, 1, @@ -485,12 +662,12 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { return (0); } for (dp = np->n_data; dp; dp = dp->d_next) { - if (match(dp, class, type)) { + if (match(dp, class, type) && dp->d_type == type) { int found = 0; for (tmp = ur; - tmp && !found; - tmp = tmp->r_next) { + tmp != NULL && !found; + tmp = NEXT(tmp, r_link)) { if (tmp->r_section != S_PREREQ) break; if (!db_cmp(dp, tmp->r_dp)) { @@ -505,9 +682,9 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { } } } - for (tmp = ur; tmp; tmp = tmp->r_next) + for (tmp = ur; tmp != NULL; tmp = NEXT(tmp, r_link)) if (tmp->r_section == S_PREREQ && - !strcasecmp(dname, tmp->r_dname) && + ns_samename(dname, tmp->r_dname) == 1 && tmp->r_class == class && tmp->r_type == type && (ur->r_dp->d_mark & D_MARK_FOUND) == 0) { @@ -527,6 +704,153 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { return (1); } +static int +prescan_nameok(ns_updrec *ur, int *rcodep, u_int16_t zclass, + struct zoneinfo *zp) { + const char *dname = ur->r_dname; + const char *owner = ur->r_dname; + u_int16_t class = ur->r_class; + u_int16_t type = ur->r_type; + char *cp = (char *)ur->r_dp->d_data; + enum context context; + + int ret = 1; + + /* We don't care about deletes */ + if (ur->r_class != zclass) + return (1); + + context = ns_ownercontext(type, primary_trans); + if (!ns_nameok(NULL, owner, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + + switch (type) { + case ns_t_soa: + context = hostname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + cp += strlen(cp) + 1; + context = mailname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_rp: + context = mailname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + cp += strlen(cp) + 1; + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_minfo: + context = mailname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + cp += strlen(cp) + 1; + context = mailname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_ns: + context = hostname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_cname: + case ns_t_mb: + case ns_t_mg: + case ns_t_mr: + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_ptr: + context = ns_ptrcontext(owner); + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_naptr: + /* + * Order (2) + * Preference (2) + * Flags (1) + */ + cp += 5; + /* Service (txt) */ + cp += strlen(cp) + 1; + /* Pattern (txt) */ + cp += strlen(cp) + 1; + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_srv: + cp += 4; + /* FALLTHROUGH */ + case ns_t_mx: + case ns_t_afsdb: + case ns_t_rt: + case ns_t_kx: + cp += 2; + context = hostname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_px: + cp += 2; + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + cp += strlen(cp) + 1; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_sig: + /* + * Type covered (2) + * Alg (1) * + * Labels (1) + * ttl (4) + * expires (4) + * signed (4) + * footprint (2) + */ + cp += 18; + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_nxt: + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + default: + break; + } + return (1); + refused: + *rcodep = REFUSED; + return (0); +} + /* * int * prescan_update(ur, rcodep) @@ -549,9 +873,7 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) { struct namebuf *np; if (class == zclass) { - if (type == T_ANY || - type == T_AXFR || type == T_IXFR || - type == T_MAILA || type == T_MAILB) { + if (!ns_t_rr_p(type)) { ns_debug(ns_log_update, 1, "prescan_update: invalid type (%s)", p_type(type)); @@ -560,19 +882,18 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) { } } else if (class == C_ANY) { if (ttl != 0 || rdp->d_size || - type == T_AXFR || type == T_IXFR || - type == T_MAILA || type == T_MAILB) { + (!ns_t_rr_p(type) && type != T_ANY)) + { ns_debug(ns_log_update, 1, "prescan_update: formerr(#2)"); *rcodep = FORMERR; return (0); } } else if (class == C_NONE) { - if (ttl != 0 || type == T_ANY || - type == T_AXFR || type == T_IXFR || - type == T_MAILA || type == T_MAILB) { + if (ttl != 0 || !ns_t_rr_p(type)) { ns_debug(ns_log_update, 1, - "prescan_update: formerr(#3)"); + "prescan_update: formerr(#3) %d %s", + ttl, p_type(type)); *rcodep = FORMERR; return (0); } @@ -589,7 +910,7 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) { /* * int - * process_updates(firstp, rcodep, from) + * process_updates(updlist, rcodep, from) * Process prerequisites and apply updates from the list to the database. * returns: * number of successful updates, 0 if none were successful. @@ -598,7 +919,9 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) { * can schedule maintainance for zone dumps and soa.serial# increments. */ static int -process_updates(ns_updrec *firstp, int *rcodep, struct sockaddr_in from) { +process_updates(const ns_updque *updlist, int *rcodep, + struct sockaddr_in from) +{ int i, j, n, dbflags, matches, zonenum; int numupdated = 0, soaupdated = 0, schedmaint = 0; u_int16_t zclass; @@ -609,11 +932,12 @@ process_updates(ns_updrec *firstp, int *rcodep, struct sockaddr_in from) { int zonelist[MAXDNAME]; *rcodep = SERVFAIL; - if (!firstp) + if (EMPTY(*updlist)) return (0); - if (firstp->r_section == S_ZONE) { - zclass = firstp->r_class; - zonenum = firstp->r_zone; + ur = HEAD(*updlist); + if (ur->r_section == S_ZONE) { + zclass = ur->r_class; + zonenum = ur->r_zone; zp = &zones[zonenum]; } else { ns_debug(ns_log_update, 1, @@ -622,7 +946,7 @@ process_updates(ns_updrec *firstp, int *rcodep, struct sockaddr_in from) { } /* Process prereq records and prescan update records. */ - for (ur = firstp; ur != NULL; ur = ur->r_next) { + for (ur = HEAD(*updlist); ur != NULL; ur = NEXT(ur, r_link)) { const char * dname = ur->r_dname; u_int16_t class = ur->r_class; u_int16_t type = ur->r_type; @@ -642,7 +966,9 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", for (j = 0; j < matches && !ur->r_zone; j++) if (zonelist[j] == zonenum) ur->r_zone = zonelist[j]; - if (!ur->r_zone) { + if (!ur->r_zone || + (section != S_ADDT && type == T_SOA && + ns_samename(dname, zp->z_origin) != 1)) { ns_debug(ns_log_update, 1, "process_updates: record does not belong to the zone %s", zones[zonenum].z_origin); @@ -661,6 +987,8 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", case S_UPDATE: if (!prescan_update(ur, rcodep, zclass)) return (0); /* *rcodep has been set. */ + if (!prescan_nameok(ur, rcodep, zclass, zp)) + return (0); /* *rcodep has been set. */ ns_debug(ns_log_update, 3, "update prescan succeeded"); break; case S_ADDT: @@ -673,7 +1001,7 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", } /* Now process the records in update section. */ - for (ur = firstp; ur != NULL; ur = ur->r_next) { + for (ur = HEAD(*updlist); ur != NULL; ur = NEXT(ur, r_link)) { const char * dname = ur->r_dname; u_int16_t class = ur->r_class; @@ -689,10 +1017,11 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", * is done in db_update(). */ ur->r_opcode = ADD; - dbflags |= DB_NODATA; + dbflags |= DB_NODATA | DB_REPLACE; n = db_update(dname, dp, dp, &savedp, dbflags, hashtab, from); - if (n != OK) { + if (!((n == OK) || + ((zp->z_xferpid == XFER_ISIXFR) && (n == DATAEXISTS)))) { ns_debug(ns_log_update, 3, "process_updates: failed to add databuf (%d)", n); @@ -723,10 +1052,11 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", dbflags |= DB_DELETE; n = db_update(dname, dp, NULL, &savedp, dbflags, hashtab, from); - if (n != OK) + if (!((n == OK) || + ((zp->z_xferpid == XFER_ISIXFR) && (n == NODATA)))) { ns_debug(ns_log_update, 3, "process_updates: delete failed"); - else { + } else { ns_debug(ns_log_update, 3, "process_updates: delete succeeded"); numupdated++; @@ -771,7 +1101,7 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", schedmaint = 1; #ifdef BIND_NOTIFY if (!loading) - sysnotify(zp->z_origin, zp->z_class, T_SOA); + ns_notify(zp->z_origin, zp->z_class, ns_t_soa); #endif } else { if (schedule_soa_update(zp, numupdated)) @@ -784,7 +1114,8 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", static enum req_action req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, - struct qstream *qsp, int dfd, struct sockaddr_in from) + struct qstream *qsp, int dfd, struct sockaddr_in from, + struct tsig_record *in_tsig) { char dnbuf[MAXDNAME], *dname; u_int zocount, prcount, upcount, adcount, class, type, dlen; @@ -801,6 +1132,9 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, int zonelist[MAXDNAME]; int should_use_tcp; u_int32_t old_serial; + int unapproved_ip = 0; + int tsig_len; + DST_KEY *in_key = (in_tsig != NULL) ? in_tsig->key : NULL; nsp[0] = NULL; @@ -854,7 +1188,7 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, * Begin Access Control Point */ - if (!ip_address_allowed(zp->z_update_acl, from.sin_addr)) { + if (!ip_addr_or_key_allowed(zp->z_update_acl, from.sin_addr, in_key)) { ns_notice(ns_log_security, "unapproved update from %s for %s", sin_ntoa(from), *dname ? dname : "."); return (Refuse); @@ -864,8 +1198,6 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, * End Access Control Point */ - /* XXXVIX should check update key when we have one. */ - /* we should be authoritative */ if (!(zp->z_flags & Z_AUTH)) { ns_debug(ns_log_update, 1, @@ -877,11 +1209,12 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, if (zp->z_type == Z_SECONDARY) { /* - * XXX the code below is broken. Until fixed, we just - * refuse. + * XXX The code below is broken. + * Until fixed, we just refuse. */ +#if 1 return (Refuse); - +#else /* We are a slave for this zone, forward it to the master. */ for (cnt = 0; cnt < zp->z_addrcnt; cnt++) *nspp++ = savedata(zp->z_class, T_A, USE_MINIMUM, @@ -892,8 +1225,15 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, * If the request came in over TCP, forward it over TCP */ should_use_tcp = (qsp != NULL); + if (in_tsig != NULL) { + tsig_len = ns_skiprr(eom, eom + TSIG_BUF_SIZE, + ns_s_ar, 1); + eom += tsig_len; + } n = ns_forw(nsp, msg, eom-msg, from, qsp, dfd, &qp, - dname, class, type, NULL, should_use_tcp); + dname, class, type, NULL, should_use_tcp, NULL); + if (in_tsig != NULL) + eom -= tsig_len; free_nsp(nsp); switch (n) { case FW_OK: @@ -905,6 +1245,7 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, hp->rcode = SERVFAIL; return (Finish); } +#endif } /* * We are the primary master server for this zone, @@ -920,11 +1261,10 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, ns_debug(ns_log_update, 3, "req_update: update request for zone %s, class %s", zp->z_origin, p_class(class)); - rrecp_start = res_mkupdrec(S_ZONE, dname, class, type, 0); - rrecp_start->r_zone = zonenum; - rrecp_start->r_prev = NULL; - rrecp_start->r_next = NULL; - rrecp_last = rrecp_start; + rrecp = res_mkupdrec(S_ZONE, dname, class, type, 0); + rrecp->r_zone = zonenum; + + APPEND(curupd, rrecp, r_link); /* * Parse the prerequisite and update sections for format errors. @@ -946,6 +1286,12 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, } GETSHORT(type, cp); GETSHORT(class, cp); + if (class > CLASS_MAX) { + ns_debug(ns_log_update, 1, + "req_update: bad class"); + hp->rcode = FORMERR; + return (Finish); + } GETLONG(ttl, cp); GETSHORT(dlen, cp); n = 0; @@ -972,14 +1318,12 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, dp = savedata(class, type, ttl, rdata, n); dp->d_zone = zonenum; dp->d_cred = DB_C_ZONE; + dp->d_secure = DB_S_INSECURE; /* should be UNCHECKED */ dp->d_clev = nlabels(zp->z_origin); /* XXX - also record in dp->d_ns, which host this came from */ rrecp->r_dp = dp; /* Append the current record to the end of list of records. */ - rrecp_last->r_next = rrecp; - rrecp->r_prev = rrecp_last; - rrecp->r_next = NULL; - rrecp_last = rrecp; + APPEND(curupd, rrecp, r_link); if (cp > eom) { ns_info(ns_log_update, "Malformed response from %s (overrun)", @@ -990,44 +1334,47 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, } /* Now process all parsed records in the prereq and update sections. */ - numupdated = process_updates(rrecp_start, &rcode, from); + numupdated = process_updates(&curupd, &rcode, from); hp->rcode = rcode; if (numupdated <= 0) { - ns_error(ns_log_update, - "error processing update packet id %d from %s", - hp->id, sin_ntoa(from)); + if (rcode != NOERROR) + ns_error(ns_log_update, + "error processing update packet (%s) id %d from %s", + p_rcode(rcode), ntohs(hp->id), sin_ntoa(from)); return (Finish); } + /* + * Stop any outbound zone transfers. + * (Eventlib is synchronous for this.) + */ + ns_stopxfrs(zp); + /* Make a log of the update. */ - (void) printupdatelog(from, rrecp_start, hp, zp, old_serial); + (void) printupdatelog(from, &curupd, hp, zp, old_serial); return (Finish); } -static void -free_rrecp(ns_updrec **startpp, ns_updrec **lastpp, int rcode, - struct sockaddr_in from) -{ +void +free_rrecp(ns_updque *updlist, int rcode, struct sockaddr_in from) { ns_updrec *rrecp, *first_rrecp, *next_rrecp; struct databuf *dp, *tmpdp; char *dname, *msg; - REQUIRE(startpp != NULL && lastpp != NULL); - if (rcode == NOERROR) { - first_rrecp = *startpp; + first_rrecp = HEAD(*updlist); msg = "free_rrecp: update transaction succeeded, cleaning up"; } else { - first_rrecp = *lastpp; + first_rrecp = TAIL(*updlist); msg = "free_rrecp: update transaction aborted, rolling back"; } ns_debug(ns_log_update, 1, msg); for (rrecp = first_rrecp; rrecp != NULL; rrecp = next_rrecp) { if (rcode == NOERROR) - next_rrecp = rrecp->r_next; + next_rrecp = NEXT(rrecp, r_link); else - next_rrecp = rrecp->r_prev; + next_rrecp = PREV(rrecp, r_link); if (rrecp->r_section != S_UPDATE) { if (rrecp->r_dp) db_freedata(rrecp->r_dp); @@ -1096,7 +1443,7 @@ free_rrecp(ns_updrec **startpp, ns_updrec **lastpp, int rcode, /* Add the databuf back. */ tmpdp->d_mark &= ~D_MARK_DELETED; if (db_update(dname, tmpdp, tmpdp, NULL, - 0, hashtab, from) != OK) { + DB_REPLACE, hashtab, from) != OK) { ns_error(ns_log_update, "free_rrecp: failed to add back databuf: dname=%s, type=%s", dname, p_type(tmpdp->d_type)); @@ -1109,18 +1456,19 @@ free_rrecp(ns_updrec **startpp, ns_updrec **lastpp, int rcode, } res_freeupdrec(rrecp); } - *startpp = NULL; - *lastpp = NULL; + INIT_LIST(*updlist); } enum req_action req_update(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, - struct qstream *qsp, int dfd, struct sockaddr_in from) + struct qstream *qsp, int dfd, struct sockaddr_in from, + struct tsig_record *in_tsig) { enum req_action ret; - ret = req_update_private(hp, cp, eom, msg, qsp, dfd, from); - free_rrecp(&rrecp_start, &rrecp_last, hp->rcode, from); + INIT_LIST(curupd); + ret = req_update_private(hp, cp, eom, msg, qsp, dfd, from, in_tsig); + free_rrecp(&curupd, ret == Refuse ? ns_r_refused : hp->rcode, from); if (ret == Finish) { hp->qdcount = hp->ancount = hp->nscount = hp->arcount = 0; memset(msg + HFIXEDSZ, 0, (eom - msg) - HFIXEDSZ); @@ -1139,11 +1487,13 @@ rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp, { const u_char *cpinit = cp; const u_char *cp1init = cp1; - int n, i; + int n, i, n1; switch (type) { case T_A: - if (dlen != INT32SZ) + case T_AAAA: + if ((type == T_A && dlen != INT32SZ) || + (type == T_AAAA && dlen != NS_IN6ADDRSZ)) return (0); /*FALLTHROUGH*/ case T_WKS: @@ -1153,6 +1503,8 @@ rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp, case T_ISDN: case T_NSAP: case T_LOC: + case T_KEY: + case ns_t_cert: if (size < dlen) return (0); memcpy(cp1, cp, dlen); @@ -1249,6 +1601,56 @@ rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp, if (cp != cpinit + dlen) return (0); return (cp1 - cp1init); + case T_SIG: + if (dlen < SIG_HDR_SIZE || size < dlen) + return (0); + memcpy(cp1, cp, SIG_HDR_SIZE); + size -= SIG_HDR_SIZE; + cp += SIG_HDR_SIZE; + cp1 += SIG_HDR_SIZE; + n = dn_expand(msg, eom, cp, (char *)cp1, size); + if (n < 0 || n + SIG_HDR_SIZE > dlen) + return (0); + cp += n; + n1 = dlen - n - SIG_HDR_SIZE; + n = strlen((char *)cp1) + 1; + cp1 += n; + if (size < n1) + return (0); + memcpy(cp1, cp, n1); + cp1 += n1; + return (cp1 - cp1init); + case T_NXT: + n = dn_expand(msg, eom, cp, (char *)cp1, size); + if (n < 0 || (u_int)n >= dlen) + return (0); + size -= n; + cp += n; + n1 = dlen - n; + n = strlen((char *)cp1) + 1; + cp1 += n; + /* + * The first bit of the first octet determines the format + * of the NXT record. A format for types >= 128 has not + * yet been defined, so if bit zero is set, we just copy + * what's there because we don't understand it. + */ + if ((*cp & 0x80) == 0) { + /* + * Bit zero is not set; this is an ordinary NXT + * record. The bitmap must be at least 4 octets + * because the NXT bit should be set. It should be + * less than or equal to 16 octets because this NXT + * format is only defined for types < 128. + */ + if (n1 < 4 || n1 > 16) + return (0); + } + if (n1 > size) + return (0); + memcpy(cp1, cp, n1); + cp1 += n1; + return (cp1 - cp1init); default: ns_debug(ns_log_update, 3, "unknown type %d", type); return (0); @@ -1267,6 +1669,10 @@ rdata_dump(struct databuf *dp, FILE *fp) { u_char *cp, *end; int i, j; const char *proto; + u_char *savecp; + char temp_base64[NS_MD5RSA_MAX_BASE64]; + u_int16_t keyflags; + u_char *sigdata, *certdata; cp = (u_char *)dp->d_data; switch (dp->d_type) { @@ -1339,6 +1745,15 @@ rdata_dump(struct databuf *dp, FILE *fp) { fprintf(fp, "%u", n); fprintf(fp, " %s.", cp); break; + case T_SRV: + GETSHORT(n, cp); /* priority */ + fprintf(fp, "%u ", n); + GETSHORT(n, cp); /* weight */ + fprintf(fp, "%u ", n); + GETSHORT(n, cp); /* port */ + fprintf(fp, "%u ", n); + fprintf(fp, " %s.", cp); + break; case T_PX: GETSHORT(n, cp); fprintf(fp, "%u", n); @@ -1353,12 +1768,16 @@ rdata_dump(struct databuf *dp, FILE *fp) { while (cp < end) { if ((n = *cp++) != '\0') { for (j = n; j > 0 && cp < end; j--) - if (*cp == '\n') { - (void) putc('\\', fp); - (void) putc(*cp++, fp); + if ((*cp < ' ') || (*cp > '~')) { + fprintf(fp, "\\%03.3d", *cp++); + } else if (*cp == '\\' || *cp =='"') { + putc('\\', fp); + putc(*cp++, fp); } else (void) putc(*cp++, fp); } + if (cp != end) + fputs("\" \"", fp); } /* XXXVIX need to keep the segmentation (see 4.9.5). */ (void) fputs("\"", fp); @@ -1393,6 +1812,91 @@ rdata_dump(struct databuf *dp, FILE *fp) { cp += strlen((char *)cp) + 1; fprintf(fp, " %s.", cp); break; + case T_KEY: + savecp = cp; /* save the beginning */ + /*>>> Flags (unsigned_16) */ + NS_GET16(keyflags,cp); + fprintf(fp, "0x%04x ", keyflags); + /*>>> Protocol (8-bit decimal) */ + fprintf(fp, "%3u ", *cp++); + /*>>> Algorithm id (8-bit decimal) */ + fprintf(fp, "%3u ", *cp++); + + /*>>> Public-Key Data (multidigit BASE64) */ + /* containing ExponentLen, Exponent, and Modulus */ + i = b64_ntop(cp, dp->d_size - (cp - savecp), + temp_base64, sizeof temp_base64); + if (i < 0) + fprintf(fp, "; BAD BASE64"); + else + fprintf(fp, "%s", temp_base64); + break; + case T_SIG: + sigdata = cp; + /* RRtype (char *) */ + NS_GET16(n,cp); + fprintf(fp, "%s ", p_type(n)); + /* Algorithm id (8-bit decimal) */ + fprintf(fp, "%d ", *cp++); + /* Labels (8-bit decimal) (not saved in file) */ + /* XXXX FIXME -- check value and print err if bad */ + cp++; + /* OTTL (u_long) */ + NS_GET32(n, cp); + fprintf(fp, "%u ", n); + /* Texp (u_long) */ + NS_GET32(n, cp); + fprintf(fp, "%s ", p_secstodate (n)); + /* Tsig (u_long) */ + NS_GET32(n, cp); + fprintf(fp, "%s ", p_secstodate (n)); + /* Kfootprint (unsigned_16) */ + NS_GET16(n, cp); + fprintf(fp, "%u ", n); + /* Signer's Name (char *) */ + fprintf(fp, "%s ", cp); + cp += strlen((char *)cp) + 1; + /* Signature (base64 of any length) */ + i = b64_ntop(cp, dp->d_size - (cp - sigdata), + temp_base64, sizeof temp_base64); + if (i < 0) + fprintf(fp, "; BAD BASE64"); + else + fprintf(fp, "%s", temp_base64); + break; + + case T_NXT: + fprintf(fp, "%s.", cp); + n = strlen ((char *)cp) + 1; + cp += n; + i = 8 * (dp->d_size - n); /* How many bits? */ + for (n = 0; n < (u_int32_t)i; n++) { + if (NS_NXT_BIT_ISSET(n, cp)) + fprintf(fp," %s",__p_type(n)); + } + break; + case ns_t_cert: + certdata = cp; + NS_GET16(n,cp); + fprintf(fp, "%d ", n); /* cert type */ + + NS_GET16(n,cp); + fprintf(fp, "%d %d ", n, *cp++); /* tag & alg */ + + /* Certificate (base64 of any length) */ + i = b64_ntop(cp, dp->d_size - (cp - certdata), + temp_base64, sizeof(temp_base64)); + if (i < 0) + fprintf(fp, "; BAD BASE64"); + else + fprintf(fp, "%s", temp_base64); + break; + case ns_t_aaaa: { + char t[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; + + (void) fputs(inet_ntop(AF_INET6, dp->d_data, t, sizeof t), fp); + break; + } default: fprintf(fp, "\t;?d_type=%d?", dp->d_type); } @@ -1404,7 +1908,7 @@ rdata_dump(struct databuf *dp, FILE *fp) { * authoritative zone numbers will be stored in "zonelist", ordered * deepest match first. */ -static int +int findzone(const char *dname, int class, int depth, int *zonelist, int maxzones){ char *tmpdname; char tmpdnamebuf[MAXDNAME]; @@ -1428,7 +1932,7 @@ zonelist=0x%x, maxzones=%d)", tmpdname = tmpdnamebuf; /* * The code to handle trailing dots and escapes is adapted - * from samedomain(). + * from ns_samedomain(). */ tmpdnamelen = strlen(tmpdname); /* @@ -1538,7 +2042,7 @@ zonelist=0x%x, maxzones=%d)", * returns -1 on error, 0 on success, 1 if dump reload needed */ int -merge_logs(struct zoneinfo *zp) { +merge_logs(struct zoneinfo *zp, char *logname) { char origin[MAXDNAME], data[MAXDATA], dnbuf[MAXDNAME], sclass[3]; char buf[BUFSIZ], buf2[100]; FILE *fp; @@ -1558,6 +2062,7 @@ merge_logs(struct zoneinfo *zp) { u_char *serialp; struct sockaddr_in empty_from; int datasize; + unsigned long l; empty_from.sin_family = AF_INET; empty_from.sin_addr.s_addr = htonl(INADDR_ANY); @@ -1568,64 +2073,67 @@ merge_logs(struct zoneinfo *zp) { * getword() is used here just to be consistent with db_load() */ + ns_debug(ns_log_update, 3, "merge_logs(%s)", logname); + /* If there is no log file, just return. */ - if (stat(zp->z_updatelog, &st) < 0) { + if (stat(logname, &st) < 0) { if (errno != ENOENT) ns_error(ns_log_update, "unexpected stat(%s) failure: %s", - zp->z_updatelog, strerror(errno)); + logname, strerror(errno)); return (-1); } - fp = fopen(zp->z_updatelog, "r"); + fp = fopen(logname, "r"); if (fp == NULL) { ns_error(ns_log_update, "fopen(%s) failed: %s", - zp->z_updatelog, strerror(errno)); + logname, strerror(errno)); return (-1); } /* * See if we really have a log file -- it might be a zone dump - * that was in the process of being renamed, or it might + * that was in the process of being movefiled, or it might * be garbage! */ if (fgets(buf, sizeof(buf), fp)==NULL) { ns_error(ns_log_update, "fgets() from %s failed: %s", - zp->z_updatelog, strerror(errno)); + logname, strerror(errno)); fclose(fp); return (-1); } if (strcmp(buf, DumpSignature) == 0) { - /* It's a dump; finish rename that was interrupted. */ + /* It's a dump; finish movefile that was interrupted. */ ns_info(ns_log_update, - "completing interrupted dump rename for %s", + "completing interrupted dump movefile for %s", zp->z_source); - if (rename(zp->z_updatelog, zp->z_source) < 0) { - ns_error(ns_log_update, "rename(%s,%s) failed: %s", - zp->z_updatelog, zp->z_source, + fclose(fp); + if (movefile(logname, zp->z_source) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s :1", + logname, zp->z_source, strerror(errno)); + fclose(fp); return (-1); } - fclose(fp); /* Finally, tell caller to reload zone. */ return (1); } if (strcmp(buf, LogSignature) != 0) { /* Not a dump and not a log; complain and then bail out. */ ns_error(ns_log_update, "invalid log file %s", - zp->z_updatelog); + logname); fclose(fp); return (-1); } ns_debug(ns_log_update, 3, "merging logs for %s from %s", - zp->z_origin, zp->z_updatelog); + zp->z_origin, logname); lineno = 1; - rrecp_start = NULL; - rrecp_last = NULL; + INIT_LIST(curupd); for (;;) { + err = 0; if (!getword(buf, sizeof buf, fp, 0)) { - if (lineno == (nonempty_lineno + 1)) { + if (lineno == (nonempty_lineno + 1) && !(feof(fp))) { /* * End of a nonempty line inside an update * packet or not inside an update packet. @@ -1644,7 +2152,8 @@ merge_logs(struct zoneinfo *zp) { nonempty_lineno = lineno; } - if (!strcasecmp(buf, "[DYNAMIC_UPDATE]")) { + if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") || + !strcasecmp(buf, "[IXFR_UPDATE]")) { err = 0; rcode = NOERROR; cp = fgets(buf, sizeof buf, fp); @@ -1665,13 +2174,13 @@ merge_logs(struct zoneinfo *zp) { &old_serial, &new_serial)) { ns_error(ns_log_update, "incr_serial problem with %s", - zp->z_updatelog); + logname); } else { serial = get_serial(zp); if (serial != old_serial) { ns_error(ns_log_update, "serial number mismatch (log=%u, zone=%u) in %s", old_serial, - serial, zp->z_updatelog); + serial, logname); } else { set_serial(zp, new_serial); /* @@ -1682,26 +2191,30 @@ merge_logs(struct zoneinfo *zp) { sched_zone_maint(zp); ns_info(ns_log_update, "set serial to %u (log file %s)", - new_serial, zp->z_updatelog); + new_serial, logname); } } prev_pktdone = 1; cont = 1; + } else if (!strcasecmp(buf, "[END_DELTA]")) { + prev_pktdone = 1; + cont = 1; } if (prev_pktdone) { - if (rrecp_start) { - n = process_updates(rrecp_start, &rcode, + if (!EMPTY(curupd)) { + n = process_updates(&curupd, &rcode, empty_from); if (n > 0) ns_info(ns_log_update, "successfully merged update id %d from log file %s", - id, zp->z_updatelog); - else + id, logname); + else { ns_error(ns_log_update, "error merging update id %d from log file %s", - id, zp->z_updatelog); - free_rrecp(&rrecp_start, &rrecp_last, rcode, - empty_from); + id, logname); + return(-1); + } + free_rrecp(&curupd, rcode, empty_from); } prev_pktdone = 0; if (feof(fp)) @@ -1738,7 +2251,7 @@ merge_logs(struct zoneinfo *zp) { *buf = '\0'; n = sscanf(cp, "origin %s class %s serial %ul", origin, sclass, &serial); - if (n != 3 || strcasecmp(origin, zp->z_origin)) + if (n != 3 || ns_samename(origin, zp->z_origin) != 1) err++; if (cp) lineno++; @@ -1746,7 +2259,7 @@ merge_logs(struct zoneinfo *zp) { ns_error(ns_log_update, "serial number mismatch in update id %d (log=%u, zone=%u) in %s", id, serial, zp->z_serial, - zp->z_updatelog); + logname); inside_next = 0; err++; } @@ -1809,11 +2322,11 @@ merge_logs(struct zoneinfo *zp) { data[0] = '\0'; (void) getword(buf, sizeof buf, fp, 1); if (isdigit(buf[0])) { /* ttl */ - ttl = strtoul(buf, 0, 10); - if (errno == ERANGE && ttl == ULONG_MAX) { + if (ns_parse_ttl(buf, &l) < 0) { err++; break; } + ttl = l; (void) getword(buf, sizeof buf, fp, 1); } @@ -1888,45 +2401,56 @@ merge_logs(struct zoneinfo *zp) { case T_MINFO: case T_RP: (void) strcpy(data, buf); - cp = data + strlen(data) + 1; + cp = data + strlen(data) -1; + *(cp++) = 0; /* ditch dot */ if (!getword((char *)cp, sizeof data - (cp - data), fp, 1)) { err++; break; } - cp += strlen((char *)cp) + 1; + cp += strlen((char *)cp) -1; + *(cp++) = 0; /* ditch dot */ if (type != T_SOA) { n = cp - data; break; } + else + n = cp - data; if (class != zp->z_class || - strcasecmp(dname, zp->z_origin)) { + ns_samename(dname, zp->z_origin) != 1) { err++; break; } - c = getnonblank(fp, zp->z_updatelog); + c = getnonblank(fp, logname); if (c == '(') { multiline = 1; } else { multiline = 0; ungetc(c, fp); } - for (i = 0; i < 5; i++) { - n = getnum(fp, zp->z_updatelog, - GETNUM_SERIAL); - if (getnum_error) { + n = getnum(fp, logname, GETNUM_SERIAL); + if (getnum_error) { + err++; + break; + } + PUTLONG(n, cp); + for (i = 0; i < 4; i++) { + if (getttl(fp, logname, lineno, + &n, &multiline) <= 0) + { err++; break; } PUTLONG(n, cp); } if (multiline && - getnonblank(fp, zp->z_updatelog) - != ')') { + (getnonblank(fp, logname) + != ')')) { err++; break; } + n = cp - data; endline(fp); break; case T_WKS: @@ -1938,11 +2462,11 @@ merge_logs(struct zoneinfo *zp) { cp = data; PUTLONG(n, cp); *cp = (char)getprotocol(fp, - zp->z_updatelog + logname ); n = INT32SZ + sizeof(char); n = getservices((int)n, data, - fp, zp->z_updatelog); + fp, logname); break; case T_NS: case T_CNAME: @@ -2012,22 +2536,24 @@ merge_logs(struct zoneinfo *zp) { cp = data; datasize = sizeof data; cp1 = buf; - while (i > 255) { - if (datasize < 256) { + while (i > MAXCHARSTRING) { + if (datasize <= MAXCHARSTRING){ ns_error(ns_log_update, "record too big"); + fclose(fp); return (-1); } - datasize -= 255; - *cp++ = 255; - memcpy(cp, cp1, 255); - cp += 255; - cp1 += 255; - i -= 255; + datasize -= MAXCHARSTRING; + *cp++ = (char)MAXCHARSTRING; + memcpy(cp, cp1, MAXCHARSTRING); + cp += MAXCHARSTRING; + cp1 += MAXCHARSTRING; + i -= MAXCHARSTRING; } if (datasize < i + 1) { ns_error(ns_log_update, "record too big"); + fclose(fp); return (-1); } *cp++ = i; @@ -2064,6 +2590,29 @@ merge_logs(struct zoneinfo *zp) { } endline(fp); break; + case ns_t_sig: + case ns_t_key: + case ns_t_nxt: + case ns_t_cert: + { + char * errmsg = NULL; + int s; + + s = parse_sec_rdata(buf, sizeof(buf), + 1, + (u_char *)data, + sizeof(data), + fp, zp, dnbuf, + ttl, type, + domain_ctx, + primary_trans, + &errmsg); + if (s < 0) { + err++; + break; + } + break; + } default: err++; } @@ -2086,11 +2635,22 @@ merge_logs(struct zoneinfo *zp) { } } else { /* section == S_UPDATE */ if (opcode == DELETE) { + ttl = 0; if (n == 0) { class = C_ANY; if (type == -1) type = T_ANY; - } else { + /* WTF? C_NONE or C_ANY _must_ be the case if + * we really are to delete this. If + * C_NONE is used, according to process_updates(), + * the class is gotten from the zone's class. + * This still isn't perfect, but it will at least + * work. + * + * Question: What is so special about the class + * of the update while we are deleting?? + */ + } else /* if (zp->z_xferpid != XFER_ISIXFR) */ { class = C_NONE; } } @@ -2108,8 +2668,7 @@ merge_logs(struct zoneinfo *zp) { ns_debug(ns_log_update, 1, "merge of update id %d failed due to error at line %d", id, lineno); - free_rrecp(&rrecp_start, &rrecp_last, rcode, - empty_from); + free_rrecp(&curupd, FORMERR, empty_from); continue; } rrecp = res_mkupdrec(section, dname, class, type, ttl); @@ -2118,21 +2677,12 @@ merge_logs(struct zoneinfo *zp) { dp->d_zone = zonenum; dp->d_cred = DB_C_ZONE; dp->d_clev = nlabels(zp->z_origin); + dp->d_secure = DB_S_INSECURE; /* should be UNCHECKED */ rrecp->r_dp = dp; } else { rrecp->r_zone = zonenum; } - if (rrecp_start == NULL) { - rrecp_start = rrecp; - rrecp_last = rrecp; - rrecp->r_prev = NULL; - rrecp->r_next = NULL; - } else { - rrecp_last->r_next = rrecp; - rrecp->r_prev = rrecp_last; - rrecp->r_next = NULL; - rrecp_last = rrecp; - } + APPEND(curupd, rrecp, r_link); } /* for (;;) */ fclose(fp); @@ -2144,9 +2694,7 @@ merge_logs(struct zoneinfo *zp) { * Create a disk database to back up zones */ int -zonedump(zp) - struct zoneinfo *zp; -{ +zonedump(struct zoneinfo *zp, int mode) { FILE *fp; const char *fname; struct hashbuf *htp; @@ -2213,11 +2761,13 @@ zonedump(zp) if (fflush(fp) == EOF) { ns_error(ns_log_update, "fflush() of %s failed: %s", tmp_name, strerror(errno)); + fclose(fp); return (-1); } if (fsync(fileno(fp)) < 0) { ns_error(ns_log_update, "fsync() of %s failed: %s", tmp_name, strerror(errno)); + fclose(fp); return (-1); } if (fclose(fp) == EOF) { @@ -2242,16 +2792,47 @@ zonedump(zp) tmp_name, st.st_mode, strerror(errno)); } - if (rename(tmp_name, zp->z_updatelog) < 0) { - ns_error(ns_log_update, "rename(%s,%s) failed: %s", - tmp_name, zp->z_updatelog, strerror(errno)); - return (-1); - } - if (rename(zp->z_updatelog, zp->z_source) < 0) { - ns_error(ns_log_update, "rename(%s,%s) failed: %s", - zp->z_updatelog, zp->z_source, - strerror(errno)); - return (-1); + + if (mode == ISIXFR) { + if (movefile(tmp_name, zp->z_ixfr_tmp) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s :2", + tmp_name, zp->z_ixfr_tmp, strerror(errno)); + return (-1); + } + if (chmod(zp->z_source, 0644) < 0) + ns_error(ns_log_update, + "chmod(%s,%o) failed, pressing on: %s", + zp->z_source, st.st_mode, + strerror(errno)); + if (movefile(zp->z_ixfr_tmp, zp->z_source) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s :3", + zp->z_ixfr_tmp, zp->z_source, + strerror(errno)); + return (-1); + } + st.st_mode &= ~WRITEABLE_MASK; + if (chmod(zp->z_source, st.st_mode) < 0) + ns_error(ns_log_update, + "chmod(%s,%o) failed, pressing on: %s", + zp->z_source, st.st_mode, + strerror(errno)); + } else if (mode == ISNOTIXFR) { + if (movefile(tmp_name, zp->z_updatelog) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s :4", + tmp_name, zp->z_updatelog, strerror(errno)); + return (-1); + } + if (movefile(zp->z_updatelog, zp->z_source) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s:5", + zp->z_updatelog, zp->z_source, + strerror(errno)); + return (-1); + } + } else { + if (movefile(tmp_name, zp->z_source) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: % s :6", tmp_name, zp->z_source, strerror(errno)); + return (-1); + } } } else ns_debug(ns_log_update, 1, "zonedump: no zone to dump"); @@ -2332,10 +2913,10 @@ set_serial(struct zoneinfo *zp, u_int32_t serial) { zp->z_updatecnt = 0; #ifdef BIND_NOTIFY if (!loading) - sysnotify(zp->z_origin, zp->z_class, T_SOA); + ns_notify(zp->z_origin, zp->z_class, ns_t_soa); #endif /* - * Note: caller is responsible for scheduling a dump + * Note: caller is responsible for scheduling a dump. */ } @@ -2346,8 +2927,10 @@ set_serial(struct zoneinfo *zp, u_int32_t serial) { int incr_serial(struct zoneinfo *zp) { u_int32_t serial, old_serial; - FILE *fp; + FILE *fp, *ifp; time_t t; + struct databuf *dp, *olddp; + unsigned char *cp; old_serial = get_serial(zp); serial = old_serial + 1; @@ -2364,6 +2947,32 @@ incr_serial(struct zoneinfo *zp) { old_serial, serial, checked_ctime(&t)); if (close_transaction_log(zp, fp)<0) return (-1); + ifp = open_ixfr_log(zp); + if (ifp == NULL) + return (-1); + dp = findzonesoa(zp); + if (dp) { + olddp = memget(DATASIZE(dp->d_size)); + if (olddp != NULL) { + memcpy(olddp, dp, DATASIZE(dp->d_size)); + cp = findsoaserial(olddp->d_data); + PUTLONG(old_serial, cp); + fprintf(ifp, "update: {delete} %s. %u %s %s ", + zp->z_origin, dp->d_ttl, + p_class(dp->d_class), p_type(dp->d_type)); + (void) rdata_dump(olddp, ifp); + fprintf(ifp, "\n"); + memput(olddp, DATASIZE(dp->d_size)); + } + fprintf(ifp, "update: {add} %s. %u %s %s ", + zp->z_origin, dp->d_ttl, + p_class(dp->d_class), p_type(dp->d_type)); + (void) rdata_dump(dp, ifp); + fprintf(ifp, "\n"); + } + fprintf(ifp, "[END_DELTA]\n"); + if (close_ixfr_log(zp, ifp)<0) + return (-1); /* * This shouldn't happen, but we check to be sure. @@ -2390,6 +2999,6 @@ dynamic_about_to_exit(void) { if ((zp->z_flags & Z_DYNAMIC) && ((zp->z_flags & Z_NEED_SOAUPDATE) || (zp->z_flags & Z_NEED_DUMP))) - (void)zonedump(zp); + (void)zonedump(zp, ISNOTIXFR); } } diff --git a/contrib/bind/bin/named/ns_xfr.c b/contrib/bind/bin/named/ns_xfr.c index 52d3464..e25a536 100644 --- a/contrib/bind/bin/named/ns_xfr.c +++ b/contrib/bind/bin/named/ns_xfr.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_xfr.c,v 8.25 1998/03/25 18:47:34 halley Exp $"; +static const char rcsid[] = "$Id: ns_xfr.c,v 8.55 1999/10/13 16:39:13 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,6 +24,7 @@ static char rcsid[] = "$Id: ns_xfr.c,v 8.25 1998/03/25 18:47:34 halley Exp $"; #include <sys/param.h> #include <sys/file.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -32,26 +33,26 @@ static char rcsid[] = "$Id: ns_xfr.c,v 8.25 1998/03/25 18:47:34 halley Exp $"; #include <errno.h> #include <fcntl.h> #include <resolv.h> +#include <res_update.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <syslog.h> #include <time.h> +#include <unistd.h> #include <isc/eventlib.h> #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" static struct qs_x_lev *sx_freelev(struct qs_x_lev *lev); -static void sx_newmsg(struct qstream *qsp), - sx_sendlev(struct qstream *qsp), - sx_sendsoa(struct qstream *qsp); - static int sx_flush(struct qstream *qsp), sx_addrr(struct qstream *qsp, const char *dname, @@ -59,20 +60,18 @@ static int sx_flush(struct qstream *qsp), sx_nsrrs(struct qstream *qsp), sx_allrrs(struct qstream *qsp), sx_pushlev(struct qstream *qsp, struct namebuf *np); +static struct databuf *db_next(struct databuf *dp); /* * void - * ns_xfr(qsp, znp, zone, class, type, opcode, id) + * ns_xfr(qsp, znp, zone, class, type, opcode, id, serial_ixfr, in_tsig) * Initiate a concurrent (event driven) outgoing zone transfer. */ void ns_xfr(struct qstream *qsp, struct namebuf *znp, int zone, int class, int type, - int opcode, int id) + int opcode, int id, u_int32_t serial_ixfr, struct tsig_record *in_tsig) { - FILE *rfp; - int fdstat; - pid_t pid; server_info si; #ifdef SO_SNDBUF static const int sndbuf = XFER_BUFSIZE * 2; @@ -80,9 +79,26 @@ ns_xfr(struct qstream *qsp, struct namebuf *znp, #ifdef SO_SNDLOWAT static const int sndlowat = XFER_BUFSIZE; #endif + ns_updrec *changes; - ns_info(ns_log_xfer_out, "zone transfer of \"%s\" (%s) to %s", - zones[zone].z_origin, p_class(class), sin_ntoa(qsp->s_from)); + switch (type) { + case ns_t_axfr: /*FALLTHROUGH*/ + case ns_t_ixfr: +#ifdef BIND_ZXFR + case ns_t_zxfr: +#endif + ns_info(ns_log_xfer_out, + "zone transfer (%s) of \"%s\" (%s) to %s", + p_type(type), zones[zone].z_origin, p_class(class), + sin_ntoa(qsp->s_from)); + break; + default: + ns_warning(ns_log_xfer_out, + "unsupported XFR (type %s) of \"%s\" (%s) to %s", + p_type(type), zones[zone].z_origin, p_class(class), + sin_ntoa(qsp->s_from)); + goto abort; + } #ifdef SO_SNDBUF /* @@ -104,9 +120,10 @@ ns_xfr(struct qstream *qsp, struct namebuf *znp, if (sq_openw(qsp, 64*1024) == -1) goto abort; memset(&qsp->xfr, 0, sizeof qsp->xfr); - qsp->xfr.top = znp; + qsp->xfr.top.axfr = znp; qsp->xfr.zone = zone; qsp->xfr.class = class; + qsp->xfr.type = type; qsp->xfr.id = id; qsp->xfr.opcode = opcode; qsp->xfr.msg = memget(XFER_BUFSIZE); @@ -118,19 +135,76 @@ ns_xfr(struct qstream *qsp, struct namebuf *znp, zones[zone].z_numxfrs++; qsp->flags |= STREAM_AXFR; +#ifdef BIND_ZXFR + if (type == ns_t_zxfr) { + enum { rd = 0, wr = 1 }; + int z[2]; + pid_t p; + + if (pipe(z) < 0) { + ns_error(ns_log_xfer_out, "pipe: %s", strerror(errno)); + goto abort; + } + p = vfork(); + if (p < 0) { + ns_error(ns_log_xfer_out, "vfork: %s", strerror(errno)); + goto abort; + } + if (p == 0) { + /* Child. */ + dup2(z[rd], STDIN_FILENO); + dup2(qsp->s_rfd, STDOUT_FILENO); + execlp("gzip", "gzip", NULL); + ns_error(ns_log_xfer_out, "execlp: %s", strerror(errno)); + _exit(1); + } + ns_info(ns_log_xfer_out, "zxfr gzip pid %lu", p); + /* Parent. */ + dup2(z[wr], qsp->s_rfd); + close(z[wr]); + close(z[rd]); + + /* When a ZXFR completes, there can be no more requests. */ + qsp->flags |= STREAM_DONE_CLOSE; + } +#endif + si = find_server(qsp->s_from.sin_addr); if (si != NULL && si->transfer_format != axfr_use_default) qsp->xfr.transfer_format = si->transfer_format; else qsp->xfr.transfer_format = server_options->transfer_format; + if (in_tsig == NULL) + qsp->xfr.tsig_state = NULL; + else { + qsp->xfr.tsig_state = memget(sizeof(ns_tcp_tsig_state)); + ns_sign_tcp_init(in_tsig->key, in_tsig->sig, in_tsig->siglen, + qsp->xfr.tsig_state); + qsp->xfr.tsig_skip = 0; + } - if (sx_pushlev(qsp, znp) < 0) { - abort: - (void) shutdown(qsp->s_rfd, 2); - sq_remove(qsp); - return; + if (type == ns_t_ixfr) { + changes = ixfr_get_change_list(&zones[zone], serial_ixfr, + zones[zone].z_serial); + if (changes != NULL) + { + qsp->xfr.serial = serial_ixfr; + qsp->xfr.top.ixfr = changes; + } + else + type = ns_t_axfr; } - (void) sq_writeh(qsp, sx_sendsoa); + if (sx_pushlev(qsp, znp) < 0) { + abort: + (void) shutdown(qsp->s_rfd, 2); + sq_remove(qsp); + return; + } + if (type != ns_t_ixfr) + (void) sq_writeh(qsp, sx_sendsoa); + else + (void) sq_writeh(qsp, sx_send_ixfr); + } /* @@ -176,7 +250,7 @@ ns_freexfr(struct qstream *qsp) { * init the header of a message, reset the compression pointers, and * reset the write pointer to the first byte following the header. */ -static void +void sx_newmsg(struct qstream *qsp) { HEADER *hp = (HEADER *)qsp->xfr.msg; @@ -190,6 +264,11 @@ sx_newmsg(struct qstream *qsp) { qsp->xfr.ptrs[1] = NULL; qsp->xfr.cp = qsp->xfr.msg + HFIXEDSZ; + + qsp->xfr.eom = qsp->xfr.msg + XFER_BUFSIZE; + + if (qsp->xfr.tsig_state != NULL) + qsp->xfr.eom -= TSIG_BUF_SIZE; } /* @@ -205,12 +284,30 @@ sx_flush(struct qstream *qsp) { #ifdef DEBUG if (debug >= 10) - fp_nquery(qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg, - log_get_stream(packet_channel)); + res_pquery(&res, qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg, + log_get_stream(packet_channel)); #endif + if (qsp->xfr.tsig_state != NULL && qsp->xfr.tsig_skip == 0) { + int msglen = qsp->xfr.cp - qsp->xfr.msg; + + ns_sign_tcp(qsp->xfr.msg, &msglen, qsp->xfr.eom - qsp->xfr.msg, + NOERROR, qsp->xfr.tsig_state, + qsp->xfr.state == s_x_done); + + if (qsp->xfr.state == s_x_done) { + memput(qsp->xfr.tsig_state, sizeof(ns_tcp_tsig_state)); + qsp->xfr.tsig_state = NULL; + } + qsp->xfr.cp = qsp->xfr.msg + msglen; + + } ret = sq_write(qsp, qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg); - if (ret >= 0) + if (ret >= 0) { qsp->xfr.cp = NULL; + qsp->xfr.tsig_skip = 0; + } + else + qsp->xfr.tsig_skip = 1; return (ret); } @@ -229,7 +326,7 @@ static int sx_addrr(struct qstream *qsp, const char *dname, struct databuf *dp) { HEADER *hp = (HEADER *)qsp->xfr.msg; u_char **edp = qsp->xfr.ptrs + sizeof qsp->xfr.ptrs / sizeof(u_char*); - int n; + int n, type; if (qsp->xfr.cp != NULL) { if (qsp->xfr.transfer_format == axfr_one_answer && @@ -238,15 +335,34 @@ sx_addrr(struct qstream *qsp, const char *dname, struct databuf *dp) { } if (qsp->xfr.cp == NULL) sx_newmsg(qsp); + + /* + * Add question to first answer. + */ + if (qsp->xfr.state == s_x_firstsoa && dp->d_type == T_SOA ) { + if ((qsp->xfr.type == ns_t_ixfr) || (qsp->flags & STREAM_AXFRIXFR)) { + n = dn_comp(dname, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp, + qsp->xfr.ptrs, edp); + if (n > 0 && (qsp->xfr.cp + n + INT16SZ * 2) <= qsp->xfr.eom) { + qsp->xfr.cp += n; + type = (qsp->xfr.type == ns_t_zxfr) ? + ns_t_axfr : qsp->xfr.type; + PUTSHORT((u_int16_t) type, qsp->xfr.cp); + PUTSHORT((u_int16_t) qsp->xfr.class, qsp->xfr.cp); + hp->qdcount = htons(ntohs(hp->qdcount) + 1); + } + } + } + n = make_rr(dname, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp, - 0, qsp->xfr.ptrs, edp); + 0, qsp->xfr.ptrs, edp, 0); if (n < 0) { if (sx_flush(qsp) < 0) return (-1); if (qsp->xfr.cp == NULL) sx_newmsg(qsp); n = make_rr(dname, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp, - 0, qsp->xfr.ptrs, edp); + 0, qsp->xfr.ptrs, edp, 0); INSIST(n >= 0); } hp->ancount = htons(ntohs(hp->ancount) + 1); @@ -264,18 +380,37 @@ sx_addrr(struct qstream *qsp, const char *dname, struct databuf *dp) { * side effects: * if progress was made, header and pointers will be advanced. */ -static int +int sx_soarr(struct qstream *qsp) { struct databuf *dp; + int added_soa = 0; - foreach_rr(dp, qsp->xfr.top, T_SOA, qsp->xfr.class, qsp->xfr.zone) { + foreach_rr(dp, qsp->xfr.top.axfr, T_SOA, qsp->xfr.class, + qsp->xfr.zone) { if (sx_addrr(qsp, zones[qsp->xfr.zone].z_origin, dp) < 0) { /* RR wouldn't fit. Bail out. */ return (-1); } - return (0); + added_soa = 1; + break; } - ns_panic(ns_log_xfer_out, 1, "no SOA at zone top"); + if (added_soa == 0) + ns_panic(ns_log_xfer_out, 1, "no SOA at zone top"); + if (qsp->xfr.state == s_x_firstsoa) { + foreach_rr(dp, qsp->xfr.top.axfr, T_SIG, qsp->xfr.class, + qsp->xfr.zone) + { + if (SIG_COVERS(dp) != T_SOA) + continue; + if (sx_addrr(qsp, zones[qsp->xfr.zone].z_origin, dp) < + 0) + { + /* RR wouldn't fit. Bail out. */ + return (-1); + } + } + } + return (0); } /* @@ -283,6 +418,9 @@ sx_soarr(struct qstream *qsp) { * sx_nsrrs(qsp) * add the NS RR's at the current level's current np, * to the assembly message + * This function also adds the SIG(NS), KEY, SIG(KEY), NXT, SIG(NXT) + * the reason for this these records are part of the delegation. + * * return: * >1 = number of NS RRs added, note that there may be more * 0 = success, there are no more NS RRs at this level @@ -303,11 +441,11 @@ sx_nsrrs(struct qstream *qsp) { int rrcount, class; class = qsp->xfr.class; - top = qsp->xfr.top; + top = qsp->xfr.top.axfr; rrcount = 0; for ((void)NULL; (dp = qsp->xfr.lev->dp) != NULL; - qsp->xfr.lev->dp = dp->d_next) { + qsp->xfr.lev->dp = db_next(dp)) { /* XYZZY foreach_rr? */ if (dp->d_class != class && class != C_ANY) continue; @@ -323,14 +461,21 @@ sx_nsrrs(struct qstream *qsp) { */ if (dp->d_zone == DB_Z_CACHE) continue; - if (dp->d_type != T_NS) + + if (dp->d_type != T_NS && dp->d_type != T_KEY && + dp->d_type != T_NXT && dp->d_type != T_SIG) + continue; + if (dp->d_type == T_SIG && ((SIG_COVERS(dp) != T_NS) && + (SIG_COVERS(dp) != T_KEY) && (SIG_COVERS(dp) != T_NXT))) continue; if (!(qsp->xfr.lev->flags & SXL_GLUING)) { if (sx_addrr(qsp, qsp->xfr.lev->dname, dp) < 0) { /* RR wouldn't fit. Bail out. */ return (-1); } - rrcount++; + if (dp->d_type != T_NS) /* no glue processing */ + continue; + rrcount++; /* only count NS records */ } /* @@ -373,6 +518,16 @@ sx_nsrrs(struct qstream *qsp) { */ return (-1); } + /* for IPv6 glue AAAA record transfer */ + /* patched by yasuhiro@nic.ad.jp, 1999/5/23 */ + foreach_rr(gdp, gnp, T_AAAA, class, DB_Z_CACHE) + if (sx_addrr(qsp, fname, gdp) < 0) { + /* + * Rats. We already sent the NS RR, too. + * Note that SXL_GLUING is being left on. + */ + return (-1); + } qsp->xfr.lev->flags &= ~SXL_GLUING; } return (rrcount); @@ -383,6 +538,8 @@ sx_nsrrs(struct qstream *qsp) { * sx_allrrs(qsp) * add the non-(SOA,NS) RR's at the current level's current np, * to the assembly message + * do not add the DNSSEC types KEY and NXT as the delegation check + * wrote these types out. * return: * >0 = number of RR's added, note that there may be more * 0 = success, there are no more RRs at this level @@ -396,20 +553,18 @@ sx_nsrrs(struct qstream *qsp) { */ static int sx_allrrs(struct qstream *qsp) { - struct databuf *dp, *tdp, *gdp; - struct namebuf *gnp, *tnp, *top; - struct hashbuf *htp; - const char *fname; + struct databuf *dp; + struct namebuf *top; int rrcount, class; u_int zone; class = qsp->xfr.class; - top = qsp->xfr.top; + top = qsp->xfr.top.axfr; zone = qsp->xfr.zone; rrcount = 0; for ((void)NULL; (dp = qsp->xfr.lev->dp) != NULL; - qsp->xfr.lev->dp = dp->d_next) { + qsp->xfr.lev->dp = db_next(dp)) { /* XYZZY foreach_rr? */ if (dp->d_class != class && class != C_ANY) continue; @@ -417,18 +572,13 @@ sx_allrrs(struct qstream *qsp) { continue; if (dp->d_zone != zone || stale(dp)) continue; - if (dp->d_type == T_SOA || dp->d_type == T_NS) + if (dp->d_type == T_SOA || dp->d_type == T_NS || + dp->d_type == T_NXT || dp->d_type == T_KEY) + continue; + if (dp->d_type == T_SIG && + (SIG_COVERS(dp) == T_SOA || SIG_COVERS(dp) == T_NS || + SIG_COVERS(dp) == T_KEY || SIG_COVERS(dp) == T_NXT)) continue; - /* XXXRTH I presume this is still relevant and that - this is the right place... */ -#if 0 /* Not yet implemented. Only a SHOULD in the I-D. -gnu@toad.com */ - /* skip the SIG AXFR record because we did it first too. */ - if (dp->d_type == T_SIG) { - int sig_rrtype = GETSHORT (dp->d_data); - if (sig_rrtype == T_AXFR) - continue; - } -#endif /* 0 */ INSIST(!(qsp->xfr.lev->flags & SXL_GLUING)); if (sx_addrr(qsp, qsp->xfr.lev->dname, dp) < 0) { @@ -452,7 +602,7 @@ sx_allrrs(struct qstream *qsp) { * qsp->xfr.state at the end of the topmost level. changes the * qsp->xfr.lev->state several times per domain name. */ -static void +void sx_sendlev(struct qstream *qsp) { struct qs_x_lev *lev; int rrcount; @@ -462,6 +612,12 @@ sx_sendlev(struct qstream *qsp) { switch (lev->state) { case sxl_ns: { while (lev->dp) { + /* Was the child zone reloaded under us? */ + if ((lev->dp->d_flags & DB_F_ACTIVE) == 0) { + (void) shutdown(qsp->s_rfd, 2); + sq_remove(qsp); + return; + } rrcount = sx_nsrrs(qsp); /* If we can't pack this one in, come back later. */ if (rrcount < 0) @@ -470,7 +626,7 @@ sx_sendlev(struct qstream *qsp) { * NS RRs other than those at the * zone top are zone cuts. */ - if (rrcount > 0 && qsp->xfr.top != lev->np) + if (rrcount > 0 && qsp->xfr.top.axfr != lev->np) lev->flags |= SXL_ZONECUT; } /* No more DP's for the NS RR pass on this NP. */ @@ -481,10 +637,18 @@ sx_sendlev(struct qstream *qsp) { /* No NS RR's, so it's safe to send other types. */ lev->state = sxl_all; lev->dp = lev->np->n_data; + if (lev->dp) + DRCNTINC(lev->dp); goto again; } case sxl_all: { while (lev->dp) { + /* Was a record updated under us? */ + if ((lev->dp->d_flags & DB_F_ACTIVE) == 0) { + (void) shutdown(qsp->s_rfd, 2); + sq_remove(qsp); + return; + } /* If we can't pack this one in, come back later. */ if (sx_allrrs(qsp) < 0) return; @@ -535,11 +699,15 @@ sx_sendlev(struct qstream *qsp) { * side effects: * changes qsp->xfr.state. adds RR to output buffer. */ -static void +void sx_sendsoa(struct qstream *qsp) { + HEADER * hp = (HEADER *) qsp->xfr.msg; + if (sx_soarr(qsp) == -1) return; /* No state change, come back here later. */ + hp->aa = 1; + switch (qsp->xfr.state) { case s_x_firstsoa: { /* Next thing to do is send the zone. */ @@ -549,8 +717,8 @@ sx_sendsoa(struct qstream *qsp) { } case s_x_lastsoa: { /* Next thing to do is go back and wait for another query. */ - (void)sx_flush(qsp); qsp->xfr.state = s_x_done; + (void)sx_flush(qsp); sq_writeh(qsp, sq_flushw); break; } @@ -581,6 +749,8 @@ sx_pushlev(struct qstream *qsp, struct namebuf *np) { new->state = sxl_ns; new->np = np; new->dp = np->n_data; + if (new->dp) + DRCNTINC(new->dp); getname(np, new->dname, sizeof new->dname); /* * We find the subdomains by looking in the hash table for this @@ -637,6 +807,26 @@ static struct qs_x_lev * sx_freelev(struct qs_x_lev *lev) { struct qs_x_lev *next = lev->next; + if (lev->dp) { + DRCNTDEC(lev->dp); + if (lev->dp->d_rcnt == 0) + db_freedata(lev->dp); + } memput(lev, sizeof *lev); return (next); } + +static struct databuf * +db_next(struct databuf *dp) { + struct databuf *next = dp->d_next; + + DRCNTDEC(dp); + if (dp->d_rcnt == 0) + db_freedata(dp); + + if (next) + DRCNTINC(next); + + return (next); +} + diff --git a/contrib/bind/bin/named/pathtemplate.h b/contrib/bind/bin/named/pathtemplate.h index d339ef8..65056b6 100644 --- a/contrib/bind/bin/named/pathtemplate.h +++ b/contrib/bind/bin/named/pathtemplate.h @@ -1,9 +1,9 @@ /* - * $Id: pathtemplate.h,v 8.1 1998/03/19 19:53:21 halley Exp $ + * $Id: pathtemplate.h,v 8.4 1999/01/08 19:28:30 vixie Exp $ */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -41,6 +41,10 @@ #define _PATH_PIDFILE "%DESTRUN%/named.pid" #endif +#ifndef _PATH_NDCSOCK +#define _PATH_NDCSOCK "%DESTRUN%/ndc" +#endif + #ifndef _PATH_STATS #define _PATH_STATS "named.stats" #endif diff --git a/contrib/bind/bin/named/test/named.conf b/contrib/bind/bin/named/test/named.conf index b852604..0e43eac 100644 --- a/contrib/bind/bin/named/test/named.conf +++ b/contrib/bind/bin/named/test/named.conf @@ -5,6 +5,8 @@ options { // directory "/var/named"; check-names master warn; /* default. */ datasize 20M; + deallocate-on-exit yes; + listen-on { 10.0.0.53; }; }; zone "localhost" IN { @@ -27,3 +29,17 @@ zone "." IN { type hint; file "root.hint"; }; + +logging { + channel xfer-log { + file "/var/tmp/bind-xfer.log" versions unlimited size 10m; + print-category yes; + print-severity yes; + print-time yes; + severity info; + }; + category xfer-in { xfer-log; }; + category xfer-out { xfer-log; }; + category notify { xfer-log; }; + category load { xfer-log; }; +}; diff --git a/contrib/bind/bin/named/version.c b/contrib/bind/bin/named/version.c index 9468be2..31820f5 100644 --- a/contrib/bind/bin/named/version.c +++ b/contrib/bind/bin/named/version.c @@ -1,11 +1,11 @@ /* * @(#)Version.c 4.9 (Berkeley) 7/21/90 - * $Id: version.c,v 8.2 1997/04/24 23:59:02 vixie Exp $ + * $Id: version.c,v 8.3 1999/01/02 06:05:14 vixie Exp $ */ #ifndef lint char sccsid[] = "@(#)named %VERSION% %WHEN% %WHOANDWHERE%"; -char rcsid[] = "$Id: version.c,v 8.2 1997/04/24 23:59:02 vixie Exp $"; +char rcsid[] = "$Id: version.c,v 8.3 1999/01/02 06:05:14 vixie Exp $"; #endif /* not lint */ char Version[] = "named %VERSION% %WHEN%\n\t%WHOANDWHERE%"; |