diff options
author | Peter Wemm <peter@FreeBSD.org> | 1995-08-20 20:55:55 +0000 |
---|---|---|
committer | Peter Wemm <peter@FreeBSD.org> | 1995-08-20 20:55:55 +0000 |
commit | 935d0975b61395242d51eb8fdb19e060c9d4cfce (patch) | |
tree | 4c99c1a6ea4806387592aa7b751e1fe415438441 | |
parent | f260c6268119605b02ddea819db271e65c53307c (diff) | |
download | src-test2-935d0975b61395242d51eb8fdb19e060c9d4cfce.tar.gz src-test2-935d0975b61395242d51eb8fdb19e060c9d4cfce.zip |
Notes
31 files changed, 3390 insertions, 1324 deletions
diff --git a/usr.sbin/named/Version.c b/usr.sbin/named/Version.c index 7cbce2820e86..60a7ba829dd9 100644 --- a/usr.sbin/named/Version.c +++ b/usr.sbin/named/Version.c @@ -1,11 +1,11 @@ /* * @(#)Version.c 4.9 (Berkeley) 7/21/90 - * $Id: Version.c,v 4.9.1.3 1994/06/01 21:09:39 vixie Exp $ + * $Id: Version.c,v 8.1 1994/12/15 06:24:14 vixie Exp $ */ #ifndef lint char sccsid[] = "@(#)named %VERSION% %WHEN% %WHOANDWHERE%"; -char rcsid[] = "$Id: Version.c,v 4.9.1.3 1994/06/01 21:09:39 vixie Exp $"; +char rcsid[] = "$Id: Version.c,v 8.1 1994/12/15 06:24:14 vixie Exp $"; #endif /* not lint */ char Version[] = "named %VERSION% %WHEN%\n\t%WHOANDWHERE%"; diff --git a/usr.sbin/named/db_defs.h b/usr.sbin/named/db_defs.h index db9b32c2e256..c4c48ed37297 100644 --- a/usr.sbin/named/db_defs.h +++ b/usr.sbin/named/db_defs.h @@ -1,6 +1,6 @@ /* * from db.h 4.16 (Berkeley) 6/1/90 - * $Id: db_defs.h,v 1.11 1994/07/22 08:42:39 vixie Exp $ + * $Id: db_defs.h,v 8.3 1995/06/19 20:55:40 vixie Exp $ */ /* @@ -152,8 +152,9 @@ struct hashbuf { #define DB_DELETE 0x04 /* delete data if it exists */ #define DB_NOTAUTH 0x08 /* must not update authoritative data */ #define DB_NOHINTS 0x10 /* don't reflect update in fcachetab */ +#define DB_PRIMING 0x20 /* is this update the result of priming? */ -#define DB_Z_CACHE (0) /* cache-zone-only db_dump() */ +#define DB_Z_CACHE (0) /* cache-zone-only db_dump() */ #define DB_Z_ALL (-1) /* normal db_dump() */ /* @@ -170,3 +171,10 @@ struct hashbuf { #define GOODDB -8 #define NEWDB -9 #define AUTH -10 + +/* + * getnum() options + */ +#define GETNUM_NONE 0x00 /* placeholder */ +#define GETNUM_SERIAL 0x01 /* treat as serial number */ +#define GETNUM_SCALED 0x02 /* permit "k", "m" suffixes, scale result */ diff --git a/usr.sbin/named/db_dump.c b/usr.sbin/named/db_dump.c index 4a0d2c93f1f0..99b3b80d7c4e 100644 --- a/usr.sbin/named/db_dump.c +++ b/usr.sbin/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 4.9.1.12 1994/07/22 08:42:39 vixie Exp $"; +static char rcsid[] = "$Id: db_dump.c,v 8.7 1995/06/29 09:26:17 vixie Exp $"; #endif /* not lint */ /* @@ -107,7 +107,7 @@ doachkpt() } (void) gettime(&tt); - fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec)); + fprintf(fp, "; Dumped at %s", ctimel(tt.tv_sec)); fflush(fp); if (ferror(fp)) { dprintf(3, (ddt, "doachkpt(write to checkpoint file failed)\n")); @@ -118,7 +118,7 @@ doachkpt() int n = scan_root(hashtab); if (n < MINROOTS) { - syslog(LOG_ERR, "%d root hints... (too low)", n); + syslog(LOG_NOTICE, "%d root hints... (too low)", n); fprintf(fp, "; ---- Root hint cache dump ----\n"); (void) db_dump(fcachetab, fp, DB_Z_CACHE, ""); } @@ -133,7 +133,6 @@ doachkpt() } } - (void) fsync(fileno(fp)); if (my_fclose(fp) == EOF) { return; } @@ -160,7 +159,7 @@ scan_root(htp) struct timeval soon; int roots = 0; - dprintf(1, (ddt, "scan_root(0x%x)\n", htp)); + dprintf(1, (ddt, "scan_root(0x%lx)\n", (u_long)htp)); /* metric by which we determine whether a root NS pointer is still */ /* valid (will be written out if we do a dump). we also add some */ @@ -235,11 +234,12 @@ doadump() FILE *fp; dprintf(3, (ddt, "doadump()\n")); + syslog(LOG_NOTICE, "dumping nameserver data\n"); if ((fp = fopen(dumpfile, "w")) == NULL) return; gettime(&tt); - fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec)); + fprintf(fp, "; Dumped at %s", ctimel(tt.tv_sec)); if (zones && nzones) zt_dump(fp); fputs( @@ -255,6 +255,7 @@ doadump() if (fcachetab != NULL) (void) db_dump(fcachetab, fp, DB_Z_ALL, ""); (void) my_fclose(fp); + syslog(LOG_NOTICE, "finished dumping nameserver data\n"); } #ifdef ALLOW_UPDATES @@ -314,7 +315,7 @@ zt_dump(fp) zp->z_expire, zp->z_minimum); fprintf(fp, ";\tftime=%ld, xaddr=[%s], state=%04x, pid=%d\n", zp->z_ftime, inet_ntoa(zp->z_xaddr), - zp->z_flags, zp->z_xferpid); + zp->z_flags, (int)zp->z_xferpid); sprintf(buf, ";\tz_addr[%d]: ", zp->z_addrcnt); pre = buf; for (cnt = 0; cnt < zp->z_addrcnt; cnt++) { @@ -323,8 +324,19 @@ zt_dump(fp) } if (zp->z_addrcnt) fputc('\n', fp); +#ifdef BIND_NOTIFY + if (zp->z_notifylist) { + register struct notify *ap; + + for (ap = zp->z_notifylist; ap; ap = ap->next) + fprintf(fp, ";\tNotify [%s] %s", + inet_ntoa(ap->addr), + ctime(&ap->last)); + } +#endif } fprintf(fp, ";; --zone table--\n"); + return (0); } int @@ -386,7 +398,7 @@ db_dump(htp, fp, zone, origin) fprintf(fp, ".%s.\t", origin); /* ??? */ } else fprintf(fp, "%s\t", np->n_dname); - if (strlen(np->n_dname) < 8) + if (strlen(np->n_dname) < (size_t)8) tab = 1; found_data++; } else { @@ -438,8 +450,8 @@ db_dump(htp, fp, zone, origin) case C_HS: GETLONG(n, cp); n = htonl(n); - fprintf(fp, "%s", - inet_ntoa(*(struct in_addr *)&n)); + fputs(inet_ntoa(*(struct in_addr *)&n), + fp); break; } if (dp->d_nstime) { @@ -487,15 +499,15 @@ db_dump(htp, fp, zone, origin) #endif cp += strlen((char *)cp) + 1; GETLONG(n, cp); - fprintf(fp, "\t\t%lu", n); + fprintf(fp, "\t\t%lu", (u_long)n); GETLONG(n, cp); - fprintf(fp, " %lu", n); + fprintf(fp, " %lu", (u_long)n); GETLONG(n, cp); - fprintf(fp, " %lu", n); + fprintf(fp, " %lu", (u_long)n); GETLONG(n, cp); - fprintf(fp, " %lu", n); + fprintf(fp, " %lu", (u_long)n); GETLONG(n, cp); - fprintf(fp, " %lu )", n); + fprintf(fp, " %lu )", (u_long)n); #if defined(RETURNSOA) && defined(NCACHE) if (dp->d_rcode == NXDOMAIN) { fprintf(fp,";%s.;NXDOMAIN%s-$",cp,sep); @@ -507,8 +519,16 @@ db_dump(htp, fp, zone, origin) case T_AFSDB: case T_RT: GETSHORT(n, cp); - fprintf(fp,"%lu", n); - fprintf(fp," %s.", cp); + fprintf(fp, "%lu", (u_long)n); + fprintf(fp, " %s.", cp); + break; + + case T_PX: + GETSHORT(n, cp); + fprintf(fp, "%lu", (u_long)n); + fprintf(fp, " %s.", cp); + cp += strlen((char *)cp) + 1; + fprintf(fp, " %s.", cp); break; case T_TXT: @@ -533,7 +553,11 @@ db_dump(htp, fp, zone, origin) dp->d_data, NULL), fp); break; - +#ifdef LOC_RR + case T_LOC: + (void) fputs(loc_ntoa(dp->d_data, NULL), fp); + break; +#endif /* LOC_RR */ case T_UINFO: fprintf(fp, "\"%s\"", cp); break; @@ -551,8 +575,7 @@ db_dump(htp, fp, zone, origin) case T_WKS: GETLONG(addr, cp); addr = htonl(addr); - fprintf(fp, "%s ", - inet_ntoa(*(struct in_addr *)&addr)); + fputs(inet_ntoa(*(struct in_addr *)&addr), fp); proto = protocolname(*cp); cp += sizeof(char); fprintf(fp, "%s ", proto); @@ -585,23 +608,10 @@ db_dump(htp, fp, zone, origin) int TmpSize = 2 * dp->d_size + 30; char *TmpBuf = (char *) malloc(TmpSize); if (TmpBuf == NULL) { - dprintf(1, - (ddt, - "Dump T_UNSPEC: bad malloc\n" - ) - ); - syslog(LOG_ERR, - "Dump T_UNSPEC: malloc: %m"); TmpBuf = "BAD_MALLOC"; } if (btoa(cp, dp->d_size, TmpBuf, TmpSize) == CONV_OVERFLOW) { - dprintf(1, (ddt, - "Dump T_UNSPEC: Output buffer overflow\n" - ) - ); - syslog(LOG_ERR, - "Dump T_UNSPEC: Output buffer overflow\n"); TmpBuf = "OVERFLOW"; } fprintf(fp, "%s", TmpBuf); diff --git a/usr.sbin/named/db_func.h b/usr.sbin/named/db_func.h index 1c7275cb46e0..8db6c2f8e482 100644 --- a/usr.sbin/named/db_func.h +++ b/usr.sbin/named/db_func.h @@ -1,6 +1,6 @@ /* db_proc.h - prototypes for functions in db_*.c * - * $Id: db_func.h,v 1.8 1994/07/23 23:23:56 vixie Exp $ + * $Id: db_func.h,v 8.5 1995/06/19 08:34:49 vixie Exp $ */ /* ++from db_update.c++ */ @@ -8,7 +8,8 @@ extern int db_update __P((char name[], struct databuf *odp, struct databuf *newdp, int flags, - struct hashbuf *htp)); + struct hashbuf *htp)), + findMyZone __P((struct namebuf *np, int class)); /* --from db_update.c-- */ /* ++from db_reload.c++ */ @@ -16,7 +17,7 @@ extern void db_reload __P((void)); /* --from db_reload.c-- */ /* ++from db_save.c++ */ -extern struct namebuf *savename __P((char *)); +extern struct namebuf *savename __P((const char *, int)); #ifdef DMALLOC extern struct databuf *savedata_tagged __P((char *, int, int, int, u_int32_t, @@ -39,6 +40,7 @@ extern void doachkpt __P((void)), #ifdef ALLOW_UPDATES extern void zonedump __P((struct zoneinfo *)); #endif +extern u_int db_getclev __P((const char *)); /* --from db_dump.c-- */ /* ++from db_load.c++ */ @@ -47,8 +49,9 @@ extern void endline __P((FILE *)), int, char *)), free_netlist __P((struct netinfo **)); extern int getword __P((char *, int, FILE *)), - getnum __P((FILE *, char *, int)), - db_load __P((char *, char *, struct zoneinfo *, int)), + getnum __P((FILE *, const char *, int)), + db_load __P((const char *, const char *, + struct zoneinfo *, const char *)), position_on_netlist __P((struct in_addr, struct netinfo *)); extern struct netinfo *addr_on_netlist __P((struct in_addr, @@ -56,7 +59,9 @@ extern struct netinfo *addr_on_netlist __P((struct in_addr, /* --from db_load.c-- */ /* ++from db_glue.c++ */ -extern void buildservicelist __P((void)), +extern const char *sin_ntoa __P((const struct sockaddr_in *)); +extern void panic __P((int, const char *)), + buildservicelist __P((void)), buildprotolist __P((void)), gettime __P((struct timeval *)), getname __P((struct namebuf *, char *, int)); @@ -68,11 +73,13 @@ extern int servicenumber __P((char *)), get_class __P((char *)), #endif writemsg __P((int, u_char *, int)), - dhash __P((u_char *, int)), + dhash __P((const u_char *, int)), + nhash __P((const char *)), samedomain __P((const char *, const char *)); extern char *protocolname __P((int)), *servicename __P((u_int16_t, char *)), - *savestr __P((char *)); + *savestr __P((const char *)); +extern const char *inet_etoa __P((const struct sockaddr_in *)); #ifndef BSD extern int getdtablesize __P((void)); #endif @@ -87,11 +94,17 @@ extern void addinv __P((struct namebuf *, struct databuf *)), rminv __P((struct databuf *)); struct invbuf *saveinv __P((void)); #endif +#ifdef LOC_RR +extern u_int32_t loc_aton __P((const char *ascii, u_char *binary)); +extern char * loc_ntoa __P((const u_char *binary, char *ascii)); +#endif +extern char * ctimel __P((long)); +extern struct in_addr data_inaddr __P((const u_char *data)); /* --from db_glue.c-- */ /* ++from db_lookup.c++ */ -extern struct namebuf *nlookup __P((char *, struct hashbuf **, - char **, int)); +extern struct namebuf *nlookup __P((const char *, struct hashbuf **, + const char **, int)); extern int match __P((struct databuf *, int, int)); /* --from db_lookup.c-- */ diff --git a/usr.sbin/named/db_glob.h b/usr.sbin/named/db_glob.h index 74ae45d45763..630b8249d077 100644 --- a/usr.sbin/named/db_glob.h +++ b/usr.sbin/named/db_glob.h @@ -1,6 +1,6 @@ /* * from db.h 4.16 (Berkeley) 6/1/90 - * $Id: db_glob.h,v 1.2 1994/04/12 08:57:50 vixie Exp $ + * $Id: db_glob.h,v 8.2 1995/06/20 23:58:50 vixie Exp $ */ /* diff --git a/usr.sbin/named/db_glue.c b/usr.sbin/named/db_glue.c index f3f306941ba4..310c49506ae0 100644 --- a/usr.sbin/named/db_glue.c +++ b/usr.sbin/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 4.9.1.12 1994/07/22 08:42:39 vixie Exp $"; +static char rcsid[] = "$Id: db_glue.c,v 8.7 1995/06/29 09:26:17 vixie Exp $"; #endif /* not lint */ /* @@ -63,6 +63,7 @@ static char rcsid[] = "$Id: db_glue.c,v 4.9.1.12 1994/07/22 08:42:39 vixie Exp $ #include <sys/param.h> #include <sys/stat.h> #include <netinet/in.h> +#include <arpa/inet.h> #include <arpa/nameser.h> #include <stdio.h> #include <syslog.h> @@ -70,6 +71,7 @@ static char rcsid[] = "$Id: db_glue.c,v 4.9.1.12 1994/07/22 08:42:39 vixie Exp $ #include <netdb.h> #include <resolv.h> #include <errno.h> +#include <signal.h> #include "named.h" @@ -91,6 +93,37 @@ static const int (*unused_junk)__P((const u_char *, int, u_char *, int)) = ; #endif +/*XXX: sin_ntoa() should probably be in libc*/ +const char * +sin_ntoa(sin) + const struct sockaddr_in *sin; +{ + static char ret[sizeof("[111.222.333.444].55555")]; + + if (!sin) + strcpy(ret, "[sin_ntoa(NULL)]"); + else + sprintf(ret, "[%s].%u", + inet_ntoa(sin->sin_addr), ntohs(sin->sin_port)); + return (ret); +} + +/* + * XXX: some day we'll make this a varargs function + */ +void +panic(err, msg) + int err; + const char *msg; +{ + if (err == -1) + syslog(LOG_CRIT, "%s - ABORT", msg); + else + syslog(LOG_CRIT, "%s: %s - ABORT", msg, strerror(err)); + signal(SIGIOT, SIG_DFL); + abort(); +} + void buildservicelist() { @@ -283,19 +316,19 @@ servicename(port, proto) return (ss->s_name); } -int +u_int db_getclev(origin) - char *origin; + const char *origin; { - int lev = 0; - dprintf(1, (ddt, "db_getclev of \"%s\"", origin)); + u_int lev = 0; + dprintf(12, (ddt, "db_getclev of \"%s\"", origin)); if (origin && *origin) lev++; while (origin && (origin = strchr(origin, '.'))) { origin++; lev++; } - dprintf(1, (ddt, " = %d\n", lev)); + dprintf(12, (ddt, " = %d\n", lev)); return (lev); } @@ -326,15 +359,17 @@ int my_close(fd) int fd; { - int s = close(fd); + int s; - if (s < 0) { - syslog(LOG_ERR, "close(%d) failed: %m", fd); - dprintf(3, (ddt, "close(%d) failed: %s\n", - fd, strerror(errno))); - } else { + do { + errno = 0; + s = close(fd); + } while (s < 0 && errno == EINTR); + + if (s < 0 && errno != EBADF) + syslog(LOG_INFO, "close(%d) failed: %m", fd); + else dprintf(3, (ddt, "close(%d) succeeded\n", fd)); - } return (s); } @@ -348,10 +383,10 @@ struct map { }; static struct map map_class[] = { - "in", C_IN, - "chaos", C_CHAOS, - "hs", C_HS, - NULL, 0, + { "in", C_IN }, + { "chaos", C_CHAOS }, + { "hs", C_HS }, + { NULL, 0 } }; int @@ -376,13 +411,10 @@ my_fclose(fp) int fd = fileno(fp), s = fclose(fp); - if (s < 0) { - syslog(LOG_ERR, "fclose(%d) failed: %m", fd); - dprintf(3, (ddt, "fclose(%d) failed: %s\n", - fd, strerror(errno))); - } else { + if (s < 0) + syslog(LOG_INFO, "fclose(%d) failed: %m", fd); + else dprintf(3, (ddt, "fclose(%d) succeeded\n", fd)); - } return (s); } @@ -391,19 +423,32 @@ my_fclose(fp) */ char * savestr(str) - char *str; + const char *str; { char *cp; cp = (char *)malloc(strlen(str) + 1); - if (cp == NULL) { - syslog(LOG_ERR, "savestr: %m"); - exit(1); - } + if (cp == NULL) + panic(errno, "savestr: malloc"); (void) strcpy(cp, str); return (cp); } +/* + * Uniform formatting of IP/UDP addresses. + */ +const char * +inet_etoa(sin) + const struct sockaddr_in *sin; +{ + static char retbuf[sizeof("[xxx.xxx.xxx.xxx].xxxxx")]; + + (void) sprintf(retbuf, "[%s].%u", + inet_ntoa(sin->sin_addr), + ntohs(sin->sin_port)); + return (retbuf); +} + int writemsg(rfd, msg, msglen) int rfd; @@ -438,8 +483,8 @@ rm_datum(dp, np, pdp) { register struct databuf *ndp = dp->d_next; - dprintf(3, (ddt, "rm_datum(%x, %x, %x) -> %x\n", - dp, np->n_data, pdp, ndp)); + dprintf(3, (ddt, "rm_datum(%lx, %lx, %lx) -> %lx\n", + (u_long)dp, (u_long)np->n_data, (u_long)pdp, (u_long)ndp)); #ifdef INVQ rminv(dp); #endif @@ -483,13 +528,10 @@ rm_name(np, pp, pnp) if ( (np->n_data && (msg = "data")) || (np->n_hash && (msg = "hash")) ) { - dprintf(1, (ddt, - "rm_name(%x(%s)): non-nil %s pointer\n", - np, np->n_dname?np->n_dname:"Nil", msg)); syslog(LOG_ERR, - "rm_name(%x(%s)): non-nil %s pointer\n", - np, np->n_dname?np->n_dname:"Nil", msg); - abort(); + "rm_name(%#lx(%s)): non-nil %s pointer\n", + (u_long)np, np->n_dname?np->n_dname:"Nil", msg); + panic(-1, "rm_name"); } /* unlink */ @@ -523,7 +565,7 @@ getname(np, buf, buflen) while (np != NULL) { if ((i = strlen(np->n_dname))+1 >= buflen) { *cp = '\0'; - syslog(LOG_ERR, "domain name too long: %s...\n", buf); + syslog(LOG_INFO, "domain name too long: %s...\n", buf); strcpy(buf, "Name_Too_Long"); return; } @@ -613,21 +655,20 @@ saveinv() ip = (struct invbuf *) malloc(sizeof(struct invbuf)); if (ip == NULL) { - syslog(LOG_ERR, "saveinv: %m"); + syslog(LOG_ERR, "saveinv: malloc: %m"); exit(1); } ip->i_next = NULL; bzero((char *)ip->i_dname, sizeof(ip->i_dname)); return (ip); } -#endif /*INVQ*/ /* * Compute hash value from data. */ int dhash(dp, dlen) - u_char *dp; + register const u_char *dp; int dlen; { register u_char *cp; @@ -638,9 +679,31 @@ dhash(dp, dlen) if (n > 8) n = 8; hval = 0; - for (cp = dp; --n >= 0; ) { + while (--n >= 0) { hval <<= 1; - hval += *cp++; + hval += *dp++; + } + return (hval % INVHASHSZ); +} +#endif /*INVQ*/ + +/* int + * nhash(name) + * compute hash for this name and return it; ignore case differences + */ +int +nhash(name) + register const char *name; +{ + register u_char ch; + register unsigned hval; + + hval = 0; + while ((ch = (u_char)*name++) != (u_char)'\0') { + if (isascii(ch) && isupper(ch)) + ch = tolower(ch); + hval <<= 1; + hval += ch; } return (hval % INVHASHSZ); } @@ -708,3 +771,422 @@ samedomain(a, b) * ignore trailing dots. */ return (strncasecmp(cp, b, lb)==0); } + +#ifdef LOC_RR +/* + * routines to convert between on-the-wire RR format and zone file format. + * Does not contain conversion to/from decimal degrees; divide or multiply + * by 60*60*1000 for that. + */ + +static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000, + 1000000,10000000,100000000,1000000000}; + +/* takes an XeY precision/size value, returns a string representation. */ +static const char * +precsize_ntoa(prec) + u_int8_t prec; +{ + static char retbuf[sizeof("90000000.00")]; + unsigned long val; + int mantissa, exponent; + + mantissa = (int)((prec >> 4) & 0x0f) % 10; + exponent = (int)((prec >> 0) & 0x0f) % 10; + + val = mantissa * poweroften[exponent]; + + (void) sprintf(retbuf,"%d.%.2d", val/100, val%100); + return (retbuf); +} + +/* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer. */ +static u_int8_t +precsize_aton(strptr) + char **strptr; +{ + unsigned int mval = 0, cmval = 0; + u_int8_t retval = 0; + register char *cp; + register int exponent; + register int mantissa; + + cp = *strptr; + + while (isdigit(*cp)) + mval = mval * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* centimeters */ + cp++; + if (isdigit(*cp)) { + cmval = (*cp++ - '0') * 10; + if (isdigit(*cp)) { + cmval += (*cp++ - '0'); + } + } + } + cmval = (mval * 100) + cmval; + + for (exponent = 0; exponent < 9; exponent++) + if (cmval < poweroften[exponent+1]) + break; + + mantissa = cmval / poweroften[exponent]; + if (mantissa > 9) + mantissa = 9; + + retval = (mantissa << 4) | exponent; + + *strptr = cp; + + return (retval); +} + +/* converts ascii lat/lon to unsigned encoded 32-bit number. moves pointer. */ +static u_int32_t +latlon2ul(latlonstrptr,which) + char **latlonstrptr; + int *which; +{ + register char *cp; + u_int32_t retval; + int deg = 0, min = 0, secs = 0, secsfrac = 0; + + cp = *latlonstrptr; + + while (isdigit(*cp)) + deg = deg * 10 + (*cp++ - '0'); + + while (isspace(*cp)) + cp++; + + if (!(isdigit(*cp))) + goto fndhemi; + + while (isdigit(*cp)) + min = min * 10 + (*cp++ - '0'); + + while (isspace(*cp)) + cp++; + + if (!(isdigit(*cp))) + goto fndhemi; + + while (isdigit(*cp)) + secs = secs * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* decimal seconds */ + cp++; + if (isdigit(*cp)) { + secsfrac = (*cp++ - '0') * 100; + if (isdigit(*cp)) { + secsfrac += (*cp++ - '0') * 10; + if (isdigit(*cp)) { + secsfrac += (*cp++ - '0'); + } + } + } + } + + while (!isspace(*cp)) /* if any trailing garbage */ + cp++; + + while (isspace(*cp)) + cp++; + + fndhemi: + switch (*cp) { + case 'N': case 'n': + case 'E': case 'e': + retval = ((unsigned)1<<31) + + (((((deg * 60) + min) * 60) + secs) * 1000) + + secsfrac; + break; + case 'S': case 's': + case 'W': case 'w': + retval = ((unsigned)1<<31) + - (((((deg * 60) + min) * 60) + secs) * 1000) + - secsfrac; + break; + default: + retval = 0; /* invalid value -- indicates error */ + break; + } + + switch (*cp) { + case 'N': case 'n': + case 'S': case 's': + *which = 1; /* latitude */ + break; + case 'E': case 'e': + case 'W': case 'w': + *which = 2; /* longitude */ + break; + default: + *which = 0; /* error */ + break; + } + + cp++; /* skip the hemisphere */ + + while (!isspace(*cp)) /* if any trailing garbage */ + cp++; + + while (isspace(*cp)) /* move to next field */ + cp++; + + *latlonstrptr = cp; + + return (retval); +} + +/* converts a zone file representation in a string to an RDATA on-the-wire + * representation. */ +u_int32_t +loc_aton(ascii, binary) + const char *ascii; + u_char *binary; +{ + const char *cp, *maxcp; + u_char *bcp; + + u_int32_t latit = 0, longit = 0, alt = 0; + u_int32_t lltemp1 = 0, lltemp2 = 0; + int altmeters = 0, altfrac = 0, altsign = 1; + u_int8_t hp = 0x16; /* default = 1e6 cm = 10000.00m = 10km */ + u_int8_t vp = 0x13; /* default = 1e3 cm = 10.00m */ + u_int8_t siz = 0x12; /* default = 1e2 cm = 1.00m */ + int which1 = 0, which2 = 0; + + cp = ascii; + maxcp = cp + strlen(ascii); + + lltemp1 = latlon2ul(&cp, &which1); + + lltemp2 = latlon2ul(&cp, &which2); + + switch (which1 + which2) { + case 3: /* 1 + 2, the only valid combination */ + if ((which1 == 1) && (which2 == 2)) { /* normal case */ + latit = lltemp1; + longit = lltemp2; + } else if ((which1 == 2) && (which2 == 1)) { /* reversed */ + longit = lltemp1; + latit = lltemp2; + } else { /* some kind of brokenness */ + return 0; + } + break; + default: /* we didn't get one of each */ + return 0; + } + + /* altitude */ + if (*cp == '-') { + altsign = -1; + cp++; + } + + if (*cp == '+') + cp++; + + while (isdigit(*cp)) + altmeters = altmeters * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* decimal meters */ + cp++; + if (isdigit(*cp)) { + altfrac = (*cp++ - '0') * 10; + if (isdigit(*cp)) { + altfrac += (*cp++ - '0'); + } + } + } + + alt = (10000000 + (altsign * (altmeters * 100 + altfrac))); + + while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */ + cp++; + + while (isspace(*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + siz = precsize_aton(&cp); + + while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */ + cp++; + + while (isspace(*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + hp = precsize_aton(&cp); + + while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */ + cp++; + + while (isspace(*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + vp = precsize_aton(&cp); + + defaults: + + bcp = binary; + *bcp++ = (u_int8_t) 0; /* version byte */ + *bcp++ = siz; + *bcp++ = hp; + *bcp++ = vp; + PUTLONG(latit,bcp); + PUTLONG(longit,bcp); + PUTLONG(alt,bcp); + + return (16); /* size of RR in octets */ +} + +/* takes an on-the-wire LOC RR and prints it in zone file (human readable) + format. */ +char * +loc_ntoa(binary,ascii) + const u_char *binary; + char *ascii; +{ + char tmpbuf[255*3]; + + register char *cp; + register const u_char *rcp; + + int latdeg, latmin, latsec, latsecfrac; + int longdeg, longmin, longsec, longsecfrac; + char northsouth, eastwest; + int altmeters, altfrac, altsign; + + const int referencealt = 100000 * 100; + + int32_t latval, longval, altval; + u_int32_t templ; + u_int8_t sizeval, hpval, vpval, versionval; + + char *sizestr, *hpstr, *vpstr; + + rcp = binary; + if (ascii) + cp = ascii; + else { + ascii = tmpbuf; + cp = tmpbuf; + } + + versionval = *rcp++; + + if (versionval) { + sprintf(cp,"; error: unknown LOC RR version"); + return (cp); + } + + sizeval = *rcp++; + + hpval = *rcp++; + vpval = *rcp++; + + GETLONG(templ,rcp); + latval = (templ - ((unsigned)1<<31)); + + GETLONG(templ,rcp); + longval = (templ - ((unsigned)1<<31)); + + GETLONG(templ,rcp); + if (templ < referencealt) { /* below WGS 84 spheroid */ + altval = referencealt - templ; + altsign = -1; + } else { + altval = templ - referencealt; + altsign = 1; + } + + if (latval < 0) { + northsouth = 'S'; + latval = -latval; + } + else + northsouth = 'N'; + + latsecfrac = latval % 1000; + latval = latval / 1000; + latsec = latval % 60; + latval = latval / 60; + latmin = latval % 60; + latval = latval / 60; + latdeg = latval; + + if (longval < 0) { + eastwest = 'W'; + longval = -longval; + } + else + eastwest = 'E'; + + longsecfrac = longval % 1000; + longval = longval / 1000; + longsec = longval % 60; + longval = longval / 60; + longmin = longval % 60; + longval = longval / 60; + longdeg = longval; + + altfrac = altval % 100; + altmeters = (altval / 100) * altsign; + + sizestr = savestr(precsize_ntoa(sizeval)); + hpstr = savestr(precsize_ntoa(hpval)); + vpstr = savestr(precsize_ntoa(vpval)); + + sprintf(cp, + "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm", + latdeg, latmin, latsec, latsecfrac, northsouth, + longdeg, longmin, longsec, longsecfrac, eastwest, + altmeters, altfrac, sizestr, hpstr, vpstr); + + free(sizestr); + free(hpstr); + free(vpstr); + + return (cp); +} + +#endif /* LOC_RR */ + +/* + * Since the fields in a "struct timeval" are longs, and the argument to ctime + * is a pointer to a time_t (which might not be a long), here's a bridge. + */ +char * +ctimel(l) + long l; +{ + time_t t = (time_t)l; + + return (ctime(&t)); +} + +/* + * This is nec'y for systems that croak when deref'ing unaligned pointers. + * SPARC is an example. + */ +struct in_addr +data_inaddr(data) + const u_char *data; +{ + struct in_addr ret; + + bcopy((char *)data, (char *)&ret, INADDRSZ); + return (ret); +} diff --git a/usr.sbin/named/db_load.c b/usr.sbin/named/db_load.c index dfd46e3af38f..5c361961ef5f 100644 --- a/usr.sbin/named/db_load.c +++ b/usr.sbin/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 4.9.1.18 1994/07/23 23:23:56 vixie Exp $"; +static char rcsid[] = "$Id: db_load.c,v 8.10 1995/07/04 06:35:12 vixie Exp $"; #endif /* not lint */ /* @@ -71,15 +71,17 @@ static char rcsid[] = "$Id: db_load.c,v 4.9.1.18 1994/07/23 23:23:56 vixie Exp $ #include <syslog.h> #include <ctype.h> #include <netdb.h> +#include <resolv.h> #include "named.h" -static int gettoken __P((register FILE *, char *)), - getnonblank __P((FILE *, char *)), - getprotocol __P((FILE *, char *)), - getservices __P((int, char *, FILE *, char *)); -static void makename __P((char *, char *)); +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 *)); +static void makename __P((char *, const char *)); static int empty_token = 0; +int getnum_error; /* * Map class and type names to number @@ -90,47 +92,52 @@ struct map { }; struct map m_class[] = { - "in", C_IN, + { "in", C_IN }, #ifdef notdef - "any", C_ANY, /* any is a QCLASS, not CLASS */ + { "any", C_ANY }, /* any is a QCLASS, not CLASS */ #endif - "chaos", C_CHAOS, - "hs", C_HS, + { "chaos", C_CHAOS }, + { "hs", C_HS }, }; -#define NCLASS (sizeof(m_class) / sizeof(struct map)) +#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, - "uid", T_UID, - "gid", T_GID, + { "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 }, #ifdef notdef - "any", T_ANY, /* any is a QTYPE, not TYPE */ + { "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, + { "unspec", T_UNSPEC }, #endif /* ALLOW_T_UNSPEC */ }; -#define NTYPE (sizeof(m_type) / sizeof(struct map)) +#define M_TYPE_CNT (sizeof(m_type) / sizeof(struct map)) /* * Parser token values @@ -146,21 +153,22 @@ struct map m_type[] = { static int clev; /* a zone deeper in a heirachy has more credability */ /* int - * db_load(filename, in_origin, zp, doinginclude) - * load a database from `filename' into zone `zp'. append `origin' - * to all nonterminal domain names in the file. `doinginclude' is - * true if this is a $INCLUDE file. + * db_load(filename, in_origin, zp, def_domain) + * load a database from `filename' into zone `zp'. append `in_origin' + * to all nonterminal domain names in the file. `def_domain' is the + * default domain for include files or NULL for zone base files. * returns: * -1 = can't open file * 0 = success * >0 = number of errors encountered */ int -db_load(filename, in_origin, zp, doinginclude) - char *filename, *in_origin; +db_load(filename, in_origin, zp, def_domain) + const char *filename, *in_origin; struct zoneinfo *zp; - int doinginclude; + const char *def_domain; { + static int read_soa, read_ns; register char *cp; register struct map *mp; char domain[MAXDNAME]; @@ -168,28 +176,35 @@ db_load(filename, in_origin, zp, doinginclude) char tmporigin[MAXDNAME]; char buf[MAXDATA]; char data[MAXDATA]; - char *cp1; - char *op; + const char *cp1, *op; int c, class, type, ttl, dbflags, dataflags, multiline; - static int read_soa; /* number of soa's read */ struct databuf *dp; FILE *fp; - int slineno, i, errs = 0, didinclude = 0; + int slineno, i, errs, didinclude, rrcount; register u_int32_t n; struct stat sb; struct in_addr ina; +#ifdef DO_WARN_SERIAL + u_int32_t serial; +#endif - if (!doinginclude) { - read_soa = 0; - clev = db_getclev(in_origin); + errs = 0; + didinclude = 0; + rrcount = 0; + if (!def_domain) { + /* This is not the result of a $INCLUDE. */ + read_soa = 0; + read_ns = 0; + clev = db_getclev(in_origin); } - dprintf(1, (ddt,"db_load(%s, %s, %d, %d)\n", - filename, in_origin, zp - zones, doinginclude)); + dprintf(1, (ddt,"db_load(%s, %s, %d, %s)\n", + filename, in_origin, zp - zones, + def_domain ? def_domain : "Nil")); (void) strcpy(origin, in_origin); if ((fp = fopen(filename, "r")) == NULL) { - syslog(LOG_ERR, "%s: %m", filename); + syslog(LOG_NOTICE, "%s: %m", filename); dprintf(1, (ddt, "db_load: error opening file %s\n", filename)); return (-1); @@ -197,18 +212,26 @@ db_load(filename, in_origin, zp, doinginclude) if (zp->z_type == Z_CACHE) { dbflags = DB_NODATA | DB_NOHINTS; dataflags = DB_F_HINT; +#ifdef STUBS + } else if (zp->z_type == Z_STUB && clev == 0) { + dbflags = DB_NODATA | DB_NOHINTS; + dataflags = DB_F_HINT; +#endif } else { dbflags = DB_NODATA; dataflags = 0; } gettime(&tt); if (fstat(fileno(fp), &sb) < 0) { - syslog(LOG_ERR, "%s: %m", filename); + syslog(LOG_NOTICE, "%s: %m", filename); sb.st_mtime = (int)tt.tv_sec; } slineno = lineno; lineno = 1; - domain[0] = '\0'; + if (def_domain) + strcpy(domain, def_domain); + else + domain[0] = '\0'; class = zp->z_class; zp->z_flags &= ~(Z_INCLUDE|Z_DB_BAD); while ((c = gettoken(fp, filename)) != EOF) { @@ -224,7 +247,7 @@ db_load(filename, in_origin, zp, doinginclude) endline(fp); } didinclude = 1; - errs += db_load((char *)buf, tmporigin, zp, 1); + errs += db_load((char *)buf, tmporigin, zp, domain); continue; case ORIGIN: @@ -255,7 +278,7 @@ db_load(filename, in_origin, zp, doinginclude) case DOT: domain[0] = '\0'; - /* fall thru ... */ + /* FALLTHROUGH */ case CURRENT: gotdomain: if (!getword((char *)buf, sizeof(buf), fp)) { @@ -269,12 +292,9 @@ db_load(filename, in_origin, zp, doinginclude) n = 0; do { if (n > (INT_MAX - (*cp - '0')) / 10) { - syslog(LOG_ERR, + syslog(LOG_INFO, "%s: line %d: number > %lu\n", - filename, lineno, INT_MAX); - dprintf(1, (ddt, - "%s: line %d: number > %lu\n", - filename, lineno, INT_MAX)); + filename, lineno, (u_long)INT_MAX); n = INT_MAX; cp++; } else @@ -292,14 +312,14 @@ db_load(filename, in_origin, zp, doinginclude) if (!getword((char *)buf, sizeof(buf), fp)) break; } - for (mp = m_class; mp < m_class+NCLASS; mp++) + 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); break; } - for (mp = m_type; mp < m_type+NTYPE; mp++) + for (mp = m_type; mp < m_type+M_TYPE_CNT; mp++) if (!strcasecmp((char *)buf, mp->token)) { type = mp->val; goto fndtype; @@ -307,7 +327,7 @@ db_load(filename, in_origin, zp, doinginclude) dprintf(1, (ddt, "%s: Line %d: Unknown type: %s.\n", filename, lineno, buf)); errs++; - syslog(LOG_ERR, "%s: Line %d: Unknown type: %s.\n", + syslog(LOG_INFO, "%s: Line %d: Unknown type: %s.\n", filename, lineno, buf); break; fndtype: @@ -344,9 +364,10 @@ db_load(filename, in_origin, zp, doinginclude) case T_ISDN: n = strlen((char *)buf); if (n > 255) { - syslog(LOG_WARNING, - "%s: line %d: CPU type too long", - filename, lineno); + syslog(LOG_INFO, + "%s: line %d: %s too long", + filename, lineno, (type == T_ISDN) ? + "ISDN-address" : "CPU type"); n = 255; } data[0] = n; @@ -361,16 +382,26 @@ db_load(filename, in_origin, zp, doinginclude) i = strlen((char *)buf); } if (i == 0) { - /* goto err; */ - /* XXX tolerate for now */ - data[n++] = 1; - data[n++] = '?'; - break; + 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_WARNING, - "%s:%d: OS type too long", - filename, lineno); + syslog(LOG_INFO, + "%s:%d: %s too long", + filename, lineno, (type == T_ISDN) ? + "ISDN-sa" : "OS type"); i = 255; } data[n] = i; @@ -385,7 +416,7 @@ db_load(filename, in_origin, zp, doinginclude) makename(data, origin); cp = data + strlen((char *)data) + 1; if (!getword((char *)cp, - sizeof(data) - (cp - data), fp)) + (sizeof data) - (cp - data), fp)) goto err; makename(cp, origin); cp += strlen((char *)cp) + 1; @@ -394,11 +425,19 @@ db_load(filename, in_origin, zp, doinginclude) break; } if (class != zp->z_class) { - syslog(LOG_WARNING, + errs++; + syslog(LOG_INFO, "%s:%d: %s", filename, lineno, "SOA class not same as zone's"); } + if (strcasecmp(zp->z_origin, domain) != 0) { + errs++; + syslog(LOG_ERR, + "%s: line %d: SOA for \"%s\" not at zone top \"%s\"", + filename, lineno, domain, + zp->z_origin); + } c = getnonblank(fp, filename); if (c == '(') { multiline = 1; @@ -406,10 +445,29 @@ db_load(filename, in_origin, zp, doinginclude) multiline = 0; ungetc(c, fp); } - zp->z_serial = getnum(fp, filename, 1); +#ifdef DO_WARN_SERIAL + serial = zp->z_serial; +#endif + zp->z_serial = getnum(fp, filename, + GETNUM_SERIAL); + if (getnum_error) + errs++; n = (u_int32_t) zp->z_serial; PUTLONG(n, cp); - zp->z_refresh = getnum(fp, filename, 0); +#ifdef DO_WARN_SERIAL + if (serial && SEQ_GT(serial, zp->z_serial)) { + syslog(LOG_NOTICE, + "%s:%d: WARNING: new serial number < old (%lu < %lu)", + filename , lineno, + zp->z_serial, serial); + } +#endif + zp->z_refresh = getnum(fp, filename, + GETNUM_NONE); + if (getnum_error) { + errs++; + zp->z_refresh = INIT_REFRESH; + } n = (u_int32_t) zp->z_refresh; PUTLONG(n, cp); if (zp->z_type == Z_SECONDARY @@ -417,16 +475,31 @@ db_load(filename, in_origin, zp, doinginclude) || zp->z_type == Z_STUB #endif ) { - zp->z_time = sb.st_mtime - + zp->z_refresh; + ns_refreshtime(zp, MIN(sb.st_mtime, + tt.tv_sec)); + } + zp->z_retry = getnum(fp, filename, + GETNUM_NONE); + if (getnum_error) { + errs++; + zp->z_retry = INIT_REFRESH; } - zp->z_retry = getnum(fp, filename, 0); n = (u_int32_t) zp->z_retry; PUTLONG(n, cp); - zp->z_expire = getnum(fp, filename, 0); + zp->z_expire = getnum(fp, filename, + GETNUM_NONE); + if (getnum_error) { + errs++; + zp->z_expire = INIT_REFRESH; + } n = (u_int32_t) zp->z_expire; PUTLONG (n, cp); - zp->z_minimum = getnum(fp, filename, 0); + zp->z_minimum = getnum(fp, filename, + GETNUM_NONE); + if (getnum_error) { + errs++; + zp->z_minimum = 120; + } n = (u_int32_t) zp->z_minimum; PUTLONG (n, cp); n = cp - data; @@ -435,6 +508,11 @@ db_load(filename, in_origin, zp, doinginclude) goto err; } read_soa++; + if (zp->z_expire < zp->z_refresh ) { + syslog(LOG_WARNING, + "%s: WARNING SOA expire value is less then SOA refresh (%lu < %lu)", + filename, zp->z_expire, zp->z_refresh); + } endline(fp); break; @@ -466,6 +544,9 @@ db_load(filename, in_origin, zp, doinginclude) break; case T_NS: + if (strcasecmp(zp->z_origin, domain) == 0) + read_ns++; + /* FALLTHROUGH */ case T_CNAME: case T_MB: case T_MG: @@ -478,7 +559,7 @@ db_load(filename, in_origin, zp, doinginclude) case T_UINFO: cp = strchr((char *)buf, '&'); - bzero(data, sizeof(data)); + bzero(data, sizeof data); if ( cp != NULL) { (void) strncpy((char *)data, (char *)buf, cp - buf); @@ -521,19 +602,37 @@ db_load(filename, in_origin, zp, doinginclude) n = (cp - data); break; + case T_PX: + n = 0; + data[0] = '\0'; + cp = buf; + 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); + + if (!getword((char *)buf, sizeof(buf), fp)) + goto err; + (void) strcpy((char *)cp, (char *)buf); + makename(cp, origin); + /* advance pointer to next field */ + cp += strlen((char *)cp) +1; + if (!getword((char *)buf, sizeof(buf), fp)) + goto err; + (void) strcpy((char *)cp, (char *)buf); + makename(cp, origin); + /* advance pointer to end of data */ + cp += strlen((char *)cp) + 1; + + /* now save length */ + n = (cp - data); + break; + case T_TXT: case T_X25: - cp = buf + (n = strlen(buf)); - while ((i = getc(fp), *cp = i, i != EOF) - && *cp != '\n' - && (n < MAXDATA)) { - cp++; n++; - } - if (*cp == '\n') /* leave \n for getword */ - ungetc(*cp, fp); - *cp = '\0'; - /* now do normal processing */ - i = strlen((char *)buf); cp = data; cp1 = buf; @@ -541,11 +640,11 @@ db_load(filename, in_origin, zp, doinginclude) * there is expansion here so make sure we * don't overflow data */ - if (i > sizeof(data) * 255 / 256) { - syslog(LOG_WARNING, + if (i > (sizeof data) * 255 / 256) { + syslog(LOG_INFO, "%s: line %d: TXT record truncated", filename, lineno); - i = sizeof(data) * 255 / 256; + i = (sizeof data) * 255 / 256; } while (i > 255) { *cp++ = 255; @@ -562,11 +661,32 @@ db_load(filename, in_origin, zp, doinginclude) break; case T_NSAP: - n = inet_nsap_addr(buf, data, MAXDATA); + n = inet_nsap_addr(buf, (u_char *)data, + sizeof data); if (n == 0) goto err; endline(fp); break; +#ifdef LOC_RR + case T_LOC: + cp = buf + (n = strlen(buf)); + *cp = ' '; + cp++; + while ((i = getc(fp), *cp = i, i != EOF) + && *cp != '\n' + && (n < MAXDATA)) { + cp++; n++; + } + if (*cp == '\n') /* leave \n for getword */ + ungetc(*cp, fp); + *cp = '\0'; + /* now process the whole line */ + n = loc_aton(buf, (u_char *)data); + if (n == 0) + goto err; + endline(fp); + break; +#endif /* LOC_RR */ #ifdef ALLOW_T_UNSPEC case T_UNSPEC: { @@ -575,25 +695,15 @@ db_load(filename, in_origin, zp, doinginclude) dprintf(1, (ddt, "loading T_UNSPEC\n")); if (rcode = atob(buf, strlen((char*)buf), - data, sizeof(data), + data, sizeof data, &n)) { if (rcode == CONV_OVERFLOW) { - dprintf(1, - (ddt, - "Load T_UNSPEC: input buffer overflow\n" - ) - ); errs++; - syslog(LOG_ERR, + syslog(LOG_INFO, "Load T_UNSPEC: input buffer overflow"); } else { - dprintf(1, - (ddt, - "Load T_UNSPEC: Data in bad atob format\n" - ) - ); errs++; - syslog(LOG_ERR, + syslog(LOG_INFO, "Load T_UNSPEC: Data in bad atob format"); } } @@ -604,10 +714,12 @@ db_load(filename, in_origin, zp, doinginclude) default: goto err; } +#ifndef PURGE_ZONE #ifdef STUBS if (type == T_SOA && zp->z_type == Z_STUB) continue; #endif +#endif #ifdef NO_GLUE /* * Ignore data outside the zone. @@ -615,13 +727,12 @@ db_load(filename, in_origin, zp, doinginclude) if (zp->z_type != Z_CACHE && !samedomain(domain, zp->z_origin)) { - syslog(LOG_WARNING, + syslog(LOG_INFO, "%s:%d: data \"%s\" outside zone \"%s\" (ignored)", filename, lineno, domain, zp->z_origin); continue; } #endif /*NO_GLUE*/ - dp = savedata(class, type, (u_int32_t)ttl, (u_char *)data, (int)n); dp->d_zone = zp - zones; @@ -639,55 +750,75 @@ db_load(filename, in_origin, zp, doinginclude) domain, type); #endif free((char*) dp); + } else { + rrcount++; } continue; case ERROR: break; } - err: + err: errs++; - syslog(LOG_ERR, "%s: line %d: database format error (%s)", + syslog(LOG_NOTICE, "%s: line %d: database format error (%s)", filename, empty_token ? (lineno - 1) : lineno, buf); - dprintf(1, (ddt, - "%s: line %d: database format error ('%s', %d)\n", - filename, empty_token ? (lineno - 1) : lineno, - buf, n)); - while ((c = getc(fp)) != EOF && c != '\n') - ; - if (c == '\n') - lineno++; + if (!empty_token) + endline(fp); } (void) my_fclose(fp); lineno = slineno; - if (doinginclude == 0) { + if (!def_domain) { if (didinclude) { zp->z_flags |= Z_INCLUDE; zp->z_ftime = 0; } else zp->z_ftime = sb.st_mtime; zp->z_lastupdate = sb.st_mtime; - if (zp->z_type != Z_CACHE && read_soa != 1) { - errs++; + if (zp->z_type != Z_CACHE) { + const char *msg = NULL; + if (read_soa == 0) - syslog(LOG_ERR, "%s: no SOA record", filename); - else - syslog(LOG_ERR, "%s: multiple SOA records", - filename); + msg = "no SOA RR found"; + else if (read_soa != 1) + msg = "multiple SOA RRs found"; + else if (read_ns == 0) + msg = "no NS RRs found at zone top"; + else if (!rrcount) + msg = "no relevant RRs found"; + if (msg != NULL) { + errs++; + syslog(LOG_NOTICE, "Zone \"%s\" (file %s): %s", + zp->z_origin, filename, msg); + } } } #ifdef SECURE_ZONES build_secure_netlist(zp); #endif + if (!def_domain) + syslog(LOG_INFO, + "%s zone \"%s\" %s (serial %lu)", + zoneTypeString(zp), zp->z_origin, + errs ? "rejected due to errors" : "loaded", + (u_long)zp->z_serial); if (errs) zp->z_flags |= Z_DB_BAD; +#ifdef BIND_NOTIFY + /* XXX: this needs to be delayed, both according to the spec, and + * because the metadata needed by sysnotify() (and its sysquery()) + * could be in other zones that we (at startup) havn't loaded yet. + */ + if (!errs && !def_domain && + (zp->z_type == Z_PRIMARY || zp->z_type == Z_SECONDARY)) + sysnotify(zp->z_origin, zp->z_class, T_SOA); +#endif return (errs); } static int gettoken(fp, src) register FILE *fp; - char *src; + const char *src; { register int c; char op[32]; @@ -706,10 +837,8 @@ gettoken(fp, src) if (!strcasecmp("origin", op)) return (ORIGIN); } - dprintf(1, (ddt, - "%s: line %d: Unknown $ option: $%s\n", - src, lineno, op)); - syslog(LOG_ERR,"%s: line %d: Unknown $ option: $%s\n", + syslog(LOG_NOTICE, + "%s: line %d: Unknown $ option: $%s\n", src, lineno, op); return (ERROR); @@ -845,10 +974,10 @@ smaller than "1.23" in their internal expressions. */ int -getnum(fp, src, is_serial) +getnum(fp, src, opt) FILE *fp; - char *src; - int is_serial; + const char *src; + int opt; { register int c, n; int seendigit = 0; @@ -856,8 +985,10 @@ getnum(fp, src, is_serial) int m = 0; int allow_dots = 0; + getnum_error = 0; #ifdef DOTTED_SERIAL - allow_dots += is_serial; + if (opt & GETNUM_SERIAL) + allow_dots++; #endif for (n = 0; (c = getc(fp)) != EOF; ) { if (isspace(c)) { @@ -876,24 +1007,39 @@ getnum(fp, src, is_serial) break; continue; } + if (getnum_error) + continue; if (!isdigit(c)) { if (c == ')' && seendigit) { (void) ungetc(c, fp); break; } + if (seendigit && (opt & GETNUM_SCALED) && + strchr("KkMmGg", c) != NULL) { + switch (c) { + case 'K': case 'k': + n *= 1024; + break; + case 'M': case 'm': + n *= (1024 * 1024); + break; + case 'G': case 'g': + n *= (1024 * 1024 * 1024); + break; + } + break; + } if (seendecimal || c != '.' || !allow_dots) { - syslog(LOG_ERR, "%s:%d: expected a number", + syslog(LOG_NOTICE, "%s:%d: expected a number", src, lineno); - dprintf(1, (ddt, "%s:%d: expected a number", - src, lineno)); - exit(1); /* XXX why exit here?? */ + getnum_error = 1; } else { if (!seendigit) n = 1; #ifdef SENSIBLE_DOTS - n = n * 10000; + n *= 10000; #else - n = n * 1000; + n *= 1000; #endif seendigit = 1; seendecimal = 1; @@ -910,14 +1056,14 @@ getnum(fp, src, is_serial) #endif seendigit = 1; } + if (getnum_error) + return (0); if (m > 9999) { - syslog(LOG_ERR, + syslog(LOG_INFO, "%s:%d: number after the decimal point exceeds 9999", src, lineno); - dprintf(1, (ddt, - "%s:%d: number after the decimal point exceeds 9999", - src, lineno)); - exit(1); /* XXX why exit here?? */ + getnum_error = 1; + return (0); } if (seendecimal) { syslog(LOG_INFO, @@ -930,7 +1076,7 @@ getnum(fp, src, is_serial) static int getnonblank(fp, src) FILE *fp; - char *src; + const char *src; { register int c; @@ -949,8 +1095,7 @@ getnonblank(fp, src) } return(c); } - syslog(LOG_ERR, "%s: line %d: unexpected EOF", src, lineno); - dprintf(1, (ddt, "%s: line %d: unexpected EOF", src, lineno)); + syslog(LOG_INFO, "%s: line %d: unexpected EOF", src, lineno); return (EOF); } @@ -963,7 +1108,8 @@ getnonblank(fp, src) */ static void makename(name, origin) - char *name, *origin; + char *name; + const char *origin; { int n; @@ -996,7 +1142,7 @@ endline(fp) { register int c; - while (c = getc(fp)) { + while ((c = getc(fp)) != '\0') { if (c == '\n') { (void) ungetc(c,fp); break; @@ -1006,13 +1152,13 @@ endline(fp) } } -#define MAXPORT 256 +#define MAXPORT 1024 #define MAXLEN 24 static int getprotocol(fp, src) FILE *fp; - char *src; + const char *src; { int k; char b[MAXLEN]; @@ -1020,17 +1166,18 @@ getprotocol(fp, src) (void) getword(b, sizeof(b), fp); k = protocolnumber(b); - if(k == -1) - syslog(LOG_ERR, "%s: line %d: unknown protocol: %s.", - src, lineno, b); + if (k == -1) + syslog(LOG_INFO, "%s: line %d: unknown protocol: %s.", + src, lineno, b); return(k); } static int getservices(n, data, fp, src) int n; - char *data, *src; + char *data; FILE *fp; + const char *src; { int j, ch; int k; @@ -1062,7 +1209,7 @@ getservices(n, data, fp, src) } k = servicenumber(b); if (k == -1) { - syslog(LOG_WARNING, + syslog(LOG_INFO, "%s: line %d: Unknown service '%s'", src, lineno, b); continue; @@ -1073,20 +1220,20 @@ getservices(n, data, fp, src) maxl=k; } else { - syslog(LOG_WARNING, - "%s: line %d: port no. (%d) too big\n", - src, lineno, k); + syslog(LOG_INFO, + "%s: line %d: port no. (%d) too big\n", + src, lineno, k); dprintf(1, (ddt, "%s: line %d: port no. (%d) too big\n", src, lineno, k)); } } if (bracket) - syslog(LOG_WARNING, "%s: line %d: missing close paren\n", - src, lineno); + syslog(LOG_INFO, "%s: line %d: missing close paren\n", + src, lineno); maxl = maxl/8+1; bcopy(bm, data+n, maxl); - return(maxl+n); + return (maxl+n); } /* get_netlist(fp, netlistp, allow) @@ -1102,10 +1249,13 @@ get_netlist(fp, netlistp, allow, print_tag) int allow; char *print_tag; { - struct netinfo *ntp = NULL, **end = netlistp; + struct netinfo *ntp, **end; char buf[BUFSIZ], *maskp; struct in_addr ina; + for (end = netlistp; *end; end = &(**end).next) + ; + ntp = NULL; dprintf(1, (ddt, "get_netlist(%s)", print_tag)); while (getword(buf, sizeof(buf), fp)) { if (strlen(buf) == 0) @@ -1117,13 +1267,13 @@ get_netlist(fp, netlistp, allow, print_tag) ntp = (struct netinfo *)malloc(sizeof(struct netinfo)); } if (!inet_aton(buf, &ntp->my_addr)) { - syslog(LOG_ERR, "%s contains bogus element (%s)", + syslog(LOG_INFO, "%s contains bogus element (%s)", print_tag, buf); continue; } if (maskp) { if (!inet_aton(maskp, &ina)) { - syslog(LOG_ERR, + syslog(LOG_INFO, "%s element %s has bad mask (%s)", print_tag, buf, maskp); continue; @@ -1144,7 +1294,7 @@ get_netlist(fp, netlistp, allow, print_tag) if (ntp->addr != ntp->my_addr.s_addr) { ina.s_addr = ntp->addr; - syslog(LOG_WARNING, + syslog(LOG_INFO, "%s element (%s) mask problem (%s)", print_tag, buf, inet_ntoa(ina)); } @@ -1160,11 +1310,13 @@ get_netlist(fp, netlistp, allow, print_tag) #ifdef DEBUG if (debug > 2) for (ntp = *netlistp; ntp != NULL; ntp = ntp->next) { - fprintf(ddt, "ntp x%x addr x%x mask x%x", - ntp, ntp->addr, ntp->mask); - fprintf(ddt, " my_addr x%x", ntp->my_addr); + fprintf(ddt, "ntp x%lx addr x%lx mask x%lx", + (u_long)ntp, (u_long)ntp->addr, + (u_long)ntp->mask); + fprintf(ddt, " my_addr x%lx", + (u_long)ntp->my_addr.s_addr); fprintf(ddt, " %s", inet_ntoa(ntp->my_addr)); - fprintf(ddt, " next x%x\n", ntp->next); + fprintf(ddt, " next x%lx\n", (u_long)ntp->next); } #endif } diff --git a/usr.sbin/named/db_lookup.c b/usr.sbin/named/db_lookup.c index 9084491c9137..db7cd97623d5 100644 --- a/usr.sbin/named/db_lookup.c +++ b/usr.sbin/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 4.9.1.5 1994/06/01 21:09:39 vixie Exp $"; +static char rcsid[] = "$Id: db_lookup.c,v 8.2 1995/06/29 09:26:17 vixie Exp $"; #endif /* not lint */ /* @@ -79,13 +79,13 @@ static char rcsid[] = "$Id: db_lookup.c,v 4.9.1.5 1994/06/01 21:09:39 vixie Exp */ struct namebuf * nlookup(name, htpp, fname, insert) - char *name; + const char *name; struct hashbuf **htpp; - char **fname; + const char **fname; int insert; { register struct namebuf *np; - register char *cp; + register const char *cp; register int c; register unsigned hval; register struct hashbuf *htp; @@ -117,8 +117,7 @@ nlookup(name, htpp, fname, insert) hval <<= HASHSHIFT; hval += (isupper(c) ? tolower(c) : c) & HASHMASK; } - c = *--cp; - *cp = '\0'; + cp--; /* * Lookup this label in current hash table. */ @@ -126,9 +125,8 @@ nlookup(name, htpp, fname, insert) np != NULL; np = np->n_next) { if (np->n_hashval == hval && - strcasecmp(name, np->n_dname) == 0) { + strncasecmp(name, np->n_dname, cp - name) == 0) { *fname = name; - *cp = c; return (np); } } @@ -143,14 +141,12 @@ nlookup(name, htpp, fname, insert) if (np->n_dname[0] == '*' && np->n_dname[1] == '\0' && np->n_data && np->n_data->d_zone != 0) { *fname = name; - *cp = c; return (np); } } - *cp = c; return (parent); } - np = savename(name); + np = savename(name, cp - name); np->n_parent = parent; np->n_hashval = hval; hval %= htp->h_size; @@ -171,7 +167,6 @@ nlookup(name, htpp, fname, insert) htp = *htpp; } *fname = name; - *cp = c; return (np); } @@ -186,8 +181,8 @@ match(dp, class, type) register struct databuf *dp; register int class, type; { - dprintf(5, (ddt, "match(0x%x, %d, %d) %d, %d\n", - dp, class, type, dp->d_class, dp->d_type)); + dprintf(5, (ddt, "match(0x%lx, %d, %d) %d, %d\n", + (u_long)dp, class, type, dp->d_class, dp->d_type)); if (dp->d_class != class && class != C_ANY) return (0); if (dp->d_type != type && type != T_ANY) diff --git a/usr.sbin/named/db_reload.c b/usr.sbin/named/db_reload.c index 1b962a63fdc2..ca420086d393 100644 --- a/usr.sbin/named/db_reload.c +++ b/usr.sbin/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 4.9.1.4 1994/07/02 16:28:11 vixie Exp $"; +static char rcsid[] = "$Id: db_reload.c,v 8.1 1994/12/15 06:24:14 vixie Exp $"; #endif /* not lint */ /* diff --git a/usr.sbin/named/db_save.c b/usr.sbin/named/db_save.c index cd1639d6ec76..868ab1fcf385 100644 --- a/usr.sbin/named/db_save.c +++ b/usr.sbin/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 4.9.1.7 1994/07/22 08:42:39 vixie Exp $"; +static char rcsid[] = "$Id: db_save.c,v 8.2 1995/06/29 09:26:17 vixie Exp $"; #endif /* not lint */ /* @@ -68,6 +68,7 @@ static char rcsid[] = "$Id: db_save.c,v 4.9.1.7 1994/07/22 08:42:39 vixie Exp $" #include <arpa/nameser.h> #include <syslog.h> #include <stdio.h> +#include <errno.h> #include "named.h" @@ -75,20 +76,21 @@ static char rcsid[] = "$Id: db_save.c,v 4.9.1.7 1994/07/22 08:42:39 vixie Exp $" * Allocate a name buffer & save name. */ struct namebuf * -savename(name) - char *name; +savename(name, len) + const char *name; + int len; { register struct namebuf *np; np = (struct namebuf *) malloc(sizeof(struct namebuf)); - if (np == NULL) { - syslog(LOG_ERR, "savename: %m"); - exit(1); - } - np->n_dname = savestr(name); - np->n_next = NULL; - np->n_data = NULL; - np->n_hash = NULL; + if (np == NULL) + panic(errno, "savename: malloc"); + bzero((char*)np, sizeof(struct namebuf)); + np->n_dname = malloc(len + 1); + if (np == NULL) + panic(errno, "savename: malloc"); + strncpy(np->n_dname, name, len); + np->n_dname[len] = '\0'; return (np); } @@ -109,27 +111,18 @@ savedata(class, type, ttl, data, size) int size; { register struct databuf *dp; + int bytes = (type == T_NS) ? DATASIZE(size)+INT32SZ : DATASIZE(size); - if (type == T_NS) - dp = (struct databuf *) + dp = (struct databuf *) #ifdef DMALLOC - dmalloc(file, line, + dmalloc(file, line, bytes) #else - malloc( + malloc(bytes) #endif - (unsigned)DATASIZE(size)+INT32SZ); - else - dp = (struct databuf *) -#ifdef DMALLOC - dmalloc(file, line, -#else - malloc( -#endif - (unsigned)DATASIZE(size)); - if (dp == NULL) { - syslog(LOG_ERR, "savedata: %m"); - exit(1); - } + ; + if (dp == NULL) + panic(errno, "savedata: malloc"); + bzero((char*)dp, bytes); dp->d_next = NULL; dp->d_type = type; dp->d_class = class; @@ -198,8 +191,8 @@ savehash(oldhtp) htp->h_cnt = 0; return (htp); } - dprintf(4, (ddt, "savehash(%#x) cnt=%d, sz=%d, newsz=%d\n", - oldhtp, oldhtp->h_cnt, oldhtp->h_size, newsize)); + dprintf(4, (ddt, "savehash(%#lx) cnt=%d, sz=%d, newsz=%d\n", + (u_long)oldhtp, oldhtp->h_cnt, oldhtp->h_size, newsize)); htp->h_cnt = oldhtp->h_cnt; for (n = 0; n < oldhtp->h_size; n++) { for (np = oldhtp->h_tab[n]; np != NULL; np = nnp) { diff --git a/usr.sbin/named/db_secure.c b/usr.sbin/named/db_secure.c index b3eb73148560..9c418f451afb 100644 --- a/usr.sbin/named/db_secure.c +++ b/usr.sbin/named/db_secure.c @@ -1,5 +1,5 @@ #ifndef LINT -static char rcsid[] = "$Id: db_secure.c,v 1.6 1994/07/23 23:23:56 vixie Exp $"; +static char rcsid[] = "$Id: db_secure.c,v 8.4 1995/06/29 09:26:17 vixie Exp $"; #endif /* this file was contributed by Gregory Neil Shapiro of WPI in August 1993 */ @@ -32,7 +32,8 @@ build_secure_netlist(zp) struct hashbuf *htp; struct namebuf *snp; struct databuf *dp; - char *fname, *dname, dnbuf[MAXDNAME]; + const char *fname; + char *dname, dnbuf[MAXDNAME]; int errs = 0, securezone = 0; if (zp->secure_nets) { @@ -59,7 +60,7 @@ build_secure_netlist(zp) /* Collect secure nets into secure_nets */ for (dp = snp->n_data; dp != NULL; dp = dp->d_next) { char *maskptr = NULL; - if (!match(dp, C_ANY, T_TXT)) { + if (!match(dp, zp->z_class, T_TXT)) { continue; } bzero(buf, sizeof(buf)); @@ -77,20 +78,17 @@ build_secure_netlist(zp) dprintf(1, (ddt, "build_secure_netlist (%s): malloc fail\n", zp->z_origin)); - syslog(LOG_ERR, + syslog(LOG_NOTICE, "build_secure_netlist (%s): Out of Memory", zp->z_origin); if (!securezone) { - zp->secure_nets=NULL; + zp->secure_nets = NULL; } - return(1); + return (1); } } if (!inet_aton(buf, &ntp->my_addr)) { - dprintf(1, (ddt, - "build_secure_netlist (%s): Bad address: %s\n", - zp->z_origin, buf)); - syslog(LOG_ERR, + syslog(LOG_INFO, "build_secure_netlist (%s): Bad address: %s", zp->z_origin, buf); errs++; @@ -105,7 +103,7 @@ build_secure_netlist(zp) dprintf(1, (ddt, "build_secure_netlist (%s): Bad mask: %s\n", zp->z_origin, maskptr)); - syslog(LOG_ERR, + syslog(LOG_INFO, "build_secure_netlist (%s): Bad mask: %s", zp->z_origin, maskptr); errs++; @@ -116,16 +114,11 @@ build_secure_netlist(zp) ntp->mask = net_mask(ntp->my_addr); } if (ntp->my_addr.s_addr & ~(ntp->mask)) { - dprintf(1, (ddt, - "build_secure_netlist (%s): addr (%s) is not in mask (x%x)\n", - zp->z_origin, - inet_ntoa(ntp->my_addr), - ntp->mask)); - syslog(LOG_WARNING, - "build_secure_netlist (%s): addr (%s) is not in mask (x%x)", + syslog(LOG_INFO, + "build_secure_netlist (%s): addr (%s) is not in mask (%#lx)", zp->z_origin, inet_ntoa(ntp->my_addr), - ntp->mask); + (u_long)ntp->mask); errs++; } ntp->next = NULL; @@ -133,10 +126,7 @@ build_secure_netlist(zp) /* Check for duplicates */ if (addr_on_netlist(ntp->my_addr, *netlistp)) { - dprintf(1, (ddt, - "build_secure_netlist (%s): duplicate address %s\n", - zp->z_origin, inet_ntoa(ntp->my_addr))); - syslog(LOG_WARNING, + syslog(LOG_INFO, "build_secure_netlist (%s): duplicate address %s\n", zp->z_origin, inet_ntoa(ntp->my_addr)); errs++; @@ -151,20 +141,21 @@ build_secure_netlist(zp) free((char *)ntp); } if (!securezone) { - zp->secure_nets=NULL; + zp->secure_nets=NULL; } #ifdef DEBUG if (debug > 1) { for (ntp = *netlistp; ntp != NULL; ntp = ntp->next) { - fprintf(ddt, "ntp x%x addr x%x mask x%x", - ntp, ntp->addr, ntp->mask); - fprintf(ddt, " my_addr x%x", ntp->my_addr); + fprintf(ddt, "ntp x%lx addr x%lx mask x%lx", + (u_long)ntp, ntp->addr, ntp->mask); + fprintf(ddt, " my_addr %#lx", + (u_long)ntp->my_addr.s_addr); fprintf(ddt, " %s", inet_ntoa(ntp->my_addr)); - fprintf(ddt, " next x%x\n", ntp->next); + fprintf(ddt, " next x%lx\n", (u_long)ntp->next); } } #endif - return(errs); + return (errs); } #endif /*SECURE_ZONES*/ diff --git a/usr.sbin/named/db_update.c b/usr.sbin/named/db_update.c index 93244930d561..70e7bde76d24 100644 --- a/usr.sbin/named/db_update.c +++ b/usr.sbin/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 4.9.1.19 1994/07/23 23:23:56 vixie Exp $"; +static char rcsid[] = "$Id: db_update.c,v 8.6 1995/06/29 09:26:17 vixie Exp $"; #endif /* not lint */ /* @@ -66,6 +66,7 @@ static char rcsid[] = "$Id: db_update.c,v 4.9.1.19 1994/07/23 23:23:56 vixie Exp #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> +#include <resolv.h> #include "named.h" @@ -91,18 +92,19 @@ isRefByNS(name, htp) for (np = htp->h_tab[0]; np != NULL; np = np->n_next) { for (dp = np->n_data; dp != NULL; dp = dp->d_next) { - if ((dp->d_class == C_ANY || dp->d_class == C_IN) && - (dp->d_type == T_NS) && + if ((dp->d_class == C_ANY || + dp->d_class == C_IN || + dp->d_class == C_HS) && + dp->d_type == T_NS && #ifdef NCACHE - (!dp->d_rcode) && + !dp->d_rcode && #endif !strcasecmp(name, (char *)dp->d_data)) { return (1); } } - if (np->n_hash && isRefByNS(name, np->n_hash)) { + if (np->n_hash && isRefByNS(name, np->n_hash)) return (1); - } } return (0); } @@ -156,6 +158,13 @@ findMyZone(np, class) } +#ifdef NO_GLUE +#define ISVALIDGLUE(xdp) ((xdp)->d_type == T_NS || (xdp)->d_type == T_A) +#else +#define ISVALIDGLUE(xdp) (1) +#endif /*NO_GLUE*/ + + /* int * db_update(name, odp, newdp, flags, htp) * update data base node at `name'. `flags' controls the action. @@ -207,22 +216,26 @@ db_update(name, odp, newdp, flags, htp) register struct databuf *dp, *pdp; register struct namebuf *np; int zn, isHintNS; - char *fname; + const char *fname; - dprintf(3, (ddt, "db_update(%s, 0x%x, 0x%x, 0%o, 0x%x)%s\n", - name, odp, newdp, flags, htp, + dprintf(3, (ddt, "db_update(%s, 0x%lx, 0x%lx, 0%o, 0x%lx)%s\n", + name, (u_long)odp, (u_long)newdp, flags, (u_long)htp, (odp && (odp->d_flags&DB_F_HINT)) ? " hint":"" )); np = nlookup(name, &htp, &fname, newdp != NULL); if (np == NULL || fname != name) return (NONAME); /* don't let nonauthoritative updates write in authority zones */ - if (newdp && (flags & DB_NOTAUTH) && - (zn = findMyZone(np, newdp->d_class)) != DB_Z_CACHE) { + if (newdp && ((zn = findMyZone(np, newdp->d_class)) != DB_Z_CACHE) && +#ifdef STUBS + (zones[zn].z_type != Z_STUB) && +#endif + (flags & DB_NOTAUTH)) { int foundRR = 0; - /* don't generate the warning if we've done so recently or - * if the update would have been harmless (identical data). + /* + * Don't generate the warning if the update + * would have been harmless (identical data). */ for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!db_cmp(dp, newdp)) { @@ -230,31 +243,28 @@ db_update(name, odp, newdp, flags, htp) break; } } - if (!foundRR && - !haveComplained((char*)from_addr.sin_addr.s_addr, - (char*)dhash((u_char*)name, strlen(name)))) - syslog(LOG_NOTICE, - "[%s].%d attempted update to auth zone \"%s\" (%s)", - inet_ntoa(from_addr.sin_addr), - ntohs(from_addr.sin_port), - zones[zn].z_origin, - name); + if (!foundRR) + dprintf(5, (ddt, + "[%s].%d update? to auth zone \"%s\" (%s)", + inet_ntoa(from_addr.sin_addr), + ntohs(from_addr.sin_port), + zones[zn].z_origin, + name)); return (AUTH); } + if (newdp && zn && !(flags & DB_NOTAUTH)) { + if (db_getclev(zones[zn].z_origin) > newdp->d_clev) { + dprintf(5,(ddt, "attempted update child zone %s, %s\n", + zones[zn].z_origin, name)); + return(AUTH); + } + } + /* some special checks for root NS' A RR's */ isHintNS = isRefByNS(name, fcachetab); +#ifdef DEPRECATED if (newdp && isHintNS && newdp->d_type == T_A) { - /* obviously bogus addresses die here */ - if ( -#ifdef NCACHE - (!newdp->d_rcode) && -#endif - (((struct in_addr *)newdp->d_data)->s_addr == INADDR_ANY)) - { - syslog(LOG_INFO, "bogus (0.0.0.0) root A RR received"); - return (AUTH); - } /* upgrade credibility of additional data for rootsrv addrs */ if (newdp->d_cred == DB_C_ADDITIONAL) { dprintf(3, (ddt, @@ -267,10 +277,12 @@ db_update(name, odp, newdp, flags, htp) newdp->d_clev = 0; } } +#endif /* Reflect certain updates in hint cache also... */ /* Don't stick data we are authoritative for in hints. */ if (!(flags & DB_NOHINTS) && + (flags & DB_PRIMING) && (odp != NULL) && (htp != fcachetab) && (odp->d_zone <= 0) && @@ -296,7 +308,8 @@ db_update(name, odp, newdp, flags, htp) (flags|DB_NOHINTS), fcachetab) != OK) { - dprintf(3, (ddt, "db_update: hint %x freed\n", dp)); + dprintf(3, (ddt, "db_update: hint %lx freed\n", + (u_long)dp)); (void) free((char *)dp); } } @@ -322,13 +335,9 @@ db_update(name, odp, newdp, flags, htp) !odp->d_rcode && #endif /*NCACHE*/ zones[odp->d_zone].z_type != Z_CACHE) { - syslog(LOG_ERR, + syslog(LOG_INFO, "%s has CNAME and other data (illegal)\n", name); - dprintf(1, (ddt, - "db_update: %s: CNAME and more (%d, %d)\n", - name, odp->d_type, - dp->d_type)); goto skip; } if (!newdp || newdp->d_class != dp->d_class) @@ -362,9 +371,35 @@ db_update(name, odp, newdp, flags, htp) * but isn't as credible, reject it. */ if (newdp->d_cred == DB_C_ZONE && - newdp->d_cred == dp->d_cred && - newdp->d_clev < dp->d_clev) - return (AUTH); + dp->d_cred == DB_C_ZONE) { + /* Both records are from a zone file. + * If their credibility levels differ, + * we're dealing with a zone cut. The + * record with lower clev is from the + * upper zone's file and is therefore + * glue. + */ + if (newdp->d_clev < dp->d_clev) { + if (!ISVALIDGLUE(newdp)) { + syslog(LOG_INFO, + "domain %s %s record in zone %s should be in zone %s, ignored", + name, p_type(newdp->d_type), + zones[newdp->d_zone].z_origin, + zones[dp->d_zone].z_origin); + } + return (AUTH); + } + if (newdp->d_clev > dp->d_clev) { + if (!ISVALIDGLUE(dp)) { + syslog(LOG_INFO, + "domain %s %s record in zone %s should be in zone %s, deleted", + name, p_type(dp->d_type), + zones[dp->d_zone].z_origin, + zones[newdp->d_zone].z_origin); + } + goto delete; + } + } #ifdef NCACHE /* process NXDOMAIN */ /* policy */ @@ -400,12 +435,9 @@ db_update(name, odp, newdp, flags, htp) ntohs(from_addr.sin_port), dp->d_cred, dp->d_clev)); - if (newdp->d_cred > dp->d_cred || - (newdp->d_cred == DB_C_ZONE && - newdp->d_clev > dp->d_clev)) { - /* better credibility and the old datum - * was not from a zone file. remove - * the old datum. + if (newdp->d_cred > dp->d_cred) { + /* better credibility. + * remove the old datum. */ goto delete; } @@ -414,9 +446,56 @@ db_update(name, odp, newdp, flags, htp) return (AUTH); } if (newdp->d_cred == DB_C_ZONE && - newdp->d_cred == dp->d_cred && - newdp->d_clev < dp->d_clev) - return (AUTH); + dp->d_cred == DB_C_ZONE ) { + /* Both records are from a zone file. + * If their credibility levels differ, + * we're dealing with a zone cut. The + * record with lower clev is from the + * upper zone's file and is therefore + * glue. + */ + + /* XXX - Tricky situation here is you + * have 2 zones a.b.c and sub.a.b.c + * being served by the same server. + * named will send NS records for + * sub.a.b.c during zone transfer of + * a.b.c zone. If we're secondary for + * both zones, and we reload zone + * a.b.c, we'll get the NS records + * (and possibly A records to go with + * them?) for sub.a.b.c as part of the + * a.b.c zone transfer. But we've + * already got a more credible record + * from the sub.a.b.c zone. So we want + * to ignore the new record, but we + * shouldn't syslog because there's + * nothing the user can do to prevent + * the situation. Perhaps we should + * only complain when we are primary? + */ + + if (newdp->d_clev < dp->d_clev) { + if (!ISVALIDGLUE(newdp)) { + syslog(LOG_INFO, + "domain %s %s record in zone %s should be in zone %s, ignored", + name, p_type(newdp->d_type), + zones[newdp->d_zone].z_origin, + zones[dp->d_zone].z_origin); + } + return (AUTH); + } + if (newdp->d_clev > dp->d_clev) { + if (!ISVALIDGLUE(dp)) { + syslog(LOG_INFO, + "domain %s %s record in zone %s should be in zone %s, deleted", + name, p_type(dp->d_type), + zones[dp->d_zone].z_origin, + zones[newdp->d_zone].z_origin); + } + goto delete; + } + } /* credibility is the same. * let it aggregate in the normal way. @@ -439,7 +518,8 @@ db_update(name, odp, newdp, flags, htp) if (dp->d_type == T_SOA) goto delete; if (dp->d_type == T_WKS && - !bcmp(dp->d_data, newdp->d_data, INT16SZ)) + !bcmp(dp->d_data, newdp->d_data, + INT32SZ + sizeof(u_char))) goto delete; } if ((flags & DB_NODATA) && !db_cmp(dp, odp)) { @@ -458,8 +538,8 @@ db_update(name, odp, newdp, flags, htp) if (odp->d_ttl > dp->d_ttl) dp->d_ttl = odp->d_ttl; dprintf(3, (ddt, - "db_update: new ttl %d, +%d\n", - dp->d_ttl, + "db_update: new ttl %ld +%d\n", + (u_long)dp->d_ttl, dp->d_ttl - tt.tv_sec)); } return (DATAEXISTS); @@ -493,8 +573,8 @@ db_update(name, odp, newdp, flags, htp) * response source address here if flags&NOTAUTH. */ fixttl(newdp); - dprintf(3, (ddt, "db_update: adding%s %x\n", - (newdp->d_flags&DB_F_HINT) ? " hint":"", newdp)); + dprintf(3, (ddt, "db_update: adding%s %lx\n", + (newdp->d_flags&DB_F_HINT) ? " hint":"", (u_long)newdp)); #ifdef INVQ if (!(newdp->d_flags & DB_F_HINT)) addinv(np, newdp); /* modify inverse query tables */ @@ -553,7 +633,7 @@ db_cmp(dp1, dp2) register struct databuf *dp1, *dp2; { register u_char *cp1, *cp2; - int len; + int len, len2; if (dp1->d_type != dp2->d_type || dp1->d_class != dp2->d_class) return (1); @@ -576,6 +656,7 @@ db_cmp(dp1, dp2) case T_WKS: case T_NULL: case T_NSAP: + case T_LOC: #ifdef ALLOW_T_UNSPEC case T_UNSPEC: #endif @@ -595,11 +676,17 @@ db_cmp(dp1, dp2) cp1 = dp1->d_data; cp2 = dp2->d_data; len = *cp1; + len2 = *cp2; + if (len != len2) + return (1); if (strncasecmp((char *)++cp1, (char *)++cp2, len)) return (1); cp1 += len; cp2 += len; len = *cp1; + len2 = *cp2; + if (len != len2) + return (1); return (strncasecmp((char *)++cp1, (char *)++cp2, len)); case T_SOA: @@ -626,6 +713,17 @@ db_cmp(dp1, dp2) return (1); return (strcasecmp((char *)cp1, (char *)cp2)); + case T_PX: + cp1 = dp1->d_data; + cp2 = dp2->d_data; + if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* cmp prio */ + return (1); + if (strcasecmp((char *)cp1, (char *)cp2)) + return (1); + cp1 += strlen((char *)cp1) + 1; + cp2 += strlen((char *)cp2) + 1; + return (strcasecmp((char *)cp1, (char *)cp2)); + case T_TXT: case T_X25: if (dp1->d_size != dp2->d_size) diff --git a/usr.sbin/named/dmalloc.c b/usr.sbin/named/dmalloc.c index 4373024a889f..50db52332002 100644 --- a/usr.sbin/named/dmalloc.c +++ b/usr.sbin/named/dmalloc.c @@ -3,7 +3,7 @@ * vix 24mar92 [added size calcs, improved printout] * vix 22mar92 [original work] * - * $Id: dmalloc.c,v 4.9.1.3 1994/07/02 16:28:11 vixie Exp $ + * $Id: dmalloc.c,v 8.1 1994/12/15 06:24:14 vixie Exp $ */ /* diff --git a/usr.sbin/named/dmalloc.h b/usr.sbin/named/dmalloc.h index 54e68f9887a2..9d0b44a91eeb 100644 --- a/usr.sbin/named/dmalloc.h +++ b/usr.sbin/named/dmalloc.h @@ -1,7 +1,7 @@ /* dmalloc - debugging layer on top of malloc * vix 22mar92 [written] * - * $Id: dmalloc.h,v 4.9.1.2 1993/09/08 00:01:17 vixie Exp $ + * $Id: dmalloc.h,v 8.1 1994/12/15 06:24:14 vixie Exp $ */ /* diff --git a/usr.sbin/named/named.h b/usr.sbin/named/named.h index 4e597d7a89e0..0575a5c6e5be 100644 --- a/usr.sbin/named/named.h +++ b/usr.sbin/named/named.h @@ -1,7 +1,7 @@ /* named.h - include the local definitions in the right order * vix 28aug93 [original] * - * $Id: named.h,v 1.1 1993/09/08 04:57:40 vixie Exp $ + * $Id: named.h,v 8.1 1994/12/15 06:24:14 vixie Exp $ */ #include "../conf/portability.h" diff --git a/usr.sbin/named/ns_defs.h b/usr.sbin/named/ns_defs.h index bb9f18fbacb1..0a21a7148ade 100644 --- a/usr.sbin/named/ns_defs.h +++ b/usr.sbin/named/ns_defs.h @@ -1,6 +1,6 @@ /* * from ns.h 4.33 (Berkeley) 8/23/90 - * $Id: ns_defs.h,v 1.12 1994/07/23 23:23:56 vixie Exp $ + * $Id: ns_defs.h,v 8.2 1995/06/19 20:55:40 vixie Exp $ */ /* @@ -95,7 +95,8 @@ #define MAX_XFER_TIME 60*60*2 /* max seconds for an xfer */ #define XFER_TIME_FUDGE 10 /* MAX_XFER_TIME fudge */ #define MAX_XFERS_RUNNING 10 /* default max value of xfers_running */ -#define MAX_XFERS_PERNS 2 /* max # of xfers per peer nameserver */ +#define MAX_XFERS_PER_NS 2 /* max # of xfers per peer nameserver */ +#define XFER_BUFSIZE (16*1024) /* arbitrary but bigger than most MTU's */ #define ALPHA 0.7 /* How much to preserve of old response time */ #define BETA 1.2 /* How much to penalize response time on failure */ @@ -128,7 +129,20 @@ struct zoneinfo { #ifdef SECURE_ZONES struct netinfo *secure_nets; /* list of secure networks for zone */ #endif +#ifdef BIND_NOTIFY + /* XXX - this will have to move to the name when we do !SOA notify */ + struct notify *z_notifylist; /* list of servers we should notify */ +#endif +}; + +#ifdef BIND_NOTIFY +struct notify { + struct in_addr addr; /* of server */ + time_t last; /* when they asked */ + struct notify *next; + /* XXX - this will need a type field when we do !SOA notify */ }; +#endif /* zone types (z_type) */ #define Z_NIL 0 /* zone slot not in use */ @@ -205,7 +219,12 @@ struct qinfo { struct zoneinfo *q_zquery; /* Zone query is about (Q_ZSERIAL) */ #ifdef LAME_DELEGATION char q_domain[MAXDNAME]; /* domain for servers we are querying */ -#endif /* LAME_DELEGATION */ +#endif +#ifdef BIND_NOTIFY + int q_notifyzone; /* zone which needs a sysnotify() + * when the reply to this comes in. + */ +#endif }; /* q_flags bits (8 bits) */ @@ -291,7 +310,12 @@ enum nameserStats { nssRcvdQ, /* sent us a query */ nssSentDupQ, /* sent them a retry */ nssSentFail, /* sent them a SERVFAIL */ nssSentFErr, /* sent them a FORMERR */ - nssSendtoErr, /* error in sendto(2) */ + nssSendtoErr, /* error in sendto */ +#ifdef XSTATS + nssNotNsQ, /* query received from remote port != ns_port */ + nssSentNaAns, /* sent them a non autoritative answer */ + nssSentNXD, /* sent them a negative response */ +#endif nssLast }; struct nameser { @@ -346,12 +370,11 @@ typedef struct _to_validate TO_Validate; #ifdef DEBUG -# define dprintf(lev, args) ((debug >= lev) && fprintf args) +# define dprintf(lev, args) (ddt && (debug >= lev) && fprintf args) #else # define dprintf(lev, args) #endif - #ifdef INIT error "INIT already defined, check system include files" #endif diff --git a/usr.sbin/named/ns_forw.c b/usr.sbin/named/ns_forw.c index 574596460ada..02848ca3b9ce 100644 --- a/usr.sbin/named/ns_forw.c +++ b/usr.sbin/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 4.9.1.17 1994/07/23 23:23:56 vixie Exp $"; +static char rcsid[] = "$Id: ns_forw.c,v 8.5 1995/06/29 09:26:17 vixie Exp $"; #endif /* not lint */ /* @@ -104,7 +104,7 @@ ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp, dname, np) hp = (HEADER *) msg; id = hp->id; /* Look at them all */ - for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) { + for (qp = nsqhead; qp != QINFO_NULL; qp = qp->q_link) { if (qp->q_id == id && bcmp((char *)&qp->q_from, fp, sizeof(qp->q_from)) == 0 && ((qp->q_cmsglen == 0 && qp->q_msglen == msglen && @@ -138,12 +138,12 @@ ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp, dname, np) qp->q_dfd = dfd; qp->q_id = id; qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2; - hp->id = qp->q_nsid = htons((u_int16_t)++nsid); + hp->id = qp->q_nsid = htons(nsid_next()); hp->ancount = 0; hp->nscount = 0; hp->arcount = 0; if ((qp->q_msg = (u_char *)malloc((unsigned)msglen)) == NULL) { - syslog(LOG_ERR, "forw: %m"); + syslog(LOG_NOTICE, "forw: malloc: %m"); qfree(qp); return (FW_SERVFAIL); } @@ -169,15 +169,15 @@ ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp, dname, np) (qp->q_addr[0].nsdata != NULL) ? qp->q_addr[0].nsdata->d_nstime : -1, - qp->q_time - tt.tv_sec)); + (int)(qp->q_time - tt.tv_sec))); #ifdef DEBUG if (debug >= 10) - fp_query(msg, ddt); + fp_nquery(msg, msglen, ddt); #endif - if (sendto(ds, msg, msglen, 0, (struct sockaddr *)nsa, + if (sendto(ds, (char *)msg, msglen, 0, (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr)) - syslog(LOG_NOTICE, "ns_forw: sendto([%s].%d): %m", + syslog(LOG_INFO, "ns_forw: sendto([%s].%d): %m", inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port)); nameserIncr(nsa->sin_addr, nssSendtoErr); } @@ -225,10 +225,10 @@ aIsUs(addr) */ int haveComplained(tag1, tag2) - char *tag1, *tag2; + const char *tag1, *tag2; { struct complaint { - char *tag1, *tag2; + const char *tag1, *tag2; time_t expire; struct complaint *next; }; @@ -274,20 +274,19 @@ haveComplained(tag1, tag2) */ void nslookupComplain(sysloginfo, queryname, complaint, dname, a_rr) - char *sysloginfo, *queryname, *complaint, *dname; - register struct databuf *a_rr; + const char *sysloginfo, *queryname, *complaint, *dname; + const struct databuf *a_rr; { dprintf(2, (ddt, "NS '%s' %s\n", dname, complaint)); if (sysloginfo && queryname && !haveComplained(queryname, complaint)) { - char buf[512]; + char buf[999]; /* syslog only takes 5 params */ sprintf(buf, "%s: query(%s) %s (%s:%s)", sysloginfo, queryname, - complaint, dname, inet_ntoa( - *(struct in_addr*)a_rr->d_data - )); + complaint, dname, + inet_ntoa(data_inaddr(a_rr->d_data))); syslog(LOG_INFO, buf); } } @@ -306,14 +305,14 @@ nslookupComplain(sysloginfo, queryname, complaint, dname, a_rr) * is detected. * side effects: * if a dangerous situation is detected and (syslogdname && sysloginfo), - * calls syslog. + * calls syslog. */ int nslookup(nsp, qp, syslogdname, sysloginfo) struct databuf *nsp[]; register struct qinfo *qp; - char *syslogdname; - char *sysloginfo; + const char *syslogdname; + const char *sysloginfo; { register struct namebuf *np; register struct databuf *dp, *nsdp; @@ -321,20 +320,22 @@ nslookup(nsp, qp, syslogdname, sysloginfo) register int n; register unsigned int i; struct hashbuf *tmphtp; - char *dname, *fname; + char *dname; + const char *fname; int oldn, naddr, class, found_arr; time_t curtime; - dprintf(3, (ddt, "nslookup(nsp=0x%x, qp=0x%x, \"%s\")\n", - nsp, qp, syslogdname)); + dprintf(3, (ddt, "nslookup(nsp=0x%lx, qp=0x%lx, \"%s\")\n", + (u_long)nsp, (u_long)qp, syslogdname)); naddr = n = qp->q_naddr; curtime = (u_long) tt.tv_sec; while ((nsdp = *nsp++) != NULL) { class = nsdp->d_class; dname = (char *)nsdp->d_data; - dprintf(3, (ddt, "nslookup: NS \"%s\" c=%d t=%d (0x%x)\n", - dname, class, nsdp->d_type, nsdp->d_flags)); + dprintf(3, (ddt, "nslookup: NS \"%s\" c=%d t=%d (%#lx)\n", + dname, class, nsdp->d_type, + (u_long)nsdp->d_flags)); /* don't put in servers we have tried */ for (i = 0; i < qp->q_nusedns; i++) { @@ -349,8 +350,8 @@ nslookup(nsp, qp, syslogdname, sysloginfo) tmphtp = ((nsdp->d_flags & DB_F_HINT) ?fcachetab :hashtab); np = nlookup(dname, &tmphtp, &fname, 1); if (np == NULL || fname != dname) { - dprintf(3, (ddt, "%s: not found %s %x\n", - dname, fname, np)); + dprintf(3, (ddt, "%s: not found %s %lx\n", + dname, fname, (u_long)np)); continue; } found_arr = 0; @@ -360,42 +361,56 @@ nslookup(nsp, qp, syslogdname, sysloginfo) for (dp = np->n_data; dp != NULL; dp = dp->d_next) { struct in_addr nsa; +#ifdef NCACHE + if (dp->d_rcode) + continue; +#endif if (dp->d_type == T_CNAME && dp->d_class == class) goto skipserver; if (dp->d_type != T_A || dp->d_class != class) continue; -#ifdef NCACHE - if (dp->d_rcode) + if (data_inaddr(dp->d_data).s_addr == INADDR_ANY) { + syslog(LOG_INFO, "Bogus (0.0.0.0) A RR for %s", + dname); continue; -#endif + } /* * Don't use records that may become invalid to * reference later when we do the rtt computation. * Never delete our safety-belt information! */ if ((dp->d_zone == 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", np->n_dname)); /* Cache invalidate the NS RR's */ +#ifndef DATUMREFCNT if (dp->d_ttl < curtime) +#endif + { delete_all(np, class, T_A); - n = oldn; - break; + n = oldn; + found_arr = 0; + goto need_sysquery; + } } #ifdef VALIDATE /* anant@isi.edu validation procedure, maintains a * table of server names-addresses used recently */ - store_name_addr(dname, (struct in_addr *)dp->d_data, + store_name_addr(dname, data_inaddr(dp->d_data), syslogdname, sysloginfo); #endif /*VALIDATE*/ found_arr++; - nsa = *(struct in_addr *)dp->d_data; + nsa = data_inaddr(dp->d_data); /* don't put in duplicates */ qs = qp->q_addr; for (i = 0; i < n; i++, qs++) @@ -440,6 +455,7 @@ nslookup(nsp, qp, syslogdname, sysloginfo) complaint, dname, dp); return (-1); } +#ifdef BOGUSNS /* * Don't forward queries to bogus servers. Note * that this is unlike the previous tests, which @@ -454,16 +470,20 @@ nslookup(nsp, qp, syslogdname, sysloginfo) */ if (addr_on_netlist(nsa, boglist)) goto skipserver; +#endif n++; if (n >= NSMAX) goto out; - skipaddr: ; + skipaddr: + NULL; } dprintf(8, (ddt, "nslookup: %d ns addrs\n", n)); + need_sysquery: if (found_arr == 0 && !(qp->q_flags & Q_SYSTEM)) - (void) sysquery(dname, class, T_A, NULL, 0); -skipserver: ; + (void) sysquery(dname, class, T_A, NULL, 0, QUERY); + skipserver: + NULL; } out: dprintf(3, (ddt, "nslookup: %d ns addrs total\n", n)); @@ -585,11 +605,12 @@ schedretry(qp, t) #ifdef DEBUG if (debug > 3) { - fprintf(ddt,"schedretry(0x%x, %ld sec)\n", qp, (long)t); + fprintf(ddt, "schedretry(0x%lx, %ld sec)\n", + (u_long)qp, (long)t); if (qp->q_time) fprintf(ddt, - "WARNING: schedretry(%#x, %d) q_time already %d\n", - qp, t, qp->q_time); + "WARNING: schedretry(%#lx, %ld) q_time already %ld\n", + (u_long)qp, (long)t, (long)qp->q_time); } #endif t += (u_long) tt.tv_sec; @@ -620,7 +641,7 @@ unsched(qp) { register struct qinfo *np; - dprintf(3, (ddt, "unsched(%#x, %d )\n", qp, ntohs(qp->q_id))); + dprintf(3, (ddt, "unsched(%#lx, %d)\n", (u_long)qp, ntohs(qp->q_id))); if (retryqp == qp) { retryqp = qp->q_next; } else { @@ -646,7 +667,7 @@ retry(qp) register HEADER *hp; struct sockaddr_in *nsa; - dprintf(3, (ddt, "retry(x%x) id=%d\n", qp, ntohs(qp->q_id))); + dprintf(3, (ddt, "retry(x%lx) id=%d\n", (u_long)qp, ntohs(qp->q_id))); if (qp->q_msg == NULL) { /* XXX - why? */ qremove(qp); @@ -655,9 +676,10 @@ retry(qp) if (qp->q_expire && (qp->q_expire < tt.tv_sec)) { dprintf(1, (ddt, - "retry(x%x): expired @ %d (%d secs before now (%d))\n", - qp, qp->q_expire, tt.tv_sec - qp->q_expire, - tt.tv_sec)); + "retry(x%lx): expired @ %lu (%d secs before now (%lu))\n", + (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 */ goto fail; qremove(qp); @@ -701,16 +723,16 @@ fail: n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen); hp->id = qp->q_id; hp->qr = 1; - hp->ra = 1; + hp->ra = (NoRecurse == 0); hp->rd = 1; hp->rcode = SERVFAIL; #ifdef DEBUG if (debug >= 10) - fp_query(qp->q_msg, ddt); + fp_nquery(qp->q_msg, n, ddt); #endif if (send_msg((u_char *)hp, n, qp)) { - dprintf(1, (ddt,"gave up retry(x%x) nsid=%d id=%d\n", - qp, ntohs(qp->q_nsid), ntohs(qp->q_id))); + dprintf(1, (ddt, "gave up retry(x%lx) nsid=%d id=%d\n", + (u_long)qp, ntohs(qp->q_nsid), ntohs(qp->q_id))); } nameserIncr(qp->q_from.sin_addr, nssSentFail); qremove(qp); @@ -735,10 +757,10 @@ found: : (-1))); #ifdef DEBUG if (debug >= 10) - fp_query(qp->q_msg, ddt); + fp_nquery(qp->q_msg, qp->q_msglen, ddt); #endif /* NOSTRICT */ - if (sendto(ds, qp->q_msg, qp->q_msglen, 0, + if (sendto(ds, (char*)qp->q_msg, qp->q_msglen, 0, (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { dprintf(3, (ddt, "error resending msg errno=%d\n", errno)); @@ -783,16 +805,16 @@ retrytime(qp) void qflush() { - while (qhead) - qremove(qhead); - qhead = QINFO_NULL; + while (nsqhead) + qremove(nsqhead); + nsqhead = QINFO_NULL; } void qremove(qp) register struct qinfo *qp; { - dprintf(3, (ddt, "qremove(x%x)\n", qp)); + dprintf(3, (ddt, "qremove(x%lx)\n", (u_long)qp)); if (qp->q_flags & Q_ZSERIAL) qserial_answer(qp, 0); @@ -812,7 +834,7 @@ qfindid(id) register struct qinfo *qp; dprintf(3, (ddt, "qfindid(%d)\n", ntohs(id))); - for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) { + for (qp = nsqhead; qp!=QINFO_NULL; qp = qp->q_link) { if (qp->q_nsid == id) return(qp); } @@ -831,20 +853,23 @@ qnew() { register struct qinfo *qp; - if ((qp = (struct qinfo *) + qp = (struct qinfo *) #ifdef DMALLOC - dcalloc(file, line, + dcalloc(file, line, 1, sizeof(struct qinfo)); #else - calloc( + calloc(1, sizeof(struct qinfo)); #endif - 1, sizeof(struct qinfo))) == NULL) { + if (qp == NULL) { dprintf(5, (ddt, "qnew: calloc error\n")); syslog(LOG_ERR, "forw: %m"); exit(12); } - dprintf(5, (ddt, "qnew(x%x)\n", qp)); - qp->q_link = qhead; - qhead = qp; + dprintf(5, (ddt, "qnew(x%lx)\n", (u_long)qp)); +#ifdef BIND_NOTIFY + qp->q_notifyzone = DB_Z_CACHE; +#endif + qp->q_link = nsqhead; + nsqhead = qp; return (qp); } @@ -858,12 +883,10 @@ qfree(qp) int i; #endif -#ifdef DEBUG - if(debug > 3) - fprintf(ddt,"Qfree( x%x )\n", qp); - if(debug && qp->q_next) - fprintf(ddt,"WARNING: qfree of linked ptr x%x\n", qp); -#endif + dprintf(3, (ddt, "Qfree(x%lx)\n", (u_long)qp)); + if (qp->q_next) + dprintf(1, (ddt, "WARNING: qfree of linked ptr x%lx\n", + (u_long)qp)); if (qp->q_msg) free(qp->q_msg); if (qp->q_cmsg) @@ -896,10 +919,10 @@ qfree(qp) } } #endif - if( qhead == qp ) { - qhead = qp->q_link; + if( nsqhead == qp ) { + nsqhead = qp->q_link; } else { - for( np=qhead; np->q_link != QINFO_NULL; np = np->q_link ) { + 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; diff --git a/usr.sbin/named/ns_func.h b/usr.sbin/named/ns_func.h index eaff3bfe11fb..6a8e3c51cf2b 100644 --- a/usr.sbin/named/ns_func.h +++ b/usr.sbin/named/ns_func.h @@ -1,16 +1,18 @@ /* ns_func.h - declarations for ns_*.c's externally visible functions * - * $Id: ns_func.h,v 1.12 1994/07/22 08:42:39 vixie Exp $ + * $Id: ns_func.h,v 8.3 1995/06/29 09:26:17 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)); -extern struct qinfo *sysquery __P((char *, int, int, - struct in_addr *, int)); -extern int - doupdate __P((u_char *, int, u_char *, int, +extern struct qinfo *sysquery __P((const char *, int, int, + struct in_addr *, int, int)); +extern struct notify *findNotifyPeer __P((const struct zoneinfo *, + struct in_addr)); +extern void sysnotify __P((const char *, int, int)); +extern int doupdate __P((u_char *, int, u_char *, int, struct databuf **, int, u_int)), send_msg __P((u_char *, int, struct qinfo *)), findns __P((struct namebuf **, int, @@ -27,14 +29,20 @@ extern int extern void ns_req __P((u_char *, int, int, struct qstream *, struct sockaddr_in *, - int)); + int)), + free_addinfo __P((void)), + free_nsp __P((struct databuf **)); extern int stale __P((struct databuf *)), - make_rr __P((char *, struct databuf *, + make_rr __P((const char *, struct databuf *, u_char *, int, int)), doaddinfo __P((HEADER *, u_char *, int)), doaddauth __P((HEADER *, u_char *, int, struct namebuf *, struct databuf *)); +#ifdef BIND_NOTIFY +extern int findZonePri __P((const struct zoneinfo *, + const struct sockaddr_in *)); +#endif /* --from ns_req.c-- */ /* ++from ns_forw.c++ */ @@ -48,15 +56,16 @@ extern int ns_forw __P((struct databuf *nsp[], struct qinfo **qpp, char *dname, struct namebuf *np)), - haveComplained __P((char *, char *)), + haveComplained __P((const char *, const char *)), nslookup __P((struct databuf *nsp[], struct qinfo *qp, - char *syslogdname, - char *sysloginfo)), + const char *syslogdname, + const char *sysloginfo)), qcomp __P((struct qserv *, struct qserv *)); extern struct qdatagram *aIsUs __P((struct in_addr)); -extern void nslookupComplain __P((char *, char *, char *, char *, - struct databuf *)), +extern void nslookupComplain __P((const char *, const char *, + const char *, const char *, + const struct databuf *)), schedretry __P((struct qinfo *, time_t)), unsched __P((struct qinfo *)), retry __P((struct qinfo *)), @@ -79,7 +88,9 @@ extern void sqrm __P((struct qstream *)), dqflush __P((time_t gen)), sq_done __P((struct qstream *)), ns_setproctitle __P((char *, int)), - getnetconf __P((void)); + getnetconf __P((void)), + nsid_init __P((void)); +extern u_int16_t nsid_next __P((void)); extern struct netinfo *findnetinfo __P((struct in_addr)); /* --from ns_main.c-- */ @@ -91,9 +102,14 @@ extern void ns_maint __P((void)), #else remove_zone __P((struct hashbuf *, int)), #endif +#ifdef PURGE_ZONE + purge_zone __P((const char *, struct hashbuf *, int)), +#endif loadxfer __P((void)), + qserial_query __P((struct zoneinfo *)), qserial_answer __P((struct qinfo *, u_int32_t)); -extern SIG_FN endxfer __P((void)); +extern SIG_FN endxfer __P(()); +extern const char * zoneTypeString __P((const struct zoneinfo *)); #ifdef DEBUG extern void printzoneinfo __P((int)); #endif @@ -107,7 +123,9 @@ extern void sort_response __P((u_char *, int, /* --from ns_sort.c-- */ /* ++from ns_init.c++ */ -extern void ns_init __P((char *)); +extern void ns_refreshtime __P((struct zoneinfo *, time_t)), + ns_retrytime __P((struct zoneinfo *, time_t)), + ns_init __P((char *)); /* --from ns_init.c-- */ /* ++from ns_ncache.c++ */ @@ -116,6 +134,9 @@ extern void cache_n_resp __P((u_char *, int)); /* ++from ns_stats.c++ */ extern void ns_stats __P((void)); +#ifdef XSTATS +extern void ns_logstats __P((void)); +#endif extern void qtypeIncr __P((int qtype)); extern struct nameser *nameserFind __P((struct in_addr addr, int flags)); #define NS_F_INSERT 0x0001 @@ -135,6 +156,6 @@ extern int dovalidate __P((u_char *, int, u_char *, int, int, struct sockaddr_in *, int *)), update_msg __P((u_char *, int *, int Vlist[], int)); -extern void store_name_addr __P((char *, struct in_addr *, +extern void store_name_addr __P((char *, struct in_addr, char *, char *)); /* --from ns_validate.c-- */ diff --git a/usr.sbin/named/ns_glob.h b/usr.sbin/named/ns_glob.h index 993d14d01385..b404e7e7607c 100644 --- a/usr.sbin/named/ns_glob.h +++ b/usr.sbin/named/ns_glob.h @@ -1,6 +1,6 @@ /* * from ns.h 4.33 (Berkeley) 8/23/90 - * $Id: ns_glob.h,v 1.7 1994/06/11 22:04:46 vixie Exp $ + * $Id: ns_glob.h,v 8.3 1995/06/19 20:55:40 vixie Exp $ */ /* @@ -77,14 +77,11 @@ DECL struct qdatagram *datagramq INIT(QDATAGRAM_NULL); DECL struct timeval tt; /* head of allocated queries */ -DECL struct qinfo *qhead INIT(QINFO_NULL); +DECL struct qinfo *nsqhead INIT(QINFO_NULL); /* list of forwarding hosts */ DECL struct fwdinfo *fwdtab INIT(NULL); - /* next forwarded query id */ -DECL int nsid INIT(0); - /* datagram socket */ DECL int ds INIT(-1); @@ -101,6 +98,16 @@ DECL int needmaint INIT(0); /* (beware: this is also the upper bound on named_xfer real time) */ DECL int maint_interval INIT(15*60); +#ifdef CLEANCACHE + /* What's the minimum interval between cache cleanings? */ +DECL int cache_interval INIT(60*60); +#endif + +#ifdef XSTATS + /* What's the minimum interval between stats output? */ +DECL int stats_interval INIT(60*60); +#endif + /* need to reload secondary zone(s) */ DECL int needzoneload INIT(0); @@ -122,6 +129,13 @@ DECL int needStatsDump INIT(0); */ DECL int needToExit INIT(0); #endif /* ALLOW_UPDATES */ +#ifdef XSTATS + /* need to exit + * set by shutdown signal handler + * (onintr) + */ +DECL int needToExit INIT(0); +#endif /* XSTATS */ #ifdef QRYLOG /* is query logging turned on? */ @@ -231,15 +245,23 @@ DECL int slave_retry INIT(4); #endif #ifdef STATSFILE -DECL char *statsfile INIT(STATSFILE); +DECL const char *statsfile INIT(STATSFILE); #else -DECL char *statsfile INIT(_PATH_STATS); +DECL const char *statsfile INIT(_PATH_STATS); #endif -DECL char sendtoStr[] INIT("sendto"); +DECL const char sendtoStr[] INIT("sendto"); /* defined in version.c, can't use DECL/INIT */ extern char Version[]; /* max value of xfers_running */ -DECL int max_xfers_running INIT(MAX_XFERS_RUNNING); +DECL int max_xfers_running INIT(MAX_XFERS_RUNNING); + + /* max number of transfers to any given name server */ +DECL int max_xfers_per_ns INIT(MAX_XFERS_PER_NS); + +#ifndef INVQ + /* should IQUERY be answered bogusly rather than with NOTIMPL? */ +DECL int fake_iquery INIT(0); +#endif diff --git a/usr.sbin/named/ns_init.c b/usr.sbin/named/ns_init.c index 82c2071ed2d6..944b9ef2cd87 100644 --- a/usr.sbin/named/ns_init.c +++ b/usr.sbin/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:"; +static char rcsid[] = "$Id: ns_init.c,v 8.7 1995/06/29 09:26:17 vixie Exp $"; #endif /* not lint */ /* @@ -70,22 +70,55 @@ static char rcsid[] = "$Id:"; #include <stdio.h> #include <errno.h> #include <ctype.h> +#include <assert.h> #include "named.h" #undef nsaddr +enum limit { Datasize }; + static void zoneinit __P((struct zoneinfo *)), get_forwarders __P((FILE *)), boot_read __P((char *)), #ifdef DEBUG content_zone __P((int)), #endif - free_forwarders __P((void)); + free_forwarders __P((void)), + ns_limit __P((const char *name, int value)), + ns_rlimit __P((const char *name, enum limit limit, + long value)), + ns_option __P((const char *name)); static struct zoneinfo *find_zone __P((char *, int, int)); /* + * Set new refresh time for zone. Use a random number in the last half of + * the refresh limit; we want it to be substantially correct while still + * preventing slave synchronization. + */ +void +ns_refreshtime(zp, timebase) + struct zoneinfo *zp; + time_t timebase; +{ + register time_t half = ((zp->z_refresh + 1) / 2); + + zp->z_time = timebase + half + (rand() % half); +} + +/* + * Set new retry time for zone. + */ +void +ns_retrytime(zp, timebase) + struct zoneinfo *zp; + time_t timebase; +{ + zp->z_time = timebase + zp->z_retry; +} + +/* * Read boot file for configuration info. */ void @@ -114,6 +147,7 @@ ns_init(bootfile) fcachetab = savehash((struct hashbuf *)NULL); /* init zone data */ zones[0].z_type = Z_CACHE; + zones[0].z_origin = ""; } else { /* Mark previous zones as not yet found in boot file. */ for (zp = &zones[1]; zp < &zones[nzones]; zp++) @@ -197,7 +231,7 @@ boot_read(bootfile) struct stat f_time; static int tmpnum = 0; /* unique number for tmp zone files */ #ifdef ALLOW_UPDATES - char *cp, *flag; + char *flag; #endif int slineno; /* Saved global line number. */ int i; @@ -208,12 +242,17 @@ boot_read(bootfile) } slineno = lineno; - lineno = 0; + lineno = 1; while (!feof(fp) && !ferror(fp)) { - if (!getword(buf, sizeof(buf), fp)) - continue; /* read named.boot keyword and process args */ + if (!getword(buf, sizeof(buf), fp)) { + /* + * This is a blank line, a commented line, or the + * '\n' of the previous line. + */ + continue; + } if (strcasecmp(buf, "directory") == 0) { (void) getword(buf, sizeof(buf), fp); if (chdir(buf) < 0) { @@ -226,14 +265,21 @@ boot_read(bootfile) get_netlist(fp, enettab, ALLOW_NETS, buf); continue; } else if (strcasecmp(buf, "max-fetch") == 0) { - max_xfers_running = getnum(fp, bootfile, 0); + max_xfers_running = getnum(fp, bootfile, GETNUM_NONE); + continue; + } else if (strcasecmp(buf, "limit") == 0) { + (void) getword(buf, sizeof(buf), fp); + ns_limit(buf, getnum(fp, bootfile, GETNUM_SCALED)); + continue; + } else if (strcasecmp(buf, "options") == 0) { + while (getword(buf, sizeof(buf), fp)) + ns_option(buf); continue; } else if (strcasecmp(buf, "forwarders") == 0) { get_forwarders(fp); continue; } else if (strcasecmp(buf, "slave") == 0) { forward_only++; - endline(fp); continue; #ifdef BOGUSNS } else if (strcasecmp(buf, "bogusns") == 0) { @@ -250,20 +296,26 @@ boot_read(bootfile) } else if (strcasecmp(buf, "domain") == 0) { if (getword(buf, sizeof(buf), fp)) localdomain = savestr(buf); - endline(fp); continue; #endif } else if (strcasecmp(buf, "include") == 0) { if (getword(buf, sizeof(buf), fp)) boot_read(buf); - endline(fp); continue; } else if (strncasecmp(buf, "cache", 5) == 0) { type = Z_CACHE; class = C_IN; #ifdef GEN_AXFR - if (class_p = strchr(buf, '/')) + if (class_p = strchr(buf, '/')) { class = get_class(class_p+1); + + if (class != C_IN) { + syslog(LOG_NOTICE, + "cache directive with non-IN class is not supported (yet)"); + endline(fp); + continue; + } + } #endif } else if (strncasecmp(buf, "primary", 7) == 0) { type = Z_PRIMARY; @@ -289,8 +341,9 @@ boot_read(bootfile) #endif #endif } else { - syslog(LOG_ERR, "%s: line %d: unknown field '%s'\n", - bootfile, lineno+1, buf); + syslog(LOG_NOTICE, + "%s: line %d: unknown directive '%s'\n", + bootfile, lineno, buf); endline(fp); continue; } @@ -299,22 +352,23 @@ boot_read(bootfile) * read zone origin */ if (!getword(obuf, sizeof(obuf), fp)) { - syslog(LOG_ERR, "%s: line %d: missing origin\n", + syslog(LOG_NOTICE, "%s: line %d: missing origin\n", bootfile, lineno); continue; } i = strlen(obuf); if ((obuf[i-1] == '.') && (i != 1)) - syslog(LOG_ERR, "%s: line %d: zone \"%s\" has trailing dot\n", - bootfile, lineno, obuf); + syslog(LOG_INFO, + "%s: line %d: zone \"%s\" has trailing dot\n", + bootfile, lineno, obuf); while ((--i >= 0) && (obuf[i] == '.')) obuf[i] = '\0'; dprintf(1, (ddt, "zone origin %s", obuf[0]?obuf:".")); /* - * read source file or host address + * Read source file or host address. */ if (!getword(buf, sizeof(buf), fp)) { - syslog(LOG_ERR, "%s: line %d: missing %s\n", + syslog(LOG_NOTICE, "%s: line %d: missing %s\n", bootfile, lineno, #ifdef STUBS (type == Z_SECONDARY || type == Z_STUB) @@ -326,36 +380,33 @@ boot_read(bootfile) continue; } - /* check for previous instance of this zone (reload) */ + /* + * Check for previous instance of this zone (reload). + */ if (!(zp = find_zone(obuf, type, class))) { if (type == Z_CACHE) { zp = &zones[0]; - zp->z_origin = ""; goto gotcache; } for (zp = &zones[1]; zp < &zones[nzones]; zp++) if (zp->z_type == Z_NIL) goto gotzone; /* - * this code assumes that nzones never decreases + * This code assumes that nzones never decreases. */ if (nzones % 64 == 0) { dprintf(1, (ddt, "Reallocating zones structure\n")); /* * Realloc() not used since it might damage zones - * if an error occurs + * if an error occurs. */ zp = (struct zoneinfo *) malloc((64 + nzones) * sizeof(struct zoneinfo)); if (zp == (struct zoneinfo *)0) { - syslog(LOG_ERR, + syslog(LOG_NOTICE, "no memory for more zones"); - dprintf(1, (ddt, - "Out of memory for new zones\n" - ) - ); endline(fp); continue; } @@ -384,16 +435,16 @@ boot_read(bootfile) #ifdef notyet zp->z_refresh = atoi(buf); if (zp->z_refresh <= 0) { - syslog(LOG_ERR, + syslog(LOG_NOTICE, "%s: line %d: bad refresh time '%s', ignored\n", bootfile, lineno, buf); zp->z_refresh = 0; } else if (cache_file == NULL) cache_file = source; #else - syslog(LOG_WARNING, - "%s: line %d: cache refresh ignored\n", - bootfile, lineno); + syslog(LOG_NOTICE, + "%s: line %d: cache refresh ignored\n", + bootfile, lineno); #endif endline(fp); } @@ -424,7 +475,7 @@ boot_read(bootfile) } zp->z_source = source; dprintf(1, (ddt, "reloading zone\n")); - (void) db_load(zp->z_source, zp->z_origin, zp, 0); + (void) db_load(zp->z_source, zp->z_origin, zp, NULL); break; case Z_PRIMARY: @@ -434,7 +485,7 @@ boot_read(bootfile) endline(fp); flag = buf; while (flag) { - cp = strchr(flag, ','); + char *cp = strchr(flag, ','); if (cp) *cp++ = 0; if (strcasecmp(flag, "dynamic") == 0) @@ -442,7 +493,7 @@ boot_read(bootfile) else if (strcasecmp(flag, "addonly") == 0) zp->z_flags |= Z_DYNADDONLY; else { - syslog(LOG_ERR, + syslog(LOG_NOTICE, "%s: line %d: bad flag '%s'\n", bootfile, lineno, flag); } @@ -478,8 +529,11 @@ boot_read(bootfile) } zp->z_source = source; zp->z_flags &= ~Z_AUTH; +#ifdef PURGE_ZONE + purge_zone(zp->z_origin, hashtab, zp->z_class); +#endif dprintf(1, (ddt, "reloading zone\n")); - if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0) + if (!db_load(zp->z_source, zp->z_origin, zp, NULL)) zp->z_flags |= Z_AUTH; #ifdef ALLOW_UPDATES /* Guarantee calls to ns_maint() */ @@ -517,8 +571,8 @@ boot_read(bootfile) * We will always transfer this zone again * after a reload. */ - sprintf(buf, "/%s/NsTmp%d.%d", _PATH_TMPDIR, - getpid(), tmpnum++); + sprintf(buf, "/%s/NsTmp%ld.%d", _PATH_TMPDIR, + (long)getpid(), tmpnum++); source = savestr(buf); zp->z_flags |= Z_TMP_FILE; } else @@ -565,16 +619,21 @@ boot_read(bootfile) break; } - zp->z_flags |= Z_FOUND; + if ((zp->z_flags & Z_FOUND) && /* already found? */ + (zp - zones) != DB_Z_CACHE) /* cache never sets Z_FOUND */ + syslog(LOG_NOTICE, + "Zone \"%s\" declared more than once", + zp->z_origin); + zp->z_flags |= Z_FOUND; dprintf(1, (ddt, "zone[%d] type %d: '%s'", zp-zones, type, *(zp->z_origin) == '\0' ? "." : zp->z_origin)); if (zp->z_refresh && zp->z_time == 0) - zp->z_time = zp->z_refresh + tt.tv_sec; + ns_refreshtime(zp, tt.tv_sec); if (zp->z_time <= tt.tv_sec) needmaint = 1; - dprintf(1, (ddt, " z_time %d, z_refresh %d\n", - zp->z_time, zp->z_refresh)); + dprintf(1, (ddt, " z_time %lu, z_refresh %lu\n", + (u_long)zp->z_time, (u_long)zp->z_refresh)); } (void) my_fclose(fp); lineno = slineno; @@ -585,6 +644,7 @@ zoneinit(zp) register struct zoneinfo *zp; { struct stat sb; + int result; /* * Try to load zone from backup file, @@ -595,8 +655,12 @@ zoneinit(zp) */ if (!zp->z_source) return; - if (stat(zp->z_source, &sb) == -1 || - db_load(zp->z_source, zp->z_origin, zp, 0) != 0) { + result = stat(zp->z_source, &sb); +#ifdef PURGE_ZONE + if (result != -1) + purge_zone(zp->z_origin, hashtab, zp->z_class); +#endif + if (result == -1 || db_load(zp->z_source, zp->z_origin, zp, NULL)) { /* * Set zone to be refreshed immediately. */ @@ -710,14 +774,13 @@ get_forwarders(fp) ftp->fwdaddr.sin_port = ns_port; ftp->fwdaddr.sin_family = AF_INET; } else { - syslog(LOG_ERR, "'%s' (ignored, NOT dotted quad)", + syslog(LOG_NOTICE, "'%s' (ignored, NOT dotted quad)", buf); - dprintf(1, (ddt, " (ignored, NOT dotted quad)")); continue; } #ifdef FWD_LOOP if (aIsUs(ftp->fwdaddr.sin_addr)) { - syslog(LOG_ERR, + syslog(LOG_NOTICE, "Forwarder '%s' ignored, my address", buf); dprintf(1, (ddt, " (ignored, my address)")); @@ -754,10 +817,10 @@ get_forwarders(fp) #ifdef DEBUG if (debug > 2) { for (ftp = fwdtab; ftp != NULL; ftp = ftp->next) { - fprintf(ddt,"ftp x%x [%s] next x%x\n", - ftp, + fprintf(ddt, "ftp x%lx [%s] next x%lx\n", + (u_long)ftp, inet_ntoa(ftp->fwdaddr.sin_addr), - ftp->next); + (u_long)ftp->next); } } #endif @@ -806,3 +869,79 @@ content_zone(end) } } #endif + +static void +ns_limit(name, value) + const char *name; + int value; +{ + if (!strcasecmp(name, "transfers-in")) { + max_xfers_running = value; + } else if (!strcasecmp(name, "transfers-per-ns")) { + max_xfers_per_ns = value; + } else if (!strcasecmp(name, "datasize")) { + ns_rlimit("datasize", Datasize, value); + } else { + syslog(LOG_ERR, + "error: unrecognized limit in bootfile: \"%s\"", + name); + exit(1); + } +} + +static void +ns_rlimit(name, limit, value) + const char *name; + enum limit limit; + long value; +{ +#ifndef HAVE_GETRUSAGE +# ifdef LINT + name; limit; value; +# endif + syslog(LOG_WARNING, "warning: unimplemented limit in bootfile: \"%s\"", + name); +#else + struct rlimit limits; + int rlimit; + + switch (limit) { + case Datasize: + rlimit = RLIMIT_DATA; + break; + default: + abort(); + } + if (getrlimit(rlimit, &limits) < 0) { + syslog(LOG_WARNING, "getrlimit(%s): %m", name); + return; + } + limits.rlim_cur = value; + if (setrlimit(rlimit, &limits) < 0) { + syslog(LOG_WARNING, "setrlimit(%s, %ld): %m", name, value); + return; + } +#endif +} + +static void +ns_option(name) + const char *name; +{ + if (!strcasecmp(name, "no-recursion")) { + NoRecurse = 1; + } else if (!strcasecmp(name, "query-log")) { + qrylog = 1; + } else if (!strcasecmp(name, "forward-only")) { + forward_only = 1; +#ifndef INVQ + } else if (!strcasecmp(name, "fake-iquery")) { + fake_iquery = 1; +#endif + } else { + syslog(LOG_ERR, + "error: unrecognized option in bootfile: \"%s\"", + name); + exit(1); + } +} diff --git a/usr.sbin/named/ns_main.c b/usr.sbin/named/ns_main.c index 8b04a49caa79..597f3de44b0a 100644 --- a/usr.sbin/named/ns_main.c +++ b/usr.sbin/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 4.9.1.19 1994/07/23 23:23:56 vixie Exp $"; +static char rcsid[] = "$Id: ns_main.c,v 8.8 1995/06/29 09:26:17 vixie Exp $"; #endif /* not lint */ /* @@ -76,17 +76,22 @@ char copyright[] = #if !defined(SYSV) && defined(XXX) #include <sys/wait.h> #endif /* !SYSV */ -#include <sys/time.h> -#define TIME_H_INCLUDED -#include <sys/resource.h> #if defined(__osf__) -#define _SOCKADDR_LEN /* XXX - should be in portability.h but that +# define _SOCKADDR_LEN /* XXX - should be in portability.h but that * would need to be included before socket.h */ #endif #include <sys/ioctl.h> #include <sys/socket.h> #include <netinet/in.h> +#if defined(__osf__) +# include <sys/mbuf.h> +# include <net/route.h> +#endif +#if defined(_AIX) +# include <sys/time.h> +# define TIME_H_INCLUDED +#endif #include <net/if.h> #include <arpa/nameser.h> #include <arpa/inet.h> @@ -108,10 +113,13 @@ char copyright[] = #undef nsaddr /* UDP receive, TCP send buffer size */ -static const int rbufsize = 8 * 1024; +static const int rbufsize = 8 * 1024, + /* TCP send window size */ + sbufsize = 16 * 1024; static struct sockaddr_in nsaddr; -static u_int16_t local_ns_port; /* our service port */ +static u_int16_t local_ns_port, /* our service port */ + nsid_state; static fd_set mask; /* open descriptors */ static char **Argv = NULL; static char *LastArg = NULL; /* end of argv */ @@ -165,9 +173,13 @@ main(argc, argv, envp) int rfd, size; time_t lasttime, maxctime; u_char buf[BUFSIZ]; +#ifdef POSIX_SIGNALS + struct sigaction sact; +#else #ifndef SYSV struct sigvec vec; #endif +#endif fd_set tmpmask; struct timeval t, *tp; struct qstream *candidate = QSTREAM_NULL; @@ -184,6 +196,12 @@ main(argc, argv, envp) local_ns_port = ns_port = htons(NAMESERVER_PORT); + /* BSD has a better random number generator but it's not clear + * that we need it here. + */ + gettime(&tt); + srand(((unsigned)getpid()) + (unsigned)tt.tv_usec); + /* ** Save start and extent of argv for ns_setproctitle(). */ @@ -298,7 +316,7 @@ main(argc, argv, envp) if (fp != NULL) { (void) fgets(oldpid, sizeof(oldpid), fp); (void) rewind(fp); - fprintf(fp, "%d\n", getpid()); + fprintf(fp, "%ld\n", (long)getpid()); (void) my_fclose(fp); } #else /*PID_FIX*/ @@ -317,6 +335,7 @@ main(argc, argv, envp) nsaddr.sin_family = AF_INET; nsaddr.sin_addr.s_addr = INADDR_ANY; nsaddr.sin_port = local_ns_port; + nsid_init(); /* ** Open stream port. @@ -329,7 +348,7 @@ main(argc, argv, envp) if (setsockopt(vs, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) { - syslog(LOG_ERR, "setsockopt(vs, reuseaddr): %m"); + syslog(LOG_NOTICE, "setsockopt(vs, reuseaddr): %m"); (void) my_close(vs); continue; } @@ -338,7 +357,7 @@ main(argc, argv, envp) if (errno != EADDRINUSE || n > 4) { if (errno == EADDRINUSE) { - syslog(LOG_ERR, + syslog(LOG_NOTICE, "There may be a name server already running"); syslog(LOG_ERR, "exiting"); } else { @@ -409,8 +428,20 @@ main(argc, argv, envp) #if defined(SIGXFSZ) (void) signal(SIGXFSZ, onhup); /* wierd DEC Hesiodism, harmless */ #endif +#if defined(POSIX_SIGNALS) + bzero((char *)&sact, sizeof(sact)); + sact.sa_handler = maint_alarm; + sigemptyset(&sact.sa_mask); + sigaddset(&sact.sa_mask, SIGCHLD); + (void) sigaction(SIGALRM, &sact, (struct sigaction *)NULL); + + sact.sa_handler = endxfer; + sigemptyset(&sact.sa_mask); + sigaddset(&sact.sa_mask, SIGALRM); + (void) sigaction(SIGCHLD, &sact, (struct sigaction *)NULL); +#else #if defined(SYSV) - (void) signal(SIGCLD, endxfer); + (void) signal(SIGCLD, (SIG_FN (*)()) endxfer); (void) signal(SIGALRM, maint_alarm); #else bzero((char *)&vec, sizeof(vec)); @@ -422,6 +453,7 @@ main(argc, argv, envp) vec.sv_mask = sigmask(SIGALRM); (void) sigvec(SIGCHLD, &vec, (struct sigvec *)NULL); #endif /* SYSV */ +#endif /* POSIX_SIGNALS */ (void) signal(SIGPIPE, SIG_IGN); #ifdef SIGSYS (void) signal(SIGSYS, sigprof); @@ -433,6 +465,11 @@ main(argc, argv, envp) (void) signal(SIGTERM, onintr); #endif +#ifdef XSTATS + /* Catch SIGTERM so we can write stats before exiting. */ + (void) signal(SIGTERM, onintr); +#endif + dprintf(1, (ddt, "database initialized\n")); t.tv_usec = 0; @@ -488,7 +525,7 @@ main(argc, argv, envp) (void) dup2(n, 2); if (n > 2) (void) my_close(n); -#ifdef SYSV +#if defined(SYSV) || defined(hpux) setpgrp(); #else { @@ -523,7 +560,7 @@ main(argc, argv, envp) /* tuck my process id away again */ fp = fopen(PidFile, "w"); if (fp != NULL) { - fprintf(fp, "%d\n", getpid()); + fprintf(fp, "%ld\n", (long)getpid()); (void) my_fclose(fp); } #endif @@ -533,7 +570,7 @@ main(argc, argv, envp) nfds = getdtablesize(); /* get the number of file descriptors */ if (nfds > FD_SETSIZE) { nfds = FD_SETSIZE; /* Bulletproofing */ - syslog(LOG_ERR, "Return from getdtablesize() > FD_SETSIZE"); + syslog(LOG_NOTICE, "Return from getdtablesize() > FD_SETSIZE"); } FD_ZERO(&mask); FD_SET(vs, &mask); @@ -563,6 +600,12 @@ main(argc, argv, envp) exit(0); } #endif /* ALLOW_UPDATES */ +#ifdef XSTATS + if (needToExit) { + ns_logstats(); + exit(0); + } +#endif /* XSTATS */ if (needreload) { needreload = 0; db_reload(); @@ -606,11 +649,9 @@ main(argc, argv, envp) tp = NULL; tmpmask = mask; n = select(nfds, &tmpmask, (fd_set *)NULL, (fd_set *)NULL, tp); - if (n < 0) { - if (errno != EINTR) { - syslog(LOG_ERR, "select: %m"); - sleep(60); - } + if (n < 0 && errno != EINTR) { + syslog(LOG_ERR, "select: %m"); + sleep(60); } if (n <= 0) continue; @@ -619,28 +660,32 @@ main(argc, argv, envp) dqp != QDATAGRAM_NULL; dqp = dqp->dq_next) { if (FD_ISSET(dqp->dq_dfd, &tmpmask)) - for (udpcnt = 0; udpcnt < 25; udpcnt++) { /*XXX*/ + for (udpcnt = 0; udpcnt < 42; udpcnt++) { /*XXX*/ from_len = sizeof(from_addr); - if ((n = recvfrom(dqp->dq_dfd, buf, sizeof(buf), 0, + if ((n = recvfrom(dqp->dq_dfd, (char *)buf, sizeof(buf), 0, (struct sockaddr *)&from_addr, &from_len)) < 0) { +#if defined(SPURIOUS_ECONNREFUSED) + if ((n < 0) && (errno == ECONNREFUSED)) + break; +#endif if ((n < 0) && (errno == PORT_WOULDBLK)) break; - syslog(LOG_WARNING, "recvfrom: %m"); + syslog(LOG_INFO, "recvfrom: %m"); break; } if (n == 0) break; gettime(&tt); dprintf(1, (ddt, - "\ndatagram from [%s].%d, fd %d, len %d; now %s", + "\ndatagram from [%s].%d, fd %d, len %d; now %s", inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port), dqp->dq_dfd, n, - ctime(&tt.tv_sec))); + ctimel(tt.tv_sec))); #ifdef DEBUG if (debug >= 10) - fp_query(buf, ddt); + fp_nquery(buf, n, ddt); #endif /* * Consult database to get the answer. @@ -684,16 +729,16 @@ main(argc, argv, envp) continue; } if (rfd < 0) { - syslog(LOG_WARNING, "accept: %m"); + syslog(LOG_INFO, "accept: %m"); continue; } if ((n = fcntl(rfd, F_GETFL, 0)) < 0) { - syslog(LOG_ERR, "fcntl(rfd, F_GETFL): %m"); + syslog(LOG_INFO, "fcntl(rfd, F_GETFL): %m"); (void) my_close(rfd); continue; } if (fcntl(rfd, F_SETFL, n|PORT_NONBLOCK) != 0) { - syslog(LOG_ERR, "fcntl(rfd, NONBLOCK): %m"); + syslog(LOG_INFO, "fcntl(rfd, NONBLOCK): %m"); (void) my_close(rfd); continue; } @@ -701,7 +746,7 @@ main(argc, argv, envp) len = sizeof ip_opts; if (getsockopt(rfd, IPPROTO_IP, IP_OPTIONS, (char *)ip_opts, &len) < 0) { - syslog(LOG_ERR, + syslog(LOG_INFO, "getsockopt(rfd, IP_OPTIONS): %m"); (void) my_close(rfd); continue; @@ -711,23 +756,31 @@ main(argc, argv, envp) if (!haveComplained((char*) from_addr.sin_addr.s_addr, "rcvd ip options")) { - syslog(LOG_NOTICE, + syslog(LOG_INFO, "rcvd IP_OPTIONS from [%s].%d (ignored)", inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port)); } if (setsockopt(rfd, IPPROTO_IP, IP_OPTIONS, NULL, 0) < 0) { - syslog(LOG_ERR, + syslog(LOG_INFO, "setsockopt(!IP_OPTIONS): %m"); (void) my_close(rfd); continue; } } #endif + if (setsockopt(rfd, SOL_SOCKET, SO_SNDBUF, + (char*)&sbufsize, sizeof(sbufsize)) < 0){ + syslog(LOG_INFO, + "setsockopt(rfd, SO_SNDBUF, %d): %m", + sbufsize); + (void) my_close(rfd); + continue; + } if (setsockopt(rfd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) { - syslog(LOG_ERR, + syslog(LOG_INFO, "setsockopt(rfd, KEEPALIVE): %m"); (void) my_close(rfd); continue; @@ -749,20 +802,21 @@ main(argc, argv, envp) inet_ntoa(sp->s_from.sin_addr), ntohs(sp->s_from.sin_port), rfd)); } - if (streamq) { - dprintf(3, (ddt, "streamq = 0x%x\n",streamq)); - } + if (streamq) + dprintf(3, (ddt, "streamq = 0x%lx\n", + (u_long)streamq)); for (sp = streamq; sp != QSTREAM_NULL; sp = nextsp) { nextsp = sp->s_next; if (!FD_ISSET(sp->s_rfd, &tmpmask)) continue; dprintf(5, (ddt, - "sp x%x rfd %d size %d time %d next x%x\n", - sp, sp->s_rfd, sp->s_size, - sp->s_time, sp->s_next)); + "sp x%lx rfd %d size %d time %d next x%lx\n", + (u_long)sp, sp->s_rfd, sp->s_size, + sp->s_time, (u_long)sp->s_next)); dprintf(5, (ddt, - "\tbufsize %d buf x%x bufp x%x\n", - sp->s_bufsize, sp->s_buf, sp->s_bufp)); + "\tbufsize %d buf x%lx bufp x%lx\n", + sp->s_bufsize, + (u_long)sp->s_buf, (u_long)sp->s_bufp)); if (sp->s_size < 0) { size = INT16SZ - (sp->s_bufp - (u_char *)&sp->s_tempsize); @@ -830,7 +884,7 @@ main(argc, argv, envp) hp = (HEADER *)sp->s_buf; hp->qr = 1; - hp->ra = 1; + hp->ra = (NoRecurse == 0); hp->ancount = 0; hp->qdcount = 0; hp->nscount = 0; @@ -877,11 +931,11 @@ getnetconf() struct ifreq ifreq, *ifr; struct qdatagram *dqp; static int first = 1; - char buf[BUFSIZ], *cp, *cplim; + char buf[32768], *cp, *cplim; u_int32_t nm; time_t my_generation = time(NULL); - ifc.ifc_len = sizeof(buf); + ifc.ifc_len = sizeof buf; ifc.ifc_buf = buf; if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) { syslog(LOG_ERR, "get interface configuration: %m - exiting"); @@ -894,7 +948,7 @@ getnetconf() #else #define my_size(p) (sizeof (p)) #endif - cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ + cplim = buf + ifc.ifc_len; /* skip over if's with big ifr_addr's */ for (cp = buf; cp < cplim; cp += sizeof (ifr->ifr_name) + my_size(ifr->ifr_addr)) { @@ -912,7 +966,7 @@ getnetconf() */ #if !defined(BSD) || (BSD < 199103) if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) { - syslog(LOG_ERR, "get interface addr: %m"); + syslog(LOG_NOTICE, "get interface addr: %m"); continue; } #endif @@ -975,7 +1029,7 @@ getnetconf() &ifreq.ifr_addr)->sin_addr; #ifdef SIOCGIFNETMASK if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) { - syslog(LOG_ERR, "get netmask: %m"); + syslog(LOG_NOTICE, "get netmask: %m"); ntp->mask = net_mask(ntp->my_addr); } else ntp->mask = ((struct sockaddr_in *) @@ -985,7 +1039,7 @@ getnetconf() ntp->mask = net_mask(ntp->my_addr); #endif if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) { - syslog(LOG_ERR, "get interface flags: %m"); + syslog(LOG_NOTICE, "get interface flags: %m"); continue; } #ifdef IFF_LOOPBACK @@ -1005,7 +1059,7 @@ getnetconf() continue; } else if ((ifreq.ifr_flags & IFF_POINTOPOINT)) { if (ioctl(vs, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { - syslog(LOG_ERR, "get dst addr: %m"); + syslog(LOG_NOTICE, "get dst addr: %m"); continue; } ntp->mask = 0xffffffff; @@ -1037,7 +1091,7 @@ getnetconf() * * XXX - need to update enettab/elocal as well. */ - dqflush(my_generation); + dqflush(my_generation); /* With apologies to The Who. */ /* * Create separate qdatagram structure for socket @@ -1107,9 +1161,10 @@ printnetinfo(ntp) register struct netinfo *ntp; { for ( ; ntp != NULL; ntp = ntp->next) { - fprintf(ddt,"addr x%lx mask x%lx", ntp->addr, ntp->mask); - fprintf(ddt," my_addr x%lx", ntp->my_addr.s_addr); - fprintf(ddt," %s\n", inet_ntoa(ntp->my_addr)); + fprintf(ddt, "addr x%lx mask x%lx", + (u_long)ntp->addr, (u_long)ntp->mask); + fprintf(ddt, " my_addr x%lx", ntp->my_addr.s_addr); + fprintf(ddt, " %s\n", inet_ntoa(ntp->my_addr)); } } #endif @@ -1133,12 +1188,12 @@ opensocket(dqp) if (setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) { - syslog(LOG_ERR, "setsockopt(dqp->dq_dfd, reuseaddr): %m"); + syslog(LOG_NOTICE, "setsockopt(dqp->dq_dfd, reuseaddr): %m"); /* XXX press on regardless, this is not too serious. */ } #ifdef SO_RCVBUF m = sizeof(n); - if ((getsockopt(dqp->dq_dfd, SOL_SOCKET, SO_RCVBUF, &n, &m) >= 0) + if ((getsockopt(dqp->dq_dfd, SOL_SOCKET, SO_RCVBUF, (char*)&n, &m) >= 0) && (m == sizeof(n)) && (n < rbufsize)) { (void) setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_RCVBUF, @@ -1146,10 +1201,10 @@ opensocket(dqp) } #endif /* SO_RCVBUF */ if ((n = fcntl(dqp->dq_dfd, F_GETFL, 0)) < 0) { - syslog(LOG_ERR, "fcntl(dfd, F_GETFL): %m"); + syslog(LOG_NOTICE, "fcntl(dfd, F_GETFL): %m"); /* XXX press on regardless, but this really is a problem. */ } else if (fcntl(dqp->dq_dfd, F_SETFL, n|PORT_NONBLOCK) != 0) { - syslog(LOG_ERR, "fcntl(dqp->dq_dfd, non-blocking): %m"); + syslog(LOG_NOTICE, "fcntl(dqp->dq_dfd, non-blocking): %m"); /* XXX press on regardless, but this really is a problem. */ } /* @@ -1160,10 +1215,11 @@ opensocket(dqp) */ nsaddr.sin_addr = dqp->dq_addr; if (bind(dqp->dq_dfd, (struct sockaddr *)&nsaddr, sizeof(nsaddr))) { - syslog(LOG_ERR, "bind(dfd=%d, [%s].%d): %m - exiting", + syslog(LOG_NOTICE, "bind(dfd=%d, [%s].%d): %m", dqp->dq_dfd, inet_ntoa(nsaddr.sin_addr), ntohs(nsaddr.sin_port)); #if !defined(sun) + syslog(LOG_ERR, "exiting"); exit(1); #endif } @@ -1180,7 +1236,7 @@ onhup() { int save_errno = errno; #if defined(SYSV) - (void)signal(SIGHUP, onhup); + (void)signal(SIGHUP, (SIG_FN (*)())onhup); #endif /* SYSV */ needreload = 1; errno = save_errno; @@ -1197,7 +1253,7 @@ maint_alarm() { int save_errno = errno; #if defined(SYSV) - (void)signal(SIGALRM, maint_alarm); + (void)signal(SIGALRM, (SIG_FN (*)())maint_alarm); #endif /* SYSV */ needmaint = 1; errno = save_errno; @@ -1216,6 +1272,17 @@ onintr() } #endif /* ALLOW_UPDATES */ +#ifdef XSTATS +/* + * Signal handler to write log information + */ +static SIG_FN +onintr() +{ + needToExit = 1; +} +#endif /* XSTATS */ + /* * Signal handler to schedule a data base dump. Do this instead of dumping the * data base immediately, to avoid seeing it in a possibly inconsistent state @@ -1227,7 +1294,7 @@ setdumpflg() { int save_errno = errno; #if defined(SYSV) - (void)signal(SIGINT, setdumpflg); + (void)signal(SIGINT, (SIG_FN (*)())setdumpflg); #endif /* SYSV */ needToDoadump = 1; errno = save_errno; @@ -1251,17 +1318,17 @@ setdebug(code) ddt = freopen(debugfile, "w+", stderr); if ( ddt == NULL) { - syslog(LOG_WARNING, "can't open debug file %s: %m", - debugfile); + syslog(LOG_NOTICE, "can't open debug file %s: %m", + debugfile); debug = 0; } else { -#if defined(SYSV) +#if defined(HAVE_SETVBUF) setvbuf(ddt, NULL, _IOLBF, BUFSIZ); #else setlinebuf(ddt); #endif if ((n = fcntl(fileno(ddt), F_GETFL, 0)) < 0) { - syslog(LOG_WARNING, + syslog(LOG_INFO, "fcntl(ddt, F_GETFL): %m"); } else { (void) fcntl(fileno(ddt), F_SETFL, n|O_APPEND); @@ -1286,7 +1353,7 @@ setIncrDbgFlg() { int save_errno = errno; #if defined(SYSV) - (void)signal(SIGUSR1, setIncrDbgFlg); + (void)signal(SIGUSR1, (SIG_FN (*)())setIncrDbgFlg); #endif /* SYSV */ #ifdef DEBUG if (debug == 0) { @@ -1310,7 +1377,7 @@ setNoDbgFlg() { int save_errno = errno; #if defined(SYSV) - (void)signal(SIGUSR2, setNoDbgFlg); + (void)signal(SIGUSR2, (SIG_FN (*)())setNoDbgFlg); #endif /* SYSV */ setdebug(0); errno = save_errno; @@ -1325,7 +1392,7 @@ setQrylogFlg() { int save_errno = errno; #if defined(SYSV) - (void)signal(SIGWINCH, setQrylogFlg); + (void)signal(SIGWINCH, (SIG_FN (*)())setQrylogFlg); #endif /* SYSV */ qrylog = !qrylog; syslog(LOG_NOTICE, "query log %s\n", qrylog ?"on" :"off"); @@ -1341,7 +1408,7 @@ setstatsflg() { int save_errno = errno; #if defined(SYSV) - (void)signal(SIGIOT, setstatsflg); + (void)signal(SIGIOT, (SIG_FN (*)())setstatsflg); #endif /* SYSV */ needStatsDump = 1; errno = save_errno; @@ -1352,7 +1419,7 @@ setchkptflg() { int save_errno = errno; #if defined(SYSV) - (void)signal(SIGQUIT, setchkptflg); + (void)signal(SIGQUIT, (SIG_FN (*)())setchkptflg); #endif /* SYSV */ needToChkpt = 1; errno = save_errno; @@ -1371,7 +1438,7 @@ sigprof() { int save_errno = errno; #if defined(SYSV) - (void)signal(SIGSYS, sigprof); + (void)signal(SIGSYS, (SIG_FN (*)())sigprof); #endif /* SYSV */ dprintf(1, (ddt, "sigprof()\n")); if (fork() == 0) @@ -1396,7 +1463,7 @@ sqadd() syslog(LOG_ERR, "sqadd: calloc: %m"); return (QSTREAM_NULL); } - dprintf(3, (ddt, "sqadd(x%x)\n", sqp)); + dprintf(3, (ddt, "sqadd(x%lx)\n", (u_long)sqp)); sqp->s_next = streamq; streamq = sqp; @@ -1415,8 +1482,8 @@ sqrm(qp) { register struct qstream *qsp; - dprintf(2, (ddt, "sqrm(%#x, %d ) rfcnt=%d\n", - qp, qp->s_rfd, qp->s_refcnt)); + dprintf(2, (ddt, "sqrm(%#lx, %d) rfcnt=%d\n", + (u_long)qp, qp->s_rfd, qp->s_refcnt)); if (qp->s_bufsize != 0) free(qp->s_buf); @@ -1480,7 +1547,7 @@ dqflush(gen) if (dqp->dq_addr.s_addr == INADDR_ANY || dqp->dq_gen == gen) continue; - syslog(LOG_CRIT, "interface [%s] missing; deleting", + syslog(LOG_NOTICE, "interface [%s] missing; deleting", inet_ntoa(dqp->dq_addr)); } if (pqp != NULL) @@ -1573,6 +1640,30 @@ net_mask(in) return (htonl(IN_CLASSC_NET)); } +/* + * These are here in case we ever want to get more clever, like perhaps + * using a bitmap to keep track of outstanding queries and a random + * allocation scheme to make it a little harder to predict them. Note + * that the resolver will need the same protection so the cleverness + * should be put there rather than here; this is just an interface layer. + */ + +void +nsid_init() +{ + nsid_state = res_randomid(); +} + +u_int16_t +nsid_next() +{ + if (nsid_state == 65535) + nsid_state = 0; + else + nsid_state++; + return (nsid_state); +} + #if defined(BSD43_BSD43_NFS) /* junk needed for old Sun NFS licensees */ #undef dn_skipname diff --git a/usr.sbin/named/ns_maint.c b/usr.sbin/named/ns_maint.c index 927fde3fde58..541ac85c0375 100644 --- a/usr.sbin/named/ns_maint.c +++ b/usr.sbin/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 4.9.1.15 1994/06/11 22:04:46 vixie Exp $"; +static char rcsid[] = "$Id: ns_maint.c,v 8.8 1995/06/29 09:26:17 vixie Exp $"; #endif /* not lint */ /* @@ -86,7 +86,6 @@ static int xfers_running, /* # of xfers running */ static void startxfer __P((struct zoneinfo *)), abortxfer __P((struct zoneinfo *)), addxfer __P((struct zoneinfo *)), - qserial_query __P((struct zoneinfo *)), tryxfer __P((void)); #define qserial_qfull() (qserials_running == MAXQSERIAL) @@ -94,6 +93,9 @@ static void startxfer __P((struct zoneinfo *)), #ifdef CLEANCACHE static time_t cache_time; #endif +#ifdef XSTATS +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, @@ -108,7 +110,7 @@ ns_maint() gettime(&tt); - dprintf(1, (ddt, "\nns_maint(); now %s", ctime(&tt.tv_sec))); + dprintf(1, (ddt, "\nns_maint(); now %s", ctimel(tt.tv_sec))); alarm_pending = 0; for (zp = zones, zonenum = 0; zp < &zones[nzones]; zp++, zonenum++) { @@ -121,21 +123,27 @@ ns_maint() case Z_CACHE: doachkpt(); - zp->z_time = tt.tv_sec + zp->z_refresh; + ns_refreshtime(zp, tt.tv_sec); break; case Z_SECONDARY: #ifdef STUBS case Z_STUB: #endif + if (zp->z_serial != 0 && + ((zp->z_lastupdate + zp->z_expire) < + tt.tv_sec) + ) { + zp->z_serial = 0; + } if (zp->z_flags & (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL)) { - zp->z_time = tt.tv_sec + zp->z_refresh; + ns_refreshtime(zp, tt.tv_sec); break; } if (zp->z_flags & Z_XFER_RUNNING) { abortxfer(zp); - zp->z_time = tt.tv_sec + zp->z_retry; + ns_retrytime(zp, tt.tv_sec); break; } qserial_query(zp); @@ -148,7 +156,7 @@ ns_maint() */ if (zp->z_flags & Z_CHANGED) { zonedump(zp); - zp->z_time = tt.tv_sec + zp->z_refresh; + ns_refreshtime(zp, tt.tv_sec); } break; #endif /* ALLOW_UPDATES */ @@ -156,8 +164,19 @@ ns_maint() gettime(&tt); } } -#ifdef CLEANCACHE - remove_zone(hashtab, 0, 0); +#ifdef CLEANCACHE + if ((cache_time + cache_interval) <= tt.tv_sec) { + if (cache_time) + remove_zone(hashtab, 0, 0); + cache_time = tt.tv_sec; + } +#endif +#ifdef XSTATS + if (stats_time + stats_interval <= tt.tv_sec) { + if (stats_time) + ns_logstats(); + stats_time = tt.tv_sec; + } #endif if (!needmaint) sched_maint(); @@ -174,7 +193,7 @@ sched_maint() register struct zoneinfo *zp; struct itimerval ival; #ifdef CLEANCACHE - time_t next_refresh = cache_time + 3600; + time_t next_refresh = cache_time + cache_interval; #else time_t next_refresh = 0; #endif @@ -207,8 +226,8 @@ sched_maint() alarm_pending = 1; } (void) setitimer(ITIMER_REAL, &ival, (struct itimerval *)NULL); - dprintf(1, (ddt, "sched_maint: Next interrupt in %d sec\n", - ival.it_value.tv_sec)); + dprintf(1, (ddt, "sched_maint: Next interrupt in %lu sec\n", + (u_long)ival.it_value.tv_sec)); } /* @@ -223,7 +242,7 @@ markUpToDate(zp) zp->z_flags &= ~Z_SYSLOGGED; zp->z_lastupdate = tt.tv_sec; - zp->z_time = tt.tv_sec + zp->z_refresh; + ns_refreshtime(zp, tt.tv_sec); /* * Restore Z_AUTH in case expired, * but only if there were no errors @@ -258,7 +277,7 @@ markUpToDate(zp) * Query for the serial number of a zone, so that * we can check to see if we need to transfer it. */ -static void +void qserial_query(zp) struct zoneinfo *zp; { @@ -270,15 +289,16 @@ qserial_query(zp) return; qp = sysquery(zp->z_origin, zp->z_class, T_SOA, - zp->z_addr, zp->z_addrcnt); + zp->z_addr, zp->z_addrcnt, QUERY); if (!qp) { - dprintf(1, (ddt, "qserial_query(%s) FAILED\n", zp->z_origin)); + syslog(LOG_INFO, "qserial_query(%s): sysquery FAILED", + zp->z_origin); return; /* XXX - this is bad, we should do something */ } qp->q_flags |= Q_ZSERIAL; qp->q_zquery = zp; zp->z_flags |= Z_QSERIAL; - zp->z_time = tt.tv_sec + zp->z_refresh; + ns_refreshtime(zp, tt.tv_sec); qserials_running++; dprintf(1, (ddt, "qserial_query(%s) QUEUED\n", zp->z_origin)); } @@ -291,7 +311,8 @@ qserial_answer(qp, serial) struct zoneinfo *zp = qp->q_zquery; int was_qfull = qserial_qfull(); - dprintf(1, (ddt, "qserial_answer(%s, %lu)\n", zp->z_origin, serial)); + dprintf(1, (ddt, "qserial_answer(%s, %lu)\n", + zp->z_origin, (u_long)serial)); zp->z_flags &= ~Z_QSERIAL; qp->q_flags &= ~Q_ZSERIAL; /* keeps us from being called twice */ qserials_running--; @@ -319,7 +340,6 @@ qserial_answer(qp, serial) dprintf(1, (ddt, "qserial_answer: zone serial is still OK\n")); markUpToDate(zp); } - done: if (was_qfull) needmaint = 1; } @@ -351,7 +371,7 @@ startxfer(zp) argv[argc++] = "-f"; argv[argc++] = zp->z_source; argv[argc++] = "-s"; - sprintf(serial_str, "%lu", zp->z_serial); + sprintf(serial_str, "%lu", (u_long)zp->z_serial); argv[argc++] = serial_str; #ifdef GEN_AXFR argv[argc++] = "-C"; @@ -397,7 +417,7 @@ startxfer(zp) if (aIsUs(a) && !haveComplained(zp->z_origin, (char*)startxfer)) { - syslog(LOG_ERR, + syslog(LOG_NOTICE, "attempted to fetch zone %s from self (%s)", zp->z_origin, inet_ntoa(a)); continue; @@ -419,10 +439,8 @@ startxfer(zp) #endif /* ECHOARGS */ #endif /* DEBUG */ -#ifdef SYSV -#define vfork fork -#else gettime(&tt); +#ifndef SYSV omask = sigblock(sigmask(SIGCHLD)); #endif if ((pid = vfork()) == -1) { @@ -452,6 +470,25 @@ startxfer(zp) #endif } +const char * +zoneTypeString(zp) + const struct zoneinfo *zp; +{ + static char ret[sizeof "(4294967296?)"]; /* 2^32 */ + + switch (zp->z_type) { + case Z_PRIMARY: return ("primary"); + case Z_SECONDARY: return ("secondary"); +#ifdef STUBS + case Z_STUB: return ("stub"); +#endif + case Z_CACHE: return ("cache"); + default: + sprintf(ret, "(%lu?)", (u_long)zp->z_type); + return (ret); + } +} + #ifdef DEBUG void printzoneinfo(zonenum) @@ -459,7 +496,6 @@ int zonenum; { struct timeval tt; struct zoneinfo *zp = &zones[zonenum]; - char *ZoneType; if (!debug) return; @@ -467,25 +503,6 @@ int zonenum; fprintf(ddt, "printzoneinfo(%d):\n", zonenum); gettime(&tt); - switch (zp->z_type) { - case Z_PRIMARY: - ZoneType = "Primary"; - break; - case Z_SECONDARY: - ZoneType = "Secondary"; - break; -#ifdef STUBS - case Z_STUB: - ZoneType = "Stub"; - break; -#endif - case Z_CACHE: - ZoneType = "Cache"; - break; - default: - ZoneType = "Unknown"; - break; - } if (zp->z_origin != NULL && (zp->z_origin[0] == '\0')) fprintf(ddt, "origin ='.'"); else @@ -493,20 +510,21 @@ int zonenum; #ifdef GEN_AXFR fprintf(ddt, ", class = %d", zp->z_class); #endif - fprintf(ddt, ", type = %s", ZoneType); + fprintf(ddt, ", type = %s", zoneTypeString(zp)); if (zp->z_source) fprintf(ddt,", source = %s\n", zp->z_source); - fprintf(ddt, "z_refresh = %ld", zp->z_refresh); - fprintf(ddt, ", retry = %ld", zp->z_retry); - fprintf(ddt, ", expire = %ld", zp->z_expire); - fprintf(ddt, ", minimum = %ld", zp->z_minimum); - fprintf(ddt, ", serial = %lu\n", zp->z_serial); - fprintf(ddt, "z_time = %d", zp->z_time); + fprintf(ddt, "z_refresh = %lu", (u_long)zp->z_refresh); + fprintf(ddt, ", retry = %lu", (u_long)zp->z_retry); + fprintf(ddt, ", expire = %lu", (u_long)zp->z_expire); + fprintf(ddt, ", minimum = %lu", (u_long)zp->z_minimum); + fprintf(ddt, ", serial = %lu\n", (u_long)zp->z_serial); + fprintf(ddt, "z_time = %lu", (u_long)zp->z_time); if (zp->z_time) { - fprintf(ddt, ", now time : %d sec", tt.tv_sec); - fprintf(ddt, ", time left: %d sec", zp->z_time - tt.tv_sec); + fprintf(ddt, ", now time : %lu sec", (u_long)tt.tv_sec); + fprintf(ddt, ", time left: %lu sec", + (int)(zp->z_time - tt.tv_sec)); } - fprintf(ddt, "; flags %x\n", zp->z_flags); + fprintf(ddt, "; flags %lx\n", (u_long)zp->z_flags); } #endif /* DEBUG */ @@ -570,6 +588,146 @@ remove_zone(htp, zone) } } } + +#ifdef PURGE_ZONE +static void purge_z_2(); +static bottom_of_zone(); + +void +purge_zone(dname, htp, class) + const char *dname; + register struct hashbuf *htp; + int class; +{ + const char *fname; + struct databuf *dp, *pdp; + struct namebuf *np; + struct hashbuf *phtp = htp; + + dprintf(1, (ddt, "purge_zone(%s,%d)\n", dname, class)); + if ((np = nlookup(dname, &phtp, &fname, 0)) && dname == fname) { + for (pdp = NULL, dp = np->n_data; dp != NULL; ) { + if (dp->d_class == class) + dp = rm_datum(dp, np, pdp); + else { + pdp = dp; + dp = dp->d_next; + } + } + + if (np->n_hash) { + + purge_z_2(np->n_hash, class); + + if (np->n_hash->h_cnt == 0) { + free((char*)np->n_hash); + np->n_hash = NULL; + } + } + + /* remove entry from cache, if required */ + if ((np->n_hash == NULL) && (np->n_data == NULL)) { + struct namebuf **npp, **nppend; + struct namebuf *npn, *pnp, *nnp; + + dprintf(3,(ddt, "purge_zone: cleaning cache\n")); + + /* walk parent hashtable looking for ourself */ + if (np->n_parent) + phtp = np->n_parent->n_hash; + else + phtp = htp; /* top / root zone */ + + if (phtp) { + nppend = phtp->h_tab + phtp->h_size; + + for (npp = phtp->h_tab; npp < nppend; npp++) { + for (pnp = NULL, nnp = *npp; + nnp != NULL; + nnp = npn + ) { + if (nnp == np) { + dprintf(3,(ddt, "purge_zone: found our selves\n")); + npn = rm_name(nnp, npp, pnp); + phtp->h_cnt--; + } else { + npn = nnp->n_next; + pnp = nnp; + } + } + } + } + + } + } +} + +static void +purge_z_2(htp, class) + register struct hashbuf *htp; + register int class; +{ + register struct databuf *dp, *pdp; + register struct namebuf *np, *pnp, *npn; + struct namebuf **npp, **nppend; + + nppend = htp->h_tab + htp->h_size; + for (npp = htp->h_tab; npp < nppend; npp++) + for (pnp = NULL, np = *npp; np != NULL; np = npn) { + if (!bottom_of_zone(np->n_data, class)) { + for (pdp = NULL, dp = np->n_data; dp != NULL; ) { + if (dp->d_class == class) + dp = rm_datum(dp, np, pdp); + else { + pdp = dp; + dp = dp->d_next; + } + } + + if (np->n_hash) { + /* call recursively to remove subdomains. */ + purge_z_2(np->n_hash, class); + + /* if now empty, free it */ + if (np->n_hash->h_cnt == 0) { + free((char*)np->n_hash); + np->n_hash = NULL; + } + } + + } + + if ((np->n_hash == NULL) && (np->n_data == NULL)) { + npn = rm_name(np, npp, pnp); + htp->h_cnt--; + } else { + npn = np->n_next; + pnp = np; + } + } +} + +static int +bottom_of_zone(dp, class) + struct databuf *dp; + int class; +{ + for ( ; dp ; dp = dp->d_next) { + if (dp->d_class != class) + continue; + if (dp->d_zone == 0) + continue; +#ifdef NCACHE + if (dp->d_rcode) /* this should not occur */ + continue; +#endif + if (dp->d_type == T_SOA) + return (1); + } + dprintf(3, (ddt, "bottom_of_zone() == 0\n")); + return (0); +} +#endif /* * Handle XFER limit for a nameserver. @@ -611,7 +769,7 @@ abortxfer(zp) kill(zp->z_xferpid, SIGKILL); syslog(LOG_NOTICE, "zone transfer timeout for \"%s\"; pid %lu killed", zp->z_origin, (u_long)zp->z_xferpid); - zp->z_time = tt.tv_sec + zp->z_retry; + ns_retrytime(zp, tt.tv_sec); (void) nxfers(zp, -1); xfers_running--; } @@ -662,7 +820,7 @@ endxfer() "named-xfer exited with signal %d\n", WTERMSIG(status)); } - zp->z_time = tt.tv_sec + zp->z_retry; + ns_retrytime(zp, tt.tv_sec); } else { switch (exitstatus) { case XFER_UPTODATE: @@ -676,29 +834,26 @@ endxfer() break; case XFER_TIMEOUT: - dprintf(1, (ddt, - "zoneref: Masters for secondary zone %s unreachable\n", - zp->z_origin)); if (!(zp->z_flags & Z_SYSLOGGED)) { zp->z_flags |= Z_SYSLOGGED; syslog(LOG_NOTICE, - "zoneref: Masters for secondary zone %s unreachable", + "zoneref: Masters for secondary zone \"%s\" unreachable", zp->z_origin); } - zp->z_time = tt.tv_sec + zp->z_retry; + ns_retrytime(zp, tt.tv_sec); break; default: if (!(zp->z_flags & Z_SYSLOGGED)) { zp->z_flags |= Z_SYSLOGGED; syslog(LOG_NOTICE, - "named-xfer for %s exited %d", + "named-xfer for \"%s\" exited %d", zp->z_origin, exitstatus); } /* FALLTHROUGH */ case XFER_FAIL: zp->z_flags |= Z_SYSLOGGED; - zp->z_time = tt.tv_sec + zp->z_retry; + ns_retrytime(zp, tt.tv_sec); break; } /*switch*/ break; @@ -707,32 +862,73 @@ endxfer() } /*while*/ tryxfer(); #if defined(SYSV) - (void)signal(SIGCLD, endxfer); + (void)signal(SIGCLD, (SIG_FN (*)()) endxfer); #endif errno = save_errno; } /* - * Try to start some xfers + * Try to start some xfers - new "fair scheduler" by Bob Heiney @DEC (1995) */ static void tryxfer() { - struct zoneinfo *zp; + static struct zoneinfo *zp = NULL; + static struct zoneinfo *lastzones = NULL; + static int lastnzones = 0; + struct zoneinfo *startzp, *stopzp; + + /* initialize, and watch out for changes in zones! */ + if (lastzones != zones) { + if (lastzones != NULL) + syslog(LOG_INFO, "zones changed: %p != %p", + lastzones, zones); + lastzones = zones; + zp = zones; + } + + /* did zones shrink? */ + if (lastnzones > nzones) { + syslog(LOG_INFO, "zones shrunk"); + zp = zones; + } + lastnzones = nzones; + + if (zp == zones) + stopzp = &zones[nzones-1]; + else + stopzp = zp - 1; + + dprintf(3, (ddt, "tryxfer start zp=%p stopzp=%p def=%d running=%d\n", + zp, stopzp, xfers_deferred, xfers_running)); - for (zp = zones; zp < &zones[nzones]; zp++) { + startzp = zp; + for (;;) { int xfers; if (!xfers_deferred || xfers_running >= max_xfers_running) break; if ((xfers = nxfers(zp, 0)) != -1 && - xfers < MAX_XFERS_PERNS && + xfers < max_xfers_per_ns && (zp->z_flags & Z_NEED_XFER)) { nxfers(zp, 1); xfers_deferred--; startxfer(zp); } + + if (zp == stopzp) { + dprintf(3, (ddt, "tryxfer stop mark\n")); + zp = startzp; + break; + } + + zp++; + /* wrap around? */ + if (zp == &zones[nzones]) + zp = zones; } + dprintf(3, (ddt, "tryxfer stop zp=%p\n", zp)); + if (!needmaint) sched_maint(); } @@ -756,13 +952,13 @@ loadxfer() #else remove_zone(hashtab, zp - zones); #endif - if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0) +#ifdef PURGE_ZONE + purge_zone(zp->z_origin, hashtab, zp->z_class); +#endif + if (!db_load(zp->z_source, zp->z_origin, zp, NULL)) zp->z_flags |= Z_AUTH; if (zp->z_flags & Z_TMP_FILE) (void) unlink(zp->z_source); - syslog(LOG_INFO, - "Zone \"%s\" (class %d) xfer'd and loaded (serial %lu)", - zp->z_origin, zp->z_class, zp->z_serial); } } if (!needmaint) diff --git a/usr.sbin/named/ns_ncache.c b/usr.sbin/named/ns_ncache.c index 54083428f979..bea17c6cfb67 100644 --- a/usr.sbin/named/ns_ncache.c +++ b/usr.sbin/named/ns_ncache.c @@ -144,8 +144,9 @@ cache_n_resp(msg, msglen) return; } dprintf(4, (ddt, - "ncache succeeded: d:%s, t:%d, c:%d rcode:%d ttl:%d\n", - dname,type,class,dp->d_rcode, dp->d_ttl-tt.tv_sec)); + "ncache succeeded: [%s %s %s] rcode:%d ttl:%l\n", + dname, p_type(type), p_class(class), + dp->d_rcode, (long)(dp->d_ttl-tt.tv_sec))); return; } diff --git a/usr.sbin/named/ns_req.c b/usr.sbin/named/ns_req.c index afc3fc5af271..1cfbef9f86f9 100644 --- a/usr.sbin/named/ns_req.c +++ b/usr.sbin/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 4.9.1.22 1994/07/23 23:23:56 vixie Exp $"; +static char rcsid[] = "$Id: ns_req.c,v 8.8 1995/06/29 09:26:17 vixie Exp $"; #endif /* not lint */ /* @@ -74,8 +74,10 @@ static char rcsid[] = "$Id: ns_req.c,v 4.9.1.22 1994/07/23 23:23:56 vixie Exp $" #include "named.h" struct addinfo { - char *a_dname; /* domain name */ - u_int a_class; /* class for address */ + char *a_dname; /* domain name */ + char *a_rname; /* referred by */ + u_int16_t a_rtype; /* referred by */ + u_int16_t a_class; /* class for address */ }; enum req_action { Finish, Refuse, Return }; @@ -86,18 +88,23 @@ static enum req_action req_query __P((HEADER *hp, u_char **cpp, u_char *eom, u_char *msg, int dfd, struct sockaddr_in *from)); -#ifdef INVQ static enum req_action req_iquery __P((HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, u_char *msg, struct sockaddr_in *from)); + +#ifdef BIND_NOTIFY +static enum req_action req_notify __P((HEADER *hp, u_char **cpp, u_char *eom, + u_char *msg,struct sockaddr_in *from)); #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 *)), - printSOAdata __P((struct databuf)); + u_char *, int, int, const char *)); #ifdef ALLOW_UPDATES static int InitDynUpdate __P((register HEADER *hp, @@ -110,7 +117,8 @@ static int InitDynUpdate __P((register HEADER *hp, #endif static struct addinfo addinfo[NADDRECS]; -static void addname __P((char *, u_int16_t)); +static void addname __P((const char *, const char *, + u_int16_t, u_int16_t)); /* * Process request using database; assemble and send response. @@ -126,12 +134,12 @@ ns_req(msg, msglen, buflen, qsp, from, dfd) register HEADER *hp = (HEADER *) msg; u_char *cp, *eom; enum req_action action; + int n; #ifdef DEBUG if (debug > 3) { - fprintf(ddt, "ns_req(from=[%s].%d)\n", - inet_ntoa(from->sin_addr), ntohs(from->sin_port)); - fp_query(msg, ddt); + fprintf(ddt, "ns_req(from=%s)\n", sin_ntoa(from)); + fp_nquery(msg, msglen, ddt); } #endif @@ -148,19 +156,17 @@ ns_req(msg, msglen, buflen, qsp, from, dfd) return; } - /* its a query and these bits have no business + /* it's not a response so these bits have no business * being set. will later simplify work if we can * safely assume these are always 0 when a query - * comes in + * comes in. */ hp->aa = hp->ra = 0; hp->rcode = NOERROR; cp = msg + HFIXEDSZ; eom = msg + msglen; - - dnptrs[0] = msg; - dnptrs[1] = NULL; + buflen -= HFIXEDSZ; free_addinfo(); /* sets addcount to zero */ dnptrs[0] = NULL; @@ -172,10 +178,14 @@ ns_req(msg, msglen, buflen, qsp, from, dfd) msg, dfd, from); break; -#ifdef INVQ case IQUERY: action = req_iquery(hp, &cp, eom, &buflen, msg, from); break; + +#ifdef BIND_NOTIFY + case NS_NOTIFY_OP: + action = req_notify(hp, &cp, eom, msg, from); + break; #endif #ifdef ALLOW_UPDATES @@ -188,14 +198,14 @@ ns_req(msg, msglen, buflen, qsp, from, dfd) * 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) { + /* 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 @@ -207,11 +217,11 @@ ns_req(msg, msglen, buflen, qsp, from, dfd) */ action = Finish; } -#endif /* ALLOW_UPDATES */ case ZONEREF: dprintf(1, (ddt, "Refresh Zone\n")); /*FALLTHROUGH*/ +#endif /* ALLOW_UPDATES */ default: dprintf(1, (ddt, "ns_req: Opcode %d not implemented\n", @@ -238,48 +248,47 @@ ns_req(msg, msglen, buflen, qsp, from, dfd) /* rest of the function handles this case */ break; default: - syslog(LOG_CRIT, "bad action variable in ns_req() -- %d", - (int) action); - return; /* XXX - should really exit here */ + panic(-1, "ns_req: bad action variable"); + /*NOTREACHED*/ } /* * apply final polish */ hp->qr = 1; /* set Response flag */ - if (NoRecurse) - hp->ra = 0; /* No recursion; maybe we're a root server */ - else - hp->ra = 1; /* Recursion is Available */ + hp->ra = (NoRecurse == 0); hp->ancount = htons(hp->ancount); - if (addcount) { - int n = doaddinfo(hp, cp, buflen); - cp += n; - buflen -= n; - } - dprintf(1, (ddt, "ns_req: answer -> [%s].%d fd=%d id=%d %s\n", - inet_ntoa(from->sin_addr), - ntohs(from->sin_port), + n = doaddinfo(hp, cp, buflen); + cp += n; + buflen -= n; + + dprintf(1, (ddt, "ns_req: answer -> %s fd=%d id=%d size=%d %s\n", + sin_ntoa(from), (qsp == QSTREAM_NULL) ?dfd :qsp->s_rfd, - ntohs(hp->id), local(from) == NULL ? "Remote" : "Local")); + ntohs(hp->id), cp - msg, local(from) == NULL ? "Remote" : "Local")); #ifdef DEBUG if (debug >= 10) - fp_query(msg, ddt); + fp_nquery(msg, cp - msg, ddt); #endif if (qsp == QSTREAM_NULL) { - if (sendto(dfd, msg, cp - msg, 0, + if (sendto(dfd, (char*)msg, cp - msg, 0, (struct sockaddr *)from, sizeof(*from)) < 0) { if (!haveComplained((char*)from->sin_addr.s_addr, sendtoStr)) - syslog(LOG_NOTICE, - "ns_req: sendto([%s].%d): %m", - inet_ntoa(from->sin_addr), - ntohs(from->sin_port)); + syslog(LOG_INFO, + "ns_req: sendto(%s): %m", + sin_ntoa(from)); nameserIncr(from->sin_addr, nssSendtoErr); } nameserIncr(from->sin_addr, nssSentAns); +#ifdef XSTATS + if (hp->rcode == NXDOMAIN) + nameserIncr(from->sin_addr, nssSentNXD); + if (!hp->aa) + nameserIncr(from->sin_addr, nssSentNaAns); +#endif } else { (void) writemsg(qsp->s_rfd, msg, cp - msg); sq_done(qsp); @@ -290,6 +299,124 @@ ns_req(msg, msglen, buflen, qsp, from, dfd) } } +#ifdef BIND_NOTIFY +int +findZonePri(zp, from) + register const struct zoneinfo *zp; + const struct sockaddr_in *from; +{ + register u_int32_t from_addr = from->sin_addr.s_addr; + register int i; + + for (i = 0; (u_int)i < zp->z_addrcnt; i++) + if (zp->z_addr[i].s_addr == from_addr) + return (i); + return (-1); +} + +static enum req_action +req_notify(hp, cpp, eom, msg, from) + HEADER *hp; + u_char **cpp, *eom, *msg; + struct sockaddr_in *from; +{ + int n, type, class, zn; + char dnbuf[MAXDNAME]; + struct namebuf *np; + const char *fname; + struct hashbuf *htp = hashtab; /* lookup relative to root */ + + /* valid notify's have one question and zero answers */ + if ((ntohs(hp->qdcount) != 1) + || hp->ancount + || hp->nscount + || hp->arcount) { + dprintf(1, (ddt, "FORMERR Notify header counts wrong\n")); + hp->qdcount = 0; + hp->ancount = 0; + hp->nscount = 0; + hp->arcount = 0; + hp->rcode = FORMERR; + return (Finish); + } + + n = dn_expand(msg, eom, *cpp, dnbuf, sizeof dnbuf); + if (n < 0) { + dprintf(1, (ddt, "FORMERR Query expand name failed\n")); + hp->rcode = FORMERR; + return (Finish); + } + *cpp += n; + GETSHORT(type, *cpp); + GETSHORT(class, *cpp); + syslog(LOG_INFO, "rcvd NOTIFY(%s %s %s)", + dnbuf, p_class(class), p_type(type)); + /* XXX - when answers are allowed, we'll need to do compression + * correctly here, and we will need to check for packet underflow. + */ + np = nlookup(dnbuf, &htp, &fname, 0); + if (!np) { + syslog(LOG_INFO, "rcvd NOTIFY for \"%s\", name not in cache", + dnbuf); + hp->rcode = SERVFAIL; + return (Finish); + } + zn = findMyZone(np, class); + if (zn == DB_Z_CACHE || zones[zn].z_type != Z_SECONDARY) { + /* this can come if a user did an AXFR of some zone somewhere + * and that zone's server now wants to tell us that the SOA + * has changed. AXFR's always come from nonpriv ports so it + * isn't possible to know whether it was the server or just + * "dig". this condition can be avoided by using secure zones + * since that way only real secondaries can AXFR from you. + */ + syslog(LOG_INFO, + "NOTIFY for non-secondary name (%s), from %s", + dnbuf, sin_ntoa(from)); + goto refuse; + } + if (findZonePri(&zones[zn], from) == -1) { + syslog(LOG_INFO, + "NOTIFY from non-master server (zone %s), from %s", + zones[zn].z_origin, sin_ntoa(from)); + goto refuse; + } + switch (type) { + case T_SOA: + if (strcasecmp(dnbuf, zones[zn].z_origin) != 0) { + syslog(LOG_INFO, + "NOTIFY(SOA) for non-origin (%s), from %s", + dnbuf, sin_ntoa(from)); + goto refuse; + } + if (zones[zn].z_flags & + (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL|Z_XFER_RUNNING)) { + syslog(LOG_INFO, + "NOTIFY(SOA) for zone already xferring (%s)", + dnbuf); + goto noerror; + } + zones[zn].z_time = tt.tv_sec; + qserial_query(&zones[zn]); + /* XXX: qserial_query() can fail due to queue full condition; + * we should detect that case here and do something. + */ + break; + default: + /* unimplemented, but it's not a protocol error, just + * something to be ignored. + */ + break; + } + noerror: + hp->rcode = NOERROR; + return (Finish); + refuse: + hp->rcode = REFUSED; + return (Finish); +} +#endif /*BIND_NOTIFY*/ + static enum req_action req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from) HEADER *hp; @@ -303,14 +430,26 @@ req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from) int n, class, type, count, foundname, founddata, omsglen, cname; u_int16_t id; u_char **dpp, *omsg, *answers; - char dnbuf[MAXDNAME], *dname, *fname; + char dnbuf[MAXDNAME], *dname; + const char *fname; struct hashbuf *htp; struct databuf *nsp[NSMAX]; - struct namebuf *np; + struct namebuf *np, *anp; struct qinfo *qp; struct netinfo *lp; +#ifdef SECURE_ZONES + struct zoneinfo *zp; +#endif + struct databuf *dp; nameserIncr(from->sin_addr, nssRcvdQ); + +#ifdef XSTATS + /* Statistics for queries coming from port <> 53, suspect some kind of forwarder */ + if (from->sin_port != ns_port) + nameserIncr(from->sin_addr, nssNotNsQ); +#endif + #ifdef DATUMREFCNT nsp[0] = NULL; #endif @@ -368,10 +507,8 @@ req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from) /* refuse request if not a TCP connection */ if (qsp == QSTREAM_NULL) { syslog(LOG_INFO, - "rejected UDP AXFR from [%s].%u for \"%s\"", - inet_ntoa(from->sin_addr), - ntohs(from->sin_port), - *dnbuf ? dnbuf : "."); + "rejected UDP AXFR from %s for \"%s\"", + sin_ntoa(from), *dnbuf ? dnbuf : "."); return (Refuse); } /* the position of this is subtle. */ @@ -384,20 +521,16 @@ req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from) */ if (!addr_on_netlist(from->sin_addr, xfrnets)) { syslog(LOG_INFO, - "unapproved AXFR from [%s].%u for %s", - inet_ntoa(from->sin_addr), - ntohs(from->sin_port), - *dnbuf ? dnbuf : "."); + "unapproved AXFR from %s for %s", + sin_ntoa(from), *dnbuf ? dnbuf : "."); return (Refuse); } } #endif /*XFRNETS*/ dnptrs[0] = NULL; /* don't compress names */ hp->rd = 0; /* recursion not possible */ - syslog(LOG_INFO, "approved AXFR from [%s].%d for \"%s\"", - inet_ntoa(from->sin_addr), - ntohs(from->sin_port), - *dnbuf ? dnbuf : "."); + syslog(LOG_INFO, "approved AXFR from %s for \"%s\"", + sin_ntoa(from), *dnbuf ? dnbuf : "."); } *buflenp -= *msglenp; count = 0; @@ -416,10 +549,10 @@ req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from) #endif /*QRYLOG*/ try_again: - dprintf(1, (ddt, "req: nlookup(%s) id %d type=%d\n", - dname, hp->id, type)); + dprintf(1, (ddt, "req: nlookup(%s) id %d type=%d class=%d\n", + dname, hp->id, type, class)); htp = hashtab; /* lookup relative to root */ - if ((np = nlookup(dname, &htp, &fname, 0)) == NULL) + if ((anp = np = nlookup(dname, &htp, &fname, 0)) == NULL) fname = ""; dprintf(1, (ddt, "req: %s '%s' as '%s' (cname=%d)\n", np == NULL ? "missed" : "found", @@ -438,7 +571,7 @@ try_again: dprintf(1, (ddt,"req: nlookup(%s) type=%d\n", dname, type)); htp = hashtab; np = nlookup(dname, &htp, &fname, 0); - } + } #endif /*LOCALDOM*/ #ifdef YPKLUDGE @@ -470,17 +603,26 @@ try_again: goto fetchns; #ifdef SECURE_ZONES - if (np->n_data) { - struct zoneinfo *zp; - - zp = &zones[np->n_data->d_zone]; + /* (gdmr) Make sure the class is correct. If we have the same name + * with more than one class then we can't refuse a request for one + * class just because another class is blocked. We *really* ought + * to look for the correct type too, but since everything in a + * particular class of zone has the same secure_zone attribute it + * doesn't really matter which type we use! Alternatively, this lot + * could all be moved to after the finddata(), by which time only + * the correct class/type combinations will be left. + */ + dp = np->n_data; + while (dp && (dp->d_class != class)) + dp = dp->d_next; + if (dp) { + zp = &zones[dp->d_zone]; if (zp->secure_nets && !addr_on_netlist(from->sin_addr, zp->secure_nets)) { - dprintf(1, (ddt, - "REFUSED Unauthorized request from %s\n", - inet_ntoa(from->sin_addr))); - syslog(LOG_INFO, "Unauthorized request %s from %s", - dname, inet_ntoa(from->sin_addr)); + syslog(LOG_NOTICE, "Unauthorized request %s from %s", + dname, sin_ntoa(from)); + dprintf(1, (ddt, "req: refuse %s from %s class %d (%d)\n", + dname, sin_ntoa(from), class, zp->z_class)); return (Refuse); } } @@ -490,36 +632,30 @@ try_again: count = *cpp - msg; #ifdef NCACHE - /* if this is a NXDOMAIN, will have only one databuf - * whose d_rcode field will be NXDOMAIN. So we can go home - * right here. -ve $ing: anant@isi.edu + /* Look for NXDOMAIN record with appropriate class + * if found return immediately */ - if (np->n_data != NULL && !stale(np->n_data)) { - if (np->n_data->d_rcode == NXDOMAIN) { + for (dp = np->n_data; dp ; dp = dp->d_next) { + if (!stale(dp) && (dp->d_rcode == NXDOMAIN) && + (dp->d_class == class)) { #ifdef RETURNSOA - n = finddata(np, class, T_SOA, hp, &dname, - buflenp, &count); - if (n != 0 ) { - if (hp->rcode == NOERROR_NODATA) { + n = finddata(np, class, T_SOA, hp, &dname, + buflenp, &count); + if (n != 0 ) { + 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); } - *cpp += n; - *buflenp -= n; - *msglenp += n; - hp->rcode = NXDOMAIN; - hp->nscount = htons((u_int16_t)count); - hp->aa = 1; - return (Finish); - } - else - goto fetchns; -#else +#endif hp->rcode = NXDOMAIN; hp->aa = 1; return (Finish); -#endif } } @@ -569,6 +705,29 @@ try_again: if ((lp = local(from)) != NULL) sort_response(answers, count, lp, *cpp); +#ifdef BIND_NOTIFY + if (type == T_SOA && + from->sin_port == ns_port && + np->n_data) { + int zn = np->n_data->d_zone; + + if (zn != DB_Z_CACHE) { + struct notify *ap; + + /* Old? */ + ap = findNotifyPeer(&zones[zn], from->sin_addr); + /* New? */ + if (!ap && (ap = (struct notify *)malloc(sizeof *ap))) { + ap->addr = from->sin_addr; + ap->next = zones[zn].z_notifylist; + zones[zn].z_notifylist = ap; + } + /* Old or New? */ + if (ap) + ap->last = tt.tv_sec; + } + } +#endif /*BIND_NOTIFY*/ if (type == T_AXFR) { hp->ancount = htons(hp->ancount); startxfr(qsp, np, msg, *cpp - msg, class, dname); @@ -598,6 +757,7 @@ fetchns: count = 0; switch (findns(&np, class, nsp, &count, 0)) { case NXDOMAIN: + /* We are authoritative for this np. */ if (!foundname) { hp->rcode = NXDOMAIN; } @@ -616,7 +776,7 @@ fetchns: #ifdef ADDAUTH } else if (hp->ancount) { /* don't add NS records for NOERROR NODATA - as some severs can get confused */ + as some servers can get confused */ #ifdef DATUMREFCNT free_nsp(nsp); #endif @@ -625,7 +785,9 @@ fetchns: case SERVFAIL: break; default: - if (np) { + if (np && + (type != T_NS || np != anp) + ) { n = add_data(np, nsp, *cpp, *buflenp); if (n < 0) { @@ -648,6 +810,7 @@ fetchns: return (Finish); case SERVFAIL: + /* We're authoritative but the zone isn't loaded. */ if (!founddata && !(forward_only && fwdtab)) { hp->rcode = SERVFAIL; #ifdef DATUMREFCNT @@ -664,17 +827,25 @@ fetchns: * ("authority section") here and we're done. */ if (founddata || (!hp->rd) || NoRecurse) { - n = add_data(np, nsp, *cpp, *buflenp); - if (n < 0) { - hp->tc = 1; - n = (-n); + /* If the qtype was NS, and the np of the authority is + * the same as the np of the data, we don't need to add + * another copy of the answer here in the authority + * section. + */ + if (!founddata || type != T_NS || anp != np) { + n = add_data(np, nsp, *cpp, *buflenp); + if (n < 0) { + hp->tc = 1; + n = (-n); + } + *cpp += n; + *buflenp -= n; + hp->nscount = htons((u_int16_t)count); } - *cpp += n; - *buflenp -= n; - hp->nscount = htons((u_int16_t)count); #ifdef DATUMREFCNT free_nsp(nsp); #endif + /* Our caller will handle the Additional section. */ return (Finish); } @@ -688,8 +859,7 @@ fetchns: if (cname) { omsg = (u_char *)malloc((unsigned) *msglenp); if (omsg == (u_char *)NULL) { - dprintf(1, (ddt, "ns_req: malloc fail\n")); - syslog(LOG_ERR, "ns_req: Out Of Memory"); + syslog(LOG_INFO, "ns_req: Out Of Memory"); hp->rcode = SERVFAIL; #ifdef DATUMREFCNT free_nsp(nsp); @@ -700,9 +870,18 @@ fetchns: hp->ancount = htons(hp->ancount); omsglen = *msglenp; bcopy(msg, omsg, omsglen); - *msglenp = res_mkquery(QUERY, dname, class, type, - NULL, 0, NULL, msg, - *msglenp + *buflenp); + n = res_mkquery(QUERY, dname, class, type, + NULL, 0, NULL, msg, + *msglenp + *buflenp); + 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); if (n != FW_OK && cname) @@ -727,10 +906,7 @@ fetchns: */ if (np) { if (np->n_dname[0] == '\0') { - dprintf(1, (ddt, - "ns_req: no address for root NS\n" - )); - syslog(LOG_ERR, + syslog(LOG_NOTICE, "ns_req: no address for root server"); hp->rcode = SERVFAIL; #ifdef DATUMREFCNT @@ -762,7 +938,6 @@ fetchns: return (Return); } -#ifdef INVQ static enum req_action req_iquery(hp, cpp, eom, buflenp, msg, from) HEADER *hp; @@ -771,12 +946,8 @@ req_iquery(hp, cpp, eom, buflenp, msg, from) u_char *msg; struct sockaddr_in *from; { - register struct invbuf *ip; - int dlen, alen, i, n, type, class, count; + int dlen, alen, n, type, class, count; char dnbuf[MAXDNAME], anbuf[PACKETSZ], *data, *fname; - struct namebuf *np; - struct qinfo *qp; - struct databuf *dp; nameserIncr(from->sin_addr, nssRcvdIQ); @@ -819,8 +990,14 @@ req_iquery(hp, cpp, eom, buflenp, msg, from) */ switch (type) { case T_A: +#ifndef INVQ + if (!fake_iquery) + return (Refuse); +#endif +#ifdef INVQ case T_UID: case T_GID: +#endif break; default: return (Refuse); @@ -833,10 +1010,29 @@ req_iquery(hp, cpp, eom, buflenp, msg, from) *cpp = (u_char *)fname; *buflenp -= HFIXEDSZ; count = 0; + +#ifdef QRYLOG + if (qrylog) { + syslog(LOG_INFO, "XX /%s/%s/-%s", + inet_ntoa(from->sin_addr), + inet_ntoa(data_inaddr((u_char *)data)), + p_type(type)); + } +#endif /*QRYLOG*/ + +#ifdef INVQ + { + register struct invbuf *ip; + for (ip = invtab[dhash((u_char *)data, dlen)]; ip != NULL; ip = ip->i_next) { + int i; + for (i = 0; i < INVBLKSZ; i++) { + struct namebuf *np; + struct databuf *dp; + if ((np = ip->i_dname[i]) == NULL) break; dprintf(5, (ddt, "dname = %d\n", np->n_dname)); @@ -863,6 +1059,30 @@ req_iquery(hp, cpp, eom, buflenp, msg, from) } } } + } +#else /*INVQ*/ + /* + * We can only get here if we are compiled without INVQ (the default) + * and the type is T_A and the option "fake-iquery" is on in the boot + * file. + * + * What we do here is send back a bogus response of "[dottedquad]". + * A better strategy would be to turn this into a PTR query, but that + * would legitimize inverse queries in a way they do not deserve. + */ + sprintf(dnbuf, "[%s]", inet_ntoa(data_inaddr((u_char *)data))); + *buflenp -= QFIXEDSZ; + n = dn_comp(dnbuf, *cpp, *buflenp, NULL, NULL); + if (n < 0) { + hp->tc = 1; + return (Finish); + } + *cpp += n; + PUTSHORT((u_int16_t)type, *cpp); + PUTSHORT((u_int16_t)class, *cpp); + *buflenp -= n; + count++; +#endif /*INVQ*/ dprintf(1, (ddt, "req: IQuery %d records\n", count)); hp->qdcount = htons((u_int16_t)count); if (alen > *buflenp) { @@ -873,7 +1093,6 @@ req_iquery(hp, cpp, eom, buflenp, msg, from) *cpp += alen; return (Finish); } -#endif static void fwritemsg(rfp, msg, msglen) @@ -886,7 +1105,8 @@ fwritemsg(rfp, msg, msglen) __putshort(msglen, len); if (fwrite((char *)len, INT16SZ, 1, rfp) != 1 || fwrite((char *)msg, msglen, 1, rfp) != 1) { - dprintf(1, (ddt, "fwrite failed %d\n", errno)); + syslog(LOG_ERR, "fwritemsg: %m"); + _exit(1); } } @@ -904,10 +1124,14 @@ stale(dp) case Z_PRIMARY: return (0); - case Z_SECONDARY: #ifdef STUBS case Z_STUB: + /* root stub zones have DB_F_HINT set */ + if (dp->d_flags & DB_F_HINT) + return (0); + /* FALLTROUGH */ #endif + case Z_SECONDARY: /* * Check to see whether a secondary zone * has expired; if so clear authority flag @@ -920,27 +1144,37 @@ stale(dp) "stale: secondary zone %s expired\n", zp->z_origin)); if (!haveComplained(zp->z_origin, (char*)stale)) { - syslog(LOG_ERR, + syslog(LOG_NOTICE, "secondary zone \"%s\" expired", zp->z_origin); } zp->z_flags &= ~Z_AUTH; return (1); } + if (zp->z_lastupdate > tt.tv_sec) { + if (!haveComplained(zp->z_origin, (char*)stale)) { + syslog(LOG_NOTICE, + "secondary zone \"%s\" time warp", + zp->z_origin); + } + zp->z_flags &= ~Z_AUTH; + return (1); + } return (0); case Z_CACHE: if (dp->d_flags & DB_F_HINT || dp->d_ttl >= tt.tv_sec) return (0); - dprintf(3, (ddt, "stale: ttl %d %d (x%x)\n", - dp->d_ttl, dp->d_ttl - tt.tv_sec, dp->d_flags)); + dprintf(3, (ddt, "stale: ttl %d %d (x%lx)\n", + dp->d_ttl, dp->d_ttl - tt.tv_sec, + (u_long)dp->d_flags)); return (1); default: /* FALLTHROUGH */ ; } - abort(); + panic(-1, "stale: impossible condition"); /* NOTREACHED */ } @@ -950,7 +1184,7 @@ stale(dp) */ int make_rr(name, dp, buf, buflen, doadd) - char *name; + const char *name; register struct databuf *dp; u_char *buf; int buflen, doadd; @@ -962,31 +1196,27 @@ make_rr(name, dp, buf, buflen, doadd) register int32_t ttl; u_char **edp = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; - dprintf(5, (ddt, "make_rr(%s, %x, %x, %d, %d) %d zone %d ttl %d\n", - name, dp, buf, + dprintf(5, (ddt, "make_rr(%s, %lx, %lx, %d, %d) %d zone %d ttl %d\n", + name, (u_long)dp, (u_long)buf, buflen, doadd, dp->d_size, dp->d_zone, dp->d_ttl)); #ifdef NCACHE if (dp->d_rcode #ifdef RETURNSOA - && dp->d_rcode != NXDOMAIN + && dp->d_rcode != NXDOMAIN #endif ) { - syslog(LOG_CRIT, "make_rr d_rcode %d", dp->d_rcode); -#ifdef DEBUG - if (debug) abort(); -#endif - return (-1); /* XXX We should exit here */ + panic(-1, "make_rr: impossible d_rcode value"); } #endif zp = &zones[dp->d_zone]; - /* check for outdated RR before updating dnptrs by dn_comp() (???) */ + /* check for outdated RR before updating dnptrs by dn_comp() (?) */ if (zp->z_type == Z_CACHE) { ttl = dp->d_ttl - (u_int32_t) tt.tv_sec; if ((dp->d_flags & DB_F_HINT) || (ttl < 0)) { dprintf(3, (ddt, - "make_rr: %d=>0, x%x\n", - ttl, dp->d_flags)); /* XXX */ + "make_rr: %d=>0, %#lx\n", + ttl, (u_long)dp->d_flags)); ttl = 0; } } else { @@ -1047,7 +1277,8 @@ make_rr(name, dp, buf, buflen, doadd) PUTSHORT((u_int16_t)n, sp); cp += n; if (doadd) - addname((char*)dp->d_data, dp->d_class); + addname((char*)dp->d_data, name, + dp->d_type, dp->d_class); break; case T_SOA: @@ -1079,22 +1310,51 @@ make_rr(name, dp, buf, buflen, doadd) /* cp1 == our data/ cp == data of RR */ cp1 = dp->d_data; + if ((buflen -= INT16SZ) < 0) + return (-1); + /* copy preference */ bcopy(cp1, cp, INT16SZ); cp += INT16SZ; cp1 += INT16SZ; - buflen -= INT16SZ; n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp); - if (n < 0) - return (-1); - cp += n; + if (n < 0) + return (-1); + cp += n; - /* save data length */ + /* save data length */ n = (u_int16_t)((cp - sp) - INT16SZ); - PUTSHORT((u_int16_t)n, sp); + PUTSHORT((u_int16_t)n, sp); if (doadd) - addname((char*)cp1, dp->d_class); + addname((char*)cp1, name, dp->d_type, dp->d_class); + break; + + case T_PX: + cp1 = dp->d_data; + + if ((buflen -= INT16SZ) < 0) + return (-1); + + /* copy preference */ + bcopy(cp1, cp, INT16SZ); + cp += INT16SZ; + cp1 += INT16SZ; + + n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp); + if (n < 0) + return (-1); + cp += n; + buflen -= n; + cp1 += strlen((char *)cp1) + 1; + n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp); + if (n < 0) + return (-1); + cp += n; + + /* save data length */ + n = (u_int16_t)((cp - sp) - INT16SZ); + PUTSHORT((u_int16_t)n, sp); break; default: @@ -1109,28 +1369,32 @@ make_rr(name, dp, buf, buflen, doadd) #if defined(__STDC__) || defined(__GNUC__) static void -addname(register char *name, +addname(register const char *dname, + register const char *rname, + u_int16_t rtype, u_int16_t class) #else static void -addname(name, class) - register char *name; - u_int16_t class; +addname(dname, rname, rtype, class) + register const char *dname; + register const char *rname; + u_int16_t rtype; + u_int16_t class; #endif { register struct addinfo *ap; register int n; for (ap = addinfo, n = addcount; --n >= 0; ap++) - if (strcasecmp(ap->a_dname, name) == 0) + if (strcasecmp(ap->a_dname, dname) == 0) return; - /* add domain name to additional section */ if (addcount < NADDRECS) { addcount++; - ap->a_dname = (char *)malloc(strlen(name)+1); - strcpy(ap->a_dname,name); + ap->a_dname = savestr(dname); + ap->a_rname = savestr(rname); + ap->a_rtype = rtype; ap->a_class = class; } } @@ -1150,9 +1414,12 @@ doaddinfo(hp, msg, msglen) register struct addinfo *ap; register u_char *cp; struct hashbuf *htp; - char *fname; + const char *fname; int n, count; + if (!addcount) + return (0); + dprintf(3, (ddt, "doaddinfo() addcount = %d\n", addcount)); if (hp->tc) { @@ -1165,11 +1432,13 @@ doaddinfo(hp, msg, msglen) for (ap = addinfo; --addcount >= 0; ap++) { int foundstale = 0, foundany = 0, + foundcname = 0, save_count = count, save_msglen = msglen; u_char *save_cp = cp; - dprintf(3, (ddt, "do additional '%s'\n", ap->a_dname)); + dprintf(3, (ddt, "do additional \"%s\" (from \"%s\")\n", + ap->a_dname, ap->a_rname)); htp = hashtab; /* because "nlookup" stomps on arg. */ np = nlookup(ap->a_dname, &htp, &fname, 0); if (np == NULL || fname != ap->a_dname) @@ -1177,9 +1446,17 @@ doaddinfo(hp, msg, msglen) dprintf(3, (ddt, "found it\n")); /* look for the data */ for (dp = np->n_data; dp != NULL; dp = dp->d_next) { - if ( (!match(dp, (int)ap->a_class, T_A)) - && (!match(dp, C_IN, T_A)) - ) { +#ifdef NCACHE + if (dp->d_rcode) + continue; +#endif + if (match(dp, (int)ap->a_class, T_CNAME) || + match(dp, C_IN, T_CNAME)) { + foundcname++; + break; + } + if (!match(dp, (int)ap->a_class, T_A) && + !match(dp, C_IN, T_A)) { continue; } foundany++; @@ -1194,10 +1471,6 @@ doaddinfo(hp, msg, msglen) )); continue; } -#ifdef NCACHE - if (dp->d_rcode) - continue; -#endif /* * Should be smart and eliminate duplicate * data here. XXX @@ -1213,6 +1486,9 @@ doaddinfo(hp, msg, msglen) * since we only do A RR's here, the name is * the key). vixie, 23apr93 */ + dprintf(5, (ddt, + "addinfo: not enough room, remaining msglen = %d\n", + save_msglen)); cp = save_cp; msglen = save_msglen; count = save_count; @@ -1225,16 +1501,31 @@ doaddinfo(hp, msg, msglen) msglen -= n; count++; } -next_rr: if (foundstale) { + next_rr: + if (foundstale) { /* Cache invalidate the address RR's */ delete_all(np, (int)ap->a_class, T_A); } - if (foundstale || !foundany) { + if ( +#if 0 /*XXX*/ + !NoRecurse && +#endif + !foundcname && (foundstale || !foundany)) { /* ask a real server for this info */ (void) sysquery(ap->a_dname, (int)ap->a_class, T_A, - NULL, 0); + NULL, 0, QUERY); + } + if (foundcname) { + if (!haveComplained((char*)nhash(ap->a_dname), + (char*)nhash(ap->a_rname))) { + syslog(LOG_INFO, + "\"%s %s %s\" points to a CNAME (%s)", + ap->a_rname, p_class(ap->a_class), + p_type(ap->a_rtype), ap->a_dname); + } } free(ap->a_dname); + free(ap->a_rname); } hp->arcount = htons((u_int16_t)count); return (cp - msg); @@ -1299,25 +1590,22 @@ doaxfr(np, rfp, top, class) struct namebuf **npp, **nppend; u_char msg[PACKETSZ]; u_char *cp; - char *fname; + const char *fname; char dname[MAXDNAME]; - HEADER *hp = (HEADER *) msg; + HEADER *hp; int fndns; if (np == top) dprintf(1, (ddt, "doaxfr()\n")); fndns = 0; - hp->id = 0; + bzero((char*)msg, sizeof msg); + hp = (HEADER *) msg; hp->opcode = QUERY; - hp->aa = hp->tc = hp->ra = hp->pr = hp->rd = 0; hp->qr = 1; hp->rcode = NOERROR; - hp->qdcount = 0; hp->ancount = htons(1); - hp->nscount = 0; - hp->arcount = 0; - cp = (u_char *) (msg + HFIXEDSZ); - getname(np, dname, sizeof(dname)); + cp = msg + HFIXEDSZ; + getname(np, dname, sizeof dname); /* first do the NS records (del@harris) */ for (dp = np->n_data; dp != NULL; dp = dp->d_next) { @@ -1357,7 +1645,9 @@ doaxfr(np, rfp, top, class) break; if ( (tnp == NULL) && (top->n_dname[0] != '\0') ) continue; /* name server is not below top domain */ - for (tnp = gnp; tnp != top; tnp = tnp->n_parent) { + for (tnp = gnp; + tnp != NULL && tnp != top; + tnp = tnp->n_parent) { for (tdp = tnp->n_data; tdp != NULL; tdp = tdp->d_next) { @@ -1371,7 +1661,8 @@ doaxfr(np, rfp, top, class) if (tdp != NULL) break; /* found a zone cut */ } - if (tnp == top) + if ((tnp == top) || + ((tnp == NULL) && (top->n_dname[0] == '\0'))) continue; /* name server is not in a delegated zone */ /* now we know glue records are needed. send them. */ #endif /*NO_GLUE*/ @@ -1562,8 +1853,6 @@ InitDynUpdate(hp, msg, msglen, startcp, from, qsp, dfd) *znp = NULL; np = nlookup(ZoneName, &htp, &fname, 0); if ((np == NULL) || (fname != ZoneName)) { - dprintf(1, (ddt, "InitDynUpdate: lookup failed on zone (%s)\n", - ZoneName)); syslog(LOG_ERR, "InitDynUpdate: lookup failed on zone (%s)\n", ZoneName); hp->rcode = NXDOMAIN; @@ -1618,13 +1907,9 @@ InitDynUpdate(hp, msg, msglen, startcp, from, qsp, dfd) if (match(olddp, class, T_SOA)) break; if (olddp == NULL) { - dprintf(1, (ddt, - "InitDynUpdate: Couldn't find SOA record for '%s'\n", - ZoneName)); - syslog(LOG_ERR, - "InitDynUpdate: Couldn't find SOA record for '%s'\n" -, - ZoneName); + syslog(LOG_NOTICE, + "InitDynUpdate: Couldn't find SOA RR for '%s'\n", + ZoneName); hp->rcode = NXDOMAIN; #ifdef DATUMREFCNT free_nsp(nsp); @@ -1690,11 +1975,14 @@ printSOAdata(dp) if (!debug) return; /* Otherwise fprintf to ddt will bomb */ cp = (u_char *)dp->d_data; - fprintf(ddt, "printSOAdata(%x): origin(%x)='%s'\n", dp, cp, cp); + 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(%x)='%s'\n", cp, cp); + fprintf(ddt, "printSOAdata: in-charge(%#lx)='%s'\n", + (u_long)cp, cp); cp += strlen(cp) + 1; /* skip in-charge string */ - fprintf(ddt, "printSOAdata: serial(%x)=%d\n", cp, _getlong(cp)); + fprintf(ddt, "printSOAdata: serial(%lx)=%d\n", + cp, (u_long)_getlong(cp)); } #endif #endif @@ -1711,6 +1999,15 @@ startxfr(qsp, np, soa, soalen, class, dname) FILE *rfp; int fdstat; pid_t pid; +#ifdef HAVE_SETVBUF + char *buf; +#endif +#ifdef SO_SNDBUF + static const int sndbuf = XFER_BUFSIZE * 2; +#endif +#ifdef SO_LINGER + static const struct linger ll = { 1, 120 }; +#endif dprintf(5, (ddt, "startxfr()\n")); @@ -1720,16 +2017,16 @@ startxfr(qsp, np, soa, soalen, class, dname) */ switch (pid = fork()) { case -1: - syslog(LOG_ERR, "startxfr(%s -> [%s]) failing; fork: %m", - dname, inet_ntoa(qsp->s_from.sin_addr)); + syslog(LOG_NOTICE, "startxfr(%s -> %s) failing; fork: %m", + dname, sin_ntoa(&qsp->s_from)); return; case 0: /* child */ break; default: /* parent */ - syslog(LOG_DEBUG, "zone transfer of \"%s\" to [%s] (pid %lu)", - dname, inet_ntoa(qsp->s_from.sin_addr), pid); + syslog(LOG_DEBUG, "zone transfer of \"%s\" to %s (pid %lu)", + dname, sin_ntoa(&qsp->s_from), pid); return; } @@ -1758,25 +2055,58 @@ startxfr(qsp, np, soa, soalen, class, dname) _exit(1); } (void) fcntl(qsp->s_rfd, F_SETFL, fdstat & ~PORT_NONBLOCK); +#ifdef HAVE_SETVBUF + /* some systems (DEC OSF/1, SunOS) don't initialize the stdio buffer + * if all you do between fdopen() and fclose() are fwrite()'s. even + * on systems where the buffer is correctly set, it is too small. + */ + if ((buf = malloc(XFER_BUFSIZE)) != NULL) + (void) setvbuf(rfp, buf, _IOFBF, XFER_BUFSIZE); +#endif +#ifdef SO_SNDBUF + /* the default seems to be 4K, and we'd like it to have enough room + * to parallelize sending the pushed data with accumulating more + * write() data from us. + */ + (void) setsockopt(qsp->s_rfd, SOL_SOCKET, SO_SNDBUF, + (char *)&sndbuf, sizeof sndbuf); +#endif + /* XXX: some day we would like to only send the size and header out + * when we fill a 64K DNS/AXFR "message" rather than on each RR. + * (PVM@ISI gets credit for this idea.) + */ fwritemsg(rfp, soa, soalen); doaxfr(np, rfp, np, class); fwritemsg(rfp, soa, soalen); (void) fflush(rfp); +#ifdef SO_LINGER + /* kernels that map pages for IO end up failing if the pipe is full + * at exit and we take away the final buffer. this is really a kernel + * bug but it's harmless on systems that are not broken, so... + */ + setsockopt(qsp->s_rfd, SOL_SOCKET, SO_LINGER, + (char *)&ll, sizeof ll); + close(qsp->s_rfd); +#endif _exit(0); + /* NOTREACHED */ } +void free_addinfo() { struct addinfo *ap; for (ap = addinfo; --addcount >= 0; ap++) { free(ap->a_dname); + free(ap->a_rname); } addcount = 0; } #ifdef DATUMREFCNT +void free_nsp(nsp) -struct databuf **nsp; + struct databuf **nsp; { while (*nsp) { if (--((*nsp)->d_rcnt)) { diff --git a/usr.sbin/named/ns_resp.c b/usr.sbin/named/ns_resp.c index f8086e316dbb..012b699feb34 100644 --- a/usr.sbin/named/ns_resp.c +++ b/usr.sbin/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 4.9.1.24 1994/07/23 23:23:56 vixie Exp $"; +static char rcsid[] = "$Id: ns_resp.c,v 8.8 1995/07/07 07:33:52 vixie Exp $"; #endif /* not lint */ /* @@ -76,19 +76,94 @@ static void check_root __P((void)), static u_int8_t norootlogged[MAXCLASS]; /* XXX- should be a bitmap */ -static char skipnameFailedAnswer[] = "skipname failed in answer", +static const char skipnameFailedAnswer[] = "skipname failed in answer", skipnameFailedQuery[] = "skipname failed in query", outofDataQuery[] = "ran out of data in query", outofDataAnswer[] = "ran out of data in answer", -#ifdef LAME_DELEGATION + notSingleQuery[] = "not exactly one query", expandFailedQuery[] = "dn_expand failed in query", + expandFailedAnswer[] = "dn_expand failed in answer", expandFailedAuth[] = "dn_expand failed in authority", outofDataAuth[] = "ran out of data in authority", -#endif /* LAME_DELEGATION */ dlenOverrunAnswer[] = "dlen overrun in answer", dlenUnderrunAnswer[] = "dlen underrun in answer", outofDataFinal[] = "out of data in final pass", - outofDataAFinal[] = "out of data after final pass"; + outofDataAFinal[] = "out of data after final pass", + editFailed[] = "edit of response failed"; + +static char * +learntFrom(qp, server) + struct qinfo *qp; + struct sockaddr_in *server; +{ + static char *buf = NULL; + char *a, *ns, *na; + struct databuf *db; + char nsbuf[20]; + char abuf[20]; + int i; + + if (buf) { + free(buf); + buf = NULL; + } + + a = ns = na = "<Not Available>"; + + for (i = 0; i < (int)qp->q_naddr; i++) { + if (qp->q_addr[i].ns_addr.sin_addr.s_addr == + server->sin_addr.s_addr) { + db = qp->q_addr[i].ns; + if (db) { +#ifdef STATS + if (db->d_ns) { + strcpy(nsbuf, + inet_ntoa(db->d_ns->addr)); + ns = nsbuf; + } else { + ns = zones[db->d_zone].z_origin; + } +#endif + +#ifdef NCACHE + if (!db->d_rcode) +#endif + na = (char*)qp->q_addr[i].ns->d_data; + } + +#ifdef STATS + db = qp->q_addr[i].nsdata; + if (db) { + if (db->d_ns) { + strcpy(abuf, + inet_ntoa(db->d_ns->addr)); + a = abuf; + } else { + a = zones[db->d_zone].z_origin; + } + } +#endif + break; + } + } + + if ((a == ns) && (ns == na)) /* all "UNKNOWN" */ + return (""); + +#ifdef STATS +# define LEARNTFROM " '%s': learnt (A=%s,NS=%s)" +#else +# define LEARNTFROM " '%s'" +#endif + if (buf = malloc(strlen(a = (*a ? a : "\".\"")) + + strlen(ns = (*ns ? ns : "\".\"")) + + strlen(na = (*na ? na : "\".\"")) + + sizeof(LEARNTFROM))) { + sprintf(buf, LEARNTFROM, na, a, ns); + return (buf); + } + return(""); +} void ns_resp(msg, msglen) @@ -100,24 +175,25 @@ ns_resp(msg, msglen) register struct qserv *qs; register struct databuf *ns, *ns2; register u_char *cp; + u_char *eom = msg + msglen; #ifdef VALIDATE register u_char *tempcp; struct sockaddr_in *server = &from_addr; int *validatelist; - int lesscount; + int lesscount, old_ancount; #endif struct sockaddr_in *nsa; struct databuf *nsp[NSMAX], **nspp; - int i, c, n, ancount, aucount, nscount, arcount; - int old_ancount; - int type, class, dbflags; + int i, c, n, qdcount, ancount, aucount, nscount, arcount; + int qtype, qclass, dbflags; int cname = 0; /* flag for processing cname response */ int count, founddata, foundname; int buflen; int newmsglen; - char name[MAXDNAME], *dname; - char *fname; - char *formerrmsg = "brain damage"; + char name[MAXDNAME], qname[MAXDNAME]; + char *dname; + const char *fname; + const char *formerrmsg = "brain damage"; u_char newmsg[BUFSIZ]; u_char **dpp, *tp; time_t rtrip; @@ -144,6 +220,53 @@ ns_resp(msg, msglen) ntohs(qp->q_nsid), ntohs(qp->q_id))); /* + * Here we handle high level formatting problems by parsing the header. + */ + qdcount = ntohs(hp->qdcount); + ancount = ntohs(hp->ancount); + aucount = ntohs(hp->nscount); /* !!! */ + arcount = ntohs(hp->arcount); + free_addinfo(); /* sets addcount to zero */ + cp = msg + HFIXEDSZ; + dpp = dnptrs; + *dpp++ = msg; + if ((*cp & INDIR_MASK) == 0) + *dpp++ = cp; + *dpp = NULL; + if (qdcount == 1) { + n = dn_expand(msg, eom, cp, qname, sizeof(qname)); + if (n <= 0) { + formerrmsg = expandFailedQuery; + goto formerr; + } + cp += n; + GETSHORT(qtype, cp); + GETSHORT(qclass, cp); + if (cp > eom) { + formerrmsg = outofDataQuery; + goto formerr; + } + if (qp->q_msg && qp->q_msglen && + !res_nameinquery(qname, qtype, qclass, + qp->q_msg, qp->q_msg + qp->q_msglen)) { + char msgbuf[MAXDNAME*2]; + + sprintf(msgbuf, + "query section mismatch (%s %s %s)", + qname, p_class(qclass), p_type(qtype)); + formerrmsg = msgbuf; + goto formerr; + } + } else { + /* Pedantic. */ + qname[0] = '\0'; + qtype = 0; + qclass = 0; + } + + /* cp now points after the query section (if there was one). */ + + /* * Here we handle bad responses from servers. * Several possibilities come to mind: * The server is sick and returns SERVFAIL @@ -157,8 +280,12 @@ ns_resp(msg, msglen) || (hp->rcode == NXDOMAIN && !hp->aa) /* must accept this one if * we allow negative caching */ -#endif /*NCACHE*/ - || hp->opcode != QUERY) { +#endif + || (hp->opcode != QUERY +#ifdef BIND_NOTIFY + && hp->opcode != NS_NOTIFY_OP +#endif + )) { dprintf(2, (ddt, "resp: error (ret %d, op %d), dropped\n", hp->rcode, hp->opcode)); switch (hp->rcode) { @@ -174,63 +301,47 @@ ns_resp(msg, msglen) } return; } + + if (qdcount != 1) { + /* We don't generate or forward these (yet). */ + formerrmsg = notSingleQuery; + goto formerr; + } + #ifdef LAME_DELEGATION /* * Non-authoritative, no answer, no error */ - if (hp->rcode == NOERROR && !hp->aa && ntohs(hp->ancount) == 0 && - ntohs(hp->nscount) > 0) { - -#ifdef LAME_LOGGING - char qname[MAXDNAME]; -#endif /* LAME_LOGGING */ - + if (qdcount == 1 && hp->rcode == NOERROR && !hp->aa && ancount == 0 + && aucount > 0 +#ifdef BIND_NOTIFY + && hp->opcode != NS_NOTIFY_OP +#endif + ) { + u_char *tp; + int type, class; #ifdef DEBUG if (debug > 0) - fp_query(msg, ddt); + fp_nquery(msg, msglen, ddt); #endif - - cp = msg + HFIXEDSZ; - dpp = dnptrs; - *dpp++ = msg; - if ((*cp & INDIR_MASK) == 0) - *dpp++ = cp; - *dpp = NULL; - if (hp->qdcount) { -#ifdef LAME_LOGGING - n = dn_expand(msg, msg + msglen, cp, qname, - sizeof(qname)); - if (n <= 0) { - formerrmsg = expandFailedQuery; - goto formerr; - } -#else /* LAME_LOGGING */ - n = dn_skipname(cp, msg + msglen); - if (n <= 0) { - formerrmsg = skipnameFailedQuery; - goto formerr; - } -#endif /* LAME_LOGGING */ - cp += n; - GETSHORT(type, cp); - GETSHORT(class, cp); - if (cp - msg > msglen) { - formerrmsg = outofDataQuery; - goto formerr; - } -#ifdef LAME_LOGGING - } else { - strcpy(qname, "[No query name!]"); -#endif /* LAME_LOGGING */ - } - n = dn_expand(msg, msg + msglen, cp, name, sizeof name); + /* + * Since there is no answer section (ancount == 0), + * we must be pointing at the authority section (aucount > 0). + */ + tp = cp; + n = dn_expand(msg, eom, tp, name, sizeof name); if (n < 0) { formerrmsg = expandFailedAuth; goto formerr; } - cp += n; - GETSHORT(type, cp); - if (cp - msg > msglen) { + tp += n; + GETSHORT(type, tp); + if (tp >= eom) { + formerrmsg = outofDataAuth; + goto formerr; + } + GETSHORT(class, tp); + if (tp >= eom) { formerrmsg = outofDataAuth; goto formerr; } @@ -238,31 +349,31 @@ ns_resp(msg, msglen) /* * If the answer delegates us either to the same level in * the hierarchy or closer to the root, we consider this - * server lame. + * server lame. Note that for now we only log the message + * if the T_NS was C_IN, which is technically wrong (NS is + * visible in all classes) but necessary anyway (non-IN + * classes tend to not have good strong delegation graphs). */ if (type == T_NS && samedomain(qp->q_domain, name)) { nameserIncr(from_addr.sin_addr, nssRcvdLDel); #ifdef LAME_LOGGING - if (!haveComplained((char*)dhash((u_char*)name, - strlen(name)), - (char*)dhash((u_char*)qp->q_domain, - strlen(qp->q_domain) - ) - ) - ) { + if (class == C_IN && + !haveComplained((char*)nhash(name), + (char*)nhash(qp->q_domain))) syslog(LAME_LOGGING, -"Lame delegation to '%s' from [%s] (server for '%s'?) on query on name '%s'\n", - name, inet_ntoa(from_addr.sin_addr), - qp->q_domain, qname); - } + "Lame server on '%s' (in '%s'?): %s%s\n", + qname, qp->q_domain, + inet_etoa(&from_addr), + learntFrom(qp, &from_addr) + ); + #endif /* LAME_LOGGING */ return; } } #endif /* LAME_DELEGATION */ - #ifdef ALLOW_UPDATES if ( (hp->rcode == NOERROR) && (hp->opcode == UPDATEA || hp->opcode == UPDATED || @@ -297,25 +408,26 @@ ns_resp(msg, msglen) /* XXX: note bad ambiguity here. if one of our forwarders is also * a delegated server for some domain, then we will not update * the RTT information on any replies we get from those servers. + * Workaround: disable recursion on authoritative servers so that + * the ambiguity does not arise. */ /* - * If we were using nameservers, find the qinfo pointer and update + * If we weren't using a forwarder, find the qinfo pointer and update * the rtt and fact that we have called on this server before. */ if (fwd == (struct fwdinfo *)NULL) { struct timeval *stp; - for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++) + for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; n++, qs++) if (qs->ns_addr.sin_addr.s_addr == from_addr.sin_addr.s_addr) break; - if (n >= qp->q_naddr) { + if ((u_int)n >= qp->q_naddr) { if (!haveComplained((char*)from_addr.sin_addr.s_addr, "unexpected source")) { - syslog(LOG_NOTICE, - "Response from unexpected source [%s].%d", - inet_ntoa(from_addr.sin_addr), - ntohs(from_addr.sin_port)); + syslog(LOG_INFO, + "Response from unexpected source (%s)", + inet_etoa(&from_addr)); } /* * We don't know who this response came from so it @@ -338,8 +450,8 @@ ns_resp(msg, msglen) */ dprintf(1, (ddt, "Response from unused address %s, assuming %s\n", - inet_ntoa(from_addr.sin_addr), - inet_ntoa(qs->ns_addr.sin_addr))); + inet_etoa(&from_addr), + inet_etoa(&qs->ns_addr))); /* XXX - catch aliases here */ } @@ -356,9 +468,10 @@ ns_resp(msg, msglen) (tt.tv_usec - stp->tv_usec) / 1000); } - dprintf(3, (ddt, "stime %d/%d now %d/%d rtt %d\n", - stp->tv_sec, stp->tv_usec, - tt.tv_sec, tt.tv_usec, rtrip)); + dprintf(3, (ddt, "stime %lu/%lu now %lu/%lu rtt %ld\n", + (u_long)stp->tv_sec, (u_long)stp->tv_usec, + (u_long)tt.tv_sec, (u_long)tt.tv_usec, + (long)rtrip)); /* prevent floating point overflow, limit to 1000 sec */ if (rtrip > 1000000) { @@ -389,8 +502,8 @@ ns_resp(msg, msglen) */ if (ns && qs->ns && (qp->q_nusedns < NSMAX)) { qp->q_usedns[qp->q_nusedns++] = qs->ns; - dprintf(2, (ddt, "NS #%d addr [%s] used, rtt %d\n", - n, inet_ntoa(qs->ns_addr.sin_addr), + dprintf(2, (ddt, "NS #%d addr %s used, rtt %d\n", + n, inet_etoa(&qs->ns_addr), ns->d_nstime)); } @@ -405,7 +518,7 @@ ns_resp(msg, msglen) * and are no longer the correct type. XXX */ - for (n = 0, qs = qp->q_addr; n < qp->q_naddr; n++, qs++) { + for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; n++, qs++) { ns2 = qs->nsdata; if ((!ns2) || (ns2 == ns)) continue; @@ -423,46 +536,28 @@ ns_resp(msg, msglen) ns2->d_nstime = 1000000; } else ns2->d_nstime = (u_int32_t)(ns2->d_nstime * GAMMA); - dprintf(2, (ddt, "NS #%d [%s] rtt now %d\n", n, - inet_ntoa(qs->ns_addr.sin_addr), + dprintf(2, (ddt, "NS #%d %s rtt now %d\n", n, + inet_etoa(&qs->ns_addr), ns2->d_nstime)); } } - /*************************************************************/ - - /* - * Skip query section +#ifdef BIND_NOTIFY + /* for now, NOTIFY isn't defined for ANCOUNT!=0, AUCOUNT!=0, + * or ADCOUNT!=0. therefore the only real work to be done for + * a NOTIFY-QR is to remove it from the query queue. */ - free_addinfo(); /* sets addcount to zero */ - cp = msg + HFIXEDSZ; - dpp = dnptrs; - *dpp++ = msg; - if ((*cp & INDIR_MASK) == 0) - *dpp++ = cp; - *dpp = NULL; - type = class = 0; - if (hp->qdcount) { - n = dn_skipname(cp, msg + msglen); - if (n <= 0) { - formerrmsg = skipnameFailedQuery; - goto formerr; - } - cp += n; - GETSHORT(type, cp); - GETSHORT(class, cp); - if (cp - msg > msglen) { - formerrmsg = outofDataQuery; - goto formerr; - } + if (hp->opcode == NS_NOTIFY_OP) { + qremove(qp); + return; } +#endif + + /*************************************************************/ /* * Save answers, authority, and additional records for future use. */ - ancount = ntohs(hp->ancount); - aucount = ntohs(hp->nscount); - arcount = ntohs(hp->arcount); nscount = 0; tp = cp; dprintf(3, (ddt, "resp: ancount %d, aucount %d, arcount %d\n", @@ -479,21 +574,21 @@ ns_resp(msg, msglen) if (ancount == 1 || (ancount == 0 && aucount > 0)) { c = aucount; do { - if (tp - msg >= msglen) { + if (tp >= eom) { formerrmsg = outofDataAnswer; goto formerr; } - n = dn_skipname(tp, msg + msglen); + n = dn_skipname(tp, eom); if (n <= 0) { formerrmsg = skipnameFailedAnswer; goto formerr; } tp += n; /* name */ GETSHORT(i, tp); /* type */ - tp += INT16SZ; /* class */ - tp += INT32SZ; /* ttl */ + tp += INT16SZ; /* class */ + tp += INT32SZ; /* ttl */ GETSHORT(count, tp); /* dlen */ - if (tp - msg > msglen - count) { + if (tp + count > eom) { formerrmsg = dlenOverrunAnswer; goto formerr; } @@ -522,38 +617,49 @@ ns_resp(msg, msglen) } if (qp->q_flags & Q_ZSERIAL) { - if ((hp->aa) - && (ancount != 0) - && (hp->rcode == NOERROR) - && (type == T_SOA) - && ((class == C_IN) || (class == C_HS)) - ) { /* XXX - should check name, too */ + if (hp->aa && ancount > 0 && hp->rcode == NOERROR && + qtype == T_SOA && ((qclass == C_IN) || (qclass == C_HS))) { int n; - u_int16_t dlen; + u_int16_t type, class, dlen; u_int32_t serial; u_char *tp = cp; - if (0 >= (n = dn_skipname(tp, msg + msglen))) { - formerrmsg = skipnameFailedAnswer; + n = dn_expand(msg, eom, tp, name, sizeof name); + if (n < 0) { + formerrmsg = expandFailedAnswer; goto formerr; } - tp += n /* name */ - + INT16SZ /* type */ - + INT16SZ /* class */ - + INT32SZ; /* ttl */ + tp += n; /* name */ + GETSHORT(type, tp); /* type */ + GETSHORT(class, tp); /* class */ + tp += INT32SZ; /* ttl */ GETSHORT(dlen, tp); /* dlen */ - - if (dlen < (5 * INT32SZ)) { + if (tp >= eom) { + formerrmsg = outofDataAnswer; + goto formerr; + } + if (strcasecmp(qname, name) || + qtype != type || + qclass != class) { + char msgbuf[MAXDNAME*2]; + + sprintf(msgbuf, + "qserial answer mismatch (%s %s %s)", + name, p_class(class), p_type(type)); + formerrmsg = msgbuf; + goto formerr; + } + if ((u_int)dlen < (5 * INT32SZ)) { formerrmsg = dlenUnderrunAnswer; goto formerr; } - if (0 >= (n = dn_skipname(tp, msg + msglen))) { + if (0 >= (n = dn_skipname(tp, eom))) { formerrmsg = skipnameFailedAnswer; goto formerr; } tp += n; /* mname */ - if (0 >= (n = dn_skipname(tp, msg + msglen))) { + if (0 >= (n = dn_skipname(tp, eom))) { formerrmsg = skipnameFailedAnswer; goto formerr; } @@ -585,7 +691,7 @@ ns_resp(msg, msglen) * DON'T do this now, as it will requery if data are already * in the cache (maybe later with negative caching). */ - if (hp->qdcount && type == T_CNAME && c == 0 && hp->rcode == NOERROR + if (type == T_CNAME && c == 0 && hp->rcode == NOERROR && !(qp->q_flags & Q_SYSTEM)) { dprintf(4, (ddt, "resp: leaving, no CNAME\n")); @@ -603,6 +709,8 @@ ns_resp(msg, msglen) else dbflags = DB_NOTAUTH | DB_NODATA | DB_NOHINTS; count = c; + if (qp->q_flags & Q_PRIMING) + dbflags |= DB_PRIMING; if (hp->tc) { count -= arcount; /* truncation had to affect this */ if (!arcount) { @@ -620,7 +728,7 @@ ns_resp(msg, msglen) old_ancount = ancount; for (i = 0; i < count; i++) { int VCode; - if (tempcp >= msg + msglen) { + if (tempcp >= eom) { free((char *)validatelist); formerrmsg = outofDataFinal; goto formerr; @@ -644,31 +752,34 @@ ns_resp(msg, msglen) */ n = update_msg(msg, &msglen, validatelist, count); free((char *)validatelist); - if (n < 0) + if (n < 0) { + formerrmsg = editFailed; goto formerr; + } count -= lesscount; - if (old_ancount && !hp->ancount) { + ancount = ntohs(hp->ancount); + if (old_ancount && !ancount) { /* We lost all the answers */ dprintf(1, (ddt, "validate count -> 0")); return; } - ancount = ntohs(hp->ancount); #endif for (i = 0; i < count; i++) { struct databuf *ns3; u_char cred; - if (cp >= msg + msglen) { + if (cp >= eom) { formerrmsg = outofDataFinal; goto formerr; } - if (i < ancount) { + if (i < ancount) cred = hp->aa ? DB_C_AUTH : DB_C_ANSWER; - } else { - cred = DB_C_ADDITIONAL; - } + else + cred = (qp->q_flags & Q_PRIMING) + ? DB_C_ANSWER + : DB_C_ADDITIONAL; ns3 = 0; n = doupdate(msg, msglen, cp, 0, &ns3, dbflags, cred); if (n < 0) { @@ -698,14 +809,25 @@ ns_resp(msg, msglen) check_root(); dprintf(3, (ddt, "resp: leaving, SYSQUERY ancount %d\n", ancount)); +#ifdef BIND_NOTIFY + if (qp->q_notifyzone != DB_Z_CACHE) { + struct zoneinfo *zp = &zones[qp->q_notifyzone]; + + /* + * Clear this first since sysnotify() might set it. + */ + qp->q_notifyzone = DB_Z_CACHE; + sysnotify(zp->z_origin, zp->z_class, T_SOA); + } +#endif qremove(qp); -#ifdef DATUMREFCNT +#ifdef DATUMREFCNT free_nsp(nsp); #endif return; } - if (cp > msg + msglen) { + if (cp > eom) { formerrmsg = outofDataAFinal; goto formerr; } @@ -715,13 +837,13 @@ ns_resp(msg, msglen) * sort them appropriately for the local context. */ if (ancount > 1 && (lp = local(&qp->q_from)) != NULL) - sort_response(tp, ancount, lp, msg + msglen); + sort_response(tp, ancount, lp, eom); /* * An answer to a T_ANY query or a successful answer to a * regular query with no indirection, then just return answer. */ - if ((hp->qdcount && type == T_ANY && ancount) || + if ((qtype == T_ANY && ancount) || (!cname && !qp->q_cmsglen && ancount)) { dprintf(3, (ddt, "resp: got as much answer as there is\n")); goto return_msg; @@ -732,7 +854,7 @@ ns_resp(msg, msglen) */ if (!ancount && (!nscount || hp->rcode == NXDOMAIN) && - (hp->aa || fwd || class == C_ANY)) { + (hp->aa || fwd || qclass == C_ANY)) { /* we have an authoritative NO */ dprintf(3, (ddt, "resp: leaving auth NO\n")); if (qp->q_cmsglen) { @@ -784,8 +906,8 @@ ns_resp(msg, msglen) cp += n + QFIXEDSZ; buflen = sizeof(newmsg) - (cp - newmsg); -try_again: - dprintf(1, (ddt, "resp: nlookup(%s) type=%d\n", dname, type)); + try_again: + dprintf(1, (ddt, "resp: nlookup(%s) qtype=%d\n", dname, qtype)); fname = ""; htp = hashtab; /* lookup relative to root */ np = nlookup(dname, &htp, &fname, 0); @@ -796,13 +918,13 @@ try_again: foundname++; count = cp - newmsg; - n = finddata(np, class, type, hp, &dname, &buflen, &count); + n = finddata(np, qclass, qtype, hp, &dname, &buflen, &count); if (n == 0) goto fetch_ns; /* NO data available */ cp += n; buflen -= n; hp->ancount += count; - if (fname != dname && type != T_CNAME && type != T_ANY) { + if (fname != dname && qtype != T_CNAME && qtype != T_ANY) { cname++; goto try_again; } @@ -812,7 +934,7 @@ try_again: "resp: foundname=%d, count=%d, founddata=%d, cname=%d\n", foundname, count, founddata, cname)); -fetch_ns: + fetch_ns: hp->ancount = htons(hp->ancount); /* * Look for name servers to refer to and fill in the authority @@ -822,13 +944,13 @@ fetch_ns: #ifdef DATUMREFCNT free_nsp(nsp); #endif - switch (findns(&np, class, nsp, &count, 0)) { + switch (findns(&np, qclass, nsp, &count, 0)) { case NXDOMAIN: /* shouldn't happen */ dprintf(3, (ddt, "req: leaving (%s, rcode %d)\n", dname, hp->rcode)); if (!foundname) hp->rcode = NXDOMAIN; - if (class != C_ANY) { + if (qclass != C_ANY) { hp->aa = 1; /* XXX: should return SOA if founddata == 0, * but old named's are confused by an SOA @@ -864,40 +986,45 @@ fetch_ns: * to iterate to try and get it. First, infinite loop avoidance. */ if (qp->q_nqueries++ > MAXQUERIES) { - dprintf(1, - (ddt, - "resp: MAXQUERIES exceeded (%s, class %d, type %d)\n", - dname, class, type - ) - ); - syslog(LOG_NOTICE, - "MAXQUERIES exceeded, possible data loop in resolving (%s)", - dname); + dprintf(1, (ddt, "resp: MAXQUERIES exceeded (%s %s %s)\n", + dname, p_class(qclass), p_type(qtype))); + syslog(LOG_INFO, + "MAXQUERIES exceeded, possible data loop in resolving (%s)", + dname); goto servfail; } /* Reset the query control structure */ #ifdef DATUMREFCNT - for (i = 0 ; i < qp->q_naddr ; i++) { - if ((--(qp->q_addr[i].ns->d_rcnt))) { - dprintf(1 ,(ddt, "ns_resp: ns %s rcnt %d\n", - qp->q_addr[i].ns->d_data, - qp->q_addr[i].ns->d_rcnt)); - } else { - dprintf(1 ,(ddt, "ns_resp: ns %s rcnt %d delayed\n", - qp->q_addr[i].ns->d_data, - qp->q_addr[i].ns->d_rcnt)); - free((char*)qp->q_addr[i].ns); - } - if ((--(qp->q_addr[i].nsdata->d_rcnt))) { - dprintf(1 ,(ddt, "ns_resp: nsdata %08.8X rcnt %d\n", - *(int32_t *)(qp->q_addr[i].nsdata->d_data), - qp->q_addr[i].nsdata->d_rcnt)); - } else { - dprintf(1 ,(ddt, "ns_resp: nsdata %08.8X rcnt %d delayed\n", - *(int32_t *)(qp->q_addr[i].nsdata->d_data), - qp->q_addr[i].nsdata->d_rcnt)); - free((char*)qp->q_addr[i].nsdata); + /* 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 { + free((char*)qp->q_addr[i].ns); + 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 (qp->q_addr[i].nsdata != NULL) { + if ((--(qp->q_addr[i].nsdata->d_rcnt))) + result = busy; + else { + free((char*)qp->q_addr[i].nsdata); + 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)); } } #endif @@ -917,7 +1044,7 @@ fetch_ns: goto return_newmsg; goto servfail; } - for (n = 0; n < qp->q_naddr; n++) + for (n = 0; (u_int)n < qp->q_naddr; n++) qp->q_addr[n].stime.tv_sec = 0; if (!qp->q_fwd) qp->q_addr[0].stime = tt; @@ -933,39 +1060,43 @@ fetch_ns: if (qp->q_msg) (void) free(qp->q_msg); if ((qp->q_msg = (u_char *)malloc(BUFSIZ)) == NULL) { - dprintf(1, (ddt, "resp: malloc error\n")); + syslog(LOG_NOTICE, "resp: malloc error\n"); goto servfail; } - qp->q_msglen = res_mkquery(QUERY, dname, class, - type, NULL, 0, NULL, - qp->q_msg, BUFSIZ); + n = res_mkquery(QUERY, dname, qclass, qtype, + NULL, 0, NULL, qp->q_msg, BUFSIZ); + if (n < 0) { + syslog(LOG_INFO, "resp: res_mkquery(%s) failed", + dname); + goto servfail; + } + qp->q_msglen = n; hp = (HEADER *) qp->q_msg; hp->rd = 0; } else - hp = (HEADER *)qp->q_msg; - hp->id = qp->q_nsid = htons((u_int16_t)++nsid); + hp = (HEADER *) qp->q_msg; + hp->id = qp->q_nsid = htons(nsid_next()); if (qp->q_fwd) hp->rd = 1; unsched(qp); schedretry(qp, retrytime(qp)); nsa = Q_NEXTADDR(qp, 0); - dprintf(1, (ddt, "resp: forw -> [%s].%d ds=%d nsid=%d id=%d %dms\n", - inet_ntoa(nsa->sin_addr), - ntohs(nsa->sin_port), ds, + dprintf(1, (ddt, "resp: forw -> %s ds=%d nsid=%d id=%d %dms\n", + inet_etoa(nsa), ds, ntohs(qp->q_nsid), ntohs(qp->q_id), (qp->q_addr[0].nsdata != NULL) ? qp->q_addr[0].nsdata->d_nstime : (-1))); #ifdef DEBUG if (debug >= 10) - fp_query(msg, ddt); + fp_nquery(qp->q_msg, qp->q_msglen, ddt); #endif - if (sendto(ds, qp->q_msg, qp->q_msglen, 0, + if (sendto(ds, (char*)qp->q_msg, qp->q_msglen, 0, (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr)) - syslog(LOG_NOTICE, "ns_resp: sendto([%s].%d): %m", - inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port)); + syslog(LOG_INFO, "ns_resp: sendto(%s): %m", + inet_etoa(nsa)); nameserIncr(nsa->sin_addr, nssSendtoErr); } hp->rd = 0; /* leave set to 0 for dup detection */ @@ -977,37 +1108,25 @@ fetch_ns: #endif return; -formerr: - dprintf(3, (ddt, - "FORMERR resp() from [%s].%d size err %d, msglen %d\n", - inet_ntoa(from_addr.sin_addr), - ntohs(from_addr.sin_port), - cp - msg, msglen)); + formerr: if (!haveComplained((char*)from_addr.sin_addr.s_addr, - (char*)dhash((u_char *)formerrmsg, - strlen(formerrmsg) - ) - ) - ) { - syslog(LOG_INFO, "Malformed response from [%s].%d (%s)\n", - inet_ntoa(from_addr.sin_addr), - ntohs(from_addr.sin_port), - formerrmsg); - } + (char*)nhash(formerrmsg))) + syslog(LOG_INFO, "Malformed response from %s (%s)\n", + inet_etoa(&from_addr), formerrmsg); nameserIncr(from_addr.sin_addr, nssSentFErr); #ifdef DATUMREFCNT free_nsp(nsp); #endif return; -return_msg: + return_msg: nameserIncr(from_addr.sin_addr, nssRcvdFwdR); nameserIncr(qp->q_from.sin_addr, nssSentFwdR); /* The "standard" return code */ hp->qr = 1; hp->id = qp->q_id; hp->rd = 1; - hp->ra = 1; + hp->ra = (NoRecurse == 0); (void) send_msg(msg, msglen, qp); qremove(qp); #ifdef DATUMREFCNT @@ -1015,17 +1134,22 @@ return_msg: #endif return; -return_newmsg: + return_newmsg: nameserIncr(qp->q_from.sin_addr, nssSentAns); - if (addcount) { - n = doaddinfo(hp, cp, buflen); - cp += n; - buflen -= n; - } + +#ifdef XSTATS + if (!hp->aa) + nameserIncr(qp->q_from.sin_addr, nssSentNaAns); + if (hp->rcode == NXDOMAIN) + nameserIncr(qp->q_from.sin_addr, nssSentNXD); +#endif + n = doaddinfo(hp, cp, buflen); + cp += n; + buflen -= n; hp->qr = 1; hp->id = qp->q_id; hp->rd = 1; - hp->ra = 1; + hp->ra = (NoRecurse == 0); (void) send_msg(newmsg, cp - newmsg, qp); qremove(qp); #ifdef DATUMREFCNT @@ -1033,14 +1157,14 @@ return_newmsg: #endif return; -servfail: + servfail: nameserIncr(qp->q_from.sin_addr, nssSentFail); hp = (HEADER *)(cname ? qp->q_cmsg : qp->q_msg); hp->rcode = SERVFAIL; + hp->qr = 1; hp->id = qp->q_id; hp->rd = 1; - hp->ra = 1; - hp->qr = 1; + hp->ra = (NoRecurse == 0); (void) send_msg((u_char *)hp, (cname ? qp->q_cmsglen : qp->q_msglen), qp); qremove(qp); @@ -1074,8 +1198,8 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) int zonenum; #endif - dprintf(3, (ddt, "doupdate(zone %d, savens %x, flags %x)\n", - zone, savens, flags)); + dprintf(3, (ddt, "doupdate(zone %d, savens %#lx, flags %#lx)\n", + zone, (u_long)savens, (u_long)flags)); cp = rrp; if ((n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname)) < 0) { @@ -1109,6 +1233,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) case T_X25: case T_ISDN: case T_NSAP: + case T_LOC: #ifdef ALLOW_T_UNSPEC case T_UNSPEC: #endif @@ -1188,6 +1313,33 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) cp1 = data; break; + case T_PX: + /* grab preference */ + bcopy(cp, data, INT16SZ); + cp1 = data + INT16SZ; + cp += INT16SZ; + + /* get MAP822 name */ + n = dn_expand(msg, msg + msglen, cp, (char *)cp1, + sizeof data - INT16SZ); + if (n < 0) { + hp->rcode = FORMERR; + return (-1); + } + cp += n; + cp1 += (n = strlen((char *)cp1) + 1); + n1 = sizeof(data) - n; + n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1); + if (n < 0) { + hp->rcode = FORMERR; + return (-1); + } + cp += n; + cp1 += strlen((char *)cp1) + 1; + n = cp1 - data; + cp1 = data; + break; + default: dprintf(3, (ddt, "unknown type %d\n", type)); return ((cp - rrp) + dlen); @@ -1196,7 +1348,7 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) dprintf(1, (ddt, "update type %d: %d bytes is too much data\n", type, n)); - hp->rcode = NOCHANGE; /* XXX - FORMERR ??? */ + hp->rcode = FORMERR; return (-1); } @@ -1379,19 +1531,17 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) if (!haveComplained((char*)from_addr.sin_addr.s_addr, "bogus root NS")) syslog(LOG_NOTICE, - "bogus root NS %s rcvd from [%s] on query for \"%s\"", - data, inet_ntoa(from_addr.sin_addr), - qname); + "bogus root NS %s rcvd from %s on query for \"%s\"", + data, inet_etoa(&from_addr), qname); return (cp - rrp); } #ifdef BOGUSNS if (bogusns) { if (!haveComplained((char*)from_addr.sin_addr.s_addr, "bogus nonroot NS")) - syslog(LOG_NOTICE, - "bogus nonroot NS %s rcvd from [%s] on query for \"%s\"", - data, inet_ntoa(from_addr.sin_addr), - qname); + syslog(LOG_INFO, + "bogus nonroot NS %s rcvd from %s on query for \"%s\"", + data, inet_etoa(&from_addr), qname); return (cp - rrp); } #endif @@ -1405,9 +1555,9 @@ doupdate(msg, msglen, rrp, zone, savens, flags, cred) if ((n = db_update(dname, dp, dp, flags, hashtab)) != OK) { #ifdef DEBUG if (debug && (n != DATAEXISTS)) - fprintf(ddt,"update failed (%d)\n", n); + fprintf(ddt, "update failed (%d)\n", n); else if (debug >= 3) - fprintf(ddt,"update failed (DATAEXISTS)\n"); + fprintf(ddt, "update failed (DATAEXISTS)\n"); #endif free((char *)dp); } else if (type == T_NS && savens != NULL) @@ -1425,39 +1575,43 @@ send_msg(msg, msglen, qp) return (1); #ifdef DEBUG if (debug) { - fprintf(ddt,"send_msg -> [%s] (%s %d %d) id=%d\n", - inet_ntoa(qp->q_from.sin_addr), + fprintf(ddt,"send_msg -> %s (%s %d) id=%d\n", + inet_etoa(&qp->q_from), qp->q_stream == QSTREAM_NULL ? "UDP" : "TCP", qp->q_stream == QSTREAM_NULL ? qp->q_dfd : qp->q_stream->s_rfd, - ntohs(qp->q_from.sin_port), ntohs(qp->q_id)); } if (debug>4) { struct qinfo *tqp; - for (tqp = qhead; tqp!=QINFO_NULL; tqp = tqp->q_link) { - fprintf(ddt, "qp %x q_id: %d q_nsid: %d q_msglen: %d ", - tqp, tqp->q_id,tqp->q_nsid,tqp->q_msglen); - fprintf(ddt,"q_naddr: %d q_curaddr: %d\n", tqp->q_naddr, - tqp->q_curaddr); - fprintf(ddt,"q_next: %x q_link: %x\n", qp->q_next, - qp->q_link); + for (tqp = nsqhead; tqp!=QINFO_NULL; tqp = tqp->q_link) { + fprintf(ddt, + "qp %#lx q_id: %d q_nsid: %d q_msglen: %d ", + (u_long)tqp, tqp->q_id, + tqp->q_nsid, tqp->q_msglen); + fprintf(ddt, + "q_naddr: %d q_curaddr: %d\n", + tqp->q_naddr, tqp->q_curaddr); + fprintf(ddt, "q_next: %#lx q_link: %#lx\n", + (u_long)qp->q_next, (u_long)qp->q_link); } } if (debug >= 10) - fp_query(msg, ddt); + fp_nquery(msg, msglen, ddt); #endif /* DEBUG */ if (qp->q_stream == QSTREAM_NULL) { - if (sendto(qp->q_dfd, msg, msglen, 0, + if (sendto(qp->q_dfd, (char*)msg, msglen, 0, (struct sockaddr *)&qp->q_from, sizeof(qp->q_from)) < 0) { if (!haveComplained((char*)qp->q_from.sin_addr.s_addr, sendtoStr)) - syslog(LOG_NOTICE, - "send_msg: sendto([%s].%d): %m", - inet_ntoa(qp->q_from.sin_addr), - ntohs(qp->q_from.sin_port)); +#if defined(SPURIOUS_ECONNREFUSED) + if (errno != ECONNREFUSED) +#endif + syslog(LOG_INFO, + "send_msg: sendto(%s): %m", + inet_etoa(&qp->q_from)); nameserIncr(qp->q_from.sin_addr, nssSendtoErr); return (1); } @@ -1484,7 +1638,7 @@ prime(class, type, oqp) sizeof(dname)) < 0) return; dprintf(2, (ddt, "prime: %s\n", dname)); - (void) sysquery(dname, class, type, NULL, 0); + (void) sysquery(dname, class, type, NULL, 0, QUERY); } #endif @@ -1496,7 +1650,7 @@ prime_cache() dprintf(1, (ddt, "prime_cache: priming = %d\n", priming)); if (!priming && fcachetab->h_tab[0] != NULL && !forward_only) { priming++; - if ((qp = sysquery("", C_IN, T_NS, NULL, 0)) == NULL) + if (!(qp = sysquery("", C_IN, T_NS, NULL, 0, QUERY))) priming = 0; else qp->q_flags |= (Q_SYSTEM | Q_PRIMING); @@ -1505,12 +1659,156 @@ prime_cache() return; } +#ifdef BIND_NOTIFY +struct notify * +findNotifyPeer(zp, ina) + const struct zoneinfo *zp; + struct in_addr ina; +{ + register struct notify *ap; + + for (ap = zp->z_notifylist; ap; ap = ap->next) + if (ap->addr.s_addr == ina.s_addr) + break; + return (ap); +} + +/* sysnotify(dname, class, type) + * cause a NOTIFY request to be sysquery()'d to each secondary server + * of the zone that "dname" is within. + */ +void +sysnotify(dname, class, type) + const char *dname; + int class, type; +{ + char *soaname, *zname; + const char *fname; + register struct databuf *dp; + struct in_addr nss[NSMAX]; + int nns, na, zn, nsc; + struct hashbuf *htp; + struct zoneinfo *zp; + struct notify *ap; + struct namebuf *np; + + htp = hashtab; + np = nlookup(dname, &htp, &fname, 0); + if (!np) + panic(-1, "sysnotify: can't find name"); + zn = findMyZone(np, class); + if (zn == DB_Z_CACHE) + panic(-1, "sysnotify: not auth zone"); + zp = &zones[zn]; + if (zp->z_type != Z_PRIMARY && zp->z_type != Z_SECONDARY) + panic(-1, "sysnotify: not pri/sec"); + zname = zp->z_origin; +/* +**DBG** syslog(LOG_INFO, "sysnotify: found \"%s\" in \"%s\" (%s)", +**DBG** dname, zname, zoneTypeString(zp)); +*/ + nns = na = 0; + /* + * Send to recent AXFR peers. + */ + for (ap = zp->z_notifylist; ap; ap = ap->next) { + if (tt.tv_sec - ap->last >= zp->z_refresh) { + /* XXX - probably should do GC here. */ + continue; + } + nss[0] = ap->addr; + nsc = 1; + nns++; + na++; + sysquery(dname, class, T_SOA, nss, nsc, NS_NOTIFY_OP); + } + if (zp->z_type != Z_PRIMARY) + goto done; + /* + * Master. + */ + htp = hashtab; + np = nlookup(zname, &htp, &fname, 0); + if (!np) + panic(-1, "sysnotify: found name but not zone"); + soaname = NULL; + for (dp = np->n_data; dp; dp = dp->d_next) { + if (!dp->d_zone || !match(dp, class, T_SOA)) + continue; + if (soaname) { + syslog(LOG_NOTICE, "multiple SOA's for zone \"%s\"?", + zname); + return; + } + soaname = (char *) dp->d_data; + } + if (!soaname) { + syslog(LOG_NOTICE, "no SOA found for zone \"%s\"", zname); + return; + } + + for (dp = np->n_data; dp; dp = dp->d_next) { + register struct databuf *adp; + struct namebuf *anp; + + if (!dp->d_zone || !match(dp, class, T_NS)) + continue; + /* NS RDATA is server name. */ + if (strcasecmp((char*)dp->d_data, soaname) == 0) + continue; + htp = hashtab; + anp = nlookup((char*)dp->d_data, &htp, &fname, 0); + if (!anp) { + syslog(LOG_INFO, "sysnotify: can't nlookup(%s)?", + (char*)dp->d_data); + continue; + } + nsc = 0; + for (adp = anp->n_data; adp; adp = adp->d_next) { + struct in_addr ina; + if (!match(adp, class, T_A)) + continue; + ina = data_inaddr(adp->d_data); + /* Don't send to things we handled above. */ + ap = findNotifyPeer(zp, ina); + if (ap && tt.tv_sec - ap->last < zp->z_refresh) + goto nextns; + if (nsc < NSMAX) + nss[nsc++] = ina; + } /*next A*/ + if (nsc == 0) { + struct qinfo *qp; + + qp = sysquery((char*)dp->d_data, /*NS name*/ + class, /*XXX: C_IN?*/ + T_A, 0, 0, QUERY); + if (qp) + qp->q_notifyzone = zn; + continue; + } + (void) sysquery(dname, class, T_SOA, nss, nsc, NS_NOTIFY_OP); + nns++; + na += nsc; + nextns:; + } /*next NS*/ + done: + if (nns || na) { + char tmp[MAXDNAME*2]; + + /* Many syslog()'s only take 5 args. */ + sprintf(tmp, "%s %s %s", dname, p_class(class), p_type(type)); + syslog(LOG_INFO, "Sent NOTIFY for \"%s\" (%s); %d NS, %d A", + tmp, zname, nns, na); + } +} +#endif /*BIND_NOTIFY*/ + struct qinfo * -sysquery(dname, class, type, nss, nsc) - char *dname; +sysquery(dname, class, type, nss, nsc, opcode) + const char *dname; int class, type; struct in_addr *nss; - int nsc; + int nsc, opcode; { register struct qinfo *qp, *oqp; register HEADER *hp; @@ -1518,14 +1816,14 @@ sysquery(dname, class, type, nss, nsc) struct databuf *nsp[NSMAX]; struct hashbuf *htp; struct sockaddr_in *nsa; - char *fname; - int count; + const char *fname; + int n, count; #ifdef DATUMREFCNT nsp[0] = NULL; #endif - dprintf(3, (ddt, "sysquery(%s, %d, %d, 0x%x, %d)\n", - dname, class, type, nss, nsc)); + dprintf(3, (ddt, "sysquery(%s, %d, %d, %#lx, %d)\n", + dname, class, type, (u_long)nss, nsc)); qp = qnew(); if (nss && nsc) { @@ -1535,23 +1833,24 @@ sysquery(dname, class, type, nss, nsc) if (priming && dname[0] == '\0') { np = NULL; } else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) { - dprintf(1, (ddt, - "sysquery: nlookup error on %s?\n", - dname)); + syslog(LOG_INFO, "sysquery: nlookup error on %s?", + dname); + err1: qfree(qp); - return (0); + return (NULL); } - switch (findns(&np, class, nsp, &count, 0)) { + n = findns(&np, class, nsp, &count, 0); + switch (n) { case NXDOMAIN: case SERVFAIL: - dprintf(1, (ddt, - "sysquery: findns error on %s?\n", dname)); - qfree(qp); + syslog(LOG_DEBUG, "sysquery: findns error (%d) on %s?", + n, dname); + err2: #ifdef DATUMREFCNT free_nsp(nsp); #endif - return (0); + goto err1; } } @@ -1569,33 +1868,39 @@ sysquery(dname, class, type, nss, nsc) #endif /* LAME_DELEGATION */ if ((qp->q_msg = (u_char *)malloc(BUFSIZ)) == NULL) { - qfree(qp); -#ifdef DATUMREFCNT - free_nsp(nsp); -#endif - return (0); + syslog(LOG_NOTICE, "sysquery: malloc failed"); + goto err2; + } + n = res_mkquery(opcode, dname, class, + type, NULL, 0, NULL, + qp->q_msg, BUFSIZ); + if (n < 0) { + syslog(LOG_INFO, "sysquery: res_mkquery(%s) failed", dname); + goto err2; } - qp->q_msglen = res_mkquery(QUERY, dname, class, - type, NULL, 0, NULL, - qp->q_msg, BUFSIZ); + qp->q_msglen = n; hp = (HEADER *) qp->q_msg; - hp->id = qp->q_nsid = htons((u_int16_t)++nsid); + hp->id = qp->q_nsid = htons(nsid_next()); hp->rd = (qp->q_fwd ? 1 : 0); /* First check for an already pending query for this data */ - for (oqp = qhead; oqp != QINFO_NULL; oqp = oqp->q_link) { + for (oqp = nsqhead; oqp != QINFO_NULL; oqp = oqp->q_link) { if ((oqp != qp) && (oqp->q_msglen == qp->q_msglen) && bcmp((char *)oqp->q_msg+2, qp->q_msg+2, qp->q_msglen-2) == 0 ) { - dprintf(3, (ddt, "sysquery: duplicate\n")); - qfree(qp); -#ifdef DATUMREFCNT - free_nsp(nsp); -#endif - return (0); +#ifdef BIND_NOTIFY + /* XXX - need fancier test to suppress duplicate + * NOTIFYs to the same server (compare nss?) + */ + if (opcode != NS_NOTIFY_OP) +#endif /*BIND_NOTIFY*/ + { + dprintf(3, (ddt, "sysquery: duplicate\n")); + goto err2; + } } } @@ -1616,20 +1921,19 @@ sysquery(dname, class, type, nss, nsc) } qp->q_naddr = nsc; } else { - if ((count = nslookup(nsp, qp, dname, "sysquery")) <= 0) { - if (count < 0) { - dprintf(1, (ddt, - "sysquery: nslookup reports danger\n")); - } else { - dprintf(1, (ddt, - "sysquery: no addrs found for NS's\n")); + count = nslookup(nsp, qp, dname, "sysquery"); + if (count <= 0) { + if (count < 0) + syslog(LOG_INFO, + "sysquery: nslookup reports danger (%s)", + dname); + else + /* "." domain gets LOG_WARNING here. */ + syslog(dname[0] ? LOG_INFO : LOG_WARNING, + "sysquery: no addrs found for NS (%s)", + dname); + goto err2; } - qfree(qp); -#ifdef DATUMREFCNT - free_nsp(nsp); -#endif - return (0); - } } schedretry(qp, retrytime(qp)); @@ -1638,21 +1942,20 @@ sysquery(dname, class, type, nss, nsc) nsa = Q_NEXTADDR(qp, 0); dprintf(1, (ddt, - "sysquery: send -> [%s].%d dfd=%d nsid=%d id=%d retry=%ld\n", - inet_ntoa(nsa->sin_addr), - ntohs(nsa->sin_port), qp->q_dfd, + "sysquery: send -> %s dfd=%d nsid=%d id=%d retry=%ld\n", + inet_etoa(nsa), qp->q_dfd, ntohs(qp->q_nsid), ntohs(qp->q_id), qp->q_time)); #ifdef DEBUG if (debug >= 10) - fp_query(qp->q_msg, ddt); + fp_nquery(qp->q_msg, qp->q_msglen, ddt); #endif - if (sendto(qp->q_dfd, qp->q_msg, qp->q_msglen, 0, + if (sendto(qp->q_dfd, (char*)qp->q_msg, qp->q_msglen, 0, (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr)) - syslog(LOG_NOTICE, "sysquery: sendto([%s].%d): %m", - inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port)); + syslog(LOG_INFO, "sysquery: sendto(%s): %m", + inet_etoa(nsa)); nameserIncr(nsa->sin_addr, nssSendtoErr); } nameserIncr(nsa->sin_addr, nssSentSysQ); @@ -1678,7 +1981,7 @@ check_root() if (np->n_dname[0] == '\0') break; if (np == NULL) { - syslog(LOG_ERR, "check_root: Can't find root!\n"); + syslog(LOG_NOTICE, "check_root: Can't find root!\n"); return; } for (dp = np->n_data; dp != NULL; dp = dp->d_next) @@ -1686,9 +1989,9 @@ check_root() count++; dprintf(1, (ddt, "%d root servers\n", count)); if (count < MINROOTS) { - syslog(LOG_WARNING, + syslog(LOG_NOTICE, "check_root: %d root servers after query to root server < min", - count); + count); return; } pdp = NULL; @@ -1719,7 +2022,7 @@ check_ns() struct hashbuf *htp; char *dname; int found_arr; - char *fname; + const char *fname; time_t curtime; dprintf(2, (ddt, "check_ns()\n")); @@ -1738,9 +2041,9 @@ check_ns() tnp = nlookup(dname, &htp, &fname, 0); if (tnp == NULL || fname != dname) { dprintf(3, (ddt, - "check_ns: %s: not found %s %x\n", - dname, fname, tnp)); - sysquery(dname, dp->d_class, T_A, NULL, 0); + "check_ns: %s: not found %s %#lx\n", + dname, fname, (u_long)tnp)); + sysquery(dname, dp->d_class, T_A, NULL, 0, QUERY); continue; } /* look for name server addresses */ @@ -1762,7 +2065,7 @@ check_ns() found_arr++; } if (!found_arr) - (void) sysquery(dname, dp->d_class, T_A, NULL, 0); + sysquery(dname, dp->d_class, T_A, NULL, 0, QUERY); } } } @@ -1770,7 +2073,7 @@ check_ns() /* int findns(npp, class, nsp, countp, flag) * Find NS' or an SOA * npp, class: - * dname whose least-superior NS is wanted + * dname whose most enclosing NS is wanted * nsp, countp: * result array and count; array will also be NULL terminated * flag: @@ -1802,7 +2105,7 @@ findns(npp, class, nsp, countp, flag) else htp = hashtab; -try_again: + try_again: if (htp == fcachetab) needs_prime_cache = 1; while (np == NULL && htp != NULL) { @@ -1814,13 +2117,19 @@ try_again: htp = (htp == hashtab ? fcachetab : NULL); /* Fallback */ } while (np != NULL) { - dprintf(5, (ddt, "findns: np 0x%x '%s'\n", np, np->n_dname)); + dprintf(5, (ddt, "findns: np %#lx '%s'\n", + (u_long)np, np->n_dname)); /* Look first for SOA records. */ #ifdef ADDAUTH if (!flag) #endif for (dp = np->n_data; dp != NULL; dp = dp->d_next) { - if (dp->d_zone != 0 && match(dp, class, T_SOA)) { + if (dp->d_zone != 0 && +#ifdef PURGE_ZONE + ((zones[dp->d_zone].z_type == Z_PRIMARY) || + (zones[dp->d_zone].z_type == Z_SECONDARY)) && +#endif + match(dp, class, T_SOA)) { dprintf(3, (ddt, "findns: SOA found\n")); if (zones[dp->d_zone].z_flags & Z_AUTH) { *npp = np; @@ -1846,6 +2155,10 @@ try_again: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!match(dp, class, T_NS)) continue; +#ifdef NCACHE + if (dp->d_rcode) + continue; +#endif /* * Don't use records that may become invalid to * reference later when we do the rtt computation. @@ -1854,12 +2167,18 @@ try_again: * 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", np->n_dname)); /* Cache invalidate the NS RR's. */ +#ifndef DATUMREFCNT if (dp->d_ttl < tt.tv_sec) +#endif delete_all(np, class, T_NS); goto try_parent; } @@ -1888,7 +2207,7 @@ try_parent: p_class(class))); if ((unsigned)class < MAXCLASS && norootlogged[class] == 0) { norootlogged[class] = 1; - syslog(LOG_ERR, "No root nameservers for class %s\n", + syslog(LOG_INFO, "No root nameservers for class %s\n", p_class(class)); } return (SERVFAIL); @@ -1936,6 +2255,10 @@ finddata(np, class, type, hp, dnamep, lenp, countp) #endif /*ROUND_ROBIN*/ buflen = *lenp; +#ifdef DEBUG + if (buflen > PACKETSZ) + dprintf(1, (ddt, "finddata(): buflen=%d\n", buflen)); +#endif cp = ((char *)hp) + *countp; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!wanted(dp, class, type)) { @@ -1986,9 +2309,9 @@ finddata(np, class, type, hp, dnamep, lenp, countp) /* * This should not happen, yet it does... */ - syslog(LOG_WARNING, + syslog(LOG_INFO, "NODATA & data for \"%s\" type %d class %d", - *dnamep, type, class); + *dnamep, type, class); continue; } if (type != T_ANY) { @@ -2005,9 +2328,9 @@ finddata(np, class, type, hp, dnamep, lenp, countp) /* * This should not happen, yet it might... */ - syslog(LOG_WARNING, + syslog(LOG_INFO, "NXDOMAIN & data for \"%s\" type %d class %d", - *dnamep, type, class); + *dnamep, type, class); continue; } if (type != T_ANY) { @@ -2040,7 +2363,7 @@ finddata(np, class, type, hp, dnamep, lenp, countp) if (dp->d_type == T_CNAME) { if (type != T_ANY) { /* or T_NS? */ *dnamep = (caddr_t) dp->d_data; - if (dp->d_zone && + if (dp->d_zone != DB_Z_CACHE && (zones[dp->d_zone].z_flags & Z_AUTH) && class != C_ANY) /* XXX */ hp->aa = 1; /* XXX */ @@ -2074,9 +2397,9 @@ wanted(dp, class, type) struct databuf *dp; int class, type; { - - dprintf(3, (ddt, "wanted(%x, %d, %d) %d, %d\n", dp, class, type, - dp->d_class, dp->d_type)); + 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); @@ -2145,7 +2468,7 @@ add_data(np, dpp, cp, buflen) register int n, count = 0; getname(np, dname, sizeof(dname)); - for(dp = *dpp++; dp != NULL; dp = *dpp++) { + for (dp = *dpp++; dp != NULL; dp = *dpp++) { if (stale(dp)) continue; /* ignore old cache entry */ #ifdef NCACHE @@ -2174,8 +2497,8 @@ delete_all(np, class, type) { register struct databuf *dp, *pdp; - dprintf(3, (ddt, "delete_all: '%s' 0x%x class %d type %d\n", - np->n_dname, np, class, type)); + dprintf(3, (ddt, "delete_all(%#lx:\"%s\" %s %s)\n", + (u_long)np, np->n_dname, p_class(class), p_type(type))); pdp = NULL; dp = np->n_data; while (dp != NULL) { diff --git a/usr.sbin/named/ns_sort.c b/usr.sbin/named/ns_sort.c index c35b58f16ae4..499a5b4f33bc 100644 --- a/usr.sbin/named/ns_sort.c +++ b/usr.sbin/named/ns_sort.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) static char sccsid[] = "@(#)ns_sort.c 4.10 (Berkeley) 3/3/91"; -static char rcsid[] = "$Id: ns_sort.c,v 4.9.1.6 1994/07/23 23:23:56 vixie Exp $"; +static char rcsid[] = "$Id: ns_sort.c,v 8.2 1995/06/29 09:26:17 vixie Exp $"; #endif /* not lint */ /* @@ -124,8 +124,8 @@ sort_rr(cp, count, ntp, eom) #ifdef DEBUG if (debug > 2) { inaddr.s_addr = ntp->addr; - fprintf(ddt, "sort_rr(x%x, %d, [%s])\n", - cp, count, inet_ntoa(inaddr)); + fprintf(ddt, "sort_rr(%#lx, %d, [%s])\n", + (u_long)cp, count, inet_ntoa(inaddr)); } #endif rr1 = NULL; diff --git a/usr.sbin/named/ns_stats.c b/usr.sbin/named/ns_stats.c index d6d6225b6210..d609edd4d2be 100644 --- a/usr.sbin/named/ns_stats.c +++ b/usr.sbin/named/ns_stats.c @@ -1,12 +1,12 @@ #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 4.9.1.7 1994/06/06 09:08:15 vixie Exp $"; +static char rcsid[] = "$Id: ns_stats.c,v 8.4 1995/06/29 09:26:17 vixie Exp $"; #endif /* not lint */ /* - * ++Copyright++ 1986 + * ++Copyright++ 1986,1994 * - - * Copyright (c) 1986 + * Copyright (c) 1986,1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,6 +66,7 @@ static char rcsid[] = "$Id: ns_stats.c,v 4.9.1.7 1994/06/06 09:08:15 vixie Exp $ #include <sys/param.h> #include <netinet/in.h> #include <arpa/nameser.h> +#include <arpa/inet.h> #include <stdio.h> #include <syslog.h> #include <errno.h> @@ -80,8 +81,10 @@ static const char *typenames[T_ANY+1] = { "CNAME", "SOA", "MB", "MG", "MR", "NULL", "WKS", "PTR", "HINFO", "MINFO", "MX", "TXT", "RP", "AFSDB", "X25", - "ISDN", "RT", "NSAP", 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "ISDN", "RT", "NSAP", "NSAP_PTR", "SIG", + "KEY", "PX", "invalid(GPOS)", "AAAA", "LOC", + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, /* 20 per line */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -109,21 +112,24 @@ static void nameserStats __P((FILE *)); void ns_stats() { - time_t timenow; + time_t timenow = time(NULL); register FILE *f; register int i; + syslog(LOG_NOTICE, "dumping nameserver stats\n"); + if (!(f = fopen(statsfile, "a"))) { - dprintf(1, (ddt, "can't open stat file, \"%s\"\n", statsfile)); - syslog(LOG_ERR, "cannot open stat file, \"%s\"\n", statsfile); + syslog(LOG_NOTICE, "cannot open stat file, \"%s\"\n", + statsfile); return; } - time(&timenow); fprintf(f, "+++ Statistics Dump +++ (%ld) %s", (long)timenow, ctime(&timenow)); - fprintf(f, "%d\ttime since boot (secs)\n", timenow - boottime); - fprintf(f, "%d\ttime since reset (secs)\n", timenow - resettime); + fprintf(f, "%ld\ttime since boot (secs)\n", + (long)(timenow - boottime)); + fprintf(f, "%ld\ttime since reset (secs)\n", + (long)(timenow - resettime)); #ifdef DMALLOC /* malloc statistics */ @@ -131,15 +137,15 @@ ns_stats() #endif /* query type statistics */ - fprintf(f, "%d\tUnknown query types\n", typestats[0]); + fprintf(f, "%lu\tUnknown query types\n", (u_long)typestats[0]); for(i=1; i < T_ANY+1; i++) if (typestats[i]) if (typenames[i]) - fprintf(f, "%lu\t%s queries\n", typestats[i], - typenames[i]); + fprintf(f, "%lu\t%s queries\n", + (u_long)typestats[i], typenames[i]); else fprintf(f, "%lu\ttype %d queries\n", - typestats[i], i); + (u_long)typestats[i], i); /* name server statistics */ nameserStats(f); @@ -147,6 +153,7 @@ ns_stats() fprintf(f, "--- Statistics Dump --- (%ld) %s", (long)timenow, ctime(&timenow)); (void) my_fclose(f); + syslog(LOG_NOTICE, "done dumping nameserver stats\n"); } void @@ -187,6 +194,12 @@ static const char *statNames[nssLast] = { "SDupQ", /* sent them a retry */ "SFail", /* sent them a SERVFAIL */ "SFErr", /* sent them a FORMERR */ + "SErr", /* sent failed (in sendto) */ +#ifdef XSTATS + "RNotNsQ", /* received from remote port != ns_port */ + "SNaAns", /* sent them a non autoritative answer */ + "SNXD", /* sent them a negative response */ +#endif }; #endif /*STATS*/ @@ -268,10 +281,10 @@ nameserStatsOut(f, stats) u_long stats[]; { int i; - char *pre = "\t"; + const char *pre = "\t"; for (i = 0; i < (int)nssLast; i++) { - fprintf(f, "%s%u", pre, stats[i]); + fprintf(f, "%s%lu", pre, (u_long)stats[i]); pre = ((i+1) % 5) ? " " : " "; } fputc('\n', f); @@ -282,7 +295,7 @@ nameserStatsHdr(f) FILE *f; { int i; - char *pre = "\t"; + const char *pre = "\t"; fprintf(f, "(Legend)\n"); for (i = 0; i < (int)nssLast; i++) { @@ -323,3 +336,63 @@ nameserStats(f) nameserStatsFile = NULL; #endif /*STATS*/ } + +#ifdef XSTATS +/* Benoit Grange, log minimal statistics, called from ns_maint */ +void +ns_logstats() +{ + char buffer[1024]; + char buffer2[32], header[64]; + time_t timenow = time(NULL); + int i; + +#ifdef HAVE_GETRUSAGE +# define tv_float(tv) ((tv).tv_sec + ((tv).tv_usec / 1000000.0)) + struct rusage usage, childu; + + getrusage(RUSAGE_SELF, &usage); + getrusage(RUSAGE_CHILDREN, &childu); + + sprintf(buffer, "CPU=%gu/%gs CHILDCPU=%gu/%gs", + tv_float(usage.ru_utime), tv_float(usage.ru_stime), + tv_float(childu.ru_utime), tv_float(childu.ru_stime)); + syslog(LOG_INFO, "USAGE %lu %lu %s", timenow, boottime, buffer); +# undef tv_float +#endif + + sprintf(header, "NSTATS %lu %lu", timenow, boottime); + strcpy(buffer, header); + + for (i = 0; i < T_ANY+1; i++) { + if (typestats[i]) { + if (typenames[i]) + sprintf(buffer2, " %s=%lu", + typenames[i], typestats[i]); + else + sprintf(buffer2, " %d=%lu", i, typestats[i]); + if (strlen(buffer) + strlen(buffer2) > + sizeof(buffer) - 1) { + syslog(LOG_INFO, buffer); + strcpy(buffer, header); + } + strcat(buffer, buffer2); + } + } + syslog(LOG_INFO, buffer); + + sprintf(header, "XSTATS %lu %lu", (u_long)timenow, (u_long)boottime); + strcpy(buffer, header); + for (i = 0; i < (int)nssLast; i++) { + sprintf(buffer2, " %s=%lu", + statNames[i]?statNames[i]:"?", (u_long)globalStats[i]); + if (strlen(buffer) + strlen(buffer2) > sizeof(buffer) - 1) { + syslog(LOG_INFO, buffer); + strcpy(buffer, header); + } + strcat(buffer, buffer2); + } + syslog(LOG_INFO, buffer); +} + +#endif /*XSTATS*/ diff --git a/usr.sbin/named/ns_validate.c b/usr.sbin/named/ns_validate.c index f1236c542e10..6978de1e137a 100644 --- a/usr.sbin/named/ns_validate.c +++ b/usr.sbin/named/ns_validate.c @@ -52,21 +52,21 @@ static int VQcount; * pseudocode for function validate is as follows: * validate(domain, server, type, class, data, dlen, rcode) { * - * if(dname or a higher level name not found in cache) + * if (dname or a higher level name not found in cache) * return INVALID; * if (NS records for "domain" found in cache){ * - * if(we are authoritative) /findns() returned NXDOMAIN;/ - * if(we did not have an exact match on names) + * if (we are authoritative) /findns() returned NXDOMAIN;/ + * if (we did not have an exact match on names) * =>the name does not exist in our database * => data is bad: return INVALID - * if(data agrees with what we have) + * if (data agrees with what we have) * return VALID_NO_CACHE; * else return INVALID; * - * if(we are not authoritative) /findns() returned OK;/ + * if (we are not authoritative) /findns() returned OK;/ * if (address records for NS's found in cache){ - * if("server" = one of the addresses){ + * if ("server" = one of the addresses){ * return VALID_CACHE; * }else{ * stick in queue of "to_validate" data; @@ -121,7 +121,7 @@ validate(dname, server, type, class, data, dlen /* everything from forwarders is the GOSPEL */ for (fwd = fwdtab; fwd != NULL; fwd = fwd->next) { if (server->sin_addr.s_addr == fwd->fwdaddr.sin_addr.s_addr) - return(VALID_CACHE); + return (VALID_CACHE); } htp = hashtab; @@ -138,16 +138,15 @@ validate(dname, server, type, class, data, dlen fname[0] = '\0'; } dprintf(5, (ddt, - "validate:namebuf found np:0x%x, d:\"%s\", f:\"%s\"\n", - np, dname, fname)); + "validate:namebuf found np:%#lx, d:\"%s\", f:\"%s\"\n", + (u_long)np, dname, fname)); /* save the namebuf if we were able to locate the exact dname */ if (!strcasecmp(dname, fname)) { dnamep = np; exactmatch = 1; } - if (np == NULL && fname != NULL) { + if (np == NULL && fname != NULL) free((char *)fname); - } switch (findns(&np, class, nsp, &count, 0)) { case NXDOMAIN: /** we are authoritative for this domain, lookup name @@ -162,19 +161,19 @@ validate(dname, server, type, class, data, dlen needs_prime_cache = 0; #ifdef NCACHE - if(rcode == NXDOMAIN) { + if (rcode == NXDOMAIN) { /* If we had an exactmatch on the name, we found the * name in our authority database, so this couldn't * have been a bad name. INVALID data, say so */ if (exactmatch) - return INVALID; + return (INVALID); else /* we did not have an exactmatch, the data is * good, we do not NCACHE stuff we are * authoritative for, though. */ - return VALID_NO_CACHE; + return (VALID_NO_CACHE); } #endif if (!strcasecmp(dname, np->n_dname)) { @@ -185,9 +184,9 @@ validate(dname, server, type, class, data, dlen * doesn't, invalid. */ if (isvalid(np, type, class, data, dlen)) - return VALID_NO_CACHE; + return (VALID_NO_CACHE); else - return INVALID; + return (INVALID); } /* we found ns records in a higher level, if we were unable to @@ -196,16 +195,16 @@ validate(dname, server, type, class, data, dlen * this name. this name is obviously invalid */ if (!exactmatch) - return INVALID; + return (INVALID); /* we found the exact name earlier and we are obviously * authoritative so check for data records and see if any * match. */ if (isvalid(dnamep, type, class, data, dlen)) - return VALID_NO_CACHE; + return (VALID_NO_CACHE); else - return INVALID; + return (INVALID); case SERVFAIL:/* could not find name server records*/ /* stick_in_queue(dname, type, class, data); */ @@ -214,7 +213,7 @@ validate(dname, server, type, class, data, dlen #ifdef DATUMREFCNT free_nsp(nsp); #endif - return INVALID; + return (INVALID); case OK: /*proceed */ dprintf(5, @@ -226,19 +225,19 @@ validate(dname, server, type, class, data, dlen #ifdef DATUMREFCNT free_nsp(nsp); #endif - return VALID_CACHE; + 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; + return (INVALID); default: #ifdef DATUMREFCNT free_nsp(nsp); #endif - return INVALID; + return (INVALID); } /*switch*/ } /*validate*/ @@ -262,7 +261,7 @@ isvalid(np, type, class, data, dlen) if (!wanted(dp, class, type)) { if ((type == T_CNAME) && (class == dp->d_class)) { /* if a cname exists, any other will not */ - return(0); + return (0); /* we come here only for zone info, * so -ve $ed info can't be */ @@ -277,12 +276,10 @@ isvalid(np, type, class, data, dlen) * we should return FAILURE since we should not have found * data here. */ - if ((data == NULL) || (dlen == 0)) { - return 0; - } + if ((data == NULL) || (dlen == 0)) + return (0); - /* XXX: why aren't we just calling db_cmp() ? - */ + /* XXX: why aren't we just calling db_cmp()? */ switch (type) { char *td; @@ -298,6 +295,7 @@ isvalid(np, type, class, data, dlen) case T_TXT: case T_X25: case T_ISDN: + case T_LOC: #ifdef ALLOW_T_UNSPEC case T_UNSPEC: #endif @@ -378,6 +376,29 @@ isvalid(np, type, class, data, dlen) break; return (1); + case T_PX: + x = memcmp(dp->d_data, data, + INT16SZ); + if (x != 0) + break; + td = data + INT16SZ; + tdp = dp->d_data + INT16SZ; + + /* compare first string */ + x = strncasecmp(td, (char *)tdp, + strlen((char *)td) + 1); + if (x != 0) + break; + td += (strlen(td) + 1); + tdp += (strlen(tdp) + 1); + + /* compare second string */ + x = strncasecmp(td, (char *)tdp, + strlen((char *)td+1)); + if (x != 0) + break; + return (1); + default: dprintf(3, (ddt, "unknown type %d\n", type)); return (0); @@ -390,7 +411,7 @@ isvalid(np, type, class, data, dlen) */ if ((data == NULL) || (dlen == 0)) { /* negative data, report success */ - return 1; + return (1); } /* positive data, no such RR, validation failed */ return (0); @@ -512,7 +533,7 @@ check_in_tables(nsp, server, syslogdname) void store_name_addr(servername, serveraddr, syslogdname, sysloginfo) char *servername; - struct in_addr *serveraddr; + struct in_addr serveraddr; char *syslogdname; char *sysloginfo; { @@ -520,21 +541,21 @@ store_name_addr(servername, serveraddr, syslogdname, sysloginfo) dprintf(3, (ddt, "store_name_addr:s:%s, a:[%s]\n", - servername, inet_ntoa(*serveraddr))); + servername, inet_ntoa(serveraddr))); /* if we already have the name address pair in cache, return */ for (i = lastNA; i != firstNA; i = (i+1) % MAXNAMECACHE) { if (strcasecmp(servername, nameaddrlist[i].nsname) == 0) { - if (serveraddr->s_addr + if (serveraddr.s_addr == nameaddrlist[i].ns_addr.s_addr) { dprintf(5, (ddt, "store_name_addr:found n and a [%s] [%s] in our $\n", inet_ntoa(nameaddrlist[i].ns_addr), - inet_ntoa(*serveraddr))); + inet_ntoa(serveraddr))); return; } /* if */ - } else if (serveraddr->s_addr + } else if (serveraddr.s_addr == nameaddrlist[i].ns_addr.s_addr) { #ifdef BAD_IDEA @@ -543,20 +564,15 @@ store_name_addr(servername, serveraddr, syslogdname, sysloginfo) * replace old name by new, next query likely to have * NS record matching new */ - if (!haveComplained( - (char*)dhash((u_char*)nameaddrlist[i].nsname, - strlen(nameaddrlist[i].nsname)), - (char*)dhash((u_char*)servername, - strlen(servername)) - ) - ) { + if (!haveComplained((char*) + nhash(nameaddrlist[i].nsname), + (char*)nhash(servername))) syslog(LOG_INFO, "%s: server name mismatch for [%s]: (%s != %s) (server for %s)", sysloginfo, - inet_ntoa(*serveraddr), + inet_ntoa(serveraddr), nameaddrlist[i].nsname, servername, syslogdname); - } #endif free(nameaddrlist[i].nsname); nameaddrlist[i].nsname = @@ -570,7 +586,7 @@ store_name_addr(servername, serveraddr, syslogdname, sysloginfo) nameaddrlist[firstNA].nsname = (char *)malloc((unsigned)strlen(servername)+1); strcpy(nameaddrlist[firstNA].nsname, servername); - bcopy((char *)serveraddr, + bcopy((char *)&serveraddr, (char *)&(nameaddrlist[firstNA].ns_addr), INADDRSZ); @@ -616,7 +632,7 @@ dovalidate(msg, msglen, rrp, zone, flags, server, VCode) zone, flags)); #ifdef DEBUG if (debug >= 10) - fp_query(msg, ddt); + fp_nquery(msg, msglen, ddt); #endif cp = rrp; @@ -646,6 +662,7 @@ dovalidate(msg, msglen, rrp, zone, flags, server, VCode) case T_TXT: case T_X25: case T_ISDN: + case T_LOC: #ifdef ALLOW_T_UNSPEC case T_UNSPEC: #endif @@ -714,7 +731,7 @@ dovalidate(msg, msglen, rrp, zone, flags, server, VCode) (char *)cp1, sizeof(data) - INT16SZ); if (n < 0) { hp->rcode = FORMERR; - return(-1); + return (-1); } cp += n; @@ -725,6 +742,35 @@ dovalidate(msg, msglen, rrp, zone, flags, server, VCode) cp1 = data; break; + case T_PX: + /* grab preference */ + bcopy((char *)cp, data, INT16SZ); + cp1 = data + INT16SZ; + cp += INT16SZ; + + /* get first name */ + n = dn_expand(msg, msg + msglen, cp, + (char *)cp1, sizeof(data) - INT16SZ); + if (n < 0) { + hp->rcode = FORMERR; + return (-1); + } + cp += n; + cp1 += (n = strlen((char *)cp1) + 1); + n1 = sizeof(data) - n; + + /* get second name */ + n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1); + if (n < 0) { + hp->rcode = FORMERR; + return (-1); + } + cp += n; + cp1 += strlen((char *)cp1) + 1; + n = cp1 - data; + cp1 = data; + break; + default: dprintf(3, (ddt, "unknown type %d\n", type)); return ((cp - rrp) + dlen); @@ -733,8 +779,8 @@ dovalidate(msg, msglen, rrp, zone, flags, server, VCode) dprintf(2, (ddt, "update type %d: %d bytes is too much data\n", type, n)); - hp->rcode = NOCHANGE; /* XXX - FORMERR ??? */ - return(-1); + hp->rcode = FORMERR; + return (-1); } *VCode = validate(dname, server, type, class,(char *)cp1, n @@ -751,7 +797,7 @@ dovalidate(msg, msglen, rrp, zone, flags, server, VCode) "validation succeeded d:%s, t:%d, c:%d\n", dname, type, class)); } - return(cp -rrp); + return (cp - rrp); } #if 0 @@ -871,7 +917,7 @@ update_msg(msg, msglen, Vlist, c) if (debug) { fprintf(ddt, "update_msg: msglen:%d, c:%d\n", *msglen, c); if (debug >= 10) - fp_query(msg, ddt); + fp_nquery(msg, *msglen, ddt); } #endif /* just making sure we do not do all the work for nothing */ @@ -942,7 +988,7 @@ update_msg(msg, msglen, Vlist, c) dprintf(3, (ddt, "newlen:%d, if no RR is INVALID == msglen\n", newlen)); newmsg = (u_char *)calloc(1,newlen + MAXDNAME); - if(newmsg == NULL) + if (newmsg == NULL) goto badend; dpp = dnptrs; *dpp++ = newmsg; @@ -1022,6 +1068,7 @@ update_msg(msg, msglen, Vlist, c) case T_TXT: case T_X25: case T_ISDN: + case T_LOC: #ifdef ALLOW_T_UNSPEC case T_UNSPEC: #endif @@ -1128,6 +1175,44 @@ update_msg(msg, msglen, Vlist, c) rembuflen -= n_new+INT16SZ; break; + case T_PX: + /* grab preference */ + bcopy(cp, newcp, INT16SZ); + cp += INT16SZ; + newcp += INT16SZ; + + /* get first name */ + n = dn_expand(msg, eom, cp, (char *)data, sizeof data); + if (n < 0) { + hp->rcode = FORMERR; + goto badend; + } + cp += n; + n_new = dn_comp((char *)data, newcp, rembuflen, + dnptrs, edp); + if (n_new < 0) + goto badend; + newcp += n_new; + newlen += n_new+INT16SZ; + rembuflen -= n_new+INT16SZ; + dlen = n_new+INT16SZ; + n = dn_expand(msg, eom, cp, (char *)data, sizeof data); + if (n < 0) { + hp->rcode = FORMERR; + goto badend; + } + cp += n; + n_new = dn_comp((char *)data, newcp, rembuflen, + dnptrs, edp); + if (n_new < 0) + goto badend; + newcp += n_new; + newlen += n_new; + rembuflen -= n_new; + dlen += n_new; + PUTSHORT(dlen, tempcp); + break; + default: dprintf(3, (ddt, "unknown type %d\n", type)); goto badend; @@ -1148,14 +1233,14 @@ update_msg(msg, msglen, Vlist, c) #ifdef DEBUG if (debug >= 10) - fp_query(msg, ddt); + fp_nquery(msg, *msglen, ddt); #endif free((char *)RRlen); - return(n); + return (n); badend: dprintf(2, (ddt, "encountered problems: UPDATE_MSG\n")); free((char *)RRlen); - return(-1); + return (-1); } #endif /*VALIDATE*/ diff --git a/usr.sbin/named/pathnames.h b/usr.sbin/named/pathnames.h index bcbe642cb4a3..7ded7d212caa 100644 --- a/usr.sbin/named/pathnames.h +++ b/usr.sbin/named/pathnames.h @@ -1,6 +1,6 @@ /* * @(#)pathnames.h 5.4 (Berkeley) 6/1/90 - * $Id: pathnames.h,v 4.9.1.5 1994/04/09 03:43:17 vixie Exp $ + * $Id: pathnames.h,v 8.1 1994/12/15 06:24:14 vixie Exp $ */ /* diff --git a/usr.sbin/named/storage.c b/usr.sbin/named/storage.c index 98a71b3f294b..6ae21633e38a 100644 --- a/usr.sbin/named/storage.c +++ b/usr.sbin/named/storage.c @@ -55,8 +55,10 @@ #include <sys/param.h> #include <syslog.h> + #include "../conf/portability.h" #include "../conf/options.h" +extern void panic __P((int, const char *)); #ifdef DSTORAGE /* @@ -83,7 +85,7 @@ * All rights reserved. */ #ifndef lint -static char RCSid[] = "$Id: storage.c,v 4.9.1.2 1993/09/08 00:01:17 vixie Exp $"; +static char RCSid[] = "$Id: storage.c,v 8.1 1994/12/15 06:24:14 vixie Exp $"; #endif #undef malloc @@ -110,8 +112,7 @@ unsigned int cnt; ptr = malloc(cnt); if( ptr==(char *)0 ) { - syslog(LOG_ERR, "rt_malloc: malloc failure"); - abort(); + panic(errno, "rt_malloc: malloc failure"); } else { register struct memdebug *mp = rt_mdb; for( ; mp < &rt_mdb[MDB_SIZE]; mp++ ) { @@ -144,18 +145,14 @@ char *ptr; if( mp->mdb_addr != ptr ) continue; { register int *ip = (int *)(ptr+mp->mdb_len-sizeof(int)); - if( *ip != MDB_MAGIC ) { - syslog(LOG_ERR, "ERROR rt_free(x%x, %s) corrupted! x%x!=x%x\n", ptr, "???", *ip, MDB_MAGIC); - abort(); - } + if( *ip != MDB_MAGIC ) + panic(-1, "rt_free: corrupt magic"); } mp->mdb_len = 0; /* successful free */ goto ok; } - syslog(LOG_ERR, "ERROR rt_free(x%x, %s) bad pointer!\n", ptr, "???"); - abort(); -ok: ; - + panic(-1, "rt_free: bad pointer"); + ok: *((int *)ptr) = -1; /* zappo! */ free(ptr); } diff --git a/usr.sbin/named/tree.h b/usr.sbin/named/tree.h index 2cad7c1233ae..7d027b948b69 100644 --- a/usr.sbin/named/tree.h +++ b/usr.sbin/named/tree.h @@ -3,7 +3,7 @@ * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes] * vix 27jun86 [broken out of tree.c] * - * $Id: tree.h,v 1.1 1994/04/09 04:05:46 vixie Exp $ + * $Id: tree.h,v 8.1 1994/12/15 06:24:14 vixie Exp $ */ |