namedconf.c revision 1.7
1/* $NetBSD: namedconf.c,v 1.7 2019/10/17 16:47:02 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 * Obsolete format for 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", "siphash24", 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_ANCIENT }, 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_ANCIENT }, 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#if defined(HAVE_GEOIP) || defined(HAVE_GEOIP2) 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_ANCIENT }, 1079 { "heartbeat-interval", &cfg_type_uint32, 0 }, 1080 { "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 1081 { "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_ANCIENT }, 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_ANCIENT }, 1094 { "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_ANCIENT }, 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_ANCIENT }, 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_ANCIENT }, 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_ANCIENT }, 1130 { "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 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 { "add-soa", &cfg_type_boolean, 0 }, 1610 { "log", &cfg_type_boolean, 0 }, 1611 { "max-policy-ttl", &cfg_type_ttlval, 0 }, 1612 { "min-update-interval", &cfg_type_ttlval, 0 }, 1613 { "policy", &cfg_type_rpz_policy, 0 }, 1614 { "recursive-only", &cfg_type_boolean, 0 }, 1615 { "nsip-enable", &cfg_type_boolean, 0 }, 1616 { "nsdname-enable", &cfg_type_boolean, 0 }, 1617 { NULL, NULL, 0 } 1618}; 1619static cfg_type_t cfg_type_rpz_tuple = { 1620 "rpz tuple", cfg_parse_kv_tuple, 1621 cfg_print_kv_tuple, cfg_doc_kv_tuple, &cfg_rep_tuple, 1622 rpz_zone_fields 1623}; 1624static cfg_type_t cfg_type_rpz_list = { 1625 "zone list", cfg_parse_bracketed_list, cfg_print_bracketed_list, 1626 cfg_doc_bracketed_list, &cfg_rep_list, 1627 &cfg_type_rpz_tuple 1628}; 1629static cfg_tuplefielddef_t rpz_fields[] = { 1630 { "zone list", &cfg_type_rpz_list, 0 }, 1631 { "add-soa", &cfg_type_boolean, 0 }, 1632 { "break-dnssec", &cfg_type_boolean, 0 }, 1633 { "max-policy-ttl", &cfg_type_ttlval, 0 }, 1634 { "min-update-interval", &cfg_type_ttlval, 0 }, 1635 { "min-ns-dots", &cfg_type_uint32, 0 }, 1636 { "nsip-wait-recurse", &cfg_type_boolean, 0 }, 1637 { "qname-wait-recurse", &cfg_type_boolean, 0 }, 1638 { "recursive-only", &cfg_type_boolean, 0 }, 1639 { "nsip-enable", &cfg_type_boolean, 0 }, 1640 { "nsdname-enable", &cfg_type_boolean, 0 }, 1641#ifdef USE_DNSRPS 1642 { "dnsrps-enable", &cfg_type_boolean, 0 }, 1643 { "dnsrps-options", &cfg_type_bracketed_text, 0 }, 1644#else 1645 { "dnsrps-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTCONFIGURED }, 1646 { "dnsrps-options", &cfg_type_bracketed_text, 1647 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1648#endif 1649 { NULL, NULL, 0 } 1650}; 1651static cfg_type_t cfg_type_rpz = { 1652 "rpz", cfg_parse_kv_tuple, 1653 cfg_print_kv_tuple, cfg_doc_kv_tuple, &cfg_rep_tuple, 1654 rpz_fields 1655}; 1656 1657/* 1658 * Catalog zones 1659 */ 1660static cfg_type_t cfg_type_catz_zone = { 1661 "zone", parse_keyvalue, print_keyvalue, 1662 doc_keyvalue, &cfg_rep_string, 1663 &zone_kw 1664}; 1665 1666static cfg_tuplefielddef_t catz_zone_fields[] = { 1667 { "zone name", &cfg_type_catz_zone, 0 }, 1668 { "default-masters", &cfg_type_namesockaddrkeylist, 0 }, 1669 { "zone-directory", &cfg_type_qstring, 0 }, 1670 { "in-memory", &cfg_type_boolean, 0 }, 1671 { "min-update-interval", &cfg_type_ttlval, 0 }, 1672 { NULL, NULL, 0 } 1673}; 1674static cfg_type_t cfg_type_catz_tuple = { 1675 "catz tuple", cfg_parse_kv_tuple, 1676 cfg_print_kv_tuple, cfg_doc_kv_tuple, &cfg_rep_tuple, 1677 catz_zone_fields 1678}; 1679static cfg_type_t cfg_type_catz_list = { 1680 "zone list", cfg_parse_bracketed_list, cfg_print_bracketed_list, 1681 cfg_doc_bracketed_list, &cfg_rep_list, 1682 &cfg_type_catz_tuple 1683}; 1684static cfg_tuplefielddef_t catz_fields[] = { 1685 { "zone list", &cfg_type_catz_list, 0 }, 1686 { NULL, NULL, 0 } 1687}; 1688static cfg_type_t cfg_type_catz = { 1689 "catz", cfg_parse_kv_tuple, cfg_print_kv_tuple, 1690 cfg_doc_kv_tuple, &cfg_rep_tuple, catz_fields 1691}; 1692 1693/* 1694 * rate-limit 1695 */ 1696static cfg_clausedef_t rrl_clauses[] = { 1697 { "all-per-second", &cfg_type_uint32, 0 }, 1698 { "errors-per-second", &cfg_type_uint32, 0 }, 1699 { "exempt-clients", &cfg_type_bracketed_aml, 0 }, 1700 { "ipv4-prefix-length", &cfg_type_uint32, 0 }, 1701 { "ipv6-prefix-length", &cfg_type_uint32, 0 }, 1702 { "log-only", &cfg_type_boolean, 0 }, 1703 { "max-table-size", &cfg_type_uint32, 0 }, 1704 { "min-table-size", &cfg_type_uint32, 0 }, 1705 { "nodata-per-second", &cfg_type_uint32, 0 }, 1706 { "nxdomains-per-second", &cfg_type_uint32, 0 }, 1707 { "qps-scale", &cfg_type_uint32, 0 }, 1708 { "referrals-per-second", &cfg_type_uint32, 0 }, 1709 { "responses-per-second", &cfg_type_uint32, 0 }, 1710 { "slip", &cfg_type_uint32, 0 }, 1711 { "window", &cfg_type_uint32, 0 }, 1712 { NULL, NULL, 0 } 1713}; 1714 1715static cfg_clausedef_t *rrl_clausesets[] = { 1716 rrl_clauses, NULL 1717}; 1718 1719static cfg_type_t cfg_type_rrl = { 1720 "rate-limit", cfg_parse_map, cfg_print_map, cfg_doc_map, 1721 &cfg_rep_map, rrl_clausesets 1722}; 1723 1724/*% 1725 * dnssec-lookaside 1726 */ 1727 1728static void 1729print_lookaside(cfg_printer_t *pctx, const cfg_obj_t *obj) { 1730 const cfg_obj_t *domain = obj->value.tuple[0]; 1731 1732 if (domain->value.string.length == 4 && 1733 strncmp(domain->value.string.base, "auto", 4) == 0) 1734 cfg_print_cstr(pctx, "auto"); 1735 else 1736 cfg_print_tuple(pctx, obj); 1737} 1738 1739static void 1740doc_lookaside(cfg_printer_t *pctx, const cfg_type_t *type) { 1741 UNUSED(type); 1742 cfg_print_cstr(pctx, "( <string> trust-anchor <string> | auto | no )"); 1743} 1744 1745static keyword_type_t trustanchor_kw = { "trust-anchor", &cfg_type_astring }; 1746 1747static cfg_type_t cfg_type_optional_trustanchor = { 1748 "optional_trustanchor", parse_optional_keyvalue, print_keyvalue, 1749 doc_keyvalue, &cfg_rep_string, &trustanchor_kw 1750}; 1751 1752static cfg_tuplefielddef_t lookaside_fields[] = { 1753 { "domain", &cfg_type_astring, 0 }, 1754 { "trust-anchor", &cfg_type_optional_trustanchor, 0 }, 1755 { NULL, NULL, 0 } 1756}; 1757 1758static cfg_type_t cfg_type_lookaside = { 1759 "lookaside", cfg_parse_tuple, print_lookaside, doc_lookaside, 1760 &cfg_rep_tuple, lookaside_fields 1761}; 1762 1763static isc_result_t 1764parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type, 1765 cfg_obj_t **ret) 1766{ 1767 isc_result_t result; 1768 UNUSED(type); 1769 1770 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); 1771 if (pctx->token.type == isc_tokentype_number) { 1772 CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret)); 1773 } else { 1774 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret)); 1775 } 1776 cleanup: 1777 return (result); 1778} 1779 1780static void 1781doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) { 1782 UNUSED(type); 1783 cfg_print_cstr(pctx, "[ <integer> ]"); 1784} 1785 1786static cfg_type_t cfg_type_optional_uint32 = { 1787 "optional_uint32", parse_optional_uint32, NULL, doc_optional_uint32, 1788 NULL, NULL 1789}; 1790 1791static cfg_tuplefielddef_t prefetch_fields[] = { 1792 { "trigger", &cfg_type_uint32, 0 }, 1793 { "eligible", &cfg_type_optional_uint32, 0 }, 1794 { NULL, NULL, 0 } 1795}; 1796 1797static cfg_type_t cfg_type_prefetch = { 1798 "prefetch", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 1799 &cfg_rep_tuple, prefetch_fields 1800}; 1801/* 1802 * DNS64. 1803 */ 1804static cfg_clausedef_t 1805dns64_clauses[] = { 1806 { "break-dnssec", &cfg_type_boolean, 0 }, 1807 { "clients", &cfg_type_bracketed_aml, 0 }, 1808 { "exclude", &cfg_type_bracketed_aml, 0 }, 1809 { "mapped", &cfg_type_bracketed_aml, 0 }, 1810 { "recursive-only", &cfg_type_boolean, 0 }, 1811 { "suffix", &cfg_type_netaddr6, 0 }, 1812 { NULL, NULL, 0 }, 1813}; 1814 1815static cfg_clausedef_t * 1816dns64_clausesets[] = { 1817 dns64_clauses, 1818 NULL 1819}; 1820 1821static cfg_type_t cfg_type_dns64 = { 1822 "dns64", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map, 1823 &cfg_rep_map, dns64_clausesets 1824}; 1825 1826/*% 1827 * Clauses that can be found within the 'view' statement, 1828 * with defaults in the 'options' statement. 1829 */ 1830 1831static cfg_clausedef_t 1832view_clauses[] = { 1833 { "acache-cleaning-interval", &cfg_type_uint32, 1834 CFG_CLAUSEFLAG_OBSOLETE }, 1835 { "acache-enable", &cfg_type_boolean, 1836 CFG_CLAUSEFLAG_OBSOLETE }, 1837 { "additional-from-auth", &cfg_type_boolean, 1838 CFG_CLAUSEFLAG_OBSOLETE }, 1839 { "additional-from-cache", &cfg_type_boolean, 1840 CFG_CLAUSEFLAG_OBSOLETE }, 1841 { "allow-new-zones", &cfg_type_boolean, 0 }, 1842 { "allow-query-cache", &cfg_type_bracketed_aml, 0 }, 1843 { "allow-query-cache-on", &cfg_type_bracketed_aml, 0 }, 1844 { "allow-recursion", &cfg_type_bracketed_aml, 0 }, 1845 { "allow-recursion-on", &cfg_type_bracketed_aml, 0 }, 1846 { "allow-v6-synthesis", &cfg_type_bracketed_aml, 1847 CFG_CLAUSEFLAG_OBSOLETE }, 1848 { "attach-cache", &cfg_type_astring, 0 }, 1849 { "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT }, 1850 { "cache-file", &cfg_type_qstring, 0 }, 1851 { "catalog-zones", &cfg_type_catz, 0 }, 1852 { "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI }, 1853 { "cleaning-interval", &cfg_type_uint32, 0 }, 1854 { "clients-per-query", &cfg_type_uint32, 0 }, 1855 { "deny-answer-addresses", &cfg_type_denyaddresses, 0 }, 1856 { "deny-answer-aliases", &cfg_type_denyaliases, 0 }, 1857 { "disable-algorithms", &cfg_type_disablealgorithm, 1858 CFG_CLAUSEFLAG_MULTI }, 1859 { "disable-ds-digests", &cfg_type_disabledsdigest, 1860 CFG_CLAUSEFLAG_MULTI }, 1861 { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI }, 1862 { "dns64", &cfg_type_dns64, CFG_CLAUSEFLAG_MULTI }, 1863 { "dns64-contact", &cfg_type_astring, 0 }, 1864 { "dns64-server", &cfg_type_astring, 0 }, 1865#ifdef USE_DNSRPS 1866 { "dnsrps-enable", &cfg_type_boolean, 0 }, 1867 { "dnsrps-options", &cfg_type_bracketed_text, 0 }, 1868#else 1869 { "dnsrps-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTCONFIGURED }, 1870 { "dnsrps-options", &cfg_type_bracketed_text, 1871 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1872#endif 1873 { "dnssec-accept-expired", &cfg_type_boolean, 0 }, 1874 { "dnssec-enable", &cfg_type_boolean, 0 }, 1875 { "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI }, 1876 { "dnssec-must-be-secure", &cfg_type_mustbesecure, 1877 CFG_CLAUSEFLAG_MULTI }, 1878 { "dnssec-validation", &cfg_type_boolorauto, 0 }, 1879#ifdef HAVE_DNSTAP 1880 { "dnstap", &cfg_type_dnstap, 0 }, 1881#else 1882 { "dnstap", &cfg_type_dnstap, CFG_CLAUSEFLAG_NOTCONFIGURED }, 1883#endif /* HAVE_DNSTAP */ 1884 { "dual-stack-servers", &cfg_type_nameportiplist, 0 }, 1885 { "edns-udp-size", &cfg_type_uint32, 0 }, 1886 { "empty-contact", &cfg_type_astring, 0 }, 1887 { "empty-server", &cfg_type_astring, 0 }, 1888 { "empty-zones-enable", &cfg_type_boolean, 0 }, 1889 { "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 1890 { "fetch-quota-params", &cfg_type_fetchquota, 0 }, 1891 { "fetches-per-server", &cfg_type_fetchesper, 0 }, 1892 { "fetches-per-zone", &cfg_type_fetchesper, 0 }, 1893 { "filter-aaaa", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_OBSOLETE }, 1894 { "filter-aaaa-on-v4", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 1895 { "filter-aaaa-on-v6", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 1896 { "glue-cache", &cfg_type_boolean, 0 }, 1897 { "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 }, 1898 { "lame-ttl", &cfg_type_ttlval, 0 }, 1899#ifdef HAVE_LMDB 1900 { "lmdb-mapsize", &cfg_type_sizeval, 0 }, 1901#else 1902 { "lmdb-mapsize", &cfg_type_sizeval, CFG_CLAUSEFLAG_NOOP }, 1903#endif 1904 { "max-acache-size", &cfg_type_sizenodefault, CFG_CLAUSEFLAG_OBSOLETE }, 1905 { "max-cache-size", &cfg_type_sizeorpercent, 0 }, 1906 { "max-cache-ttl", &cfg_type_ttlval, 0 }, 1907 { "max-clients-per-query", &cfg_type_uint32, 0 }, 1908 { "max-ncache-ttl", &cfg_type_ttlval, 0 }, 1909 { "max-recursion-depth", &cfg_type_uint32, 0 }, 1910 { "max-recursion-queries", &cfg_type_uint32, 0 }, 1911 { "max-stale-ttl", &cfg_type_ttlval, 0 }, 1912 { "max-udp-size", &cfg_type_uint32, 0 }, 1913 { "message-compression", &cfg_type_boolean, 0 }, 1914 { "min-cache-ttl", &cfg_type_ttlval, 0 }, 1915 { "min-ncache-ttl", &cfg_type_ttlval, 0 }, 1916 { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_ANCIENT }, 1917 { "minimal-any", &cfg_type_boolean, 0 }, 1918 { "minimal-responses", &cfg_type_minimal, 0 }, 1919 { "new-zones-directory", &cfg_type_qstring, 0 }, 1920 { "no-case-compress", &cfg_type_bracketed_aml, 0 }, 1921 { "nocookie-udp-size", &cfg_type_uint32, 0 }, 1922 { "nosit-udp-size", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE }, 1923 { "nta-lifetime", &cfg_type_ttlval, 0 }, 1924 { "nta-recheck", &cfg_type_ttlval, 0 }, 1925 { "nxdomain-redirect", &cfg_type_astring, 0 }, 1926 { "preferred-glue", &cfg_type_astring, 0 }, 1927 { "prefetch", &cfg_type_prefetch, 0 }, 1928 { "provide-ixfr", &cfg_type_boolean, 0 }, 1929 { "qname-minimization", &cfg_type_qminmethod, 0 }, 1930 /* 1931 * Note that the query-source option syntax is different 1932 * from the other -source options. 1933 */ 1934 { "query-source", &cfg_type_querysource4, 0 }, 1935 { "query-source-v6", &cfg_type_querysource6, 0 }, 1936 { "queryport-pool-ports", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE }, 1937 { "queryport-pool-updateinterval", &cfg_type_uint32, 1938 CFG_CLAUSEFLAG_OBSOLETE }, 1939 { "rate-limit", &cfg_type_rrl, 0 }, 1940 { "recursion", &cfg_type_boolean, 0 }, 1941 { "request-nsid", &cfg_type_boolean, 0 }, 1942 { "request-sit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 1943 { "require-server-cookie", &cfg_type_boolean, 0 }, 1944 { "resolver-nonbackoff-tries", &cfg_type_uint32, 0 }, 1945 { "resolver-query-timeout", &cfg_type_uint32, 0 }, 1946 { "resolver-retry-interval", &cfg_type_uint32, 0 }, 1947 { "response-padding", &cfg_type_resppadding, 0 }, 1948 { "response-policy", &cfg_type_rpz, 0 }, 1949 { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT }, 1950 { "root-delegation-only", &cfg_type_optional_exclude, 0 }, 1951 { "root-key-sentinel", &cfg_type_boolean, 0 }, 1952 { "rrset-order", &cfg_type_rrsetorder, 0 }, 1953 { "send-cookie", &cfg_type_boolean, 0 }, 1954 { "servfail-ttl", &cfg_type_ttlval, 0 }, 1955 { "sortlist", &cfg_type_bracketed_aml, 0 }, 1956 { "stale-answer-enable", &cfg_type_boolean, 0 }, 1957 { "stale-answer-ttl", &cfg_type_ttlval, 0 }, 1958 { "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI }, 1959 { "synth-from-dnssec", &cfg_type_boolean, 0 }, 1960 { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_ANCIENT }, 1961 { "transfer-format", &cfg_type_transferformat, 0 }, 1962 { "trust-anchor-telemetry", &cfg_type_boolean, 1963 CFG_CLAUSEFLAG_EXPERIMENTAL }, 1964 { "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 1965 { "validate-except", &cfg_type_namelist, 0 }, 1966 { "v6-bias", &cfg_type_uint32, 0 }, 1967 { "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 }, 1968 { NULL, NULL, 0 } 1969}; 1970 1971/*% 1972 * Clauses that can be found within the 'view' statement only. 1973 */ 1974static cfg_clausedef_t 1975view_only_clauses[] = { 1976 { "match-clients", &cfg_type_bracketed_aml, 0 }, 1977 { "match-destinations", &cfg_type_bracketed_aml, 0 }, 1978 { "match-recursive-only", &cfg_type_boolean, 0 }, 1979 { NULL, NULL, 0 } 1980}; 1981 1982/*% 1983 * Sig-validity-interval. 1984 */ 1985 1986static cfg_tuplefielddef_t validityinterval_fields[] = { 1987 { "validity", &cfg_type_uint32, 0 }, 1988 { "re-sign", &cfg_type_optional_uint32, 0 }, 1989 { NULL, NULL, 0 } 1990}; 1991 1992static cfg_type_t cfg_type_validityinterval = { 1993 "validityinterval", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 1994 &cfg_rep_tuple, validityinterval_fields 1995}; 1996 1997/*% 1998 * Clauses that can be found in a 'zone' statement, 1999 * with defaults in the 'view' or 'options' statement. 2000 * 2001 * Note: CFG_ZONE_* options indicate in which zone types this clause is 2002 * legal. 2003 */ 2004static cfg_clausedef_t 2005zone_clauses[] = { 2006 { "allow-notify", &cfg_type_bracketed_aml, 2007 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2008 }, 2009 { "allow-query", &cfg_type_bracketed_aml, 2010 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | 2011 CFG_ZONE_STUB | CFG_ZONE_REDIRECT | CFG_ZONE_STATICSTUB 2012 }, 2013 { "allow-query-on", &cfg_type_bracketed_aml, 2014 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | 2015 CFG_ZONE_STUB | CFG_ZONE_REDIRECT | CFG_ZONE_STATICSTUB 2016 }, 2017 { "allow-transfer", &cfg_type_bracketed_aml, 2018 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2019 }, 2020 { "allow-update", &cfg_type_bracketed_aml, 2021 CFG_ZONE_MASTER 2022 }, 2023 { "allow-update-forwarding", &cfg_type_bracketed_aml, 2024 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2025 }, 2026 { "also-notify", &cfg_type_namesockaddrkeylist, 2027 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2028 }, 2029 { "alt-transfer-source", &cfg_type_sockaddr4wild, 2030 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2031 }, 2032 { "alt-transfer-source-v6", &cfg_type_sockaddr6wild, 2033 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2034 }, 2035 { "auto-dnssec", &cfg_type_autodnssec, 2036 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2037 }, 2038 { "check-dup-records", &cfg_type_checkmode, 2039 CFG_ZONE_MASTER 2040 }, 2041 { "check-integrity", &cfg_type_boolean, 2042 CFG_ZONE_MASTER 2043 }, 2044 { "check-mx", &cfg_type_checkmode, 2045 CFG_ZONE_MASTER 2046 }, 2047 { "check-mx-cname", &cfg_type_checkmode, 2048 CFG_ZONE_MASTER 2049 }, 2050 { "check-sibling", &cfg_type_boolean, 2051 CFG_ZONE_MASTER 2052 }, 2053 { "check-spf", &cfg_type_warn, 2054 CFG_ZONE_MASTER 2055 }, 2056 { "check-srv-cname", &cfg_type_checkmode, 2057 CFG_ZONE_MASTER 2058 }, 2059 { "check-wildcard", &cfg_type_boolean, 2060 CFG_ZONE_MASTER 2061 }, 2062 { "dialup", &cfg_type_dialuptype, 2063 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB 2064 }, 2065 { "dnssec-dnskey-kskonly", &cfg_type_boolean, 2066 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2067 }, 2068 { "dnssec-loadkeys-interval", &cfg_type_uint32, 2069 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2070 }, 2071 { "dnssec-secure-to-insecure", &cfg_type_boolean, 2072 CFG_ZONE_MASTER 2073 }, 2074 { "dnssec-update-mode", &cfg_type_dnssecupdatemode, 2075 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2076 }, 2077 { "forward", &cfg_type_forwardtype, 2078 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB | 2079 CFG_ZONE_STATICSTUB | CFG_ZONE_FORWARD 2080 }, 2081 { "forwarders", &cfg_type_portiplist, 2082 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB | 2083 CFG_ZONE_STATICSTUB | CFG_ZONE_FORWARD 2084 }, 2085 { "inline-signing", &cfg_type_boolean, 2086 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2087 }, 2088 { "key-directory", &cfg_type_qstring, 2089 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2090 }, 2091 { "maintain-ixfr-base", &cfg_type_boolean, 2092 CFG_CLAUSEFLAG_ANCIENT 2093 }, 2094 { "masterfile-format", &cfg_type_masterformat, 2095 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | 2096 CFG_ZONE_STUB | CFG_ZONE_REDIRECT 2097 }, 2098 { "masterfile-style", &cfg_type_masterstyle, 2099 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | 2100 CFG_ZONE_STUB | CFG_ZONE_REDIRECT 2101 }, 2102 { "max-ixfr-log-size", &cfg_type_size, 2103 CFG_CLAUSEFLAG_ANCIENT 2104 }, 2105 { "max-journal-size", &cfg_type_size, 2106 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2107 }, 2108 { "max-records", &cfg_type_uint32, 2109 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | 2110 CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT 2111 }, 2112 { "max-refresh-time", &cfg_type_uint32, 2113 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB 2114 }, 2115 { "max-retry-time", &cfg_type_uint32, 2116 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB 2117 }, 2118 { "max-transfer-idle-in", &cfg_type_uint32, 2119 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB 2120 }, 2121 { "max-transfer-idle-out", &cfg_type_uint32, 2122 CFG_ZONE_MASTER | CFG_ZONE_MIRROR | CFG_ZONE_SLAVE 2123 }, 2124 { "max-transfer-time-in", &cfg_type_uint32, 2125 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB 2126 }, 2127 { "max-transfer-time-out", &cfg_type_uint32, 2128 CFG_ZONE_MASTER | CFG_ZONE_MIRROR | CFG_ZONE_SLAVE 2129 }, 2130 { "max-zone-ttl", &cfg_type_maxttl, 2131 CFG_ZONE_MASTER | CFG_ZONE_REDIRECT 2132 }, 2133 { "min-refresh-time", &cfg_type_uint32, 2134 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB 2135 }, 2136 { "min-retry-time", &cfg_type_uint32, 2137 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB 2138 }, 2139 { "multi-master", &cfg_type_boolean, 2140 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB 2141 }, 2142 { "notify", &cfg_type_notifytype, 2143 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2144 }, 2145 { "notify-delay", &cfg_type_uint32, 2146 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2147 }, 2148 { "notify-source", &cfg_type_sockaddr4wild, 2149 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2150 }, 2151 { "notify-source-v6", &cfg_type_sockaddr6wild, 2152 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2153 }, 2154 { "notify-to-soa", &cfg_type_boolean, 2155 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2156 }, 2157 { "nsec3-test-zone", &cfg_type_boolean, 2158 CFG_CLAUSEFLAG_TESTONLY | 2159 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2160 }, 2161 { "request-expire", &cfg_type_boolean, 2162 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2163 }, 2164 { "request-ixfr", &cfg_type_boolean, 2165 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2166 }, 2167 { "serial-update-method", &cfg_type_updatemethod, 2168 CFG_ZONE_MASTER 2169 }, 2170 { "sig-signing-nodes", &cfg_type_uint32, 2171 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2172 }, 2173 { "sig-signing-signatures", &cfg_type_uint32, 2174 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2175 }, 2176 { "sig-signing-type", &cfg_type_uint32, 2177 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2178 }, 2179 { "sig-validity-interval", &cfg_type_validityinterval, 2180 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2181 }, 2182 { "dnskey-sig-validity", &cfg_type_uint32, 2183 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2184 }, 2185 { "transfer-source", &cfg_type_sockaddr4wild, 2186 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB 2187 }, 2188 { "transfer-source-v6", &cfg_type_sockaddr6wild, 2189 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB 2190 }, 2191 { "try-tcp-refresh", &cfg_type_boolean, 2192 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2193 }, 2194 { "update-check-ksk", &cfg_type_boolean, 2195 CFG_ZONE_MASTER | CFG_ZONE_SLAVE 2196 }, 2197 { "use-alt-transfer-source", &cfg_type_boolean, 2198 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB 2199 }, 2200 { "zero-no-soa-ttl", &cfg_type_boolean, 2201 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2202 }, 2203 { "zone-statistics", &cfg_type_zonestat, 2204 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | 2205 CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT 2206 }, 2207 { NULL, NULL, 0 } 2208}; 2209 2210/*% 2211 * Clauses that can be found in a 'zone' statement only. 2212 * 2213 * Note: CFG_ZONE_* options indicate in which zone types this clause is 2214 * legal. 2215 */ 2216static cfg_clausedef_t 2217zone_only_clauses[] = { 2218 /* 2219 * Note that the format of the check-names option is different between 2220 * the zone options and the global/view options. Ugh. 2221 */ 2222 { "type", &cfg_type_zonetype, 2223 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | 2224 CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_DELEGATION | 2225 CFG_ZONE_HINT | CFG_ZONE_REDIRECT | CFG_ZONE_FORWARD 2226 }, 2227 { "check-names", &cfg_type_checkmode, 2228 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | 2229 CFG_ZONE_HINT | CFG_ZONE_STUB 2230 }, 2231 { "database", &cfg_type_astring, 2232 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | 2233 CFG_ZONE_STUB 2234 }, 2235 { "delegation-only", &cfg_type_boolean, 2236 CFG_ZONE_HINT | CFG_ZONE_STUB | CFG_ZONE_FORWARD 2237 }, 2238 { "dlz", &cfg_type_astring, 2239 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_REDIRECT 2240 }, 2241 { "file", &cfg_type_qstring, 2242 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | 2243 CFG_ZONE_STUB | CFG_ZONE_HINT | CFG_ZONE_REDIRECT 2244 }, 2245 { "in-view", &cfg_type_astring, 2246 CFG_ZONE_INVIEW 2247 }, 2248 { "ixfr-base", &cfg_type_qstring, 2249 CFG_CLAUSEFLAG_ANCIENT 2250 }, 2251 { "ixfr-from-differences", &cfg_type_boolean, 2252 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2253 }, 2254 { "ixfr-tmp-file", &cfg_type_qstring, 2255 CFG_CLAUSEFLAG_ANCIENT 2256 }, 2257 { "journal", &cfg_type_qstring, 2258 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR 2259 }, 2260 { "masters", &cfg_type_namesockaddrkeylist, 2261 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB | 2262 CFG_ZONE_REDIRECT 2263 }, 2264 { "pubkey", &cfg_type_pubkey, 2265 CFG_CLAUSEFLAG_ANCIENT 2266 }, 2267 { "server-addresses", &cfg_type_bracketed_netaddrlist, 2268 CFG_ZONE_STATICSTUB 2269 }, 2270 { "server-names", &cfg_type_namelist, 2271 CFG_ZONE_STATICSTUB 2272 }, 2273 { "update-policy", &cfg_type_updatepolicy, 2274 CFG_ZONE_MASTER 2275 }, 2276 { NULL, NULL, 0 } 2277}; 2278 2279/*% The top-level named.conf syntax. */ 2280 2281static cfg_clausedef_t * 2282namedconf_clausesets[] = { 2283 namedconf_clauses, 2284 namedconf_or_view_clauses, 2285 NULL 2286}; 2287LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = { 2288 "namedconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, 2289 &cfg_rep_map, namedconf_clausesets 2290}; 2291 2292/*% The bind.keys syntax (trusted-keys/managed-keys only). */ 2293static cfg_clausedef_t * 2294bindkeys_clausesets[] = { 2295 bindkeys_clauses, 2296 NULL 2297}; 2298LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bindkeys = { 2299 "bindkeys", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, 2300 &cfg_rep_map, bindkeys_clausesets 2301}; 2302 2303/*% The "options" statement syntax. */ 2304 2305static cfg_clausedef_t * 2306options_clausesets[] = { 2307 options_clauses, 2308 view_clauses, 2309 zone_clauses, 2310 NULL 2311}; 2312static cfg_type_t cfg_type_options = { 2313 "options", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, 2314 options_clausesets 2315}; 2316 2317/*% The "view" statement syntax. */ 2318 2319static cfg_clausedef_t * 2320view_clausesets[] = { 2321 view_only_clauses, 2322 namedconf_or_view_clauses, 2323 view_clauses, 2324 zone_clauses, 2325 NULL 2326}; 2327 2328static cfg_type_t cfg_type_viewopts = { 2329 "view", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, 2330 view_clausesets 2331}; 2332 2333/*% The "zone" statement syntax. */ 2334 2335static cfg_clausedef_t * 2336zone_clausesets[] = { 2337 zone_only_clauses, 2338 zone_clauses, 2339 NULL 2340}; 2341LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_zoneopts = { 2342 "zoneopts", cfg_parse_map, cfg_print_map, 2343 cfg_doc_map, &cfg_rep_map, zone_clausesets }; 2344 2345/*% The "dynamically loadable zones" statement syntax. */ 2346 2347static cfg_clausedef_t 2348dlz_clauses[] = { 2349 { "database", &cfg_type_astring, 0 }, 2350 { "search", &cfg_type_boolean, 0 }, 2351 { NULL, NULL, 0 } 2352}; 2353static cfg_clausedef_t * 2354dlz_clausesets[] = { 2355 dlz_clauses, 2356 NULL 2357}; 2358static cfg_type_t cfg_type_dlz = { 2359 "dlz", cfg_parse_named_map, cfg_print_map, cfg_doc_map, 2360 &cfg_rep_map, dlz_clausesets 2361}; 2362 2363/*% 2364 * The "dyndb" statement syntax. 2365 */ 2366 2367static cfg_tuplefielddef_t dyndb_fields[] = { 2368 { "name", &cfg_type_astring, 0 }, 2369 { "library", &cfg_type_qstring, 0 }, 2370 { "parameters", &cfg_type_bracketed_text, 0 }, 2371 { NULL, NULL, 0 } 2372}; 2373 2374static cfg_type_t cfg_type_dyndb = { 2375 "dyndb", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 2376 &cfg_rep_tuple, dyndb_fields 2377}; 2378 2379/*% 2380 * The "plugin" statement syntax. 2381 * Currently only one plugin type is supported: query. 2382 */ 2383 2384static const char *plugin_enums[] = { 2385 "query", NULL 2386}; 2387static cfg_type_t cfg_type_plugintype = { 2388 "plugintype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, 2389 &cfg_rep_string, plugin_enums 2390}; 2391static cfg_tuplefielddef_t plugin_fields[] = { 2392 { "type", &cfg_type_plugintype, 0 }, 2393 { "library", &cfg_type_astring, 0 }, 2394 { "parameters", &cfg_type_optional_bracketed_text, 0 }, 2395 { NULL, NULL, 0 } 2396}; 2397static cfg_type_t cfg_type_plugin = { 2398 "plugin", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 2399 &cfg_rep_tuple, plugin_fields 2400}; 2401 2402/*% 2403 * Clauses that can be found within the 'key' statement. 2404 */ 2405static cfg_clausedef_t 2406key_clauses[] = { 2407 { "algorithm", &cfg_type_astring, 0 }, 2408 { "secret", &cfg_type_sstring, 0 }, 2409 { NULL, NULL, 0 } 2410}; 2411 2412static cfg_clausedef_t * 2413key_clausesets[] = { 2414 key_clauses, 2415 NULL 2416}; 2417static cfg_type_t cfg_type_key = { 2418 "key", cfg_parse_named_map, cfg_print_map, 2419 cfg_doc_map, &cfg_rep_map, key_clausesets 2420}; 2421 2422 2423/*% 2424 * Clauses that can be found in a 'server' statement. 2425 */ 2426static cfg_clausedef_t 2427server_clauses[] = { 2428 { "bogus", &cfg_type_boolean, 0 }, 2429 { "edns", &cfg_type_boolean, 0 }, 2430 { "edns-udp-size", &cfg_type_uint32, 0 }, 2431 { "edns-version", &cfg_type_uint32, 0 }, 2432 { "keys", &cfg_type_server_key_kludge, 0 }, 2433 { "max-udp-size", &cfg_type_uint32, 0 }, 2434 { "notify-source", &cfg_type_sockaddr4wild, 0 }, 2435 { "notify-source-v6", &cfg_type_sockaddr6wild, 0 }, 2436 { "padding", &cfg_type_uint32, 0 }, 2437 { "provide-ixfr", &cfg_type_boolean, 0 }, 2438 { "query-source", &cfg_type_querysource4, 0 }, 2439 { "query-source-v6", &cfg_type_querysource6, 0 }, 2440 { "request-expire", &cfg_type_boolean, 0 }, 2441 { "request-ixfr", &cfg_type_boolean, 0 }, 2442 { "request-nsid", &cfg_type_boolean, 0 }, 2443 { "request-sit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 2444 { "send-cookie", &cfg_type_boolean, 0 }, 2445 { "support-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 2446 { "tcp-keepalive", &cfg_type_boolean, 0 }, 2447 { "tcp-only", &cfg_type_boolean, 0 }, 2448 { "transfer-format", &cfg_type_transferformat, 0 }, 2449 { "transfer-source", &cfg_type_sockaddr4wild, 0 }, 2450 { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 }, 2451 { "transfers", &cfg_type_uint32, 0 }, 2452 { NULL, NULL, 0 } 2453}; 2454static cfg_clausedef_t * 2455server_clausesets[] = { 2456 server_clauses, 2457 NULL 2458}; 2459static cfg_type_t cfg_type_server = { 2460 "server", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map, 2461 &cfg_rep_map, server_clausesets 2462}; 2463 2464/*% 2465 * Clauses that can be found in a 'channel' clause in the 2466 * 'logging' statement. 2467 * 2468 * These have some additional constraints that need to be 2469 * checked after parsing: 2470 * - There must exactly one of file/syslog/null/stderr 2471 */ 2472 2473static const char *printtime_enums[] = { 2474 "iso8601", "iso8601-utc", "local", NULL 2475}; 2476static isc_result_t 2477parse_printtime(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2478 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 2479} 2480static void 2481doc_printtime(cfg_printer_t *pctx, const cfg_type_t *type) { 2482 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); 2483} 2484static cfg_type_t cfg_type_printtime = { 2485 "printtime", parse_printtime, cfg_print_ustring, doc_printtime, 2486 &cfg_rep_string, printtime_enums 2487}; 2488 2489static cfg_clausedef_t 2490channel_clauses[] = { 2491 /* Destinations. We no longer require these to be first. */ 2492 { "file", &cfg_type_logfile, 0 }, 2493 { "syslog", &cfg_type_optional_facility, 0 }, 2494 { "null", &cfg_type_void, 0 }, 2495 { "stderr", &cfg_type_void, 0 }, 2496 /* Options. We now accept these for the null channel, too. */ 2497 { "severity", &cfg_type_logseverity, 0 }, 2498 { "print-time", &cfg_type_printtime, 0 }, 2499 { "print-severity", &cfg_type_boolean, 0 }, 2500 { "print-category", &cfg_type_boolean, 0 }, 2501 { "buffered", &cfg_type_boolean, 0 }, 2502 { NULL, NULL, 0 } 2503}; 2504static cfg_clausedef_t * 2505channel_clausesets[] = { 2506 channel_clauses, 2507 NULL 2508}; 2509static cfg_type_t cfg_type_channel = { 2510 "channel", cfg_parse_named_map, cfg_print_map, cfg_doc_map, 2511 &cfg_rep_map, channel_clausesets 2512}; 2513 2514/*% A list of log destination, used in the "category" clause. */ 2515static cfg_type_t cfg_type_destinationlist = { 2516 "destinationlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, 2517 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring 2518}; 2519 2520/*% 2521 * Clauses that can be found in a 'logging' statement. 2522 */ 2523static cfg_clausedef_t logging_clauses[] = { 2524 { "channel", &cfg_type_channel, CFG_CLAUSEFLAG_MULTI }, 2525 { "category", &cfg_type_category, CFG_CLAUSEFLAG_MULTI }, 2526 { NULL, NULL, 0 } 2527}; 2528static cfg_clausedef_t * logging_clausesets[] = { 2529 logging_clauses, NULL 2530}; 2531static cfg_type_t cfg_type_logging = { 2532 "logging", cfg_parse_map, cfg_print_map, cfg_doc_map, 2533 &cfg_rep_map, logging_clausesets 2534}; 2535 2536/*% 2537 * For parsing an 'addzone' statement 2538 */ 2539static cfg_tuplefielddef_t addzone_fields[] = { 2540 { "name", &cfg_type_astring, 0 }, 2541 { "class", &cfg_type_optional_class, 0 }, 2542 { "view", &cfg_type_optional_class, 0 }, 2543 { "options", &cfg_type_zoneopts, 0 }, 2544 { NULL, NULL, 0 } 2545}; 2546static cfg_type_t cfg_type_addzone = { 2547 "zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 2548 &cfg_rep_tuple, addzone_fields 2549}; 2550 2551static cfg_clausedef_t 2552addzoneconf_clauses[] = { 2553 { "zone", &cfg_type_addzone, CFG_CLAUSEFLAG_MULTI }, 2554 { NULL, NULL, 0 } 2555}; 2556 2557static cfg_clausedef_t * 2558addzoneconf_clausesets[] = { 2559 addzoneconf_clauses, 2560 NULL 2561}; 2562 2563LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_addzoneconf = { 2564 "addzoneconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, 2565 &cfg_rep_map, addzoneconf_clausesets 2566}; 2567 2568static isc_result_t 2569parse_unitstring(char *str, isc_resourcevalue_t *valuep) { 2570 char *endp; 2571 unsigned int len; 2572 uint64_t value; 2573 uint64_t unit; 2574 2575 value = strtoull(str, &endp, 10); 2576 if (*endp == 0) { 2577 *valuep = value; 2578 return (ISC_R_SUCCESS); 2579 } 2580 2581 len = strlen(str); 2582 if (len < 2 || endp[1] != '\0') 2583 return (ISC_R_FAILURE); 2584 2585 switch (str[len - 1]) { 2586 case 'k': 2587 case 'K': 2588 unit = 1024; 2589 break; 2590 case 'm': 2591 case 'M': 2592 unit = 1024 * 1024; 2593 break; 2594 case 'g': 2595 case 'G': 2596 unit = 1024 * 1024 * 1024; 2597 break; 2598 default: 2599 return (ISC_R_FAILURE); 2600 } 2601 if (value > ((uint64_t)UINT64_MAX / unit)) { 2602 return (ISC_R_FAILURE); 2603 } 2604 *valuep = value * unit; 2605 return (ISC_R_SUCCESS); 2606} 2607 2608static isc_result_t 2609parse_sizeval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2610 isc_result_t result; 2611 cfg_obj_t *obj = NULL; 2612 uint64_t val; 2613 2614 UNUSED(type); 2615 2616 CHECK(cfg_gettoken(pctx, 0)); 2617 if (pctx->token.type != isc_tokentype_string) { 2618 result = ISC_R_UNEXPECTEDTOKEN; 2619 goto cleanup; 2620 } 2621 CHECK(parse_unitstring(TOKEN_STRING(pctx), &val)); 2622 2623 CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj)); 2624 obj->value.uint64 = val; 2625 *ret = obj; 2626 return (ISC_R_SUCCESS); 2627 2628 cleanup: 2629 cfg_parser_error(pctx, CFG_LOG_NEAR, 2630 "expected integer and optional unit"); 2631 return (result); 2632} 2633 2634static isc_result_t 2635parse_sizeval_percent(cfg_parser_t *pctx, const cfg_type_t *type, 2636 cfg_obj_t **ret) 2637{ 2638 char *endp; 2639 isc_result_t result; 2640 cfg_obj_t *obj = NULL; 2641 uint64_t val; 2642 uint64_t percent; 2643 2644 UNUSED(type); 2645 2646 CHECK(cfg_gettoken(pctx, 0)); 2647 if (pctx->token.type != isc_tokentype_string) { 2648 result = ISC_R_UNEXPECTEDTOKEN; 2649 goto cleanup; 2650 } 2651 2652 percent = strtoull(TOKEN_STRING(pctx), &endp, 10); 2653 2654 if (*endp == '%' && *(endp+1) == 0) { 2655 CHECK(cfg_create_obj(pctx, &cfg_type_percentage, &obj)); 2656 obj->value.uint32 = (uint32_t)percent; 2657 *ret = obj; 2658 return (ISC_R_SUCCESS); 2659 } else { 2660 CHECK(parse_unitstring(TOKEN_STRING(pctx), &val)); 2661 CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj)); 2662 obj->value.uint64 = val; 2663 *ret = obj; 2664 return (ISC_R_SUCCESS); 2665 } 2666 2667 cleanup: 2668 cfg_parser_error(pctx, CFG_LOG_NEAR, 2669 "expected integer and optional unit or percent"); 2670 return (result); 2671} 2672 2673static void 2674doc_sizeval_percent(cfg_printer_t *pctx, const cfg_type_t *type) { 2675 2676 UNUSED(type); 2677 2678 cfg_print_cstr(pctx, "( "); 2679 cfg_doc_terminal(pctx, &cfg_type_size); 2680 cfg_print_cstr(pctx, " | "); 2681 cfg_doc_terminal(pctx, &cfg_type_percentage); 2682 cfg_print_cstr(pctx, " )"); 2683} 2684 2685/*% 2686 * A size value (number + optional unit). 2687 */ 2688static cfg_type_t cfg_type_sizeval = { 2689 "sizeval", parse_sizeval, cfg_print_uint64, cfg_doc_terminal, 2690 &cfg_rep_uint64, NULL 2691}; 2692 2693/*% 2694 * A size, "unlimited", or "default". 2695 */ 2696 2697static isc_result_t 2698parse_size(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2699 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret)); 2700} 2701 2702static void 2703doc_size(cfg_printer_t *pctx, const cfg_type_t *type) { 2704 cfg_doc_enum_or_other(pctx, type, &cfg_type_sizeval); 2705} 2706 2707static const char *size_enums[] = { "default", "unlimited", NULL }; 2708static cfg_type_t cfg_type_size = { 2709 "size", parse_size, cfg_print_ustring, doc_size, 2710 &cfg_rep_string, size_enums 2711}; 2712 2713/*% 2714 * A size or "unlimited", but not "default". 2715 */ 2716static const char *sizenodefault_enums[] = { "unlimited", NULL }; 2717static cfg_type_t cfg_type_sizenodefault = { 2718 "size_no_default", parse_size, cfg_print_ustring, doc_size, 2719 &cfg_rep_string, sizenodefault_enums 2720}; 2721 2722/*% 2723 * A size in absolute values or percents. 2724 */ 2725static cfg_type_t cfg_type_sizeval_percent = { 2726 "sizeval_percent", parse_sizeval_percent, cfg_print_ustring, 2727 doc_sizeval_percent, &cfg_rep_string, NULL 2728}; 2729 2730/*% 2731 * A size in absolute values or percents, or "unlimited", or "default" 2732 */ 2733 2734static isc_result_t 2735parse_size_or_percent(cfg_parser_t *pctx, const cfg_type_t *type, 2736 cfg_obj_t **ret) 2737{ 2738 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_sizeval_percent, 2739 ret)); 2740} 2741 2742static void 2743doc_parse_size_or_percent(cfg_printer_t *pctx, const cfg_type_t *type) { 2744 UNUSED(type); 2745 cfg_print_cstr(pctx, "( default | unlimited | "); 2746 cfg_doc_terminal(pctx, &cfg_type_sizeval); 2747 cfg_print_cstr(pctx, " | "); 2748 cfg_doc_terminal(pctx, &cfg_type_percentage); 2749 cfg_print_cstr(pctx, " )"); 2750} 2751 2752static const char *sizeorpercent_enums[] = { "default", "unlimited", NULL }; 2753static cfg_type_t cfg_type_sizeorpercent = { 2754 "size_or_percent", parse_size_or_percent, cfg_print_ustring, 2755 doc_parse_size_or_percent, &cfg_rep_string, sizeorpercent_enums 2756}; 2757 2758/*% 2759 * optional_keyvalue 2760 */ 2761static isc_result_t 2762parse_maybe_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, 2763 bool optional, cfg_obj_t **ret) 2764{ 2765 isc_result_t result; 2766 cfg_obj_t *obj = NULL; 2767 const keyword_type_t *kw = type->of; 2768 2769 CHECK(cfg_peektoken(pctx, 0)); 2770 if (pctx->token.type == isc_tokentype_string && 2771 strcasecmp(TOKEN_STRING(pctx), kw->name) == 0) { 2772 CHECK(cfg_gettoken(pctx, 0)); 2773 CHECK(kw->type->parse(pctx, kw->type, &obj)); 2774 obj->type = type; /* XXX kludge */ 2775 } else { 2776 if (optional) { 2777 CHECK(cfg_parse_void(pctx, NULL, &obj)); 2778 } else { 2779 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected '%s'", 2780 kw->name); 2781 result = ISC_R_UNEXPECTEDTOKEN; 2782 goto cleanup; 2783 } 2784 } 2785 *ret = obj; 2786 cleanup: 2787 return (result); 2788} 2789 2790static isc_result_t 2791parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2792 return (parse_maybe_optional_keyvalue(pctx, type, false, ret)); 2793} 2794 2795static isc_result_t 2796parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, 2797 cfg_obj_t **ret) 2798{ 2799 return (parse_maybe_optional_keyvalue(pctx, type, true, ret)); 2800} 2801 2802static void 2803print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj) { 2804 const keyword_type_t *kw = obj->type->of; 2805 cfg_print_cstr(pctx, kw->name); 2806 cfg_print_cstr(pctx, " "); 2807 kw->type->print(pctx, obj); 2808} 2809 2810static void 2811doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) { 2812 const keyword_type_t *kw = type->of; 2813 cfg_print_cstr(pctx, kw->name); 2814 cfg_print_cstr(pctx, " "); 2815 cfg_doc_obj(pctx, kw->type); 2816} 2817 2818static void 2819doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) { 2820 const keyword_type_t *kw = type->of; 2821 cfg_print_cstr(pctx, "[ "); 2822 cfg_print_cstr(pctx, kw->name); 2823 cfg_print_cstr(pctx, " "); 2824 cfg_doc_obj(pctx, kw->type); 2825 cfg_print_cstr(pctx, " ]"); 2826} 2827 2828static const char *dialup_enums[] = { 2829 "notify", "notify-passive", "passive", "refresh", NULL 2830}; 2831static isc_result_t 2832parse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type, 2833 cfg_obj_t **ret) 2834{ 2835 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 2836} 2837static void 2838doc_dialup_type(cfg_printer_t *pctx, const cfg_type_t *type) { 2839 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); 2840} 2841static cfg_type_t cfg_type_dialuptype = { 2842 "dialuptype", parse_dialup_type, cfg_print_ustring, doc_dialup_type, 2843 &cfg_rep_string, dialup_enums 2844}; 2845 2846static const char *notify_enums[] = { "explicit", "master-only", NULL }; 2847static isc_result_t 2848parse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type, 2849 cfg_obj_t **ret) 2850{ 2851 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 2852} 2853static void 2854doc_notify_type(cfg_printer_t *pctx, const cfg_type_t *type) { 2855 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); 2856} 2857static cfg_type_t cfg_type_notifytype = { 2858 "notifytype", parse_notify_type, cfg_print_ustring, doc_notify_type, 2859 &cfg_rep_string, notify_enums, 2860}; 2861 2862static const char *minimal_enums[] = { "no-auth", "no-auth-recursive", NULL }; 2863static isc_result_t 2864parse_minimal(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2865 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 2866} 2867static void 2868doc_minimal(cfg_printer_t *pctx, const cfg_type_t *type) { 2869 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); 2870} 2871static cfg_type_t cfg_type_minimal = { 2872 "mimimal", parse_minimal, cfg_print_ustring, doc_minimal, 2873 &cfg_rep_string, minimal_enums, 2874}; 2875 2876static const char *ixfrdiff_enums[] = { 2877 "primary", "master", "secondary", "slave", NULL 2878}; 2879static isc_result_t 2880parse_ixfrdiff_type(cfg_parser_t *pctx, const cfg_type_t *type, 2881 cfg_obj_t **ret) 2882{ 2883 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 2884} 2885static void 2886doc_ixfrdiff_type(cfg_printer_t *pctx, const cfg_type_t *type) { 2887 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); 2888} 2889static cfg_type_t cfg_type_ixfrdifftype = { 2890 "ixfrdiff", parse_ixfrdiff_type, cfg_print_ustring, doc_ixfrdiff_type, 2891 &cfg_rep_string, ixfrdiff_enums, 2892}; 2893 2894static keyword_type_t key_kw = { "key", &cfg_type_astring }; 2895 2896LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = { 2897 "keyref", parse_keyvalue, print_keyvalue, doc_keyvalue, 2898 &cfg_rep_string, &key_kw 2899}; 2900 2901static cfg_type_t cfg_type_optional_keyref = { 2902 "optional_keyref", parse_optional_keyvalue, print_keyvalue, 2903 doc_optional_keyvalue, &cfg_rep_string, &key_kw 2904}; 2905 2906static const char *qminmethod_enums[] = { 2907 "strict", "relaxed", "disabled", "off", NULL 2908}; 2909 2910static cfg_type_t cfg_type_qminmethod = { 2911 "qminmethod", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, 2912 &cfg_rep_string, qminmethod_enums 2913}; 2914 2915/*% 2916 * A "controls" statement is represented as a map with the multivalued 2917 * "inet" and "unix" clauses. 2918 */ 2919 2920static keyword_type_t controls_allow_kw = { 2921 "allow", &cfg_type_bracketed_aml }; 2922 2923static cfg_type_t cfg_type_controls_allow = { 2924 "controls_allow", parse_keyvalue, 2925 print_keyvalue, doc_keyvalue, 2926 &cfg_rep_list, &controls_allow_kw 2927}; 2928 2929static keyword_type_t controls_keys_kw = { 2930 "keys", &cfg_type_keylist 2931}; 2932 2933static cfg_type_t cfg_type_controls_keys = { 2934 "controls_keys", parse_optional_keyvalue, 2935 print_keyvalue, doc_optional_keyvalue, 2936 &cfg_rep_list, &controls_keys_kw 2937}; 2938 2939static keyword_type_t controls_readonly_kw = { 2940 "read-only", &cfg_type_boolean 2941}; 2942 2943static cfg_type_t cfg_type_controls_readonly = { 2944 "controls_readonly", parse_optional_keyvalue, 2945 print_keyvalue, doc_optional_keyvalue, 2946 &cfg_rep_boolean, &controls_readonly_kw 2947}; 2948 2949static cfg_tuplefielddef_t inetcontrol_fields[] = { 2950 { "address", &cfg_type_controls_sockaddr, 0 }, 2951 { "allow", &cfg_type_controls_allow, 0 }, 2952 { "keys", &cfg_type_controls_keys, 0 }, 2953 { "read-only", &cfg_type_controls_readonly, 0 }, 2954 { NULL, NULL, 0 } 2955}; 2956 2957static cfg_type_t cfg_type_inetcontrol = { 2958 "inetcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 2959 &cfg_rep_tuple, inetcontrol_fields 2960}; 2961 2962static keyword_type_t controls_perm_kw = { 2963 "perm", &cfg_type_uint32 2964}; 2965 2966static cfg_type_t cfg_type_controls_perm = { 2967 "controls_perm", parse_keyvalue, 2968 print_keyvalue, doc_keyvalue, 2969 &cfg_rep_uint32, &controls_perm_kw 2970}; 2971 2972static keyword_type_t controls_owner_kw = { 2973 "owner", &cfg_type_uint32 2974}; 2975 2976static cfg_type_t cfg_type_controls_owner = { 2977 "controls_owner", parse_keyvalue, 2978 print_keyvalue, doc_keyvalue, 2979 &cfg_rep_uint32, &controls_owner_kw 2980}; 2981 2982static keyword_type_t controls_group_kw = { 2983 "group", &cfg_type_uint32 2984}; 2985 2986static cfg_type_t cfg_type_controls_group = { 2987 "controls_allow", parse_keyvalue, 2988 print_keyvalue, doc_keyvalue, 2989 &cfg_rep_uint32, &controls_group_kw 2990}; 2991 2992static cfg_tuplefielddef_t unixcontrol_fields[] = { 2993 { "path", &cfg_type_qstring, 0 }, 2994 { "perm", &cfg_type_controls_perm, 0 }, 2995 { "owner", &cfg_type_controls_owner, 0 }, 2996 { "group", &cfg_type_controls_group, 0 }, 2997 { "keys", &cfg_type_controls_keys, 0 }, 2998 { "read-only", &cfg_type_controls_readonly, 0 }, 2999 { NULL, NULL, 0 } 3000}; 3001 3002static cfg_type_t cfg_type_unixcontrol = { 3003 "unixcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 3004 &cfg_rep_tuple, unixcontrol_fields 3005}; 3006 3007static cfg_clausedef_t 3008controls_clauses[] = { 3009 { "inet", &cfg_type_inetcontrol, CFG_CLAUSEFLAG_MULTI }, 3010 { "unix", &cfg_type_unixcontrol, CFG_CLAUSEFLAG_MULTI }, 3011 { NULL, NULL, 0 } 3012}; 3013 3014static cfg_clausedef_t * 3015controls_clausesets[] = { 3016 controls_clauses, 3017 NULL 3018}; 3019static cfg_type_t cfg_type_controls = { 3020 "controls", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, 3021 &controls_clausesets 3022}; 3023 3024/*% 3025 * A "statistics-channels" statement is represented as a map with the 3026 * multivalued "inet" clauses. 3027 */ 3028static void 3029doc_optional_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) { 3030 const keyword_type_t *kw = type->of; 3031 cfg_print_cstr(pctx, "[ "); 3032 cfg_print_cstr(pctx, kw->name); 3033 cfg_print_cstr(pctx, " "); 3034 cfg_doc_obj(pctx, kw->type); 3035 cfg_print_cstr(pctx, " ]"); 3036} 3037 3038static cfg_type_t cfg_type_optional_allow = { 3039 "optional_allow", parse_optional_keyvalue, print_keyvalue, 3040 doc_optional_bracketed_list, &cfg_rep_list, &controls_allow_kw 3041}; 3042 3043static cfg_tuplefielddef_t statserver_fields[] = { 3044 { "address", &cfg_type_controls_sockaddr, 0 }, /* reuse controls def */ 3045 { "allow", &cfg_type_optional_allow, 0 }, 3046 { NULL, NULL, 0 } 3047}; 3048 3049static cfg_type_t cfg_type_statschannel = { 3050 "statschannel", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 3051 &cfg_rep_tuple, statserver_fields 3052}; 3053 3054static cfg_clausedef_t 3055statservers_clauses[] = { 3056 { "inet", &cfg_type_statschannel, CFG_CLAUSEFLAG_MULTI }, 3057 { NULL, NULL, 0 } 3058}; 3059 3060static cfg_clausedef_t * 3061statservers_clausesets[] = { 3062 statservers_clauses, 3063 NULL 3064}; 3065 3066static cfg_type_t cfg_type_statschannels = { 3067 "statistics-channels", cfg_parse_map, cfg_print_map, cfg_doc_map, 3068 &cfg_rep_map, &statservers_clausesets 3069}; 3070 3071/*% 3072 * An optional class, as used in view and zone statements. 3073 */ 3074static isc_result_t 3075parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type, 3076 cfg_obj_t **ret) 3077{ 3078 isc_result_t result; 3079 UNUSED(type); 3080 CHECK(cfg_peektoken(pctx, 0)); 3081 if (pctx->token.type == isc_tokentype_string) 3082 CHECK(cfg_parse_obj(pctx, &cfg_type_ustring, ret)); 3083 else 3084 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret)); 3085 cleanup: 3086 return (result); 3087} 3088 3089static void 3090doc_optional_class(cfg_printer_t *pctx, const cfg_type_t *type) { 3091 UNUSED(type); 3092 cfg_print_cstr(pctx, "[ <class> ]"); 3093} 3094 3095static cfg_type_t cfg_type_optional_class = { 3096 "optional_class", parse_optional_class, NULL, doc_optional_class, 3097 NULL, NULL 3098}; 3099 3100static isc_result_t 3101parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type, 3102 cfg_obj_t **ret) 3103{ 3104 isc_result_t result; 3105 cfg_obj_t *obj = NULL; 3106 isc_netaddr_t netaddr; 3107 in_port_t port = 0; 3108 isc_dscp_t dscp = -1; 3109 unsigned int have_address = 0; 3110 unsigned int have_port = 0; 3111 unsigned int have_dscp = 0; 3112 const unsigned int *flagp = type->of; 3113 3114 if ((*flagp & CFG_ADDR_V4OK) != 0) { 3115 isc_netaddr_any(&netaddr); 3116 } else if ((*flagp & CFG_ADDR_V6OK) != 0) { 3117 isc_netaddr_any6(&netaddr); 3118 } else { 3119 INSIST(0); 3120 ISC_UNREACHABLE(); 3121 } 3122 3123 for (;;) { 3124 CHECK(cfg_peektoken(pctx, 0)); 3125 if (pctx->token.type == isc_tokentype_string) { 3126 if (strcasecmp(TOKEN_STRING(pctx), 3127 "address") == 0) 3128 { 3129 /* read "address" */ 3130 CHECK(cfg_gettoken(pctx, 0)); 3131 CHECK(cfg_parse_rawaddr(pctx, *flagp, 3132 &netaddr)); 3133 have_address++; 3134 } else if (strcasecmp(TOKEN_STRING(pctx), "port") == 0) 3135 { 3136 /* read "port" */ 3137 CHECK(cfg_gettoken(pctx, 0)); 3138 CHECK(cfg_parse_rawport(pctx, 3139 CFG_ADDR_WILDOK, 3140 &port)); 3141 have_port++; 3142 } else if (strcasecmp(TOKEN_STRING(pctx), "dscp") == 0) 3143 { 3144 /* read "dscp" */ 3145 CHECK(cfg_gettoken(pctx, 0)); 3146 CHECK(cfg_parse_dscp(pctx, &dscp)); 3147 have_dscp++; 3148 } else if (have_port == 0 && have_dscp == 0 && 3149 have_address == 0) 3150 { 3151 return (cfg_parse_sockaddr(pctx, type, ret)); 3152 } else { 3153 cfg_parser_error(pctx, CFG_LOG_NEAR, 3154 "expected 'address', 'port', " 3155 "or 'dscp'"); 3156 return (ISC_R_UNEXPECTEDTOKEN); 3157 } 3158 } else 3159 break; 3160 } 3161 if (have_address > 1 || have_port > 1 || 3162 have_address + have_port == 0) { 3163 cfg_parser_error(pctx, 0, "expected one address and/or port"); 3164 return (ISC_R_UNEXPECTEDTOKEN); 3165 } 3166 3167 if (have_dscp > 1) { 3168 cfg_parser_error(pctx, 0, "expected at most one dscp"); 3169 return (ISC_R_UNEXPECTEDTOKEN); 3170 } 3171 3172 CHECK(cfg_create_obj(pctx, &cfg_type_querysource, &obj)); 3173 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); 3174 obj->value.sockaddrdscp.dscp = dscp; 3175 *ret = obj; 3176 return (ISC_R_SUCCESS); 3177 3178 cleanup: 3179 cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid query source"); 3180 CLEANUP_OBJ(obj); 3181 return (result); 3182} 3183 3184static void 3185print_querysource(cfg_printer_t *pctx, const cfg_obj_t *obj) { 3186 isc_netaddr_t na; 3187 isc_netaddr_fromsockaddr(&na, &obj->value.sockaddr); 3188 cfg_print_cstr(pctx, "address "); 3189 cfg_print_rawaddr(pctx, &na); 3190 cfg_print_cstr(pctx, " port "); 3191 cfg_print_rawuint(pctx, isc_sockaddr_getport(&obj->value.sockaddr)); 3192 if (obj->value.sockaddrdscp.dscp != -1) { 3193 cfg_print_cstr(pctx, " dscp "); 3194 cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp); 3195 } 3196} 3197 3198static void 3199doc_querysource(cfg_printer_t *pctx, const cfg_type_t *type) { 3200 const unsigned int *flagp = type->of; 3201 3202 cfg_print_cstr(pctx, "( ( [ address ] ( "); 3203 if ((*flagp & CFG_ADDR_V4OK) != 0) { 3204 cfg_print_cstr(pctx, "<ipv4_address>"); 3205 } else if ((*flagp & CFG_ADDR_V6OK) != 0) { 3206 cfg_print_cstr(pctx, "<ipv6_address>"); 3207 } else { 3208 INSIST(0); 3209 ISC_UNREACHABLE(); 3210 } 3211 cfg_print_cstr(pctx, " | * ) [ port ( <integer> | * ) ] ) | " 3212 "( [ [ address ] ( "); 3213 if ((*flagp & CFG_ADDR_V4OK) != 0) { 3214 cfg_print_cstr(pctx, "<ipv4_address>"); 3215 } else if ((*flagp & CFG_ADDR_V6OK) != 0) { 3216 cfg_print_cstr(pctx, "<ipv6_address>"); 3217 } else { 3218 INSIST(0); 3219 ISC_UNREACHABLE(); 3220 } 3221 cfg_print_cstr(pctx, " | * ) ] port ( <integer> | * ) ) )" 3222 " [ dscp <integer> ]"); 3223} 3224 3225static unsigned int sockaddr4wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V4OK | 3226 CFG_ADDR_DSCPOK; 3227static unsigned int sockaddr6wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V6OK | 3228 CFG_ADDR_DSCPOK; 3229 3230static cfg_type_t cfg_type_querysource4 = { 3231 "querysource4", parse_querysource, NULL, doc_querysource, 3232 NULL, &sockaddr4wild_flags 3233}; 3234 3235static cfg_type_t cfg_type_querysource6 = { 3236 "querysource6", parse_querysource, NULL, doc_querysource, 3237 NULL, &sockaddr6wild_flags 3238}; 3239 3240static cfg_type_t cfg_type_querysource = { 3241 "querysource", NULL, print_querysource, NULL, &cfg_rep_sockaddr, NULL 3242}; 3243 3244/*% 3245 * The socket address syntax in the "controls" statement is silly. 3246 * It allows both socket address families, but also allows "*", 3247 * whis is gratuitously interpreted as the IPv4 wildcard address. 3248 */ 3249static unsigned int controls_sockaddr_flags = 3250 CFG_ADDR_V4OK | CFG_ADDR_V6OK | CFG_ADDR_WILDOK; 3251static cfg_type_t cfg_type_controls_sockaddr = { 3252 "controls_sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, 3253 cfg_doc_sockaddr, &cfg_rep_sockaddr, &controls_sockaddr_flags 3254}; 3255 3256/*% 3257 * Handle the special kludge syntax of the "keys" clause in the "server" 3258 * statement, which takes a single key with or without braces and semicolon. 3259 */ 3260static isc_result_t 3261parse_server_key_kludge(cfg_parser_t *pctx, const cfg_type_t *type, 3262 cfg_obj_t **ret) 3263{ 3264 isc_result_t result; 3265 bool braces = false; 3266 UNUSED(type); 3267 3268 /* Allow opening brace. */ 3269 CHECK(cfg_peektoken(pctx, 0)); 3270 if (pctx->token.type == isc_tokentype_special && 3271 pctx->token.value.as_char == '{') { 3272 CHECK(cfg_gettoken(pctx, 0)); 3273 braces = true; 3274 } 3275 3276 CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret)); 3277 3278 if (braces) { 3279 /* Skip semicolon if present. */ 3280 CHECK(cfg_peektoken(pctx, 0)); 3281 if (pctx->token.type == isc_tokentype_special && 3282 pctx->token.value.as_char == ';') 3283 CHECK(cfg_gettoken(pctx, 0)); 3284 3285 CHECK(cfg_parse_special(pctx, '}')); 3286 } 3287 cleanup: 3288 return (result); 3289} 3290static cfg_type_t cfg_type_server_key_kludge = { 3291 "server_key", parse_server_key_kludge, NULL, cfg_doc_terminal, 3292 NULL, NULL 3293}; 3294 3295 3296/*% 3297 * An optional logging facility. 3298 */ 3299 3300static isc_result_t 3301parse_optional_facility(cfg_parser_t *pctx, const cfg_type_t *type, 3302 cfg_obj_t **ret) 3303{ 3304 isc_result_t result; 3305 UNUSED(type); 3306 3307 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); 3308 if (pctx->token.type == isc_tokentype_string || 3309 pctx->token.type == isc_tokentype_qstring) { 3310 CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret)); 3311 } else { 3312 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret)); 3313 } 3314 cleanup: 3315 return (result); 3316} 3317 3318static void 3319doc_optional_facility(cfg_printer_t *pctx, const cfg_type_t *type) { 3320 UNUSED(type); 3321 cfg_print_cstr(pctx, "[ <syslog_facility> ]"); 3322} 3323 3324static cfg_type_t cfg_type_optional_facility = { 3325 "optional_facility", parse_optional_facility, NULL, 3326 doc_optional_facility, NULL, NULL 3327}; 3328 3329 3330/*% 3331 * A log severity. Return as a string, except "debug N", 3332 * which is returned as a keyword object. 3333 */ 3334 3335static keyword_type_t debug_kw = { "debug", &cfg_type_uint32 }; 3336static cfg_type_t cfg_type_debuglevel = { 3337 "debuglevel", parse_keyvalue, 3338 print_keyvalue, doc_keyvalue, 3339 &cfg_rep_uint32, &debug_kw 3340}; 3341 3342static isc_result_t 3343parse_logseverity(cfg_parser_t *pctx, const cfg_type_t *type, 3344 cfg_obj_t **ret) 3345{ 3346 isc_result_t result; 3347 UNUSED(type); 3348 3349 CHECK(cfg_peektoken(pctx, 0)); 3350 if (pctx->token.type == isc_tokentype_string && 3351 strcasecmp(TOKEN_STRING(pctx), "debug") == 0) { 3352 CHECK(cfg_gettoken(pctx, 0)); /* read "debug" */ 3353 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER)); 3354 if (pctx->token.type == isc_tokentype_number) { 3355 CHECK(cfg_parse_uint32(pctx, NULL, ret)); 3356 } else { 3357 /* 3358 * The debug level is optional and defaults to 1. 3359 * This makes little sense, but we support it for 3360 * compatibility with BIND 8. 3361 */ 3362 CHECK(cfg_create_obj(pctx, &cfg_type_uint32, ret)); 3363 (*ret)->value.uint32 = 1; 3364 } 3365 (*ret)->type = &cfg_type_debuglevel; /* XXX kludge */ 3366 } else { 3367 CHECK(cfg_parse_obj(pctx, &cfg_type_loglevel, ret)); 3368 } 3369 cleanup: 3370 return (result); 3371} 3372 3373static cfg_type_t cfg_type_logseverity = { 3374 "log_severity", parse_logseverity, NULL, cfg_doc_terminal, 3375 NULL, NULL 3376}; 3377 3378/*% 3379 * The "file" clause of the "channel" statement. 3380 * This is yet another special case. 3381 */ 3382 3383static const char *logversions_enums[] = { "unlimited", NULL }; 3384static isc_result_t 3385parse_logversions(cfg_parser_t *pctx, const cfg_type_t *type, 3386 cfg_obj_t **ret) 3387{ 3388 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_uint32, ret)); 3389} 3390 3391static void 3392doc_logversions(cfg_printer_t *pctx, const cfg_type_t *type) { 3393 cfg_doc_enum_or_other(pctx, type, &cfg_type_uint32); 3394} 3395 3396static cfg_type_t cfg_type_logversions = { 3397 "logversions", parse_logversions, cfg_print_ustring, doc_logversions, 3398 &cfg_rep_string, logversions_enums 3399}; 3400 3401static const char *logsuffix_enums[] = { "increment", "timestamp", NULL }; 3402static cfg_type_t cfg_type_logsuffix = { 3403 "logsuffix", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, 3404 &cfg_rep_string, &logsuffix_enums 3405}; 3406 3407static cfg_tuplefielddef_t logfile_fields[] = { 3408 { "file", &cfg_type_qstring, 0 }, 3409 { "versions", &cfg_type_logversions, 0 }, 3410 { "size", &cfg_type_size, 0 }, 3411 { "suffix", &cfg_type_logsuffix, 0 }, 3412 { NULL, NULL, 0 } 3413}; 3414 3415static isc_result_t 3416parse_logfile(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 3417 isc_result_t result; 3418 cfg_obj_t *obj = NULL; 3419 const cfg_tuplefielddef_t *fields = type->of; 3420 3421 CHECK(cfg_create_tuple(pctx, type, &obj)); 3422 3423 /* Parse the mandatory "file" field */ 3424 CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0])); 3425 3426 /* Parse "versions" and "size" fields in any order. */ 3427 for (;;) { 3428 CHECK(cfg_peektoken(pctx, 0)); 3429 if (pctx->token.type == isc_tokentype_string) { 3430 CHECK(cfg_gettoken(pctx, 0)); 3431 if (strcasecmp(TOKEN_STRING(pctx), 3432 "versions") == 0 && 3433 obj->value.tuple[1] == NULL) { 3434 CHECK(cfg_parse_obj(pctx, fields[1].type, 3435 &obj->value.tuple[1])); 3436 } else if (strcasecmp(TOKEN_STRING(pctx), 3437 "size") == 0 && 3438 obj->value.tuple[2] == NULL) { 3439 CHECK(cfg_parse_obj(pctx, fields[2].type, 3440 &obj->value.tuple[2])); 3441 } else if (strcasecmp(TOKEN_STRING(pctx), 3442 "suffix") == 0 && 3443 obj->value.tuple[3] == NULL) { 3444 CHECK(cfg_parse_obj(pctx, fields[3].type, 3445 &obj->value.tuple[3])); 3446 } else { 3447 break; 3448 } 3449 } else { 3450 break; 3451 } 3452 } 3453 3454 /* Create void objects for missing optional values. */ 3455 if (obj->value.tuple[1] == NULL) 3456 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1])); 3457 if (obj->value.tuple[2] == NULL) 3458 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2])); 3459 if (obj->value.tuple[3] == NULL) 3460 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[3])); 3461 3462 *ret = obj; 3463 return (ISC_R_SUCCESS); 3464 3465 cleanup: 3466 CLEANUP_OBJ(obj); 3467 return (result); 3468} 3469 3470static void 3471print_logfile(cfg_printer_t *pctx, const cfg_obj_t *obj) { 3472 cfg_print_obj(pctx, obj->value.tuple[0]); /* file */ 3473 if (obj->value.tuple[1]->type->print != cfg_print_void) { 3474 cfg_print_cstr(pctx, " versions "); 3475 cfg_print_obj(pctx, obj->value.tuple[1]); 3476 } 3477 if (obj->value.tuple[2]->type->print != cfg_print_void) { 3478 cfg_print_cstr(pctx, " size "); 3479 cfg_print_obj(pctx, obj->value.tuple[2]); 3480 } 3481 if (obj->value.tuple[3]->type->print != cfg_print_void) { 3482 cfg_print_cstr(pctx, " suffix "); 3483 cfg_print_obj(pctx, obj->value.tuple[3]); 3484 } 3485} 3486 3487 3488static void 3489doc_logfile(cfg_printer_t *pctx, const cfg_type_t *type) { 3490 UNUSED(type); 3491 cfg_print_cstr(pctx, "<quoted_string>"); 3492 cfg_print_cstr(pctx, " "); 3493 cfg_print_cstr(pctx, "[ versions ( unlimited | <integer> ) ]"); 3494 cfg_print_cstr(pctx, " "); 3495 cfg_print_cstr(pctx, "[ size <size> ]"); 3496 cfg_print_cstr(pctx, " "); 3497 cfg_print_cstr(pctx, "[ suffix ( increment | timestamp ) ]"); 3498} 3499 3500static cfg_type_t cfg_type_logfile = { 3501 "log_file", parse_logfile, print_logfile, doc_logfile, 3502 &cfg_rep_tuple, logfile_fields 3503}; 3504 3505/*% An IPv4 address with optional dscp and port, "*" accepted as wildcard. */ 3506static cfg_type_t cfg_type_sockaddr4wild = { 3507 "sockaddr4wild", cfg_parse_sockaddr, cfg_print_sockaddr, 3508 cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr4wild_flags 3509}; 3510 3511/*% An IPv6 address with optional port, "*" accepted as wildcard. */ 3512static cfg_type_t cfg_type_sockaddr6wild = { 3513 "v6addrportwild", cfg_parse_sockaddr, cfg_print_sockaddr, 3514 cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr6wild_flags 3515}; 3516 3517/*% 3518 * rndc 3519 */ 3520 3521static cfg_clausedef_t 3522rndcconf_options_clauses[] = { 3523 { "default-key", &cfg_type_astring, 0 }, 3524 { "default-port", &cfg_type_uint32, 0 }, 3525 { "default-server", &cfg_type_astring, 0 }, 3526 { "default-source-address", &cfg_type_netaddr4wild, 0 }, 3527 { "default-source-address-v6", &cfg_type_netaddr6wild, 0 }, 3528 { NULL, NULL, 0 } 3529}; 3530 3531static cfg_clausedef_t * 3532rndcconf_options_clausesets[] = { 3533 rndcconf_options_clauses, 3534 NULL 3535}; 3536 3537static cfg_type_t cfg_type_rndcconf_options = { 3538 "rndcconf_options", cfg_parse_map, cfg_print_map, cfg_doc_map, 3539 &cfg_rep_map, rndcconf_options_clausesets 3540}; 3541 3542static cfg_clausedef_t 3543rndcconf_server_clauses[] = { 3544 { "key", &cfg_type_astring, 0 }, 3545 { "port", &cfg_type_uint32, 0 }, 3546 { "source-address", &cfg_type_netaddr4wild, 0 }, 3547 { "source-address-v6", &cfg_type_netaddr6wild, 0 }, 3548 { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 }, 3549 { NULL, NULL, 0 } 3550}; 3551 3552static cfg_clausedef_t * 3553rndcconf_server_clausesets[] = { 3554 rndcconf_server_clauses, 3555 NULL 3556}; 3557 3558static cfg_type_t cfg_type_rndcconf_server = { 3559 "rndcconf_server", cfg_parse_named_map, cfg_print_map, cfg_doc_map, 3560 &cfg_rep_map, rndcconf_server_clausesets 3561}; 3562 3563static cfg_clausedef_t 3564rndcconf_clauses[] = { 3565 { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI }, 3566 { "server", &cfg_type_rndcconf_server, CFG_CLAUSEFLAG_MULTI }, 3567 { "options", &cfg_type_rndcconf_options, 0 }, 3568 { NULL, NULL, 0 } 3569}; 3570 3571static cfg_clausedef_t * 3572rndcconf_clausesets[] = { 3573 rndcconf_clauses, 3574 NULL 3575}; 3576 3577LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndcconf = { 3578 "rndcconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, 3579 &cfg_rep_map, rndcconf_clausesets 3580}; 3581 3582static cfg_clausedef_t 3583rndckey_clauses[] = { 3584 { "key", &cfg_type_key, 0 }, 3585 { NULL, NULL, 0 } 3586}; 3587 3588static cfg_clausedef_t * 3589rndckey_clausesets[] = { 3590 rndckey_clauses, 3591 NULL 3592}; 3593 3594LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndckey = { 3595 "rndckey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, 3596 &cfg_rep_map, rndckey_clausesets 3597}; 3598 3599/* 3600 * session.key has exactly the same syntax as rndc.key, but it's defined 3601 * separately for clarity (and so we can extend it someday, if needed). 3602 */ 3603LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sessionkey = { 3604 "sessionkey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, 3605 &cfg_rep_map, rndckey_clausesets 3606}; 3607 3608static cfg_tuplefielddef_t nameport_fields[] = { 3609 { "name", &cfg_type_astring, 0 }, 3610 { "port", &cfg_type_optional_port, 0 }, 3611 { "dscp", &cfg_type_optional_dscp, 0 }, 3612 { NULL, NULL, 0 } 3613}; 3614 3615static cfg_type_t cfg_type_nameport = { 3616 "nameport", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 3617 &cfg_rep_tuple, nameport_fields 3618}; 3619 3620static void 3621doc_sockaddrnameport(cfg_printer_t *pctx, const cfg_type_t *type) { 3622 UNUSED(type); 3623 cfg_print_cstr(pctx, "( "); 3624 cfg_print_cstr(pctx, "<quoted_string>"); 3625 cfg_print_cstr(pctx, " "); 3626 cfg_print_cstr(pctx, "[ port <integer> ]"); 3627 cfg_print_cstr(pctx, " "); 3628 cfg_print_cstr(pctx, "[ dscp <integer> ]"); 3629 cfg_print_cstr(pctx, " | "); 3630 cfg_print_cstr(pctx, "<ipv4_address>"); 3631 cfg_print_cstr(pctx, " "); 3632 cfg_print_cstr(pctx, "[ port <integer> ]"); 3633 cfg_print_cstr(pctx, " "); 3634 cfg_print_cstr(pctx, "[ dscp <integer> ]"); 3635 cfg_print_cstr(pctx, " | "); 3636 cfg_print_cstr(pctx, "<ipv6_address>"); 3637 cfg_print_cstr(pctx, " "); 3638 cfg_print_cstr(pctx, "[ port <integer> ]"); 3639 cfg_print_cstr(pctx, " "); 3640 cfg_print_cstr(pctx, "[ dscp <integer> ]"); 3641 cfg_print_cstr(pctx, " )"); 3642} 3643 3644static isc_result_t 3645parse_sockaddrnameport(cfg_parser_t *pctx, const cfg_type_t *type, 3646 cfg_obj_t **ret) 3647{ 3648 isc_result_t result; 3649 cfg_obj_t *obj = NULL; 3650 UNUSED(type); 3651 3652 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); 3653 if (pctx->token.type == isc_tokentype_string || 3654 pctx->token.type == isc_tokentype_qstring) { 3655 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK)) 3656 CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, 3657 ret)); 3658 else { 3659 const cfg_tuplefielddef_t *fields = 3660 cfg_type_nameport.of; 3661 CHECK(cfg_create_tuple(pctx, &cfg_type_nameport, 3662 &obj)); 3663 CHECK(cfg_parse_obj(pctx, fields[0].type, 3664 &obj->value.tuple[0])); 3665 CHECK(cfg_parse_obj(pctx, fields[1].type, 3666 &obj->value.tuple[1])); 3667 CHECK(cfg_parse_obj(pctx, fields[2].type, 3668 &obj->value.tuple[2])); 3669 *ret = obj; 3670 obj = NULL; 3671 } 3672 } else { 3673 cfg_parser_error(pctx, CFG_LOG_NEAR, 3674 "expected IP address or hostname"); 3675 return (ISC_R_UNEXPECTEDTOKEN); 3676 } 3677 cleanup: 3678 CLEANUP_OBJ(obj); 3679 return (result); 3680} 3681 3682static cfg_type_t cfg_type_sockaddrnameport = { 3683 "sockaddrnameport_element", parse_sockaddrnameport, NULL, 3684 doc_sockaddrnameport, NULL, NULL 3685}; 3686 3687static cfg_type_t cfg_type_bracketed_sockaddrnameportlist = { 3688 "bracketed_sockaddrnameportlist", cfg_parse_bracketed_list, 3689 cfg_print_bracketed_list, cfg_doc_bracketed_list, 3690 &cfg_rep_list, &cfg_type_sockaddrnameport 3691}; 3692 3693/*% 3694 * A list of socket addresses or name with an optional default port, 3695 * as used in the dual-stack-servers option. E.g., 3696 * "port 1234 { dual-stack-servers.net; 10.0.0.1; 1::2 port 69; }" 3697 */ 3698static cfg_tuplefielddef_t nameportiplist_fields[] = { 3699 { "port", &cfg_type_optional_port, 0 }, 3700 { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 }, 3701 { NULL, NULL, 0 } 3702}; 3703 3704static cfg_type_t cfg_type_nameportiplist = { 3705 "nameportiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 3706 &cfg_rep_tuple, nameportiplist_fields 3707}; 3708 3709/*% 3710 * masters element. 3711 */ 3712 3713static void 3714doc_masterselement(cfg_printer_t *pctx, const cfg_type_t *type) { 3715 UNUSED(type); 3716 cfg_print_cstr(pctx, "( "); 3717 cfg_print_cstr(pctx, "<masters>"); 3718 cfg_print_cstr(pctx, " | "); 3719 cfg_print_cstr(pctx, "<ipv4_address>"); 3720 cfg_print_cstr(pctx, " "); 3721 cfg_print_cstr(pctx, "[ port <integer> ]"); 3722 cfg_print_cstr(pctx, " | "); 3723 cfg_print_cstr(pctx, "<ipv6_address>"); 3724 cfg_print_cstr(pctx, " "); 3725 cfg_print_cstr(pctx, "[ port <integer> ]"); 3726 cfg_print_cstr(pctx, " )"); 3727} 3728 3729static isc_result_t 3730parse_masterselement(cfg_parser_t *pctx, const cfg_type_t *type, 3731 cfg_obj_t **ret) 3732{ 3733 isc_result_t result; 3734 cfg_obj_t *obj = NULL; 3735 UNUSED(type); 3736 3737 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); 3738 if (pctx->token.type == isc_tokentype_string || 3739 pctx->token.type == isc_tokentype_qstring) { 3740 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK)) 3741 CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, 3742 ret)); 3743 else 3744 CHECK(cfg_parse_astring(pctx, &cfg_type_astring, ret)); 3745 } else { 3746 cfg_parser_error(pctx, CFG_LOG_NEAR, 3747 "expected IP address or masters name"); 3748 return (ISC_R_UNEXPECTEDTOKEN); 3749 } 3750 cleanup: 3751 CLEANUP_OBJ(obj); 3752 return (result); 3753} 3754 3755static cfg_type_t cfg_type_masterselement = { 3756 "masters_element", parse_masterselement, NULL, 3757 doc_masterselement, NULL, NULL 3758}; 3759 3760static isc_result_t 3761parse_ttlval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 3762 isc_result_t result; 3763 cfg_obj_t *obj = NULL; 3764 uint32_t ttl; 3765 3766 UNUSED(type); 3767 3768 CHECK(cfg_gettoken(pctx, 0)); 3769 if (pctx->token.type != isc_tokentype_string) { 3770 result = ISC_R_UNEXPECTEDTOKEN; 3771 goto cleanup; 3772 } 3773 3774 result = dns_ttl_fromtext(&pctx->token.value.as_textregion, &ttl); 3775 if (result == ISC_R_RANGE ) { 3776 cfg_parser_error(pctx, CFG_LOG_NEAR, "TTL out of range "); 3777 return (result); 3778 } else if (result != ISC_R_SUCCESS) 3779 goto cleanup; 3780 3781 CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj)); 3782 obj->value.uint32 = ttl; 3783 *ret = obj; 3784 return (ISC_R_SUCCESS); 3785 3786 cleanup: 3787 cfg_parser_error(pctx, CFG_LOG_NEAR, 3788 "expected integer and optional unit"); 3789 return (result); 3790} 3791 3792/*% 3793 * A TTL value (number + optional unit). 3794 */ 3795static cfg_type_t cfg_type_ttlval = { 3796 "ttlval", parse_ttlval, cfg_print_uint64, cfg_doc_terminal, 3797 &cfg_rep_uint64, NULL 3798}; 3799 3800static isc_result_t 3801parse_maxttl(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 3802 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_ttlval, ret)); 3803} 3804 3805static void 3806doc_maxttl(cfg_printer_t *pctx, const cfg_type_t *type) { 3807 cfg_doc_enum_or_other(pctx, type, &cfg_type_ttlval); 3808} 3809 3810/*% 3811 * A size or "unlimited", but not "default". 3812 */ 3813static const char *maxttl_enums[] = { "unlimited", NULL }; 3814static cfg_type_t cfg_type_maxttl = { 3815 "maxttl_no_default", parse_maxttl, cfg_print_ustring, doc_maxttl, 3816 &cfg_rep_string, maxttl_enums 3817}; 3818 3819static int cmp_clause(const void *ap, const void *bp) { 3820 const cfg_clausedef_t *a = (const cfg_clausedef_t *)ap; 3821 const cfg_clausedef_t *b = (const cfg_clausedef_t *)bp; 3822 return (strcmp(a->name, b->name)); 3823} 3824 3825bool 3826cfg_clause_validforzone(const char *name, unsigned int ztype) { 3827 const cfg_clausedef_t *clause; 3828 bool valid = false; 3829 3830 for (clause = zone_clauses; clause->name != NULL; clause++) { 3831 if ((clause->flags & ztype) == 0 || 3832 strcmp(clause->name, name) != 0) 3833 { 3834 continue; 3835 } 3836 valid = true; 3837 } 3838 for (clause = zone_only_clauses; clause->name != NULL; clause++) { 3839 if ((clause->flags & ztype) == 0 || 3840 strcmp(clause->name, name) != 0) 3841 { 3842 continue; 3843 } 3844 valid = true; 3845 } 3846 3847 return (valid); 3848} 3849 3850void 3851cfg_print_zonegrammar(const unsigned int zonetype, 3852 void (*f)(void *closure, const char *text, int textlen), 3853 void *closure) 3854{ 3855#define NCLAUSES \ 3856 (((sizeof(zone_clauses) + sizeof(zone_only_clauses)) / \ 3857 sizeof(clause[0])) - 1) 3858 3859 cfg_printer_t pctx; 3860 cfg_clausedef_t *clause = NULL; 3861 cfg_clausedef_t clauses[NCLAUSES]; 3862 3863 pctx.f = f; 3864 pctx.closure = closure; 3865 pctx.indent = 0; 3866 pctx.flags = 0; 3867 3868 memmove(clauses, zone_clauses, sizeof(zone_clauses)); 3869 memmove(clauses + sizeof(zone_clauses)/sizeof(zone_clauses[0]) - 1, 3870 zone_only_clauses, sizeof(zone_only_clauses)); 3871 qsort(clauses, NCLAUSES - 1, sizeof(clause[0]), cmp_clause); 3872 3873 cfg_print_cstr(&pctx, "zone <string> [ <class> ] {\n"); 3874 pctx.indent++; 3875 3876 switch (zonetype) { 3877 case CFG_ZONE_MASTER: 3878 cfg_print_indent(&pctx); 3879 cfg_print_cstr(&pctx, "type ( master | primary );\n"); 3880 break; 3881 case CFG_ZONE_SLAVE: 3882 cfg_print_indent(&pctx); 3883 cfg_print_cstr(&pctx, "type ( slave | secondary );\n"); 3884 break; 3885 case CFG_ZONE_MIRROR: 3886 cfg_print_indent(&pctx); 3887 cfg_print_cstr(&pctx, "type mirror;\n"); 3888 break; 3889 case CFG_ZONE_STUB: 3890 cfg_print_indent(&pctx); 3891 cfg_print_cstr(&pctx, "type stub;\n"); 3892 break; 3893 case CFG_ZONE_HINT: 3894 cfg_print_indent(&pctx); 3895 cfg_print_cstr(&pctx, "type hint;\n"); 3896 break; 3897 case CFG_ZONE_FORWARD: 3898 cfg_print_indent(&pctx); 3899 cfg_print_cstr(&pctx, "type forward;\n"); 3900 break; 3901 case CFG_ZONE_STATICSTUB: 3902 cfg_print_indent(&pctx); 3903 cfg_print_cstr(&pctx, "type static-stub;\n"); 3904 break; 3905 case CFG_ZONE_REDIRECT: 3906 cfg_print_indent(&pctx); 3907 cfg_print_cstr(&pctx, "type redirect;\n"); 3908 break; 3909 case CFG_ZONE_DELEGATION: 3910 cfg_print_indent(&pctx); 3911 cfg_print_cstr(&pctx, "type delegation-only;\n"); 3912 break; 3913 case CFG_ZONE_INVIEW: 3914 /* no zone type is specified for these */ 3915 break; 3916 default: 3917 INSIST(0); 3918 ISC_UNREACHABLE(); 3919 } 3920 3921 for (clause = clauses; clause->name != NULL; clause++) { 3922 if ((clause->flags & zonetype) == 0 || 3923 strcasecmp(clause->name, "type") == 0) { 3924 continue; 3925 } 3926 cfg_print_indent(&pctx); 3927 cfg_print_cstr(&pctx, clause->name); 3928 cfg_print_cstr(&pctx, " "); 3929 cfg_doc_obj(&pctx, clause->type); 3930 cfg_print_cstr(&pctx, ";"); 3931 cfg_print_clauseflags(&pctx, clause->flags); 3932 cfg_print_cstr(&pctx, "\n"); 3933 } 3934 3935 pctx.indent--; 3936 cfg_print_cstr(&pctx, "};\n"); 3937} 3938