1 /* $NetBSD: zfparse.c,v 1.1.1.1 2015/07/08 15:37:48 christos Exp $ */ 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 #ifdef HAVE_CONFIG_H 46 # include <config.h> 47 #endif 48 # include "config_zkt.h" 49 # include "zconf.h" 50 # include "misc.h" 51 # include "log.h" 52 # include "debug.h" 53 #define extern 54 # include "zfparse.h" 55 #undef extern 56 57 58 extern const char *progname; 59 60 /***************************************************************** 61 ** is_multiline_rr (const char *s) 62 *****************************************************************/ 63 static const char *is_multiline_rr (int *multi_line_rr, const char *p) 64 { 65 while ( *p && *p != ';' ) 66 { 67 if ( *p == '\"' ) 68 do 69 p++; 70 while ( *p && *p != '\"' ); 71 72 if ( *p == '(' ) 73 *multi_line_rr = 1; 74 if ( *p == ')' ) 75 *multi_line_rr = 0; 76 p++; 77 } 78 return p; 79 } 80 81 /***************************************************************** 82 ** skipws (const char *s) 83 *****************************************************************/ 84 static const char *skipws (const char *s) 85 { 86 while ( *s && (*s == ' ' || *s == '\t' || *s == '\n') ) 87 s++; 88 return s; 89 } 90 91 /***************************************************************** 92 ** skiplabel (const char *s) 93 *****************************************************************/ 94 static const char *skiplabel (const char *s) 95 { 96 while ( *s && *s != ';' && *s != ' ' && *s != '\t' && *s != '\n' ) 97 s++; 98 return s; 99 } 100 101 /***************************************************************** 102 ** setminmax () 103 *****************************************************************/ 104 static void setminmax (long *pmin, long val, long *pmax) 105 { 106 if ( val < *pmin ) 107 *pmin = val; 108 if ( val > *pmax ) 109 *pmax = val; 110 } 111 112 /***************************************************************** 113 ** get_ttl () 114 *****************************************************************/ 115 static long get_ttl (const char *s) 116 { 117 char quantity; 118 long lval; 119 120 quantity = 'd'; 121 sscanf (s, "%ld%c", &lval, &quantity); 122 quantity = tolower (quantity); 123 if ( quantity == 'm' ) 124 lval *= MINSEC; 125 else if ( quantity == 'h' ) 126 lval *= HOURSEC; 127 else if ( quantity == 'd' ) 128 lval *= DAYSEC; 129 else if ( quantity == 'w' ) 130 lval *= WEEKSEC; 131 else if ( quantity == 'y' ) 132 lval *= YEARSEC; 133 134 return lval; 135 } 136 137 /***************************************************************** 138 ** addkeydb () 139 *****************************************************************/ 140 int addkeydb (const char *file, const char *keydbfile) 141 { 142 FILE *fp; 143 144 if ( (fp = fopen (file, "a")) == NULL ) 145 return -1; 146 147 fprintf (fp, "\n"); 148 fprintf (fp, "$INCLUDE %s\t; this is the database of public DNSKEY RR\n", keydbfile); 149 150 fclose (fp); 151 152 return 0; 153 } 154 155 /***************************************************************** 156 ** parsezonefile () 157 ** parse the BIND zone file 'file' and store the minimum and 158 ** maximum ttl value in the corresponding parameter. 159 ** if keydbfile is set, check if this file is already include. 160 ** if inclfiles is not NULL store a list of included files names 161 ** in it. 162 ** return 0 if keydbfile is not included 163 ** return 1 if keydbfile is included 164 ** return -1 on error 165 *****************************************************************/ 166 int parsezonefile (const char *file, long *pminttl, long *pmaxttl, const char *keydbfile, char *inclfiles, size_t *plen) 167 { 168 FILE *infp; 169 int len; 170 int lnr; 171 long ttl; 172 int multi_line_rr; 173 int keydbfilefound; 174 char buf[1024]; 175 const char *p; 176 177 assert (file != NULL); 178 assert (pminttl != NULL); 179 assert (pmaxttl != NULL); 180 181 dbg_val4 ("parsezonefile (\"%s\", %ld, %ld, \"%s\")\n", file, *pminttl, *pmaxttl, keydbfile); 182 183 if ( (infp = fopen (file, "r")) == NULL ) 184 { 185 error ("parsezonefile: couldn't open file \"%s\" for input\n", file); 186 return -1; 187 } 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 ( strcmp (fname, keydbfile) == 0 ) 221 keydbfilefound = 1; 222 else 223 { 224 if ( inclfiles && plen ) 225 { 226 len = snprintf (inclfiles, *plen, ",%s", fname); 227 if ( *plen <= len ) /* no space left in include file string */ 228 return keydbfilefound; 229 inclfiles += len; 230 *plen -= len; 231 } 232 int ret = parsezonefile (fname, pminttl, pmaxttl, keydbfile, inclfiles, plen); 233 if ( ret ) /* keydb found or read error ? */ 234 keydbfilefound = ret; 235 } 236 } 237 } 238 else if ( !isspace (*p) ) /* label ? */ 239 p = skiplabel (p); 240 241 p = skipws (p); 242 if ( *p == ';' ) /* skip line if it's a comment line */ 243 continue; 244 245 /* skip class (hesiod is not supported now) */ 246 if ( (toupper (*p) == 'I' && toupper (p[1]) == 'N') || 247 (toupper (*p) == 'C' && toupper (p[1]) == 'H') ) 248 p += 2; 249 p = skipws (p); 250 251 if ( isdigit (*p) ) /* ttl ? */ 252 { 253 ttl = get_ttl (p); 254 dbg_val3 ("%s:%d:ttl %ld\n", file, lnr, ttl); 255 setminmax (pminttl, ttl, pmaxttl); 256 } 257 258 /* check the rest of the line if it's the beginning of a multi_line_rr */ 259 is_multiline_rr (&multi_line_rr, p); 260 } 261 262 if ( file ) 263 fclose (infp); 264 265 dbg_val5 ("parsezonefile (\"%s\", %ld, %ld, \"%s\") ==> %d\n", 266 file, *pminttl, *pmaxttl, keydbfile, keydbfilefound); 267 return keydbfilefound; 268 } 269 270 271 #ifdef TEST 272 const char *progname; 273 int main (int argc, char *argv[]) 274 { 275 long minttl; 276 long maxttl; 277 int keydbfound; 278 char *dnskeydb; 279 280 progname = *argv; 281 dnskeydb = NULL; 282 dnskeydb = "dnskey.db"; 283 284 minttl = 0x7FFFFFFF; 285 maxttl = 0; 286 keydbfound = parsezonefile (argv[1], &minttl, &maxttl, dnskeydb); 287 if ( keydbfound < 0 ) 288 error ("can't parse zone file %s\n", argv[1]); 289 290 if ( dnskeydb && !keydbfound ) 291 { 292 printf ("$INCLUDE %s directive added \n", dnskeydb); 293 addkeydb (argv[1], dnskeydb); 294 } 295 296 printf ("minttl = %ld\n", minttl); 297 printf ("maxttl = %ld\n", maxttl); 298 299 return 0; 300 } 301 #endif 302