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