1 /* 2 * configparser.y -- yacc grammar for NSD configuration files 3 * 4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. 5 * 6 * See LICENSE for the license. 7 * 8 */ 9 10 %{ 11 #include <config.h> 12 13 #include <stdarg.h> 14 #include <stdio.h> 15 #include <string.h> 16 #include <stdlib.h> 17 #include <assert.h> 18 19 #include "options.h" 20 #include "util.h" 21 #include "configyyrename.h" 22 int c_lex(void); 23 void c_error(const char *message); 24 25 #ifdef __cplusplus 26 extern "C" 27 #endif /* __cplusplus */ 28 29 /* these need to be global, otherwise they cannot be used inside yacc */ 30 extern config_parser_state_t* cfg_parser; 31 static int server_settings_seen = 0; 32 33 #if 0 34 #define OUTYY(s) printf s /* used ONLY when debugging */ 35 #else 36 #define OUTYY(s) 37 #endif 38 39 %} 40 %union { 41 char* str; 42 } 43 44 %token SPACE LETTER NEWLINE COMMENT COLON ANY ZONESTR 45 %token <str> STRING 46 %token VAR_SERVER VAR_NAME VAR_IP_ADDRESS VAR_DEBUG_MODE 47 %token VAR_IP4_ONLY VAR_IP6_ONLY VAR_DATABASE VAR_IDENTITY VAR_NSID VAR_LOGFILE 48 %token VAR_SERVER_COUNT VAR_TCP_COUNT VAR_PIDFILE VAR_PORT VAR_STATISTICS 49 %token VAR_CHROOT VAR_USERNAME VAR_ZONESDIR VAR_XFRDFILE VAR_DIFFFILE 50 %token VAR_XFRD_RELOAD_TIMEOUT VAR_TCP_QUERY_COUNT VAR_TCP_TIMEOUT 51 %token VAR_IPV4_EDNS_SIZE VAR_IPV6_EDNS_SIZE 52 %token VAR_ZONEFILE 53 %token VAR_ZONE 54 %token VAR_ALLOW_NOTIFY VAR_REQUEST_XFR VAR_NOTIFY VAR_PROVIDE_XFR 55 %token VAR_NOTIFY_RETRY VAR_OUTGOING_INTERFACE VAR_ALLOW_AXFR_FALLBACK 56 %token VAR_KEY 57 %token VAR_ALGORITHM VAR_SECRET 58 %token VAR_AXFR VAR_UDP 59 %token VAR_VERBOSITY VAR_HIDE_VERSION 60 61 %% 62 toplevelvars: /* empty */ | toplevelvars toplevelvar ; 63 toplevelvar: serverstart contents_server | zonestart contents_zone | 64 keystart contents_key; 65 66 /* server: declaration */ 67 serverstart: VAR_SERVER 68 { OUTYY(("\nP(server:)\n")); 69 if(server_settings_seen) { 70 yyerror("duplicate server: element."); 71 } 72 server_settings_seen = 1; 73 } 74 ; 75 contents_server: contents_server content_server | ; 76 content_server: server_ip_address | server_debug_mode | server_ip4_only | 77 server_ip6_only | server_database | server_identity | server_nsid | server_logfile | 78 server_server_count | server_tcp_count | server_pidfile | server_port | 79 server_statistics | server_chroot | server_username | server_zonesdir | 80 server_difffile | server_xfrdfile | server_xfrd_reload_timeout | 81 server_tcp_query_count | server_tcp_timeout | server_ipv4_edns_size | 82 server_ipv6_edns_size | server_verbosity | server_hide_version; 83 server_ip_address: VAR_IP_ADDRESS STRING 84 { 85 OUTYY(("P(server_ip_address:%s)\n", $2)); 86 if(cfg_parser->current_ip_address_option) { 87 cfg_parser->current_ip_address_option->next = 88 (ip_address_option_t*)region_alloc( 89 cfg_parser->opt->region, sizeof(ip_address_option_t)); 90 cfg_parser->current_ip_address_option = 91 cfg_parser->current_ip_address_option->next; 92 cfg_parser->current_ip_address_option->next=0; 93 } else { 94 cfg_parser->current_ip_address_option = 95 (ip_address_option_t*)region_alloc( 96 cfg_parser->opt->region, sizeof(ip_address_option_t)); 97 cfg_parser->current_ip_address_option->next=0; 98 cfg_parser->opt->ip_addresses = cfg_parser->current_ip_address_option; 99 } 100 101 cfg_parser->current_ip_address_option->address = 102 region_strdup(cfg_parser->opt->region, $2); 103 } 104 ; 105 server_debug_mode: VAR_DEBUG_MODE STRING 106 { 107 OUTYY(("P(server_debug_mode:%s)\n", $2)); 108 if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) 109 yyerror("expected yes or no."); 110 else cfg_parser->opt->debug_mode = (strcmp($2, "yes")==0); 111 } 112 ; 113 server_verbosity: VAR_VERBOSITY STRING 114 { 115 OUTYY(("P(server_verbosity:%s)\n", $2)); 116 if(atoi($2) == 0 && strcmp($2, "0") != 0) 117 yyerror("number expected"); 118 else cfg_parser->opt->verbosity = atoi($2); 119 } 120 ; 121 server_hide_version: VAR_HIDE_VERSION STRING 122 { 123 OUTYY(("P(server_hide_version:%s)\n", $2)); 124 if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) 125 yyerror("expected yes or no."); 126 else cfg_parser->opt->hide_version = (strcmp($2, "yes")==0); 127 } 128 ; 129 server_ip4_only: VAR_IP4_ONLY STRING 130 { 131 OUTYY(("P(server_ip4_only:%s)\n", $2)); 132 if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) 133 yyerror("expected yes or no."); 134 else cfg_parser->opt->ip4_only = (strcmp($2, "yes")==0); 135 } 136 ; 137 server_ip6_only: VAR_IP6_ONLY STRING 138 { 139 OUTYY(("P(server_ip6_only:%s)\n", $2)); 140 if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) 141 yyerror("expected yes or no."); 142 else cfg_parser->opt->ip6_only = (strcmp($2, "yes")==0); 143 } 144 ; 145 server_database: VAR_DATABASE STRING 146 { 147 OUTYY(("P(server_database:%s)\n", $2)); 148 cfg_parser->opt->database = region_strdup(cfg_parser->opt->region, $2); 149 } 150 ; 151 server_identity: VAR_IDENTITY STRING 152 { 153 OUTYY(("P(server_identity:%s)\n", $2)); 154 cfg_parser->opt->identity = region_strdup(cfg_parser->opt->region, $2); 155 } 156 ; 157 server_nsid: VAR_NSID STRING 158 { 159 unsigned char* nsid = 0; 160 uint16_t nsid_len = 0; 161 162 OUTYY(("P(server_nsid:%s)\n", $2)); 163 164 if (strlen($2) % 2 != 0) { 165 yyerror("the NSID must be a hex string of an even length."); 166 } else { 167 nsid_len = strlen($2) / 2; 168 nsid = xalloc(nsid_len); 169 if (hex_pton($2, nsid, nsid_len) == -1) 170 yyerror("hex string cannot be parsed in NSID."); 171 else 172 cfg_parser->opt->nsid = region_strdup(cfg_parser->opt->region, $2); 173 free(nsid); 174 } 175 } 176 ; 177 server_logfile: VAR_LOGFILE STRING 178 { 179 OUTYY(("P(server_logfile:%s)\n", $2)); 180 cfg_parser->opt->logfile = region_strdup(cfg_parser->opt->region, $2); 181 } 182 ; 183 server_server_count: VAR_SERVER_COUNT STRING 184 { 185 OUTYY(("P(server_server_count:%s)\n", $2)); 186 if(atoi($2) <= 0) 187 yyerror("number greater than zero expected"); 188 else cfg_parser->opt->server_count = atoi($2); 189 } 190 ; 191 server_tcp_count: VAR_TCP_COUNT STRING 192 { 193 OUTYY(("P(server_tcp_count:%s)\n", $2)); 194 if(atoi($2) <= 0) 195 yyerror("number greater than zero expected"); 196 else cfg_parser->opt->tcp_count = atoi($2); 197 } 198 ; 199 server_pidfile: VAR_PIDFILE STRING 200 { 201 OUTYY(("P(server_pidfile:%s)\n", $2)); 202 cfg_parser->opt->pidfile = region_strdup(cfg_parser->opt->region, $2); 203 } 204 ; 205 server_port: VAR_PORT STRING 206 { 207 OUTYY(("P(server_port:%s)\n", $2)); 208 cfg_parser->opt->port = region_strdup(cfg_parser->opt->region, $2); 209 } 210 ; 211 server_statistics: VAR_STATISTICS STRING 212 { 213 OUTYY(("P(server_statistics:%s)\n", $2)); 214 if(atoi($2) == 0 && strcmp($2, "0") != 0) 215 yyerror("number expected"); 216 else cfg_parser->opt->statistics = atoi($2); 217 } 218 ; 219 server_chroot: VAR_CHROOT STRING 220 { 221 OUTYY(("P(server_chroot:%s)\n", $2)); 222 cfg_parser->opt->chroot = region_strdup(cfg_parser->opt->region, $2); 223 } 224 ; 225 server_username: VAR_USERNAME STRING 226 { 227 OUTYY(("P(server_username:%s)\n", $2)); 228 cfg_parser->opt->username = region_strdup(cfg_parser->opt->region, $2); 229 } 230 ; 231 server_zonesdir: VAR_ZONESDIR STRING 232 { 233 OUTYY(("P(server_zonesdir:%s)\n", $2)); 234 cfg_parser->opt->zonesdir = region_strdup(cfg_parser->opt->region, $2); 235 } 236 ; 237 server_difffile: VAR_DIFFFILE STRING 238 { 239 OUTYY(("P(server_difffile:%s)\n", $2)); 240 cfg_parser->opt->difffile = region_strdup(cfg_parser->opt->region, $2); 241 } 242 ; 243 server_xfrdfile: VAR_XFRDFILE STRING 244 { 245 OUTYY(("P(server_xfrdfile:%s)\n", $2)); 246 cfg_parser->opt->xfrdfile = region_strdup(cfg_parser->opt->region, $2); 247 } 248 ; 249 server_xfrd_reload_timeout: VAR_XFRD_RELOAD_TIMEOUT STRING 250 { 251 OUTYY(("P(server_xfrd_reload_timeout:%s)\n", $2)); 252 if(atoi($2) == 0 && strcmp($2, "0") != 0) 253 yyerror("number expected"); 254 cfg_parser->opt->xfrd_reload_timeout = atoi($2); 255 } 256 ; 257 server_tcp_query_count: VAR_TCP_QUERY_COUNT STRING 258 { 259 OUTYY(("P(server_tcp_query_count:%s)\n", $2)); 260 if(atoi($2) == 0 && strcmp($2, "0") != 0) 261 yyerror("number expected"); 262 cfg_parser->opt->tcp_query_count = atoi($2); 263 } 264 ; 265 server_tcp_timeout: VAR_TCP_TIMEOUT STRING 266 { 267 OUTYY(("P(server_tcp_timeout:%s)\n", $2)); 268 if(atoi($2) == 0 && strcmp($2, "0") != 0) 269 yyerror("number expected"); 270 cfg_parser->opt->tcp_timeout = atoi($2); 271 } 272 ; 273 server_ipv4_edns_size: VAR_IPV4_EDNS_SIZE STRING 274 { 275 OUTYY(("P(server_ipv4_edns_size:%s)\n", $2)); 276 if(atoi($2) == 0 && strcmp($2, "0") != 0) 277 yyerror("number expected"); 278 cfg_parser->opt->ipv4_edns_size = atoi($2); 279 } 280 ; 281 server_ipv6_edns_size: VAR_IPV6_EDNS_SIZE STRING 282 { 283 OUTYY(("P(server_ipv6_edns_size:%s)\n", $2)); 284 if(atoi($2) == 0 && strcmp($2, "0") != 0) 285 yyerror("number expected"); 286 cfg_parser->opt->ipv6_edns_size = atoi($2); 287 } 288 ; 289 290 /* zone: declaration */ 291 zonestart: VAR_ZONE 292 { 293 OUTYY(("\nP(zone:)\n")); 294 if(cfg_parser->current_zone) { 295 if(!cfg_parser->current_zone->name) 296 c_error("previous zone has no name"); 297 else { 298 if(!nsd_options_insert_zone(cfg_parser->opt, 299 cfg_parser->current_zone)) 300 c_error("duplicate zone"); 301 } 302 if(!cfg_parser->current_zone->zonefile) 303 c_error("previous zone has no zonefile"); 304 } 305 cfg_parser->current_zone = zone_options_create(cfg_parser->opt->region); 306 cfg_parser->current_allow_notify = 0; 307 cfg_parser->current_request_xfr = 0; 308 cfg_parser->current_notify = 0; 309 cfg_parser->current_provide_xfr = 0; 310 cfg_parser->current_outgoing_interface = 0; 311 } 312 ; 313 contents_zone: contents_zone content_zone | content_zone; 314 content_zone: zone_name | zone_zonefile | zone_allow_notify | 315 zone_request_xfr | zone_notify | zone_notify_retry | zone_provide_xfr | 316 zone_outgoing_interface | zone_allow_axfr_fallback; 317 zone_name: VAR_NAME STRING 318 { 319 OUTYY(("P(zone_name:%s)\n", $2)); 320 #ifndef NDEBUG 321 assert(cfg_parser->current_zone); 322 #endif 323 cfg_parser->current_zone->name = region_strdup(cfg_parser->opt->region, $2); 324 } 325 ; 326 zone_zonefile: VAR_ZONEFILE STRING 327 { 328 OUTYY(("P(zone_zonefile:%s)\n", $2)); 329 #ifndef NDEBUG 330 assert(cfg_parser->current_zone); 331 #endif 332 cfg_parser->current_zone->zonefile = region_strdup(cfg_parser->opt->region, $2); 333 } 334 ; 335 zone_allow_notify: VAR_ALLOW_NOTIFY STRING STRING 336 { 337 acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $2, $3); 338 OUTYY(("P(zone_allow_notify:%s %s)\n", $2, $3)); 339 if(cfg_parser->current_allow_notify) 340 cfg_parser->current_allow_notify->next = acl; 341 else 342 cfg_parser->current_zone->allow_notify = acl; 343 cfg_parser->current_allow_notify = acl; 344 } 345 ; 346 zone_request_xfr: VAR_REQUEST_XFR zone_request_xfr_data 347 { 348 } 349 ; 350 zone_request_xfr_data: STRING STRING 351 { 352 acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $1, $2); 353 OUTYY(("P(zone_request_xfr:%s %s)\n", $1, $2)); 354 if(acl->blocked) c_error("blocked address used for request-xfr"); 355 if(acl->rangetype!=acl_range_single) c_error("address range used for request-xfr"); 356 if(cfg_parser->current_request_xfr) 357 cfg_parser->current_request_xfr->next = acl; 358 else 359 cfg_parser->current_zone->request_xfr = acl; 360 cfg_parser->current_request_xfr = acl; 361 } 362 | VAR_AXFR STRING STRING 363 { 364 acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $2, $3); 365 acl->use_axfr_only = 1; 366 OUTYY(("P(zone_request_xfr:%s %s)\n", $2, $3)); 367 if(acl->blocked) c_error("blocked address used for request-xfr"); 368 if(acl->rangetype!=acl_range_single) c_error("address range used for request-xfr"); 369 if(cfg_parser->current_request_xfr) 370 cfg_parser->current_request_xfr->next = acl; 371 else 372 cfg_parser->current_zone->request_xfr = acl; 373 cfg_parser->current_request_xfr = acl; 374 } 375 | VAR_UDP STRING STRING 376 { 377 acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $2, $3); 378 acl->allow_udp = 1; 379 OUTYY(("P(zone_request_xfr:%s %s)\n", $2, $3)); 380 if(acl->blocked) c_error("blocked address used for request-xfr"); 381 if(acl->rangetype!=acl_range_single) c_error("address range used for request-xfr"); 382 if(cfg_parser->current_request_xfr) 383 cfg_parser->current_request_xfr->next = acl; 384 else 385 cfg_parser->current_zone->request_xfr = acl; 386 cfg_parser->current_request_xfr = acl; 387 } 388 ; 389 zone_notify: VAR_NOTIFY STRING STRING 390 { 391 acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $2, $3); 392 OUTYY(("P(zone_notify:%s %s)\n", $2, $3)); 393 if(acl->blocked) c_error("blocked address used for notify"); 394 if(acl->rangetype!=acl_range_single) c_error("address range used for notify"); 395 if(cfg_parser->current_notify) 396 cfg_parser->current_notify->next = acl; 397 else 398 cfg_parser->current_zone->notify = acl; 399 cfg_parser->current_notify = acl; 400 } 401 ; 402 zone_notify_retry: VAR_NOTIFY_RETRY STRING 403 { 404 OUTYY(("P(zone_notify_retry:%s)\n", $2)); 405 if(atoi($2) == 0 && strcmp($2, "0") != 0) 406 yyerror("number expected"); 407 else cfg_parser->current_zone->notify_retry = atoi($2); 408 } 409 ; 410 zone_provide_xfr: VAR_PROVIDE_XFR STRING STRING 411 { 412 acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $2, $3); 413 OUTYY(("P(zone_provide_xfr:%s %s)\n", $2, $3)); 414 if(cfg_parser->current_provide_xfr) 415 cfg_parser->current_provide_xfr->next = acl; 416 else 417 cfg_parser->current_zone->provide_xfr = acl; 418 cfg_parser->current_provide_xfr = acl; 419 } 420 ; 421 zone_outgoing_interface: VAR_OUTGOING_INTERFACE STRING 422 { 423 acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $2, "NOKEY"); 424 OUTYY(("P(zone_outgoing_interface:%s)\n", $2)); 425 426 if(cfg_parser->current_outgoing_interface) 427 cfg_parser->current_outgoing_interface->next = acl; 428 else 429 cfg_parser->current_zone->outgoing_interface = acl; 430 cfg_parser->current_outgoing_interface = acl; 431 } 432 ; 433 zone_allow_axfr_fallback: VAR_ALLOW_AXFR_FALLBACK STRING 434 { 435 OUTYY(("P(zone_allow_axfr_fallback:%s)\n", $2)); 436 if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) 437 yyerror("expected yes or no."); 438 else cfg_parser->current_zone->allow_axfr_fallback = (strcmp($2, "yes")==0); 439 } 440 ; 441 442 /* key: declaration */ 443 keystart: VAR_KEY 444 { 445 OUTYY(("\nP(key:)\n")); 446 if(cfg_parser->current_key) { 447 if(!cfg_parser->current_key->name) c_error("previous key has no name"); 448 if(!cfg_parser->current_key->algorithm) c_error("previous key has no algorithm"); 449 if(!cfg_parser->current_key->secret) c_error("previous key has no secret blob"); 450 cfg_parser->current_key->next = key_options_create(cfg_parser->opt->region); 451 cfg_parser->current_key = cfg_parser->current_key->next; 452 } else { 453 cfg_parser->current_key = key_options_create(cfg_parser->opt->region); 454 cfg_parser->opt->keys = cfg_parser->current_key; 455 } 456 cfg_parser->opt->numkeys++; 457 } 458 ; 459 contents_key: contents_key content_key | content_key; 460 content_key: key_name | key_algorithm | key_secret; 461 key_name: VAR_NAME STRING 462 { 463 OUTYY(("P(key_name:%s)\n", $2)); 464 #ifndef NDEBUG 465 assert(cfg_parser->current_key); 466 #endif 467 cfg_parser->current_key->name = region_strdup(cfg_parser->opt->region, $2); 468 } 469 ; 470 key_algorithm: VAR_ALGORITHM STRING 471 { 472 OUTYY(("P(key_algorithm:%s)\n", $2)); 473 #ifndef NDEBUG 474 assert(cfg_parser->current_key); 475 #endif 476 cfg_parser->current_key->algorithm = region_strdup(cfg_parser->opt->region, $2); 477 } 478 ; 479 key_secret: VAR_SECRET STRING 480 { 481 OUTYY(("key_secret:%s)\n", $2)); 482 #ifndef NDEBUG 483 assert(cfg_parser->current_key); 484 #endif 485 cfg_parser->current_key->secret = region_strdup(cfg_parser->opt->region, $2); 486 } 487 ; 488 489 %% 490 491 /* parse helper routines could be here */ 492