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