diff options
author | peter <peter@FreeBSD.org> | 1996-12-31 19:51:17 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1996-12-31 19:51:17 +0000 |
commit | b13db018fbb01d60dabb34ce9bd3f06994fd81b7 (patch) | |
tree | a2327c4e40b3c074798fd7f0ddd86f66879ceab5 /contrib/bind/named | |
parent | 2d3cf9fcaf1ca2528c5fe3ba683d1f6c1268dc41 (diff) | |
download | FreeBSD-src-b13db018fbb01d60dabb34ce9bd3f06994fd81b7.zip FreeBSD-src-b13db018fbb01d60dabb34ce9bd3f06994fd81b7.tar.gz |
Import Paul Vixie/ISC's bind-4.9.5-patch1 onto the vendor branch.
This has some (all?) of the DNSSEC key management/distribution mechanism
in place. (The SIG and KEY RR's)
Obtained from: Paul Vixie / ISC / ftp.isc.org
Diffstat (limited to 'contrib/bind/named')
25 files changed, 3169 insertions, 1643 deletions
diff --git a/contrib/bind/named/Makefile b/contrib/bind/named/Makefile index edd6533..777cbb9 100644 --- a/contrib/bind/named/Makefile +++ b/contrib/bind/named/Makefile @@ -1,6 +1,6 @@ # # @(#)Makefile.dist 5.4 (Berkeley) 8/15/90 -# $Id: Makefile,v 8.7 1995/12/22 10:20:30 vixie Exp $ +# $Id: Makefile,v 8.10 1996/09/22 00:13:10 vixie Exp $ # ## ++Copyright++ 1987, 1988, 1990 @@ -89,7 +89,8 @@ CDEBUG= -g LIBS= COMPLIB= ../compat/lib/lib44bsd.a PATH_XFER = ${DESTEXEC}/${XFER_INDOT}named-xfer -DEFS = -D_PATH_XFER=\"${PATH_XFER}\" -D_PATH_PIDFILE=\"${PIDDIR}/named.pid\" +DEFS = -D_PATH_XFER=\"${PATH_XFER}\" -D_PATH_PIDFILE=\"${PIDDIR}/named.pid\" \ + -DKSYMS=\"${KSYMS}\" -DKMEM=\"${KMEM}\" -DUDPSUM=\"${UDPSUM}\" INSTALL = install PS=ps IOT=ABRT @@ -101,14 +102,14 @@ SRCS= db_dump.c db_load.c db_lookup.c db_reload.c db_save.c db_update.c \ db_secure.c db_glue.c \ ns_forw.c ns_init.c ns_main.c ns_maint.c ns_req.c ns_resp.c \ ns_sort.c ns_stats.c ns_validate.c ns_ncache.c \ - storage.c dmalloc.c tree.c + storage.c tree.c ns_udp.c OBJS= db_dump.o db_load.o db_lookup.o db_reload.o db_save.o db_update.o \ db_secure.o db_glue.o \ ns_forw.o ns_init.o ns_main.o ns_maint.o ns_req.o ns_resp.o \ ns_sort.o ns_stats.o ns_validate.o ns_ncache.o \ - storage.o dmalloc.o tree.o + storage.o tree.o ns_udp.o XFERSRCS= named-xfer.c -XFEROBJ= named-xfer.o db_glue.o storage.o dmalloc.o version.o +XFEROBJ= named-xfer.o db_glue.o storage.o version.o all: named named-xfer named.reload named.restart ndc diff --git a/contrib/bind/named/db_defs.h b/contrib/bind/named/db_defs.h index 7356818..7882393 100644 --- a/contrib/bind/named/db_defs.h +++ b/contrib/bind/named/db_defs.h @@ -1,6 +1,6 @@ /* * from db.h 4.16 (Berkeley) 6/1/90 - * $Id: db_defs.h,v 8.4 1996/05/17 09:10:46 vixie Exp $ + * $Id: db_defs.h,v 8.5 1996/08/27 08:33:23 vixie Exp $ */ /* @@ -90,16 +90,15 @@ struct databuf { int16_t d_zone; /* zone number or 0 for the cache */ int16_t d_class; /* class number */ int16_t d_type; /* type number */ - int16_t d_mark; /* place to mark data */ int16_t d_size; /* size of data area */ #ifdef NCACHE - int16_t d_rcode; /* rcode added for negative caching */ + unsigned d_rcode :4; /* rcode added for negative caching */ #endif - int16_t d_rcnt; + unsigned d_rcnt :12; #ifdef STATS struct nameser *d_ns; /* NS from whence this came */ #endif -/*XXX*/ u_int32_t d_nstime; /* NS response time, milliseconds */ + u_int16_t d_nstime; /* NS response time, milliseconds */ u_char d_data[sizeof(char*)]; /* malloc'd (padded) */ }; #define DATASIZE(n) (sizeof(struct databuf) - sizeof(char*) + n) @@ -108,6 +107,7 @@ struct databuf { * d_flags definitions */ #define DB_F_HINT 0x01 /* databuf belongs to fcachetab */ +#define DB_F_ACTIVE 0x02 /* databuf is linked into a cache */ /* * d_cred definitions diff --git a/contrib/bind/named/db_dump.c b/contrib/bind/named/db_dump.c index 421c121..09e96d3 100644 --- a/contrib/bind/named/db_dump.c +++ b/contrib/bind/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.14 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: db_dump.c,v 8.19 1996/10/08 04:51:03 vixie Exp $"; #endif /* not lint */ /* @@ -55,6 +55,28 @@ static char rcsid[] = "$Id: db_dump.c,v 8.14 1996/08/05 08:31:30 vixie Exp $"; * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * - + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. * --Copyright-- */ @@ -260,42 +282,6 @@ doadump() syslog(LOG_NOTICE, "finished dumping nameserver data\n"); } -#ifdef ALLOW_UPDATES -/* Create a disk database to back up zones - */ -void -zonedump(zp) - register struct zoneinfo *zp; -{ - FILE *fp; - char *fname; - struct hashbuf *htp; - char *op; - struct stat st; - - /* Only dump zone if there is a cache specified */ - if (zp->z_source && *(zp->z_source)) { - dprintf(1, (ddt, "zonedump(%s)\n", zp->z_source)); - - if ((fp = fopen(zp->z_source, "w")) == NULL) - return; - if (op = strchr(zp->z_origin, '.')) - op++; - gettime(&tt); - htp = hashtab; - if (nlookup(zp->z_origin, &htp, &fname, 0) != NULL) { - db_dump(htp, fp, zp-zones, (op == NULL ? "" : op)); - zp->z_flags &= ~Z_CHANGED; /* Checkpointed */ - } - (void) my_fclose(fp); - if (stat(zp->z_source, &st) == 0) - zp->z_ftime = st.st_mtime; - } else { - dprintf(1, (ddt, "zonedump: no zone to dump\n")); - } -} -#endif - int zt_dump(fp) FILE *fp; @@ -365,7 +351,12 @@ db_dump(htp, fp, zone, origin) register u_char *cp; u_char *end; char *proto, *sep; + int16_t type; int found_data = 0, tab, printed_origin = 0; + u_int16_t keyflags; + u_char *sigdata; + u_char *savecp; + char temp_base64[MAX_KEY_BASE64]; npp = htp->h_tab; nppend = npp + htp->h_size; @@ -407,7 +398,7 @@ db_dump(htp, fp, zone, origin) fprintf(fp, ".%s.\t", origin); /* ??? */ } else fprintf(fp, "%s\t", NAME(*np)); - if (NAMELEN(*np) < (size_t)8) + if (NAMELEN(*np) < (unsigned)8) tab = 1; found_data++; } else { @@ -432,27 +423,29 @@ db_dump(htp, fp, zone, origin) p_type(dp->d_type)); cp = (u_char *)dp->d_data; sep = "\t;"; + type = dp->d_type; #ifdef NCACHE -#ifdef RETURNSOA - if (dp->d_rcode == NOERROR_NODATA) { - fprintf(fp, "NODATA%s-$", sep); - goto eoln; - } -#else if (dp->d_rcode == NXDOMAIN || dp->d_rcode == NOERROR_NODATA) { +#ifdef RETURNSOA + if (dp->d_size == 0) { +#endif fprintf(fp, "%s%s-$", (dp->d_rcode == NXDOMAIN) ?"NXDOMAIN" :"NODATA", sep); goto eoln; - } +#ifdef RETURNSOA + } else { + type = T_SOA; + } #endif + } #endif /* * Print type specific data */ - switch (dp->d_type) { + switch (type) { case T_A: switch (dp->d_class) { case C_IN: @@ -486,24 +479,28 @@ db_dump(htp, fp, zone, origin) break; case T_HINFO: - case T_ISDN: + case T_ISDN: { + char buf[256]; if ((n = *cp++) != '\0') { - fprintf(fp, "\"%.*s\"", (int)n, cp); + bcopy(cp, buf, n); buf[n] = '\0'; + fprintf(fp, "\"%.*s\"", (int)n, buf); cp += n; } else fprintf(fp, "\"\""); - if ((n = *cp++) != '\0') - fprintf(fp, " \"%.*s\"", (int)n, cp); - else + if ((n = *cp++) != '\0') { + bcopy(cp, buf, n); buf[n] = '\0'; + fprintf(fp, " \"%.*s\"", (int)n, buf); + } else fprintf(fp, " \"\""); break; + } case T_SOA: fprintf(fp, "%s.", cp); cp += strlen((char *)cp) + 1; fprintf(fp, " %s. (\n", cp); #if defined(RETURNSOA) && defined(NCACHE) - if (dp->d_rcode == NXDOMAIN) + if (dp->d_rcode) fputs(";", fp); #endif cp += strlen((char *)cp) + 1; @@ -518,8 +515,11 @@ db_dump(htp, fp, zone, origin) GETLONG(n, cp); fprintf(fp, " %lu )", (u_long)n); #if defined(RETURNSOA) && defined(NCACHE) - if (dp->d_rcode == NXDOMAIN) { - fprintf(fp,";%s.;NXDOMAIN%s-$",cp,sep); + if (dp->d_rcode) { + fprintf(fp,";%s.;%s%s-$",cp, + (dp->d_rcode == NXDOMAIN) ? + "NXDOMAIN" : "NODATA", + sep); } #endif break; @@ -540,21 +540,28 @@ db_dump(htp, fp, zone, origin) fprintf(fp, " %s.", cp); break; - case T_TXT: case T_X25: + if ((n = *cp++) != '\0') + fprintf(fp, " \"%.*s\"", (int)n, cp); + else + fprintf(fp, " \"\""); + break; + + case T_TXT: end = (u_char *)dp->d_data + dp->d_size; - (void) putc('"', fp); while (cp < end) { - if ((n = *cp++) != '\0') { - for (j = n ; j > 0 && cp < end ; j--) - if (*cp == '\n') { - (void) putc('\\', fp); - (void) putc(*cp++, fp); - } else - (void) putc(*cp++, fp); - } + (void) putc('"', fp); + if ((n = *cp++) != '\0') { + for (j = n ; j > 0 && cp < end ; j--) { + if (*cp == '\n' || *cp == '"' || *cp == '\\') + (void) putc('\\', fp); + (void) putc(*cp++, fp); + } + } + (void) putc('"', fp); + if (cp < end) + (void) putc(' ', fp); } - (void) fputs("\"", fp); break; case T_NSAP: @@ -580,6 +587,43 @@ db_dump(htp, fp, zone, origin) break; } #endif /* LOC_RR */ + + case T_NAPTR: { + u_int order, preference; + + GETSHORT(order, cp); + fprintf(fp, "%lu", (u_long)order); + + GETSHORT(preference, cp); + fprintf(fp, "%lu", (u_long)preference); + + if (n = *cp++) { + fprintf(fp, "\"%.*s\"", (int)n, cp); + cp += n; + } + if (n = *cp++) { + fprintf(fp, "\"%.*s\"", (int)n, cp); + cp += n; + } + if (n = *cp++) { + fprintf(fp, " \"%.*s\"", (int)n, cp); + cp += n; + } + fprintf(fp, " %s.", cp); + + break; + } + + case T_SRV: { + u_int priority, weight, port; + + GETSHORT(priority, cp); + GETSHORT(weight, cp); + GETSHORT(port, cp); + fprintf(fp, "\t%u %u %u %s.", + priority, weight, port, cp); + break; + } case T_UINFO: fprintf(fp, "\"%s\"", cp); break; @@ -619,6 +663,63 @@ db_dump(htp, fp, zone, origin) cp += strlen((char *)cp) + 1; fprintf(fp, " %s.", cp); break; + + case T_KEY: + savecp = cp; /* save the beginning */ + /*>>> Flags (unsigned_16) */ + GETSHORT(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 *) */ + GETSHORT(n,cp); + fprintf(fp, "%s ", p_type(n)); + /* Algorithm id (8-bit decimal) */ + fprintf(fp, "%d ", *cp++); + /* Labels (8-bit decimal) (not saved in file) */ + /* FIXME -- check value and print err if bad */ + cp++; + /* OTTL (u_long) */ + GETLONG(n, cp); + fprintf(fp, "%lu ", n); + /* Texp (u_long) */ + GETLONG(n, cp); + fprintf(fp, "%s ", p_secstodate (n)); + /* Tsig (u_long) */ + GETLONG(n, cp); + fprintf(fp, "%s ", p_secstodate (n)); + /* Kfootprint (unsigned_16) */ + GETSHORT(n, cp); + fprintf(fp, "%lu ", 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; + #ifdef ALLOW_T_UNSPEC case T_UNSPEC: /* Dump binary data out in an ASCII-encoded @@ -860,7 +961,7 @@ byte_btoa(c, bufp) register int32_t tmpword = word; if (tmpword < 0) { - /* Because some don't support unsigned long */ + /* Because some don't support u_long */ tmp = 32; tmpword -= (int32_t)(85 * 85 * 85 * 85 * 32); } diff --git a/contrib/bind/named/db_func.h b/contrib/bind/named/db_func.h index 60b7f32..5d3929d 100644 --- a/contrib/bind/named/db_func.h +++ b/contrib/bind/named/db_func.h @@ -1,6 +1,6 @@ /* db_proc.h - prototypes for functions in db_*.c * - * $Id: db_func.h,v 8.9 1996/06/02 08:20:39 vixie Exp $ + * $Id: db_func.h,v 8.12 1996/09/22 00:13:10 vixie Exp $ */ /* ++from db_update.c++ */ @@ -9,6 +9,7 @@ extern int db_update __P((char name[], struct databuf *newdp, int flags, struct hashbuf *htp)), + db_cmp __P((struct databuf *,struct databuf *)), findMyZone __P((struct namebuf *np, int class)); /* --from db_update.c-- */ @@ -18,16 +19,7 @@ extern void db_reload __P((void)); /* ++from db_save.c++ */ extern struct namebuf *savename __P((const char *, int)); -#ifdef DMALLOC -extern struct databuf *savedata_tagged __P((char *, int, - int, int, u_int32_t, - u_char *, int)); -#define savedata(class, type, ttl, data, size) \ - savedata_tagged(__FILE__, __LINE__, class, type, ttl, data, size) -#else -extern struct databuf *savedata __P((int, int, u_int32_t, - u_char *, int)); -#endif +extern struct databuf *savedata __P((int, int, u_int32_t, u_char *, int)); extern struct hashbuf *savehash __P((struct hashbuf *)); /* --from db_save.c-- */ @@ -37,9 +29,6 @@ extern int db_dump __P((struct hashbuf *, FILE *, int, char *)), atob __P((char *, int, char *, int, int *)); extern void doachkpt __P((void)), doadump __P((void)); -#ifdef ALLOW_UPDATES -extern void zonedump __P((struct zoneinfo *)); -#endif extern u_int db_getclev __P((const char *)); /* --from db_dump.c-- */ @@ -97,6 +86,7 @@ extern char * ctimel __P((long)); extern struct in_addr data_inaddr __P((const u_char *data)); extern void setsignal __P((int, int, SIG_FN (*)())), resignal __P((int, int, SIG_FN (*)())); +extern void db_free __P((struct databuf *)); /* --from db_glue.c-- */ /* ++from db_lookup.c++ */ diff --git a/contrib/bind/named/db_glob.h b/contrib/bind/named/db_glob.h index b339b5b..bd9235f 100644 --- a/contrib/bind/named/db_glob.h +++ b/contrib/bind/named/db_glob.h @@ -1,6 +1,6 @@ /* * from db.h 4.16 (Berkeley) 6/1/90 - * $Id: db_glob.h,v 8.3 1995/12/06 20:34:38 vixie Exp $ + * $Id: db_glob.h,v 8.4 1996/08/27 08:33:23 vixie Exp $ */ /* @@ -63,10 +63,10 @@ */ /* ONE_WEEK maximum ttl */ -DECL int max_cache_ttl INIT(7*24*60*60); +DECL u_int max_cache_ttl INIT(7*24*60*60); /* no minimum ttl */ -DECL int min_cache_ttl INIT(0); +DECL u_int min_cache_ttl INIT(0); /* current line number */ DECL int lineno; diff --git a/contrib/bind/named/db_glue.c b/contrib/bind/named/db_glue.c index 647ae80..4f6deb0 100644 --- a/contrib/bind/named/db_glue.c +++ b/contrib/bind/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.13 1996/06/02 08:20:39 vixie Exp $"; +static char rcsid[] = "$Id: db_glue.c,v 8.16 1996/09/22 00:13:10 vixie Exp $"; #endif /* not lint */ /* @@ -481,23 +481,33 @@ rm_datum(dp, np, pdp) np->n_data = ndp; else pdp->d_next = ndp; -#ifdef DATUMREFCNT + if ((dp->d_flags & DB_F_ACTIVE) == 0) + panic(-1, "rm_datum: DB_F_ACTIVE not set"); + dp->d_flags &= ~DB_F_ACTIVE; + dp->d_next = NULL; if (--(dp->d_rcnt)) { +#ifdef DEBUG + int32_t ii; +#endif + switch(dp->d_type) { case T_NS: dprintf(1, (ddt, "rm_datum: %s rcnt = %d\n", dp->d_data, dp->d_rcnt)); break; case T_A: + +#ifdef DEBUG + bcopy(dp->d_data, &ii, sizeof(ii)); +#endif dprintf(1, (ddt, "rm_datum: %08.8X rcnt = %d\n", - *(int32_t*)(dp->d_data), dp->d_rcnt)); + ii, dp->d_rcnt)); break; default: dprintf(1, (ddt, "rm_datum: rcnt = %d\n", dp->d_rcnt)); } } else -#endif - free((char *)dp); + db_free(dp); return (ndp); } @@ -551,7 +561,7 @@ getname(np, buf, buflen) cp = buf; while (np != NULL) { - i = NAMELEN(*np); + i = (int) NAMELEN(*np); if (i + 1 >= buflen) { *cp = '\0'; syslog(LOG_INFO, "domain name too long: %s...\n", buf); @@ -718,45 +728,93 @@ samedomain(a, b) const char *a, *b; { size_t la, lb; + int diff, i, escaped; const char *cp; la = strlen(a); lb = strlen(b); - /* don't count trailing dots, if any. */ - if (la && a[la-1]=='.') - la--; - if (lb && b[lb-1]=='.') - lb--; + /* ignore a trailing label separator (i.e. an unescaped dot) in 'a' */ + if (la && a[la-1] == '.') { + escaped = 0; + /* note this loop doesn't get executed if la==1 */ + for (i = la - 2; i >= 0; i--) + if (a[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else { + break; + } + if (!escaped) + la--; + } + /* ignore a trailing label separator (i.e. an unescaped dot) in 'b' */ + if (lb && b[lb-1] == '.') { + escaped = 0; + /* note this loop doesn't get executed if lb==1 */ + for (i = lb - 2; i >= 0; i--) + if (b[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else { + break; + } + if (!escaped) + lb--; + } - /* lb==0 means b is the root domain, so a must be in b. */ + /* lb==0 means 'b' is the root domain, so 'a' must be in 'b'. */ if (lb == 0) return (1); - /* b longer than a means a can't be in b. */ + /* 'b' longer than 'a' means 'a' can't be in 'b'. */ if (lb > la) return (0); /* We use strncasecmp because we might be trying to - * ignore trailing dots. */ + * ignore a trailing dot. */ if (lb == la) return (strncasecmp(a, b, lb) == 0); /* Ok, we know la > lb. */ - /* Point at the character before the last 'lb' characters of a. */ - cp = a + (la - lb - 1); + diff = la - lb; - /* If it isn't '.', can't be a match (this lets us avoid - * having "foobar.com" match "bar.com"). */ - if (*cp != '.') + /* If 'a' is only 1 character longer than 'b', then it can't be + a subdomain of 'b' (because of the need for the '.' label + separator). */ + if (diff < 2) return (0); - cp++; + /* If the character before the last 'lb' characters of 'b' + isn't '.', then it can't be a match (this lets us avoid + having "foobar.com" match "bar.com"). */ + if (a[diff-1] != '.') + return (0); + /* We're not sure about that '.', however. It could be escaped + and thus not a really a label separator. */ + escaped=0; + for (i = diff-2; i >= 0; i--) + if (a[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } + else + break; + if (escaped) + return (0); + /* We use strncasecmp because we might be trying to * ignore trailing dots. */ - return (strncasecmp(cp, b, lb)==0); + cp = a + diff; + return (strncasecmp(cp, b, lb) == 0); } /* @@ -784,8 +842,8 @@ data_inaddr(data) struct in_addr ret; u_int32_t tmp; - bcopy((char *)data, (char *)&tmp, INADDRSZ); - ret.s_addr = tmp; + GETLONG(tmp, data); + ret.s_addr = htonl(tmp); return (ret); } @@ -833,3 +891,19 @@ resignal(catch, block, handler) setsignal(catch, block, handler); #endif } + +void +db_free(dp) + struct databuf *dp; +{ + int bytes = DATASIZE(dp->d_size); + + if (dp->d_rcnt != 0) + panic(-1, "db_free: d_rcnt != 0"); + if (dp->d_flags & DB_F_ACTIVE) + panic(-1, "db_free: DB_F_ACTIVE set"); + if (dp->d_next) + panic(-1, "db_free: d_next != 0"); + memset(dp, 0x5E, bytes); + free((char*)dp); +} diff --git a/contrib/bind/named/db_load.c b/contrib/bind/named/db_load.c index dda27c9..6b0a11a 100644 --- a/contrib/bind/named/db_load.c +++ b/contrib/bind/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.22 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: db_load.c,v 8.31 1996/12/18 04:09:48 vixie Exp $"; #endif /* not lint */ /* @@ -55,6 +55,28 @@ static char rcsid[] = "$Id: db_load.c,v 8.22 1996/08/05 08:31:30 vixie Exp $"; * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * - + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. * --Copyright-- */ @@ -66,88 +88,45 @@ static char rcsid[] = "$Id: db_load.c,v 8.22 1996/08/05 08:31:30 vixie Exp $"; #include <sys/param.h> #include <sys/stat.h> #include <sys/socket.h> + #include <netinet/in.h> #include <arpa/nameser.h> #include <arpa/inet.h> -#include <stdio.h> -#include <syslog.h> + #include <ctype.h> +#include <errno.h> #include <netdb.h> #include <resolv.h> -#include <errno.h> +#include <stdio.h> +#include <syslog.h> +#include <time.h> #include "named.h" +#define ALLOW_LONG_TXT_RDATA + static int gettoken __P((register FILE *, const char *)), getnonblank __P((FILE *, const char *)), getprotocol __P((FILE *, const char *)), - getservices __P((int, char *, FILE *, const char *)); + getservices __P((int, char *, FILE *, const char *)), + getcharstring __P((char *, char *, int, int, int, FILE *, const char *)); static void makename __P((char *, const char *)); static int makename_ok __P((char *name, const char *origin, int class, enum transport transport, enum context context, + const char *owner, const char *filename, int lineno)); +static int getmlword __P((char *, int, FILE *, int)); +static int getallwords __P((char *, int, FILE *, int)); +static u_int32_t wordtouint32 __P((char *)); +static u_int32_t datetosecs __P((char *, int *)); +static int wordtouint32_error = 0; static int empty_token = 0; -int getnum_error; +static int getmlword_nesting = 0; -/* - * Map class and type names to number - */ -struct map { - char token[8]; - int val; -}; - -struct map m_class[] = { - { "in", C_IN }, -#ifdef notdef - { "any", C_ANY }, /* any is a QCLASS, not CLASS */ -#endif - { "chaos", C_CHAOS }, - { "hs", C_HS }, -}; -#define M_CLASS_CNT (sizeof(m_class) / sizeof(struct map)) - -struct map m_type[] = { - { "a", T_A }, - { "ns", T_NS }, - { "cname", T_CNAME }, - { "soa", T_SOA }, - { "mb", T_MB }, - { "mg", T_MG }, - { "mr", T_MR }, - { "null", T_NULL }, - { "wks", T_WKS }, - { "ptr", T_PTR }, - { "hinfo", T_HINFO }, - { "minfo", T_MINFO }, - { "mx", T_MX }, - { "uinfo", T_UINFO }, - { "txt", T_TXT }, - { "rp", T_RP }, - { "afsdb", T_AFSDB }, - { "x25", T_X25 }, - { "isdn", T_ISDN }, - { "rt", T_RT }, - { "nsap", T_NSAP }, - { "nsap_ptr", T_NSAP_PTR }, - { "uid", T_UID }, - { "gid", T_GID }, - { "px", T_PX }, - { "aaaa", T_AAAA }, -#ifdef notdef - { "any", T_ANY }, /* any is a QTYPE, not TYPE */ -#endif -#ifdef LOC_RR - { "loc", T_LOC }, -#endif /* LOC_RR */ -#ifdef ALLOW_T_UNSPEC - { "unspec", T_UNSPEC }, -#endif /* ALLOW_T_UNSPEC */ -}; -#define M_TYPE_CNT (sizeof(m_type) / sizeof(struct map)) +int getnum_error; /* * Parser token values @@ -160,11 +139,11 @@ struct map m_type[] = { #define ORIGIN 6 #define ERROR 7 -static int clev; /* a zone deeper in a heirachy has more credability */ +static int clev; /* a zone deeper in a hierachy has more credability */ #define MAKENAME_OK(N) if (!makename_ok(N, origin, class, \ transport, context, \ - filename, lineno)) { \ + domain, filename, lineno)) { \ errs++; \ sprintf(buf, "bad name \"%s\"", N); \ goto err; \ @@ -188,14 +167,13 @@ db_load(filename, in_origin, zp, def_domain) { static int read_soa, read_ns, rrcount; register char *cp; - register struct map *mp; char domain[MAXDNAME]; char origin[MAXDNAME]; char tmporigin[MAXDNAME]; char buf[MAXDATA]; char data[MAXDATA]; - const char *cp1, *op; - int c, class, type, dbflags, dataflags, multiline; + const char *op; + int c, someclass, class, type, dbflags, dataflags, multiline; u_int32_t ttl; struct databuf *dp; FILE *fp; @@ -206,10 +184,19 @@ db_load(filename, in_origin, zp, def_domain) int escape; enum transport transport; enum context context; + u_int32_t sig_type; + u_int32_t keyflags; + int success; + int dateerror; #ifdef DO_WARN_SERIAL u_int32_t serial; #endif +/* Simple macro for setting error messages about RR's being parsed, + before jumping to err label. If no SETERR is done, the last word + scanned into "buf" by getword will be printed. */ +#define SETERR(x) strcpy (buf, x); + switch (zp->z_type) { case Z_PRIMARY: case Z_CACHE: @@ -347,41 +334,49 @@ db_load(filename, in_origin, zp, def_domain) if (!getword((char *)buf, sizeof(buf), fp, 0)) break; } - for (mp = m_class; mp < m_class+M_CLASS_CNT; mp++) - if (!strcasecmp((char *)buf, mp->token)) { - class = mp->val; - (void) getword((char *)buf, - sizeof(buf), fp, 0); - break; - } - for (mp = m_type; mp < m_type+M_TYPE_CNT; mp++) - if (!strcasecmp((char *)buf, mp->token)) { - type = mp->val; - goto fndtype; - } - dprintf(1, (ddt, "%s: Line %d: Unknown type: %s.\n", - filename, lineno, buf)); - errs++; - syslog(LOG_NOTICE, "%s: Line %d: Unknown type: %s.\n", - filename, lineno, buf); - break; - fndtype: + + /* Parse class (IN, etc) */ + someclass = sym_ston(__p_class_syms, + (char *)buf, &success); + if (success && someclass != C_ANY) { + class = someclass; + (void) getword((char *)buf, + sizeof(buf), fp, 0); + } + + /* Parse RR type (A, MX, etc) */ + type = sym_ston(__p_type_syms, + (char *)buf, &success); + if ((!success) || type == T_ANY) { + dprintf(1, (ddt, "%s: Line %d: Unknown type: %s.\n", + filename, lineno, buf)); + errs++; + syslog(LOG_INFO, "%s: Line %d: Unknown type: %s.\n", + filename, lineno, buf); + break; + } + context = ns_ownercontext(type, transport); - if (!ns_nameok(domain, class, transport, context)) { + if (!ns_nameok(domain, class, transport, context, + domain, inaddr_any)) { errs++; syslog(LOG_NOTICE, "%s:%d: owner name error\n", filename, lineno); break; } -#ifdef ALLOW_T_UNSPEC - /* Don't do anything here for T_UNSPEC... - * read input separately later - */ - if (type != T_UNSPEC) { -#endif + context = domain_ctx; switch (type) { +#ifdef ALLOW_T_UNSPEC + case T_UNSPEC: +#endif + case T_KEY: + case T_SIG: + /* Don't do anything here for these types -- + they read their own input separately later */ + goto dont_get_word; + case T_SOA: case T_MINFO: case T_RP: @@ -402,13 +397,11 @@ db_load(filename, in_origin, zp, def_domain) (ddt, "d='%s', c=%d, t=%d, ttl=%d, data='%s'\n", domain, class, type, ttl, buf)); -#ifdef ALLOW_T_UNSPEC - } -#endif /* * Convert the ascii data 'buf' to the proper format * based on the type and pack into 'data'. */ + dont_get_word: switch (type) { case T_A: if (!inet_aton(buf, &ina)) @@ -419,55 +412,6 @@ db_load(filename, in_origin, zp, def_domain) n = INT32SZ; break; - case T_HINFO: - case T_ISDN: - n = strlen((char *)buf); - if (n > 255) { - syslog(LOG_INFO, - "%s: line %d: %s too long", - filename, lineno, (type == T_ISDN) ? - "ISDN-address" : "CPU type"); - n = 255; - } - data[0] = n; - bcopy(buf, (char *)data + 1, (int)n); - if (n == 0) - goto err; - n++; - if (!getword((char *)buf, sizeof(buf), fp, 0)) - i = 0; - else { - endline(fp); - i = strlen((char *)buf); - } - if (i == 0) { - if (type == T_ISDN) { - data[n++] = 0; - break; - } - else - /* goto err; */ - /* XXX tolerate for now */ - data[n++] = 1; - data[n++] = '?'; - syslog(LOG_INFO, - "%s: line %d: OS-type missing", - filename, - empty_token ? (lineno - 1) : lineno); - break; - } - if (i > 255) { - syslog(LOG_INFO, - "%s:%d: %s too long", - filename, lineno, (type == T_ISDN) ? - "ISDN-sa" : "OS type"); - i = 255; - } - data[n] = i; - bcopy(buf, data + n + 1, i); - n += i + 1; - break; - case T_SOA: context = hostname_ctx; goto soa_rp_minfo; @@ -481,7 +425,8 @@ db_load(filename, in_origin, zp, def_domain) MAKENAME_OK(data); cp = data + strlen((char *)data) + 1; if (!getword((char *)cp, - (sizeof data) - (cp - data), + (sizeof data) - + (cp - (char *)data), fp, 1)) goto err; if (type == T_RP) @@ -491,7 +436,7 @@ db_load(filename, in_origin, zp, def_domain) MAKENAME_OK(cp); cp += strlen((char *)cp) + 1; if (type != T_SOA) { - n = cp - data; + n = cp - (char *)data; break; } if (class != zp->z_class) { @@ -572,18 +517,81 @@ db_load(filename, in_origin, zp, def_domain) } n = (u_int32_t) zp->z_minimum; PUTLONG (n, cp); - n = cp - data; + n = cp - (char *)data; if (multiline) { if (getnonblank(fp, filename) != ')') goto err; + endline(fp); } read_soa++; - if (zp->z_expire < zp->z_refresh ) { + if (zp->z_type != Z_PRIMARY) + break; + /* sanity checks PRIMARY ONLY */ + /* + * sanity: give enough time for the + * zone to transfer (retry) + */ + if (zp->z_expire < + (zp->z_refresh+zp->z_retry)) { + syslog(LOG_NOTICE, + "%s: WARNING SOA expire value is less then SOA refresh + retry (%lu < %lu + %lu)", + filename, zp->z_expire, zp->z_refresh, + zp->z_retry); + } + /* BIND specific */ + if (zp->z_expire < maint_interval) { + syslog(LOG_NOTICE, + "%s: WARNING SOA expire value is less then maintainance interval (%lu < %lu)", + filename, zp->z_expire, maint_interval); + } + /* BIND Specific */ + if (zp->z_refresh < maint_interval) { syslog(LOG_WARNING, - "%s: WARNING SOA expire value is less then SOA refresh (%lu < %lu)", - filename, zp->z_expire, zp->z_refresh); + "%s: WARNING SOA refresh value is less then maintainance interval (%lu < %lu)", + filename, zp->z_refresh, maint_interval); + } + /* BIND specific */ + if (zp->z_retry < maint_interval) { + syslog(LOG_WARNING, + "%s: WARNING SOA retry value is less then maintainance interval (%lu < %lu)", + filename, zp->z_retry, maint_interval); + } + /* sanity */ + if (zp->z_expire < + (zp->z_refresh + 10 * zp->z_retry)) { + syslog(LOG_WARNING, + "%s: WARNING SOA expire value is less then refresh + 10 * retry (%lu < (%lu + 10 * %lu))", + filename, zp->z_expire, zp->z_refresh, + zp->z_retry); + } + /* + * sanity: most harware/telco faults are + * detected and fixed within a week, + * secondaries should continue to + * operate for this time. + * (minimum of 4 days for long weekends) + */ + if (zp->z_expire < (7 * 24 * 3600)) { + syslog(LOG_WARNING, + "%s: WARNING SOA expire value is less then 7 days (%lu)", + filename, zp->z_expire); + } + /* + * sanity: maximum down time + * if we havn't talked for six months + * war must have broken out + */ + if (zp->z_expire > ( 183 * 24 * 3600)) { + syslog(LOG_WARNING, + "%s: WARNING SOA expire value is greater then 6 months (%lu)", + filename, zp->z_expire); + } + /* sanity */ + if (zp->z_refresh < (zp->z_retry * 2)) { + syslog(LOG_WARNING, + "%s: WARNING SOA refresh value is less than 2 * retry (%lu < %lu * 2)", + filename, zp->z_refresh, zp->z_retry); } - endline(fp); break; case T_UID: @@ -652,9 +660,66 @@ db_load(filename, in_origin, zp, def_domain) (char *)buf); n = strlen((char *)data) + 1; break; + + case T_NAPTR: + /* Order Preference Flags Service Replacement Regexp */ + n = 0; + cp = buf; + /* Order */ + while (isdigit(*cp)) + n = n * 10 + (*cp++ - '0'); + /* catch bad values */ + if ((cp == buf) || (n > 65535)) + goto err; + cp = data; + PUTSHORT((u_int16_t)n, cp); + /* Preference */ + n = getnum(fp, filename, GETNUM_NONE); + if (getnum_error || n > 65536) + goto err; + PUTSHORT((u_int16_t)n, cp); + + /* Flags */ + if (!getword((char *)buf, sizeof(buf), fp, 0)) + goto err; + n = strlen((char *)buf); + *cp++ = n; + bcopy(buf, (char *)cp, (int)n); + cp += n; + + /* Service Classes */ + if (!getword((char *)buf, sizeof(buf), fp, 0)) + goto err; + n = strlen((char *)buf); + *cp++ = n; + bcopy(buf, (char *)cp, (int)n); + cp += n; + + /* Pattern */ + if (!getword((char *)buf, sizeof(buf), fp, 0)) + goto err; + n = strlen((char *)buf); + *cp++ = n; + bcopy(buf, (char *)cp, (int)n); + cp += n; + + /* Replacement */ + if (!getword((char *)buf, sizeof(buf), fp, 1)) + goto err; + (void) strcpy((char *)cp, (char *)buf); + context = domain_ctx; + MAKENAME_OK(cp); + /* advance pointer to end of data */ + cp += strlen((char *)cp) +1; + + /* now save length */ + n = (cp - (char *)data); + break; + case T_MX: case T_AFSDB: case T_RT: + case T_SRV: n = 0; cp = buf; while (isdigit(*cp)) @@ -662,10 +727,21 @@ db_load(filename, in_origin, zp, def_domain) /* catch bad values */ if ((cp == buf) || (n > 65535)) goto err; - cp = data; PUTSHORT((u_int16_t)n, cp); + if (type == T_SRV) { + n = getnum(fp, filename, GETNUM_NONE); + if (getnum_error || n > 65536) + goto err; + PUTSHORT((u_int16_t)n, cp); + + n = getnum(fp, filename, GETNUM_NONE); + if (getnum_error || n > 65536) + goto err; + PUTSHORT((u_int16_t)n, cp); + } + if (!getword((char *)buf, sizeof(buf), fp, 1)) goto err; (void) strcpy((char *)cp, (char *)buf); @@ -675,7 +751,7 @@ db_load(filename, in_origin, zp, def_domain) cp += strlen((char *)cp) +1; /* now save length */ - n = (cp - data); + n = (cp - (char *)data); break; case T_PX: @@ -705,36 +781,31 @@ db_load(filename, in_origin, zp, def_domain) cp += strlen((char *)cp) + 1; /* now save length */ - n = (cp - data); + n = (cp - (char *)data); + break; + + case T_HINFO: + n = getcharstring(buf, data, type, 2, 2, fp, filename); + if (n == 0) + goto err; + break; + + case T_ISDN: + n = getcharstring(buf, data, type, 1, 2, fp, filename); + if (n == 0) + goto err; break; case T_TXT: + n = getcharstring(buf, data, type, 1, 0, fp, filename); + if (n == 0) + goto err; + break; + case T_X25: - i = strlen((char *)buf); - cp = data; - cp1 = buf; - /* - * there is expansion here so make sure we - * don't overflow data - */ - if (i > (sizeof data) * 255 / 256) { - syslog(LOG_INFO, - "%s: line %d: TXT record truncated", - filename, lineno); - i = (sizeof data) * 255 / 256; - } - while (i > 255) { - *cp++ = 255; - bcopy(cp1, cp, 255); - cp += 255; - cp1 += 255; - i -= 255; - } - *cp++ = i; - bcopy(cp1, cp, i); - cp += i; - n = cp - data; - endline(fp); + n = getcharstring(buf, data, type, 1, 1, fp, filename); + if (n == 0) + goto err; break; case T_NSAP: @@ -750,6 +821,459 @@ db_load(filename, in_origin, zp, def_domain) n = IN6ADDRSZ; endline(fp); break; + + case 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 = data; + getmlword_nesting = 0; /* KLUDGE err recov. */ + /*>>> Flags (unsigned_16) */ + if (!getmlword((char*)buf, sizeof(buf), fp, 0) + ) { + SETERR("No flags field"); + goto err; + } + keyflags = wordtouint32(buf); + if (wordtouint32_error || 0xFFFF < keyflags) + goto err; + if (keyflags & KEYFLAG_RESERVED_BITMASK) { + SETERR("Reserved flag bits are set"); + goto err; + } + PUTSHORT(keyflags, cp); + + /*>>> Protocol (8-bit decimal) */ + if (!getmlword((char*)buf, sizeof(buf), fp, 0) + ) { + SETERR("No protocol field"); + goto err; + } + pr = wordtouint32(buf); + if (wordtouint32_error || 255 < pr) + goto err; + *cp++ = (u_char) pr; + + /*>>> Algorithm id (8-bit decimal) */ + if (!getmlword((char*)buf, sizeof(buf), fp, 0) + ) { + SETERR("No algorithm ID") + goto err; + } + al = wordtouint32(buf); + if (wordtouint32_error || + 0 == al || 255 == al || 255 < al) + goto err; + *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((char *)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) + goto err; + } + + /* set total length */ + n = cp + klen - (char *)data; + + /* + * Now check for valid key flags & algs & etc, + * from the RFC. + */ + + if (keyflags & (KEYFLAG_ZONEKEY | KEYFLAG_IPSEC + | KEYFLAG_EMAIL)) + pr |= 1; /* A nonzero proto. */ + if (KEYFLAG_TYPE_NO_KEY == + (keyflags & KEYFLAG_TYPEMASK)) + nk = 1; /* No-key */ + else + nk = 0; /* have a key */ + if ((keyflags & KEYFLAG_ZONEKEY) && + (KEYFLAG_TYPE_CONF_ONLY == + (keyflags & KEYFLAG_TYPEMASK))) { + /* Zone key must have Authentication bit + set ogud@tis.com */ + SETERR("Zonekey needs authentication bit"); + goto err; + } + + if (al == 0 && nk == 0) { + SETERR("Key specified, but no alg"); + goto err; + } + if (al != 0 && pr == 0) { + SETERR("Alg specified, but no protos"); + goto err; + } + + if (nk == 1 && klen != 0) { + SETERR("No-key flags set but key fnd"); + goto err; + } + + if (nk == 0 && klen == 0) { + SETERR("Key type spec'd, but no key"); + goto err; + } + + /* Check algorithm-ID and key structure, for + the algorithm-ID's that we know about. */ + switch (al) { + case ALGORITHM_MD5RSA: + if (klen == 0) + break; + expstart = cp; + expbytes = *expstart++; + if (expbytes == 0) + GETSHORT(expbytes, expstart); + + if (expbytes < 1) { + SETERR("Exponent too short"); + goto err; + } + if (expbytes > + (MAX_MD5RSA_KEY_PART_BITS + 7) / 8 + ) { + SETERR("Exponent too long"); + goto err; + } + if (*expstart == 0) { + SETERR("Exponent starts w/ 0"); + goto err; + } + + modbytes = klen - + (expbytes + (expstart - cp)); + if (modbytes < + (MIN_MD5RSA_KEY_PART_BITS + 7) / 8 + ) { + SETERR("Modulus too short"); + goto err; + } + if (modbytes > + (MAX_MD5RSA_KEY_PART_BITS + 7) / 8 + ) { + SETERR("Modulus too long"); + goto err; + } + if (*(expstart+expbytes) == 0) { + SETERR("Modulus starts w/ 0"); + goto err; + } + break; + + case ALGORITHM_EXPIRE_ONLY: + if (klen != 0) { + SETERR( + "Key provided for expire-only algorithm"); + goto err; + } + break; + case ALGORITHM_PRIVATE_OID: + if (klen == 0) { + SETERR("No ObjectID in key"); + goto err; + } + break; + } + + endline(fp); /* flush the rest of the line */ + break; + } /*T_KEY*/ + + case 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)) { + SETERR("SIG record doesn't specify type"); + goto err; + } + sig_type = sym_ston(__p_type_syms, (char *)buf, &success); + if (!success || sig_type == 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 T_ANY case, we rely on wordtouint32 + * to fail when scanning the string "ANY". + */ + sig_type = wordtouint32 (buf); + if (wordtouint32_error || sig_type > 0xFFFF) { + SETERR("Unknown RR type in SIG record"); + goto err; + } + } + cp = &data[i]; + PUTSHORT((u_int16_t)sig_type, cp); + i += 2; + + /* Algorithm id (8-bit decimal) */ + if (!getmlword((char *)buf, sizeof(buf), fp, 0)) { + SETERR("Missing algorithm ID"); + goto err; + } + 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) { + SETERR ("SIG label count invalid"); + goto err; + } + data[i] = (u_char) n; + i++; + + /* + * OTTL (optional u_int32_t) and + * Texp (u_int32_t date) + */ + if (!getmlword((char *)buf, sizeof(buf), fp, 0)) { + SETERR("OTTL and expiration time missing"); + goto err; + } + /* + * 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 = &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 = &data[i]; + PUTLONG(origTTL, cp); + i += 4; + if (!getmlword((char *)buf, sizeof(buf), fp, 0)) { + SETERR ("Expiration time missing"); + goto err; + } + exptime = datetosecs(buf, &dateerror); + } + if (dateerror || exptime > 0x7fffffff || exptime <= 0) { + SETERR("Invalid expiration time"); + goto err; + } + cp = &data[i]; + PUTLONG(exptime, cp); + i += 4; + + /* Tsig (u_int32_t) */ + if (!getmlword((char *)buf, sizeof(buf), fp, 0)) { + SETERR("Missing signature time"); + goto err; + } + signtime = datetosecs(buf, &dateerror); + if (0 == signtime || dateerror) { + SETERR("Invalid signature time"); + goto err; + } + cp = &data[i]; + PUTLONG(signtime, cp); + i += 4; + + /* Kfootprint (unsigned_16) */ + if (!getmlword((char *)buf, sizeof(buf), fp, 0)) { + SETERR("Missing key footprint"); + goto err; + } + n = wordtouint32(buf); + if (wordtouint32_error || n >= 0x0ffff) { + SETERR("Invalid key footprint"); + goto err; + } + cp = &data[i]; + PUTSHORT((u_int16_t)n, cp); + i += 2; + + /* Signer's Name */ + if (!getmlword((char*)buf, sizeof(buf), fp, 0)) { + SETERR("Missing signer's name"); + goto err; + } + cp = &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((char *)buf, sizeof(buf), fp, 0)) { + siglen = 0; + } else { + cp = &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) { + SETERR("TTL is greater than signed original TTL"); + goto err; + } + + /* Don't let bogus signers "sign" in the future. */ + if (signtime > now) { + SETERR("signature time is in the future"); + goto err; + } + + /* Ignore received SIG RR's that are already expired. */ + if (exptime <= now) { + SETERR("expiration time is in the past"); + goto err; + } + + /* Lop off the TTL at the expiration time. */ + timetilexp = exptime - now; + if (timetilexp < ttl) { + dprintf(1, (ddt, + "shrinking expiring %s SIG TTL from %d to %d\n", + 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 ALGORITHM_MD5RSA: + if (siglen == 0) { + SETERR("No key for RSA algorithm"); + goto err; + } + if (siglen < 1) { + SETERR("Signature too short"); + goto err; + } + if (siglen > (MAX_MD5RSA_KEY_PART_BITS + 7) / 8) { + SETERR("Signature too long"); + goto err; + } + /* We rely on cp from parse */ + if (*cp == 0) { + SETERR("Signature starts with zeroes"); + goto err; + } + break; + + case ALGORITHM_EXPIRE_ONLY: + if (siglen != 0) { + SETERR( + "Signature supplied to expire-only algorithm" + ); + goto err; + } + break; + case ALGORITHM_PRIVATE_OID: + if (siglen == 0) { + SETERR("No ObjectID in key"); + goto err; + } + break; + } + + endline(fp); /* flush the rest of the line */ + + break; /* Accept this RR. */ + } + #ifdef LOC_RR case T_LOC: cp = buf + (n = strlen(buf)); @@ -832,7 +1356,7 @@ db_load(filename, in_origin, zp, def_domain) fprintf(ddt, "update failed %s %d\n", domain, type); #endif - free((char*) dp); + db_free(dp); } else { rrcount++; } @@ -885,8 +1409,10 @@ db_load(filename, in_origin, zp, def_domain) zoneTypeString(zp), zp->z_origin, errs ? "rejected due to errors" : "loaded", (u_long)zp->z_serial); - if (errs) + if (errs) { zp->z_flags |= Z_DB_BAD; + zp->z_ftime = 0; + } #ifdef BIND_NOTIFY /* XXX: this needs to be delayed, both according to the spec, and * because the metadata needed by sysnotify() (and its sysquery()) @@ -962,7 +1488,7 @@ gettoken(fp, src) * fp - file to read from * preserve - should we preserve \ before \\ and \.? * return value: - * 0 = no word; perhaps EOL or EOF + * 0 = no word; perhaps EOL or EOF; lineno was incremented. * 1 = word was read */ int @@ -1063,6 +1589,84 @@ getword(buf, size, fp, preserve) return (cp != buf); } +/* Get multiline words. Same parameters as getword. Handles any + number of leading ('s or )'s in the words it sees. + FIXME: We kludge recognition of ( and ) for multiline input. + Each paren must appear at the start of a (blank-separated) word, + which is particularly counter-intuitive for ). Good enough for now, + until Paul rewrites the parser. +*/ +static int +getmlword(buf, size, fp, preserve) + char *buf; + int size; + FILE *fp; + int preserve; +{ + char *p; + + do { + while (!getword (buf, size, fp, preserve)) { + /* No more words on this line. See if doing the + multiline thing. */ + if (!getmlword_nesting) { /* Nope... */ + ungetc('\n', fp); /* Push back newline */ + lineno--; /* Unbump the lineno */ + empty_token = 0; /* Undo this botch */ + return 0; + } + if (feof(fp) || ferror(fp)) + return 0; /* Error, no terminating ')' */ + /* Continue reading til we get a word... */ + } + while ('(' == *buf) { + /* Word starts with paren. Multiline mode. + Move the rest of the word down over the paren. */ + getmlword_nesting++; + p = buf; + while (0 != (p[0]=p[1])) p++; + } + while (')' == *buf) { + getmlword_nesting--; + p = buf; + while (0 != (p[0]=p[1])) p++; + } + } while (buf[0] == 0); /* loop til we get a non-( non-) word */ + + return 1; /* Got a word... */ +} + +/* Get all the remaining words on a line, concatenated into one big + long (not too long!) string, with the whitespace squeezed out. + This routine, like getword(), does not swallow the newline if words seen. + This routine, unlike getword(), never swallows the newline if no words. + Parameters are the same as getword(). Result is: + 0 got no words at all + 1 got one or more words + -1 got too many words, they don't all fit; or missing close paren +*/ +static int +getallwords(buf, size, fp, preserve) + char *buf; + int size; + FILE *fp; + int preserve; +{ + char *runningbuf = buf; + int runningsize = size; + int len; + + while (runningsize > 0) { + if (!getmlword (runningbuf, runningsize, fp, preserve)) { + return runningbuf!=buf; /* 1 or 0 */ + } + len = strlen(runningbuf); + runningbuf += len; + runningsize -= len; + } + return -1; /* Error, String too long */ +} + /* From: kagotani@cs.titech.ac.jp Message-Id: <9007040716.AA26646@saeko.cs.titech.ac.jp> @@ -1249,19 +1853,20 @@ makename(name, origin) } static int -makename_ok(name, origin, class, transport, context, filename, lineno) +makename_ok(name, origin, class, transport, context, owner, filename, lineno) char *name; const char *origin; int class; enum transport transport; enum context context; + const char *owner; const char *filename; int lineno; { int ret = 1; makename(name, origin); - if (!ns_nameok(name, class, transport, context)) { + if (!ns_nameok(name, class, transport, context, owner, inaddr_any)) { syslog(LOG_INFO, "%s:%d: database naming error\n", filename, lineno); ret = 0; @@ -1297,7 +1902,7 @@ getprotocol(fp, src) char b[MAXLEN]; (void) getword(b, sizeof(b), fp, 0); - + k = protocolnumber(b); if (k == -1) syslog(LOG_INFO, "%s: line %d: unknown protocol: %s.", @@ -1354,7 +1959,7 @@ getservices(n, data, fp, src) } else { syslog(LOG_INFO, - "%s: line %d: port no. (%d) too big\n", + "%s: line %d: port no. (%d) too big", src, lineno, k); dprintf(1, (ddt, "%s: line %d: port no. (%d) too big\n", @@ -1362,7 +1967,7 @@ getservices(n, data, fp, src) } } if (bracket) - syslog(LOG_INFO, "%s: line %d: missing close paren\n", + syslog(LOG_INFO, "%s: line %d: missing close paren", src, lineno); maxl = maxl/8+1; bcopy(bm, data+n, maxl); @@ -1404,7 +2009,7 @@ get_netlist(fp, netlistp, allow, print_tag) if (!inet_aton(buf, &ntp->my_addr)) { syslog(LOG_INFO, "%s contains bogus element (%s)", print_tag, buf); - continue; + continue; } if (maskp) { if (!inet_aton(maskp, &ina)) { @@ -1440,7 +2045,7 @@ get_netlist(fp, netlistp, allow, print_tag) } if (ntp) free((char *)ntp); - + dprintf(1, (ddt, "\n")); #ifdef DEBUG if (debug > 2) @@ -1499,3 +2104,186 @@ free_netlist(netlistp) } *netlistp = NULL; } + +/* + * Converts a word to a u_int32_t. Error if any non-numeric + * characters in the word, except leading or trailing white space. + */ +static u_int32_t +wordtouint32(buf) + char *buf; +{ + u_long result; + u_int32_t res2; + char *bufend; + + wordtouint32_error = 0; + result = strtoul(buf, &bufend, 0); + if (bufend == buf) + wordtouint32_error = 1; + else + while ('\0' != *bufend) { + if (isspace(*bufend)) + bufend++; + else { + wordtouint32_error = 1; + break; + } + } + /* Check for truncation between u_long and u_int32_t */ + res2 = result; + if (res2 != result) + wordtouint32_error = 1; + return (res2); +} + + +/* + * Parse part of a date. Set error flag if any error. + * Don't reset the flag if there is no error. + */ +static int +datepart(buf, size, min, max, errp) + char *buf; + int size, min, max, *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(cp, errp) + 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; + + bzero((char *)&time, 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(buf, data, type, minfields, maxfields, fp, src) + char *buf; + char *data; + int type; + int minfields; + int maxfields; + FILE *fp; + const char *src; +{ + int nfield = 0, done = 0, n = 0, i; + char *b = buf; + + do { + nfield++; + i = strlen(buf); +#ifdef ALLOW_LONG_TXT_RDATA + b = buf; + if (type == T_TXT || type == T_X25) { + while (i > MAXCHARSTRING + && n + MAXCHARSTRING + 1 < MAXDATA) { + data[n] = MAXCHARSTRING; + bcopy(b, data + n + 1, MAXCHARSTRING); + n += MAXCHARSTRING + 1; + b += MAXCHARSTRING; + i -= MAXCHARSTRING; + } + } +#endif /* ALLOW_LONG_TXT_RDATA */ + if (i > MAXCHARSTRING) { + syslog(LOG_INFO, + "%s: line %d: RDATA field %d too long", + src, lineno, nfield); + return (0); + } + if (n + i + 1 > MAXDATA) { + syslog(LOG_INFO, + "%s: line %d: total RDATA too long", + src, lineno); + return (0); + } + data[n] = i; + bcopy(b, data + n + 1, (int)i); + n += i + 1; + done = (maxfields && nfield >= maxfields); + } while (!done && getword(buf, MAXDATA, fp, 0)); + + if (nfield < minfields) { + syslog(LOG_INFO, + "%s: line %d: expected %d RDATA fields, only saw %d", + src, lineno, minfields, nfield); + return (0); + } + + if (done) + endline(fp); + + return (n); +} diff --git a/contrib/bind/named/db_lookup.c b/contrib/bind/named/db_lookup.c index 4582589..fce3ffd 100644 --- a/contrib/bind/named/db_lookup.c +++ b/contrib/bind/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.7 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: db_lookup.c,v 8.9 1996/09/22 00:13:10 vixie Exp $"; #endif /* not lint */ /* @@ -119,7 +119,8 @@ nlookup(name, htpp, fname, insert) /* rotate left HASHSHIFT */ hval = (hval << HASHSHIFT) | (hval>>((sizeof(hval)*8)-HASHSHIFT)); - hval += (isupper(c) ? tolower(c) : c) & HASHMASK; + hval += ((isascii(c) && isupper(c)) ? tolower(c) : c) + & HASHMASK; if (escaped) escaped = 0; else if (c == '\\') @@ -133,7 +134,7 @@ nlookup(name, htpp, fname, insert) np != NULL; np = np->n_next) { if (np->n_hashval == hval && - (NAMELEN(*np) == (cp - name)) && + ((size_t)NAMELEN(*np) == (cp - name)) && (strncasecmp(name, NAME(*np), cp - name) == 0)) { *fname = name; return (np); diff --git a/contrib/bind/named/db_reload.c b/contrib/bind/named/db_reload.c index 46fa7fe..640f5bd 100644 --- a/contrib/bind/named/db_reload.c +++ b/contrib/bind/named/db_reload.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) static char sccsid[] = "@(#)db_reload.c 4.22 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: db_reload.c,v 8.2 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: db_reload.c,v 8.3 1996/08/27 08:33:23 vixie Exp $"; #endif /* not lint */ /* @@ -98,7 +98,7 @@ db_reload() #if 0 /* someday we'll need this.. (untested since before 1990) */ void -db_free(htp) +ht_free(htp) struct hashbuf *htp; { register struct databuf *dp, *nextdp; @@ -114,7 +114,7 @@ db_free(htp) (void) free((char *)np->n_dname); for (dp = np->n_data; dp != NULL; ) { nextdp = dp->d_next; - (void) free((char *)dp); + db_free(dp); dp = nextdp; } nextnp = np->n_next; diff --git a/contrib/bind/named/db_save.c b/contrib/bind/named/db_save.c index 88b31d1..277b008 100644 --- a/contrib/bind/named/db_save.c +++ b/contrib/bind/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.4 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: db_save.c,v 8.6 1996/09/22 00:13:10 vixie Exp $"; #endif /* not lint */ /* @@ -84,12 +84,12 @@ savename(name, len) { register struct namebuf *np; - assert(len >= 0 && len <= (MAXLABEL * 2)); + assert(len >= 0 && len <= (MAXLABEL * 4)); np = (struct namebuf *) malloc(NAMESIZE(len)); if (np == NULL) panic(errno, "savename: malloc"); bzero((char*)np, NAMESIZE(len)); - NAMELEN(*np) = len; + NAMELEN(*np) = (unsigned)len; bcopy(name, NAME(*np), len); NAME(*np)[len] = '\0'; return (np); @@ -99,28 +99,16 @@ savename(name, len) * Allocate a data buffer & save data. */ struct databuf * -#ifdef DMALLOC -savedata_tagged(file, line, class, type, ttl, data, size) - char *file; - int line; -#else savedata(class, type, ttl, data, size) -#endif int class, type; u_int32_t ttl; u_char *data; int size; { register struct databuf *dp; - int bytes = (type == T_NS) ? DATASIZE(size)+INT32SZ : DATASIZE(size); + int bytes = DATASIZE(size); - dp = (struct databuf *) -#ifdef DMALLOC - dmalloc(file, line, bytes) -#else - malloc(bytes) -#endif - ; + dp = (struct databuf *)malloc(bytes); if (dp == NULL) panic(errno, "savedata: malloc"); bzero((char*)dp, bytes); @@ -129,7 +117,6 @@ savedata(class, type, ttl, data, size) dp->d_class = class; dp->d_ttl = ttl; dp->d_size = size; - dp->d_mark = 0; dp->d_flags = 0; dp->d_cred = 0; dp->d_clev = 0; diff --git a/contrib/bind/named/db_update.c b/contrib/bind/named/db_update.c index c706c66..bacc7f7 100644 --- a/contrib/bind/named/db_update.c +++ b/contrib/bind/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.12 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: db_update.c,v 8.18 1996/10/08 04:51:03 vixie Exp $"; #endif /* not lint */ /* @@ -72,8 +72,6 @@ static char rcsid[] = "$Id: db_update.c,v 8.12 1996/08/05 08:31:30 vixie Exp $"; #include "named.h" static void fixttl __P((struct databuf *)); -static int db_cmp __P((struct databuf *, - struct databuf *)); /* int * isRefByNS(name, htp) @@ -218,6 +216,7 @@ db_update(name, odp, newdp, flags, htp) register struct databuf *dp, *pdp; register struct namebuf *np; int zn, isHintNS; + int check_ttl = 0; const char *fname; dprintf(3, (ddt, "db_update(%s, 0x%lx, 0x%lx, 0%o, 0x%lx)%s\n", @@ -226,6 +225,9 @@ db_update(name, odp, newdp, flags, htp) np = nlookup(name, &htp, &fname, newdp != NULL); if (np == NULL || fname != name) return (NONAME); + + if (newdp && zones[newdp->d_zone].z_type == Z_PRIMARY) + check_ttl = 1; /* don't let nonauthoritative updates write in authority zones */ if (newdp && ((zn = findMyZone(np, newdp->d_class)) != DB_Z_CACHE) && @@ -312,7 +314,7 @@ db_update(name, odp, newdp, flags, htp) != OK) { dprintf(3, (ddt, "db_update: hint %lx freed\n", (u_long)dp)); - (void) free((char *)dp); + db_free(dp); } } @@ -325,10 +327,18 @@ db_update(name, odp, newdp, flags, htp) /* {class,type} doesn't match. these are * the aggregation cases. */ - if ((dp->d_type == T_CNAME || - odp->d_type == T_CNAME) && + /* Check that CNAMEs are only accompanied by + * Secure DNS RR's (KEY, SIG, and NXT). + */ + if (((dp->d_type == T_CNAME && + odp->d_type != T_KEY && + odp->d_type != T_SIG && + odp->d_type != T_NXT) || + (odp->d_type == T_CNAME && + dp->d_type != T_KEY && + dp->d_type != T_SIG && + dp->d_type != T_NXT)) && odp->d_class == dp->d_class && - odp->d_mark == dp->d_mark && #ifdef NCACHE /* neither the odp nor the new dp are * negatively cached records... @@ -338,7 +348,7 @@ db_update(name, odp, newdp, flags, htp) #endif /*NCACHE*/ zones[odp->d_zone].z_type != Z_CACHE) { syslog(LOG_INFO, - "%s has CNAME and other data (illegal)\n", + "%s has CNAME and other data (invalid)\n", name); goto skip; } @@ -520,6 +530,19 @@ db_update(name, odp, newdp, flags, htp) !bcmp(dp->d_data, newdp->d_data, INT32SZ + sizeof(u_char))) goto delete; + if (check_ttl) { + if (newdp->d_ttl != dp->d_ttl) + syslog(LOG_WARNING, + "%s %s %s differing ttls: corrected", + name[0]?name:".", + p_class(dp->d_class), + p_type(dp->d_type)); + if (newdp->d_ttl > dp->d_ttl) { + newdp->d_ttl = dp->d_ttl; + } else { + dp->d_ttl = newdp->d_ttl; + } + } } if ((flags & DB_NODATA) && !db_cmp(dp, odp)) { /* refresh ttl if cache entry */ @@ -552,6 +575,10 @@ db_update(name, odp, newdp, flags, htp) if (odp->d_size > 0) if (db_cmp(dp, odp)) goto skip; + if (odp->d_clev < dp->d_clev) + goto skip; + if (odp->d_cred < dp->d_cred) + goto skip; foundRR = 1; if (flags & DB_DELETE) { delete: dp = rm_datum(dp, np, pdp); @@ -588,9 +615,10 @@ db_update(name, odp, newdp, flags, htp) /* Add to end of list, generally preserving order */ newdp->d_next = NULL; if ((dp = np->n_data) == NULL) { -#ifdef DATUMREFCNT newdp->d_rcnt = 1; -#endif + if (newdp->d_flags & DB_F_ACTIVE) + panic(-1, "db_update: DB_F_ACTIVE set"); + newdp->d_flags |= DB_F_ACTIVE; np->n_data = newdp; return (OK); } @@ -601,9 +629,10 @@ db_update(name, odp, newdp, flags, htp) } if ((flags & DB_NODATA) && !db_cmp(dp, newdp)) return (DATAEXISTS); -#ifdef DATUMREFCNT newdp->d_rcnt = 1; -#endif + if (newdp->d_flags & DB_F_ACTIVE) + panic(-1, "db_update: DB_F_ACTIVE set"); + newdp->d_flags |= DB_F_ACTIVE; dp->d_next = newdp; return (OK); } @@ -628,7 +657,7 @@ fixttl(dp) * Must be case insensitive for some domain names. * Return 0 if equivalent, nonzero otherwise. */ -static int +int db_cmp(dp1, dp2) register struct databuf *dp1, *dp2; { @@ -639,8 +668,6 @@ db_cmp(dp1, dp2) return (1); if (dp1->d_size != dp2->d_size) return (1); - if (dp1->d_mark != dp2->d_mark) - return (1); /* old and new RR's are distinct */ #ifdef NCACHE if (dp1->d_rcode && dp2->d_rcode) return ((dp1->d_rcode == dp1->d_rcode)?0:1); @@ -650,6 +677,8 @@ db_cmp(dp1, dp2) switch (dp1->d_type) { + case T_SIG: + case T_KEY: case T_A: case T_UID: case T_GID: @@ -705,13 +734,64 @@ db_cmp(dp1, dp2) cp2 += strlen((char *)cp2) + 1; return (bcmp(cp1, cp2, INT32SZ * 5)); + case T_NAPTR: { + int t1,t2; + + if (dp1->d_size != dp2->d_size) + return (1); + cp1 = dp1->d_data; + cp2 = dp2->d_data; + + /* Order */ + if (*cp1++ != *cp2++ || *cp1++ != *cp2++) + return (1); + + /* Preference */ + if (*cp1++ != *cp2++ || *cp1++ != *cp2++) + return (1); + + /* Flags */ + t1 = *cp1++; t2 = *cp2++; + if (t1 != t2 || bcmp(cp1, cp2, t1)) + return (1); + cp1 += t1; cp2 += t2; + + /* Services */ + t1 = *cp1++; t2 = *cp2++; + if (t1 != t2 || bcmp(cp1, cp2, t1)) + return (1); + cp1 += t1; cp2 += t2; + + /* Regexp */ + t1 = *cp1++; t2 = *cp2++; + if (t1 != t2 || bcmp(cp1, cp2, t1)) + return (1); + cp1 += t1; cp2 += t2; + + /* Replacement */ + t1 = strlen((char *)cp1); t2 = strlen((char *)cp2); + if (t1 != t2 || bcmp(cp1, cp2, t1)) + return (1); + cp1 += t1 + 1; cp2 += t2 + 1; + + /* they all checked out! */ + return (0); + } + case T_MX: case T_AFSDB: case T_RT: + case T_SRV: cp1 = dp1->d_data; cp2 = dp2->d_data; if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* cmp prio */ return (1); + if (dp1->d_type == T_SRV) { + if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* weight */ + return (1); + if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* port */ + return (1); + } return (strcasecmp((char *)cp1, (char *)cp2)); case T_PX: diff --git a/contrib/bind/named/named-xfer.c b/contrib/bind/named/named-xfer.c index b71ebfb..1772b84 100644 --- a/contrib/bind/named/named-xfer.c +++ b/contrib/bind/named/named-xfer.c @@ -58,6 +58,28 @@ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * - + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. * --Copyright-- */ @@ -70,7 +92,7 @@ char copyright[] = #if !defined(lint) && !defined(SABER) static char sccsid[] = "@(#)named-xfer.c 4.18 (Berkeley) 3/7/91"; -static char rcsid[] = "$Id: named-xfer.c,v 8.15 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: named-xfer.c,v 8.22 1996/12/02 09:17:21 vixie Exp $"; #endif /* not lint */ #include <sys/types.h> @@ -347,8 +369,7 @@ main(argc, argv) (void) signal(SIGFPE, SIG_IGN); #endif /* SIGUSR1&&SIGUSR2 */ - dprintf(1, (ddt, - "domain `%s'; file `%s'; serial %lu; closed %d\n", + dprintf(1, (ddt, "domain `%s'; file `%s'; serial %lu; closed %d\n", domain, dbfile, (u_long)serial_no, closed)); buildservicelist(); @@ -425,20 +446,16 @@ main(argc, argv) (void) unlink(tmpname); exit(XFER_UPTODATE); + default: + result = XFER_FAIL; + /* fall through */ case XFER_TIMEOUT: -#ifdef DEBUG - if (!debug) -#endif - (void) unlink(tmpname); - exit(XFER_TIMEOUT); /* servers not reachable exit */ - case XFER_FAIL: - default: #ifdef DEBUG if (!debug) #endif (void) unlink(tmpname); - exit(XFER_FAIL); /* yuck exit */ + exit(result); /* error or timeout */ } /*NOTREACHED*/ } @@ -663,6 +680,7 @@ getzone(zp, serial_no, port) goto tryagain; } #endif +#ifndef ultrix syslog(LOG_NOTICE, "[%s] %s for %s, SOA query got rcode %d, aa %d, ancount %d, aucount %d", inet_ntoa(sin.sin_addr), @@ -671,6 +689,7 @@ getzone(zp, serial_no, port) : "not authoritative"), zp->z_origin[0] != '\0' ? zp->z_origin : ".", hp->rcode, hp->aa, ancount, aucount); +#endif error++; (void) my_close(s); continue; @@ -711,13 +730,40 @@ getzone(zp, serial_no, port) (void) my_close(s); continue; } - /* ... Answer Section. */ - n = dn_expand(buf, eom, tmp, name2, sizeof name2); - if (n < 0) { - badsoa_msg = "aname error"; - goto badsoa; - } - tmp += n; + /* ... Answer Section. + * We may have to loop a little, to bypass SIG SOA's in + * the response. + */ + do { + u_char *cp4; + u_short type, class, dlen; + u_long ttl; + + n = dn_expand(buf, eom, tmp, name2, sizeof name2); + if (n < 0) { + badsoa_msg = "aname error"; + goto badsoa; + } + tmp += n; + + /* Are type, class, and ttl OK? */ + cp4 = tmp; /* Leave tmp pointing to type field */ + if (eom - cp4 < 3 * INT16SZ + INT32SZ) { + badsoa_msg = "zinfo too short"; + goto badsoa; + } + GETSHORT(type, cp4); + GETSHORT(class, cp4); + GETLONG(ttl, cp4); + GETSHORT(dlen, cp4); + if (type == T_SOA) + break; + /* Skip to next record, if any. */ + dprintf (1, (ddt, "skipping %s %s RR in response\n", + name2, p_type (type))); + tmp = cp4 + dlen; + } while (1); + if (strcasecmp(zp->z_origin, name2) != 0) { syslog(LOG_INFO, "wrong answer in resp from [%s], zone %s: [%s %s %s]\n", @@ -860,24 +906,34 @@ getzone(zp, serial_no, port) #ifdef STUBS if (zp->z_type == Z_STUB) { ancount = ntohs(hp->ancount); - for (cnt = 0 ; cnt < ancount ; cnt++) { - + for (n = cnt = 0 ; cnt < ancount ; cnt++) { n = print_output(buf, bufsize, cp); + if (n < 0) + break; cp += n; } - if (hp->nscount) { + if (n >= 0 && hp->nscount) { /* we should not get here */ ancount = ntohs(hp->nscount); for (cnt = 0 ; cnt < ancount ; cnt++) { n = print_output(buf, bufsize, cp); - cp += n; + if (n < 0) + break; + cp += n; } } ancount = ntohs(hp->arcount); - for (cnt = 0 ; cnt < ancount ; cnt ++) { + for (cnt = 0 ; n >= 0 && cnt < ancount ; cnt++) { n = print_output(buf, bufsize, cp); cp += n; } + if (n < 0) { + syslog(LOG_INFO, + "print_output: unparseable answer (%d), zone %s", + hp->rcode, zp->z_origin); + error++; + break; + } if (cp != eom) { syslog(LOG_INFO, "print_output: short answer (%d, %d), zone %s", @@ -889,10 +945,19 @@ getzone(zp, serial_no, port) } else { #endif /*STUBS*/ ancount = ntohs(hp->ancount); - for (cnt = 0; cnt < ancount; cnt++) { + for (n = cnt = 0; cnt < ancount; cnt++) { n = print_output(buf, bufsize, cp); + if (n < 0) + break; cp += n; } + if (n < 0) { + syslog(LOG_INFO, + "print_output: unparseable answer (%d), zone %s", + hp->rcode, zp->z_origin); + error++; + break; + } if (cp != eom) { syslog(LOG_INFO, "print_output: short answer (%d, %d), zone %s", @@ -1029,7 +1094,7 @@ getzone(zp, serial_no, port) #else (void) sigvec(SIGALRM, &osv, (struct sigvec *)0); #endif - if (error) + if (!error) return (XFER_TIMEOUT); return (XFER_FAIL); } @@ -1162,7 +1227,8 @@ print_output(msg, msglen, rrp) int i, j, tab, result, class, type, dlen, n1, n; char data[BUFSIZ]; u_char *cp1, *cp2, *temp_ptr; - char *cdata, *origin, *proto, dname[MAXDNAME]; + u_char *cdata; + char *origin, *proto, dname[MAXDNAME]; char *ignore = ""; cp = rrp; @@ -1187,6 +1253,11 @@ print_output(msg, msglen, rrp) dname, type, class, ttl)); /* * Convert the resource record data into the internal database format. + * CP points to the raw resource record. + * After this switch: + * CP has been updated to point past the RR. + * CP1 points to the internal database version. + * N is the length of the internal database version. */ switch (type) { case T_A: @@ -1201,6 +1272,7 @@ print_output(msg, msglen, rrp) case T_AAAA: case T_UID: case T_GID: + case T_KEY: cp1 = cp; n = dlen; cp += n; @@ -1255,14 +1327,59 @@ print_output(msg, msglen, rrp) cp1 = (u_char *)data; break; + case T_NAPTR: + /* Grab weight and port. */ + bcopy(cp, data, INT16SZ*2); + cp1 = (u_char *) (data + INT16SZ*2); + cp += INT16SZ*2; + + /* Flags */ + n = *cp++; + *cp1++ = n; + bcopy(cp, cp1, n); + cp += n; cp1 += n; + + /* Service */ + n = *cp++; + *cp1++ = n; + bcopy(cp, cp1, n); + cp += n; cp1 += n; + + /* Regexp */ + n = *cp++; + *cp1++ = n; + bcopy(cp, cp1, n); + cp += n; cp1 += n; + + /* Replacement */ + n = dn_expand(msg, msg + msglen, cp, (char *)cp1, + sizeof data - ((char *)cp1 - data)); + if (n < 0) + return (-1); + cp += n; + + /* compute end of data */ + cp1 += strlen((char *)cp1) + 1; + /* compute size of data */ + n = cp1 - (u_char *)data; + cp1 = (u_char *)data; + break; + case T_MX: case T_AFSDB: case T_RT: + case T_SRV: /* grab preference */ bcopy((char *)cp, data, INT16SZ); cp1 = (u_char *)data + INT16SZ; cp += INT16SZ; + if (type == T_SRV) { + bcopy((char *)cp, data, INT16SZ*2); + cp1 += INT16SZ*2; + cp += INT16SZ*2; + } + /* get name */ n = dn_expand(msg, msg + msglen, cp, (char *)cp1, sizeof data - INT16SZ); @@ -1302,12 +1419,46 @@ print_output(msg, msglen, rrp) cp1 = (u_char *)data; break; + case T_SIG: + /* CP is the raw resource record as it arrived. + * CP1, after this switch, points to the internal database version. */ + cp1 = (u_char *)data; + + /* first just copy over the type_covered, algorithm, */ + /* labels, orig ttl, two timestamps, and the footprint */ + bcopy( cp, cp1, 18 ); + cp += 18; + cp1 += 18; + + /* then the signer's name */ + n = dn_expand(msg, msg + msglen, cp, + (char *)cp1, (sizeof data) - 18); + if (n < 0) + return (-1); + cp += n; + cp1 += strlen((char*)cp1)+1; + + /* finally, we copy over the variable-length signature. + Its size is the total data length, minus what we copied. */ + n = dlen - (18 + n); + if (n > (sizeof data) - (cp1 - (u_char *)data)) + return (-1); /* out of room! */ + bcopy(cp, cp1, n); + cp += n; + cp1 += n; + + /* compute size of data */ + n = cp1 - (u_char *)data; + cp1 = (u_char *)data; + break; + default: syslog(LOG_INFO, "\"%s %s %s\" - unknown type (%d)", dname, p_class(class), p_type(type), type); hp->rcode = NOTIMP; return (-1); } + if (n > MAXDATA) { dprintf(1, (ddt, "update type %d: %d bytes is too much data\n", @@ -1315,7 +1466,7 @@ print_output(msg, msglen, rrp) hp->rcode = FORMERR; return (-1); } - cdata = (char *) cp1; + cdata = cp1; result = cp - rrp; /* @@ -1424,7 +1575,7 @@ print_output(msg, msglen, rrp) (void) putc('\t', dbfp); (void) fprintf(dbfp, "%s\t%s\t", p_class(class), p_type(type)); - cp = (u_char *) cdata; + cp = cdata; /* * Print type specific data @@ -1455,7 +1606,7 @@ print_output(msg, msglen, rrp) break; case T_NS: - cp = (u_char *) cdata; + cp = cdata; if (cp[0] == '\0') (void) fprintf(dbfp, ".\t"); else @@ -1528,8 +1679,8 @@ print_output(msg, msglen, rrp) case T_TXT: case T_X25: cp1 = cp + n; - (void) putc('"', dbfp); while (cp < cp1) { + (void) putc('"', dbfp); if (i = *cp++) { for (j = i; j > 0 && cp < cp1; j--) { if (strchr("\n\"\\", *cp)) @@ -1537,8 +1688,11 @@ print_output(msg, msglen, rrp) (void) putc(*cp++, dbfp); } } + (void) putc('"', dbfp); + if (cp < cp1) + (void) putc(' ', dbfp); } - (void) fputs("\"\n", dbfp); + (void) putc('\n', dbfp); break; case T_NSAP: @@ -1550,17 +1704,65 @@ print_output(msg, msglen, rrp) fprintf(dbfp, "%s\n", inet_ntop(AF_INET6, cp, t, sizeof t)); break; - } + } case T_UINFO: (void) fprintf(dbfp, "\"%s\"\n", cp); break; #ifdef LOC_RR - case T_LOC: - (void) fprintf(dbfp, "%s\n", loc_ntoa(cp, NULL)); + case T_LOC: { + char t[255]; + + (void) fprintf(dbfp, "%s\n", loc_ntoa(cp, t)); break; + } #endif /* LOC_RR */ + case T_NAPTR: { + u_int order, preference; + + /* Order */ + GETSHORT(order, cp); + fprintf(dbfp, "%lu", (u_long)order); + + /* Preference */ + GETSHORT(preference, cp); + fprintf(dbfp, " %lu", (u_long)preference); + + /* Flags */ + if (n = *cp++) { + fprintf(dbfp, " \"%.*s\"", (int)n, cp); + cp += n; + } + + /* Service */ + if (n = *cp++) { + fprintf(dbfp, " \"%.*s\"", (int)n, cp); + cp += n; + } + + /* Regexp */ + if (n = *cp++) { + fprintf(dbfp, " \"%.*s\"", (int)n, cp); + cp += n; + } + + /* Replacement */ + fprintf(dbfp, " %s.\n", cp); + + break; + } + case T_SRV: { + u_int priority, weight, port; + + GETSHORT(priority, cp); + GETSHORT(weight, cp); + GETSHORT(port, cp); + fprintf(dbfp, "\t%u %u %u %s.\n", + priority, weight, port, cp); + break; + } + case T_UID: case T_GID: if (n == INT32SZ) { @@ -1578,7 +1780,7 @@ print_output(msg, msglen, rrp) cp += sizeof(char); (void) fprintf(dbfp, "%s ", proto); i = 0; - while (cp < (u_char *) cdata + n) { + while (cp < cdata + n) { j = *cp++; do { if (j & 0200) @@ -1597,7 +1799,76 @@ print_output(msg, msglen, rrp) (void) fprintf(dbfp, " %s.\n", cp); break; + case T_KEY: { + char databuf[16+MAX_KEY_BASE64]; /* 16 for slop */ + u_int16_t keyflags; + + /* get & format key flags */ + keyflags = _getshort(cp); + (void) fprintf(dbfp, "0x%04x ", keyflags); + cp += INT16SZ; + + /* protocol id */ + (void) fprintf(dbfp, " %u", *cp++); + + /* algorithm id */ + (void) fprintf(dbfp, " %u ", *cp++); + + /* key itself (which may have zero length) */ + n = b64_ntop(cp, (cp1 + n) - cp, databuf, sizeof databuf); + if (n < 0) + fprintf(dbfp, "; BAD BASE64\n"); + else + fprintf(dbfp, "%s\n", databuf); + break; + } + + case T_SIG: { + char databuf[16+MAX_KEY_BASE64]; /* 16 for slop */ + + /* get & format rr type which signature covers */ + (void) fprintf(dbfp,"%s", p_type(_getshort((u_char*)cp))); + cp += INT16SZ; + + /* algorithm id */ + (void) fprintf(dbfp," %d",*cp++); + + /* labels (# of labels in name) - skip in textual record */ + cp++; + + /* orig time to live (TTL)) */ + (void) fprintf(dbfp," %d", _getlong((u_char*)cp)); + cp += INT32SZ; + + /* expiration time */ + (void) fprintf(dbfp," %s", p_secstodate(_getlong((u_char*)cp))); + cp += INT32SZ; + + /* time signed */ + (void) fprintf(dbfp," %s", p_secstodate(_getlong((u_char*)cp))); + cp += INT32SZ; + + /* Key footprint */ + (void) fprintf(dbfp," %d", _getshort((u_char*)cp)); + cp += INT16SZ; + + /* signer's name */ + (void) fprintf(dbfp, " %s. ", cp); + cp += strlen((char *) cp) + 1; + + /* signature itself */ + n = b64_ntop(cp, (cdata + n) - cp, databuf, sizeof databuf); + if (n < 0) + fprintf (dbfp, "; BAD BASE64\n"); + else + fprintf (dbfp, "%s\n", databuf); + break; + } + default: + cp1 = cp + n; + while (cp < cp1) + fprintf(dbfp, "0x%02.2X ", *cp++ & 0xFF); (void) fprintf(dbfp, "???\n"); } if (ferror(dbfp)) { diff --git a/contrib/bind/named/ns_defs.h b/contrib/bind/named/ns_defs.h index 6bd10e5..05c4a39 100644 --- a/contrib/bind/named/ns_defs.h +++ b/contrib/bind/named/ns_defs.h @@ -1,6 +1,6 @@ /* * from ns.h 4.33 (Berkeley) 8/23/90 - * $Id: ns_defs.h,v 8.6 1996/05/17 09:10:46 vixie Exp $ + * $Id: ns_defs.h,v 8.8 1996/09/22 00:13:10 vixie Exp $ */ /* @@ -167,13 +167,8 @@ struct notify { #define Z_INCLUDE 0x0080 /* set if include used in file */ #define Z_DB_BAD 0x0100 /* errors when loading file */ #define Z_TMP_FILE 0x0200 /* backup file for xfer is temporary */ -#ifdef ALLOW_UPDATES -#define Z_DYNAMIC 0x0400 /* allow dynamic updates */ -#define Z_DYNADDONLY 0x0800 /* dynamic mode: add new data only */ -#define Z_CHANGED 0x1000 /* zone has changed */ -#endif /* ALLOW_UPDATES */ -#define Z_XFER_ABORTED 0x2000 /* zone transfer has been aborted */ -#define Z_XFER_GONE 0x4000 /* zone transfer process is gone */ +#define Z_XFER_ABORTED 0x0400 /* zone transfer has been aborted */ +#define Z_XFER_GONE 0x0800 /* zone transfer process is gone */ /* named_xfer exit codes */ #define XFER_UPTODATE 0 /* zone is up-to-date */ @@ -224,9 +219,10 @@ 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) */ -#if defined(LAME_DELEGATION) || defined(VALIDATE) - char q_domain[MAXDNAME]; /* domain for servers we are querying */ -#endif + char *q_domain; /* domain of most enclosing zone cut */ + char *q_name; /* domain of query */ + u_int16_t q_class; /* class of query */ + u_int16_t q_type; /* type of query */ #ifdef BIND_NOTIFY int q_notifyzone; /* zone which needs a sysnotify() * when the reply to this comes in. diff --git a/contrib/bind/named/ns_forw.c b/contrib/bind/named/ns_forw.c index 362bf8b..f523855 100644 --- a/contrib/bind/named/ns_forw.c +++ b/contrib/bind/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.14 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: ns_forw.c,v 8.19 1996/12/02 09:27:36 vixie Exp $"; #endif /* not lint */ /* @@ -83,7 +83,7 @@ static char rcsid[] = "$Id: ns_forw.c,v 8.14 1996/08/05 08:31:30 vixie Exp $"; * (no action is taken on errors and qpp is not filled in.) */ int -ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp, dname, np) +ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp, dname, class, type, np) struct databuf *nsp[]; u_char *msg; int msglen; @@ -92,9 +92,11 @@ ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp, dname, np) int dfd; struct qinfo **qpp; char *dname; + int class, type; struct namebuf *np; { register struct qinfo *qp; + char tmpdomain[MAXDNAME]; struct sockaddr_in *nsa; HEADER *hp; u_int16_t id; @@ -121,16 +123,19 @@ ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp, dname, np) } } - qp = qnew(); -#if defined(LAME_DELEGATION) || defined(VALIDATE) - getname(np, qp->q_domain, sizeof qp->q_domain); -#endif + qp = qnew(dname, class, type); + getname(np, tmpdomain, sizeof tmpdomain); + qp->q_domain = strdup(tmpdomain); + if (!qp->q_domain) + panic(ENOMEM, "ns_forw: strdup failed"); qp->q_from = *fp; /* nslookup wants to know this */ - if ((n = nslookup(nsp, qp, dname, "ns_forw")) < 0) { + n = nslookup(nsp, qp, dname, "ns_forw"); + if (n < 0) { dprintf(2, (ddt, "forw: nslookup reports danger\n")); qfree(qp); return (FW_SERVFAIL); - } else if (n == 0 && !fwdtab) { + } + if (n == 0 && !fwdtab) { dprintf(2, (ddt, "forw: no nameservers found\n")); qfree(qp); return (FW_NOSERVER); @@ -345,7 +350,7 @@ nslookupComplain(sysloginfo, queryname, complaint, dname, a_rr, nsdp) complaint, dname, print_a ? inet_ntoa(data_inaddr(a_rr->d_data)) : ""); - syslog(LOG_INFO, buf); + syslog(LOG_INFO, "%s", buf); } } @@ -376,7 +381,7 @@ nslookup(nsp, qp, syslogdname, sysloginfo) register struct databuf *dp, *nsdp; register struct qserv *qs; register int n; - register unsigned int i; + register u_int i; struct hashbuf *tmphtp; char *dname; const char *fname; @@ -423,7 +428,7 @@ nslookup(nsp, qp, syslogdname, sysloginfo) * to see if we've got missing glue */ for (; np; np = np_parent(np)) - for (dp = np->n_data; dp; dp=dp->d_next) + for (dp = np->n_data; dp; dp = dp->d_next) if (match(dp, class, T_NS)) { #ifdef NCACHE if (dp->d_rcode) @@ -447,10 +452,7 @@ nslookup(nsp, qp, syslogdname, sysloginfo) found_arr = 0; goto need_sysquery; } else { - static char *complaint = - "Authoritative A RR missing"; - nslookupComplain(sysloginfo, syslogdname, - complaint, dname, dp, nsdp); + /* Authoritative A RR missing. */ continue; } } @@ -458,11 +460,13 @@ nslookup(nsp, qp, syslogdname, sysloginfo) oldn = n; /* look for name server addresses */ - for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + delete_stale(np); + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { struct in_addr nsa; if (dp->d_type == T_CNAME && dp->d_class == class) { - static char *complaint = "NS points to CNAME"; + static const char *complaint = + "NS points to CNAME"; #ifdef NCACHE if (dp->d_rcode) continue; @@ -475,7 +479,7 @@ nslookup(nsp, qp, syslogdname, sysloginfo) continue; #ifdef NCACHE if (dp->d_rcode) { - static char *complaint = + static const char *complaint = "A RR negative cache entry"; nslookupComplain(sysloginfo, syslogdname, complaint, dname, dp, nsdp); @@ -483,7 +487,8 @@ nslookup(nsp, qp, syslogdname, sysloginfo) } #endif if (data_inaddr(dp->d_data).s_addr == INADDR_ANY) { - static char *complaint = "Bogus (0.0.0.0) A RR"; + static const char *complaint = + "Bogus (0.0.0.0) A RR"; nslookupComplain(sysloginfo, syslogdname, complaint, dname, dp, nsdp); continue; @@ -491,26 +496,29 @@ nslookup(nsp, qp, syslogdname, sysloginfo) #ifdef INADDR_LOOPBACK if (ntohl(data_inaddr(dp->d_data).s_addr) == INADDR_LOOPBACK) { - static char *complaint = "Bogus LOOPBACK A RR"; + static const char *complaint = + "Bogus LOOPBACK A RR"; nslookupComplain(sysloginfo, syslogdname, - complaint, dname, dp, nsdp); + complaint, dname, dp, nsdp); continue; } #endif #ifdef INADDR_BROADCAST if (ntohl(data_inaddr(dp->d_data).s_addr) == INADDR_BROADCAST) { - static char *complaint = "Bogus BROADCAST A RR"; + static const char *complaint = + "Bogus BROADCAST A RR"; nslookupComplain(sysloginfo, syslogdname, - complaint, dname, dp, nsdp); + complaint, dname, dp, nsdp); continue; } #endif #ifdef IN_MULTICAST if (IN_MULTICAST(ntohl(data_inaddr(dp->d_data).s_addr))) { - static char *complaint = "Bogus MULTICAST A RR"; + static const char *complaint = + "Bogus MULTICAST A RR"; nslookupComplain(sysloginfo, syslogdname, - complaint, dname, dp, nsdp); + complaint, dname, dp, nsdp); continue; } #endif @@ -520,26 +528,14 @@ nslookup(nsp, qp, syslogdname, sysloginfo) * Never delete our safety-belt information! */ if ((dp->d_zone == 0) && -#ifdef DATUMREFCNT (dp->d_ttl < curtime) && -#else - (dp->d_ttl < (curtime+900)) && -#endif !(dp->d_flags & DB_F_HINT) ) { - dprintf(3, (ddt, - "nslookup: stale entry '%s'\n", - NAME(*np))); - /* Cache invalidate the NS RR's */ -#ifndef DATUMREFCNT - if (dp->d_ttl < curtime) -#endif - { - delete_all(np, class, T_A); - n = oldn; - found_arr = 0; - goto need_sysquery; - } + syslog(LOG_DEBUG, "nslookup: stale '%s'\n", + NAME(*np)); + n = oldn; + found_arr = 0; + goto need_sysquery; } #ifdef VALIDATE /* anant@isi.edu validation procedure, maintains a @@ -635,7 +631,7 @@ nslookup(nsp, qp, syslogdname, sysloginfo) skipserver: NULL; } -out: + out: dprintf(3, (ddt, "nslookup: %d ns addrs total\n", n)); qp->q_naddr = n; if (n == 0 && potential_ns == 0 && !fwdtab) { @@ -648,13 +644,11 @@ out: } return(-1); } -#ifdef DATUMREFCNT - /* must be run before the sort */ - for (i = naddr ; i < n ; i++) { + /* Update the refcounts before the sort. */ + for (i = naddr; i < n; i++) { qp->q_addr[i].nsdata->d_rcnt++; qp->q_addr[i].ns->d_rcnt++; } -#endif if (n > 1) { qsort((char *)qp->q_addr, n, sizeof(struct qserv), (int (*)__P((const void *, const void *)))qcomp); @@ -840,7 +834,7 @@ retry(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) /* return failure code on stream */ + if (qp->q_stream || (qp->q_flags & Q_PRIMING)) goto fail; qremove(qp); return; @@ -970,6 +964,7 @@ qflush() while (nsqhead) qremove(nsqhead); nsqhead = QINFO_NULL; + priming = 0; } void @@ -1005,45 +1000,67 @@ qfindid(id) } struct qinfo * -#ifdef DMALLOC -qnew_tagged(file, line) - char *file; - int line; -#else -qnew() -#endif +qnew(name, class, type) + const char *name; + int class; + int type; { register struct qinfo *qp; - qp = (struct qinfo *) -#ifdef DMALLOC - dcalloc(file, line, 1, sizeof(struct qinfo)); -#else - calloc(1, sizeof(struct qinfo)); -#endif - if (qp == NULL) { - dprintf(5, (ddt, "qnew: calloc error\n")); - syslog(LOG_ERR, "forw: %m"); - exit(12); - } - dprintf(5, (ddt, "qnew(x%lx)\n", (u_long)qp)); + qp = (struct qinfo *)calloc(1, sizeof(struct qinfo)); + if (qp == NULL) + panic(ENOMEM, "qnew: calloc failed"); + dprintf(5, (ddt, "qnew(%#x)\n", qp)); #ifdef BIND_NOTIFY qp->q_notifyzone = DB_Z_CACHE; #endif qp->q_link = nsqhead; nsqhead = qp; + qp->q_name = strdup(name); + if (!qp->q_name) + panic(ENOMEM, "qnew: strdup failed"); + qp->q_class = (u_int16_t)class; + qp->q_type = (u_int16_t)type; return (qp); } void -qfree(qp) +nsfree(qp, where) struct qinfo *qp; + char *where; { - register struct qinfo *np; - register struct databuf *dp; -#ifdef DATUMREFCNT + static const char freed[] = "freed", busy[] = "busy"; + const char *result; + struct databuf *dp; int i; -#endif + + for (i = 0 ; i < (int)qp->q_naddr ; i++) { + dp = qp->q_addr[i].ns; + if (dp) { + result = (--(dp->d_rcnt)) ? busy : freed; + dprintf(1, (ddt, "%s: ns %s rcnt %d (%s)\n", + where, dp->d_data, dp->d_rcnt, result)); + if (result == freed) + db_free(dp); + } + dp = qp->q_addr[i].nsdata; + if (dp) { + result = (--(dp->d_rcnt)) ? busy : freed; + dprintf(1, (ddt, "%s: nsdata %s rcnt %d (%s)\n", + where, inet_ntoa(data_inaddr(dp->d_data)), + dp->d_rcnt, result)); + if (result == freed) + db_free(dp); + } + } +} + +void +qfree(qp) + struct qinfo *qp; +{ + struct qinfo *np; + struct databuf *dp; dprintf(3, (ddt, "Qfree(x%lx)\n", (u_long)qp)); if (qp->q_next) @@ -1053,42 +1070,20 @@ qfree(qp) free(qp->q_msg); if (qp->q_cmsg) free(qp->q_cmsg); -#ifdef DATUMREFCNT - for (i = 0 ; i < (int)qp->q_naddr ; i++) { - dp = qp->q_addr[i].ns; - if (dp) - if (--(dp->d_rcnt)) { - dprintf(3, (ddt, "qfree: ns %s rcnt %d\n", - dp->d_data, - dp->d_rcnt)); - } else { - dprintf(3, (ddt, "qfree: ns %s rcnt %d delayed\n", - dp->d_data, - dp->d_rcnt)); - free((char*)dp); - } - dp = qp->q_addr[i].nsdata; - if (dp) - if ((--(dp->d_rcnt))) { - dprintf(3, (ddt, "qfree: nsdata %08.8X rcnt %d\n", - *(int32_t *)(dp->d_data), - dp->d_rcnt)); - } else { - dprintf(3, (ddt, "qfree: nsdata %08.8X rcnt %d delayed\n", - *(int32_t *)(dp->d_data), - dp->d_rcnt)); - free((char*)dp); - } - } -#endif - if( nsqhead == qp ) { + if (qp->q_domain) + free(qp->q_domain); + if (qp->q_name) + free(qp->q_name); + nsfree(qp, "qfree"); + if (nsqhead == qp) nsqhead = qp->q_link; - } else { - for( np=nsqhead; np->q_link != QINFO_NULL; np = np->q_link ) { - if( np->q_link != qp ) continue; + else { + for (np = nsqhead; np->q_link != QINFO_NULL; np = np->q_link) { + if (np->q_link != qp) + continue; np->q_link = qp->q_link; /* dequeue */ break; } } - free((char *)qp); + free((char*)qp); } diff --git a/contrib/bind/named/ns_func.h b/contrib/bind/named/ns_func.h index 204aee2..aa61381 100644 --- a/contrib/bind/named/ns_func.h +++ b/contrib/bind/named/ns_func.h @@ -1,12 +1,13 @@ /* ns_func.h - declarations for ns_*.c's externally visible functions * - * $Id: ns_func.h,v 8.9 1996/05/20 15:10:01 vixie Exp $ + * $Id: ns_func.h,v 8.13 1996/11/11 06:36:49 vixie Exp $ */ /* ++from ns_resp.c++ */ extern void ns_resp __P((u_char *, int)), prime_cache __P((void)), - delete_all __P((struct namebuf *, int, int)); + delete_all __P((struct namebuf *, int, int)), + delete_stale __P((struct namebuf *)); extern struct qinfo *sysquery __P((const char *, int, int, struct in_addr *, int, int)); extern struct notify *findNotifyPeer __P((const struct zoneinfo *, @@ -55,6 +56,7 @@ extern int ns_forw __P((struct databuf *nsp[], int dfd, struct qinfo **qpp, char *dname, + int class, int type, struct namebuf *np)), haveComplained __P((const char *, const char *)), nslookup __P((struct databuf *nsp[], @@ -68,14 +70,10 @@ extern void schedretry __P((struct qinfo *, time_t)), retry __P((struct qinfo *)), qflush __P((void)), qremove __P((struct qinfo *)), + nsfree __P((struct qinfo *, char *)), qfree __P((struct qinfo *)); extern struct qinfo *qfindid __P((u_int16_t)), -#ifdef DMALLOC - *qnew_tagged __P((void)); -# define qnew() qnew_tagged(__FILE__, __LINE__) -#else - *qnew(); -#endif + *qnew __P((const char *, int, int)); /* --from ns_forw.c-- */ /* ++from ns_main.c++ */ @@ -129,7 +127,9 @@ extern void ns_refreshtime __P((struct zoneinfo *, time_t)), extern enum context ns_ptrcontext __P((const char *owner)); extern enum context ns_ownercontext __P((int type, enum transport)); extern int ns_nameok __P((const char *name, int class, - enum transport, enum context)); + enum transport, enum context, + const char *owner, + struct in_addr source)); extern int ns_wildcard __P((const char *name)); /* --from ns_init.c-- */ @@ -137,6 +137,10 @@ extern int ns_wildcard __P((const char *name)); extern void cache_n_resp __P((u_char *, int)); /* --from ns_ncache.c-- */ +/* ++from ns_udp.c++ */ +extern void ns_udp __P((void)); +/* --from ns_udp.c-- */ + /* ++from ns_stats.c++ */ extern void ns_stats __P((void)); #ifdef XSTATS diff --git a/contrib/bind/named/ns_glob.h b/contrib/bind/named/ns_glob.h index 46abaf7..bf31e33 100644 --- a/contrib/bind/named/ns_glob.h +++ b/contrib/bind/named/ns_glob.h @@ -1,6 +1,6 @@ /* * from ns.h 4.33 (Berkeley) 8/23/90 - * $Id: ns_glob.h,v 8.9 1996/05/20 15:10:01 vixie Exp $ + * $Id: ns_glob.h,v 8.11 1996/11/11 06:36:49 vixie Exp $ */ /* @@ -123,15 +123,6 @@ DECL int needToChkpt INIT(0); /* need to dump statistics */ DECL int needStatsDump INIT(0); -#ifdef ALLOW_UPDATES - /* need to exit (may need to doadump - * first, if database has changed since - * it was last dumped/booted). Gets - * set by shutdown signal handler - * (onintr) - */ -DECL int needToExit INIT(0); -#endif /* ALLOW_UPDATES */ #ifdef XSTATS /* need to exit * set by shutdown signal handler @@ -289,3 +280,5 @@ DECL const char *severity_strings[] = { "ignore", "warn", "fail", NULL } #endif ; + +DECL struct in_addr inaddr_any; /* Inits to 0.0.0.0 */ diff --git a/contrib/bind/named/ns_init.c b/contrib/bind/named/ns_init.c index 3ca8180..8a6fd92 100644 --- a/contrib/bind/named/ns_init.c +++ b/contrib/bind/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.17 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: ns_init.c,v 8.24 1996/12/02 09:17:21 vixie Exp $"; #endif /* not lint */ /* @@ -75,7 +75,7 @@ static char rcsid[] = "$Id: ns_init.c,v 8.17 1996/08/05 08:31:30 vixie Exp $"; #undef nsaddr -enum limit { Datasize }; +enum limit { Datasize , Files }; static void zoneinit __P((struct zoneinfo *)), get_forwarders __P((FILE *)), @@ -83,6 +83,7 @@ static void zoneinit __P((struct zoneinfo *)), #ifdef DEBUG content_zone __P((int)), #endif + do_reload __P((char *, int, int)), free_forwarders __P((void)), ns_limit __P((const char *name, int value)), ns_checknames __P((const char *names, @@ -197,6 +198,7 @@ ns_init(bootfile) #ifdef SECURE_ZONES free_netlist(&zp->secure_nets); #endif + do_reload(zp->z_origin, zp->z_type, zp->z_class); syslog(LOG_NOTICE, "Zone \"%s\" was removed", zp->z_origin); free(zp->z_origin); free(zp->z_source); @@ -240,9 +242,6 @@ boot_read(filename, includefile) #endif struct stat f_time; static int tmpnum = 0; /* unique number for tmp zone files */ -#ifdef ALLOW_UPDATES - char *flag; -#endif int slineno; /* Saved global line number. */ int i; @@ -497,29 +496,7 @@ boot_read(filename, includefile) case Z_PRIMARY: source = savestr(buf); -#ifdef ALLOW_UPDATES - if (getword(buf, sizeof(buf), fp, 0)) { - endline(fp); - flag = buf; - while (flag) { - char *cp = strchr(flag, ','); - if (cp) - *cp++ = 0; - if (strcasecmp(flag, "dynamic") == 0) - zp->z_flags |= Z_DYNAMIC; - else if (strcasecmp(flag, "addonly") == 0) - zp->z_flags |= Z_DYNADDONLY; - else { - syslog(LOG_NOTICE, - "%s: line %d: bad flag '%s'\n", - filename, lineno, flag); - } - flag = cp; - } - } -#else /*ALLOW_UPDATES*/ endline(fp); -#endif dprintf(1, (ddt, ", source = %s\n", source)); /* @@ -552,13 +529,8 @@ boot_read(filename, includefile) dprintf(1, (ddt, "reloading zone\n")); if (!db_load(zp->z_source, zp->z_origin, zp, NULL)) zp->z_flags |= Z_AUTH; -#ifdef ALLOW_UPDATES - /* Guarantee calls to ns_maint() */ - zp->z_refresh = maint_interval; -#else zp->z_refresh = 0; /* no maintenance needed */ zp->z_time = 0; -#endif break; case Z_SECONDARY: @@ -603,7 +575,7 @@ boot_read(filename, includefile) if (zp->z_source && (strcmp(source, zp->z_source) || (stat(zp->z_source, &f_time) == -1 || - (zp->z_ftime != f_time.st_mtime)))) { + (zp->z_ftime != f_time.st_mtime)))) { dprintf(1, (ddt, "backup file changed\n")); free(zp->z_source); zp->z_source = NULL; @@ -614,6 +586,11 @@ boot_read(filename, includefile) #else remove_zone(hashtab, zp - zones); #endif + /* + * reload parent so that NS records are + * present during the zone transfer. + */ + do_reload(zp->z_origin, zp->z_type, zp->z_class); } if (zp->z_source) free(source); @@ -693,71 +670,6 @@ zoneinit(zp) } } -#ifdef ALLOW_UPDATES -/* - * Look for the authoritative zone with the longest matching RHS of dname - * and return its zone # or zero if not found. - */ -int -findzone(dname, class) - char *dname; - int class; -{ - char *dZoneName, *zoneName; - int dZoneNameLen, zoneNameLen; - int maxMatchLen = 0; - int maxMatchZoneNum = 0; - int zoneNum; - - dprintf(4, (ddt, "findzone(dname=%s, class=%d)\n", dname, class)); -#ifdef DEBUG - if (debug >= 5) { - fprintf(ddt, "zone dump:\n"); - for (zoneNum = 1; zoneNum < nzones; zoneNum++) - printzoneinfo(zoneNum); - } -#endif - - dZoneName = strchr(dname, '.'); - if (dZoneName == NULL) - dZoneName = ""; /* root */ - else - dZoneName++; /* There is a '.' in dname, so use remainder of - string as the zone name */ - dZoneNameLen = strlen(dZoneName); - for (zoneNum = 1; zoneNum < nzones; zoneNum++) { - if (zones[zoneNum].z_type == Z_NIL) - continue; - zoneName = (zones[zoneNum]).z_origin; - zoneNameLen = strlen(zoneName); - /* The zone name may or may not end with a '.' */ - if (zoneName[zoneNameLen - 1] == '.') - zoneNameLen--; - if (dZoneNameLen != zoneNameLen) - continue; - dprintf(5, (ddt, "about to strncasecmp('%s', '%s', %d)\n", - dZoneName, zoneName, dZoneNameLen)); - if (strncasecmp(dZoneName, zoneName, dZoneNameLen) == 0) { - dprintf(5, (ddt, "match\n")); - /* - * See if this is as long a match as any so far. - * Check if "<=" instead of just "<" so that if - * root domain (whose name length is 0) matches, - * we use it's zone number instead of just 0 - */ - if (maxMatchLen <= zoneNameLen) { - maxMatchZoneNum = zoneNum; - maxMatchLen = zoneNameLen; - } - } else { - dprintf(5, (ddt, "no match\n")); - } - } - dprintf(4, (ddt, "findzone: returning %d\n", maxMatchZoneNum)); - return (maxMatchZoneNum); -} -#endif /* ALLOW_UPDATES */ - static void get_forwarders(fp) FILE *fp; @@ -881,6 +793,75 @@ find_zone(name, type, class) return NULL; } +static void +do_reload(domain, type, class) + char *domain; + int type; + int class; +{ + char *s; + struct zoneinfo *zp; + + dprintf(1, (ddt, "do_reload: %s %d %d\n", + *domain ? domain : ".", type, class)); + + /* the zone has changed type? */ + /* NOTE: we still exist so don't match agains ourselves */ + /* If we are a STUB or SECONDARY check that we have loaded */ + if (((type != Z_STUB) && (zp = find_zone(domain, Z_STUB, class)) && + zp->z_serial) || + ((type != Z_CACHE) && find_zone(domain, Z_CACHE, class)) || + ((type != Z_PRIMARY) && find_zone(domain, Z_PRIMARY, class)) || + ((type != Z_SECONDARY) + && (zp = find_zone(domain, Z_SECONDARY, class)) && zp->z_serial) + ) { + return; + } + + while ((s = strchr(domain, '.')) || *domain) { + if (s) + domain = s + 1; /* skip dot */ + 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))) { + + dprintf(1, (ddt, "do_reload: matched %s\n", + *domain ? domain : ".")); + +#ifdef CLEANCACHE + if (zp->z_type == Z_CACHE) + remove_zone(fcachetab, 0, 1); + else + remove_zone(hashtab, zp - zones, 1); +#else + if (zp->z_type == Z_CACHE) + remove_zone(fcachetab, 0); + else + remove_zone(hashtab, zp - zones); +#endif + zp->z_flags &= ~Z_AUTH; + + switch (zp->z_type) { + case Z_SECONDARY: + case Z_STUB: + zoneinit(zp); + break; + case Z_PRIMARY: + case Z_CACHE: + if (db_load(zp->z_source, zp->z_origin, zp, 0) + == 0) + zp->z_flags |= Z_AUTH; + break; + } + break; + } + } +} + #ifdef DEBUG /* prints out the content of zones */ static void @@ -906,6 +887,8 @@ ns_limit(name, value) max_xfers_per_ns = value; } else if (!strcasecmp(name, "datasize")) { ns_rlimit("datasize", Datasize, value); + } else if (!strcasecmp(name, "files")) { + ns_rlimit("files", Files, value); } else { syslog(LOG_ERR, "error: unrecognized limit in bootfile: \"%s\"", @@ -985,7 +968,7 @@ ns_ownercontext(type, transport) context = hostname_ctx; break; default: - abort(); + panic(-1, "impossible condition in ns_ownercontext()"); } break; case T_MB: @@ -999,14 +982,16 @@ ns_ownercontext(type, transport) } int -ns_nameok(name, class, transport, context) +ns_nameok(name, class, transport, context, owner, source) const char *name; int class; enum transport transport; enum context context; + struct in_addr source; + const char *owner; { - int ok = 1; enum severity severity = checkname_severity[transport]; + int ok; if (severity == ignore) return (1); @@ -1024,17 +1009,44 @@ ns_nameok(name, class, transport, context) ok = res_hnok(name); break; default: - abort(); + panic(-1, "impossible condition in ns_nameok()"); } if (!ok) { + char *s, *o; + + if (source.s_addr == INADDR_ANY) + s = strdup(transport_strings[transport]); + else { + s = malloc(strlen(transport_strings[transport]) + + sizeof " from [000.000.000.000]"); + if (s) + sprintf(s, "%s from [%s]", + transport_strings[transport], + inet_ntoa(source)); + } + if (strcasecmp(owner, name) == 0) + o = strdup(""); + else { + const char *t = (*owner == '\0') ? "." : owner; + + o = malloc(strlen(t) + sizeof " (owner \"\")"); + if (o) + sprintf(o, " (owner \"%s\")", t); + } +#ifndef ultrix syslog((transport == response_trans) ? LOG_INFO : LOG_NOTICE, - "%s name \"%s %s\" (%s) is invalid - %s", + "%s name \"%s\"%s %s (%s) is invalid - %s", context_strings[context], - name, p_class(class), - transport_strings[transport], + name, o != NULL ? o : "[malloc failed]", p_class(class), + s != NULL ? s : "[malloc failed]", (severity == fail) ? "rejecting" : "proceeding anyway"); +#endif if (severity == warn) ok = 1; + if (s) + free(s); + if (o) + free(o); } return (ok); } @@ -1062,14 +1074,25 @@ ns_rlimit(name, limit, value) name); #else struct rlimit limits; - int rlimit; + int rlimit = -1; switch (limit) { case Datasize: rlimit = RLIMIT_DATA; break; + case Files: +#ifdef RLIMIT_NOFILE + rlimit = RLIMIT_NOFILE; +#endif + break; default: - abort(); + panic(-1, "impossible condition in ns_rlimit()"); + } + if (rlimit == -1) { + syslog(LOG_WARNING, + "limit \"%s\" not supported on this system - ignored", + name); + return; } if (getrlimit(rlimit, &limits) < 0) { syslog(LOG_WARNING, "getrlimit(%s): %m", name); diff --git a/contrib/bind/named/ns_main.c b/contrib/bind/named/ns_main.c index bac7d5a..6fff4cc 100644 --- a/contrib/bind/named/ns_main.c +++ b/contrib/bind/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.17 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: ns_main.c,v 8.24 1996/11/26 10:11:22 vixie Exp $"; #endif /* not lint */ /* @@ -173,13 +173,6 @@ main(argc, argv, envp) int rfd, size, len; time_t lasttime, maxctime; u_char buf[BUFSIZ]; -#ifdef POSIX_SIGNALS - struct sigaction sact; -#else -#ifndef SYSV - struct sigvec vec; -#endif -#endif #ifdef NeXT int old_sigmask; #endif @@ -196,6 +189,9 @@ main(argc, argv, envp) #ifdef IP_OPTIONS u_char ip_opts[50]; /* arbitrary size */ #endif +#ifdef RLIMIT_NOFILE + struct rlimit rl; +#endif local_ns_port = ns_port = htons(NAMESERVER_PORT); @@ -304,7 +300,10 @@ main(argc, argv, envp) n = 0; #if defined(DEBUG) && defined(LOG_PERROR) if (debug) - n = LOG_PERROR; + n |= LOG_PERROR; +#endif +#ifdef LOG_NOWAIT + n |= LOG_NOWAIT; #endif #ifdef LOG_DAEMON openlog("named", LOG_PID|LOG_CONS|LOG_NDELAY|n, LOGFAC); @@ -312,6 +311,14 @@ main(argc, argv, envp) openlog("named", LOG_PID); #endif +#ifdef RLIMIT_NOFILE + rl.rlim_cur = rl.rlim_max = FD_SETSIZE; + if (setrlimit(RLIMIT_NOFILE, &rl) == -1) + syslog(LOG_ERR, "setrlimit(RLIMIT_FSIZE,FD_SETSIZE): %m"); +#endif + /* check that udp checksums are on */ + ns_udp(); + #ifdef WANT_PIDFILE /* tuck my process id away */ #ifdef PID_FIX @@ -344,10 +351,21 @@ main(argc, argv, envp) ** Open stream port. */ for (n = 0; ; n++) { + int fd; if ((vs = socket(AF_INET, SOCK_STREAM, 0)) < 0) { syslog(LOG_ERR, "socket(SOCK_STREAM): %m"); exit(1); } +#ifdef F_DUPFD + /* + * leave a space for stdio to work in + */ + if ((fd = fcntl(vs, F_DUPFD, 20)) != -1) { + close(vs); + vs = fd; + } else + syslog(LOG_NOTICE, "fcntl(vs, F_DUPFD, 20): %m"); +#endif if (setsockopt(vs, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) { @@ -395,6 +413,7 @@ main(argc, argv, envp) setsignal(SIGIOT, -1, setstatsflg); setsignal(SIGUSR1, -1, setIncrDbgFlg); setsignal(SIGUSR2, -1, setNoDbgFlg); + setsignal(SIGHUP, -1, onhup); #if defined(SIGWINCH) && defined(QRYLOG) setsignal(SIGWINCH, -1, setQrylogFlg); @@ -427,7 +446,6 @@ main(argc, argv, envp) setsignal(SIGALRM, SIGCHLD, maint_alarm); setsignal(SIGCHLD, SIGALRM, reapchild); setsignal(SIGPIPE, -1, (SIG_FN (*)())SIG_IGN); - setsignal(SIGHUP, -1, onhup); #if defined(SIGXFSZ) /* Wierd DEC Hesiodism, harmless. */ @@ -438,12 +456,6 @@ main(argc, argv, envp) setsignal(SIGSYS, -1, sigprof); #endif /* SIGSYS */ -#ifdef ALLOW_UPDATES - /* Catch SIGTERM so we can dump the database upon shutdown if it - has changed since it was last dumped/booted */ - setsignal(SIGTERM, -1, onintr); -#endif - #ifdef XSTATS /* Catch SIGTERM so we can write stats before exiting. */ setsignal(SIGTERM, -1, onintr); @@ -562,22 +574,6 @@ main(argc, argv, envp) ddt = 0; } #endif -#ifdef ALLOW_UPDATES - if (needToExit) { - struct zoneinfo *zp; - sigblock(~0); /* - * Block all blockable signals - * to ensure a consistant - * state during final dump - */ - dprintf(1, (ddt, "Received shutdown signal\n")); - for (zp = zones; zp < &zones[nzones]; zp++) { - if (zp->z_flags & Z_CHANGED) - zonedump(zp); - } - exit(0); - } -#endif /* ALLOW_UPDATES */ #ifdef XSTATS if (needToExit) { ns_logstats(); @@ -675,6 +671,8 @@ main(argc, argv, envp) ntohs(from_addr.sin_port), dqp->dq_dfd, n, ctimel(tt.tv_sec))); + if (n < HFIXEDSZ) + break; #ifdef DEBUG if (debug >= 10) fp_nquery(buf, n, ddt); @@ -790,10 +788,12 @@ main(argc, argv, envp) sp->s_bufp = (u_char *)&sp->s_tempsize; FD_SET(rfd, &mask); FD_SET(rfd, &tmpmask); - dprintf(1, (ddt, - "\nTCP connection from [%s].%d (fd %d)\n", - inet_ntoa(sp->s_from.sin_addr), - ntohs(sp->s_from.sin_port), rfd)); +#ifdef DEBUG + if (debug) + syslog(LOG_DEBUG, + "IP/TCP connection from %s (fd %d)\n", + sin_ntoa(&sp->s_from), rfd); +#endif } if (streamq) dprintf(3, (ddt, "streamq = 0x%lx\n", @@ -871,8 +871,8 @@ main(argc, argv, envp) * if we have a query id, then we will send an * error back to the user. */ - if (sp->s_bufsize == 0 && - (sp->s_bufp - sp->s_buf > INT16SZ)) { + if (sp->s_bufsize == 0) { + if (sp->s_bufp - sp->s_buf > INT16SZ) { HEADER *hp; hp = (HEADER *)sp->s_buf; @@ -885,7 +885,30 @@ main(argc, argv, envp) hp->rcode = SERVFAIL; (void) writemsg(sp->s_rfd, sp->s_buf, HFIXEDSZ); - continue; + } + continue; + } + /* + * If the message is too short to contain a valid + * header, try to send back an error, and drop the + * message. + */ + if (sp->s_bufp - sp->s_buf < HFIXEDSZ) { + if (sp->s_bufp - sp->s_buf > INT16SZ) { + HEADER *hp; + + hp = (HEADER *)sp->s_buf; + hp->qr = 1; + hp->ra = (NoRecurse == 0); + hp->ancount = 0; + hp->qdcount = 0; + hp->nscount = 0; + hp->arcount = 0; + hp->rcode = SERVFAIL; + (void) writemsg(sp->s_rfd, sp->s_buf, + HFIXEDSZ); + } + continue; } if ((n == -1) && (errno == PORT_WOULDBLK)) continue; @@ -937,7 +960,9 @@ getnetconf() exit(1); } ntp = NULL; -#if defined(AF_LINK) && !defined(RISCOS_BSD) && !defined(M_UNIX) +#if defined(AF_LINK) && \ + !defined(RISCOS_BSD) && !defined(M_UNIX) && \ + !defined(sgi) && !defined(sun) && !defined(NO_SA_LEN) #define my_max(a, b) (a > b ? a : b) #define my_size(p) my_max((p).sa_len, sizeof(p)) #else @@ -1168,6 +1193,7 @@ opensocket(dqp) { int m, n; int on = 1; + int fd; /* * Open datagram sockets bound to interface address. @@ -1176,6 +1202,16 @@ opensocket(dqp) syslog(LOG_ERR, "socket(SOCK_DGRAM): %m - exiting"); exit(1); } +#ifdef F_DUPFD + /* + * leave a space for stdio to work in + */ + if ((fd = fcntl(dqp->dq_dfd, F_DUPFD, 20)) != -1) { + close(dqp->dq_dfd); + dqp->dq_dfd = fd; + } else + syslog(LOG_NOTICE, "fcntl(dfd, F_DUPFD, 20): %m"); +#endif dprintf(1, (ddt, "dqp->dq_addr %s d_dfd %d\n", inet_ntoa(dqp->dq_addr), dqp->dq_dfd)); if (setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_REUSEADDR, @@ -1252,22 +1288,6 @@ maint_alarm() } -#ifdef ALLOW_UPDATES -/* - * Signal handler to schedule shutdown. Just set flag, to ensure a consistent - * state during dump. - */ -static SIG_FN -onintr() -{ - int save_errno = errno; - - resignal(SIGTERM, -1, onintr); - needToExit = 1; - errno = save_errno; -} -#endif /* ALLOW_UPDATES */ - #ifdef XSTATS /* * Signal handler to write log information diff --git a/contrib/bind/named/ns_maint.c b/contrib/bind/named/ns_maint.c index 631210b..944d2b2 100644 --- a/contrib/bind/named/ns_maint.c +++ b/contrib/bind/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.16 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: ns_maint.c,v 8.18 1996/09/22 00:13:10 vixie Exp $"; #endif /* not lint */ /* @@ -98,9 +98,7 @@ static time_t stats_time; #endif /* * Invoked at regular intervals by signal interrupt; refresh all secondary - * zones from primary name server and remove old cache entries. Also, - * ifdef'd ALLOW_UPDATES, dump database if it has changed since last - * dump/bootup. + * zones from primary name server and remove old cache entries. */ void ns_maint() @@ -147,18 +145,6 @@ ns_maint() } qserial_query(zp); break; -#ifdef ALLOW_UPDATES - case Z_PRIMARY: - /* - * Checkpoint the zone if it has changed - * since we last checkpointed - */ - if (zp->z_flags & Z_CHANGED) { - zonedump(zp); - ns_refreshtime(zp, tt.tv_sec); - } - break; -#endif /* ALLOW_UPDATES */ } gettime(&tt); } @@ -403,7 +389,7 @@ static void startxfer(zp) struct zoneinfo *zp; { - static char *argv[NSMAX + 20], argv_ns[NSMAX][MAXDNAME]; + char *argv[NSMAX + 20], argv_ns[NSMAX][MAXDNAME]; int argc = 0, argc_ns = 0, pid, i; unsigned int cnt; char debug_str[10]; @@ -937,7 +923,8 @@ endxfer() if (WIFSIGNALED(status)) { if (WTERMSIG(status) != SIGKILL) { syslog(LOG_NOTICE, - "named-xfer exited with signal %d\n", + "named-xfer \"%s\" exited with signal %d\n", + zp->z_origin[0]?zp->z_origin:".", WTERMSIG(status)); } ns_retrytime(zp, tt.tv_sec); diff --git a/contrib/bind/named/ns_ncache.c b/contrib/bind/named/ns_ncache.c index eb8faaf..9de1fc8 100644 --- a/contrib/bind/named/ns_ncache.c +++ b/contrib/bind/named/ns_ncache.c @@ -32,7 +32,9 @@ cache_n_resp(msg, msglen) char dname[MAXDNAME]; int n; int type, class; +#ifdef VALIDATE int Vcode; +#endif int flags; nameserIncr(from_addr.sin_addr, nssRcvdNXD); @@ -62,67 +64,74 @@ cache_n_resp(msg, msglen) } #endif #ifdef RETURNSOA - if (hp->rcode==NXDOMAIN) { - u_int32_t ttl; - u_int16_t atype; - u_char * tp = cp; - u_char * cp1; - u_char data[BUFSIZ+MAXDNAME]; - int len = sizeof(data); + if (hp->nscount) { + u_int32_t ttl; + u_int16_t atype; + u_char *tp = cp; + u_char *cp1; + u_char data[BUFSIZ+MAXDNAME]; + size_t len = sizeof data; - /* store ther SOA record */ - if (!hp->nscount) { - dprintf(3, (ddt, "ncache: nscount == 0\n")); - return; - } - n = dn_skipname(tp, msg + msglen); - if (n < 0) { - dprintf(3, (ddt, "ncache: form error\n")); - return; - } - tp += n; - GETSHORT(atype,tp); /* type */ - if (atype != T_SOA) { - dprintf(3, (ddt, "ncache: type (%d) != T_SOA\n",atype)); - return; - } - tp += sizeof(u_int16_t); /* class */ - GETLONG(ttl,tp); /* ttl */ - tp += sizeof(u_int16_t); /* dlen */ + /* we store NXDOMAIN as T_SOA regardless of the query type */ + if (hp->rcode == NXDOMAIN) + type = T_SOA; - if ((n = dn_expand(msg, msg + msglen, tp, data, len)) - < 0 ) { - dprintf(3, (ddt, "ncache: form error 2\n")); - return; - } /* origin */ - tp += n; - cp1 = data + (n = strlen(data) + 1); - len -= n; - if ((n = dn_expand(msg, msg + msglen, tp, cp1, len)) < 0 ) { - dprintf(3, (ddt, "ncache: form error 2\n")); - return; - } /* mail */ - tp += n; - n = strlen(cp1) + 1; - cp1 += n; - len -= n; - bcopy(tp, cp1, n = 5 * sizeof(u_int32_t)); - /* serial, refresh, retry, expire, min */ - cp1 += n; - len -= n; - /* store the zone of the soa record */ - if ((n = dn_expand(msg, msg + msglen, cp, cp1, len)) < 0 ) { - dprintf(3, (ddt, "ncache: form error 2\n")); - return; - } - n = strlen(cp1) + 1; - cp1 += n; + /* store ther SOA record */ + n = dn_skipname(tp, msg + msglen); + if (n < 0) { + dprintf(3, (ddt, "ncache: form error\n")); + return; + } + tp += n; + GETSHORT(atype, tp); /* type */ + if (atype != T_SOA) { + dprintf(3, (ddt, + "ncache: type (%d) != T_SOA\n",atype)); + goto no_soa; + } + tp += INT16SZ; /* class */ + GETLONG(ttl, tp); /* ttl */ + tp += INT16SZ; /* dlen */ + + /* origin */ + n = dn_expand(msg, msg + msglen, tp, (char*)data, len); + if (n < 0) { + dprintf(3, (ddt, "ncache: form error 2\n")); + return; + } + tp += n; + n = strlen((char*)data) + 1; + cp1 = data + n; + len -= n; + /* mail */ + n = dn_expand(msg, msg + msglen, tp, (char*)cp1, len); + if (n < 0) { + dprintf(3, (ddt, "ncache: form error 2\n")); + return; + } + tp += n; + n = strlen((char*)cp1) + 1; + cp1 += n; + len -= n; + bcopy(tp, cp1, n = 5 * INT32SZ); + /* serial, refresh, retry, expire, min */ + cp1 += n; + len -= n; + /* store the zone of the soa record */ + n = dn_expand(msg, msg + msglen, cp, (char*)cp1, len); + if (n < 0) { + dprintf(3, (ddt, "ncache: form error 2\n")); + return; + } + n = strlen((char*)cp1) + 1; + cp1 += n; - dp = savedata(class, T_SOA, MIN(ttl,NTTL)+tt.tv_sec, data, - cp1 - data); + dp = savedata(class, type, MIN(ttl, NTTL) + tt.tv_sec, data, + cp1 - data); } else { + no_soa: #endif - dp = savedata(class, type, NTTL+tt.tv_sec, NULL, 0); + dp = savedata(class, type, NTTL + tt.tv_sec, NULL, 0); #ifdef RETURNSOA } #endif @@ -137,11 +146,11 @@ cache_n_resp(msg, msglen) flags = DB_NOTAUTH|DB_NOHINTS; } - if ((n = db_update(dname,dp,dp,flags,hashtab)) != OK) { + if ((n = db_update(dname, dp, dp, flags, hashtab)) != OK) { dprintf(1, (ddt, "db_update failed return value:%d, cache_n_resp()\n", n)); - free((char *)dp); + db_free(dp); return; } dprintf(4, (ddt, diff --git a/contrib/bind/named/ns_req.c b/contrib/bind/named/ns_req.c index c485f59..1d7e39e 100644 --- a/contrib/bind/named/ns_req.c +++ b/contrib/bind/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.20 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: ns_req.c,v 8.27 1996/10/08 04:51:03 vixie Exp $"; #endif /* not lint */ /* @@ -55,6 +55,28 @@ static char rcsid[] = "$Id: ns_req.c,v 8.20 1996/08/05 08:31:30 vixie Exp $"; * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * - + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. * --Copyright-- */ @@ -99,27 +121,15 @@ static enum req_action req_notify __P((HEADER *hp, u_char **cpp, u_char *eom, #endif static void fwritemsg __P((FILE *, u_char *, int)), -#ifdef DEBUG - printSOAdata __P((struct databuf)), -#endif doaxfr __P((struct namebuf *, FILE *, struct namebuf *, int)), startxfr __P((struct qstream *, struct namebuf *, u_char *, int, int, const char *)); -#ifdef ALLOW_UPDATES -static int InitDynUpdate __P((register HEADER *hp, - char *msg, - int msglen, - u_char *startcp, - struct sockaddr_in *from, - struct qstream *qsp, - int dfd)); -#endif - static struct addinfo addinfo[NADDRECS]; static void addname __P((const char *, const char *, u_int16_t, u_int16_t)); +static void copyCharString __P((u_char **, const char *)); /* * Process request using database; assemble and send response. @@ -192,41 +202,6 @@ ns_req(msg, msglen, buflen, qsp, from, dfd) break; #endif -#ifdef ALLOW_UPDATES -#define FORWARDED 1000 -/* - * In a sense the following constant should be defined in <arpa/nameser.h>, - * since it is returned here in place of a response code if the update was - * forwarded, and the response codes are defined in nameser.h. On the other - * hand, though, this constant is only seen in this file. The assumption - * here is that none of the other return codes equals this one (a good - * assumption, since they only occupy 4 bits over-the-wire) - */ - /* Call InitDynUpdate for all dynamic update requests */ - case UPDATEM: - case UPDATEMA: - case UPDATED: - case UPDATEDA: - case UPDATEA: - n = InitDynUpdate(hp, msg, msglen, cp, from, qsp, dfd); - if (n == FORWARDED) { - /* Return directly because InitDynUpdate - * forwarded the query to the primary, so we - * will send response later - */ - action = Return; - } else { - /* Either sucessful primary update or failure; - * return response code to client - */ - action = Finish; - } - - case ZONEREF: - dprintf(1, (ddt, "Refresh Zone\n")); - /*FALLTHROUGH*/ -#endif /* ALLOW_UPDATES */ - default: dprintf(1, (ddt, "ns_req: Opcode %d not implemented\n", hp->opcode)); @@ -453,10 +428,7 @@ req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from) nameserIncr(from->sin_addr, nssRcvdQ); #endif -#ifdef DATUMREFCNT nsp[0] = NULL; -#endif - dpp = dnptrs; *dpp++ = msg; *dpp = NULL; @@ -504,6 +476,33 @@ req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from) qtypeIncr(type); /* + * Yow! + */ + if (!strcasecmp(dnbuf, "VERSION.BIND") && + class == C_CHAOS && type == T_TXT) { + u_char *tp; + + hp->ancount = htons(1); + hp->nscount = htons(0); + hp->arcount = htons(0); + hp->rcode = NOERROR; + hp->aa = 1; + hp->ra = 0; + copyCharString(cpp, "VERSION"); /* Name */ + copyCharString(cpp, "BIND"); + *(*cpp)++ = 0x00; + PUTSHORT(T_TXT, *cpp); /* Type */ + PUTSHORT(C_CHAOS, *cpp); /* Class */ + PUTLONG(0, *cpp); /* TTL */ + tp = *cpp; /* Temp RdLength */ + PUTSHORT(0, *cpp); + copyCharString(cpp, Version); + PUTSHORT((*cpp) - (tp + INT16SZ), tp); /* Real RdLength */ + *msglenp = *cpp - msg; /* Total message length */ + return (Finish); + } + + /* * Process query. */ if (type == T_AXFR) { @@ -551,7 +550,7 @@ req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from) } #endif /*QRYLOG*/ -try_again: + try_again: dprintf(1, (ddt, "req: nlookup(%s) id %d type=%d class=%d\n", dname, ntohs(hp->id), type, class)); htp = hashtab; /* lookup relative to root */ @@ -645,15 +644,17 @@ try_again: n = finddata(np, class, T_SOA, hp, &dname, buflenp, &count); if (n != 0 ) { + if (count) { + *cpp += n; + *buflenp -= n; + *msglenp += n; + hp->nscount = htons((u_int16_t)count); + } if (hp->rcode == NOERROR_NODATA) { /* this should not occur */ hp->rcode = NOERROR; return (Finish); } - *cpp += n; - *buflenp -= n; - *msglenp += n; - hp->nscount = htons((u_int16_t)count); } #endif hp->rcode = NXDOMAIN; @@ -683,6 +684,14 @@ try_again: #ifdef NCACHE if (hp->rcode == NOERROR_NODATA) { hp->rcode = NOERROR; +#ifdef RETURNSOA + if (count) { + *cpp += n; + *buflenp -= n; + *msglenp += n; + hp->nscount = htons(count); + } +#endif founddata = 1; return (Finish); } @@ -746,7 +755,7 @@ try_again: return (Finish); #endif -fetchns: + fetchns: /* * If we're already out of room in the response, we're done. */ @@ -758,9 +767,7 @@ fetchns: * section or record the address for forwarding the query * (recursion desired). */ -#ifdef DATUMREFCNT free_nsp(nsp); -#endif nsp[0] = NULL; count = 0; switch (findns(&np, class, nsp, &count, 0)) { @@ -772,11 +779,7 @@ fetchns: dname, hp->rcode)); if (class != C_ANY) { hp->aa = 1; - /* XXX: should return SOA if founddata == 0, - * but old named's are confused by an SOA - * in the auth. section if there's no error. - */ - if (foundname == 0 && np) { + if (np && (!foundname || !founddata)) { n = doaddauth(hp, *cpp, *buflenp, np, nsp[0]); *cpp += n; *buflenp -= n; @@ -784,9 +787,7 @@ fetchns: } else if (ntohs(hp->ancount) != 0) { /* don't add NS records for NOERROR NODATA as some servers can get confused */ -#ifdef DATUMREFCNT free_nsp(nsp); -#endif switch (findns(&np, class, nsp, &count, 1)) { case NXDOMAIN: case SERVFAIL: @@ -811,18 +812,14 @@ fetchns: #endif /*ADDAUTH*/ } } -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return (Finish); case SERVFAIL: /* We're authoritative but the zone isn't loaded. */ if (!founddata && !(forward_only && fwdtab)) { hp->rcode = SERVFAIL; -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return (Finish); } } @@ -850,9 +847,7 @@ fetchns: *buflenp -= n; hp->nscount = htons((u_int16_t)count); } -#ifdef DATUMREFCNT free_nsp(nsp); -#endif /* Our caller will handle the Additional section. */ return (Finish); } @@ -869,9 +864,7 @@ fetchns: if (omsg == (u_char *)NULL) { syslog(LOG_INFO, "ns_req: Out Of Memory"); hp->rcode = SERVFAIL; -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return (Finish); } id = hp->id; @@ -883,14 +876,13 @@ fetchns: if (n < 0) { syslog(LOG_INFO, "res_mkquery(%s) failed", dname); hp->rcode = SERVFAIL; -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return (Finish); } *msglenp = n; } - n = ns_forw(nsp, msg, *msglenp, from, qsp, dfd, &qp, dname, np); + n = ns_forw(nsp, msg, *msglenp, from, qsp, dfd, &qp, + dname, class, type, np); if (n != FW_OK && cname) free(omsg); switch (n) { @@ -906,22 +898,20 @@ fetchns: break; /* Duplicate request dropped */ case FW_NOSERVER: /* - ** Don't go into an infinite loop if - ** the admin gave root NS records in the cache - ** file without giving address records - ** for the root servers. - */ + * Don't go into an infinite loop if + * the admin gave root NS records in the cache + * file without giving address records + * for the root servers. + */ if (np) { if (NAME(*np)[0] == '\0') { syslog(LOG_NOTICE, "ns_req: no address for root server"); hp->rcode = SERVFAIL; -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return (Finish); } -#ifdef VALIDATE +#ifdef VALIDATE /* * we need to kill all the NS records here as * validate will fail as we are talking to the parent @@ -956,14 +946,10 @@ fetchns: case FW_SERVFAIL: do_servfail: hp->rcode = SERVFAIL; -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return (Finish); } -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return (Return); } @@ -1179,6 +1165,7 @@ stale(dp) zp->z_origin); } zp->z_flags &= ~Z_AUTH; + needmaint = 1; return (1); } if (zp->z_lastupdate > tt.tv_sec) { @@ -1188,6 +1175,7 @@ stale(dp) zp->z_origin); } zp->z_flags &= ~Z_AUTH; + needmaint = 1; return (1); } return (0); @@ -1223,6 +1211,7 @@ make_rr(name, dp, buf, buflen, doadd) u_char *cp1, *sp; struct zoneinfo *zp; register int32_t n; + register int16_t type = dp->d_type; register u_int32_t ttl; u_char **edp = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; @@ -1233,7 +1222,7 @@ make_rr(name, dp, buf, buflen, doadd) #ifdef NCACHE if (dp->d_rcode #ifdef RETURNSOA - && dp->d_rcode != NXDOMAIN + && dp->d_size == 0 #endif ) { panic(-1, "make_rr: impossible d_rcode value"); @@ -1268,23 +1257,24 @@ make_rr(name, dp, buf, buflen, doadd) buflen -= RRFIXEDSZ; #if defined(RETURNSOA) && defined(NCACHE) - if (dp->d_rcode == NXDOMAIN) { + if (dp->d_rcode) { name = (char *)dp->d_data; name += strlen(name) +1; name += strlen(name) +1; name += 5 * INT32SZ; + type = T_SOA; } #endif if ((n = dn_comp(name, buf, buflen, dnptrs, edp)) < 0) return (-1); cp = buf + n; buflen -= n; - PUTSHORT((u_int16_t)dp->d_type, cp); + PUTSHORT((u_int16_t)type, cp); PUTSHORT((u_int16_t)dp->d_class, cp); PUTLONG(ttl, cp); sp = cp; cp += INT16SZ; - switch (dp->d_type) { + switch (type) { case T_CNAME: case T_MG: case T_MR: @@ -1306,7 +1296,7 @@ make_rr(name, dp, buf, buflen, doadd) cp += n; if (doadd) addname((char*)dp->d_data, name, - dp->d_type, dp->d_class); + type, dp->d_class); break; case T_SOA: @@ -1317,13 +1307,13 @@ make_rr(name, dp, buf, buflen, doadd) if (n < 0) return (-1); cp += n; - buflen -= dp->d_type == T_SOA ? n + 5 * INT32SZ : n; + buflen -= type == T_SOA ? n + 5 * INT32SZ : n; cp1 += strlen((char *)cp1) + 1; n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp); if (n < 0) return (-1); cp += n; - if (dp->d_type == T_SOA) { + if (type == T_SOA) { cp1 += strlen((char *)cp1) + 1; bcopy(cp1, cp, (n = 5 * INT32SZ)); cp += n; @@ -1332,9 +1322,74 @@ make_rr(name, dp, buf, buflen, doadd) PUTSHORT((u_int16_t)n, sp); break; + case T_NAPTR: + /* cp1 == our data/ cp == data of RR */ + cp1 = dp->d_data; + + if ((buflen -= INT16SZ) < 0) + return (-1); + + /* copy order */ + bcopy(cp1, cp, INT16SZ); + cp += INT16SZ; + cp1 += INT16SZ; + n = (u_int16_t)((cp - sp) - INT16SZ); + dprintf(1, (ddt, "current size n = %u\n", n)); + + /* copy preference */ + bcopy(cp1, cp, INT16SZ); + cp += INT16SZ; + cp1 += INT16SZ; + n = (u_int16_t)((cp - sp) - INT16SZ); + dprintf(1, (ddt, "current size n = %u\n", n)); + + /* Flags */ + n = *cp1++; + dprintf(1, (ddt, "size of n at flags = %d\n", n)); + *cp++ = n; + bcopy(cp1,cp,n); + cp += n; + cp1 += n; + n = (u_int16_t)((cp - sp) - INT16SZ); + dprintf(1, (ddt, "current size n = %u\n", n)); + + /* Service */ + n = *cp1++; + *cp++ = n; + bcopy(cp1,cp,n); + cp += n; + cp1 += n; + n = (u_int16_t)((cp - sp) - INT16SZ); + dprintf(1, (ddt, "current size n = %u\n", n)); + + /* Regexp */ + n = *cp1++; + *cp++ = n; + bcopy(cp1,cp,n); + cp += n; + cp1 += n; + n = (u_int16_t)((cp - sp) - INT16SZ); + dprintf(1, (ddt, "current size n = %u\n", n)); + + /* Replacement */ + dprintf(1, (ddt, "Replacement = %s\n", cp1)); + n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp); + dprintf(1, (ddt, "dn_comp's n = %u\n", n)); + if (n < 0) + return (-1); + cp += n; + + /* save data length */ + n = (u_int16_t)((cp - sp) - INT16SZ); + dprintf(1, (ddt, "saved size n = %u\n", n)); + PUTSHORT((u_int16_t)n, sp); + + break; + case T_MX: case T_AFSDB: case T_RT: + case T_SRV: /* cp1 == our data/ cp == data of RR */ cp1 = dp->d_data; @@ -1346,6 +1401,12 @@ make_rr(name, dp, buf, buflen, doadd) cp += INT16SZ; cp1 += INT16SZ; + if (type == T_SRV) { + bcopy(cp1, cp, INT16SZ*2); + cp += INT16SZ*2; + cp1 += INT16SZ*2; + } + n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp); if (n < 0) return (-1); @@ -1355,7 +1416,7 @@ make_rr(name, dp, buf, buflen, doadd) n = (u_int16_t)((cp - sp) - INT16SZ); PUTSHORT((u_int16_t)n, sp); if (doadd) - addname((char*)cp1, name, dp->d_type, dp->d_class); + addname((char*)cp1, name, type, dp->d_class); break; case T_PX: @@ -1385,6 +1446,39 @@ make_rr(name, dp, buf, buflen, doadd) PUTSHORT((u_int16_t)n, sp); break; + case T_SIG: + /* cp1 == our data; cp == data of target RR */ + cp1 = dp->d_data; + + /* first just copy over the type_covered, algorithm, */ + /* labels, orig ttl, two timestamps, and the footprint */ + if ((dp->d_size - 18) > buflen) + return (-1); /* out of room! */ + bcopy( cp1, cp, 18 ); + cp += 18; + cp1 += 18; + buflen -= 18; + + /* then the signer's name */ + n = dn_comp((char *)cp1, cp, buflen, NULL, NULL); + if (n < 0) + return (-1); + cp += n; + buflen -= n; + cp1 += strlen((char*)cp1)+1; + + /* finally, we copy over the variable-length signature */ + n = dp->d_size - (u_int16_t)((cp1 - dp->d_data)); + if (n > buflen) + return (-1); /* out of room! */ + bcopy(cp1, cp, n); + cp += n; + + /* save data length & return */ + n = (u_int16_t)((cp - sp) - INT16SZ); + PUTSHORT((u_int16_t)n, sp); + break; + default: if (dp->d_size > buflen) return (-1); @@ -1458,8 +1552,7 @@ doaddinfo(hp, msg, msglen) count = 0; cp = msg; for (ap = addinfo; --addcount >= 0; ap++) { - int foundstale = 0, - foundany = 0, + int foundany = 0, foundcname = 0, save_count = count, save_msglen = msglen; @@ -1473,6 +1566,7 @@ doaddinfo(hp, msg, msglen) goto next_rr; dprintf(3, (ddt, "found it\n")); /* look for the data */ + delete_stale(np); for (dp = np->n_data; dp != NULL; dp = dp->d_next) { #ifdef NCACHE if (dp->d_rcode) @@ -1490,17 +1584,6 @@ doaddinfo(hp, msg, msglen) continue; } foundany++; - if (stale(dp)) { - foundstale++; - dprintf(1, (ddt, - "doaddinfo: stale entry '%s'%s\n", - NAME(*np), - (dp->d_flags&DB_F_HINT) - ? " hint" - : "" - )); - continue; - } /* * Should be smart and eliminate duplicate * data here. XXX @@ -1532,11 +1615,7 @@ doaddinfo(hp, msg, msglen) count++; } next_rr: - if (foundstale) { - /* Cache invalidate the address RR's */ - delete_all(np, (int)ap->a_class, T_A); - } - if (!NoFetchGlue && !foundcname && (foundstale || !foundany)) { + if (!NoFetchGlue && !foundcname && !foundany) { /* ask a real server for this info */ (void) sysquery(ap->a_dname, (int)ap->a_class, T_A, NULL, 0, QUERY); @@ -1730,6 +1809,16 @@ doaxfr(np, rfp, top, class) */ if (dp->d_type == T_SOA || dp->d_type == T_NS) continue; + +#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 */ + if (dp->d_zone == 0 || stale(dp)) continue; #ifdef NCACHE @@ -1791,228 +1880,6 @@ doaxfr(np, rfp, top, class) dprintf(1, (ddt, "exit doaxfr()\n")); } -#ifdef ALLOW_UPDATES -/* - * Called by UPDATE{A,D,DA,M,MA} to initiate a dynamic update. If this is the - * primary server for the zone being updated, we update the zone's serial - * number and then call doupdate directly. If this is a secondary, we just - * forward the update; this way, if the primary update fails (e.g., if the - * primary is unavailable), we don't update the secondary; if the primary - * update suceeds, ns_resp will get called with the response (when it comes - * in), and then update the secondary's copy. - */ -static int -InitDynUpdate(hp, msg, msglen, startcp, from, qsp, dfd) - register HEADER *hp; - char *msg; - int msglen; - u_char *startcp; - struct sockaddr_in *from; - struct qstream *qsp; - int dfd; -{ - struct databuf *nsp[NSMAX]; - struct zoneinfo *zp; - char dnbuf[MAXDNAME]; - struct hashbuf *htp = hashtab; /* lookup relative to root */ - struct namebuf *np; - struct databuf *olddp, *newdp, *dp; - struct databuf **nspp; - char *fname; - register u_char *cp = startcp; - u_int16_t class, type; - int n, size, zonenum; - char ZoneName[MAXDNAME], *znp; - -#ifdef DATUMREFCNT - nsp[0] = NULL; -#endif - if ((n = dn_expand(msg, msg + msglen, cp, dnbuf, sizeof(dnbuf))) < 0) { - dprintf(1, (ddt,"FORMERR InitDynUpdate expand name failed\n")); - hp->rcode = FORMERR; - return (FORMERR); - } - cp += n; - GETSHORT(type, cp); - if (type == T_SOA) { /* T_SOA updates not allowed */ - hp->rcode = REFUSED; - dprintf(1, (ddt, "InitDynUpdate: REFUSED - SOA update\n")); - return (REFUSED); - } - GETSHORT(class, cp); - cp += INT32SZ; - GETSHORT(size, cp); -/****XXX - need bounds checking here ****/ - cp += size; - - if ((zonenum = findzone(dnbuf, class)) == 0) { /* zone not found */ - hp->rcode = NXDOMAIN; - return (NXDOMAIN); - } - zp = &zones[zonenum]; - - /* Disallow updates for which we aren't authoratative. Note: the - following test doesn't work right: If it's for a non-local zone, - we will think it's a primary but be unable to lookup the namebuf, - thus returning 'NXDOMAIN' */ - if (zp->z_type != Z_PRIMARY && zp->z_type != Z_SECONDARY) { - hp->rcode = REFUSED; - dprintf(1, (ddt, - "InitDynUpdate: REFUSED - non-{primary,secondary} update\n")); - return (REFUSED); - } - if (!(zp->z_flags & Z_DYNAMIC)) { - hp->rcode = REFUSED; - dprintf(1, (ddt, - "InitDynUpdate: REFUSED - dynamic flag not set for zone\n")); - return (REFUSED); - } - - /* - * Lookup the zone namebuf. Lookup "xyz" not "xyz.", since - * otherwise the lookup fails, because '.' may have a nil n_hash - * associated with it. - */ - strcpy(ZoneName, zp->z_origin); - znp = &ZoneName[strlen(ZoneName) - 1]; - if (*znp == '.') - *znp = NULL; - np = nlookup(ZoneName, &htp, &fname, 0); - if ((np == NULL) || (fname != ZoneName)) { - syslog(LOG_ERR, "InitDynUpdate: lookup failed on zone (%s)\n", - ZoneName); - hp->rcode = NXDOMAIN; - return (NXDOMAIN); - } - - /* - * If this is the primary copy increment the serial number. Don't - * increment the serial number if this is a secondary; this way, if 2 - * different secondaries both update the primary, they will both have - * lower serial numbers than the primary has, and hence eventually - * refresh and get all updates and become consistent. - * - * Note that the serial number must be incremented in both the zone - * data structure and the zone's namebuf. - */ - switch (zp->z_type) { - case Z_SECONDARY: /* forward update to primary */ - nspp = nsp; - dp = np->n_data; - while (dp != NULL) { - if (match(dp, class, T_NS)) { - if (nspp < &nsp[NSMAX-1]) { - *nspp++ = dp; -#ifdef DATUMREFCNT - dp->d_rcnt++; -#endif - } else - break; - } - dp = dp->d_next; - } - *nspp = NULL; /* Delimiter */ - if (ns_forw(nsp, msg, msglen, from, qsp, dfd, NULL, dnbuf, np) - < - 0) { - hp->rcode = SERVFAIL; -#ifdef DATUMREFCNT - free_nsp(nsp); -#endif - return (SERVFAIL); - } -#ifdef DATUMREFCNT - free_nsp(nsp); -#endif - return (FORWARDED); - - case Z_PRIMARY: - zp->z_serial++; - /* Find the SOA record */ - for (olddp = np->n_data; olddp != NULL; olddp = olddp->d_next) - if (match(olddp, class, T_SOA)) - break; - if (olddp == NULL) { - syslog(LOG_NOTICE, - "InitDynUpdate: Couldn't find SOA RR for '%s'\n", - ZoneName); - hp->rcode = NXDOMAIN; -#ifdef DATUMREFCNT - free_nsp(nsp); -#endif - return (NXDOMAIN); - } - newdp = savedata(olddp->d_class, olddp->d_type, olddp->d_ttl, - olddp->d_data, olddp->d_size); - newdp->d_zone = olddp->d_zone; - newdp->d_cred = DB_C_AUTH; /* XXX - it may not be so */ - newdp->d_clev = db_getclev(zp->z_origin); - cp = (u_char *)newdp->d_data; - cp += strlen(cp) + 1; /* skip origin string */ - cp += strlen(cp) + 1; /* skip in-charge string */ - putlong((u_int32_t)(zp->z_serial), cp); - dprintf(4, (ddt, "after stuffing data into newdp:\n")); -#ifdef DEBUG - if (debug >= 4) - printSOAdata(newdp); -#endif - - if ((n = db_update(ZoneName, olddp, newdp, DB_DELETE, - hashtab)) != NOERROR) { /* XXX */ - dprintf(1, (ddt, - "InitDynUpdate: SOA update failed\n")); - hp->rcode = NOCHANGE; - free((char*) dp); -#ifdef DATUMREFCNT - free_nsp(nsp); -#endif - return (NOCHANGE); - } - - /* Now update the RR itself */ - /* XXX - DB_C_AUTH may be wrong */ - if (doupdate(msg, msglen, msg + HFIXEDSZ, zonenum, - (struct databuf *)0, DB_NODATA, DB_C_AUTH) < 0) { - dprintf(1, (ddt, "InitDynUpdate: doupdate failed\n")); - /* doupdate fills in rcode */ -#ifdef DATUMREFCNT - free_nsp(nsp); -#endif - return (hp->rcode); - } - zp->z_flags |= Z_CHANGED; -#ifdef DATUMREFCNT - free_nsp(nsp); -#endif - return (NOERROR); - } -} - -#ifdef DEBUG -/* - * Print the contents of the data in databuf pointed to by dp for an SOA record - */ -static void -printSOAdata(dp) - struct databuf *dp; -{ - register u_char *cp; - - if (!debug) - return; /* Otherwise fprintf to ddt will bomb */ - cp = (u_char *)dp->d_data; - fprintf(ddt, "printSOAdata(%#lx): origin(%#lx)='%s'\n", - (u_long)dp, (u_long)cp, cp); - cp += strlen(cp) + 1; /* skip origin string */ - fprintf(ddt, "printSOAdata: in-charge(%#lx)='%s'\n", - (u_long)cp, cp); - cp += strlen(cp) + 1; /* skip in-charge string */ - fprintf(ddt, "printSOAdata: serial(%lx)=%lu\n", - (u_long)cp, (u_long)_getlong(cp)); -} -#endif -#endif - static void startxfr(qsp, np, soa, soalen, class, dname) struct qstream *qsp; @@ -2159,7 +2026,6 @@ free_addinfo() { addcount = 0; } -#ifdef DATUMREFCNT void free_nsp(nsp) struct databuf **nsp; @@ -2171,9 +2037,20 @@ free_nsp(nsp) } else { dprintf(3, (ddt, "free_nsp: %s rcnt %d delayed\n", (*nsp)->d_data, (*nsp)->d_rcnt)); - free(*nsp); /* delayed free */ + db_free(*nsp); /* delayed free */ } *nsp++ = NULL; } } -#endif + +static void +copyCharString(dst, src) + u_char **dst; + const char *src; +{ + size_t len = strlen(src) & 0xff; + + *(*dst)++ = (u_char) len; + memcpy(*dst, src, len); + *dst += len; +} diff --git a/contrib/bind/named/ns_resp.c b/contrib/bind/named/ns_resp.c index f64306e..71b60f9 100644 --- a/contrib/bind/named/ns_resp.c +++ b/contrib/bind/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.27 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: ns_resp.c,v 8.37 1996/12/02 09:17:21 vixie Exp $"; #endif /* not lint */ /* @@ -55,6 +55,28 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.27 1996/08/05 08:31:30 vixie Exp $"; * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * - + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. * --Copyright-- */ @@ -72,9 +94,6 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.27 1996/08/05 08:31:30 vixie Exp $"; #include "named.h" -static void check_root __P((void)), - check_ns __P((void)); - static u_int8_t norootlogged[MAXCLASS]; /* XXX- should be a bitmap */ static const char skipnameFailedAnswer[] = "skipname failed in answer", @@ -92,8 +111,34 @@ static const char skipnameFailedAnswer[] = "skipname failed in answer", dlenUnderrunAnswer[] = "dlen underrun in answer", outofDataFinal[] = "out of data in final pass", outofDataAFinal[] = "out of data after final pass", - badNameFound[] = "found an invalid domain name"; + badNameFound[] = "found an invalid domain name", + wrongQuestion[] = "answer to wrong question", + danglingCname[] = "dangling CNAME pointer"; + +struct db_list { + struct db_list *db_next; + struct databuf *db_dp; +}; + +struct flush_set { + char * fs_name; + int fs_type; + int fs_class; + u_int fs_cred; + struct db_list *fs_list; +}; + +static void rrsetadd __P((struct flush_set *, char *, + struct databuf *)), + rrsetupdate __P((struct flush_set *, int flags)), + flushrrset __P((struct flush_set *)); +static int rrsetcmp __P((char *, struct db_list *)), + check_root __P((void)), + check_ns __P((void)), + rrextract __P((u_char *, int, u_char *, + struct databuf **, char *, int)); +#ifdef LAME_LOGGING static char * learntFrom(qp, server) struct qinfo *qp; @@ -102,8 +147,10 @@ learntFrom(qp, server) static char *buf = NULL; char *a, *ns, *na; struct databuf *db; +#ifdef STATS char nsbuf[20]; char abuf[20]; +#endif int i; if (buf) { @@ -167,6 +214,7 @@ learntFrom(qp, server) sprintf(buf, LEARNTFROM, na, a, ns); return (buf); } +#endif /*LAME_LOGGING*/ void ns_resp(msg, msglen) @@ -179,24 +227,20 @@ ns_resp(msg, msglen) register struct databuf *ns, *ns2; register u_char *cp; u_char *eom = msg + msglen; - register u_char *tempcp; -#ifdef VALIDATE - struct sockaddr_in *server = &from_addr; - struct { char *name; int type, class; u_int cred; } defer_rm[99]; - int defer_rm_count; -#endif + struct flush_set *flushset; struct sockaddr_in *nsa; struct databuf *nsp[NSMAX]; int i, c, n, qdcount, ancount, aucount, nscount, arcount; int qtype, qclass, dbflags; int restart; /* flag for processing cname response */ int validanswer; - int cname; + int cname, lastwascname; int count, founddata, foundname; int buflen; int newmsglen; - char name[MAXDNAME], qname[MAXDNAME], msgbuf[MAXDNAME*2]; - char *dname; + char name[MAXDNAME], qname[MAXDNAME], aname[MAXDNAME]; + char msgbuf[MAXDNAME]; + char *dname, tmpdomain[MAXDNAME]; const char *fname; const char *formerrmsg = "brain damage"; u_char newmsg[PACKETSZ]; @@ -208,9 +252,7 @@ ns_resp(msg, msglen) struct fwdinfo *fwd; nameserIncr(from_addr.sin_addr, nssRcvdR); -#ifdef DATUMREFCNT nsp[0] = NULL; -#endif hp = (HEADER *) msg; if ((qp = qfindid(hp->id)) == NULL ) { dprintf(1, (ddt, "DUP? dropped (id %d)\n", ntohs(hp->id))); @@ -248,7 +290,8 @@ ns_resp(msg, msglen) GETSHORT(qtype, cp); GETSHORT(qclass, cp); if (!ns_nameok(qname, qclass, response_trans, - ns_ownercontext(qtype, response_trans))) { + ns_ownercontext(qtype, response_trans), + qname, from_addr.sin_addr)) { formerrmsg = badNameFound; goto formerr; } @@ -265,11 +308,16 @@ ns_resp(msg, msglen) formerrmsg = msgbuf; goto formerr; } + if (strcasecmp(qp->q_name, qname) != 0 || + qp->q_class != qclass || + qp->q_type != qtype) { + formerrmsg = wrongQuestion; + goto formerr; + } } else { - /* Pedantic. */ - qname[0] = '\0'; - qtype = 0; - qclass = 0; + strcpy(qname, qp->q_name); + qclass = qp->q_class; + qtype = qp->q_type; } /* cp now points after the query section. */ @@ -325,25 +373,6 @@ ns_resp(msg, msglen) goto formerr; } -#ifdef ALLOW_UPDATES - if ( (hp->rcode == NOERROR) && - (hp->opcode == UPDATEA || hp->opcode == UPDATED || - hp->opcode == UPDATEDA || hp->opcode == UPDATEM || - hp->opcode == UPDATEMA) ) { - /* - * Update the secondary's copy, now that the primary - * successfully completed the update. Zone doesn't matter - * for dyn. update -- doupdate calls findzone to find it - */ - /* XXX - DB_C_AUTH may be wrong */ - (void) doupdate(qp->q_msg, qp->q_msglen, qp->q_msg + HFIXEDSZ, - 0, (struct databuf *)0, 0, DB_C_AUTH); - dprintf(3, (ddt, "resp: leaving, UPDATE*\n")); - /* return code filled in by doupdate */ - goto return_msg; - } -#endif /* ALLOW_UPDATES */ - /* * Determine if the response came from a forwarder. Packets from * anyplace not listed as a forwarder or as a server to whom we @@ -434,19 +463,20 @@ ns_resp(msg, msglen) * Don't update nstime if this doesn't look * like an address databuf now. XXX */ - if (ns && (ns->d_type==T_A) && (ns->d_class==qs->ns->d_class)){ + if (ns && + ns->d_type == T_A && + ns->d_class == qs->ns->d_class) { + u_long t; + if (ns->d_nstime == 0) - ns->d_nstime = (u_int32_t)rtrip; + t = rtrip; else - ns->d_nstime = (u_int32_t) - (ns->d_nstime * ALPHA - + - (1-ALPHA) * (u_int32_t)rtrip); - /* prevent floating point overflow, - * limit to 1000 sec - */ - if (ns->d_nstime > 1000000) - ns->d_nstime = 1000000; + t = ns->d_nstime * ALPHA + + + (1 - ALPHA) * rtrip; + if (t > 65535) + t = 65535; + ns->d_nstime = (u_int16_t)t; } /* @@ -473,6 +503,8 @@ ns_resp(msg, msglen) for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; n++, qs++) { + u_long t; + ns2 = qs->nsdata; if ((!ns2) || (ns2 == ns)) continue; @@ -481,15 +513,16 @@ ns_resp(msg, msglen) continue; if (qs->stime.tv_sec) { if (ns2->d_nstime == 0) - ns2->d_nstime = (u_int32_t)(rtrip * BETA); + t = (rtrip * BETA); else - ns2->d_nstime = (u_int32_t)( - ns2->d_nstime * BETA + (1-ALPHA) * rtrip - ); - if (ns2->d_nstime > 1000000) - ns2->d_nstime = 1000000; + t = ns2->d_nstime * BETA + + + (1 - ALPHA) * rtrip; } else - ns2->d_nstime = (u_int32_t)(ns2->d_nstime * GAMMA); + t = ns2->d_nstime * GAMMA; + if (t > 65535) + t = 65535; + ns2->d_nstime = (u_int16_t)t; dprintf(2, (ddt, "NS #%d %s rtt now %d\n", n, sin_ntoa(&qs->ns_addr), ns2->d_nstime)); @@ -509,10 +542,9 @@ ns_resp(msg, msglen) #ifdef LAME_DELEGATION /* - * Non-authoritative, no answer, no error + * Non-authoritative, no answer, no error, with referral. */ - if (qdcount == 1 && hp->rcode == NOERROR && !hp->aa && ancount == 0 - && aucount > 0 + if (hp->rcode == NOERROR && !hp->aa && ancount == 0 && aucount > 0 #ifdef BIND_NOTIFY && hp->opcode != NS_NOTIFY_OP #endif @@ -545,7 +577,8 @@ ns_resp(msg, msglen) goto formerr; } if (!ns_nameok(name, class, response_trans, - ns_ownercontext(type, response_trans))) { + ns_ownercontext(type, response_trans), + name, from_addr.sin_addr)) { formerrmsg = badNameFound; goto formerr; } @@ -613,7 +646,8 @@ ns_resp(msg, msglen) goto formerr; } if (!ns_nameok(name, class, response_trans, - ns_ownercontext(type, response_trans))){ + ns_ownercontext(type, response_trans), + name, from_addr.sin_addr)) { formerrmsg = badNameFound; goto formerr; } @@ -717,168 +751,90 @@ ns_resp(msg, msglen) validanswer = 0; nscount = 0; cname = 0; -#ifdef VALIDATE - defer_rm_count = 0; -#endif + lastwascname = 0; + strcpy(aname, qname); + + if (count) { + /* allocate 1 extra record for end of set detection */ + flushset = (struct flush_set *) + calloc(count+1, sizeof(struct flush_set)); + if (!flushset) + panic(-1, "flushset: out of memory"); + } else + flushset = NULL; for (i = 0; i < count; i++) { - struct databuf *ns3 = NULL; - u_char cred; - int VCode; - u_int16_t type, class; + struct databuf *dp; + int type; if (cp >= eom) { formerrmsg = outofDataFinal; goto formerr; } - - /* Get the DNAME. */ - tempcp = cp; - n = dn_expand(msg, eom, tempcp, name, sizeof name); - if (n <= 0) { + n = rrextract(msg, msglen, cp, &dp, name, sizeof name); + if (n < 0) { formerrmsg = outofDataFinal; goto formerr; } - tempcp += n; - GETSHORT(type, tempcp); - GETSHORT(class, tempcp); - if (!ns_nameok(name, class, response_trans, - ns_ownercontext(type, response_trans))) { - formerrmsg = badNameFound; - goto formerr; - } - - /* - * See if there are any NS RRs in the authority section - * for the negative caching logic below. We'll count - * these before validation. - */ - if (type == T_NS && i >= ancount && i < ancount + aucount) - nscount++; + cp += n; + if (!dp) + continue; + type = dp->d_type; + if (i < ancount) { + /* Answer section. */ + if (strcasecmp(name, aname) != 0) { + syslog(LOG_DEBUG, "wrong ans. name (%s != %s)", + name, aname); + db_free(dp); + continue; + } + if (type == T_CNAME && + qtype != T_CNAME && qtype != T_ANY) { + strcpy(aname, (char *)dp->d_data); + cname = 1; + lastwascname = 1; + } else { + validanswer = 1; + lastwascname = 0; + } - /* Decide what credibility this ought to have in the cache. */ - if (i < ancount) - cred = (hp->aa && !strcasecmp(name, qname)) + dp->d_cred = (hp->aa && !strcasecmp(name, qname)) ? DB_C_AUTH : DB_C_ANSWER; - else - cred = (qp->q_flags & Q_PRIMING) - ? DB_C_ANSWER - : DB_C_ADDITIONAL; -#ifdef VALIDATE - if ((n = dovalidate(msg, msglen, cp, 0, - dbflags, qp->q_domain, server, - &VCode)) < 0) { - formerrmsg = outofDataFinal; - goto formerr; - } - if (VCode == INVALID && !(qp->q_flags & Q_SYSTEM)) { - /* - * If anything in the answer section fails - * validation this means that it definitely did - * not reside below the domain owning the NS RRs - * that we sent the query to. This means either - * that it was the target of a CNAME early in the - * response, in which case we will treat this the - * same as if the answer was incomplete and restart - * the query on the CNAME target, or that someone - * was trying to spoof us. - */ - if (i < ancount) - restart = 1; - /* - * Restart or no, if we're here it means we are not - * going to cache this RR. That being the case, we - * must burn down whatever partial RRset we've got - * in the cache now, lest we inadvertently answer - * with a truncated RRset in some future section. - */ - for (c = 0; c < defer_rm_count; c++) - if (!strcasecmp(defer_rm[c].name, name) && - defer_rm[c].class == class && - defer_rm[c].type == type) - break; - if (c < defer_rm_count) { - if (defer_rm[c].cred < cred) - defer_rm[c].cred = cred; - } else { - if (defer_rm_count+1 >= - (sizeof defer_rm / sizeof defer_rm[0])) { - formerrmsg = "too many RRs in ns_resp"; - goto formerr; - } - defer_rm[defer_rm_count].name = savestr(name); - defer_rm[defer_rm_count].type = type; - defer_rm[defer_rm_count].class = class; - defer_rm[defer_rm_count].cred = cred; - defer_rm_count++; - } } else { -#endif - if (i < ancount) { - /* - * If there are any non-CNAME RRs (or - * CNAME RRs if they are an acceptable) - * then the query is complete unless an - * intermediate CNAME didn't pass validation, - * but that's OK. - */ - if (type != T_CNAME || qtype == T_CNAME || - qtype == T_ANY) - validanswer = 1; - else - cname = 1; - } - n = doupdate(msg, msglen, cp, 0, &ns3, dbflags, cred); -#ifdef VALIDATE - } -#endif - if (n < 0) { - dprintf(1, (ddt, "resp: leaving, doupdate failed\n")); - formerrmsg = outofDataFinal; - goto formerr; - } - cp += n; - } -#ifdef VALIDATE - if (defer_rm_count > 0) { - for (i = 0; i < defer_rm_count; i++) { - register struct databuf *db = NULL; - - fname = ""; - htp = hashtab; /* lookup relative to root */ - np = nlookup(defer_rm[i].name, &htp, &fname, 0); - if (np && fname == defer_rm[i].name && - defer_rm[i].class != C_ANY && - defer_rm[i].type != T_ANY) { - /* - * If doupdate() wouldn't have cached this - * RR anyway, there's no need to delete it. - */ - for (db = np->n_data; - db != NULL; - db = db->d_next) { - if (!db->d_zone && - match(db, defer_rm[i].class, - defer_rm[i].type) && - db->d_cred >= defer_rm[i].cred) { - break; - } + /* After answer section. */ + if (lastwascname) { + db_free(dp); + break; + } + if (i < ancount + aucount && type == T_NS) { + /* Authority section. */ + if (!samedomain(aname, name) || + (!cname && !samedomain(name, qp->q_domain)) + ) { + syslog(LOG_DEBUG, + "bad referral (%s !< %s)", + name, qp->q_domain); + db_free(dp); + continue; } - if (db == NULL) - delete_all(np, defer_rm[i].class, - defer_rm[i].type); - /* XXX: should delete name node if empty? */ + nscount++; } - syslog(LOG_DEBUG, "defer_rm [%s %s %s] (np%#x, db%#x)", - defer_rm[i].name, - p_class(defer_rm[i].class), - p_type(defer_rm[i].type), - np, db); - free(defer_rm[i].name); + dp->d_cred = (qp->q_flags & Q_PRIMING) + ? DB_C_ANSWER + : DB_C_ADDITIONAL; } + rrsetadd(flushset, name, dp); } -#endif + if (flushset) { + rrsetupdate(flushset, dbflags); + for (i = 0; i < count; i++) + if (flushset[i].fs_name) + free(flushset[i].fs_name); + free((char*)flushset); + } + if (lastwascname) + syslog(LOG_DEBUG, "%s (%s)", danglingCname, aname); if (cp > eom) { formerrmsg = outofDataAFinal; @@ -886,8 +842,22 @@ ns_resp(msg, msglen) } if ((qp->q_flags & Q_SYSTEM) && ancount) { - if (qp->q_flags & Q_PRIMING) - check_root(); + 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 (qp->q_addr[i].ns_addr.sin_addr.s_addr + == from_addr.sin_addr.s_addr) + qp->q_addr[i].nretry = MAXRETRY; + /* XXX - doesn't handle responses sent from + * the wronginterface on a multihomed server + */ + if (qp->q_fwd || + qp->q_addr[qp->q_curaddr].ns_addr.sin_addr.s_addr + == from_addr.sin_addr.s_addr) + retry(qp); + return; + } dprintf(3, (ddt, "resp: leaving, SYSQUERY ancount %d\n", ancount)); #ifdef BIND_NOTIFY @@ -949,12 +919,6 @@ ns_resp(msg, msglen) (hp->aa || fwd || qclass == C_ANY)) { /* we have an authoritative NO */ dprintf(3, (ddt, "resp: leaving auth NO\n")); - if (qp->q_cmsglen) { - /* XXX - what about additional CNAMEs in the chain? */ - msg = qp->q_cmsg; - msglen = qp->q_cmsglen; - hp = (HEADER *)msg; - } #ifdef NCACHE /* answer was NO */ if (hp->aa && @@ -962,6 +926,12 @@ ns_resp(msg, msglen) cache_n_resp(msg, msglen); } #endif /*NCACHE*/ + if (qp->q_cmsglen) { + /* XXX - what about additional CNAMEs in the chain? */ + msg = qp->q_cmsg; + msglen = qp->q_cmsglen; + hp = (HEADER *)msg; + } goto return_msg; } @@ -995,6 +965,7 @@ ns_resp(msg, msglen) hp->ancount = htons(0); hp->nscount = htons(0); hp->arcount = htons(0); + hp->rcode = NOERROR; dnptrs[0] = newmsg; dnptrs[1] = NULL; cp = newmsg + HFIXEDSZ; @@ -1037,6 +1008,20 @@ ns_resp(msg, msglen) n = finddata(np, qclass, qtype, hp, &dname, &buflen, &count); if (n == 0) goto fetch_ns; /* NO data available */ +#ifdef NCACHE + if (hp->rcode) { + if (hp->rcode == NOERROR_NODATA) + hp->rcode = NOERROR; +#ifdef RETURNSOA + if (count) { + cp += n; + buflen -= n; + hp->nscount = htons((u_int16_t)count); + } +#endif + goto return_newmsg; + } +#endif cp += n; buflen -= n; hp->ancount = htons(ntohs(hp->ancount) + (u_int16_t)count); @@ -1060,9 +1045,7 @@ ns_resp(msg, msglen) * section or record the address for forwarding the query * (recursion desired). */ -#ifdef DATUMREFCNT free_nsp(nsp); -#endif switch (findns(&np, qclass, nsp, &count, 0)) { case NXDOMAIN: /* shouldn't happen */ dprintf(3, (ddt, "req: leaving (%s, rcode %d)\n", @@ -1071,11 +1054,7 @@ ns_resp(msg, msglen) hp->rcode = NXDOMAIN; if (qclass != C_ANY) { hp->aa = 1; - /* XXX: should return SOA if founddata == 0, - * but old named's are confused by an SOA - * in the auth. section if there's no error. - */ - if (foundname == 0 && np) { + if (np && (!foundname || !founddata)) { n = doaddauth(hp, cp, buflen, np, nsp[0]); cp += n; buflen -= n; @@ -1114,45 +1093,15 @@ ns_resp(msg, msglen) } /* Reset the query control structure */ -#ifdef DATUMREFCNT - /* XXX - this code should be shared with qfree()'s similar logic. */ - for (i = 0; (u_int)i < qp->q_naddr; i++) { - static const char freed[] = "freed", busy[] = "busy"; - const char *result; - - if (qp->q_addr[i].ns != NULL) { - if ((--(qp->q_addr[i].ns->d_rcnt))) - result = busy; - else - result = freed; - dprintf(1, (ddt, "ns_resp: ns %s rcnt %d (%s)\n", - qp->q_addr[i].ns->d_data, - qp->q_addr[i].ns->d_rcnt, - result)); - if (result == freed) - free((char*)qp->q_addr[i].ns); - } - if (qp->q_addr[i].nsdata != NULL) { - if ((--(qp->q_addr[i].nsdata->d_rcnt))) - result = busy; - else - result = freed; - dprintf(1, (ddt, - "ns_resp: nsdata %08.8X rcnt %d (%s)\n", - *(int32_t *)(qp->q_addr[i].nsdata->d_data), - qp->q_addr[i].nsdata->d_rcnt, - result)); - if (result == freed) - free((char*)qp->q_addr[i].nsdata); - } - } -#endif + + nsfree(qp, "ns_resp"); qp->q_naddr = 0; qp->q_curaddr = 0; qp->q_fwd = fwdtab; -#if defined(LAME_DELEGATION) || defined(VALIDATE) - getname(np, qp->q_domain, sizeof(qp->q_domain)); -#endif /* LAME_DELEGATION */ + + getname(np, tmpdomain, sizeof tmpdomain); + qp->q_domain = strdup(tmpdomain); + if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) { if (n < 0) { dprintf(3, (ddt, "resp: nslookup reports danger\n")); @@ -1243,9 +1192,7 @@ ns_resp(msg, msglen) #endif nameserIncr(qp->q_from.sin_addr, nssRcvdFwdR); dprintf(3, (ddt, "resp: Query sent.\n")); -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return; formerr: @@ -1256,9 +1203,7 @@ ns_resp(msg, msglen) #ifdef XSTATS nameserIncr(from_addr.sin_addr, nssSentFErr); #endif -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return; return_msg: @@ -1273,9 +1218,7 @@ ns_resp(msg, msglen) hp->ra = (NoRecurse == 0); (void) send_msg(msg, msglen, qp); qremove(qp); -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return; return_newmsg: @@ -1296,9 +1239,7 @@ ns_resp(msg, msglen) hp->ra = (NoRecurse == 0); (void) send_msg(newmsg, cp - newmsg, qp); qremove(qp); -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return; servfail: @@ -1315,42 +1256,31 @@ ns_resp(msg, msglen) qp); timeout: qremove(qp); -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return; } -/* - * Decode the resource record 'rrp' and update the database. - * If savens is non-nil, record pointer for forwarding queries a second time. - */ -int -doupdate(msg, msglen, rrp, zone, savens, flags, cred) - u_char *msg, *rrp; - struct databuf **savens; - int msglen, zone, flags; - u_int cred; +static int +rrextract(msg, msglen, rrp, dpp, dname, namelen) + u_char *msg; + int msglen; + u_char *rrp; + struct databuf **dpp; + char *dname; + int namelen; { register u_char *cp; register int n; int class, type, dlen, n1; u_int32_t ttl; - struct databuf *dp; - char dname[MAXDNAME]; u_char *cp1; u_char data[BUFSIZ]; register HEADER *hp = (HEADER *)msg; enum context context; -#ifdef ALLOW_UPDATES - int zonenum; -#endif - - dprintf(3, (ddt, "doupdate(zone %d, savens %#lx, flags %#lx)\n", - zone, (u_long)savens, (u_long)flags)); + *dpp = NULL; cp = rrp; - if ((n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname)) < 0) { + if ((n = dn_expand(msg, msg + msglen, cp, dname, namelen)) < 0) { hp->rcode = FORMERR; return (-1); } @@ -1360,15 +1290,29 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) GETLONG(ttl, cp); GETSHORT(dlen, cp); if (!ns_nameok(dname, class, response_trans, - ns_ownercontext(type, response_trans))) { + ns_ownercontext(type, response_trans), + dname, from_addr.sin_addr)) { hp->rcode = FORMERR; return (-1); } - dprintf(3, (ddt, "doupdate: dname %s type %d class %d ttl %d\n", + dprintf(3, (ddt, "rrextract: dname %s type %d class %d ttl %d\n", dname, type, class, ttl)); /* * Convert the resource record data into the internal * database format. + * + * On entry to the switch: + * CP points to the RDATA section of the wire-format RR. + * DLEN is its length. + * The memory area at DATA is available for processing. + * + * On exit from the switch: + * CP has been incremented past the RR. + * CP1 points to the RDATA section of the database-format RR. + * N contains the length of the RDATA section of the dbase-format RR. + * + * The new data at CP1 for length N will be copied into the database, + * so it need not be in any particular storage location. */ switch (type) { case T_A: @@ -1388,6 +1332,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) case T_NSAP: case T_AAAA: case T_LOC: + case T_KEY: #ifdef ALLOW_T_UNSPEC case T_UNSPEC: #endif @@ -1409,9 +1354,8 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) return (-1); } if (!ns_nameok((char *)data, class, response_trans, - (type == T_PTR) - ? ns_ptrcontext(dname) - : domain_ctx)) { + type == T_PTR ?ns_ptrcontext(dname) :domain_ctx, + dname, from_addr.sin_addr)) { hp->rcode = FORMERR; return (-1); } @@ -1434,7 +1378,8 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) hp->rcode = FORMERR; return (-1); } - if (!ns_nameok((char *)data, class, response_trans, context)) { + if (!ns_nameok((char *)data, class, response_trans, context, + dname, from_addr.sin_addr)) { hp->rcode = FORMERR; return (-1); } @@ -1452,7 +1397,8 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) context = domain_ctx; else context = mailname_ctx; - if (!ns_nameok((char *)cp1, class, response_trans, context)) { + if (!ns_nameok((char *)cp1, class, response_trans, context, + dname, from_addr.sin_addr)) { hp->rcode = FORMERR; return (-1); } @@ -1467,23 +1413,76 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) cp1 = data; break; + case T_NAPTR: + /* Grab weight and port. */ + bcopy(cp, data, INT16SZ*2); + cp1 = data + INT16SZ*2; + cp += INT16SZ*2; + + /* Flags */ + n = *cp++; + *cp1++ = n; + bcopy(cp, cp1, n); + cp += n; cp1 += n; + + /* Service */ + n = *cp++; + *cp1++ = n; + bcopy(cp, cp1, n); + cp += n; cp1 += n; + + /* Regexp */ + n = *cp++; + *cp1++ = n; + bcopy(cp, cp1, n); + cp += n; cp1 += n; + + /* Replacement */ + n = dn_expand(msg, msg + msglen, cp, (char *)cp1, + sizeof data - (cp1 - data)); + if (n < 0) { + hp->rcode = FORMERR; + return (-1); + } + if (!ns_nameok((char *)cp1, class, response_trans, + hostname_ctx, dname, from_addr.sin_addr)) { + hp->rcode = FORMERR; + return (-1); + } + cp += n; + + /* compute end of data */ + cp1 += strlen((char *)cp1) + 1; + /* compute size of data */ + n = cp1 - data; + cp1 = data; + break; + case T_MX: case T_AFSDB: case T_RT: + case T_SRV: /* grab preference */ bcopy(cp, data, INT16SZ); cp1 = data + INT16SZ; cp += INT16SZ; + if (type == T_SRV) { + /* Grab weight and port. */ + bcopy(cp, data, INT16SZ*2); + cp1 += INT16SZ*2; + cp += INT16SZ*2; + } + /* get name */ n = dn_expand(msg, msg + msglen, cp, (char *)cp1, - sizeof data - INT16SZ); + sizeof data - (cp1 - data)); if (n < 0) { hp->rcode = FORMERR; return (-1); } if (!ns_nameok((char *)cp1, class, response_trans, - hostname_ctx)) { + hostname_ctx, dname, from_addr.sin_addr)) { hp->rcode = FORMERR; return (-1); } @@ -1510,7 +1509,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) return (-1); } if (!ns_nameok((char *)cp1, class, response_trans, - domain_ctx)) { + domain_ctx, dname, from_addr.sin_addr)) { hp->rcode = FORMERR; return (-1); } @@ -1523,7 +1522,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) return (-1); } if (!ns_nameok((char *)cp1, class, response_trans, - domain_ctx)) { + domain_ctx, dname, from_addr.sin_addr)) { hp->rcode = FORMERR; return (-1); } @@ -1533,6 +1532,84 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) cp1 = data; break; + case T_SIG: { + u_long origTTL, exptime, signtime, timetilexp, now; + + /* Check signature time, expiration, and adjust TTL. */ + /* This code is similar to that in db_load.c. */ + + /* Skip coveredType, alg, labels */ + cp1 = cp + INT16SZ + 1 + 1; + GETLONG(origTTL, cp1); + GETLONG(exptime, cp1); + GETLONG(signtime, cp1); + now = time(NULL); /* Get current time in GMT/UTC */ + + /* Don't let bogus name servers increase the signed TTL */ + if (ttl > origTTL) { + dprintf(3, (ddt, + "shrinking SIG TTL from %d to origTTL %d\n", + ttl, origTTL)); + ttl = origTTL; + } + + /* Don't let bogus signers "sign" in the future. */ + if (signtime > now) { + dprintf(3, (ddt, + "ignoring SIG: signature date %s is in the future\n", + p_secstodate (signtime))); + return ((cp - rrp) + dlen); + } + + /* Ignore received SIG RR's that are already expired. */ + if (exptime <= now) { + dprintf(3, (ddt, + "ignoring SIG: expiration %s is in the past\n", + p_secstodate (exptime))); + return ((cp - rrp) + dlen); + } + + /* Lop off the TTL at the expiration time. */ + timetilexp = exptime - now; + if (timetilexp < ttl) { + dprintf(3, (ddt, + "shrinking expiring %s SIG TTL from %d to %d\n", + p_secstodate (exptime), ttl, timetilexp)); + ttl = timetilexp; + } + + /* The following code is copied from named-xfer.c. */ + cp1 = (u_char *)data; + + /* first just copy over the type_covered, algorithm, */ + /* labels, orig ttl, two timestamps, and the footprint */ + bcopy(cp, cp1, 18); + cp += 18; + cp1 += 18; + + /* then the signer's name */ + n = dn_expand(msg, msg + msglen, cp, + (char *)cp1, (sizeof data) - 18); + if (n < 0) + return (-1); + cp += n; + cp1 += strlen((char*)cp1)+1; + + /* finally, we copy over the variable-length signature. + Its size is the total data length, minus what we copied. */ + n = dlen - (18 + n); + if (n > (sizeof data) - (cp1 - (u_char *)data)) + return (-1); /* out of room! */ + bcopy(cp, cp1, n); + cp += n; + cp1 += n; + + /* compute size of data */ + n = cp1 - (u_char *)data; + cp1 = (u_char *)data; + break; + } + default: dprintf(3, (ddt, "unknown type %d\n", type)); return ((cp - rrp) + dlen); @@ -1545,157 +1622,45 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) return (-1); } -#ifdef ALLOW_UPDATES - /* - * If this is a dynamic update request, process it specially; else, - * execute normal update code. - */ - switch(hp->opcode) { + ttl += tt.tv_sec; - /* For UPDATEM and UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA */ - case UPDATEM: - case UPDATEMA: + *dpp = savedata(class, type, ttl, cp1, n); + return (cp - rrp); +} - /* - * The named code for UPDATED and UPDATEDA is the same except that for - * UPDATEDA we we ignore any data that was passed: we just delete all - * RRs whose name, type, and class matches - */ - case UPDATED: - case UPDATEDA: - if (type == T_SOA) { /* Not allowed */ - dprintf(1, (ddt, "UDPATE: REFUSED - SOA delete\n")); - hp->rcode = REFUSED; - return (-1); - } - /* - * Don't check message length if doing UPDATEM/UPDATEMA, - * since the whole message wont have been demarshalled until - * we reach the code for UPDATEA - */ - if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEDA) ) { - if (cp != (u_char *)(msg + msglen)) { - dprintf(1, (ddt, - "FORMERR UPDATE message length off\n" - )); - hp->rcode = FORMERR; - return (-1); - } - } - if ((zonenum = findzone(dname, class)) == 0) { - hp->rcode = NXDOMAIN; - return (-1); - } - if (zones[zonenum].z_flags & Z_DYNADDONLY) { - hp->rcode = NXDOMAIN; - return (-1); - } - if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEM) ) { - /* Make a dp for use in db_update, as old dp */ - dp = savedata(class, type, 0, cp1, n); - dp->d_zone = zonenum; - dp->d_cred = cred; - dp->d_clev = db_getclev(zones[zonenum].z_origin); - n = db_update(dname, dp, NULL, DB_MEXIST | DB_DELETE, - hashtab); - if (n != OK) { - dprintf(1, (ddt, - "UPDATE: db_update failed\n")); - free((char*) dp); - hp->rcode = NOCHANGE; - return (-1); - } - } else { /* UPDATEDA or UPDATEMA */ - int DeletedOne = 0; - /* Make a dp for use in db_update, as old dp */ - dp = savedata(class, type, 0, NULL, 0); - dp->d_zone = zonenum; - dp->d_cred = cred; - dp->d_clev = db_getclev(zones[zonenum].z_origin); - do { /* Loop and delete all matching RR(s) */ - n = db_update(dname, dp, NULL, DB_DELETE, - hashtab); - if (n != OK) - break; - DeletedOne++; - } while (1); - free((char*) dp); - /* Ok for UPDATEMA not to have deleted any RRs */ - if (!DeletedOne && hp->opcode == UPDATEDA) { - dprintf(1, (ddt, - "UPDATE: db_update failed\n")); - hp->rcode = NOCHANGE; - return (-1); - } - } - if ( (hp->opcode == UPDATED) || (hp->opcode == UPDATEDA) ) - return (cp - rrp);; - /* - * Else unmarshal the RR to be added and continue on to - * UPDATEA code for UPDATEM/UPDATEMA - */ - if ((n = - dn_expand(msg, msg+msglen, cp, dname, sizeof(dname))) < 0) { - dprintf(1, (ddt, - "FORMERR UPDATE expand name failed\n")); - hp->rcode = FORMERR; - return (-1); - } - cp += n; - GETSHORT(type, cp); - GETSHORT(class, cp); - GETLONG(ttl, cp); - GETSHORT(n, cp); - cp1 = cp; -/**** XXX - need bounds checking here ****/ - cp += n; +/* + * Decode the resource record 'rrp' and update the database. + * If savens is non-nil, record pointer for forwarding queries a second time. + */ +int +doupdate(msg, msglen, rrp, zone, savens, flags, cred) + u_char *msg; + int msglen; + u_char *rrp; + int zone; + struct databuf **savens; + int flags; + u_int cred; +{ + register u_char *cp; + register int n; + int class, type; + struct databuf *dp; + char dname[MAXDNAME]; + u_char data[BUFSIZ+MAX_MD5RSA_KEY_BYTES]; - case UPDATEA: - if (n > MAXDATA) { - dprintf(1, (ddt, "UPDATE: too much data\n")); - hp->rcode = NOCHANGE; - return (-1); - } - if (cp != (u_char *)(msg + msglen)) { - dprintf(1, (ddt, - "FORMERR UPDATE message length off\n")); - hp->rcode = FORMERR; - return (-1); - } - if ((zonenum = findzone(dname, class)) == 0) { - hp->rcode = NXDOMAIN; - return (-1); - } - if (zones[zonenum].z_flags & Z_DYNADDONLY) { - struct hashbuf *htp = hashtab; - char *fname; - if (nlookup(dname, &htp, &fname, 0) && - !strcasecmp(dname, fname)) { - dprintf(1, (ddt, - "refusing add of existing name\n" - )); - hp->rcode = REFUSED; - return (-1); - } - } - dp = savedata(class, type, ttl, cp1, n); - dp->d_zone = zonenum; - dp->d_cred = cred; - dp->d_clev = db_getclev(zones[zonenum].z_origin); - if ((n = db_update(dname, NULL, dp, DB_NODATA, - hashtab)) != OK) { - dprintf(1, (ddt, "UPDATE: db_update failed\n")); - hp->rcode = NOCHANGE; - free((char*) dp); - return (-1); - } - else - return (cp - rrp); - } -#endif /* ALLOW_UPDATES */ + dprintf(3, (ddt, "doupdate(zone %d, savens %#lx, flags %#lx)\n", + zone, (u_long)savens, (u_long)flags)); + + if ((n = rrextract(msg, msglen, rrp, &dp, dname, sizeof(dname))) == -1) + return (-1); + if (!dp) + return (-1); + + type = dp->d_type; + class = dp->d_class; + cp = rrp + n; - if (zone == 0) - ttl += tt.tv_sec; #if defined(TRACEROOT) || defined(BOGUSNS) if ((type == T_NS) && (savens != NULL)) { char *temp, qname[MAXDNAME]; @@ -1724,6 +1689,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) syslog(LOG_NOTICE, "bogus root NS %s rcvd from %s on query for \"%s\"", data, sin_ntoa(&from_addr), qname); + db_free(dp); return (cp - rrp); } #ifdef BOGUSNS @@ -1733,13 +1699,13 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) syslog(LOG_INFO, "bogus nonroot NS %s rcvd from %s on query for \"%s\"", data, sin_ntoa(&from_addr), qname); + db_free(dp); return (cp - rrp); } #endif } #endif /*TRACEROOT || BOGUSNS*/ - dp = savedata(class, type, ttl, cp1, n); dp->d_zone = zone; dp->d_cred = cred; dp->d_clev = 0; /* We trust what is on disk more, except root srvrs */ @@ -1750,7 +1716,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) else if (debug >= 3) fprintf(ddt, "update failed (DATAEXISTS)\n"); #endif - free((char *)dp); + db_free(dp); } else if (type == T_NS && savens != NULL) *savens = dp; return (cp - rrp); @@ -1984,7 +1950,7 @@ sysnotify(dname, class, type) } /*next NS*/ done: if (nns || na) { - char tmp[MAXDNAME*2]; + char tmp[MAXDNAME]; /* Many syslog()'s only take 5 args. */ sprintf(tmp, "%s %s %s", dname, p_class(class), p_type(type)); @@ -2003,6 +1969,7 @@ sysquery(dname, class, type, nss, nsc, opcode) { register struct qinfo *qp, *oqp; register HEADER *hp; + char tmpdomain[MAXDNAME]; struct namebuf *np; struct databuf *nsp[NSMAX]; struct hashbuf *htp; @@ -2010,12 +1977,10 @@ sysquery(dname, class, type, nss, nsc, opcode) const char *fname; int n, count; -#ifdef DATUMREFCNT nsp[0] = NULL; -#endif dprintf(3, (ddt, "sysquery(%s, %d, %d, %#lx, %d)\n", dname, class, type, (u_long)nss, nsc)); - qp = qnew(); + qp = qnew(dname, class, type); if (nss && nsc) { np = NULL; @@ -2035,12 +2000,10 @@ sysquery(dname, class, type, nss, nsc, opcode) switch (n) { case NXDOMAIN: case SERVFAIL: - syslog(LOG_DEBUG, "sysquery: findns error (%d) on %s?", - n, dname); + syslog(LOG_DEBUG, "sysquery: findns error (%s) on %s?", + n == NXDOMAIN ? "NXDOMAIN" : "SERVFAIL", dname); err2: -#ifdef DATUMREFCNT free_nsp(nsp); -#endif goto err1; } } @@ -2054,9 +2017,11 @@ sysquery(dname, class, type, nss, nsc, opcode) qp->q_fwd = fwdtab; qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2; qp->q_flags |= Q_SYSTEM; -#if defined(LAME_DELEGATION) || defined(VALIDATE) - getname(np, qp->q_domain, sizeof(qp->q_domain)); -#endif /* LAME_DELEGATION */ + + getname(np, tmpdomain, sizeof tmpdomain); + qp->q_domain = strdup(tmpdomain); + if (!qp->q_domain) + panic(ENOMEM, "ns_resp: strdup failed"); if ((qp->q_msg = (u_char *)malloc(BUFSIZ)) == NULL) { syslog(LOG_NOTICE, "sysquery: malloc failed"); @@ -2129,10 +2094,8 @@ sysquery(dname, class, type, nss, nsc, opcode) goto err2; } if (np) { -#ifdef DATUMREFCNT free_nsp(nsp); nsp[0] = NULL; -#endif np = np_parent(np); n = findns(&np, class, nsp, &count, 0); switch (n) { @@ -2172,9 +2135,7 @@ sysquery(dname, class, type, nss, nsc, opcode) nameserIncr(nsa->sin_addr, nssSendtoErr); } nameserIncr(nsa->sin_addr, nssSentSysQ); -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return (qp); } @@ -2182,7 +2143,7 @@ sysquery(dname, class, type, nss, nsc, opcode) * Check the list of root servers after receiving a response * to a query for the root servers. */ -static void +static int check_root() { register struct databuf *dp, *pdp; @@ -2195,7 +2156,7 @@ check_root() break; if (np == NULL) { syslog(LOG_NOTICE, "check_root: Can't find root!\n"); - return; + return (0); } for (dp = np->n_data; dp != NULL; dp = dp->d_next) if (dp->d_type == T_NS) @@ -2205,7 +2166,7 @@ check_root() syslog(LOG_NOTICE, "check_root: %d root servers after query to root server < min", count); - return; + return (0); } pdp = NULL; dp = np->n_data; @@ -2221,13 +2182,18 @@ check_root() pdp = dp; dp = dp->d_next; } - check_ns(); + if (check_ns()) + return (1); + else { + priming = 1; + return (0); + } } /* * Check the root to make sure that for each NS record we have a A RR */ -static void +static int check_ns() { register struct databuf *dp, *tdp; @@ -2237,6 +2203,7 @@ check_ns() int found_arr; const char *fname; time_t curtime; + int servers = 0, rrsets = 0; dprintf(2, (ddt, "check_ns()\n")); @@ -2245,9 +2212,17 @@ check_ns() if (NAME(*np)[0] != '\0') continue; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + int cnames = 0; + +#ifdef NCACHE + if (dp->d_rcode) + continue; +#endif if (dp->d_type != T_NS) continue; + servers++; + /* look for A records */ dname = (caddr_t) dp->d_data; htp = hashtab; @@ -2262,7 +2237,16 @@ check_ns() } /* look for name server addresses */ found_arr = 0; - for (tdp=tnp->n_data; tdp != NULL; tdp=tdp->d_next) { + delete_stale(tnp); + for (tdp = tnp->n_data; + tdp != NULL; + tdp = tdp->d_next) { +#ifdef NCACHE + if (tdp->d_rcode) + continue; +#endif + if (tdp->d_type == T_CNAME) + cnames++; if (tdp->d_type != T_A || tdp->d_class != dp->d_class) continue; @@ -2271,22 +2255,28 @@ check_ns() dprintf(3, (ddt, "check_ns: stale entry '%s'\n", NAME(*tnp))); - /* Cache invalidate the address RR's */ - delete_all(tnp, dp->d_class, T_A); found_arr = 0; break; } found_arr++; } - if (!found_arr) + if (found_arr) + rrsets++; + else if (cnames > 0) + syslog(LOG_INFO, "Root NS %s -> CNAME %s", + NAME(*np), NAME(*tnp)); + else sysquery(dname, dp->d_class, T_A, NULL, 0, QUERY); } } + + dprintf(2, (ddt, "check_ns: %d %d\n", servers, rrsets)); + return ((servers<=2)?(rrsets==servers):((rrsets*2)>=servers)); } /* int findns(npp, class, nsp, countp, flag) - * Find NS' or an SOA + * Find NS's or an SOA * npp, class: * dname whose most enclosing NS is wanted * nsp, countp: @@ -2295,8 +2285,11 @@ check_ns() * boolean: we're being called from ADDAUTH, bypass authority checks * return value: * NXDOMAIN: we are authoritative for this {dname,class} + * *countp is bogus, but nsp[] has a single SOA returned in it. * SERVFAIL: we are auth but zone isn't loaded; or, no root servers found - * OK: success (this is the only case where *countp and nsp[] are valid) + * *countp and nsp[] are bogus. + * OK: we are not authoritative, and here are the NS records we found. + * *countp and nsp[] return NS records of interest. */ int findns(npp, class, nsp, countp, flag) @@ -2311,9 +2304,7 @@ findns(npp, class, nsp, countp, flag) register struct databuf **nspp; struct hashbuf *htp; -#ifdef DATUMREFCNT nsp[0] = NULL; -#endif if (priming && (np == NULL || NAME(*np)[0] == '\0')) htp = fcachetab; @@ -2347,10 +2338,8 @@ findns(npp, class, nsp, countp, flag) if (zones[dp->d_zone].z_flags & Z_AUTH) { *npp = np; nsp[0] = dp; -#ifdef DATUMREFCNT nsp[1] = NULL; dp->d_rcnt++; -#endif return (NXDOMAIN); } else { /* XXX: zone isn't loaded but we're @@ -2365,6 +2354,7 @@ findns(npp, class, nsp, countp, flag) /* If no SOA records, look for NS records. */ nspp = &nsp[0]; *nspp = NULL; + delete_stale(np); for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!match(dp, class, T_NS)) continue; @@ -2380,15 +2370,10 @@ findns(npp, class, nsp, countp, flag) * XXX: this is horribly bogus. */ if ((dp->d_zone == 0) && -#ifdef DATUMREFCNT (dp->d_ttl < tt.tv_sec) && -#else - (dp->d_ttl < (tt.tv_sec+900)) && -#endif !(dp->d_flags & DB_F_HINT)) { dprintf(1, (ddt, "findns: stale entry '%s'\n", NAME(*np))); -#ifdef DATUMREFCNT /* * We may have already added NS databufs * and are going to throw them away. Fix @@ -2398,20 +2383,12 @@ findns(npp, class, nsp, countp, flag) */ while (nspp > &nsp[0]) (*--nspp)->d_rcnt--; -#endif - /* Cache invalidate the NS RR's. */ -#ifndef DATUMREFCNT - if (dp->d_ttl < tt.tv_sec) -#endif - delete_all(np, class, T_NS); nsp[0] = NULL; goto try_parent; } if (nspp < &nsp[NSMAX-1]) { *nspp++ = dp; -#ifdef DATUMREFCNT dp->d_rcnt++; -#endif } } @@ -2423,7 +2400,7 @@ findns(npp, class, nsp, countp, flag) *npp = np; return (OK); /* Success, got some NS's */ } -try_parent: + try_parent: np = np_parent(np); } if (htp == hashtab) { @@ -2440,6 +2417,7 @@ try_parent: return (SERVFAIL); } + /* * Extract RR's from the given node that match class and type. * Return number of bytes added to response. @@ -2455,7 +2433,9 @@ finddata(np, class, type, hp, dnamep, lenp, countp) { register struct databuf *dp; register char *cp; - int buflen, n, count = 0, foundstale = 0; + int buflen, n, count = 0; + + delete_stale(np); #ifdef ROUND_ROBIN if (type != T_ANY && type != T_PTR) { @@ -2498,33 +2478,20 @@ finddata(np, class, type, hp, dnamep, lenp, countp) #endif /*NCACHE*/ continue; } - if (stale(dp)) { - /* - * Don't use stale data. - * Would like to call delete_all here - * and continue, but the data chain would get - * munged; can't restart, as make_rr has side - * effects (leaving pointers in dnptr). - * Just skip this entry for now - * and call delete_all at the end. - */ - dprintf(3, (ddt, - "finddata: stale entry '%s'\n", - NAME(*np))); - if (dp->d_zone == 0) - foundstale++; - continue; - } if (dp->d_cred == DB_C_ADDITIONAL) { +#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 faster when this datum is + * 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 } #ifdef NCACHE /* -ve $ing stuff, anant@isi.edu @@ -2541,15 +2508,14 @@ finddata(np, class, type, hp, dnamep, lenp, countp) *dnamep, type, class); continue; } - if (type != T_ANY) { - hp->rcode = NOERROR_NODATA; + if (type == T_ANY) + continue; + hp->rcode = NOERROR_NODATA; + if (dp->d_size == 0) { /* !RETURNSOA */ *countp = 0; return 1; /* XXX - we have to report success */ } - /* don't satisfy T_ANY queries from -$ info */ - continue; } -#ifndef RETURNSOA if (dp->d_rcode == NXDOMAIN) { if (count != 0) { /* @@ -2560,17 +2526,20 @@ finddata(np, class, type, hp, dnamep, lenp, countp) *dnamep, type, class); continue; } - if (type != T_ANY) { - hp->rcode = NXDOMAIN; + hp->rcode = NXDOMAIN; + if (dp->d_size == 0) { /* !RETURNSOA */ *countp = 0; return 1; /* XXX - we have to report success */ } - /* don't satisfy T_ANY queries from -$ info */ - continue; } -#endif #endif /*NCACHE*/ + /* Don't put anything but key or sig RR's in response to + requests for key or sig */ + if (((type == T_SIG) || (type == T_KEY)) && + (!((dp->d_type == T_SIG) || (dp->d_type == T_KEY))) ) + continue; + if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1)) < 0) { hp->tc = 1; *countp = count; @@ -2588,7 +2557,11 @@ finddata(np, class, type, hp, dnamep, lenp, countp) hp->aa = 1; /* XXX */ #endif if (dp->d_type == T_CNAME) { - if (type != T_ANY) { /* or T_NS? */ + /* 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 (dp->d_zone != DB_Z_CACHE && (zones[dp->d_zone].z_flags & Z_AUTH) && @@ -2602,14 +2575,6 @@ finddata(np, class, type, hp, dnamep, lenp, countp) * Cache invalidate the other RR's of same type * if some have timed out */ - if (foundstale) { - delete_all(np, class, type); - /* XXX this isn't right if 'type' is something special - * such as T_AXFR or T_MAILB, since the matching done - * by match() in delete_all() is different from that - * done by wanted() above. - */ - } dprintf(3, (ddt, "finddata: added %d class %d type %d RRs\n", count, class, type)); *countp = count; @@ -2618,19 +2583,25 @@ finddata(np, class, type, hp, dnamep, lenp, countp) /* * Do we want this data record based on the class and type? + * (We always return found unexpired SIG RR's that cover the wanted rrtype.) */ int wanted(dp, class, type) struct databuf *dp; int class, type; { + u_char *cp; + u_int16_t coveredType; + time_t expiration; + dprintf(3, (ddt, "wanted(%#lx, %d, %d) [%s %s]\n", (u_long)dp, class, type, p_class(dp->d_class), p_type(dp->d_type))); if (dp->d_class != class && class != C_ANY) return (0); - if (type == dp->d_type) + /* Must check SIG for expiration below, other matches return OK here. */ + if (type == dp->d_type && (type != T_SIG)) return (1); #ifdef NCACHE /*-ve $ing stuff, for a T_ANY query, we do not want to return @@ -2640,7 +2611,26 @@ wanted(dp, class, type) return (0); #endif + /* First, look at the type of RR. */ switch (dp->d_type) { + + /* Cases to deal with: + T_ANY search, return all unexpired SIGs. + T_SIG search, return all unexpired SIGs. + T_<foo> search, return all unexp SIG <FOO>s. + */ + case T_SIG: + cp = dp->d_data; + GETSHORT(coveredType,cp); + cp += INT16SZ + INT32SZ; /* skip alg, labels, & orig TTL */ + GETLONG(expiration,cp); + + if (type == T_ANY || type == T_SIG || type == coveredType) { + if (expiration > time(0)) + return (1); /* Unexpired matching SIG */ + } + return (0); /* We don't return this SIG. */ + case T_ANY: return (1); case T_CNAME: @@ -2653,6 +2643,7 @@ wanted(dp, class, type) break; #endif } + /* OK, now look at the type of query. */ switch (type) { case T_ANY: return (1); @@ -2713,6 +2704,225 @@ add_data(np, dpp, cp, buflen, countp) return (bytes); } +static void +rrsetadd(flushset, name, dp) + struct flush_set *flushset; + char *name; + struct databuf *dp; +{ + struct flush_set *fs = flushset; + struct db_list *dbl; + + while (fs->fs_name && ( + strcasecmp(fs->fs_name,name) || + (fs->fs_class != dp->d_class) || + (fs->fs_type != dp->d_type) || + (fs->fs_cred != dp->d_cred))) { + fs++; + } + if (!fs->fs_name) { + fs->fs_name = strdup(name); + if (!fs->fs_name) + panic(-1, "rrsetadd: out of memory"); + fs->fs_class = dp->d_class; + fs->fs_type = dp->d_type; + fs->fs_cred = dp->d_cred; + fs->fs_list = NULL; + } + dbl = (struct db_list *)malloc(sizeof(struct db_list)); + if (!dbl) + panic(-1, "rrsetadd: out of memory"); + dbl->db_next = fs->fs_list; + dbl->db_dp = dp; + fs->fs_list = dbl; +} + +static int +ttlcheck(name,dbl) + char *name; + struct db_list *dbl; +{ + int type = dbl->db_dp->d_type; + int class = dbl->db_dp->d_class; + struct hashbuf *htp = hashtab; + const char *fname; + register struct namebuf *np; + struct db_list *dbp = dbl; + struct databuf *dp; + u_int32_t ttl; + int first; + + + np = nlookup(name, &htp, &fname, 0); + if (np == NULL || fname != name || ns_wildcard(NAME(*np))) { + return(1); + } + + /* check that all the ttl's we have are the same, if not return 1 */ + first = 1; + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + if (!match(dp, class, type)) + continue; + if (first) { + ttl = dp->d_ttl; + first = 0; + } else if (ttl != dp->d_ttl) { + return(1); + } + } + + /* there are no records of this type in the cache */ + if (first) + return(1); + + /* + * the ttls of all records we have in the cache are the same + * if the ttls differ in the new set we don't want it. + */ + + /* check that all the ttl's we have are the same, if not return 0 */ + first = 1; + while (dbp) { + if (first) { + ttl = dbp->db_dp->d_ttl; + first = 0; + } else if (ttl != dbp->db_dp->d_ttl) { + return(0); + } + dbp = dbp->db_next; + } + return(1); +} + +static int +rrsetcmp(name, dbl) + char *name; + struct db_list *dbl; +{ + int type = dbl->db_dp->d_type; + int class = dbl->db_dp->d_class; + struct hashbuf *htp = hashtab; + const char *fname; + register struct namebuf *np; + struct db_list *dbp = dbl; + struct databuf *dp; + int exists = 0; + + + np = nlookup(name, &htp, &fname, 0); + if (np == NULL || fname != name || ns_wildcard(NAME(*np))) { + dprintf(1, (ddt, "rrsetcmp: name not in database\n")); + return(-1); + } + + /* check that all entries in dbl are in the cache */ + while (dbp) { + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + if (match(dp, class, type)) + exists++; + if (!db_cmp(dp, dbp->db_dp) +#ifdef NOADDITIONAL + && ((dp->d_cred == dbp->db_dp->d_cred) || + (dp->d_cred != DB_C_ADDITIONAL)) +#endif + ) + break; + } + if (!dp) { + dprintf(1, (ddt, "rrsetcmp: %srecord%s in database\n", + exists ? "" : "no ", exists ? " not" : "s")); + return(exists? 1 : -1); + } + dbp = dbp->db_next; + } + + /* Check that all cache entries are in the list. */ + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + if (!match(dp, class, type)) + continue; +#ifdef NCACHE + if (dp->d_rcode) + return(1); +#endif + dbp = dbl; + while (dbp) { + if (!db_cmp(dp, dbp->db_dp)) + break; + dbp = dbp->db_next; + } + if (!dbp) { + dprintf(1, (ddt, "rrsetcmp: record not in rrset\n")); + return(1); + } + } + dprintf(1, (ddt, "rrsetcmp: rrsets matched\n")); + return(0); +} + +static void +rrsetupdate(flushset, flags) + struct flush_set * flushset; + int flags; +{ + struct flush_set *fs = flushset; + struct db_list *dbp, *odbp; + int n; + + while (fs->fs_name) { + dprintf(1,(ddt, "rrsetupdate: %s\n", + fs->fs_name[0] ? fs->fs_name : ".")); + if ((n = rrsetcmp(fs->fs_name,fs->fs_list)) && + ttlcheck(fs->fs_name,fs->fs_list)) { + if (n > 0) + flushrrset(fs); + + dbp = fs->fs_list; + while (dbp) { + n = db_update(fs->fs_name, dbp->db_dp, + dbp->db_dp, flags, hashtab); + dprintf(1,(ddt, "rrsetupdate: %s %d\n", + fs->fs_name[0] ? fs->fs_name : ".", n)); + if (n != OK) + db_free(dbp->db_dp); + odbp = dbp; + dbp = dbp->db_next; + free((char *)odbp); + } + } else { + dbp = fs->fs_list; + while (dbp) { + db_free(dbp->db_dp); + odbp = dbp; + dbp = dbp->db_next; + free((char *)odbp); + } + } + fs->fs_list = NULL; + fs++; + } +} + +static void +flushrrset(fs) + struct flush_set * fs; +{ + struct databuf *dp; + int n; + + dprintf(1, (ddt, "flushrrset(%s, %s, %s, %d)\n", + fs->fs_name[0]?fs->fs_name:".", p_type(fs->fs_type), + p_class(fs->fs_class), fs->fs_cred)); + dp = savedata(fs->fs_class, fs->fs_type, 0, NULL, 0); + dp->d_zone = 0; + dp->d_cred = fs->fs_cred; + dp->d_clev = 0; + do { + n = db_update(fs->fs_name, dp, NULL, DB_DELETE, hashtab); + dprintf(1, (ddt, "flushrrset: %d\n", n)); + } while (n == OK); + db_free(dp); +} + /* * This is best thought of as a "cache invalidate" function. * It is called whenever a piece of data is determined to have @@ -2741,3 +2951,26 @@ delete_all(np, class, type) dp = dp->d_next; } } + +/* delete_stale(np) + * for all RRs associated with this name, check for staleness (& delete) + * arguments: + * np = pointer to namebuf to be cleaned. + * returns: + * void. + * side effects: + * delete_all() can be called, freeing memory and relinking chains. + */ +void +delete_stale(np) + struct namebuf *np; +{ + struct databuf *dp; + again: + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + if ((dp->d_zone == 0) && stale(dp)) { + delete_all(np, dp->d_class, dp->d_type); + goto again; + } + } +} diff --git a/contrib/bind/named/ns_stats.c b/contrib/bind/named/ns_stats.c index 9a29fb1..1fe382a 100644 --- a/contrib/bind/named/ns_stats.c +++ b/contrib/bind/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.7 1996/08/05 08:31:30 vixie Exp $"; +static char rcsid[] = "$Id: ns_stats.c,v 8.8 1996/09/22 00:13:10 vixie Exp $"; #endif /* not lint */ /* @@ -132,11 +132,6 @@ ns_stats() fprintf(f, "%ld\ttime since reset (secs)\n", (long)(timenow - resettime)); -#ifdef DMALLOC - /* malloc statistics */ - dmallocstats(f); -#endif - /* query type statistics */ fprintf(f, "%lu\tUnknown query types\n", (u_long)typestats[0]); for(i=1; i < T_ANY+1; i++) diff --git a/contrib/bind/named/ns_udp.c b/contrib/bind/named/ns_udp.c new file mode 100644 index 0000000..7fb5831 --- /dev/null +++ b/contrib/bind/named/ns_udp.c @@ -0,0 +1,113 @@ +#if !defined(lint) && !defined(SABER) +static char rcsid[] = "$Id: ns_udp.c,v 8.3 1996/08/27 08:33:23 vixie Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/file.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <syslog.h> +#include <netdb.h> +#include <nlist.h> +#include <resolv.h> + +#include "named.h" + +void +ns_udp() { +#if defined(CHECK_UDP_SUM) || defined(FIX_UDP_SUM) + struct nlist nl[2]; + int fd; + int sum; + u_long res, offset; + + nl[0].n_name = UDPSUM; + nl[1].n_name = 0; + + if (nlist(KSYMS, nl)) { + dprintf(1, (ddt, "ns_udp: nlist (%s,%s) failed\n", + KSYMS, UDPSUM)); + return; + } + + dprintf(1, (ddt, "ns_udp: %s %d %lu (%ld)\n", + nl[0].n_name, nl[0].n_type, nl[0].n_value, + nl[0].n_value)); + + if (!nl[0].n_type) + return; + + if ((fd = open(KMEM, O_RDWR, 0)) < 0) { + dprintf(1, (ddt, "ns_udp: open %s failed\n", KMEM)); + return; + } + + offset = nl[0].n_value; +#ifdef KMAP + offset &= ((~0UL)>>1); +#endif + + res = lseek(fd, offset, SEEK_SET); + if (res != offset) { + dprintf(1, (ddt, "ns_udp: lseek %ul failed %lu %d\n", + offset, res, errno)); + goto cleanup; + } + + if (read(fd, &sum, sizeof(sum)) != sizeof(sum)) { + dprintf(1, (ddt, "ns_udp: read failed\n")); + goto cleanup; + } + + dprintf(1, (ddt, "ns_udp: %d\n", sum)); + if (sum == 0) { +#ifdef FIX_UDP_SUM + sum = 1; + lseek(fd, offset, SEEK_SET); + if (res != offset) { + dprintf(1, (ddt, "ns_udp: lseek %ul failed %lu %d\n", + offset, res, errno)); + goto cleanup; + } + if (write(fd, &sum, sizeof(sum)) != sizeof(sum)) { + dprintf(1, (ddt, "ns_udp: write failed\n")); + goto cleanup; + } + dprintf(1, (ddt, "ns_udp: set to 1\n")); + syslog(LOG_WARNING, "ns_udp: check sums turned on"); +#else + dprintf(1, (ddt, "ns_udp: Exiting\n")); + syslog(LOG_WARNING, "ns_udp: checksums NOT turned on: Exiting"); + exit(1); +#endif + } +cleanup: + close(fd); +#endif +} diff --git a/contrib/bind/named/ns_validate.c b/contrib/bind/named/ns_validate.c index 00df9d7..1192471 100644 --- a/contrib/bind/named/ns_validate.c +++ b/contrib/bind/named/ns_validate.c @@ -116,9 +116,7 @@ validate(dname, qdomain, server, type, class, data, dlen int exactmatch = 0; struct fwdinfo *fwd; -#ifdef DATUMREFCNT nsp[0] = NULL; -#endif dprintf(3, (ddt, "validate(), d:%s, s:[%s], t:%d, c:%d\n", dname, inet_ntoa(server->sin_addr), type, class)); @@ -155,9 +153,7 @@ validate(dname, qdomain, server, type, class, data, dlen * in either case, do not cache **/ dprintf(5, (ddt, "validate: auth data found\n")); -#ifdef DATUMREFCNT free_nsp(nsp); -#endif if (needs_prime_cache) needs_prime_cache = 0; @@ -211,9 +207,7 @@ validate(dname, qdomain, server, type, class, data, dlen /* stick_in_queue(dname, type, class, data); */ if (needs_prime_cache) needs_prime_cache = 0; -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return (INVALID); case OK: /*proceed */ @@ -222,21 +216,15 @@ validate(dname, qdomain, server, type, class, data, dlen needs_prime_cache = 0; if (samedomain(dname, qdomain) || check_addr_ns(nsp, server, dname)) { -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return (VALID_CACHE); } /* server is not one of those we know of */ /* stick_in_queue(dname, type, class, data); */ -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return (INVALID); default: -#ifdef DATUMREFCNT free_nsp(nsp); -#endif return (INVALID); } /*switch*/ |