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