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