302 lines
8.1 KiB
C
302 lines
8.1 KiB
C
/* $NetBSD: zfparse.c,v 1.1.1.1 2015/07/08 15:37:48 christos Exp $ */
|
|
|
|
/*****************************************************************
|
|
**
|
|
** @(#) 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>
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
# include "config_zkt.h"
|
|
# include "zconf.h"
|
|
# include "misc.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.
|
|
** if inclfiles is not NULL store a list of included files names
|
|
** in it.
|
|
** 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, char *inclfiles, size_t *plen)
|
|
{
|
|
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 )
|
|
{
|
|
error ("parsezonefile: couldn't open file \"%s\" for input\n", file);
|
|
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 ( strcmp (fname, keydbfile) == 0 )
|
|
keydbfilefound = 1;
|
|
else
|
|
{
|
|
if ( inclfiles && plen )
|
|
{
|
|
len = snprintf (inclfiles, *plen, ",%s", fname);
|
|
if ( *plen <= len ) /* no space left in include file string */
|
|
return keydbfilefound;
|
|
inclfiles += len;
|
|
*plen -= len;
|
|
}
|
|
int ret = parsezonefile (fname, pminttl, pmaxttl, keydbfile, inclfiles, plen);
|
|
if ( ret ) /* keydb found or read error ? */
|
|
keydbfilefound = ret;
|
|
}
|
|
}
|
|
}
|
|
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
|