1/***************************************************************** 2** 3** @(#) zfparse.c -- A zone file parser 4** 5** Copyright (c) Jan 2010 - Jan 2010, Holger Zuleger HZnet. All rights reserved. 6** 7** This software is open source. 8** 9** Redistribution and use in source and binary forms, with or without 10** modification, are permitted provided that the following conditions 11** are met: 12** 13** Redistributions of source code must retain the above copyright notice, 14** this list of conditions and the following disclaimer. 15** 16** Redistributions in binary form must reproduce the above copyright notice, 17** this list of conditions and the following disclaimer in the documentation 18** and/or other materials provided with the distribution. 19** 20** Neither the name of Holger Zuleger HZnet nor the names of its contributors may 21** be used to endorse or promote products derived from this software without 22** specific prior written permission. 23** 24** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 28** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34** POSSIBILITY OF SUCH DAMAGE. 35** 36*****************************************************************/ 37# include <stdio.h> 38# include <string.h> 39# include <stdlib.h> 40# include <unistd.h> /* for link(), unlink() */ 41# include <ctype.h> 42# include <assert.h> 43#if 0 44# include <sys/types.h> 45# include <sys/stat.h> 46# include <time.h> 47# include <utime.h> 48# include <errno.h> 49# include <fcntl.h> 50#endif 51#ifdef HAVE_CONFIG_H 52# include <config.h> 53#endif 54# include "config_zkt.h" 55# include "zconf.h" 56# include "log.h" 57# include "debug.h" 58#define extern 59# include "zfparse.h" 60#undef extern 61 62 63extern const char *progname; 64 65/***************************************************************** 66** is_multiline_rr (const char *s) 67*****************************************************************/ 68static const char *is_multiline_rr (int *multi_line_rr, const char *p) 69{ 70 while ( *p && *p != ';' ) 71 { 72 if ( *p == '\"' ) 73 do 74 p++; 75 while ( *p && *p != '\"' ); 76 77 if ( *p == '(' ) 78 *multi_line_rr = 1; 79 if ( *p == ')' ) 80 *multi_line_rr = 0; 81 p++; 82 } 83 return p; 84} 85 86/***************************************************************** 87** skipws (const char *s) 88*****************************************************************/ 89static const char *skipws (const char *s) 90{ 91 while ( *s && (*s == ' ' || *s == '\t' || *s == '\n') ) 92 s++; 93 return s; 94} 95 96/***************************************************************** 97** skiplabel (const char *s) 98*****************************************************************/ 99static const char *skiplabel (const char *s) 100{ 101 while ( *s && *s != ';' && *s != ' ' && *s != '\t' && *s != '\n' ) 102 s++; 103 return s; 104} 105 106/***************************************************************** 107** setminmax () 108*****************************************************************/ 109static void setminmax (long *pmin, long val, long *pmax) 110{ 111 if ( val < *pmin ) 112 *pmin = val; 113 if ( val > *pmax ) 114 *pmax = val; 115} 116 117/***************************************************************** 118** get_ttl () 119*****************************************************************/ 120static long get_ttl (const char *s) 121{ 122 char quantity; 123 long lval; 124 125 quantity = 'd'; 126 sscanf (s, "%ld%c", &lval, &quantity); 127 quantity = tolower (quantity); 128 if ( quantity == 'm' ) 129 lval *= MINSEC; 130 else if ( quantity == 'h' ) 131 lval *= HOURSEC; 132 else if ( quantity == 'd' ) 133 lval *= DAYSEC; 134 else if ( quantity == 'w' ) 135 lval *= WEEKSEC; 136 else if ( quantity == 'y' ) 137 lval *= YEARSEC; 138 139 return lval; 140} 141 142/***************************************************************** 143** addkeydb () 144*****************************************************************/ 145int addkeydb (const char *file, const char *keydbfile) 146{ 147 FILE *fp; 148 149 if ( (fp = fopen (file, "a")) == NULL ) 150 return -1; 151 152 fprintf (fp, "\n"); 153 fprintf (fp, "$INCLUDE %s\t; this is the database of public DNSKEY RR\n", keydbfile); 154 155 fclose (fp); 156 157 return 0; 158} 159 160/***************************************************************** 161** parsezonefile () 162** parse the BIND zone file 'file' and store the minimum and 163** maximum ttl value in the corresponding parameter. 164** if keydbfile is set, check if this file is already include. 165** return 0 if keydbfile is not included 166** return 1 if keydbfile is included 167** return -1 on error 168*****************************************************************/ 169int parsezonefile (const char *file, long *pminttl, long *pmaxttl, const char *keydbfile) 170{ 171 FILE *infp; 172 int len; 173 int lnr; 174 long ttl; 175 int multi_line_rr; 176 int keydbfilefound; 177 char buf[1024]; 178 const char *p; 179 180 assert (file != NULL); 181 assert (pminttl != NULL); 182 assert (pmaxttl != NULL); 183 184 dbg_val4 ("parsezonefile (\"%s\", %ld, %ld, \"%s\")\n", file, *pminttl, *pmaxttl, keydbfile); 185 186 if ( (infp = fopen (file, "r")) == NULL ) 187 return -1; 188 189 lnr = 0; 190 keydbfilefound = 0; 191 multi_line_rr = 0; 192 while ( fgets (buf, sizeof buf, infp) != NULL ) 193 { 194 len = strlen (buf); 195 if ( buf[len-1] != '\n' ) /* line too long ? */ 196 fprintf (stderr, "line too long\n"); 197 lnr++; 198 199 p = buf; 200 if ( multi_line_rr ) /* skip line if it's part of a multiline rr */ 201 { 202 is_multiline_rr (&multi_line_rr, p); 203 continue; 204 } 205 206 if ( *p == '$' ) /* special directive ? */ 207 { 208 if ( strncmp (p+1, "TTL", 3) == 0 ) /* $TTL ? */ 209 { 210 ttl = get_ttl (p+4); 211 dbg_val3 ("%s:%d:ttl %ld\n", file, lnr, ttl); 212 setminmax (pminttl, ttl, pmaxttl); 213 } 214 else if ( strncmp (p+1, "INCLUDE", 7) == 0 ) /* $INCLUDE ? */ 215 { 216 char fname[30+1]; 217 218 sscanf (p+9, "%30s", fname); 219 dbg_val ("$INCLUDE directive for file \"%s\" found\n", fname); 220 if ( keydbfile && strcmp (fname, keydbfile) == 0 ) 221 keydbfilefound = 1; 222 else 223 keydbfilefound = parsezonefile (fname, pminttl, pmaxttl, keydbfile); 224 } 225 } 226 else if ( !isspace (*p) ) /* label ? */ 227 p = skiplabel (p); 228 229 p = skipws (p); 230 if ( *p == ';' ) /* skip line if it's a comment line */ 231 continue; 232 233 /* skip class (hesiod is not supported now) */ 234 if ( (toupper (*p) == 'I' && toupper (p[1]) == 'N') || 235 (toupper (*p) == 'C' && toupper (p[1]) == 'H') ) 236 p += 2; 237 p = skipws (p); 238 239 if ( isdigit (*p) ) /* ttl ? */ 240 { 241 ttl = get_ttl (p); 242 dbg_val3 ("%s:%d:ttl %ld\n", file, lnr, ttl); 243 setminmax (pminttl, ttl, pmaxttl); 244 } 245 246 /* check the rest of the line if it's the beginning of a multi_line_rr */ 247 is_multiline_rr (&multi_line_rr, p); 248 } 249 250 if ( file ) 251 fclose (infp); 252 253 dbg_val5 ("parsezonefile (\"%s\", %ld, %ld, \"%s\") ==> %d\n", 254 file, *pminttl, *pmaxttl, keydbfile, keydbfilefound); 255 return keydbfilefound; 256} 257 258 259#ifdef TEST 260const char *progname; 261int main (int argc, char *argv[]) 262{ 263 long minttl; 264 long maxttl; 265 int keydbfound; 266 char *dnskeydb; 267 268 progname = *argv; 269 dnskeydb = NULL; 270 dnskeydb = "dnskey.db"; 271 272 minttl = 0x7FFFFFFF; 273 maxttl = 0; 274 keydbfound = parsezonefile (argv[1], &minttl, &maxttl, dnskeydb); 275 if ( keydbfound < 0 ) 276 error ("can't parse zone file %s\n", argv[1]); 277 278 if ( dnskeydb && !keydbfound ) 279 { 280 printf ("$INCLUDE %s directive added \n", dnskeydb); 281 addkeydb (argv[1], dnskeydb); 282 } 283 284 printf ("minttl = %ld\n", minttl); 285 printf ("maxttl = %ld\n", maxttl); 286 287 return 0; 288} 289#endif 290