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