/***************************************************************** ** ** @(#) 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 # include # include # include /* for link(), unlink() */ # include # include #if 0 # include # include # include # include # include # include #endif #ifdef HAVE_CONFIG_H # include #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