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