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