1 /* $NetBSD: namedconf.c,v 1.1 2024/02/18 20:57:58 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file */ 17 18 #include <inttypes.h> 19 #include <stdbool.h> 20 #include <stdlib.h> 21 #include <string.h> 22 23 #include <isc/lex.h> 24 #include <isc/mem.h> 25 #include <isc/print.h> 26 #include <isc/result.h> 27 #include <isc/string.h> 28 #include <isc/util.h> 29 30 #include <dns/result.h> 31 #include <dns/ttl.h> 32 33 #include <isccfg/cfg.h> 34 #include <isccfg/grammar.h> 35 #include <isccfg/log.h> 36 #include <isccfg/namedconf.h> 37 38 #define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base) 39 40 /*% Check a return value. */ 41 #define CHECK(op) \ 42 do { \ 43 result = (op); \ 44 if (result != ISC_R_SUCCESS) \ 45 goto cleanup; \ 46 } while (0) 47 48 /*% Clean up a configuration object if non-NULL. */ 49 #define CLEANUP_OBJ(obj) \ 50 do { \ 51 if ((obj) != NULL) \ 52 cfg_obj_destroy(pctx, &(obj)); \ 53 } while (0) 54 55 /*% 56 * Forward declarations of static functions. 57 */ 58 59 static isc_result_t 60 parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); 61 62 static isc_result_t 63 parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, 64 cfg_obj_t **ret); 65 66 static isc_result_t 67 parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); 68 static void 69 print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj); 70 71 static void 72 doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type); 73 74 static void 75 print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj); 76 77 static void 78 doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type); 79 80 static void 81 doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type); 82 83 static cfg_type_t cfg_type_acl; 84 static cfg_type_t cfg_type_bracketed_dscpsockaddrlist; 85 static cfg_type_t cfg_type_bracketed_namesockaddrkeylist; 86 static cfg_type_t cfg_type_bracketed_netaddrlist; 87 static cfg_type_t cfg_type_bracketed_sockaddrnameportlist; 88 static cfg_type_t cfg_type_controls; 89 static cfg_type_t cfg_type_controls_sockaddr; 90 static cfg_type_t cfg_type_destinationlist; 91 static cfg_type_t cfg_type_dialuptype; 92 static cfg_type_t cfg_type_dlz; 93 static cfg_type_t cfg_type_dnssecpolicy; 94 static cfg_type_t cfg_type_dnstap; 95 static cfg_type_t cfg_type_dnstapoutput; 96 static cfg_type_t cfg_type_dyndb; 97 static cfg_type_t cfg_type_plugin; 98 static cfg_type_t cfg_type_ixfrdifftype; 99 static cfg_type_t cfg_type_ixfrratio; 100 static cfg_type_t cfg_type_key; 101 static cfg_type_t cfg_type_logfile; 102 static cfg_type_t cfg_type_logging; 103 static cfg_type_t cfg_type_logseverity; 104 static cfg_type_t cfg_type_logsuffix; 105 static cfg_type_t cfg_type_logversions; 106 static cfg_type_t cfg_type_remoteselement; 107 static cfg_type_t cfg_type_maxduration; 108 static cfg_type_t cfg_type_minimal; 109 static cfg_type_t cfg_type_nameportiplist; 110 static cfg_type_t cfg_type_notifytype; 111 static cfg_type_t cfg_type_optional_allow; 112 static cfg_type_t cfg_type_optional_class; 113 static cfg_type_t cfg_type_optional_dscp; 114 static cfg_type_t cfg_type_optional_facility; 115 static cfg_type_t cfg_type_optional_keyref; 116 static cfg_type_t cfg_type_optional_port; 117 static cfg_type_t cfg_type_optional_uint32; 118 static cfg_type_t cfg_type_options; 119 static cfg_type_t cfg_type_portiplist; 120 static cfg_type_t cfg_type_printtime; 121 static cfg_type_t cfg_type_qminmethod; 122 static cfg_type_t cfg_type_querysource4; 123 static cfg_type_t cfg_type_querysource6; 124 static cfg_type_t cfg_type_querysource; 125 static cfg_type_t cfg_type_server; 126 static cfg_type_t cfg_type_server_key_kludge; 127 static cfg_type_t cfg_type_size; 128 static cfg_type_t cfg_type_sizenodefault; 129 static cfg_type_t cfg_type_sizeorpercent; 130 static cfg_type_t cfg_type_sizeval; 131 static cfg_type_t cfg_type_sockaddr4wild; 132 static cfg_type_t cfg_type_sockaddr6wild; 133 static cfg_type_t cfg_type_statschannels; 134 static cfg_type_t cfg_type_view; 135 static cfg_type_t cfg_type_viewopts; 136 static cfg_type_t cfg_type_zone; 137 138 /*% tkey-dhkey */ 139 140 static cfg_tuplefielddef_t tkey_dhkey_fields[] = { 141 { "name", &cfg_type_qstring, 0 }, 142 { "keyid", &cfg_type_uint32, 0 }, 143 { NULL, NULL, 0 } 144 }; 145 146 static cfg_type_t cfg_type_tkey_dhkey = { "tkey-dhkey", cfg_parse_tuple, 147 cfg_print_tuple, cfg_doc_tuple, 148 &cfg_rep_tuple, tkey_dhkey_fields }; 149 150 /*% listen-on */ 151 152 static cfg_tuplefielddef_t listenon_fields[] = { 153 { "port", &cfg_type_optional_port, 0 }, 154 { "dscp", &cfg_type_optional_dscp, CFG_CLAUSEFLAG_DEPRECATED }, 155 { "acl", &cfg_type_bracketed_aml, 0 }, 156 { NULL, NULL, 0 } 157 }; 158 159 static cfg_type_t cfg_type_listenon = { "listenon", cfg_parse_tuple, 160 cfg_print_tuple, cfg_doc_tuple, 161 &cfg_rep_tuple, listenon_fields }; 162 163 /*% acl */ 164 165 static cfg_tuplefielddef_t acl_fields[] = { { "name", &cfg_type_astring, 0 }, 166 { "value", &cfg_type_bracketed_aml, 167 0 }, 168 { NULL, NULL, 0 } }; 169 170 static cfg_type_t cfg_type_acl = { "acl", cfg_parse_tuple, 171 cfg_print_tuple, cfg_doc_tuple, 172 &cfg_rep_tuple, acl_fields }; 173 174 /*% remote servers, used for primaries and parental agents */ 175 static cfg_tuplefielddef_t remotes_fields[] = { 176 { "name", &cfg_type_astring, 0 }, 177 { "port", &cfg_type_optional_port, 0 }, 178 { "dscp", &cfg_type_optional_dscp, CFG_CLAUSEFLAG_DEPRECATED }, 179 { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 }, 180 { NULL, NULL, 0 } 181 }; 182 183 static cfg_type_t cfg_type_remoteservers = { "remote-servers", cfg_parse_tuple, 184 cfg_print_tuple, cfg_doc_tuple, 185 &cfg_rep_tuple, remotes_fields }; 186 187 /*% 188 * "sockaddrkeylist", a list of socket addresses with optional keys 189 * and an optional default port, as used in the remote-servers option. 190 * E.g., 191 * "port 1234 { myservers; 10.0.0.1 key foo; 1::2 port 69; }" 192 */ 193 194 static cfg_tuplefielddef_t namesockaddrkey_fields[] = { 195 { "remoteselement", &cfg_type_remoteselement, 0 }, 196 { "key", &cfg_type_optional_keyref, 0 }, 197 { NULL, NULL, 0 }, 198 }; 199 200 static cfg_type_t cfg_type_namesockaddrkey = { 201 "namesockaddrkey", cfg_parse_tuple, cfg_print_tuple, 202 cfg_doc_tuple, &cfg_rep_tuple, namesockaddrkey_fields 203 }; 204 205 static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = { 206 "bracketed_namesockaddrkeylist", 207 cfg_parse_bracketed_list, 208 cfg_print_bracketed_list, 209 cfg_doc_bracketed_list, 210 &cfg_rep_list, 211 &cfg_type_namesockaddrkey 212 }; 213 214 static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = { 215 { "port", &cfg_type_optional_port, 0 }, 216 { "dscp", &cfg_type_optional_dscp, CFG_CLAUSEFLAG_DEPRECATED }, 217 { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 }, 218 { NULL, NULL, 0 } 219 }; 220 static cfg_type_t cfg_type_namesockaddrkeylist = { 221 "sockaddrkeylist", cfg_parse_tuple, cfg_print_tuple, 222 cfg_doc_tuple, &cfg_rep_tuple, namesockaddrkeylist_fields 223 }; 224 225 /*% 226 * A list of socket addresses with an optional default port, as used 227 * in the 'listen-on' option. E.g., "{ 10.0.0.1; 1::2 port 69; }" 228 */ 229 static cfg_tuplefielddef_t portiplist_fields[] = { 230 { "port", &cfg_type_optional_port, 0 }, 231 { "dscp", &cfg_type_optional_dscp, CFG_CLAUSEFLAG_DEPRECATED }, 232 { "addresses", &cfg_type_bracketed_dscpsockaddrlist, 0 }, 233 { NULL, NULL, 0 } 234 }; 235 static cfg_type_t cfg_type_portiplist = { "portiplist", cfg_parse_tuple, 236 cfg_print_tuple, cfg_doc_tuple, 237 &cfg_rep_tuple, portiplist_fields }; 238 239 /* 240 * Obsolete format for the "pubkey" statement. 241 */ 242 static cfg_tuplefielddef_t pubkey_fields[] = { 243 { "flags", &cfg_type_uint32, 0 }, 244 { "protocol", &cfg_type_uint32, 0 }, 245 { "algorithm", &cfg_type_uint32, 0 }, 246 { "key", &cfg_type_qstring, 0 }, 247 { NULL, NULL, 0 } 248 }; 249 static cfg_type_t cfg_type_pubkey = { "pubkey", cfg_parse_tuple, 250 cfg_print_tuple, cfg_doc_tuple, 251 &cfg_rep_tuple, pubkey_fields }; 252 253 /*% 254 * A list of RR types, used in grant statements. 255 * Note that the old parser allows quotes around the RR type names. 256 */ 257 static cfg_type_t cfg_type_rrtypelist = { 258 "rrtypelist", cfg_parse_spacelist, cfg_print_spacelist, 259 cfg_doc_terminal, &cfg_rep_list, &cfg_type_astring 260 }; 261 262 static const char *mode_enums[] = { "deny", "grant", NULL }; 263 static cfg_type_t cfg_type_mode = { 264 "mode", cfg_parse_enum, cfg_print_ustring, 265 cfg_doc_enum, &cfg_rep_string, &mode_enums 266 }; 267 268 static isc_result_t 269 parse_matchtype(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 270 isc_result_t result; 271 272 CHECK(cfg_peektoken(pctx, 0)); 273 if (pctx->token.type == isc_tokentype_string && 274 strcasecmp(TOKEN_STRING(pctx), "zonesub") == 0) 275 { 276 pctx->flags |= CFG_PCTX_SKIP; 277 } 278 return (cfg_parse_enum(pctx, type, ret)); 279 280 cleanup: 281 return (result); 282 } 283 284 static isc_result_t 285 parse_matchname(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 286 isc_result_t result; 287 cfg_obj_t *obj = NULL; 288 289 if ((pctx->flags & CFG_PCTX_SKIP) != 0) { 290 pctx->flags &= ~CFG_PCTX_SKIP; 291 CHECK(cfg_parse_void(pctx, NULL, &obj)); 292 } else { 293 result = cfg_parse_astring(pctx, type, &obj); 294 } 295 296 *ret = obj; 297 cleanup: 298 return (result); 299 } 300 301 static void 302 doc_matchname(cfg_printer_t *pctx, const cfg_type_t *type) { 303 cfg_print_cstr(pctx, "[ "); 304 cfg_doc_obj(pctx, type->of); 305 cfg_print_cstr(pctx, " ]"); 306 } 307 308 static const char *matchtype_enums[] = { "6to4-self", 309 "external", 310 "krb5-self", 311 "krb5-selfsub", 312 "krb5-subdomain", 313 "ms-self", 314 "ms-selfsub", 315 "ms-subdomain", 316 "name", 317 "self", 318 "selfsub", 319 "selfwild", 320 "subdomain", 321 "tcp-self", 322 "wildcard", 323 "zonesub", 324 NULL }; 325 326 static cfg_type_t cfg_type_matchtype = { "matchtype", parse_matchtype, 327 cfg_print_ustring, cfg_doc_enum, 328 &cfg_rep_string, &matchtype_enums }; 329 330 static cfg_type_t cfg_type_matchname = { 331 "optional_matchname", parse_matchname, cfg_print_ustring, 332 doc_matchname, &cfg_rep_tuple, &cfg_type_ustring 333 }; 334 335 /*% 336 * A grant statement, used in the update policy. 337 */ 338 static cfg_tuplefielddef_t grant_fields[] = { 339 { "mode", &cfg_type_mode, 0 }, 340 { "identity", &cfg_type_astring, 0 }, /* domain name */ 341 { "matchtype", &cfg_type_matchtype, 0 }, 342 { "name", &cfg_type_matchname, 0 }, /* domain name */ 343 { "types", &cfg_type_rrtypelist, 0 }, 344 { NULL, NULL, 0 } 345 }; 346 static cfg_type_t cfg_type_grant = { "grant", cfg_parse_tuple, 347 cfg_print_tuple, cfg_doc_tuple, 348 &cfg_rep_tuple, grant_fields }; 349 350 static cfg_type_t cfg_type_updatepolicy = { 351 "update_policy", parse_updatepolicy, print_updatepolicy, 352 doc_updatepolicy, &cfg_rep_list, &cfg_type_grant 353 }; 354 355 static isc_result_t 356 parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type, 357 cfg_obj_t **ret) { 358 isc_result_t result; 359 CHECK(cfg_gettoken(pctx, 0)); 360 if (pctx->token.type == isc_tokentype_special && 361 pctx->token.value.as_char == '{') 362 { 363 cfg_ungettoken(pctx); 364 return (cfg_parse_bracketed_list(pctx, type, ret)); 365 } 366 367 if (pctx->token.type == isc_tokentype_string && 368 strcasecmp(TOKEN_STRING(pctx), "local") == 0) 369 { 370 cfg_obj_t *obj = NULL; 371 CHECK(cfg_create_obj(pctx, &cfg_type_ustring, &obj)); 372 obj->value.string.length = strlen("local"); 373 obj->value.string.base = 374 isc_mem_get(pctx->mctx, obj->value.string.length + 1); 375 memmove(obj->value.string.base, "local", 5); 376 obj->value.string.base[5] = '\0'; 377 *ret = obj; 378 return (ISC_R_SUCCESS); 379 } 380 381 cfg_ungettoken(pctx); 382 return (ISC_R_UNEXPECTEDTOKEN); 383 384 cleanup: 385 return (result); 386 } 387 388 static void 389 print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj) { 390 if (cfg_obj_isstring(obj)) { 391 cfg_print_ustring(pctx, obj); 392 } else { 393 cfg_print_bracketed_list(pctx, obj); 394 } 395 } 396 397 static void 398 doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type) { 399 cfg_print_cstr(pctx, "( local | { "); 400 cfg_doc_obj(pctx, type->of); 401 cfg_print_cstr(pctx, "; ... } )"); 402 } 403 404 /*% 405 * A view statement. 406 */ 407 static cfg_tuplefielddef_t view_fields[] = { 408 { "name", &cfg_type_astring, 0 }, 409 { "class", &cfg_type_optional_class, 0 }, 410 { "options", &cfg_type_viewopts, 0 }, 411 { NULL, NULL, 0 } 412 }; 413 static cfg_type_t cfg_type_view = { "view", cfg_parse_tuple, 414 cfg_print_tuple, cfg_doc_tuple, 415 &cfg_rep_tuple, view_fields }; 416 417 /*% 418 * A zone statement. 419 */ 420 static cfg_tuplefielddef_t zone_fields[] = { 421 { "name", &cfg_type_astring, 0 }, 422 { "class", &cfg_type_optional_class, 0 }, 423 { "options", &cfg_type_zoneopts, 0 }, 424 { NULL, NULL, 0 } 425 }; 426 static cfg_type_t cfg_type_zone = { "zone", cfg_parse_tuple, 427 cfg_print_tuple, cfg_doc_tuple, 428 &cfg_rep_tuple, zone_fields }; 429 430 /*% 431 * A dnssec-policy statement. 432 */ 433 static cfg_tuplefielddef_t dnssecpolicy_fields[] = { 434 { "name", &cfg_type_astring, 0 }, 435 { "options", &cfg_type_dnssecpolicyopts, 0 }, 436 { NULL, NULL, 0 } 437 }; 438 439 static cfg_type_t cfg_type_dnssecpolicy = { 440 "dnssec-policy", cfg_parse_tuple, cfg_print_tuple, 441 cfg_doc_tuple, &cfg_rep_tuple, dnssecpolicy_fields 442 }; 443 444 /*% 445 * A "category" clause in the "logging" statement. 446 */ 447 static cfg_tuplefielddef_t category_fields[] = { 448 { "name", &cfg_type_astring, 0 }, 449 { "destinations", &cfg_type_destinationlist, 0 }, 450 { NULL, NULL, 0 } 451 }; 452 static cfg_type_t cfg_type_category = { "category", cfg_parse_tuple, 453 cfg_print_tuple, cfg_doc_tuple, 454 &cfg_rep_tuple, category_fields }; 455 456 static isc_result_t 457 parse_maxduration(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 458 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_duration, ret)); 459 } 460 461 static void 462 doc_maxduration(cfg_printer_t *pctx, const cfg_type_t *type) { 463 cfg_doc_enum_or_other(pctx, type, &cfg_type_duration); 464 } 465 466 /*% 467 * A duration or "unlimited", but not "default". 468 */ 469 static const char *maxduration_enums[] = { "unlimited", NULL }; 470 static cfg_type_t cfg_type_maxduration = { 471 "maxduration_no_default", parse_maxduration, cfg_print_ustring, 472 doc_maxduration, &cfg_rep_duration, maxduration_enums 473 }; 474 475 /*% 476 * A dnssec key, as used in the "trusted-keys" statement. 477 */ 478 static cfg_tuplefielddef_t dnsseckey_fields[] = { 479 { "name", &cfg_type_astring, 0 }, 480 { "anchortype", &cfg_type_void, 0 }, 481 { "rdata1", &cfg_type_uint32, 0 }, 482 { "rdata2", &cfg_type_uint32, 0 }, 483 { "rdata3", &cfg_type_uint32, 0 }, 484 { "data", &cfg_type_qstring, 0 }, 485 { NULL, NULL, 0 } 486 }; 487 static cfg_type_t cfg_type_dnsseckey = { "dnsseckey", cfg_parse_tuple, 488 cfg_print_tuple, cfg_doc_tuple, 489 &cfg_rep_tuple, dnsseckey_fields }; 490 491 /*% 492 * Optional enums. 493 * 494 */ 495 static isc_result_t 496 parse_optional_enum(cfg_parser_t *pctx, const cfg_type_t *type, 497 cfg_obj_t **ret) { 498 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_void, ret)); 499 } 500 501 static void 502 doc_optional_enum(cfg_printer_t *pctx, const cfg_type_t *type) { 503 UNUSED(type); 504 cfg_print_cstr(pctx, "[ "); 505 cfg_doc_enum(pctx, type); 506 cfg_print_cstr(pctx, " ]"); 507 } 508 509 /*% 510 * A key initialization specifier, as used in the 511 * "trust-anchors" (or synonymous "managed-keys") statement. 512 */ 513 static const char *anchortype_enums[] = { "static-key", "initial-key", 514 "static-ds", "initial-ds", NULL }; 515 static cfg_type_t cfg_type_anchortype = { "anchortype", cfg_parse_enum, 516 cfg_print_ustring, cfg_doc_enum, 517 &cfg_rep_string, anchortype_enums }; 518 static cfg_tuplefielddef_t managedkey_fields[] = { 519 { "name", &cfg_type_astring, 0 }, 520 { "anchortype", &cfg_type_anchortype, 0 }, 521 { "rdata1", &cfg_type_uint32, 0 }, 522 { "rdata2", &cfg_type_uint32, 0 }, 523 { "rdata3", &cfg_type_uint32, 0 }, 524 { "data", &cfg_type_qstring, 0 }, 525 { NULL, NULL, 0 } 526 }; 527 static cfg_type_t cfg_type_managedkey = { "managedkey", cfg_parse_tuple, 528 cfg_print_tuple, cfg_doc_tuple, 529 &cfg_rep_tuple, managedkey_fields }; 530 531 /*% 532 * DNSSEC key roles. 533 */ 534 static const char *dnsseckeyrole_enums[] = { "csk", "ksk", "zsk", NULL }; 535 static cfg_type_t cfg_type_dnsseckeyrole = { 536 "dnssec-key-role", cfg_parse_enum, cfg_print_ustring, 537 cfg_doc_enum, &cfg_rep_string, &dnsseckeyrole_enums 538 }; 539 540 /*% 541 * DNSSEC key storage types. 542 */ 543 static const char *dnsseckeystore_enums[] = { "key-directory", NULL }; 544 static cfg_type_t cfg_type_dnsseckeystore = { 545 "dnssec-key-storage", parse_optional_enum, cfg_print_ustring, 546 doc_optional_enum, &cfg_rep_string, dnsseckeystore_enums 547 }; 548 549 /*% 550 * A dnssec key, as used in the "keys" statement in a "dnssec-policy". 551 */ 552 static keyword_type_t algorithm_kw = { "algorithm", &cfg_type_ustring }; 553 static cfg_type_t cfg_type_algorithm = { "algorithm", parse_keyvalue, 554 print_keyvalue, doc_keyvalue, 555 &cfg_rep_string, &algorithm_kw }; 556 557 static keyword_type_t lifetime_kw = { "lifetime", 558 &cfg_type_duration_or_unlimited }; 559 static cfg_type_t cfg_type_lifetime = { "lifetime", parse_keyvalue, 560 print_keyvalue, doc_keyvalue, 561 &cfg_rep_duration, &lifetime_kw }; 562 563 static cfg_tuplefielddef_t kaspkey_fields[] = { 564 { "role", &cfg_type_dnsseckeyrole, 0 }, 565 { "keystore-type", &cfg_type_dnsseckeystore, 0 }, 566 { "lifetime", &cfg_type_lifetime, 0 }, 567 { "algorithm", &cfg_type_algorithm, 0 }, 568 { "length", &cfg_type_optional_uint32, 0 }, 569 { NULL, NULL, 0 } 570 }; 571 static cfg_type_t cfg_type_kaspkey = { "kaspkey", cfg_parse_tuple, 572 cfg_print_tuple, cfg_doc_tuple, 573 &cfg_rep_tuple, kaspkey_fields }; 574 575 /*% 576 * NSEC3 parameters. 577 */ 578 static keyword_type_t nsec3iter_kw = { "iterations", &cfg_type_uint32 }; 579 static cfg_type_t cfg_type_nsec3iter = { 580 "iterations", parse_optional_keyvalue, print_keyvalue, 581 doc_optional_keyvalue, &cfg_rep_uint32, &nsec3iter_kw 582 }; 583 584 static keyword_type_t nsec3optout_kw = { "optout", &cfg_type_boolean }; 585 static cfg_type_t cfg_type_nsec3optout = { 586 "optout", parse_optional_keyvalue, 587 print_keyvalue, doc_optional_keyvalue, 588 &cfg_rep_boolean, &nsec3optout_kw 589 }; 590 591 static keyword_type_t nsec3salt_kw = { "salt-length", &cfg_type_uint32 }; 592 static cfg_type_t cfg_type_nsec3salt = { 593 "salt-length", parse_optional_keyvalue, print_keyvalue, 594 doc_optional_keyvalue, &cfg_rep_uint32, &nsec3salt_kw 595 }; 596 597 static cfg_tuplefielddef_t nsec3param_fields[] = { 598 { "iterations", &cfg_type_nsec3iter, 0 }, 599 { "optout", &cfg_type_nsec3optout, 0 }, 600 { "salt-length", &cfg_type_nsec3salt, 0 }, 601 { NULL, NULL, 0 } 602 }; 603 604 static cfg_type_t cfg_type_nsec3 = { "nsec3param", cfg_parse_tuple, 605 cfg_print_tuple, cfg_doc_tuple, 606 &cfg_rep_tuple, nsec3param_fields }; 607 608 /*% 609 * Wild class, type, name. 610 */ 611 static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring }; 612 613 static cfg_type_t cfg_type_optional_wild_class = { 614 "optional_wild_class", parse_optional_keyvalue, print_keyvalue, 615 doc_optional_keyvalue, &cfg_rep_string, &wild_class_kw 616 }; 617 618 static keyword_type_t wild_type_kw = { "type", &cfg_type_ustring }; 619 620 static cfg_type_t cfg_type_optional_wild_type = { 621 "optional_wild_type", parse_optional_keyvalue, print_keyvalue, 622 doc_optional_keyvalue, &cfg_rep_string, &wild_type_kw 623 }; 624 625 static keyword_type_t wild_name_kw = { "name", &cfg_type_qstring }; 626 627 static cfg_type_t cfg_type_optional_wild_name = { 628 "optional_wild_name", parse_optional_keyvalue, print_keyvalue, 629 doc_optional_keyvalue, &cfg_rep_string, &wild_name_kw 630 }; 631 632 /*% 633 * An rrset ordering element. 634 */ 635 static cfg_tuplefielddef_t rrsetorderingelement_fields[] = { 636 { "class", &cfg_type_optional_wild_class, 0 }, 637 { "type", &cfg_type_optional_wild_type, 0 }, 638 { "name", &cfg_type_optional_wild_name, 0 }, 639 { "order", &cfg_type_ustring, 0 }, /* must be literal "order" */ 640 { "ordering", &cfg_type_ustring, 0 }, 641 { NULL, NULL, 0 } 642 }; 643 static cfg_type_t cfg_type_rrsetorderingelement = { 644 "rrsetorderingelement", cfg_parse_tuple, cfg_print_tuple, 645 cfg_doc_tuple, &cfg_rep_tuple, rrsetorderingelement_fields 646 }; 647 648 /*% 649 * A global or view "check-names" option. Note that the zone 650 * "check-names" option has a different syntax. 651 */ 652 653 static const char *checktype_enums[] = { "primary", "master", "secondary", 654 "slave", "response", NULL }; 655 static cfg_type_t cfg_type_checktype = { "checktype", cfg_parse_enum, 656 cfg_print_ustring, cfg_doc_enum, 657 &cfg_rep_string, &checktype_enums }; 658 659 static const char *checkmode_enums[] = { "fail", "warn", "ignore", NULL }; 660 static cfg_type_t cfg_type_checkmode = { "checkmode", cfg_parse_enum, 661 cfg_print_ustring, cfg_doc_enum, 662 &cfg_rep_string, &checkmode_enums }; 663 664 static const char *warn_enums[] = { "warn", "ignore", NULL }; 665 static cfg_type_t cfg_type_warn = { 666 "warn", cfg_parse_enum, cfg_print_ustring, 667 cfg_doc_enum, &cfg_rep_string, &warn_enums 668 }; 669 670 static cfg_tuplefielddef_t checknames_fields[] = { 671 { "type", &cfg_type_checktype, 0 }, 672 { "mode", &cfg_type_checkmode, 0 }, 673 { NULL, NULL, 0 } 674 }; 675 676 static cfg_type_t cfg_type_checknames = { "checknames", cfg_parse_tuple, 677 cfg_print_tuple, cfg_doc_tuple, 678 &cfg_rep_tuple, checknames_fields }; 679 680 static cfg_type_t cfg_type_bracketed_dscpsockaddrlist = { 681 "bracketed_sockaddrlist", 682 cfg_parse_bracketed_list, 683 cfg_print_bracketed_list, 684 cfg_doc_bracketed_list, 685 &cfg_rep_list, 686 &cfg_type_sockaddrdscp 687 }; 688 689 static cfg_type_t cfg_type_bracketed_netaddrlist = { "bracketed_netaddrlist", 690 cfg_parse_bracketed_list, 691 cfg_print_bracketed_list, 692 cfg_doc_bracketed_list, 693 &cfg_rep_list, 694 &cfg_type_netaddr }; 695 696 static const char *autodnssec_enums[] = { "allow", "maintain", "off", NULL }; 697 static cfg_type_t cfg_type_autodnssec = { 698 "autodnssec", cfg_parse_enum, cfg_print_ustring, 699 cfg_doc_enum, &cfg_rep_string, &autodnssec_enums 700 }; 701 702 static const char *dnssecupdatemode_enums[] = { "maintain", "no-resign", NULL }; 703 static cfg_type_t cfg_type_dnssecupdatemode = { 704 "dnssecupdatemode", cfg_parse_enum, cfg_print_ustring, 705 cfg_doc_enum, &cfg_rep_string, &dnssecupdatemode_enums 706 }; 707 708 static const char *updatemethods_enums[] = { "date", "increment", "unixtime", 709 NULL }; 710 static cfg_type_t cfg_type_updatemethod = { 711 "updatemethod", cfg_parse_enum, cfg_print_ustring, 712 cfg_doc_enum, &cfg_rep_string, &updatemethods_enums 713 }; 714 715 /* 716 * zone-statistics: full, terse, or none. 717 * 718 * for backward compatibility, we also support boolean values. 719 * yes represents "full", no represents "terse". in the future we 720 * may change no to mean "none". 721 */ 722 static const char *zonestat_enums[] = { "full", "terse", "none", NULL }; 723 static isc_result_t 724 parse_zonestat(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 725 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 726 } 727 static void 728 doc_zonestat(cfg_printer_t *pctx, const cfg_type_t *type) { 729 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); 730 } 731 static cfg_type_t cfg_type_zonestat = { "zonestat", parse_zonestat, 732 cfg_print_ustring, doc_zonestat, 733 &cfg_rep_string, zonestat_enums }; 734 735 static cfg_type_t cfg_type_rrsetorder = { "rrsetorder", 736 cfg_parse_bracketed_list, 737 cfg_print_bracketed_list, 738 cfg_doc_bracketed_list, 739 &cfg_rep_list, 740 &cfg_type_rrsetorderingelement }; 741 742 static keyword_type_t dscp_kw = { "dscp", &cfg_type_uint32 }; 743 744 static cfg_type_t cfg_type_optional_dscp = { 745 "optional_dscp", parse_optional_keyvalue, print_keyvalue, 746 doc_optional_keyvalue, &cfg_rep_uint32, &dscp_kw 747 }; 748 749 static keyword_type_t port_kw = { "port", &cfg_type_uint32 }; 750 751 static cfg_type_t cfg_type_optional_port = { 752 "optional_port", parse_optional_keyvalue, print_keyvalue, 753 doc_optional_keyvalue, &cfg_rep_uint32, &port_kw 754 }; 755 756 /*% A list of keys, as in the "key" clause of the controls statement. */ 757 static cfg_type_t cfg_type_keylist = { "keylist", 758 cfg_parse_bracketed_list, 759 cfg_print_bracketed_list, 760 cfg_doc_bracketed_list, 761 &cfg_rep_list, 762 &cfg_type_astring }; 763 764 /*% A list of dnssec keys, as in "trusted-keys". Deprecated. */ 765 static cfg_type_t cfg_type_trustedkeys = { "trustedkeys", 766 cfg_parse_bracketed_list, 767 cfg_print_bracketed_list, 768 cfg_doc_bracketed_list, 769 &cfg_rep_list, 770 &cfg_type_dnsseckey }; 771 772 /*% 773 * A list of managed trust anchors. Each entry contains a name, a keyword 774 * ("static-key", initial-key", "static-ds" or "initial-ds"), and the 775 * fields associated with either a DNSKEY or a DS record. 776 */ 777 static cfg_type_t cfg_type_dnsseckeys = { "dnsseckeys", 778 cfg_parse_bracketed_list, 779 cfg_print_bracketed_list, 780 cfg_doc_bracketed_list, 781 &cfg_rep_list, 782 &cfg_type_managedkey }; 783 784 /*% 785 * A list of key entries, used in a DNSSEC Key and Signing Policy. 786 */ 787 static cfg_type_t cfg_type_kaspkeys = { "kaspkeys", 788 cfg_parse_bracketed_list, 789 cfg_print_bracketed_list, 790 cfg_doc_bracketed_list, 791 &cfg_rep_list, 792 &cfg_type_kaspkey }; 793 794 static const char *forwardtype_enums[] = { "first", "only", NULL }; 795 static cfg_type_t cfg_type_forwardtype = { 796 "forwardtype", cfg_parse_enum, cfg_print_ustring, 797 cfg_doc_enum, &cfg_rep_string, &forwardtype_enums 798 }; 799 800 static const char *zonetype_enums[] = { 801 "primary", "master", "secondary", "slave", 802 "mirror", "delegation-only", "forward", "hint", 803 "redirect", "static-stub", "stub", NULL 804 }; 805 static cfg_type_t cfg_type_zonetype = { "zonetype", cfg_parse_enum, 806 cfg_print_ustring, cfg_doc_enum, 807 &cfg_rep_string, &zonetype_enums }; 808 809 static const char *loglevel_enums[] = { "critical", "error", "warning", 810 "notice", "info", "dynamic", 811 NULL }; 812 static cfg_type_t cfg_type_loglevel = { "loglevel", cfg_parse_enum, 813 cfg_print_ustring, cfg_doc_enum, 814 &cfg_rep_string, &loglevel_enums }; 815 816 static const char *transferformat_enums[] = { "many-answers", "one-answer", 817 NULL }; 818 static cfg_type_t cfg_type_transferformat = { 819 "transferformat", cfg_parse_enum, cfg_print_ustring, 820 cfg_doc_enum, &cfg_rep_string, &transferformat_enums 821 }; 822 823 /*% 824 * The special keyword "none", as used in the pid-file option. 825 */ 826 827 static void 828 print_none(cfg_printer_t *pctx, const cfg_obj_t *obj) { 829 UNUSED(obj); 830 cfg_print_cstr(pctx, "none"); 831 } 832 833 static cfg_type_t cfg_type_none = { "none", NULL, print_none, 834 NULL, &cfg_rep_void, NULL }; 835 836 /*% 837 * A quoted string or the special keyword "none". Used in the pid-file option. 838 */ 839 static isc_result_t 840 parse_qstringornone(cfg_parser_t *pctx, const cfg_type_t *type, 841 cfg_obj_t **ret) { 842 isc_result_t result; 843 844 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); 845 if (pctx->token.type == isc_tokentype_string && 846 strcasecmp(TOKEN_STRING(pctx), "none") == 0) 847 { 848 return (cfg_create_obj(pctx, &cfg_type_none, ret)); 849 } 850 cfg_ungettoken(pctx); 851 return (cfg_parse_qstring(pctx, type, ret)); 852 cleanup: 853 return (result); 854 } 855 856 static void 857 doc_qstringornone(cfg_printer_t *pctx, const cfg_type_t *type) { 858 UNUSED(type); 859 cfg_print_cstr(pctx, "( <quoted_string> | none )"); 860 } 861 862 static cfg_type_t cfg_type_qstringornone = { "qstringornone", 863 parse_qstringornone, 864 NULL, 865 doc_qstringornone, 866 NULL, 867 NULL }; 868 869 /*% 870 * A boolean ("yes" or "no"), or the special keyword "auto". 871 * Used in the dnssec-validation option. 872 */ 873 static void 874 print_auto(cfg_printer_t *pctx, const cfg_obj_t *obj) { 875 UNUSED(obj); 876 cfg_print_cstr(pctx, "auto"); 877 } 878 879 static cfg_type_t cfg_type_auto = { "auto", NULL, print_auto, 880 NULL, &cfg_rep_void, NULL }; 881 882 static isc_result_t 883 parse_boolorauto(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 884 isc_result_t result; 885 886 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); 887 if (pctx->token.type == isc_tokentype_string && 888 strcasecmp(TOKEN_STRING(pctx), "auto") == 0) 889 { 890 return (cfg_create_obj(pctx, &cfg_type_auto, ret)); 891 } 892 cfg_ungettoken(pctx); 893 return (cfg_parse_boolean(pctx, type, ret)); 894 cleanup: 895 return (result); 896 } 897 898 static void 899 print_boolorauto(cfg_printer_t *pctx, const cfg_obj_t *obj) { 900 if (obj->type->rep == &cfg_rep_void) { 901 cfg_print_cstr(pctx, "auto"); 902 } else if (obj->value.boolean) { 903 cfg_print_cstr(pctx, "yes"); 904 } else { 905 cfg_print_cstr(pctx, "no"); 906 } 907 } 908 909 static void 910 doc_boolorauto(cfg_printer_t *pctx, const cfg_type_t *type) { 911 UNUSED(type); 912 cfg_print_cstr(pctx, "( yes | no | auto )"); 913 } 914 915 static cfg_type_t cfg_type_boolorauto = { 916 "boolorauto", parse_boolorauto, print_boolorauto, doc_boolorauto, NULL, 917 NULL 918 }; 919 920 /*% 921 * keyword hostname 922 */ 923 static void 924 print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) { 925 UNUSED(obj); 926 cfg_print_cstr(pctx, "hostname"); 927 } 928 929 static cfg_type_t cfg_type_hostname = { "hostname", NULL, 930 print_hostname, NULL, 931 &cfg_rep_boolean, NULL }; 932 933 /*% 934 * "server-id" argument. 935 */ 936 937 static isc_result_t 938 parse_serverid(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 939 isc_result_t result; 940 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); 941 if (pctx->token.type == isc_tokentype_string && 942 strcasecmp(TOKEN_STRING(pctx), "none") == 0) 943 { 944 return (cfg_create_obj(pctx, &cfg_type_none, ret)); 945 } 946 if (pctx->token.type == isc_tokentype_string && 947 strcasecmp(TOKEN_STRING(pctx), "hostname") == 0) 948 { 949 result = cfg_create_obj(pctx, &cfg_type_hostname, ret); 950 if (result == ISC_R_SUCCESS) { 951 (*ret)->value.boolean = true; 952 } 953 return (result); 954 } 955 cfg_ungettoken(pctx); 956 return (cfg_parse_qstring(pctx, type, ret)); 957 cleanup: 958 return (result); 959 } 960 961 static void 962 doc_serverid(cfg_printer_t *pctx, const cfg_type_t *type) { 963 UNUSED(type); 964 cfg_print_cstr(pctx, "( <quoted_string> | none | hostname )"); 965 } 966 967 static cfg_type_t cfg_type_serverid = { "serverid", parse_serverid, NULL, 968 doc_serverid, NULL, NULL }; 969 970 /*% 971 * Port list. 972 */ 973 static void 974 print_porttuple(cfg_printer_t *pctx, const cfg_obj_t *obj) { 975 cfg_print_cstr(pctx, "range "); 976 cfg_print_tuple(pctx, obj); 977 } 978 static cfg_tuplefielddef_t porttuple_fields[] = { 979 { "loport", &cfg_type_uint32, 0 }, 980 { "hiport", &cfg_type_uint32, 0 }, 981 { NULL, NULL, 0 } 982 }; 983 static cfg_type_t cfg_type_porttuple = { "porttuple", cfg_parse_tuple, 984 print_porttuple, cfg_doc_tuple, 985 &cfg_rep_tuple, porttuple_fields }; 986 987 static isc_result_t 988 parse_port(cfg_parser_t *pctx, cfg_obj_t **ret) { 989 isc_result_t result; 990 991 CHECK(cfg_parse_uint32(pctx, NULL, ret)); 992 if ((*ret)->value.uint32 > 0xffff) { 993 cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid port"); 994 cfg_obj_destroy(pctx, ret); 995 result = ISC_R_RANGE; 996 } 997 998 cleanup: 999 return (result); 1000 } 1001 1002 static isc_result_t 1003 parse_portrange(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1004 isc_result_t result; 1005 cfg_obj_t *obj = NULL; 1006 1007 UNUSED(type); 1008 1009 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); 1010 if (pctx->token.type == isc_tokentype_number) { 1011 CHECK(parse_port(pctx, ret)); 1012 } else { 1013 CHECK(cfg_gettoken(pctx, 0)); 1014 if (pctx->token.type != isc_tokentype_string || 1015 strcasecmp(TOKEN_STRING(pctx), "range") != 0) 1016 { 1017 cfg_parser_error(pctx, CFG_LOG_NEAR, 1018 "expected integer or 'range'"); 1019 return (ISC_R_UNEXPECTEDTOKEN); 1020 } 1021 CHECK(cfg_create_tuple(pctx, &cfg_type_porttuple, &obj)); 1022 CHECK(parse_port(pctx, &obj->value.tuple[0])); 1023 CHECK(parse_port(pctx, &obj->value.tuple[1])); 1024 if (obj->value.tuple[0]->value.uint32 > 1025 obj->value.tuple[1]->value.uint32) 1026 { 1027 cfg_parser_error(pctx, CFG_LOG_NOPREP, 1028 "low port '%u' must not be larger " 1029 "than high port", 1030 obj->value.tuple[0]->value.uint32); 1031 result = ISC_R_RANGE; 1032 goto cleanup; 1033 } 1034 *ret = obj; 1035 obj = NULL; 1036 } 1037 1038 cleanup: 1039 if (obj != NULL) { 1040 cfg_obj_destroy(pctx, &obj); 1041 } 1042 return (result); 1043 } 1044 1045 static cfg_type_t cfg_type_portrange = { "portrange", parse_portrange, 1046 NULL, cfg_doc_terminal, 1047 NULL, NULL }; 1048 1049 static cfg_type_t cfg_type_bracketed_portlist = { "bracketed_sockaddrlist", 1050 cfg_parse_bracketed_list, 1051 cfg_print_bracketed_list, 1052 cfg_doc_bracketed_list, 1053 &cfg_rep_list, 1054 &cfg_type_portrange }; 1055 1056 static const char *cookiealg_enums[] = { "aes", "siphash24", NULL }; 1057 static cfg_type_t cfg_type_cookiealg = { "cookiealg", cfg_parse_enum, 1058 cfg_print_ustring, cfg_doc_enum, 1059 &cfg_rep_string, &cookiealg_enums }; 1060 1061 /*% 1062 * fetch-quota-params 1063 */ 1064 1065 static cfg_tuplefielddef_t fetchquota_fields[] = { 1066 { "frequency", &cfg_type_uint32, 0 }, 1067 { "low", &cfg_type_fixedpoint, 0 }, 1068 { "high", &cfg_type_fixedpoint, 0 }, 1069 { "discount", &cfg_type_fixedpoint, 0 }, 1070 { NULL, NULL, 0 } 1071 }; 1072 1073 static cfg_type_t cfg_type_fetchquota = { "fetchquota", cfg_parse_tuple, 1074 cfg_print_tuple, cfg_doc_tuple, 1075 &cfg_rep_tuple, fetchquota_fields }; 1076 1077 /*% 1078 * fetches-per-server or fetches-per-zone 1079 */ 1080 1081 static const char *response_enums[] = { "drop", "fail", NULL }; 1082 1083 static cfg_type_t cfg_type_responsetype = { 1084 "responsetype", parse_optional_enum, cfg_print_ustring, 1085 doc_optional_enum, &cfg_rep_string, response_enums 1086 }; 1087 1088 static cfg_tuplefielddef_t fetchesper_fields[] = { 1089 { "fetches", &cfg_type_uint32, 0 }, 1090 { "response", &cfg_type_responsetype, 0 }, 1091 { NULL, NULL, 0 } 1092 }; 1093 1094 static cfg_type_t cfg_type_fetchesper = { "fetchesper", cfg_parse_tuple, 1095 cfg_print_tuple, cfg_doc_tuple, 1096 &cfg_rep_tuple, fetchesper_fields }; 1097 1098 /*% 1099 * Clauses that can be found within the top level of the named.conf 1100 * file only. 1101 */ 1102 static cfg_clausedef_t namedconf_clauses[] = { 1103 { "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI }, 1104 { "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI }, 1105 { "dnssec-policy", &cfg_type_dnssecpolicy, CFG_CLAUSEFLAG_MULTI }, 1106 { "logging", &cfg_type_logging, 0 }, 1107 { "lwres", &cfg_type_bracketed_text, 1108 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE }, 1109 { "masters", &cfg_type_remoteservers, CFG_CLAUSEFLAG_MULTI }, 1110 { "options", &cfg_type_options, 0 }, 1111 { "parental-agents", &cfg_type_remoteservers, CFG_CLAUSEFLAG_MULTI }, 1112 { "primaries", &cfg_type_remoteservers, CFG_CLAUSEFLAG_MULTI }, 1113 { "statistics-channels", &cfg_type_statschannels, 1114 CFG_CLAUSEFLAG_MULTI }, 1115 { "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI }, 1116 { NULL, NULL, 0 } 1117 }; 1118 1119 /*% 1120 * Clauses that can occur at the top level or in the view 1121 * statement, but not in the options block. 1122 */ 1123 static cfg_clausedef_t namedconf_or_view_clauses[] = { 1124 { "dlz", &cfg_type_dlz, CFG_CLAUSEFLAG_MULTI }, 1125 { "dyndb", &cfg_type_dyndb, CFG_CLAUSEFLAG_MULTI }, 1126 { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI }, 1127 { "managed-keys", &cfg_type_dnsseckeys, 1128 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_DEPRECATED }, 1129 { "plugin", &cfg_type_plugin, CFG_CLAUSEFLAG_MULTI }, 1130 { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI }, 1131 { "trust-anchors", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI }, 1132 { "trusted-keys", &cfg_type_trustedkeys, 1133 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_DEPRECATED }, 1134 { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI }, 1135 { NULL, NULL, 0 } 1136 }; 1137 1138 /*% 1139 * Clauses that can occur in the bind.keys file. 1140 */ 1141 static cfg_clausedef_t bindkeys_clauses[] = { 1142 { "managed-keys", &cfg_type_dnsseckeys, 1143 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_DEPRECATED }, 1144 { "trust-anchors", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI }, 1145 { "trusted-keys", &cfg_type_trustedkeys, 1146 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_DEPRECATED }, 1147 { NULL, NULL, 0 } 1148 }; 1149 1150 static const char *fstrm_model_enums[] = { "mpsc", "spsc", NULL }; 1151 static cfg_type_t cfg_type_fstrm_model = { 1152 "model", cfg_parse_enum, cfg_print_ustring, 1153 cfg_doc_enum, &cfg_rep_string, &fstrm_model_enums 1154 }; 1155 1156 /*% 1157 * Clauses that can be found within the 'options' statement. 1158 */ 1159 static cfg_clausedef_t options_clauses[] = { 1160 { "answer-cookie", &cfg_type_boolean, 0 }, 1161 { "automatic-interface-scan", &cfg_type_boolean, 0 }, 1162 { "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 }, 1163 { "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 }, 1164 { "bindkeys-file", &cfg_type_qstring, 0 }, 1165 { "blackhole", &cfg_type_bracketed_aml, 0 }, 1166 { "cookie-algorithm", &cfg_type_cookiealg, 0 }, 1167 { "cookie-secret", &cfg_type_sstring, CFG_CLAUSEFLAG_MULTI }, 1168 { "coresize", &cfg_type_size, 0 }, 1169 { "datasize", &cfg_type_size, 0 }, 1170 { "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 1171 { "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK }, 1172 #ifdef HAVE_DNSTAP 1173 { "dnstap-output", &cfg_type_dnstapoutput, 0 }, 1174 { "dnstap-identity", &cfg_type_serverid, 0 }, 1175 { "dnstap-version", &cfg_type_qstringornone, 0 }, 1176 #else /* ifdef HAVE_DNSTAP */ 1177 { "dnstap-output", &cfg_type_dnstapoutput, 1178 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1179 { "dnstap-identity", &cfg_type_serverid, CFG_CLAUSEFLAG_NOTCONFIGURED }, 1180 { "dnstap-version", &cfg_type_qstringornone, 1181 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1182 #endif /* ifdef HAVE_DNSTAP */ 1183 { "dscp", &cfg_type_uint32, CFG_CLAUSEFLAG_DEPRECATED }, 1184 { "dump-file", &cfg_type_qstring, 0 }, 1185 { "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 1186 { "files", &cfg_type_size, 0 }, 1187 { "flush-zones-on-shutdown", &cfg_type_boolean, 0 }, 1188 #ifdef HAVE_DNSTAP 1189 { "fstrm-set-buffer-hint", &cfg_type_uint32, 0 }, 1190 { "fstrm-set-flush-timeout", &cfg_type_uint32, 0 }, 1191 { "fstrm-set-input-queue-size", &cfg_type_uint32, 0 }, 1192 { "fstrm-set-output-notify-threshold", &cfg_type_uint32, 0 }, 1193 { "fstrm-set-output-queue-model", &cfg_type_fstrm_model, 0 }, 1194 { "fstrm-set-output-queue-size", &cfg_type_uint32, 0 }, 1195 { "fstrm-set-reopen-interval", &cfg_type_duration, 0 }, 1196 #else /* ifdef HAVE_DNSTAP */ 1197 { "fstrm-set-buffer-hint", &cfg_type_uint32, 1198 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1199 { "fstrm-set-flush-timeout", &cfg_type_uint32, 1200 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1201 { "fstrm-set-input-queue-size", &cfg_type_uint32, 1202 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1203 { "fstrm-set-output-notify-threshold", &cfg_type_uint32, 1204 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1205 { "fstrm-set-output-queue-model", &cfg_type_fstrm_model, 1206 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1207 { "fstrm-set-output-queue-size", &cfg_type_uint32, 1208 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1209 { "fstrm-set-reopen-interval", &cfg_type_duration, 1210 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1211 #endif /* HAVE_DNSTAP */ 1212 #if defined(HAVE_GEOIP2) 1213 { "geoip-directory", &cfg_type_qstringornone, 0 }, 1214 #else /* if defined(HAVE_GEOIP2) */ 1215 { "geoip-directory", &cfg_type_qstringornone, 1216 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1217 #endif /* HAVE_GEOIP2 */ 1218 { "geoip-use-ecs", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 1219 { "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 1220 { "heartbeat-interval", &cfg_type_uint32, 0 }, 1221 { "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 1222 { "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_ANCIENT }, 1223 { "hostname", &cfg_type_qstringornone, 0 }, 1224 { "interface-interval", &cfg_type_duration, 0 }, 1225 { "keep-response-order", &cfg_type_bracketed_aml, 0 }, 1226 { "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI }, 1227 { "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI }, 1228 { "lock-file", &cfg_type_qstringornone, 0 }, 1229 { "managed-keys-directory", &cfg_type_qstring, 0 }, 1230 { "match-mapped-addresses", &cfg_type_boolean, 0 }, 1231 { "max-rsa-exponent-size", &cfg_type_uint32, 0 }, 1232 { "memstatistics", &cfg_type_boolean, 0 }, 1233 { "memstatistics-file", &cfg_type_qstring, 0 }, 1234 { "multiple-cnames", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 1235 { "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_ANCIENT }, 1236 { "notify-rate", &cfg_type_uint32, 0 }, 1237 { "pid-file", &cfg_type_qstringornone, 0 }, 1238 { "port", &cfg_type_uint32, 0 }, 1239 { "querylog", &cfg_type_boolean, 0 }, 1240 { "random-device", &cfg_type_qstringornone, 0 }, 1241 { "recursing-file", &cfg_type_qstring, 0 }, 1242 { "recursive-clients", &cfg_type_uint32, 0 }, 1243 { "reuseport", &cfg_type_boolean, 0 }, 1244 { "reserved-sockets", &cfg_type_uint32, 0 }, 1245 { "secroots-file", &cfg_type_qstring, 0 }, 1246 { "serial-queries", &cfg_type_uint32, CFG_CLAUSEFLAG_ANCIENT }, 1247 { "serial-query-rate", &cfg_type_uint32, 0 }, 1248 { "server-id", &cfg_type_serverid, 0 }, 1249 { "session-keyalg", &cfg_type_astring, 0 }, 1250 { "session-keyfile", &cfg_type_qstringornone, 0 }, 1251 { "session-keyname", &cfg_type_astring, 0 }, 1252 { "sit-secret", &cfg_type_sstring, CFG_CLAUSEFLAG_OBSOLETE }, 1253 { "stacksize", &cfg_type_size, 0 }, 1254 { "startup-notify-rate", &cfg_type_uint32, 0 }, 1255 { "statistics-file", &cfg_type_qstring, 0 }, 1256 { "statistics-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_ANCIENT }, 1257 { "tcp-advertised-timeout", &cfg_type_uint32, 0 }, 1258 { "tcp-clients", &cfg_type_uint32, 0 }, 1259 { "tcp-idle-timeout", &cfg_type_uint32, 0 }, 1260 { "tcp-initial-timeout", &cfg_type_uint32, 0 }, 1261 { "tcp-keepalive-timeout", &cfg_type_uint32, 0 }, 1262 { "tcp-listen-queue", &cfg_type_uint32, 0 }, 1263 { "tkey-dhkey", &cfg_type_tkey_dhkey, 0 }, 1264 { "tkey-domain", &cfg_type_qstring, 0 }, 1265 { "tkey-gssapi-credential", &cfg_type_qstring, 0 }, 1266 { "tkey-gssapi-keytab", &cfg_type_qstring, 0 }, 1267 { "transfer-message-size", &cfg_type_uint32, 0 }, 1268 { "transfers-in", &cfg_type_uint32, 0 }, 1269 { "transfers-out", &cfg_type_uint32, 0 }, 1270 { "transfers-per-ns", &cfg_type_uint32, 0 }, 1271 { "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 1272 { "update-quota", &cfg_type_uint32, 0 }, 1273 { "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 1274 { "use-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 1275 { "use-v4-udp-ports", &cfg_type_bracketed_portlist, 0 }, 1276 { "use-v6-udp-ports", &cfg_type_bracketed_portlist, 0 }, 1277 { "version", &cfg_type_qstringornone, 0 }, 1278 { NULL, NULL, 0 } 1279 }; 1280 1281 static cfg_type_t cfg_type_namelist = { "namelist", 1282 cfg_parse_bracketed_list, 1283 cfg_print_bracketed_list, 1284 cfg_doc_bracketed_list, 1285 &cfg_rep_list, 1286 &cfg_type_astring }; 1287 1288 static keyword_type_t exclude_kw = { "exclude", &cfg_type_namelist }; 1289 1290 static cfg_type_t cfg_type_optional_exclude = { 1291 "optional_exclude", parse_optional_keyvalue, print_keyvalue, 1292 doc_optional_keyvalue, &cfg_rep_list, &exclude_kw 1293 }; 1294 1295 static keyword_type_t exceptionnames_kw = { "except-from", &cfg_type_namelist }; 1296 1297 static cfg_type_t cfg_type_optional_exceptionnames = { 1298 "optional_allow", parse_optional_keyvalue, print_keyvalue, 1299 doc_optional_keyvalue, &cfg_rep_list, &exceptionnames_kw 1300 }; 1301 1302 static cfg_tuplefielddef_t denyaddresses_fields[] = { 1303 { "acl", &cfg_type_bracketed_aml, 0 }, 1304 { "except-from", &cfg_type_optional_exceptionnames, 0 }, 1305 { NULL, NULL, 0 } 1306 }; 1307 1308 static cfg_type_t cfg_type_denyaddresses = { 1309 "denyaddresses", cfg_parse_tuple, cfg_print_tuple, 1310 cfg_doc_tuple, &cfg_rep_tuple, denyaddresses_fields 1311 }; 1312 1313 static cfg_tuplefielddef_t denyaliases_fields[] = { 1314 { "name", &cfg_type_namelist, 0 }, 1315 { "except-from", &cfg_type_optional_exceptionnames, 0 }, 1316 { NULL, NULL, 0 } 1317 }; 1318 1319 static cfg_type_t cfg_type_denyaliases = { 1320 "denyaliases", cfg_parse_tuple, cfg_print_tuple, 1321 cfg_doc_tuple, &cfg_rep_tuple, denyaliases_fields 1322 }; 1323 1324 static cfg_type_t cfg_type_algorithmlist = { "algorithmlist", 1325 cfg_parse_bracketed_list, 1326 cfg_print_bracketed_list, 1327 cfg_doc_bracketed_list, 1328 &cfg_rep_list, 1329 &cfg_type_astring }; 1330 1331 static cfg_tuplefielddef_t disablealgorithm_fields[] = { 1332 { "name", &cfg_type_astring, 0 }, 1333 { "algorithms", &cfg_type_algorithmlist, 0 }, 1334 { NULL, NULL, 0 } 1335 }; 1336 1337 static cfg_type_t cfg_type_disablealgorithm = { 1338 "disablealgorithm", cfg_parse_tuple, cfg_print_tuple, 1339 cfg_doc_tuple, &cfg_rep_tuple, disablealgorithm_fields 1340 }; 1341 1342 static cfg_type_t cfg_type_dsdigestlist = { "dsdigestlist", 1343 cfg_parse_bracketed_list, 1344 cfg_print_bracketed_list, 1345 cfg_doc_bracketed_list, 1346 &cfg_rep_list, 1347 &cfg_type_astring }; 1348 1349 static cfg_tuplefielddef_t disabledsdigest_fields[] = { 1350 { "name", &cfg_type_astring, 0 }, 1351 { "digests", &cfg_type_dsdigestlist, 0 }, 1352 { NULL, NULL, 0 } 1353 }; 1354 1355 static cfg_type_t cfg_type_disabledsdigest = { 1356 "disabledsdigest", cfg_parse_tuple, cfg_print_tuple, 1357 cfg_doc_tuple, &cfg_rep_tuple, disabledsdigest_fields 1358 }; 1359 1360 static cfg_tuplefielddef_t mustbesecure_fields[] = { 1361 { "name", &cfg_type_astring, 0 }, 1362 { "value", &cfg_type_boolean, 0 }, 1363 { NULL, NULL, 0 } 1364 }; 1365 1366 static cfg_type_t cfg_type_mustbesecure = { 1367 "mustbesecure", cfg_parse_tuple, cfg_print_tuple, 1368 cfg_doc_tuple, &cfg_rep_tuple, mustbesecure_fields 1369 }; 1370 1371 static const char *masterformat_enums[] = { "map", "raw", "text", NULL }; 1372 static cfg_type_t cfg_type_masterformat = { 1373 "masterformat", cfg_parse_enum, cfg_print_ustring, 1374 cfg_doc_enum, &cfg_rep_string, &masterformat_enums 1375 }; 1376 1377 static const char *masterstyle_enums[] = { "full", "relative", NULL }; 1378 static cfg_type_t cfg_type_masterstyle = { 1379 "masterstyle", cfg_parse_enum, cfg_print_ustring, 1380 cfg_doc_enum, &cfg_rep_string, &masterstyle_enums 1381 }; 1382 1383 static keyword_type_t blocksize_kw = { "block-size", &cfg_type_uint32 }; 1384 1385 static cfg_type_t cfg_type_blocksize = { "blocksize", parse_keyvalue, 1386 print_keyvalue, doc_keyvalue, 1387 &cfg_rep_uint32, &blocksize_kw }; 1388 1389 static cfg_tuplefielddef_t resppadding_fields[] = { 1390 { "acl", &cfg_type_bracketed_aml, 0 }, 1391 { "block-size", &cfg_type_blocksize, 0 }, 1392 { NULL, NULL, 0 } 1393 }; 1394 1395 static cfg_type_t cfg_type_resppadding = { 1396 "resppadding", cfg_parse_tuple, cfg_print_tuple, 1397 cfg_doc_tuple, &cfg_rep_tuple, resppadding_fields 1398 }; 1399 1400 /*% 1401 * dnstap { 1402 * <message type> [query | response] ; 1403 * ... 1404 * } 1405 * 1406 * ... where message type is one of: client, resolver, auth, forwarder, 1407 * update, all 1408 */ 1409 static const char *dnstap_types[] = { "all", "auth", "client", 1410 "forwarder", "resolver", "update", 1411 NULL }; 1412 1413 static const char *dnstap_modes[] = { "query", "response", NULL }; 1414 1415 static cfg_type_t cfg_type_dnstap_type = { "dnstap_type", cfg_parse_enum, 1416 cfg_print_ustring, cfg_doc_enum, 1417 &cfg_rep_string, dnstap_types }; 1418 1419 static cfg_type_t cfg_type_dnstap_mode = { 1420 "dnstap_mode", parse_optional_enum, cfg_print_ustring, 1421 doc_optional_enum, &cfg_rep_string, dnstap_modes 1422 }; 1423 1424 static cfg_tuplefielddef_t dnstap_fields[] = { 1425 { "type", &cfg_type_dnstap_type, 0 }, 1426 { "mode", &cfg_type_dnstap_mode, 0 }, 1427 { NULL, NULL, 0 } 1428 }; 1429 1430 static cfg_type_t cfg_type_dnstap_entry = { "dnstap_value", cfg_parse_tuple, 1431 cfg_print_tuple, cfg_doc_tuple, 1432 &cfg_rep_tuple, dnstap_fields }; 1433 1434 static cfg_type_t cfg_type_dnstap = { "dnstap", 1435 cfg_parse_bracketed_list, 1436 cfg_print_bracketed_list, 1437 cfg_doc_bracketed_list, 1438 &cfg_rep_list, 1439 &cfg_type_dnstap_entry }; 1440 1441 /*% 1442 * dnstap-output 1443 */ 1444 static isc_result_t 1445 parse_dtout(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1446 isc_result_t result; 1447 cfg_obj_t *obj = NULL; 1448 const cfg_tuplefielddef_t *fields = type->of; 1449 1450 CHECK(cfg_create_tuple(pctx, type, &obj)); 1451 1452 /* Parse the mandatory "mode" and "path" fields */ 1453 CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0])); 1454 CHECK(cfg_parse_obj(pctx, fields[1].type, &obj->value.tuple[1])); 1455 1456 /* Parse "versions" and "size" fields in any order. */ 1457 for (;;) { 1458 CHECK(cfg_peektoken(pctx, 0)); 1459 if (pctx->token.type == isc_tokentype_string) { 1460 CHECK(cfg_gettoken(pctx, 0)); 1461 if (strcasecmp(TOKEN_STRING(pctx), "size") == 0 && 1462 obj->value.tuple[2] == NULL) 1463 { 1464 CHECK(cfg_parse_obj(pctx, fields[2].type, 1465 &obj->value.tuple[2])); 1466 } else if (strcasecmp(TOKEN_STRING(pctx), "versions") == 1467 0 && 1468 obj->value.tuple[3] == NULL) 1469 { 1470 CHECK(cfg_parse_obj(pctx, fields[3].type, 1471 &obj->value.tuple[3])); 1472 } else if (strcasecmp(TOKEN_STRING(pctx), "suffix") == 1473 0 && 1474 obj->value.tuple[4] == NULL) 1475 { 1476 CHECK(cfg_parse_obj(pctx, fields[4].type, 1477 &obj->value.tuple[4])); 1478 } else { 1479 cfg_parser_error(pctx, CFG_LOG_NEAR, 1480 "unexpected token"); 1481 result = ISC_R_UNEXPECTEDTOKEN; 1482 goto cleanup; 1483 } 1484 } else { 1485 break; 1486 } 1487 } 1488 1489 /* Create void objects for missing optional values. */ 1490 if (obj->value.tuple[2] == NULL) { 1491 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2])); 1492 } 1493 if (obj->value.tuple[3] == NULL) { 1494 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[3])); 1495 } 1496 if (obj->value.tuple[4] == NULL) { 1497 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[4])); 1498 } 1499 1500 *ret = obj; 1501 return (ISC_R_SUCCESS); 1502 1503 cleanup: 1504 CLEANUP_OBJ(obj); 1505 return (result); 1506 } 1507 1508 static void 1509 print_dtout(cfg_printer_t *pctx, const cfg_obj_t *obj) { 1510 cfg_print_obj(pctx, obj->value.tuple[0]); /* mode */ 1511 cfg_print_obj(pctx, obj->value.tuple[1]); /* file */ 1512 if (obj->value.tuple[2]->type->print != cfg_print_void) { 1513 cfg_print_cstr(pctx, " size "); 1514 cfg_print_obj(pctx, obj->value.tuple[2]); 1515 } 1516 if (obj->value.tuple[3]->type->print != cfg_print_void) { 1517 cfg_print_cstr(pctx, " versions "); 1518 cfg_print_obj(pctx, obj->value.tuple[3]); 1519 } 1520 if (obj->value.tuple[4]->type->print != cfg_print_void) { 1521 cfg_print_cstr(pctx, " suffix "); 1522 cfg_print_obj(pctx, obj->value.tuple[4]); 1523 } 1524 } 1525 1526 static void 1527 doc_dtout(cfg_printer_t *pctx, const cfg_type_t *type) { 1528 UNUSED(type); 1529 cfg_print_cstr(pctx, "( file | unix ) <quoted_string>"); 1530 cfg_print_cstr(pctx, " "); 1531 cfg_print_cstr(pctx, "[ size ( unlimited | <size> ) ]"); 1532 cfg_print_cstr(pctx, " "); 1533 cfg_print_cstr(pctx, "[ versions ( unlimited | <integer> ) ]"); 1534 cfg_print_cstr(pctx, " "); 1535 cfg_print_cstr(pctx, "[ suffix ( increment | timestamp ) ]"); 1536 } 1537 1538 static const char *dtoutmode_enums[] = { "file", "unix", NULL }; 1539 static cfg_type_t cfg_type_dtmode = { "dtmode", cfg_parse_enum, 1540 cfg_print_ustring, cfg_doc_enum, 1541 &cfg_rep_string, &dtoutmode_enums }; 1542 1543 static cfg_tuplefielddef_t dtout_fields[] = { 1544 { "mode", &cfg_type_dtmode, 0 }, 1545 { "path", &cfg_type_qstring, 0 }, 1546 { "size", &cfg_type_sizenodefault, 0 }, 1547 { "versions", &cfg_type_logversions, 0 }, 1548 { "suffix", &cfg_type_logsuffix, 0 }, 1549 { NULL, NULL, 0 } 1550 }; 1551 1552 static cfg_type_t cfg_type_dnstapoutput = { "dnstapoutput", parse_dtout, 1553 print_dtout, doc_dtout, 1554 &cfg_rep_tuple, dtout_fields }; 1555 1556 /*% 1557 * response-policy { 1558 * zone <string> [ policy (given|disabled|passthru|drop|tcp-only| 1559 * nxdomain|nodata|cname <domain> ) ] 1560 * [ recursive-only yes|no ] [ log yes|no ] 1561 * [ max-policy-ttl number ] 1562 * [ nsip-enable yes|no ] [ nsdname-enable yes|no ]; 1563 * } [ recursive-only yes|no ] [ max-policy-ttl number ] 1564 * [ min-update-interval number ] 1565 * [ break-dnssec yes|no ] [ min-ns-dots number ] 1566 * [ qname-wait-recurse yes|no ] 1567 * [ nsip-enable yes|no ] [ nsdname-enable yes|no ] 1568 * [ dnsrps-enable yes|no ] 1569 * [ dnsrps-options { DNSRPS configuration string } ]; 1570 */ 1571 1572 static void 1573 doc_rpz_policy(cfg_printer_t *pctx, const cfg_type_t *type) { 1574 const char *const *p; 1575 /* 1576 * This is cfg_doc_enum() without the trailing " )". 1577 */ 1578 cfg_print_cstr(pctx, "( "); 1579 for (p = type->of; *p != NULL; p++) { 1580 cfg_print_cstr(pctx, *p); 1581 if (p[1] != NULL) { 1582 cfg_print_cstr(pctx, " | "); 1583 } 1584 } 1585 } 1586 1587 static void 1588 doc_rpz_cname(cfg_printer_t *pctx, const cfg_type_t *type) { 1589 cfg_doc_terminal(pctx, type); 1590 cfg_print_cstr(pctx, " )"); 1591 } 1592 1593 /* 1594 * Parse 1595 * given|disabled|passthru|drop|tcp-only|nxdomain|nodata|cname <domain> 1596 */ 1597 static isc_result_t 1598 cfg_parse_rpz_policy(cfg_parser_t *pctx, const cfg_type_t *type, 1599 cfg_obj_t **ret) { 1600 isc_result_t result; 1601 cfg_obj_t *obj = NULL; 1602 const cfg_tuplefielddef_t *fields; 1603 1604 CHECK(cfg_create_tuple(pctx, type, &obj)); 1605 1606 fields = type->of; 1607 CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0])); 1608 /* 1609 * parse cname domain only after "policy cname" 1610 */ 1611 if (strcasecmp("cname", cfg_obj_asstring(obj->value.tuple[0])) != 0) { 1612 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1])); 1613 } else { 1614 CHECK(cfg_parse_obj(pctx, fields[1].type, 1615 &obj->value.tuple[1])); 1616 } 1617 1618 *ret = obj; 1619 return (ISC_R_SUCCESS); 1620 1621 cleanup: 1622 CLEANUP_OBJ(obj); 1623 return (result); 1624 } 1625 1626 /* 1627 * Parse a tuple consisting of any kind of required field followed 1628 * by 2 or more optional keyvalues that can be in any order. 1629 */ 1630 static isc_result_t 1631 cfg_parse_kv_tuple(cfg_parser_t *pctx, const cfg_type_t *type, 1632 cfg_obj_t **ret) { 1633 const cfg_tuplefielddef_t *fields, *f; 1634 cfg_obj_t *obj = NULL; 1635 int fn; 1636 isc_result_t result; 1637 1638 CHECK(cfg_create_tuple(pctx, type, &obj)); 1639 1640 /* 1641 * The zone first field is required and always first. 1642 */ 1643 fields = type->of; 1644 CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0])); 1645 1646 for (;;) { 1647 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); 1648 if (pctx->token.type != isc_tokentype_string) { 1649 break; 1650 } 1651 1652 for (fn = 1, f = &fields[1];; ++fn, ++f) { 1653 if (f->name == NULL) { 1654 cfg_parser_error(pctx, 0, "unexpected '%s'", 1655 TOKEN_STRING(pctx)); 1656 result = ISC_R_UNEXPECTEDTOKEN; 1657 goto cleanup; 1658 } 1659 if (obj->value.tuple[fn] == NULL && 1660 strcasecmp(f->name, TOKEN_STRING(pctx)) == 0) 1661 { 1662 break; 1663 } 1664 } 1665 1666 CHECK(cfg_gettoken(pctx, 0)); 1667 CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[fn])); 1668 } 1669 1670 for (fn = 1, f = &fields[1]; f->name != NULL; ++fn, ++f) { 1671 if (obj->value.tuple[fn] == NULL) { 1672 CHECK(cfg_parse_void(pctx, NULL, 1673 &obj->value.tuple[fn])); 1674 } 1675 } 1676 1677 *ret = obj; 1678 return (ISC_R_SUCCESS); 1679 1680 cleanup: 1681 CLEANUP_OBJ(obj); 1682 return (result); 1683 } 1684 1685 static void 1686 cfg_print_kv_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) { 1687 unsigned int i; 1688 const cfg_tuplefielddef_t *fields, *f; 1689 const cfg_obj_t *fieldobj; 1690 1691 fields = obj->type->of; 1692 for (f = fields, i = 0; f->name != NULL; f++, i++) { 1693 fieldobj = obj->value.tuple[i]; 1694 if (fieldobj->type->print == cfg_print_void) { 1695 continue; 1696 } 1697 if (i != 0) { 1698 cfg_print_cstr(pctx, " "); 1699 cfg_print_cstr(pctx, f->name); 1700 cfg_print_cstr(pctx, " "); 1701 } 1702 cfg_print_obj(pctx, fieldobj); 1703 } 1704 } 1705 1706 static void 1707 cfg_doc_kv_tuple(cfg_printer_t *pctx, const cfg_type_t *type) { 1708 const cfg_tuplefielddef_t *fields, *f; 1709 1710 fields = type->of; 1711 for (f = fields; f->name != NULL; f++) { 1712 if (f != fields) { 1713 cfg_print_cstr(pctx, " [ "); 1714 cfg_print_cstr(pctx, f->name); 1715 if (f->type->doc != cfg_doc_void) { 1716 cfg_print_cstr(pctx, " "); 1717 } 1718 } 1719 cfg_doc_obj(pctx, f->type); 1720 if (f != fields) { 1721 cfg_print_cstr(pctx, " ]"); 1722 } 1723 } 1724 } 1725 1726 static keyword_type_t zone_kw = { "zone", &cfg_type_astring }; 1727 static cfg_type_t cfg_type_rpz_zone = { "zone", parse_keyvalue, 1728 print_keyvalue, doc_keyvalue, 1729 &cfg_rep_string, &zone_kw }; 1730 /* 1731 * "no-op" is an obsolete equivalent of "passthru". 1732 */ 1733 static const char *rpz_policies[] = { "cname", "disabled", "drop", 1734 "given", "no-op", "nodata", 1735 "nxdomain", "passthru", "tcp-only", 1736 NULL }; 1737 static cfg_type_t cfg_type_rpz_policy_name = { 1738 "policy name", cfg_parse_enum, cfg_print_ustring, 1739 doc_rpz_policy, &cfg_rep_string, &rpz_policies 1740 }; 1741 static cfg_type_t cfg_type_rpz_cname = { 1742 "quoted_string", cfg_parse_astring, NULL, 1743 doc_rpz_cname, &cfg_rep_string, NULL 1744 }; 1745 static cfg_tuplefielddef_t rpz_policy_fields[] = { 1746 { "policy name", &cfg_type_rpz_policy_name, 0 }, 1747 { "cname", &cfg_type_rpz_cname, 0 }, 1748 { NULL, NULL, 0 } 1749 }; 1750 static cfg_type_t cfg_type_rpz_policy = { "policy tuple", cfg_parse_rpz_policy, 1751 cfg_print_tuple, cfg_doc_tuple, 1752 &cfg_rep_tuple, rpz_policy_fields }; 1753 static cfg_tuplefielddef_t rpz_zone_fields[] = { 1754 { "zone name", &cfg_type_rpz_zone, 0 }, 1755 { "add-soa", &cfg_type_boolean, 0 }, 1756 { "log", &cfg_type_boolean, 0 }, 1757 { "max-policy-ttl", &cfg_type_duration, 0 }, 1758 { "min-update-interval", &cfg_type_duration, 0 }, 1759 { "policy", &cfg_type_rpz_policy, 0 }, 1760 { "recursive-only", &cfg_type_boolean, 0 }, 1761 { "nsip-enable", &cfg_type_boolean, 0 }, 1762 { "nsdname-enable", &cfg_type_boolean, 0 }, 1763 { NULL, NULL, 0 } 1764 }; 1765 static cfg_type_t cfg_type_rpz_tuple = { "rpz tuple", cfg_parse_kv_tuple, 1766 cfg_print_kv_tuple, cfg_doc_kv_tuple, 1767 &cfg_rep_tuple, rpz_zone_fields }; 1768 static cfg_type_t cfg_type_rpz_list = { "zone list", 1769 cfg_parse_bracketed_list, 1770 cfg_print_bracketed_list, 1771 cfg_doc_bracketed_list, 1772 &cfg_rep_list, 1773 &cfg_type_rpz_tuple }; 1774 static cfg_tuplefielddef_t rpz_fields[] = { 1775 { "zone list", &cfg_type_rpz_list, 0 }, 1776 { "add-soa", &cfg_type_boolean, 0 }, 1777 { "break-dnssec", &cfg_type_boolean, 0 }, 1778 { "max-policy-ttl", &cfg_type_duration, 0 }, 1779 { "min-update-interval", &cfg_type_duration, 0 }, 1780 { "min-ns-dots", &cfg_type_uint32, 0 }, 1781 { "nsip-wait-recurse", &cfg_type_boolean, 0 }, 1782 { "qname-wait-recurse", &cfg_type_boolean, 0 }, 1783 { "recursive-only", &cfg_type_boolean, 0 }, 1784 { "nsip-enable", &cfg_type_boolean, 0 }, 1785 { "nsdname-enable", &cfg_type_boolean, 0 }, 1786 #ifdef USE_DNSRPS 1787 { "dnsrps-enable", &cfg_type_boolean, 0 }, 1788 { "dnsrps-options", &cfg_type_bracketed_text, 0 }, 1789 #else /* ifdef USE_DNSRPS */ 1790 { "dnsrps-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTCONFIGURED }, 1791 { "dnsrps-options", &cfg_type_bracketed_text, 1792 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1793 #endif /* ifdef USE_DNSRPS */ 1794 { NULL, NULL, 0 } 1795 }; 1796 static cfg_type_t cfg_type_rpz = { "rpz", 1797 cfg_parse_kv_tuple, 1798 cfg_print_kv_tuple, 1799 cfg_doc_kv_tuple, 1800 &cfg_rep_tuple, 1801 rpz_fields }; 1802 1803 /* 1804 * Catalog zones 1805 */ 1806 static cfg_type_t cfg_type_catz_zone = { "zone", parse_keyvalue, 1807 print_keyvalue, doc_keyvalue, 1808 &cfg_rep_string, &zone_kw }; 1809 1810 static cfg_tuplefielddef_t catz_zone_fields[] = { 1811 { "zone name", &cfg_type_catz_zone, 0 }, 1812 { "default-masters", &cfg_type_namesockaddrkeylist, 0 }, 1813 { "zone-directory", &cfg_type_qstring, 0 }, 1814 { "in-memory", &cfg_type_boolean, 0 }, 1815 { "min-update-interval", &cfg_type_duration, 0 }, 1816 { NULL, NULL, 0 } 1817 }; 1818 static cfg_type_t cfg_type_catz_tuple = { 1819 "catz tuple", cfg_parse_kv_tuple, cfg_print_kv_tuple, 1820 cfg_doc_kv_tuple, &cfg_rep_tuple, catz_zone_fields 1821 }; 1822 static cfg_type_t cfg_type_catz_list = { "zone list", 1823 cfg_parse_bracketed_list, 1824 cfg_print_bracketed_list, 1825 cfg_doc_bracketed_list, 1826 &cfg_rep_list, 1827 &cfg_type_catz_tuple }; 1828 static cfg_tuplefielddef_t catz_fields[] = { 1829 { "zone list", &cfg_type_catz_list, 0 }, { NULL, NULL, 0 } 1830 }; 1831 static cfg_type_t cfg_type_catz = { 1832 "catz", cfg_parse_kv_tuple, cfg_print_kv_tuple, 1833 cfg_doc_kv_tuple, &cfg_rep_tuple, catz_fields 1834 }; 1835 1836 /* 1837 * rate-limit 1838 */ 1839 static cfg_clausedef_t rrl_clauses[] = { 1840 { "all-per-second", &cfg_type_uint32, 0 }, 1841 { "errors-per-second", &cfg_type_uint32, 0 }, 1842 { "exempt-clients", &cfg_type_bracketed_aml, 0 }, 1843 { "ipv4-prefix-length", &cfg_type_uint32, 0 }, 1844 { "ipv6-prefix-length", &cfg_type_uint32, 0 }, 1845 { "log-only", &cfg_type_boolean, 0 }, 1846 { "max-table-size", &cfg_type_uint32, 0 }, 1847 { "min-table-size", &cfg_type_uint32, 0 }, 1848 { "nodata-per-second", &cfg_type_uint32, 0 }, 1849 { "nxdomains-per-second", &cfg_type_uint32, 0 }, 1850 { "qps-scale", &cfg_type_uint32, 0 }, 1851 { "referrals-per-second", &cfg_type_uint32, 0 }, 1852 { "responses-per-second", &cfg_type_uint32, 0 }, 1853 { "slip", &cfg_type_uint32, 0 }, 1854 { "window", &cfg_type_uint32, 0 }, 1855 { NULL, NULL, 0 } 1856 }; 1857 1858 static cfg_clausedef_t *rrl_clausesets[] = { rrl_clauses, NULL }; 1859 1860 static cfg_type_t cfg_type_rrl = { "rate-limit", cfg_parse_map, cfg_print_map, 1861 cfg_doc_map, &cfg_rep_map, rrl_clausesets }; 1862 1863 /*% 1864 * dnssec-lookaside 1865 */ 1866 1867 static void 1868 print_lookaside(cfg_printer_t *pctx, const cfg_obj_t *obj) { 1869 const cfg_obj_t *domain = obj->value.tuple[0]; 1870 1871 if (domain->value.string.length == 4 && 1872 strncmp(domain->value.string.base, "auto", 4) == 0) 1873 { 1874 cfg_print_cstr(pctx, "auto"); 1875 } else { 1876 cfg_print_tuple(pctx, obj); 1877 } 1878 } 1879 1880 static void 1881 doc_lookaside(cfg_printer_t *pctx, const cfg_type_t *type) { 1882 UNUSED(type); 1883 cfg_print_cstr(pctx, "( <string> trust-anchor <string> | auto | no )"); 1884 } 1885 1886 static keyword_type_t trustanchor_kw = { "trust-anchor", &cfg_type_astring }; 1887 1888 static cfg_type_t cfg_type_optional_trustanchor = { 1889 "optional_trustanchor", parse_optional_keyvalue, print_keyvalue, 1890 doc_keyvalue, &cfg_rep_string, &trustanchor_kw 1891 }; 1892 1893 static cfg_tuplefielddef_t lookaside_fields[] = { 1894 { "domain", &cfg_type_astring, 0 }, 1895 { "trust-anchor", &cfg_type_optional_trustanchor, 0 }, 1896 { NULL, NULL, 0 } 1897 }; 1898 1899 static cfg_type_t cfg_type_lookaside = { "lookaside", cfg_parse_tuple, 1900 print_lookaside, doc_lookaside, 1901 &cfg_rep_tuple, lookaside_fields }; 1902 1903 static isc_result_t 1904 parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type, 1905 cfg_obj_t **ret) { 1906 isc_result_t result; 1907 UNUSED(type); 1908 1909 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); 1910 if (pctx->token.type == isc_tokentype_number) { 1911 CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret)); 1912 } else { 1913 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret)); 1914 } 1915 cleanup: 1916 return (result); 1917 } 1918 1919 static void 1920 doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) { 1921 UNUSED(type); 1922 cfg_print_cstr(pctx, "[ <integer> ]"); 1923 } 1924 1925 static cfg_type_t cfg_type_optional_uint32 = { "optional_uint32", 1926 parse_optional_uint32, 1927 NULL, 1928 doc_optional_uint32, 1929 NULL, 1930 NULL }; 1931 1932 static cfg_tuplefielddef_t prefetch_fields[] = { 1933 { "trigger", &cfg_type_uint32, 0 }, 1934 { "eligible", &cfg_type_optional_uint32, 0 }, 1935 { NULL, NULL, 0 } 1936 }; 1937 1938 static cfg_type_t cfg_type_prefetch = { "prefetch", cfg_parse_tuple, 1939 cfg_print_tuple, cfg_doc_tuple, 1940 &cfg_rep_tuple, prefetch_fields }; 1941 /* 1942 * DNS64. 1943 */ 1944 static cfg_clausedef_t dns64_clauses[] = { 1945 { "break-dnssec", &cfg_type_boolean, 0 }, 1946 { "clients", &cfg_type_bracketed_aml, 0 }, 1947 { "exclude", &cfg_type_bracketed_aml, 0 }, 1948 { "mapped", &cfg_type_bracketed_aml, 0 }, 1949 { "recursive-only", &cfg_type_boolean, 0 }, 1950 { "suffix", &cfg_type_netaddr6, 0 }, 1951 { NULL, NULL, 0 }, 1952 }; 1953 1954 static cfg_clausedef_t *dns64_clausesets[] = { dns64_clauses, NULL }; 1955 1956 static cfg_type_t cfg_type_dns64 = { "dns64", cfg_parse_netprefix_map, 1957 cfg_print_map, cfg_doc_map, 1958 &cfg_rep_map, dns64_clausesets }; 1959 1960 static const char *staleanswerclienttimeout_enums[] = { "disabled", "off", 1961 NULL }; 1962 static isc_result_t 1963 parse_staleanswerclienttimeout(cfg_parser_t *pctx, const cfg_type_t *type, 1964 cfg_obj_t **ret) { 1965 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_uint32, ret)); 1966 } 1967 1968 static void 1969 doc_staleanswerclienttimeout(cfg_printer_t *pctx, const cfg_type_t *type) { 1970 cfg_doc_enum_or_other(pctx, type, &cfg_type_uint32); 1971 } 1972 1973 static cfg_type_t cfg_type_staleanswerclienttimeout = { 1974 "staleanswerclienttimeout", 1975 parse_staleanswerclienttimeout, 1976 cfg_print_ustring, 1977 doc_staleanswerclienttimeout, 1978 &cfg_rep_string, 1979 staleanswerclienttimeout_enums 1980 }; 1981 1982 /*% 1983 * Clauses that can be found within the 'view' statement, 1984 * with defaults in the 'options' statement. 1985 */ 1986 1987 static cfg_clausedef_t view_clauses[] = { 1988 { "acache-cleaning-interval", &cfg_type_uint32, 1989 CFG_CLAUSEFLAG_OBSOLETE }, 1990 { "acache-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 1991 { "additional-from-auth", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 1992 { "additional-from-cache", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 1993 { "allow-new-zones", &cfg_type_boolean, 0 }, 1994 { "allow-query-cache", &cfg_type_bracketed_aml, 0 }, 1995 { "allow-query-cache-on", &cfg_type_bracketed_aml, 0 }, 1996 { "allow-recursion", &cfg_type_bracketed_aml, 0 }, 1997 { "allow-recursion-on", &cfg_type_bracketed_aml, 0 }, 1998 { "allow-v6-synthesis", &cfg_type_bracketed_aml, 1999 CFG_CLAUSEFLAG_OBSOLETE }, 2000 { "attach-cache", &cfg_type_astring, 0 }, 2001 { "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT }, 2002 { "cache-file", &cfg_type_qstring, CFG_CLAUSEFLAG_DEPRECATED }, 2003 { "catalog-zones", &cfg_type_catz, 0 }, 2004 { "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI }, 2005 { "cleaning-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE }, 2006 { "clients-per-query", &cfg_type_uint32, 0 }, 2007 { "deny-answer-addresses", &cfg_type_denyaddresses, 0 }, 2008 { "deny-answer-aliases", &cfg_type_denyaliases, 0 }, 2009 { "disable-algorithms", &cfg_type_disablealgorithm, 2010 CFG_CLAUSEFLAG_MULTI }, 2011 { "disable-ds-digests", &cfg_type_disabledsdigest, 2012 CFG_CLAUSEFLAG_MULTI }, 2013 { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI }, 2014 { "dns64", &cfg_type_dns64, CFG_CLAUSEFLAG_MULTI }, 2015 { "dns64-contact", &cfg_type_astring, 0 }, 2016 { "dns64-server", &cfg_type_astring, 0 }, 2017 #ifdef USE_DNSRPS 2018 { "dnsrps-enable", &cfg_type_boolean, 0 }, 2019 { "dnsrps-options", &cfg_type_bracketed_text, 0 }, 2020 #else /* ifdef USE_DNSRPS */ 2021 { "dnsrps-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTCONFIGURED }, 2022 { "dnsrps-options", &cfg_type_bracketed_text, 2023 CFG_CLAUSEFLAG_NOTCONFIGURED }, 2024 #endif /* ifdef USE_DNSRPS */ 2025 { "dnssec-accept-expired", &cfg_type_boolean, 0 }, 2026 { "dnssec-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 2027 { "dnssec-lookaside", &cfg_type_lookaside, 2028 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE }, 2029 { "dnssec-must-be-secure", &cfg_type_mustbesecure, 2030 CFG_CLAUSEFLAG_MULTI }, 2031 { "dnssec-validation", &cfg_type_boolorauto, 0 }, 2032 #ifdef HAVE_DNSTAP 2033 { "dnstap", &cfg_type_dnstap, 0 }, 2034 #else /* ifdef HAVE_DNSTAP */ 2035 { "dnstap", &cfg_type_dnstap, CFG_CLAUSEFLAG_NOTCONFIGURED }, 2036 #endif /* HAVE_DNSTAP */ 2037 { "dual-stack-servers", &cfg_type_nameportiplist, 0 }, 2038 { "edns-udp-size", &cfg_type_uint32, 0 }, 2039 { "empty-contact", &cfg_type_astring, 0 }, 2040 { "empty-server", &cfg_type_astring, 0 }, 2041 { "empty-zones-enable", &cfg_type_boolean, 0 }, 2042 { "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 2043 { "fetch-quota-params", &cfg_type_fetchquota, 0 }, 2044 { "fetches-per-server", &cfg_type_fetchesper, 0 }, 2045 { "fetches-per-zone", &cfg_type_fetchesper, 0 }, 2046 { "filter-aaaa", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_OBSOLETE }, 2047 { "filter-aaaa-on-v4", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 2048 { "filter-aaaa-on-v6", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 2049 { "glue-cache", &cfg_type_boolean, 0 }, 2050 { "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 }, 2051 { "lame-ttl", &cfg_type_duration, 0 }, 2052 #ifdef HAVE_LMDB 2053 { "lmdb-mapsize", &cfg_type_sizeval, 0 }, 2054 #else /* ifdef HAVE_LMDB */ 2055 { "lmdb-mapsize", &cfg_type_sizeval, CFG_CLAUSEFLAG_NOOP }, 2056 #endif /* ifdef HAVE_LMDB */ 2057 { "max-acache-size", &cfg_type_sizenodefault, CFG_CLAUSEFLAG_OBSOLETE }, 2058 { "max-cache-size", &cfg_type_sizeorpercent, 0 }, 2059 { "max-cache-ttl", &cfg_type_duration, 0 }, 2060 { "max-clients-per-query", &cfg_type_uint32, 0 }, 2061 { "max-ncache-ttl", &cfg_type_duration, 0 }, 2062 { "max-recursion-depth", &cfg_type_uint32, 0 }, 2063 { "max-recursion-queries", &cfg_type_uint32, 0 }, 2064 { "max-stale-ttl", &cfg_type_duration, 0 }, 2065 { "max-udp-size", &cfg_type_uint32, 0 }, 2066 { "message-compression", &cfg_type_boolean, 0 }, 2067 { "min-cache-ttl", &cfg_type_duration, 0 }, 2068 { "min-ncache-ttl", &cfg_type_duration, 0 }, 2069 { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_ANCIENT }, 2070 { "minimal-any", &cfg_type_boolean, 0 }, 2071 { "minimal-responses", &cfg_type_minimal, 0 }, 2072 { "new-zones-directory", &cfg_type_qstring, 0 }, 2073 { "no-case-compress", &cfg_type_bracketed_aml, 0 }, 2074 { "nocookie-udp-size", &cfg_type_uint32, 0 }, 2075 { "nosit-udp-size", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE }, 2076 { "nta-lifetime", &cfg_type_duration, 0 }, 2077 { "nta-recheck", &cfg_type_duration, 0 }, 2078 { "nxdomain-redirect", &cfg_type_astring, 0 }, 2079 { "preferred-glue", &cfg_type_astring, 0 }, 2080 { "prefetch", &cfg_type_prefetch, 0 }, 2081 { "provide-ixfr", &cfg_type_boolean, 0 }, 2082 { "qname-minimization", &cfg_type_qminmethod, 0 }, 2083 /* 2084 * Note that the query-source option syntax is different 2085 * from the other -source options. 2086 */ 2087 { "query-source", &cfg_type_querysource4, 0 }, 2088 { "query-source-v6", &cfg_type_querysource6, 0 }, 2089 { "queryport-pool-ports", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE }, 2090 { "queryport-pool-updateinterval", &cfg_type_uint32, 2091 CFG_CLAUSEFLAG_OBSOLETE }, 2092 { "rate-limit", &cfg_type_rrl, 0 }, 2093 { "recursion", &cfg_type_boolean, 0 }, 2094 { "request-nsid", &cfg_type_boolean, 0 }, 2095 { "request-sit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 2096 { "require-server-cookie", &cfg_type_boolean, 0 }, 2097 { "resolver-nonbackoff-tries", &cfg_type_uint32, 0 }, 2098 { "resolver-query-timeout", &cfg_type_uint32, 0 }, 2099 { "resolver-retry-interval", &cfg_type_uint32, 0 }, 2100 { "response-padding", &cfg_type_resppadding, 0 }, 2101 { "response-policy", &cfg_type_rpz, 0 }, 2102 { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 2103 { "root-delegation-only", &cfg_type_optional_exclude, 0 }, 2104 { "root-key-sentinel", &cfg_type_boolean, 0 }, 2105 { "rrset-order", &cfg_type_rrsetorder, 0 }, 2106 { "send-cookie", &cfg_type_boolean, 0 }, 2107 { "servfail-ttl", &cfg_type_duration, 0 }, 2108 { "sortlist", &cfg_type_bracketed_aml, 0 }, 2109 { "stale-answer-enable", &cfg_type_boolean, 0 }, 2110 { "stale-answer-client-timeout", &cfg_type_staleanswerclienttimeout, 2111 0 }, 2112 { "stale-answer-ttl", &cfg_type_duration, 0 }, 2113 { "stale-cache-enable", &cfg_type_boolean, 0 }, 2114 { "stale-refresh-time", &cfg_type_duration, 0 }, 2115 { "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI }, 2116 { "synth-from-dnssec", &cfg_type_boolean, 0 }, 2117 { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_ANCIENT }, 2118 { "transfer-format", &cfg_type_transferformat, 0 }, 2119 { "trust-anchor-telemetry", &cfg_type_boolean, 2120 CFG_CLAUSEFLAG_EXPERIMENTAL }, 2121 { "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 2122 { "validate-except", &cfg_type_namelist, 0 }, 2123 { "v6-bias", &cfg_type_uint32, 0 }, 2124 { "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 }, 2125 { NULL, NULL, 0 } 2126 }; 2127 2128 /*% 2129 * Clauses that can be found within the 'view' statement only. 2130 */ 2131 static cfg_clausedef_t view_only_clauses[] = { 2132 { "match-clients", &cfg_type_bracketed_aml, 0 }, 2133 { "match-destinations", &cfg_type_bracketed_aml, 0 }, 2134 { "match-recursive-only", &cfg_type_boolean, 0 }, 2135 { NULL, NULL, 0 } 2136 }; 2137 2138 /*% 2139 * Sig-validity-interval. 2140 */ 2141 2142 static cfg_tuplefielddef_t validityinterval_fields[] = { 2143 { "validity", &cfg_type_uint32, 0 }, 2144 { "re-sign", &cfg_type_optional_uint32, 0 }, 2145 { NULL, NULL, 0 } 2146 }; 2147 2148 static cfg_type_t cfg_type_validityinterval = { 2149 "validityinterval", cfg_parse_tuple, cfg_print_tuple, 2150 cfg_doc_tuple, &cfg_rep_tuple, validityinterval_fields 2151 }; 2152 2153 /*% 2154 * Clauses that can be found in a 'dnssec-policy' statement. 2155 */ 2156 static cfg_clausedef_t dnssecpolicy_clauses[] = { 2157 { "dnskey-ttl", &cfg_type_duration, 0 }, 2158 { "keys", &cfg_type_kaspkeys, 0 }, 2159 { "max-zone-ttl", &cfg_type_duration, 0 }, 2160 { "nsec3param", &cfg_type_nsec3, 0 }, 2161 { "parent-ds-ttl", &cfg_type_duration, 0 }, 2162 { "parent-propagation-delay", &cfg_type_duration, 0 }, 2163 { "parent-registration-delay", &cfg_type_duration, 2164 CFG_CLAUSEFLAG_OBSOLETE }, 2165 { "publish-safety", &cfg_type_duration, 0 }, 2166 { "purge-keys", &cfg_type_duration, 0 }, 2167 { "retire-safety", &cfg_type_duration, 0 }, 2168 { "signatures-refresh", &cfg_type_duration, 0 }, 2169 { "signatures-validity", &cfg_type_duration, 0 }, 2170 { "signatures-validity-dnskey", &cfg_type_duration, 0 }, 2171 { "zone-propagation-delay", &cfg_type_duration, 0 }, 2172 { NULL, NULL, 0 } 2173 }; 2174 2175 /*% 2176 * Clauses that can be found in a 'zone' statement, 2177 * with defaults in the 'view' or 'options' statement. 2178 * 2179 * Note: CFG_ZONE_* options indicate in which zone types this clause is 2180 * legal. 2181 */ 2182 static cfg_clausedef_t zone_clauses[] = { 2183 { "allow-notify", &cfg_type_bracketed_aml, 2184 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2185 { "allow-query", &cfg_type_bracketed_aml, 2186 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | 2187 CFG_ZONE_STUB | CFG_ZONE_REDIRECT | CFG_ZONE_STATICSTUB }, 2188 { "allow-query-on", &cfg_type_bracketed_aml, 2189 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | 2190 CFG_ZONE_STUB | CFG_ZONE_REDIRECT | CFG_ZONE_STATICSTUB }, 2191 { "allow-transfer", &cfg_type_bracketed_aml, 2192 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2193 { "allow-update", &cfg_type_bracketed_aml, CFG_ZONE_PRIMARY }, 2194 { "allow-update-forwarding", &cfg_type_bracketed_aml, 2195 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2196 { "also-notify", &cfg_type_namesockaddrkeylist, 2197 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2198 { "alt-transfer-source", &cfg_type_sockaddr4wild, 2199 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2200 { "alt-transfer-source-v6", &cfg_type_sockaddr6wild, 2201 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2202 { "auto-dnssec", &cfg_type_autodnssec, 2203 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_CLAUSEFLAG_DEPRECATED }, 2204 { "check-dup-records", &cfg_type_checkmode, CFG_ZONE_PRIMARY }, 2205 { "check-integrity", &cfg_type_boolean, CFG_ZONE_PRIMARY }, 2206 { "check-mx", &cfg_type_checkmode, CFG_ZONE_PRIMARY }, 2207 { "check-mx-cname", &cfg_type_checkmode, CFG_ZONE_PRIMARY }, 2208 { "check-sibling", &cfg_type_boolean, CFG_ZONE_PRIMARY }, 2209 { "check-spf", &cfg_type_warn, CFG_ZONE_PRIMARY }, 2210 { "check-srv-cname", &cfg_type_checkmode, CFG_ZONE_PRIMARY }, 2211 { "check-wildcard", &cfg_type_boolean, CFG_ZONE_PRIMARY }, 2212 { "dialup", &cfg_type_dialuptype, 2213 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_STUB }, 2214 { "dnssec-dnskey-kskonly", &cfg_type_boolean, 2215 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2216 { "dnssec-loadkeys-interval", &cfg_type_uint32, 2217 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2218 { "dnssec-policy", &cfg_type_astring, 2219 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2220 { "dnssec-secure-to-insecure", &cfg_type_boolean, CFG_ZONE_PRIMARY }, 2221 { "dnssec-update-mode", &cfg_type_dnssecupdatemode, 2222 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2223 { "forward", &cfg_type_forwardtype, 2224 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_STUB | 2225 CFG_ZONE_STATICSTUB | CFG_ZONE_FORWARD }, 2226 { "forwarders", &cfg_type_portiplist, 2227 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_STUB | 2228 CFG_ZONE_STATICSTUB | CFG_ZONE_FORWARD }, 2229 { "key-directory", &cfg_type_qstring, 2230 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2231 { "maintain-ixfr-base", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 2232 { "masterfile-format", &cfg_type_masterformat, 2233 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | 2234 CFG_ZONE_STUB | CFG_ZONE_REDIRECT }, 2235 { "masterfile-style", &cfg_type_masterstyle, 2236 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | 2237 CFG_ZONE_STUB | CFG_ZONE_REDIRECT }, 2238 { "max-ixfr-log-size", &cfg_type_size, CFG_CLAUSEFLAG_ANCIENT }, 2239 { "max-ixfr-ratio", &cfg_type_ixfrratio, 2240 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2241 { "max-journal-size", &cfg_type_size, 2242 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2243 { "max-records", &cfg_type_uint32, 2244 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | 2245 CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT }, 2246 { "max-refresh-time", &cfg_type_uint32, 2247 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB }, 2248 { "max-retry-time", &cfg_type_uint32, 2249 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB }, 2250 { "max-transfer-idle-in", &cfg_type_uint32, 2251 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB }, 2252 { "max-transfer-idle-out", &cfg_type_uint32, 2253 CFG_ZONE_PRIMARY | CFG_ZONE_MIRROR | CFG_ZONE_SECONDARY }, 2254 { "max-transfer-time-in", &cfg_type_uint32, 2255 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB }, 2256 { "max-transfer-time-out", &cfg_type_uint32, 2257 CFG_ZONE_PRIMARY | CFG_ZONE_MIRROR | CFG_ZONE_SECONDARY }, 2258 { "max-zone-ttl", &cfg_type_maxduration, 2259 CFG_ZONE_PRIMARY | CFG_ZONE_REDIRECT }, 2260 { "min-refresh-time", &cfg_type_uint32, 2261 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB }, 2262 { "min-retry-time", &cfg_type_uint32, 2263 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB }, 2264 { "multi-master", &cfg_type_boolean, 2265 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB }, 2266 { "notify", &cfg_type_notifytype, 2267 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2268 { "notify-delay", &cfg_type_uint32, 2269 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2270 { "notify-source", &cfg_type_sockaddr4wild, 2271 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2272 { "notify-source-v6", &cfg_type_sockaddr6wild, 2273 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2274 { "notify-to-soa", &cfg_type_boolean, 2275 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2276 { "nsec3-test-zone", &cfg_type_boolean, 2277 CFG_CLAUSEFLAG_TESTONLY | CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2278 { "parental-source", &cfg_type_sockaddr4wild, 2279 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2280 { "parental-source-v6", &cfg_type_sockaddr6wild, 2281 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2282 { "request-expire", &cfg_type_boolean, 2283 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2284 { "request-ixfr", &cfg_type_boolean, 2285 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2286 { "serial-update-method", &cfg_type_updatemethod, CFG_ZONE_PRIMARY }, 2287 { "sig-signing-nodes", &cfg_type_uint32, 2288 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2289 { "sig-signing-signatures", &cfg_type_uint32, 2290 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2291 { "sig-signing-type", &cfg_type_uint32, 2292 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2293 { "sig-validity-interval", &cfg_type_validityinterval, 2294 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2295 { "dnskey-sig-validity", &cfg_type_uint32, 2296 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2297 { "transfer-source", &cfg_type_sockaddr4wild, 2298 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB }, 2299 { "transfer-source-v6", &cfg_type_sockaddr6wild, 2300 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB }, 2301 { "try-tcp-refresh", &cfg_type_boolean, 2302 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2303 { "update-check-ksk", &cfg_type_boolean, 2304 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2305 { "use-alt-transfer-source", &cfg_type_boolean, 2306 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB }, 2307 { "zero-no-soa-ttl", &cfg_type_boolean, 2308 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2309 { "zone-statistics", &cfg_type_zonestat, 2310 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | 2311 CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT }, 2312 { NULL, NULL, 0 } 2313 }; 2314 2315 /*% 2316 * Clauses that can be found in a 'zone' statement only. 2317 * 2318 * Note: CFG_ZONE_* options indicate in which zone types this clause is 2319 * legal. 2320 */ 2321 static cfg_clausedef_t zone_only_clauses[] = { 2322 /* 2323 * Note that the format of the check-names option is different between 2324 * the zone options and the global/view options. Ugh. 2325 */ 2326 { "type", &cfg_type_zonetype, 2327 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | 2328 CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_DELEGATION | 2329 CFG_ZONE_HINT | CFG_ZONE_REDIRECT | CFG_ZONE_FORWARD }, 2330 { "check-names", &cfg_type_checkmode, 2331 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | 2332 CFG_ZONE_HINT | CFG_ZONE_STUB }, 2333 { "database", &cfg_type_astring, 2334 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | 2335 CFG_ZONE_STUB }, 2336 { "delegation-only", &cfg_type_boolean, 2337 CFG_ZONE_HINT | CFG_ZONE_STUB | CFG_ZONE_FORWARD }, 2338 { "dlz", &cfg_type_astring, 2339 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_REDIRECT }, 2340 { "file", &cfg_type_qstring, 2341 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | 2342 CFG_ZONE_STUB | CFG_ZONE_HINT | CFG_ZONE_REDIRECT }, 2343 { "in-view", &cfg_type_astring, CFG_ZONE_INVIEW }, 2344 { "inline-signing", &cfg_type_boolean, 2345 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2346 { "ixfr-base", &cfg_type_qstring, CFG_CLAUSEFLAG_ANCIENT }, 2347 { "ixfr-from-differences", &cfg_type_boolean, 2348 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2349 { "ixfr-tmp-file", &cfg_type_qstring, CFG_CLAUSEFLAG_ANCIENT }, 2350 { "journal", &cfg_type_qstring, 2351 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR }, 2352 { "masters", &cfg_type_namesockaddrkeylist, 2353 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB | 2354 CFG_ZONE_REDIRECT }, 2355 { "parental-agents", &cfg_type_namesockaddrkeylist, 2356 CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2357 { "primaries", &cfg_type_namesockaddrkeylist, 2358 CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB | 2359 CFG_ZONE_REDIRECT }, 2360 { "pubkey", &cfg_type_pubkey, CFG_CLAUSEFLAG_ANCIENT }, 2361 { "server-addresses", &cfg_type_bracketed_netaddrlist, 2362 CFG_ZONE_STATICSTUB }, 2363 { "server-names", &cfg_type_namelist, CFG_ZONE_STATICSTUB }, 2364 { "update-policy", &cfg_type_updatepolicy, CFG_ZONE_PRIMARY }, 2365 { NULL, NULL, 0 } 2366 }; 2367 2368 /*% The top-level named.conf syntax. */ 2369 2370 static cfg_clausedef_t *namedconf_clausesets[] = { namedconf_clauses, 2371 namedconf_or_view_clauses, 2372 NULL }; 2373 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = { 2374 "namedconf", cfg_parse_mapbody, cfg_print_mapbody, 2375 cfg_doc_mapbody, &cfg_rep_map, namedconf_clausesets 2376 }; 2377 2378 /*% The bind.keys syntax (trust-anchors/managed-keys/trusted-keys only). */ 2379 static cfg_clausedef_t *bindkeys_clausesets[] = { bindkeys_clauses, NULL }; 2380 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bindkeys = { 2381 "bindkeys", cfg_parse_mapbody, cfg_print_mapbody, 2382 cfg_doc_mapbody, &cfg_rep_map, bindkeys_clausesets 2383 }; 2384 2385 /*% The "options" statement syntax. */ 2386 2387 static cfg_clausedef_t *options_clausesets[] = { options_clauses, view_clauses, 2388 zone_clauses, NULL }; 2389 static cfg_type_t cfg_type_options = { "options", cfg_parse_map, 2390 cfg_print_map, cfg_doc_map, 2391 &cfg_rep_map, options_clausesets }; 2392 2393 /*% The "view" statement syntax. */ 2394 2395 static cfg_clausedef_t *view_clausesets[] = { view_only_clauses, 2396 namedconf_or_view_clauses, 2397 view_clauses, zone_clauses, 2398 NULL }; 2399 2400 static cfg_type_t cfg_type_viewopts = { "view", cfg_parse_map, 2401 cfg_print_map, cfg_doc_map, 2402 &cfg_rep_map, view_clausesets }; 2403 2404 /*% The "zone" statement syntax. */ 2405 2406 static cfg_clausedef_t *zone_clausesets[] = { zone_only_clauses, zone_clauses, 2407 NULL }; 2408 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_zoneopts = { 2409 "zoneopts", cfg_parse_map, cfg_print_map, 2410 cfg_doc_map, &cfg_rep_map, zone_clausesets 2411 }; 2412 2413 /*% The "dnssec-policy" statement syntax. */ 2414 static cfg_clausedef_t *dnssecpolicy_clausesets[] = { dnssecpolicy_clauses, 2415 NULL }; 2416 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_dnssecpolicyopts = { 2417 "dnssecpolicyopts", cfg_parse_map, cfg_print_map, 2418 cfg_doc_map, &cfg_rep_map, dnssecpolicy_clausesets 2419 }; 2420 2421 /*% The "dynamically loadable zones" statement syntax. */ 2422 2423 static cfg_clausedef_t dlz_clauses[] = { { "database", &cfg_type_astring, 0 }, 2424 { "search", &cfg_type_boolean, 0 }, 2425 { NULL, NULL, 0 } }; 2426 static cfg_clausedef_t *dlz_clausesets[] = { dlz_clauses, NULL }; 2427 static cfg_type_t cfg_type_dlz = { "dlz", cfg_parse_named_map, 2428 cfg_print_map, cfg_doc_map, 2429 &cfg_rep_map, dlz_clausesets }; 2430 2431 /*% 2432 * The "dyndb" statement syntax. 2433 */ 2434 2435 static cfg_tuplefielddef_t dyndb_fields[] = { 2436 { "name", &cfg_type_astring, 0 }, 2437 { "library", &cfg_type_qstring, 0 }, 2438 { "parameters", &cfg_type_bracketed_text, 0 }, 2439 { NULL, NULL, 0 } 2440 }; 2441 2442 static cfg_type_t cfg_type_dyndb = { "dyndb", cfg_parse_tuple, 2443 cfg_print_tuple, cfg_doc_tuple, 2444 &cfg_rep_tuple, dyndb_fields }; 2445 2446 /*% 2447 * The "plugin" statement syntax. 2448 * Currently only one plugin type is supported: query. 2449 */ 2450 2451 static const char *plugin_enums[] = { "query", NULL }; 2452 static cfg_type_t cfg_type_plugintype = { "plugintype", cfg_parse_enum, 2453 cfg_print_ustring, cfg_doc_enum, 2454 &cfg_rep_string, plugin_enums }; 2455 static cfg_tuplefielddef_t plugin_fields[] = { 2456 { "type", &cfg_type_plugintype, 0 }, 2457 { "library", &cfg_type_astring, 0 }, 2458 { "parameters", &cfg_type_optional_bracketed_text, 0 }, 2459 { NULL, NULL, 0 } 2460 }; 2461 static cfg_type_t cfg_type_plugin = { "plugin", cfg_parse_tuple, 2462 cfg_print_tuple, cfg_doc_tuple, 2463 &cfg_rep_tuple, plugin_fields }; 2464 2465 /*% 2466 * Clauses that can be found within the 'key' statement. 2467 */ 2468 static cfg_clausedef_t key_clauses[] = { { "algorithm", &cfg_type_astring, 0 }, 2469 { "secret", &cfg_type_sstring, 0 }, 2470 { NULL, NULL, 0 } }; 2471 2472 static cfg_clausedef_t *key_clausesets[] = { key_clauses, NULL }; 2473 static cfg_type_t cfg_type_key = { "key", cfg_parse_named_map, 2474 cfg_print_map, cfg_doc_map, 2475 &cfg_rep_map, key_clausesets }; 2476 2477 /*% 2478 * Clauses that can be found in a 'server' statement. 2479 */ 2480 static cfg_clausedef_t server_clauses[] = { 2481 { "bogus", &cfg_type_boolean, 0 }, 2482 { "edns", &cfg_type_boolean, 0 }, 2483 { "edns-udp-size", &cfg_type_uint32, 0 }, 2484 { "edns-version", &cfg_type_uint32, 0 }, 2485 { "keys", &cfg_type_server_key_kludge, 0 }, 2486 { "max-udp-size", &cfg_type_uint32, 0 }, 2487 { "notify-source", &cfg_type_sockaddr4wild, 0 }, 2488 { "notify-source-v6", &cfg_type_sockaddr6wild, 0 }, 2489 { "padding", &cfg_type_uint32, 0 }, 2490 { "provide-ixfr", &cfg_type_boolean, 0 }, 2491 { "query-source", &cfg_type_querysource4, 0 }, 2492 { "query-source-v6", &cfg_type_querysource6, 0 }, 2493 { "request-expire", &cfg_type_boolean, 0 }, 2494 { "request-ixfr", &cfg_type_boolean, 0 }, 2495 { "request-nsid", &cfg_type_boolean, 0 }, 2496 { "request-sit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 2497 { "send-cookie", &cfg_type_boolean, 0 }, 2498 { "support-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 2499 { "tcp-keepalive", &cfg_type_boolean, 0 }, 2500 { "tcp-only", &cfg_type_boolean, 0 }, 2501 { "transfer-format", &cfg_type_transferformat, 0 }, 2502 { "transfer-source", &cfg_type_sockaddr4wild, 0 }, 2503 { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 }, 2504 { "transfers", &cfg_type_uint32, 0 }, 2505 { NULL, NULL, 0 } 2506 }; 2507 static cfg_clausedef_t *server_clausesets[] = { server_clauses, NULL }; 2508 static cfg_type_t cfg_type_server = { "server", cfg_parse_netprefix_map, 2509 cfg_print_map, cfg_doc_map, 2510 &cfg_rep_map, server_clausesets }; 2511 2512 /*% 2513 * Clauses that can be found in a 'channel' clause in the 2514 * 'logging' statement. 2515 * 2516 * These have some additional constraints that need to be 2517 * checked after parsing: 2518 * - There must exactly one of file/syslog/null/stderr 2519 */ 2520 2521 static const char *printtime_enums[] = { "iso8601", "iso8601-utc", "local", 2522 NULL }; 2523 static isc_result_t 2524 parse_printtime(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2525 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 2526 } 2527 static void 2528 doc_printtime(cfg_printer_t *pctx, const cfg_type_t *type) { 2529 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); 2530 } 2531 static cfg_type_t cfg_type_printtime = { "printtime", parse_printtime, 2532 cfg_print_ustring, doc_printtime, 2533 &cfg_rep_string, printtime_enums }; 2534 2535 static cfg_clausedef_t channel_clauses[] = { 2536 /* Destinations. We no longer require these to be first. */ 2537 { "file", &cfg_type_logfile, 0 }, 2538 { "syslog", &cfg_type_optional_facility, 0 }, 2539 { "null", &cfg_type_void, 0 }, 2540 { "stderr", &cfg_type_void, 0 }, 2541 /* Options. We now accept these for the null channel, too. */ 2542 { "severity", &cfg_type_logseverity, 0 }, 2543 { "print-time", &cfg_type_printtime, 0 }, 2544 { "print-severity", &cfg_type_boolean, 0 }, 2545 { "print-category", &cfg_type_boolean, 0 }, 2546 { "buffered", &cfg_type_boolean, 0 }, 2547 { NULL, NULL, 0 } 2548 }; 2549 static cfg_clausedef_t *channel_clausesets[] = { channel_clauses, NULL }; 2550 static cfg_type_t cfg_type_channel = { "channel", cfg_parse_named_map, 2551 cfg_print_map, cfg_doc_map, 2552 &cfg_rep_map, channel_clausesets }; 2553 2554 /*% A list of log destination, used in the "category" clause. */ 2555 static cfg_type_t cfg_type_destinationlist = { "destinationlist", 2556 cfg_parse_bracketed_list, 2557 cfg_print_bracketed_list, 2558 cfg_doc_bracketed_list, 2559 &cfg_rep_list, 2560 &cfg_type_astring }; 2561 2562 /*% 2563 * Clauses that can be found in a 'logging' statement. 2564 */ 2565 static cfg_clausedef_t logging_clauses[] = { 2566 { "channel", &cfg_type_channel, CFG_CLAUSEFLAG_MULTI }, 2567 { "category", &cfg_type_category, CFG_CLAUSEFLAG_MULTI }, 2568 { NULL, NULL, 0 } 2569 }; 2570 static cfg_clausedef_t *logging_clausesets[] = { logging_clauses, NULL }; 2571 static cfg_type_t cfg_type_logging = { "logging", cfg_parse_map, 2572 cfg_print_map, cfg_doc_map, 2573 &cfg_rep_map, logging_clausesets }; 2574 2575 /*% 2576 * For parsing an 'addzone' statement 2577 */ 2578 static cfg_tuplefielddef_t addzone_fields[] = { 2579 { "name", &cfg_type_astring, 0 }, 2580 { "class", &cfg_type_optional_class, 0 }, 2581 { "view", &cfg_type_optional_class, 0 }, 2582 { "options", &cfg_type_zoneopts, 0 }, 2583 { NULL, NULL, 0 } 2584 }; 2585 static cfg_type_t cfg_type_addzone = { "zone", cfg_parse_tuple, 2586 cfg_print_tuple, cfg_doc_tuple, 2587 &cfg_rep_tuple, addzone_fields }; 2588 2589 static cfg_clausedef_t addzoneconf_clauses[] = { 2590 { "zone", &cfg_type_addzone, CFG_CLAUSEFLAG_MULTI }, { NULL, NULL, 0 } 2591 }; 2592 2593 static cfg_clausedef_t *addzoneconf_clausesets[] = { addzoneconf_clauses, 2594 NULL }; 2595 2596 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_addzoneconf = { 2597 "addzoneconf", cfg_parse_mapbody, cfg_print_mapbody, 2598 cfg_doc_mapbody, &cfg_rep_map, addzoneconf_clausesets 2599 }; 2600 2601 static isc_result_t 2602 parse_unitstring(char *str, isc_resourcevalue_t *valuep) { 2603 char *endp; 2604 unsigned int len; 2605 uint64_t value; 2606 uint64_t unit; 2607 2608 value = strtoull(str, &endp, 10); 2609 if (*endp == 0) { 2610 *valuep = value; 2611 return (ISC_R_SUCCESS); 2612 } 2613 2614 len = strlen(str); 2615 if (len < 2 || endp[1] != '\0') { 2616 return (ISC_R_FAILURE); 2617 } 2618 2619 switch (str[len - 1]) { 2620 case 'k': 2621 case 'K': 2622 unit = 1024; 2623 break; 2624 case 'm': 2625 case 'M': 2626 unit = 1024 * 1024; 2627 break; 2628 case 'g': 2629 case 'G': 2630 unit = 1024 * 1024 * 1024; 2631 break; 2632 default: 2633 return (ISC_R_FAILURE); 2634 } 2635 if (value > ((uint64_t)UINT64_MAX / unit)) { 2636 return (ISC_R_FAILURE); 2637 } 2638 *valuep = value * unit; 2639 return (ISC_R_SUCCESS); 2640 } 2641 2642 static isc_result_t 2643 parse_sizeval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2644 isc_result_t result; 2645 cfg_obj_t *obj = NULL; 2646 uint64_t val; 2647 2648 UNUSED(type); 2649 2650 CHECK(cfg_gettoken(pctx, 0)); 2651 if (pctx->token.type != isc_tokentype_string) { 2652 result = ISC_R_UNEXPECTEDTOKEN; 2653 goto cleanup; 2654 } 2655 CHECK(parse_unitstring(TOKEN_STRING(pctx), &val)); 2656 2657 CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj)); 2658 obj->value.uint64 = val; 2659 *ret = obj; 2660 return (ISC_R_SUCCESS); 2661 2662 cleanup: 2663 cfg_parser_error(pctx, CFG_LOG_NEAR, 2664 "expected integer and optional unit"); 2665 return (result); 2666 } 2667 2668 static isc_result_t 2669 parse_sizeval_percent(cfg_parser_t *pctx, const cfg_type_t *type, 2670 cfg_obj_t **ret) { 2671 char *endp; 2672 isc_result_t result; 2673 cfg_obj_t *obj = NULL; 2674 uint64_t val; 2675 uint64_t percent; 2676 2677 UNUSED(type); 2678 2679 CHECK(cfg_gettoken(pctx, 0)); 2680 if (pctx->token.type != isc_tokentype_string) { 2681 result = ISC_R_UNEXPECTEDTOKEN; 2682 goto cleanup; 2683 } 2684 2685 percent = strtoull(TOKEN_STRING(pctx), &endp, 10); 2686 2687 if (*endp == '%' && *(endp + 1) == 0) { 2688 CHECK(cfg_create_obj(pctx, &cfg_type_percentage, &obj)); 2689 obj->value.uint32 = (uint32_t)percent; 2690 *ret = obj; 2691 return (ISC_R_SUCCESS); 2692 } else { 2693 CHECK(parse_unitstring(TOKEN_STRING(pctx), &val)); 2694 CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj)); 2695 obj->value.uint64 = val; 2696 *ret = obj; 2697 return (ISC_R_SUCCESS); 2698 } 2699 2700 cleanup: 2701 cfg_parser_error(pctx, CFG_LOG_NEAR, 2702 "expected integer and optional unit or percent"); 2703 return (result); 2704 } 2705 2706 static void 2707 doc_sizeval_percent(cfg_printer_t *pctx, const cfg_type_t *type) { 2708 UNUSED(type); 2709 2710 cfg_print_cstr(pctx, "( "); 2711 cfg_doc_terminal(pctx, &cfg_type_size); 2712 cfg_print_cstr(pctx, " | "); 2713 cfg_doc_terminal(pctx, &cfg_type_percentage); 2714 cfg_print_cstr(pctx, " )"); 2715 } 2716 2717 /*% 2718 * A size value (number + optional unit). 2719 */ 2720 static cfg_type_t cfg_type_sizeval = { "sizeval", parse_sizeval, 2721 cfg_print_uint64, cfg_doc_terminal, 2722 &cfg_rep_uint64, NULL }; 2723 2724 /*% 2725 * A size, "unlimited", or "default". 2726 */ 2727 2728 static isc_result_t 2729 parse_size(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2730 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret)); 2731 } 2732 2733 static void 2734 doc_size(cfg_printer_t *pctx, const cfg_type_t *type) { 2735 cfg_doc_enum_or_other(pctx, type, &cfg_type_sizeval); 2736 } 2737 2738 static const char *size_enums[] = { "default", "unlimited", NULL }; 2739 static cfg_type_t cfg_type_size = { 2740 "size", parse_size, cfg_print_ustring, 2741 doc_size, &cfg_rep_string, size_enums 2742 }; 2743 2744 /*% 2745 * A size or "unlimited", but not "default". 2746 */ 2747 static const char *sizenodefault_enums[] = { "unlimited", NULL }; 2748 static cfg_type_t cfg_type_sizenodefault = { 2749 "size_no_default", parse_size, cfg_print_ustring, 2750 doc_size, &cfg_rep_string, sizenodefault_enums 2751 }; 2752 2753 /*% 2754 * A size in absolute values or percents. 2755 */ 2756 static cfg_type_t cfg_type_sizeval_percent = { 2757 "sizeval_percent", parse_sizeval_percent, cfg_print_ustring, 2758 doc_sizeval_percent, &cfg_rep_string, NULL 2759 }; 2760 2761 /*% 2762 * A size in absolute values or percents, or "unlimited", or "default" 2763 */ 2764 2765 static isc_result_t 2766 parse_size_or_percent(cfg_parser_t *pctx, const cfg_type_t *type, 2767 cfg_obj_t **ret) { 2768 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_sizeval_percent, 2769 ret)); 2770 } 2771 2772 static void 2773 doc_parse_size_or_percent(cfg_printer_t *pctx, const cfg_type_t *type) { 2774 UNUSED(type); 2775 cfg_print_cstr(pctx, "( default | unlimited | "); 2776 cfg_doc_terminal(pctx, &cfg_type_sizeval); 2777 cfg_print_cstr(pctx, " | "); 2778 cfg_doc_terminal(pctx, &cfg_type_percentage); 2779 cfg_print_cstr(pctx, " )"); 2780 } 2781 2782 static const char *sizeorpercent_enums[] = { "default", "unlimited", NULL }; 2783 static cfg_type_t cfg_type_sizeorpercent = { 2784 "size_or_percent", parse_size_or_percent, cfg_print_ustring, 2785 doc_parse_size_or_percent, &cfg_rep_string, sizeorpercent_enums 2786 }; 2787 2788 /*% 2789 * An IXFR size ratio: percentage, or "unlimited". 2790 */ 2791 2792 static isc_result_t 2793 parse_ixfrratio(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2794 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_percentage, ret)); 2795 } 2796 2797 static void 2798 doc_ixfrratio(cfg_printer_t *pctx, const cfg_type_t *type) { 2799 UNUSED(type); 2800 cfg_print_cstr(pctx, "( unlimited | "); 2801 cfg_doc_terminal(pctx, &cfg_type_percentage); 2802 cfg_print_cstr(pctx, " )"); 2803 } 2804 2805 static const char *ixfrratio_enums[] = { "unlimited", NULL }; 2806 static cfg_type_t cfg_type_ixfrratio = { "ixfr_ratio", parse_ixfrratio, 2807 NULL, doc_ixfrratio, 2808 NULL, ixfrratio_enums }; 2809 2810 /*% 2811 * optional_keyvalue 2812 */ 2813 static isc_result_t 2814 parse_maybe_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, 2815 bool optional, cfg_obj_t **ret) { 2816 isc_result_t result; 2817 cfg_obj_t *obj = NULL; 2818 const keyword_type_t *kw = type->of; 2819 2820 CHECK(cfg_peektoken(pctx, 0)); 2821 if (pctx->token.type == isc_tokentype_string && 2822 strcasecmp(TOKEN_STRING(pctx), kw->name) == 0) 2823 { 2824 CHECK(cfg_gettoken(pctx, 0)); 2825 CHECK(kw->type->parse(pctx, kw->type, &obj)); 2826 obj->type = type; /* XXX kludge */ 2827 } else { 2828 if (optional) { 2829 CHECK(cfg_parse_void(pctx, NULL, &obj)); 2830 } else { 2831 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected '%s'", 2832 kw->name); 2833 result = ISC_R_UNEXPECTEDTOKEN; 2834 goto cleanup; 2835 } 2836 } 2837 *ret = obj; 2838 cleanup: 2839 return (result); 2840 } 2841 2842 static isc_result_t 2843 parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2844 return (parse_maybe_optional_keyvalue(pctx, type, false, ret)); 2845 } 2846 2847 static isc_result_t 2848 parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, 2849 cfg_obj_t **ret) { 2850 return (parse_maybe_optional_keyvalue(pctx, type, true, ret)); 2851 } 2852 2853 static void 2854 print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj) { 2855 const keyword_type_t *kw = obj->type->of; 2856 cfg_print_cstr(pctx, kw->name); 2857 cfg_print_cstr(pctx, " "); 2858 kw->type->print(pctx, obj); 2859 } 2860 2861 static void 2862 doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) { 2863 const keyword_type_t *kw = type->of; 2864 cfg_print_cstr(pctx, kw->name); 2865 cfg_print_cstr(pctx, " "); 2866 cfg_doc_obj(pctx, kw->type); 2867 } 2868 2869 static void 2870 doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) { 2871 const keyword_type_t *kw = type->of; 2872 cfg_print_cstr(pctx, "[ "); 2873 cfg_print_cstr(pctx, kw->name); 2874 cfg_print_cstr(pctx, " "); 2875 cfg_doc_obj(pctx, kw->type); 2876 cfg_print_cstr(pctx, " ]"); 2877 } 2878 2879 static const char *dialup_enums[] = { "notify", "notify-passive", "passive", 2880 "refresh", NULL }; 2881 static isc_result_t 2882 parse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2883 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 2884 } 2885 static void 2886 doc_dialup_type(cfg_printer_t *pctx, const cfg_type_t *type) { 2887 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); 2888 } 2889 static cfg_type_t cfg_type_dialuptype = { "dialuptype", parse_dialup_type, 2890 cfg_print_ustring, doc_dialup_type, 2891 &cfg_rep_string, dialup_enums }; 2892 2893 static const char *notify_enums[] = { "explicit", "master-only", "primary-only", 2894 NULL }; 2895 static isc_result_t 2896 parse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2897 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 2898 } 2899 static void 2900 doc_notify_type(cfg_printer_t *pctx, const cfg_type_t *type) { 2901 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); 2902 } 2903 static cfg_type_t cfg_type_notifytype = { 2904 "notifytype", parse_notify_type, cfg_print_ustring, 2905 doc_notify_type, &cfg_rep_string, notify_enums, 2906 }; 2907 2908 static const char *minimal_enums[] = { "no-auth", "no-auth-recursive", NULL }; 2909 static isc_result_t 2910 parse_minimal(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2911 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 2912 } 2913 static void 2914 doc_minimal(cfg_printer_t *pctx, const cfg_type_t *type) { 2915 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); 2916 } 2917 static cfg_type_t cfg_type_minimal = { 2918 "minimal", parse_minimal, cfg_print_ustring, 2919 doc_minimal, &cfg_rep_string, minimal_enums, 2920 }; 2921 2922 static const char *ixfrdiff_enums[] = { "primary", "master", "secondary", 2923 "slave", NULL }; 2924 static isc_result_t 2925 parse_ixfrdiff_type(cfg_parser_t *pctx, const cfg_type_t *type, 2926 cfg_obj_t **ret) { 2927 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 2928 } 2929 static void 2930 doc_ixfrdiff_type(cfg_printer_t *pctx, const cfg_type_t *type) { 2931 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); 2932 } 2933 static cfg_type_t cfg_type_ixfrdifftype = { 2934 "ixfrdiff", parse_ixfrdiff_type, cfg_print_ustring, 2935 doc_ixfrdiff_type, &cfg_rep_string, ixfrdiff_enums, 2936 }; 2937 2938 static keyword_type_t key_kw = { "key", &cfg_type_astring }; 2939 2940 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = { 2941 "keyref", parse_keyvalue, print_keyvalue, 2942 doc_keyvalue, &cfg_rep_string, &key_kw 2943 }; 2944 2945 static cfg_type_t cfg_type_optional_keyref = { 2946 "optional_keyref", parse_optional_keyvalue, print_keyvalue, 2947 doc_optional_keyvalue, &cfg_rep_string, &key_kw 2948 }; 2949 2950 static const char *qminmethod_enums[] = { "strict", "relaxed", "disabled", 2951 "off", NULL }; 2952 2953 static cfg_type_t cfg_type_qminmethod = { "qminmethod", cfg_parse_enum, 2954 cfg_print_ustring, cfg_doc_enum, 2955 &cfg_rep_string, qminmethod_enums }; 2956 2957 /*% 2958 * A "controls" statement is represented as a map with the multivalued 2959 * "inet" and "unix" clauses. 2960 */ 2961 2962 static keyword_type_t controls_allow_kw = { "allow", &cfg_type_bracketed_aml }; 2963 2964 static cfg_type_t cfg_type_controls_allow = { 2965 "controls_allow", parse_keyvalue, print_keyvalue, 2966 doc_keyvalue, &cfg_rep_list, &controls_allow_kw 2967 }; 2968 2969 static keyword_type_t controls_keys_kw = { "keys", &cfg_type_keylist }; 2970 2971 static cfg_type_t cfg_type_controls_keys = { 2972 "controls_keys", parse_optional_keyvalue, print_keyvalue, 2973 doc_optional_keyvalue, &cfg_rep_list, &controls_keys_kw 2974 }; 2975 2976 static keyword_type_t controls_readonly_kw = { "read-only", &cfg_type_boolean }; 2977 2978 static cfg_type_t cfg_type_controls_readonly = { 2979 "controls_readonly", parse_optional_keyvalue, print_keyvalue, 2980 doc_optional_keyvalue, &cfg_rep_boolean, &controls_readonly_kw 2981 }; 2982 2983 static cfg_tuplefielddef_t inetcontrol_fields[] = { 2984 { "address", &cfg_type_controls_sockaddr, 0 }, 2985 { "allow", &cfg_type_controls_allow, 0 }, 2986 { "keys", &cfg_type_controls_keys, 0 }, 2987 { "read-only", &cfg_type_controls_readonly, 0 }, 2988 { NULL, NULL, 0 } 2989 }; 2990 2991 static cfg_type_t cfg_type_inetcontrol = { 2992 "inetcontrol", cfg_parse_tuple, cfg_print_tuple, 2993 cfg_doc_tuple, &cfg_rep_tuple, inetcontrol_fields 2994 }; 2995 2996 static keyword_type_t controls_perm_kw = { "perm", &cfg_type_uint32 }; 2997 2998 static cfg_type_t cfg_type_controls_perm = { 2999 "controls_perm", parse_keyvalue, print_keyvalue, 3000 doc_keyvalue, &cfg_rep_uint32, &controls_perm_kw 3001 }; 3002 3003 static keyword_type_t controls_owner_kw = { "owner", &cfg_type_uint32 }; 3004 3005 static cfg_type_t cfg_type_controls_owner = { 3006 "controls_owner", parse_keyvalue, print_keyvalue, 3007 doc_keyvalue, &cfg_rep_uint32, &controls_owner_kw 3008 }; 3009 3010 static keyword_type_t controls_group_kw = { "group", &cfg_type_uint32 }; 3011 3012 static cfg_type_t cfg_type_controls_group = { 3013 "controls_allow", parse_keyvalue, print_keyvalue, 3014 doc_keyvalue, &cfg_rep_uint32, &controls_group_kw 3015 }; 3016 3017 static cfg_tuplefielddef_t unixcontrol_fields[] = { 3018 { "path", &cfg_type_qstring, 0 }, 3019 { "perm", &cfg_type_controls_perm, 0 }, 3020 { "owner", &cfg_type_controls_owner, 0 }, 3021 { "group", &cfg_type_controls_group, 0 }, 3022 { "keys", &cfg_type_controls_keys, 0 }, 3023 { "read-only", &cfg_type_controls_readonly, 0 }, 3024 { NULL, NULL, 0 } 3025 }; 3026 3027 static cfg_type_t cfg_type_unixcontrol = { 3028 "unixcontrol", cfg_parse_tuple, cfg_print_tuple, 3029 cfg_doc_tuple, &cfg_rep_tuple, unixcontrol_fields 3030 }; 3031 3032 static cfg_clausedef_t controls_clauses[] = { 3033 { "inet", &cfg_type_inetcontrol, CFG_CLAUSEFLAG_MULTI }, 3034 { "unix", &cfg_type_unixcontrol, CFG_CLAUSEFLAG_MULTI }, 3035 { NULL, NULL, 0 } 3036 }; 3037 3038 static cfg_clausedef_t *controls_clausesets[] = { controls_clauses, NULL }; 3039 static cfg_type_t cfg_type_controls = { "controls", cfg_parse_map, 3040 cfg_print_map, cfg_doc_map, 3041 &cfg_rep_map, &controls_clausesets }; 3042 3043 /*% 3044 * A "statistics-channels" statement is represented as a map with the 3045 * multivalued "inet" clauses. 3046 */ 3047 static void 3048 doc_optional_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) { 3049 const keyword_type_t *kw = type->of; 3050 cfg_print_cstr(pctx, "[ "); 3051 cfg_print_cstr(pctx, kw->name); 3052 cfg_print_cstr(pctx, " "); 3053 cfg_doc_obj(pctx, kw->type); 3054 cfg_print_cstr(pctx, " ]"); 3055 } 3056 3057 static cfg_type_t cfg_type_optional_allow = { 3058 "optional_allow", parse_optional_keyvalue, 3059 print_keyvalue, doc_optional_bracketed_list, 3060 &cfg_rep_list, &controls_allow_kw 3061 }; 3062 3063 static cfg_tuplefielddef_t statserver_fields[] = { 3064 { "address", &cfg_type_controls_sockaddr, 0 }, /* reuse controls def */ 3065 { "allow", &cfg_type_optional_allow, 0 }, 3066 { NULL, NULL, 0 } 3067 }; 3068 3069 static cfg_type_t cfg_type_statschannel = { 3070 "statschannel", cfg_parse_tuple, cfg_print_tuple, 3071 cfg_doc_tuple, &cfg_rep_tuple, statserver_fields 3072 }; 3073 3074 static cfg_clausedef_t statservers_clauses[] = { 3075 { "inet", &cfg_type_statschannel, CFG_CLAUSEFLAG_MULTI }, 3076 { NULL, NULL, 0 } 3077 }; 3078 3079 static cfg_clausedef_t *statservers_clausesets[] = { statservers_clauses, 3080 NULL }; 3081 3082 static cfg_type_t cfg_type_statschannels = { 3083 "statistics-channels", cfg_parse_map, cfg_print_map, 3084 cfg_doc_map, &cfg_rep_map, &statservers_clausesets 3085 }; 3086 3087 /*% 3088 * An optional class, as used in view and zone statements. 3089 */ 3090 static isc_result_t 3091 parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type, 3092 cfg_obj_t **ret) { 3093 isc_result_t result; 3094 UNUSED(type); 3095 CHECK(cfg_peektoken(pctx, 0)); 3096 if (pctx->token.type == isc_tokentype_string) { 3097 CHECK(cfg_parse_obj(pctx, &cfg_type_ustring, ret)); 3098 } else { 3099 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret)); 3100 } 3101 cleanup: 3102 return (result); 3103 } 3104 3105 static void 3106 doc_optional_class(cfg_printer_t *pctx, const cfg_type_t *type) { 3107 UNUSED(type); 3108 cfg_print_cstr(pctx, "[ <class> ]"); 3109 } 3110 3111 static cfg_type_t cfg_type_optional_class = { "optional_class", 3112 parse_optional_class, 3113 NULL, 3114 doc_optional_class, 3115 NULL, 3116 NULL }; 3117 3118 static isc_result_t 3119 parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 3120 isc_result_t result; 3121 cfg_obj_t *obj = NULL; 3122 isc_netaddr_t netaddr; 3123 in_port_t port = 0; 3124 isc_dscp_t dscp = -1; 3125 unsigned int have_address = 0; 3126 unsigned int have_port = 0; 3127 unsigned int have_dscp = 0; 3128 const unsigned int *flagp = type->of; 3129 3130 if ((*flagp & CFG_ADDR_V4OK) != 0) { 3131 isc_netaddr_any(&netaddr); 3132 } else if ((*flagp & CFG_ADDR_V6OK) != 0) { 3133 isc_netaddr_any6(&netaddr); 3134 } else { 3135 UNREACHABLE(); 3136 } 3137 3138 for (;;) { 3139 CHECK(cfg_peektoken(pctx, 0)); 3140 if (pctx->token.type == isc_tokentype_string) { 3141 if (strcasecmp(TOKEN_STRING(pctx), "address") == 0) { 3142 /* read "address" */ 3143 CHECK(cfg_gettoken(pctx, 0)); 3144 CHECK(cfg_parse_rawaddr(pctx, *flagp, 3145 &netaddr)); 3146 have_address++; 3147 } else if (strcasecmp(TOKEN_STRING(pctx), "port") == 0) 3148 { 3149 /* read "port" */ 3150 CHECK(cfg_gettoken(pctx, 0)); 3151 CHECK(cfg_parse_rawport(pctx, CFG_ADDR_WILDOK, 3152 &port)); 3153 have_port++; 3154 } else if (strcasecmp(TOKEN_STRING(pctx), "dscp") == 0) 3155 { 3156 if ((pctx->flags & CFG_PCTX_NODEPRECATED) == 0) 3157 { 3158 cfg_parser_warning( 3159 pctx, 0, 3160 "token 'dscp' is deprecated"); 3161 } 3162 /* read "dscp" */ 3163 CHECK(cfg_gettoken(pctx, 0)); 3164 CHECK(cfg_parse_dscp(pctx, &dscp)); 3165 have_dscp++; 3166 } else if (have_port == 0 && have_dscp == 0 && 3167 have_address == 0) 3168 { 3169 return (cfg_parse_sockaddr(pctx, type, ret)); 3170 } else { 3171 cfg_parser_error(pctx, CFG_LOG_NEAR, 3172 "expected 'address', 'port', " 3173 "or 'dscp'"); 3174 return (ISC_R_UNEXPECTEDTOKEN); 3175 } 3176 } else { 3177 break; 3178 } 3179 } 3180 if (have_address > 1 || have_port > 1 || have_address + have_port == 0) 3181 { 3182 cfg_parser_error(pctx, 0, "expected one address and/or port"); 3183 return (ISC_R_UNEXPECTEDTOKEN); 3184 } 3185 3186 if (have_dscp > 1) { 3187 cfg_parser_error(pctx, 0, "expected at most one dscp"); 3188 return (ISC_R_UNEXPECTEDTOKEN); 3189 } 3190 3191 CHECK(cfg_create_obj(pctx, &cfg_type_querysource, &obj)); 3192 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); 3193 obj->value.sockaddrdscp.dscp = dscp; 3194 *ret = obj; 3195 return (ISC_R_SUCCESS); 3196 3197 cleanup: 3198 cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid query source"); 3199 CLEANUP_OBJ(obj); 3200 return (result); 3201 } 3202 3203 static void 3204 print_querysource(cfg_printer_t *pctx, const cfg_obj_t *obj) { 3205 isc_netaddr_t na; 3206 isc_netaddr_fromsockaddr(&na, &obj->value.sockaddr); 3207 cfg_print_cstr(pctx, "address "); 3208 cfg_print_rawaddr(pctx, &na); 3209 cfg_print_cstr(pctx, " port "); 3210 cfg_print_rawuint(pctx, isc_sockaddr_getport(&obj->value.sockaddr)); 3211 if (obj->value.sockaddrdscp.dscp != -1) { 3212 cfg_print_cstr(pctx, " dscp "); 3213 cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp); 3214 } 3215 } 3216 3217 static void 3218 doc_querysource(cfg_printer_t *pctx, const cfg_type_t *type) { 3219 const unsigned int *flagp = type->of; 3220 3221 cfg_print_cstr(pctx, "( ( [ address ] ( "); 3222 if ((*flagp & CFG_ADDR_V4OK) != 0) { 3223 cfg_print_cstr(pctx, "<ipv4_address>"); 3224 } else if ((*flagp & CFG_ADDR_V6OK) != 0) { 3225 cfg_print_cstr(pctx, "<ipv6_address>"); 3226 } else { 3227 UNREACHABLE(); 3228 } 3229 cfg_print_cstr(pctx, " | * ) [ port ( <integer> | * ) ] ) | " 3230 "( [ [ address ] ( "); 3231 if ((*flagp & CFG_ADDR_V4OK) != 0) { 3232 cfg_print_cstr(pctx, "<ipv4_address>"); 3233 } else if ((*flagp & CFG_ADDR_V6OK) != 0) { 3234 cfg_print_cstr(pctx, "<ipv6_address>"); 3235 } else { 3236 UNREACHABLE(); 3237 } 3238 cfg_print_cstr(pctx, " | * ) ] port ( <integer> | * ) ) )" 3239 " [ dscp <integer> ]"); 3240 } 3241 3242 static unsigned int sockaddr4wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V4OK | 3243 CFG_ADDR_DSCPOK; 3244 static unsigned int sockaddr6wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V6OK | 3245 CFG_ADDR_DSCPOK; 3246 3247 static cfg_type_t cfg_type_querysource4 = { 3248 "querysource4", parse_querysource, NULL, doc_querysource, 3249 NULL, &sockaddr4wild_flags 3250 }; 3251 3252 static cfg_type_t cfg_type_querysource6 = { 3253 "querysource6", parse_querysource, NULL, doc_querysource, 3254 NULL, &sockaddr6wild_flags 3255 }; 3256 3257 static cfg_type_t cfg_type_querysource = { "querysource", NULL, 3258 print_querysource, NULL, 3259 &cfg_rep_sockaddr, NULL }; 3260 3261 /*% 3262 * The socket address syntax in the "controls" statement is silly. 3263 * It allows both socket address families, but also allows "*", 3264 * which is gratuitously interpreted as the IPv4 wildcard address. 3265 */ 3266 static unsigned int controls_sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK | 3267 CFG_ADDR_WILDOK; 3268 static cfg_type_t cfg_type_controls_sockaddr = { 3269 "controls_sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, 3270 cfg_doc_sockaddr, &cfg_rep_sockaddr, &controls_sockaddr_flags 3271 }; 3272 3273 /*% 3274 * Handle the special kludge syntax of the "keys" clause in the "server" 3275 * statement, which takes a single key with or without braces and semicolon. 3276 */ 3277 static isc_result_t 3278 parse_server_key_kludge(cfg_parser_t *pctx, const cfg_type_t *type, 3279 cfg_obj_t **ret) { 3280 isc_result_t result; 3281 bool braces = false; 3282 UNUSED(type); 3283 3284 /* Allow opening brace. */ 3285 CHECK(cfg_peektoken(pctx, 0)); 3286 if (pctx->token.type == isc_tokentype_special && 3287 pctx->token.value.as_char == '{') 3288 { 3289 CHECK(cfg_gettoken(pctx, 0)); 3290 braces = true; 3291 } 3292 3293 CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret)); 3294 3295 if (braces) { 3296 /* Skip semicolon if present. */ 3297 CHECK(cfg_peektoken(pctx, 0)); 3298 if (pctx->token.type == isc_tokentype_special && 3299 pctx->token.value.as_char == ';') 3300 { 3301 CHECK(cfg_gettoken(pctx, 0)); 3302 } 3303 3304 CHECK(cfg_parse_special(pctx, '}')); 3305 } 3306 cleanup: 3307 return (result); 3308 } 3309 static cfg_type_t cfg_type_server_key_kludge = { 3310 "server_key", parse_server_key_kludge, NULL, cfg_doc_terminal, NULL, 3311 NULL 3312 }; 3313 3314 /*% 3315 * An optional logging facility. 3316 */ 3317 3318 static isc_result_t 3319 parse_optional_facility(cfg_parser_t *pctx, const cfg_type_t *type, 3320 cfg_obj_t **ret) { 3321 isc_result_t result; 3322 UNUSED(type); 3323 3324 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); 3325 if (pctx->token.type == isc_tokentype_string || 3326 pctx->token.type == isc_tokentype_qstring) 3327 { 3328 CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret)); 3329 } else { 3330 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret)); 3331 } 3332 cleanup: 3333 return (result); 3334 } 3335 3336 static void 3337 doc_optional_facility(cfg_printer_t *pctx, const cfg_type_t *type) { 3338 UNUSED(type); 3339 cfg_print_cstr(pctx, "[ <syslog_facility> ]"); 3340 } 3341 3342 static cfg_type_t cfg_type_optional_facility = { "optional_facility", 3343 parse_optional_facility, 3344 NULL, 3345 doc_optional_facility, 3346 NULL, 3347 NULL }; 3348 3349 /*% 3350 * A log severity. Return as a string, except "debug N", 3351 * which is returned as a keyword object. 3352 */ 3353 3354 static keyword_type_t debug_kw = { "debug", &cfg_type_uint32 }; 3355 static cfg_type_t cfg_type_debuglevel = { "debuglevel", parse_keyvalue, 3356 print_keyvalue, doc_keyvalue, 3357 &cfg_rep_uint32, &debug_kw }; 3358 3359 static isc_result_t 3360 parse_logseverity(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 3361 isc_result_t result; 3362 UNUSED(type); 3363 3364 CHECK(cfg_peektoken(pctx, 0)); 3365 if (pctx->token.type == isc_tokentype_string && 3366 strcasecmp(TOKEN_STRING(pctx), "debug") == 0) 3367 { 3368 CHECK(cfg_gettoken(pctx, 0)); /* read "debug" */ 3369 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER)); 3370 if (pctx->token.type == isc_tokentype_number) { 3371 CHECK(cfg_parse_uint32(pctx, NULL, ret)); 3372 } else { 3373 /* 3374 * The debug level is optional and defaults to 1. 3375 * This makes little sense, but we support it for 3376 * compatibility with BIND 8. 3377 */ 3378 CHECK(cfg_create_obj(pctx, &cfg_type_uint32, ret)); 3379 (*ret)->value.uint32 = 1; 3380 } 3381 (*ret)->type = &cfg_type_debuglevel; /* XXX kludge */ 3382 } else { 3383 CHECK(cfg_parse_obj(pctx, &cfg_type_loglevel, ret)); 3384 } 3385 cleanup: 3386 return (result); 3387 } 3388 3389 static cfg_type_t cfg_type_logseverity = { "log_severity", parse_logseverity, 3390 NULL, cfg_doc_terminal, 3391 NULL, NULL }; 3392 3393 /*% 3394 * The "file" clause of the "channel" statement. 3395 * This is yet another special case. 3396 */ 3397 3398 static const char *logversions_enums[] = { "unlimited", NULL }; 3399 static isc_result_t 3400 parse_logversions(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 3401 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_uint32, ret)); 3402 } 3403 3404 static void 3405 doc_logversions(cfg_printer_t *pctx, const cfg_type_t *type) { 3406 cfg_doc_enum_or_other(pctx, type, &cfg_type_uint32); 3407 } 3408 3409 static cfg_type_t cfg_type_logversions = { 3410 "logversions", parse_logversions, cfg_print_ustring, 3411 doc_logversions, &cfg_rep_string, logversions_enums 3412 }; 3413 3414 static const char *logsuffix_enums[] = { "increment", "timestamp", NULL }; 3415 static cfg_type_t cfg_type_logsuffix = { "logsuffix", cfg_parse_enum, 3416 cfg_print_ustring, cfg_doc_enum, 3417 &cfg_rep_string, &logsuffix_enums }; 3418 3419 static cfg_tuplefielddef_t logfile_fields[] = { 3420 { "file", &cfg_type_qstring, 0 }, 3421 { "versions", &cfg_type_logversions, 0 }, 3422 { "size", &cfg_type_size, 0 }, 3423 { "suffix", &cfg_type_logsuffix, 0 }, 3424 { NULL, NULL, 0 } 3425 }; 3426 3427 static isc_result_t 3428 parse_logfile(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 3429 isc_result_t result; 3430 cfg_obj_t *obj = NULL; 3431 const cfg_tuplefielddef_t *fields = type->of; 3432 3433 CHECK(cfg_create_tuple(pctx, type, &obj)); 3434 3435 /* Parse the mandatory "file" field */ 3436 CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0])); 3437 3438 /* Parse "versions" and "size" fields in any order. */ 3439 for (;;) { 3440 CHECK(cfg_peektoken(pctx, 0)); 3441 if (pctx->token.type == isc_tokentype_string) { 3442 CHECK(cfg_gettoken(pctx, 0)); 3443 if (strcasecmp(TOKEN_STRING(pctx), "versions") == 0 && 3444 obj->value.tuple[1] == NULL) 3445 { 3446 CHECK(cfg_parse_obj(pctx, fields[1].type, 3447 &obj->value.tuple[1])); 3448 } else if (strcasecmp(TOKEN_STRING(pctx), "size") == 3449 0 && 3450 obj->value.tuple[2] == NULL) 3451 { 3452 CHECK(cfg_parse_obj(pctx, fields[2].type, 3453 &obj->value.tuple[2])); 3454 } else if (strcasecmp(TOKEN_STRING(pctx), "suffix") == 3455 0 && 3456 obj->value.tuple[3] == NULL) 3457 { 3458 CHECK(cfg_parse_obj(pctx, fields[3].type, 3459 &obj->value.tuple[3])); 3460 } else { 3461 break; 3462 } 3463 } else { 3464 break; 3465 } 3466 } 3467 3468 /* Create void objects for missing optional values. */ 3469 if (obj->value.tuple[1] == NULL) { 3470 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1])); 3471 } 3472 if (obj->value.tuple[2] == NULL) { 3473 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2])); 3474 } 3475 if (obj->value.tuple[3] == NULL) { 3476 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[3])); 3477 } 3478 3479 *ret = obj; 3480 return (ISC_R_SUCCESS); 3481 3482 cleanup: 3483 CLEANUP_OBJ(obj); 3484 return (result); 3485 } 3486 3487 static void 3488 print_logfile(cfg_printer_t *pctx, const cfg_obj_t *obj) { 3489 cfg_print_obj(pctx, obj->value.tuple[0]); /* file */ 3490 if (obj->value.tuple[1]->type->print != cfg_print_void) { 3491 cfg_print_cstr(pctx, " versions "); 3492 cfg_print_obj(pctx, obj->value.tuple[1]); 3493 } 3494 if (obj->value.tuple[2]->type->print != cfg_print_void) { 3495 cfg_print_cstr(pctx, " size "); 3496 cfg_print_obj(pctx, obj->value.tuple[2]); 3497 } 3498 if (obj->value.tuple[3]->type->print != cfg_print_void) { 3499 cfg_print_cstr(pctx, " suffix "); 3500 cfg_print_obj(pctx, obj->value.tuple[3]); 3501 } 3502 } 3503 3504 static void 3505 doc_logfile(cfg_printer_t *pctx, const cfg_type_t *type) { 3506 UNUSED(type); 3507 cfg_print_cstr(pctx, "<quoted_string>"); 3508 cfg_print_cstr(pctx, " "); 3509 cfg_print_cstr(pctx, "[ versions ( unlimited | <integer> ) ]"); 3510 cfg_print_cstr(pctx, " "); 3511 cfg_print_cstr(pctx, "[ size <size> ]"); 3512 cfg_print_cstr(pctx, " "); 3513 cfg_print_cstr(pctx, "[ suffix ( increment | timestamp ) ]"); 3514 } 3515 3516 static cfg_type_t cfg_type_logfile = { "log_file", parse_logfile, 3517 print_logfile, doc_logfile, 3518 &cfg_rep_tuple, logfile_fields }; 3519 3520 /*% An IPv4 address with optional dscp and port, "*" accepted as wildcard. */ 3521 static cfg_type_t cfg_type_sockaddr4wild = { 3522 "sockaddr4wild", cfg_parse_sockaddr, cfg_print_sockaddr, 3523 cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr4wild_flags 3524 }; 3525 3526 /*% An IPv6 address with optional port, "*" accepted as wildcard. */ 3527 static cfg_type_t cfg_type_sockaddr6wild = { 3528 "v6addrportwild", cfg_parse_sockaddr, cfg_print_sockaddr, 3529 cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr6wild_flags 3530 }; 3531 3532 /*% 3533 * rndc 3534 */ 3535 3536 static cfg_clausedef_t rndcconf_options_clauses[] = { 3537 { "default-key", &cfg_type_astring, 0 }, 3538 { "default-port", &cfg_type_uint32, 0 }, 3539 { "default-server", &cfg_type_astring, 0 }, 3540 { "default-source-address", &cfg_type_netaddr4wild, 0 }, 3541 { "default-source-address-v6", &cfg_type_netaddr6wild, 0 }, 3542 { NULL, NULL, 0 } 3543 }; 3544 3545 static cfg_clausedef_t *rndcconf_options_clausesets[] = { 3546 rndcconf_options_clauses, NULL 3547 }; 3548 3549 static cfg_type_t cfg_type_rndcconf_options = { 3550 "rndcconf_options", cfg_parse_map, cfg_print_map, 3551 cfg_doc_map, &cfg_rep_map, rndcconf_options_clausesets 3552 }; 3553 3554 static cfg_clausedef_t rndcconf_server_clauses[] = { 3555 { "key", &cfg_type_astring, 0 }, 3556 { "port", &cfg_type_uint32, 0 }, 3557 { "source-address", &cfg_type_netaddr4wild, 0 }, 3558 { "source-address-v6", &cfg_type_netaddr6wild, 0 }, 3559 { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 }, 3560 { NULL, NULL, 0 } 3561 }; 3562 3563 static cfg_clausedef_t *rndcconf_server_clausesets[] = { 3564 rndcconf_server_clauses, NULL 3565 }; 3566 3567 static cfg_type_t cfg_type_rndcconf_server = { 3568 "rndcconf_server", cfg_parse_named_map, cfg_print_map, 3569 cfg_doc_map, &cfg_rep_map, rndcconf_server_clausesets 3570 }; 3571 3572 static cfg_clausedef_t rndcconf_clauses[] = { 3573 { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI }, 3574 { "server", &cfg_type_rndcconf_server, CFG_CLAUSEFLAG_MULTI }, 3575 { "options", &cfg_type_rndcconf_options, 0 }, 3576 { NULL, NULL, 0 } 3577 }; 3578 3579 static cfg_clausedef_t *rndcconf_clausesets[] = { rndcconf_clauses, NULL }; 3580 3581 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndcconf = { 3582 "rndcconf", cfg_parse_mapbody, cfg_print_mapbody, 3583 cfg_doc_mapbody, &cfg_rep_map, rndcconf_clausesets 3584 }; 3585 3586 static cfg_clausedef_t rndckey_clauses[] = { { "key", &cfg_type_key, 0 }, 3587 { NULL, NULL, 0 } }; 3588 3589 static cfg_clausedef_t *rndckey_clausesets[] = { rndckey_clauses, NULL }; 3590 3591 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndckey = { 3592 "rndckey", cfg_parse_mapbody, cfg_print_mapbody, 3593 cfg_doc_mapbody, &cfg_rep_map, rndckey_clausesets 3594 }; 3595 3596 /* 3597 * session.key has exactly the same syntax as rndc.key, but it's defined 3598 * separately for clarity (and so we can extend it someday, if needed). 3599 */ 3600 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sessionkey = { 3601 "sessionkey", cfg_parse_mapbody, cfg_print_mapbody, 3602 cfg_doc_mapbody, &cfg_rep_map, rndckey_clausesets 3603 }; 3604 3605 static cfg_tuplefielddef_t nameport_fields[] = { 3606 { "name", &cfg_type_astring, 0 }, 3607 { "port", &cfg_type_optional_port, 0 }, 3608 { "dscp", &cfg_type_optional_dscp, CFG_CLAUSEFLAG_DEPRECATED }, 3609 { NULL, NULL, 0 } 3610 }; 3611 3612 static cfg_type_t cfg_type_nameport = { "nameport", cfg_parse_tuple, 3613 cfg_print_tuple, cfg_doc_tuple, 3614 &cfg_rep_tuple, nameport_fields }; 3615 3616 static void 3617 doc_sockaddrnameport(cfg_printer_t *pctx, const cfg_type_t *type) { 3618 UNUSED(type); 3619 cfg_print_cstr(pctx, "( "); 3620 cfg_print_cstr(pctx, "<quoted_string>"); 3621 cfg_print_cstr(pctx, " "); 3622 cfg_print_cstr(pctx, "[ port <integer> ]"); 3623 cfg_print_cstr(pctx, " "); 3624 cfg_print_cstr(pctx, "[ dscp <integer> ]"); 3625 cfg_print_cstr(pctx, " | "); 3626 cfg_print_cstr(pctx, "<ipv4_address>"); 3627 cfg_print_cstr(pctx, " "); 3628 cfg_print_cstr(pctx, "[ port <integer> ]"); 3629 cfg_print_cstr(pctx, " "); 3630 cfg_print_cstr(pctx, "[ dscp <integer> ]"); 3631 cfg_print_cstr(pctx, " | "); 3632 cfg_print_cstr(pctx, "<ipv6_address>"); 3633 cfg_print_cstr(pctx, " "); 3634 cfg_print_cstr(pctx, "[ port <integer> ]"); 3635 cfg_print_cstr(pctx, " "); 3636 cfg_print_cstr(pctx, "[ dscp <integer> ]"); 3637 cfg_print_cstr(pctx, " )"); 3638 } 3639 3640 static isc_result_t 3641 parse_sockaddrnameport(cfg_parser_t *pctx, const cfg_type_t *type, 3642 cfg_obj_t **ret) { 3643 isc_result_t result; 3644 cfg_obj_t *obj = NULL; 3645 UNUSED(type); 3646 3647 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); 3648 if (pctx->token.type == isc_tokentype_string || 3649 pctx->token.type == isc_tokentype_qstring) 3650 { 3651 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK)) 3652 { 3653 CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, 3654 ret)); 3655 } else { 3656 const cfg_tuplefielddef_t *fields = 3657 cfg_type_nameport.of; 3658 CHECK(cfg_create_tuple(pctx, &cfg_type_nameport, &obj)); 3659 CHECK(cfg_parse_obj(pctx, fields[0].type, 3660 &obj->value.tuple[0])); 3661 CHECK(cfg_parse_obj(pctx, fields[1].type, 3662 &obj->value.tuple[1])); 3663 CHECK(cfg_parse_obj(pctx, fields[2].type, 3664 &obj->value.tuple[2])); 3665 *ret = obj; 3666 obj = NULL; 3667 } 3668 } else { 3669 cfg_parser_error(pctx, CFG_LOG_NEAR, 3670 "expected IP address or hostname"); 3671 return (ISC_R_UNEXPECTEDTOKEN); 3672 } 3673 cleanup: 3674 CLEANUP_OBJ(obj); 3675 return (result); 3676 } 3677 3678 static cfg_type_t cfg_type_sockaddrnameport = { "sockaddrnameport_element", 3679 parse_sockaddrnameport, 3680 NULL, 3681 doc_sockaddrnameport, 3682 NULL, 3683 NULL }; 3684 3685 static cfg_type_t cfg_type_bracketed_sockaddrnameportlist = { 3686 "bracketed_sockaddrnameportlist", 3687 cfg_parse_bracketed_list, 3688 cfg_print_bracketed_list, 3689 cfg_doc_bracketed_list, 3690 &cfg_rep_list, 3691 &cfg_type_sockaddrnameport 3692 }; 3693 3694 /*% 3695 * A list of socket addresses or name with an optional default port, 3696 * as used in the dual-stack-servers option. E.g., 3697 * "port 1234 { dual-stack-servers.net; 10.0.0.1; 1::2 port 69; }" 3698 */ 3699 static cfg_tuplefielddef_t nameportiplist_fields[] = { 3700 { "port", &cfg_type_optional_port, 0 }, 3701 { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 }, 3702 { NULL, NULL, 0 } 3703 }; 3704 3705 static cfg_type_t cfg_type_nameportiplist = { 3706 "nameportiplist", cfg_parse_tuple, cfg_print_tuple, 3707 cfg_doc_tuple, &cfg_rep_tuple, nameportiplist_fields 3708 }; 3709 3710 /*% 3711 * primaries element. 3712 */ 3713 3714 static void 3715 doc_remoteselement(cfg_printer_t *pctx, const cfg_type_t *type) { 3716 UNUSED(type); 3717 cfg_print_cstr(pctx, "( "); 3718 cfg_print_cstr(pctx, "<remote-servers>"); 3719 cfg_print_cstr(pctx, " | "); 3720 cfg_print_cstr(pctx, "<ipv4_address>"); 3721 cfg_print_cstr(pctx, " "); 3722 cfg_print_cstr(pctx, "[ port <integer> ]"); 3723 cfg_print_cstr(pctx, " | "); 3724 cfg_print_cstr(pctx, "<ipv6_address>"); 3725 cfg_print_cstr(pctx, " "); 3726 cfg_print_cstr(pctx, "[ port <integer> ]"); 3727 cfg_print_cstr(pctx, " )"); 3728 } 3729 3730 static isc_result_t 3731 parse_remoteselement(cfg_parser_t *pctx, const cfg_type_t *type, 3732 cfg_obj_t **ret) { 3733 isc_result_t result; 3734 cfg_obj_t *obj = NULL; 3735 UNUSED(type); 3736 3737 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); 3738 if (pctx->token.type == isc_tokentype_string || 3739 pctx->token.type == isc_tokentype_qstring) 3740 { 3741 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK)) 3742 { 3743 CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, 3744 ret)); 3745 } else { 3746 CHECK(cfg_parse_astring(pctx, &cfg_type_astring, ret)); 3747 } 3748 } else { 3749 cfg_parser_error(pctx, CFG_LOG_NEAR, 3750 "expected IP address or remote servers list " 3751 "name"); 3752 return (ISC_R_UNEXPECTEDTOKEN); 3753 } 3754 cleanup: 3755 CLEANUP_OBJ(obj); 3756 return (result); 3757 } 3758 3759 static cfg_type_t cfg_type_remoteselement = { "remotes_element", 3760 parse_remoteselement, 3761 NULL, 3762 doc_remoteselement, 3763 NULL, 3764 NULL }; 3765 3766 static int 3767 cmp_clause(const void *ap, const void *bp) { 3768 const cfg_clausedef_t *a = (const cfg_clausedef_t *)ap; 3769 const cfg_clausedef_t *b = (const cfg_clausedef_t *)bp; 3770 return (strcmp(a->name, b->name)); 3771 } 3772 3773 bool 3774 cfg_clause_validforzone(const char *name, unsigned int ztype) { 3775 const cfg_clausedef_t *clause; 3776 bool valid = false; 3777 3778 for (clause = zone_clauses; clause->name != NULL; clause++) { 3779 if ((clause->flags & ztype) == 0 || 3780 strcmp(clause->name, name) != 0) 3781 { 3782 continue; 3783 } 3784 valid = true; 3785 } 3786 for (clause = zone_only_clauses; clause->name != NULL; clause++) { 3787 if ((clause->flags & ztype) == 0 || 3788 strcmp(clause->name, name) != 0) 3789 { 3790 continue; 3791 } 3792 valid = true; 3793 } 3794 3795 return (valid); 3796 } 3797 3798 void 3799 cfg_print_zonegrammar(const unsigned int zonetype, unsigned int flags, 3800 void (*f)(void *closure, const char *text, int textlen), 3801 void *closure) { 3802 #define NCLAUSES \ 3803 (((sizeof(zone_clauses) + sizeof(zone_only_clauses)) / \ 3804 sizeof(clause[0])) - \ 3805 1) 3806 3807 cfg_printer_t pctx; 3808 cfg_clausedef_t *clause = NULL; 3809 cfg_clausedef_t clauses[NCLAUSES]; 3810 3811 pctx.f = f; 3812 pctx.closure = closure; 3813 pctx.indent = 0; 3814 pctx.flags = flags; 3815 3816 memmove(clauses, zone_clauses, sizeof(zone_clauses)); 3817 memmove(clauses + sizeof(zone_clauses) / sizeof(zone_clauses[0]) - 1, 3818 zone_only_clauses, sizeof(zone_only_clauses)); 3819 qsort(clauses, NCLAUSES - 1, sizeof(clause[0]), cmp_clause); 3820 3821 cfg_print_cstr(&pctx, "zone <string> [ <class> ] {\n"); 3822 pctx.indent++; 3823 3824 switch (zonetype) { 3825 case CFG_ZONE_PRIMARY: 3826 cfg_print_indent(&pctx); 3827 cfg_print_cstr(&pctx, "type ( master | primary );\n"); 3828 break; 3829 case CFG_ZONE_SECONDARY: 3830 cfg_print_indent(&pctx); 3831 cfg_print_cstr(&pctx, "type ( slave | secondary );\n"); 3832 break; 3833 case CFG_ZONE_MIRROR: 3834 cfg_print_indent(&pctx); 3835 cfg_print_cstr(&pctx, "type mirror;\n"); 3836 break; 3837 case CFG_ZONE_STUB: 3838 cfg_print_indent(&pctx); 3839 cfg_print_cstr(&pctx, "type stub;\n"); 3840 break; 3841 case CFG_ZONE_HINT: 3842 cfg_print_indent(&pctx); 3843 cfg_print_cstr(&pctx, "type hint;\n"); 3844 break; 3845 case CFG_ZONE_FORWARD: 3846 cfg_print_indent(&pctx); 3847 cfg_print_cstr(&pctx, "type forward;\n"); 3848 break; 3849 case CFG_ZONE_STATICSTUB: 3850 cfg_print_indent(&pctx); 3851 cfg_print_cstr(&pctx, "type static-stub;\n"); 3852 break; 3853 case CFG_ZONE_REDIRECT: 3854 cfg_print_indent(&pctx); 3855 cfg_print_cstr(&pctx, "type redirect;\n"); 3856 break; 3857 case CFG_ZONE_DELEGATION: 3858 cfg_print_indent(&pctx); 3859 cfg_print_cstr(&pctx, "type delegation-only;\n"); 3860 break; 3861 case CFG_ZONE_INVIEW: 3862 /* no zone type is specified for these */ 3863 break; 3864 default: 3865 UNREACHABLE(); 3866 } 3867 3868 for (clause = clauses; clause->name != NULL; clause++) { 3869 if (((pctx.flags & CFG_PRINTER_ACTIVEONLY) != 0) && 3870 (((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0) || 3871 ((clause->flags & CFG_CLAUSEFLAG_ANCIENT) != 0) || 3872 ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0) || 3873 ((clause->flags & CFG_CLAUSEFLAG_TESTONLY) != 0))) 3874 { 3875 continue; 3876 } 3877 if ((clause->flags & zonetype) == 0 || 3878 strcasecmp(clause->name, "type") == 0) 3879 { 3880 continue; 3881 } 3882 cfg_print_indent(&pctx); 3883 cfg_print_cstr(&pctx, clause->name); 3884 cfg_print_cstr(&pctx, " "); 3885 cfg_doc_obj(&pctx, clause->type); 3886 cfg_print_cstr(&pctx, ";"); 3887 cfg_print_clauseflags(&pctx, clause->flags); 3888 cfg_print_cstr(&pctx, "\n"); 3889 } 3890 3891 pctx.indent--; 3892 cfg_print_cstr(&pctx, "};\n"); 3893 } 3894