--- /dev/null
+/*****************************************************************
+**
+** @(#) zfparse.c -- A zone file parser
+**
+** Copyright (c) Jan 2010 - Jan 2010, Holger Zuleger HZnet. All rights reserved.
+**
+** This software is open source.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** 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.
+**
+** Neither the name of Holger Zuleger HZnet 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 COPYRIGHT HOLDERS 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.
+**
+*****************************************************************/
+# include <stdio.h>
+# include <string.h>
+# include <stdlib.h>
+# include <unistd.h> /* for link(), unlink() */
+# include <ctype.h>
+# include <assert.h>
+#if 0
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <time.h>
+# include <utime.h>
+# include <errno.h>
+# include <fcntl.h>
+#endif
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+# include "config_zkt.h"
+# include "zconf.h"
+# include "log.h"
+# include "debug.h"
+#define extern
+# include "zfparse.h"
+#undef extern
+
+
+extern const char *progname;
+
+/*****************************************************************
+** is_multiline_rr (const char *s)
+*****************************************************************/
+static const char *is_multiline_rr (int *multi_line_rr, const char *p)
+{
+ while ( *p && *p != ';' )
+ {
+ if ( *p == '\"' )
+ do
+ p++;
+ while ( *p && *p != '\"' );
+
+ if ( *p == '(' )
+ *multi_line_rr = 1;
+ if ( *p == ')' )
+ *multi_line_rr = 0;
+ p++;
+ }
+ return p;
+}
+
+/*****************************************************************
+** skipws (const char *s)
+*****************************************************************/
+static const char *skipws (const char *s)
+{
+ while ( *s && (*s == ' ' || *s == '\t' || *s == '\n') )
+ s++;
+ return s;
+}
+
+/*****************************************************************
+** skiplabel (const char *s)
+*****************************************************************/
+static const char *skiplabel (const char *s)
+{
+ while ( *s && *s != ';' && *s != ' ' && *s != '\t' && *s != '\n' )
+ s++;
+ return s;
+}
+
+/*****************************************************************
+** setminmax ()
+*****************************************************************/
+static void setminmax (long *pmin, long val, long *pmax)
+{
+ if ( val < *pmin )
+ *pmin = val;
+ if ( val > *pmax )
+ *pmax = val;
+}
+
+/*****************************************************************
+** get_ttl ()
+*****************************************************************/
+static long get_ttl (const char *s)
+{
+ char quantity;
+ long lval;
+
+ quantity = 'd';
+ sscanf (s, "%ld%c", &lval, &quantity);
+ quantity = tolower (quantity);
+ if ( quantity == 'm' )
+ lval *= MINSEC;
+ else if ( quantity == 'h' )
+ lval *= HOURSEC;
+ else if ( quantity == 'd' )
+ lval *= DAYSEC;
+ else if ( quantity == 'w' )
+ lval *= WEEKSEC;
+ else if ( quantity == 'y' )
+ lval *= YEARSEC;
+
+ return lval;
+}
+
+/*****************************************************************
+** addkeydb ()
+*****************************************************************/
+int addkeydb (const char *file, const char *keydbfile)
+{
+ FILE *fp;
+
+ if ( (fp = fopen (file, "a")) == NULL )
+ return -1;
+
+ fprintf (fp, "\n");
+ fprintf (fp, "$INCLUDE %s\t; this is the database of public DNSKEY RR\n", keydbfile);
+
+ fclose (fp);
+
+ return 0;
+}
+
+/*****************************************************************
+** parsezonefile ()
+** parse the BIND zone file 'file' and store the minimum and
+** maximum ttl value in the corresponding parameter.
+** if keydbfile is set, check if this file is already include.
+** return 0 if keydbfile is not included
+** return 1 if keydbfile is included
+** return -1 on error
+*****************************************************************/
+int parsezonefile (const char *file, long *pminttl, long *pmaxttl, const char *keydbfile)
+{
+ FILE *infp;
+ int len;
+ int lnr;
+ long ttl;
+ int multi_line_rr;
+ int keydbfilefound;
+ char buf[1024];
+ const char *p;
+
+ assert (file != NULL);
+ assert (pminttl != NULL);
+ assert (pmaxttl != NULL);
+
+ dbg_val4 ("parsezonefile (\"%s\", %ld, %ld, \"%s\")\n", file, *pminttl, *pmaxttl, keydbfile);
+
+ if ( (infp = fopen (file, "r")) == NULL )
+ return -1;
+
+ lnr = 0;
+ keydbfilefound = 0;
+ multi_line_rr = 0;
+ while ( fgets (buf, sizeof buf, infp) != NULL )
+ {
+ len = strlen (buf);
+ if ( buf[len-1] != '\n' ) /* line too long ? */
+ fprintf (stderr, "line too long\n");
+ lnr++;
+
+ p = buf;
+ if ( multi_line_rr ) /* skip line if it's part of a multiline rr */
+ {
+ is_multiline_rr (&multi_line_rr, p);
+ continue;
+ }
+
+ if ( *p == '$' ) /* special directive ? */
+ {
+ if ( strncmp (p+1, "TTL", 3) == 0 ) /* $TTL ? */
+ {
+ ttl = get_ttl (p+4);
+ dbg_val3 ("%s:%d:ttl %ld\n", file, lnr, ttl);
+ setminmax (pminttl, ttl, pmaxttl);
+ }
+ else if ( strncmp (p+1, "INCLUDE", 7) == 0 ) /* $INCLUDE ? */
+ {
+ char fname[30+1];
+
+ sscanf (p+9, "%30s", fname);
+ dbg_val ("$INCLUDE directive for file \"%s\" found\n", fname);
+ if ( keydbfile && strcmp (fname, keydbfile) == 0 )
+ keydbfilefound = 1;
+ else
+ keydbfilefound = parsezonefile (fname, pminttl, pmaxttl, keydbfile);
+ }
+ }
+ else if ( !isspace (*p) ) /* label ? */
+ p = skiplabel (p);
+
+ p = skipws (p);
+ if ( *p == ';' ) /* skip line if it's a comment line */
+ continue;
+
+ /* skip class (hesiod is not supported now) */
+ if ( (toupper (*p) == 'I' && toupper (p[1]) == 'N') ||
+ (toupper (*p) == 'C' && toupper (p[1]) == 'H') )
+ p += 2;
+ p = skipws (p);
+
+ if ( isdigit (*p) ) /* ttl ? */
+ {
+ ttl = get_ttl (p);
+ dbg_val3 ("%s:%d:ttl %ld\n", file, lnr, ttl);
+ setminmax (pminttl, ttl, pmaxttl);
+ }
+
+ /* check the rest of the line if it's the beginning of a multi_line_rr */
+ is_multiline_rr (&multi_line_rr, p);
+ }
+
+ if ( file )
+ fclose (infp);
+
+ dbg_val5 ("parsezonefile (\"%s\", %ld, %ld, \"%s\") ==> %d\n",
+ file, *pminttl, *pmaxttl, keydbfile, keydbfilefound);
+ return keydbfilefound;
+}
+
+
+#ifdef TEST
+const char *progname;
+int main (int argc, char *argv[])
+{
+ long minttl;
+ long maxttl;
+ int keydbfound;
+ char *dnskeydb;
+
+ progname = *argv;
+ dnskeydb = NULL;
+ dnskeydb = "dnskey.db";
+
+ minttl = 0x7FFFFFFF;
+ maxttl = 0;
+ keydbfound = parsezonefile (argv[1], &minttl, &maxttl, dnskeydb);
+ if ( keydbfound < 0 )
+ error ("can't parse zone file %s\n", argv[1]);
+
+ if ( dnskeydb && !keydbfound )
+ {
+ printf ("$INCLUDE %s directive added \n", dnskeydb);
+ addkeydb (argv[1], dnskeydb);
+ }
+
+ printf ("minttl = %ld\n", minttl);
+ printf ("maxttl = %ld\n", maxttl);
+
+ return 0;
+}
+#endif