#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 1.3 1995/05/30 03:48:39 rgrimes Exp $"; #endif /* not lint */ /* * ++Copyright++ 1986, 1988, 1990 * - * Copyright (c) 1986, 1988, 1990 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * - * --Copyright-- */ /* * Load data base from ascii backupfile. Format similar to RFC 883. */ #include #include #include #include #include #include #include #include #include #include #include #include "named.h" 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 */ struct map { char token[8]; int val; }; struct map m_class[] = { { "in", C_IN }, #ifdef notdef { "any", C_ANY }, /* any is a QCLASS, not CLASS */ #endif { "chaos", C_CHAOS }, { "hs", C_HS }, }; #define M_CLASS_CNT (sizeof(m_class) / sizeof(struct map)) struct map m_type[] = { { "a", T_A }, { "ns", T_NS }, { "cname", T_CNAME }, { "soa", T_SOA }, { "mb", T_MB }, { "mg", T_MG }, { "mr", T_MR }, { "null", T_NULL }, { "wks", T_WKS }, { "ptr", T_PTR }, { "hinfo", T_HINFO }, { "minfo", T_MINFO }, { "mx", T_MX }, { "uinfo", T_UINFO }, { "txt", T_TXT }, { "rp", T_RP }, { "afsdb", T_AFSDB }, { "x25", T_X25 }, { "isdn", T_ISDN }, { "rt", T_RT }, { "nsap", T_NSAP }, { "nsap_ptr", T_NSAP_PTR }, { "uid", T_UID }, { "gid", T_GID }, { "px", T_PX }, #ifdef notdef { "any", T_ANY }, /* any is a QTYPE, not TYPE */ #endif #ifdef LOC_RR { "loc", T_LOC }, #endif /* LOC_RR */ #ifdef ALLOW_T_UNSPEC { "unspec", T_UNSPEC }, #endif /* ALLOW_T_UNSPEC */ }; #define M_TYPE_CNT (sizeof(m_type) / sizeof(struct map)) /* * Parser token values */ #define CURRENT 1 #define DOT 2 #define AT 3 #define DNAME 4 #define INCLUDE 5 #define ORIGIN 6 #define ERROR 7 static int clev; /* a zone deeper in a heirachy has more credability */ /* int * 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, def_domain) const char *filename, *in_origin; struct zoneinfo *zp; const char *def_domain; { static int read_soa, read_ns; register char *cp; register struct map *mp; char domain[MAXDNAME]; char origin[MAXDNAME]; char tmporigin[MAXDNAME]; char buf[MAXDATA]; char data[MAXDATA]; const char *cp1, *op; int c, class, type, ttl, dbflags, dataflags, multiline; struct databuf *dp; struct iso_addr *isoa; FILE *fp; 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 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, %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_NOTICE, "%s: %m", filename); dprintf(1, (ddt, "db_load: error opening file %s\n", filename)); return (-1); } 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_NOTICE, "%s: %m", filename); sb.st_mtime = (int)tt.tv_sec; } slineno = lineno; lineno = 1; 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) { switch (c) { case INCLUDE: if (!getword((char *)buf, sizeof(buf), fp)) /* file name*/ break; if (!getword(tmporigin, sizeof(tmporigin), fp)) strcpy(tmporigin, origin); else { makename(tmporigin, origin); endline(fp); } didinclude = 1; errs += db_load((char *)buf, tmporigin, zp, domain); continue; case ORIGIN: (void) strcpy((char *)buf, origin); if (!getword(origin, sizeof(origin), fp)) break; dprintf(3, (ddt, "db_load: origin %s, buf %s\n", origin, buf)); makename(origin, buf); dprintf(3, (ddt, "db_load: origin now %s\n", origin)); continue; case DNAME: if (!getword(domain, sizeof(domain), fp)) break; n = strlen(domain) - 1; if (domain[n] == '.') domain[n] = '\0'; else if (*origin) { (void) strcat(domain, "."); (void) strcat(domain, origin); } goto gotdomain; case AT: (void) strcpy(domain, origin); goto gotdomain; case DOT: domain[0] = '\0'; /* FALLTHROUGH */ case CURRENT: gotdomain: if (!getword((char *)buf, sizeof(buf), fp)) { if (c == CURRENT) continue; break; } cp = buf; ttl = 0; if (isdigit(*cp)) { n = 0; do { if (n > (INT_MAX - (*cp - '0')) / 10) { syslog(LOG_INFO, "%s: line %d: number > %lu\n", filename, lineno, (u_long)INT_MAX); n = INT_MAX; cp++; } else n = n * 10 + (*cp++ - '0'); } while (isdigit(*cp)); if (zp->z_type == Z_CACHE) { /* this allows the cache entry to age */ /* while sitting on disk (powered off) */ if (n > max_cache_ttl) n = max_cache_ttl; n += sb.st_mtime; } ttl = n; if (!getword((char *)buf, sizeof(buf), fp)) break; } for (mp = m_class; mp < m_class+M_CLASS_CNT; mp++) if (!strcasecmp((char *)buf, mp->token)) { class = mp->val; (void) getword((char *)buf, sizeof(buf), fp); break; } for (mp = m_type; mp < m_type+M_TYPE_CNT; mp++) if (!strcasecmp((char *)buf, mp->token)) { type = mp->val; goto fndtype; } dprintf(1, (ddt, "%s: Line %d: Unknown type: %s.\n", filename, lineno, buf)); errs++; syslog(LOG_INFO, "%s: Line %d: Unknown type: %s.\n", filename, lineno, buf); break; fndtype: #ifdef ALLOW_T_UNSPEC /* Don't do anything here for T_UNSPEC... * read input separately later */ if (type != T_UNSPEC) { #endif if (!getword((char *)buf, sizeof(buf), fp)) break; dprintf(3, (ddt, "d='%s', c=%d, t=%d, ttl=%d, data='%s'\n", domain, class, type, ttl, buf)); #ifdef ALLOW_T_UNSPEC } #endif /* * Convert the ascii data 'buf' to the proper format * based on the type and pack into 'data'. */ switch (type) { case T_A: if (!inet_aton(buf, &ina)) goto err; n = ntohl(ina.s_addr); cp = data; PUTLONG(n, cp); n = INT32SZ; break; case T_HINFO: case T_ISDN: n = strlen((char *)buf); if (n > 255) { syslog(LOG_INFO, "%s: line %d: %s too long", filename, lineno, (type == T_ISDN) ? "ISDN-address" : "CPU type"); n = 255; } data[0] = n; bcopy(buf, (char *)data + 1, (int)n); if (n == 0) goto err; n++; if (!getword((char *)buf, sizeof(buf), fp)) i = 0; else { endline(fp); i = strlen((char *)buf); } if (i == 0) { if (type == T_ISDN) { data[n++] = 0; break; } else /* goto err; */ /* XXX tolerate for now */ data[n++] = 1; data[n++] = '?'; syslog(LOG_INFO, "%s: line %d: OS-type missing", filename, empty_token ? (lineno - 1) : lineno); break; } if (i > 255) { syslog(LOG_INFO, "%s:%d: %s too long", filename, lineno, (type == T_ISDN) ? "ISDN-sa" : "OS type"); i = 255; } data[n] = i; bcopy(buf, data + n + 1, i); n += i + 1; break; case T_SOA: case T_MINFO: case T_RP: (void) strcpy((char *)data, (char *)buf); makename(data, origin); cp = data + strlen((char *)data) + 1; if (!getword((char *)cp, (sizeof data) - (cp - data), fp)) goto err; makename(cp, origin); cp += strlen((char *)cp) + 1; if (type != T_SOA) { n = cp - data; break; } if (class != zp->z_class) { 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; } else { multiline = 0; ungetc(c, fp); } #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); #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 #if defined(STUBS) || zp->z_type == Z_STUB #endif ) { 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; } n = (u_int32_t) zp->z_retry; PUTLONG(n, cp); 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, GETNUM_NONE); if (getnum_error) { errs++; zp->z_minimum = 120; } n = (u_int32_t) zp->z_minimum; PUTLONG (n, cp); n = cp - data; if (multiline) { if (getnonblank(fp, filename) != ')') 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; case T_UID: case T_GID: n = 0; cp = buf; while (isdigit(*cp)) n = n * 10 + (*cp++ - '0'); if (cp == buf) goto err; cp = data; PUTLONG(n, cp); n = INT32SZ; break; case T_WKS: /* Address */ if (!inet_aton(buf, &ina)) goto err; n = ntohl(ina.s_addr); cp = data; PUTLONG(n, cp); *cp = (char)getprotocol(fp, filename); /* Protocol */ n = INT32SZ + sizeof(char); /* Services */ n = getservices((int)n, data, fp, filename); break; case T_NS: if (strcasecmp(zp->z_origin, domain) == 0) read_ns++; /* FALLTHROUGH */ case T_CNAME: case T_MB: case T_MG: case T_MR: case T_PTR: (void) strcpy((char *)data, (char *)buf); makename(data, origin); n = strlen((char *)data) + 1; break; case T_UINFO: cp = strchr((char *)buf, '&'); bzero(data, sizeof data); if ( cp != NULL) { (void) strncpy((char *)data, (char *)buf, cp - buf); op = strchr(domain, '.'); if ( op != NULL) (void) strncat((char *)data, domain,op-domain); else (void) strcat((char *)data, domain); (void) strcat((char *)data, (char *)++cp); } else (void) strcpy((char *)data, (char *)buf); n = strlen((char *)data) + 1; break; case T_MX: case T_AFSDB: case T_RT: n = 0; cp = buf; while (isdigit(*cp)) n = n * 10 + (*cp++ - '0'); /* catch bad values */ 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 end of data */ cp += strlen((char *)cp) +1; /* now save length */ n = (cp - data); break; case T_PX: n = 0; data[0] = '\0'; cp = buf; while (isdigit(*cp)) n = n * 10 + (*cp++ - '0'); /* 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: i = strlen((char *)buf); cp = data; cp1 = buf; /* * there is expansion here so make sure we * don't overflow data */ if (i > (sizeof data) * 255 / 256) { syslog(LOG_INFO, "%s: line %d: TXT record truncated", filename, lineno); i = (sizeof data) * 255 / 256; } while (i > 255) { *cp++ = 255; bcopy(cp1, cp, 255); cp += 255; cp1 += 255; i -= 255; } *cp++ = i; bcopy(cp1, cp, i); cp += i; n = cp - data; endline(fp); break; case T_NSAP: isoa = iso_addr(buf); if (!isoa) goto err; n = isoa->isoa_len; bcopy(isoa->isoa_genaddr, data, n); 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: { int rcode; fgets(buf, sizeof(buf), fp); dprintf(1, (ddt, "loading T_UNSPEC\n")); if (rcode = atob(buf, strlen((char*)buf), data, sizeof data, &n)) { if (rcode == CONV_OVERFLOW) { errs++; syslog(LOG_INFO, "Load T_UNSPEC: input buffer overflow"); } else { errs++; syslog(LOG_INFO, "Load T_UNSPEC: Data in bad atob format"); } } } break; #endif /* ALLOW_T_UNSPEC */ 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. */ if (zp->z_type != Z_CACHE && !samedomain(domain, zp->z_origin)) { 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; dp->d_flags = dataflags; dp->d_cred = DB_C_ZONE; dp->d_clev = clev; if ((c = db_update(domain, dp, dp, dbflags, (zp->z_type == Z_CACHE) ? fcachetab : hashtab)) != OK) { #ifdef DEBUG if (debug && (c != DATAEXISTS)) fprintf(ddt, "update failed %s %d\n", domain, type); #endif free((char*) dp); } else { rrcount++; } continue; case ERROR: break; } err: errs++; syslog(LOG_NOTICE, "%s: line %d: database format error (%s)", filename, empty_token ? (lineno - 1) : lineno, buf); if (!empty_token) endline(fp); } (void) my_fclose(fp); lineno = slineno; 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) { const char *msg = NULL; if (read_soa == 0) 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; const char *src; { register int c; char op[32]; for (;;) { c = getc(fp); top: switch (c) { case EOF: return (EOF); case '$': if (getword(op, sizeof(op), fp)) { if (!strcasecmp("include", op)) return (INCLUDE); if (!strcasecmp("origin", op)) return (ORIGIN); } syslog(LOG_NOTICE, "%s: line %d: Unknown $ option: $%s\n", src, lineno, op); return (ERROR); case ';': while ((c = getc(fp)) != EOF && c != '\n') ; goto top; case ' ': case '\t': return (CURRENT); case '.': return (DOT); case '@': return (AT); case '\n': lineno++; continue; default: (void) ungetc(c, fp); return (DNAME); } } } /* int * getword(buf, size, fp) * get next word, skipping blanks & comments. * parameters: * buf - destination * size - of destination * fp - file to read from * return value: * 0 = no word; perhaps EOL or EOF * 1 = word was read */ int getword(buf, size, fp) char *buf; int size; FILE *fp; { register char *cp; register int c; empty_token = 0; for (cp = buf; (c = getc(fp)) != EOF; ) { if (c == ';') { while ((c = getc(fp)) != EOF && c != '\n') ; c = '\n'; } if (c == '\n') { if (cp != buf) ungetc(c, fp); else lineno++; break; } if (isspace(c)) { while (isspace(c = getc(fp)) && c != '\n') ; ungetc(c, fp); if (cp != buf) /* Trailing whitespace */ break; continue; /* Leading whitespace */ } if (c == '"') { while ((c = getc(fp)) != EOF && c != '"' && c != '\n') { if (c == '\\') { if ((c = getc(fp)) == EOF) c = '\\'; if (c == '\n') lineno++; } if (cp >= buf+size-1) break; *cp++ = c; } if (c == '\n') { lineno++; break; } if ((c = getc(fp)) != EOF) ungetc(c, fp); if (c == EOF || isspace(c) || c == '\n') { *cp = '\0'; return (1); } else continue; } if (c == '\\') { if ((c = getc(fp)) == EOF) c = '\\'; if (c == '\n') lineno++; } if (cp >= buf+size-1) break; *cp++ = (char)c; } *cp = '\0'; if (cp == buf) empty_token = 1; return (cp != buf); } /* From: kagotani@cs.titech.ac.jp Message-Id: <9007040716.AA26646@saeko.cs.titech.ac.jp> Subject: named bug report and fix Date: Wed, 04 Jul 90 16:16:52 JST I found a bug in the BIND source code. Named with this bug parses the serial_no field of SOA records incorrectly. For example: expression internal in files expression I expect 1. 1000 10000 1.2 10002 10002 1.23 100023 10023 2.3 20003 20003 Especially I can not accept that "2.3" is treated as if it is smaller than "1.23" in their internal expressions. [ if you define SENSIBLE_DOTS in ../conf/options.h, you get m. kagotani's expected behaviour. this is NOT compatible with pre-4.9 versions of BIND. --vix ] */ int getnum(fp, src, opt) FILE *fp; const char *src; int opt; { register int c, n; int seendigit = 0; int seendecimal = 0; int m = 0; int allow_dots = 0; getnum_error = 0; #ifdef DOTTED_SERIAL if (opt & GETNUM_SERIAL) allow_dots++; #endif for (n = 0; (c = getc(fp)) != EOF; ) { if (isspace(c)) { if (c == '\n') lineno++; if (seendigit) break; continue; } if (c == ';') { while ((c = getc(fp)) != EOF && c != '\n') ; if (c == '\n') lineno++; if (seendigit) 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_NOTICE, "%s:%d: expected a number", src, lineno); getnum_error = 1; } else { if (!seendigit) n = 1; #ifdef SENSIBLE_DOTS n *= 10000; #else n *= 1000; #endif seendigit = 1; seendecimal = 1; } continue; } #ifdef SENSIBLE_DOTS if (seendecimal) m = m * 10 + (c - '0'); else n = n * 10 + (c - '0'); #else n = n * 10 + (c - '0'); #endif seendigit = 1; } if (getnum_error) return (0); if (m > 9999) { syslog(LOG_INFO, "%s:%d: number after the decimal point exceeds 9999", src, lineno); getnum_error = 1; return (0); } if (seendecimal) { syslog(LOG_INFO, "%s:%d: decimal serial number interpreted as %d", src, lineno, n+m); } return (n + m); } static int getnonblank(fp, src) FILE *fp; const char *src; { register int c; while ( (c = getc(fp)) != EOF ) { if (isspace(c)) { if (c == '\n') lineno++; continue; } if (c == ';') { while ((c = getc(fp)) != EOF && c != '\n') ; if (c == '\n') lineno++; continue; } return(c); } syslog(LOG_INFO, "%s: line %d: unexpected EOF", src, lineno); return (EOF); } /* * Take name and fix it according to following rules: * "." means root. * "@" means current origin. * "name." means no changes. * "name" means append origin. */ static void makename(name, origin) char *name; const char *origin; { int n; if (origin[0] == '.') origin++; n = strlen(name); if (n == 1) { if (name[0] == '.') { name[0] = '\0'; return; } if (name[0] == '@') { (void) strcpy(name, origin); return; } } if (n > 0) { if (name[n - 1] == '.') name[n - 1] = '\0'; else if (origin[0] != '\0') { name[n] = '.'; (void) strcpy(name + n + 1, origin); } } } void endline(fp) register FILE *fp; { register int c; while ((c = getc(fp)) != '\0') { if (c == '\n') { (void) ungetc(c,fp); break; } else if (c == EOF) { break; } } } #define MAXPORT 1024 #define MAXLEN 24 static int getprotocol(fp, src) FILE *fp; const char *src; { int k; char b[MAXLEN]; (void) getword(b, sizeof(b), fp); k = protocolnumber(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; FILE *fp; const char *src; { int j, ch; int k; int maxl; int bracket; char b[MAXLEN]; char bm[MAXPORT/8]; for (j = 0; j < MAXPORT/8; j++) bm[j] = 0; maxl = 0; bracket = 0; while (getword(b, sizeof(b), fp) || bracket) { if (feof(fp) || ferror(fp)) break; if (strlen(b) == 0) continue; if ( b[0] == '(') { bracket++; continue; } if ( b[0] == ')') { bracket = 0; while ((ch = getc(fp)) != EOF && ch != '\n') ; if (ch == '\n') lineno++; break; } k = servicenumber(b); if (k == -1) { syslog(LOG_INFO, "%s: line %d: Unknown service '%s'", src, lineno, b); continue; } if ((k < MAXPORT) && (k)) { bm[k/8] |= (0x80>>(k%8)); if (k > maxl) maxl=k; } else { 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_INFO, "%s: line %d: missing close paren\n", src, lineno); maxl = maxl/8+1; bcopy(bm, data+n, maxl); return (maxl+n); } /* get_netlist(fp, netlistp, allow) * get list of nets from 'fp', put on *netlistp, 'allow' controls * whether hosts, nets, or both shall be accepted without warnings. * (note that they are always accepted; 'allow' just controls the * warnings.) */ void get_netlist(fp, netlistp, allow, print_tag) FILE *fp; struct netinfo **netlistp; int allow; char *print_tag; { 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) break; if ((maskp = strchr(buf, '&')) != NULL) *maskp++ = '\0'; dprintf(1, (ddt," %s", buf)); if (ntp == NULL) { ntp = (struct netinfo *)malloc(sizeof(struct netinfo)); } if (!inet_aton(buf, &ntp->my_addr)) { syslog(LOG_INFO, "%s contains bogus element (%s)", print_tag, buf); continue; } if (maskp) { if (!inet_aton(maskp, &ina)) { syslog(LOG_INFO, "%s element %s has bad mask (%s)", print_tag, buf, maskp); continue; } } else { if (allow & ALLOW_HOSTS) ina.s_addr = 0xffffffff; /* "exact" */ else ina.s_addr = net_mask(ntp->my_addr); } ntp->next = NULL; ntp->mask = ina.s_addr; ntp->addr = ntp->my_addr.s_addr & ntp->mask; /* Check for duplicates */ if (addr_on_netlist(ntp->my_addr, *netlistp)) continue; if (ntp->addr != ntp->my_addr.s_addr) { ina.s_addr = ntp->addr; syslog(LOG_INFO, "%s element (%s) mask problem (%s)", print_tag, buf, inet_ntoa(ina)); } *end = ntp; end = &ntp->next; ntp = NULL; } if (ntp) free((char *)ntp); dprintf(1, (ddt, "\n")); #ifdef DEBUG if (debug > 2) for (ntp = *netlistp; ntp != NULL; ntp = ntp->next) { 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%lx\n", (u_long)ntp->next); } #endif } struct netinfo * addr_on_netlist(addr, netlist) struct in_addr addr; struct netinfo *netlist; { u_int32_t a = addr.s_addr; struct netinfo *t; for (t = netlist; t != NULL; t = t->next) if (t->addr == (a & t->mask)) return t; return NULL; } int position_on_netlist(addr, netlist) struct in_addr addr; struct netinfo *netlist; { u_int32_t a = addr.s_addr; struct netinfo *t; int position = 0; for (t = netlist; t != NULL; t = t->next) if (t->addr == (a & t->mask)) break; else position++; return position; } void free_netlist(netlistp) struct netinfo **netlistp; { register struct netinfo *ntp, *next; for (ntp = *netlistp; ntp != NULL; ntp = next) { next = ntp->next; free((char *)ntp); } *netlistp = NULL; }