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