1/* 2 * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2002, 2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id$ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <string.h> 25 26#include <isc/lex.h> 27#include <isc/mem.h> 28#include <isc/result.h> 29#include <isc/string.h> 30#include <isc/util.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 (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 (0) 48 49 50/*% 51 * Forward declarations of static functions. 52 */ 53 54static isc_result_t 55parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype, 56 const cfg_type_t *othertype, cfg_obj_t **ret); 57 58static isc_result_t 59parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); 60 61static isc_result_t 62parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, 63 cfg_obj_t **ret); 64 65static void 66print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj); 67 68static isc_result_t 69parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type, 70 cfg_obj_t **ret); 71static void 72print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj); 73 74static void 75doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type); 76 77static void 78print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj); 79 80static void 81doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type); 82 83static void 84doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type); 85 86static cfg_type_t cfg_type_addrmatchelt; 87static cfg_type_t cfg_type_bracketed_sockaddrnameportlist; 88static cfg_type_t cfg_type_controls; 89static cfg_type_t cfg_type_controls_sockaddr; 90static cfg_type_t cfg_type_dialuptype; 91static cfg_type_t cfg_type_ixfrdifftype; 92static cfg_type_t cfg_type_key; 93static cfg_type_t cfg_type_logseverity; 94static cfg_type_t cfg_type_lwres; 95static cfg_type_t cfg_type_masterselement; 96static cfg_type_t cfg_type_nameportiplist; 97static cfg_type_t cfg_type_negated; 98static cfg_type_t cfg_type_notifytype; 99static cfg_type_t cfg_type_optional_allow; 100static cfg_type_t cfg_type_optional_class; 101static cfg_type_t cfg_type_optional_facility; 102static cfg_type_t cfg_type_optional_port; 103static cfg_type_t cfg_type_querysource4; 104static cfg_type_t cfg_type_querysource6; 105static cfg_type_t cfg_type_querysource; 106static cfg_type_t cfg_type_server; 107static cfg_type_t cfg_type_server_key_kludge; 108static cfg_type_t cfg_type_size; 109static cfg_type_t cfg_type_sizenodefault; 110static cfg_type_t cfg_type_sockaddr4wild; 111static cfg_type_t cfg_type_sockaddr6wild; 112static cfg_type_t cfg_type_statschannels; 113static cfg_type_t cfg_type_dynamically_loadable_zones; 114static cfg_type_t cfg_type_dynamically_loadable_zones_opts; 115static cfg_type_t cfg_type_v4_aaaa; 116 117/* 118 * Clauses that can be found in a 'dynamically loadable zones' statement 119 */ 120static cfg_clausedef_t 121dynamically_loadable_zones_clauses[] = { 122 { "database", &cfg_type_astring, 0 }, 123 { NULL, NULL, 0 } 124}; 125 126/* 127 * A dynamically loadable zones statement. 128 */ 129static cfg_tuplefielddef_t dynamically_loadable_zones_fields[] = { 130 { "name", &cfg_type_astring, 0 }, 131 { "options", &cfg_type_dynamically_loadable_zones_opts, 0 }, 132 { NULL, NULL, 0 } 133}; 134 135static cfg_type_t cfg_type_dynamically_loadable_zones = { 136 "dlz", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 137 &cfg_rep_tuple, 138 dynamically_loadable_zones_fields 139 }; 140 141 142/*% tkey-dhkey */ 143 144static cfg_tuplefielddef_t tkey_dhkey_fields[] = { 145 { "name", &cfg_type_qstring, 0 }, 146 { "keyid", &cfg_type_uint32, 0 }, 147 { NULL, NULL, 0 } 148}; 149 150static cfg_type_t cfg_type_tkey_dhkey = { 151 "tkey-dhkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, 152 tkey_dhkey_fields 153}; 154 155/*% listen-on */ 156 157static cfg_tuplefielddef_t listenon_fields[] = { 158 { "port", &cfg_type_optional_port, 0 }, 159 { "acl", &cfg_type_bracketed_aml, 0 }, 160 { NULL, NULL, 0 } 161}; 162cfg_type_t cfg_type_listenon = { 163 "listenon", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, listenon_fields }; 164 165/*% acl */ 166 167static cfg_tuplefielddef_t acl_fields[] = { 168 { "name", &cfg_type_astring, 0 }, 169 { "value", &cfg_type_bracketed_aml, 0 }, 170 { NULL, NULL, 0 } 171}; 172 173cfg_type_t cfg_type_acl = { 174 "acl", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, acl_fields }; 175 176/*% masters */ 177static cfg_tuplefielddef_t masters_fields[] = { 178 { "name", &cfg_type_astring, 0 }, 179 { "port", &cfg_type_optional_port, 0 }, 180 { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 }, 181 { NULL, NULL, 0 } 182}; 183 184static cfg_type_t cfg_type_masters = { 185 "masters", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, masters_fields }; 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 200cfg_type_t cfg_type_namesockaddrkey = { 201 "namesockaddrkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, 202 namesockaddrkey_fields 203}; 204 205cfg_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, &cfg_type_namesockaddrkey 208}; 209 210static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = { 211 { "port", &cfg_type_optional_port, 0 }, 212 { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 }, 213 { NULL, NULL, 0 } 214}; 215cfg_type_t cfg_type_namesockaddrkeylist = { 216 "sockaddrkeylist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, 217 namesockaddrkeylist_fields 218}; 219 220/*% 221 * A list of socket addresses with an optional default port, 222 * as used in the also-notify option. E.g., 223 * "port 1234 { 10.0.0.1; 1::2 port 69; }" 224 */ 225static cfg_tuplefielddef_t portiplist_fields[] = { 226 { "port", &cfg_type_optional_port, 0 }, 227 { "addresses", &cfg_type_bracketed_sockaddrlist, 0 }, 228 { NULL, NULL, 0 } 229}; 230cfg_type_t cfg_type_portiplist = { 231 "portiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, 232 portiplist_fields 233}; 234 235/*% 236 * A public key, as in the "pubkey" statement. 237 */ 238static cfg_tuplefielddef_t pubkey_fields[] = { 239 { "flags", &cfg_type_uint32, 0 }, 240 { "protocol", &cfg_type_uint32, 0 }, 241 { "algorithm", &cfg_type_uint32, 0 }, 242 { "key", &cfg_type_qstring, 0 }, 243 { NULL, NULL, 0 } 244}; 245static cfg_type_t cfg_type_pubkey = { 246 "pubkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 247 &cfg_rep_tuple, pubkey_fields }; 248 249/*% 250 * A list of RR types, used in grant statements. 251 * Note that the old parser allows quotes around the RR type names. 252 */ 253cfg_type_t cfg_type_rrtypelist = { 254 "rrtypelist", cfg_parse_spacelist, cfg_print_spacelist, 255 cfg_doc_terminal, &cfg_rep_list, &cfg_type_astring 256}; 257 258static const char *mode_enums[] = { "grant", "deny", NULL }; 259cfg_type_t cfg_type_mode = { 260 "mode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, 261 &cfg_rep_string, &mode_enums 262}; 263 264static isc_result_t 265parse_matchtype(cfg_parser_t *pctx, const cfg_type_t *type, 266 cfg_obj_t **ret) { 267 isc_result_t result; 268 269 CHECK(cfg_peektoken(pctx, 0)); 270 if (pctx->token.type == isc_tokentype_string && 271 strcasecmp(TOKEN_STRING(pctx), "zonesub") == 0) { 272 pctx->flags |= CFG_PCTX_SKIP; 273 } 274 return (cfg_parse_enum(pctx, type, ret)); 275 276 cleanup: 277 return (result); 278} 279 280static isc_result_t 281parse_matchname(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 282 isc_result_t result; 283 cfg_obj_t *obj = NULL; 284 285 if ((pctx->flags & CFG_PCTX_SKIP) != 0) { 286 pctx->flags &= ~CFG_PCTX_SKIP; 287 CHECK(cfg_parse_void(pctx, NULL, &obj)); 288 } else 289 result = cfg_parse_astring(pctx, type, &obj); 290 291 *ret = obj; 292 cleanup: 293 return (result); 294} 295 296static void 297doc_matchname(cfg_printer_t *pctx, const cfg_type_t *type) { 298 cfg_print_chars(pctx, "[ ", 2); 299 cfg_doc_obj(pctx, type->of); 300 cfg_print_chars(pctx, " ]", 2); 301} 302 303static const char *matchtype_enums[] = { 304 "name", "subdomain", "wildcard", "self", "selfsub", "selfwild", 305 "krb5-self", "ms-self", "krb5-subdomain", "ms-subdomain", 306 "tcp-self", "6to4-self", "zonesub", "external", NULL }; 307 308cfg_type_t cfg_type_matchtype = { 309 "matchtype", parse_matchtype, cfg_print_ustring, 310 cfg_doc_enum, &cfg_rep_string, &matchtype_enums 311}; 312 313cfg_type_t cfg_type_matchname = { 314 "optional_matchname", parse_matchname, cfg_print_ustring, 315 &doc_matchname, &cfg_rep_string, &cfg_type_ustring 316}; 317 318/*% 319 * A grant statement, used in the update policy. 320 */ 321static cfg_tuplefielddef_t grant_fields[] = { 322 { "mode", &cfg_type_mode, 0 }, 323 { "identity", &cfg_type_astring, 0 }, /* domain name */ 324 { "matchtype", &cfg_type_matchtype, 0 }, 325 { "name", &cfg_type_matchname, 0 }, /* domain name */ 326 { "types", &cfg_type_rrtypelist, 0 }, 327 { NULL, NULL, 0 } 328}; 329cfg_type_t cfg_type_grant = { 330 "grant", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 331 &cfg_rep_tuple, grant_fields 332}; 333 334cfg_type_t cfg_type_updatepolicy = { 335 "update_policy", parse_updatepolicy, print_updatepolicy, doc_updatepolicy, 336 &cfg_rep_list, &cfg_type_grant 337}; 338 339static isc_result_t 340parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type, 341 cfg_obj_t **ret) { 342 isc_result_t result; 343 CHECK(cfg_gettoken(pctx, 0)); 344 if (pctx->token.type == isc_tokentype_special && 345 pctx->token.value.as_char == '{') { 346 cfg_ungettoken(pctx); 347 return (cfg_parse_bracketed_list(pctx, type, ret)); 348 } 349 350 if (pctx->token.type == isc_tokentype_string && 351 strcasecmp(TOKEN_STRING(pctx), "local") == 0) { 352 cfg_obj_t *obj = NULL; 353 CHECK(cfg_create_obj(pctx, &cfg_type_ustring, &obj)); 354 obj->value.string.length = strlen("local"); 355 obj->value.string.base = isc_mem_get(pctx->mctx, 356 obj->value.string.length + 1); 357 if (obj->value.string.base == NULL) { 358 isc_mem_put(pctx->mctx, obj, sizeof(*obj)); 359 return (ISC_R_NOMEMORY); 360 } 361 memcpy(obj->value.string.base, "local", 5); 362 obj->value.string.base[5] = '\0'; 363 *ret = obj; 364 return (ISC_R_SUCCESS); 365 } 366 367 cfg_ungettoken(pctx); 368 return (ISC_R_UNEXPECTEDTOKEN); 369 370 cleanup: 371 return (result); 372} 373 374static void 375print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj) { 376 if (cfg_obj_isstring(obj)) 377 cfg_print_ustring(pctx, obj); 378 else 379 cfg_print_bracketed_list(pctx, obj); 380} 381 382static void 383doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type) { 384 cfg_print_cstr(pctx, "( local | { "); 385 cfg_doc_obj(pctx, type->of); 386 cfg_print_cstr(pctx, "; ... }"); 387} 388 389/*% 390 * A view statement. 391 */ 392static cfg_tuplefielddef_t view_fields[] = { 393 { "name", &cfg_type_astring, 0 }, 394 { "class", &cfg_type_optional_class, 0 }, 395 { "options", &cfg_type_viewopts, 0 }, 396 { NULL, NULL, 0 } 397}; 398cfg_type_t cfg_type_view = { 399 "view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 400 &cfg_rep_tuple, view_fields 401}; 402 403/*% 404 * A zone statement. 405 */ 406static cfg_tuplefielddef_t zone_fields[] = { 407 { "name", &cfg_type_astring, 0 }, 408 { "class", &cfg_type_optional_class, 0 }, 409 { "options", &cfg_type_zoneopts, 0 }, 410 { NULL, NULL, 0 } 411}; 412cfg_type_t cfg_type_zone = { 413 "zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 414 &cfg_rep_tuple, zone_fields 415}; 416 417/*% 418 * A "category" clause in the "logging" statement. 419 */ 420static cfg_tuplefielddef_t category_fields[] = { 421 { "name", &cfg_type_astring, 0 }, 422 { "destinations", &cfg_type_destinationlist,0 }, 423 { NULL, NULL, 0 } 424}; 425cfg_type_t cfg_type_category = { 426 "category", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 427 &cfg_rep_tuple, category_fields 428}; 429 430 431/*% 432 * A dnssec key, as used in the "trusted-keys" statement. 433 */ 434static cfg_tuplefielddef_t dnsseckey_fields[] = { 435 { "name", &cfg_type_astring, 0 }, 436 { "flags", &cfg_type_uint32, 0 }, 437 { "protocol", &cfg_type_uint32, 0 }, 438 { "algorithm", &cfg_type_uint32, 0 }, 439 { "key", &cfg_type_qstring, 0 }, 440 { NULL, NULL, 0 } 441}; 442static cfg_type_t cfg_type_dnsseckey = { 443 "dnsseckey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 444 &cfg_rep_tuple, dnsseckey_fields 445}; 446 447/*% 448 * A managed key initialization specifier, as used in the 449 * "managed-keys" statement. 450 */ 451static cfg_tuplefielddef_t managedkey_fields[] = { 452 { "name", &cfg_type_astring, 0 }, 453 { "init", &cfg_type_ustring, 0 }, /* must be literal "initial-key" */ 454 { "flags", &cfg_type_uint32, 0 }, 455 { "protocol", &cfg_type_uint32, 0 }, 456 { "algorithm", &cfg_type_uint32, 0 }, 457 { "key", &cfg_type_qstring, 0 }, 458 { NULL, NULL, 0 } 459}; 460static cfg_type_t cfg_type_managedkey = { 461 "managedkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 462 &cfg_rep_tuple, managedkey_fields 463}; 464 465static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring }; 466 467static cfg_type_t cfg_type_optional_wild_class = { 468 "optional_wild_class", parse_optional_keyvalue, print_keyvalue, 469 doc_optional_keyvalue, &cfg_rep_string, &wild_class_kw 470}; 471 472static keyword_type_t wild_type_kw = { "type", &cfg_type_ustring }; 473 474static cfg_type_t cfg_type_optional_wild_type = { 475 "optional_wild_type", parse_optional_keyvalue, 476 print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_type_kw 477}; 478 479static keyword_type_t wild_name_kw = { "name", &cfg_type_qstring }; 480 481static cfg_type_t cfg_type_optional_wild_name = { 482 "optional_wild_name", parse_optional_keyvalue, 483 print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_name_kw 484}; 485 486/*% 487 * An rrset ordering element. 488 */ 489static cfg_tuplefielddef_t rrsetorderingelement_fields[] = { 490 { "class", &cfg_type_optional_wild_class, 0 }, 491 { "type", &cfg_type_optional_wild_type, 0 }, 492 { "name", &cfg_type_optional_wild_name, 0 }, 493 { "order", &cfg_type_ustring, 0 }, /* must be literal "order" */ 494 { "ordering", &cfg_type_ustring, 0 }, 495 { NULL, NULL, 0 } 496}; 497static cfg_type_t cfg_type_rrsetorderingelement = { 498 "rrsetorderingelement", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, 499 rrsetorderingelement_fields 500}; 501 502/*% 503 * A global or view "check-names" option. Note that the zone 504 * "check-names" option has a different syntax. 505 */ 506 507static const char *checktype_enums[] = { "master", "slave", "response", NULL }; 508static cfg_type_t cfg_type_checktype = { 509 "checktype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, 510 &cfg_rep_string, &checktype_enums 511}; 512 513static const char *checkmode_enums[] = { "fail", "warn", "ignore", NULL }; 514static cfg_type_t cfg_type_checkmode = { 515 "checkmode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, 516 &cfg_rep_string, &checkmode_enums 517}; 518 519static cfg_tuplefielddef_t checknames_fields[] = { 520 { "type", &cfg_type_checktype, 0 }, 521 { "mode", &cfg_type_checkmode, 0 }, 522 { NULL, NULL, 0 } 523}; 524 525static cfg_type_t cfg_type_checknames = { 526 "checknames", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, 527 checknames_fields 528}; 529 530cfg_type_t cfg_type_bracketed_sockaddrlist = { 531 "bracketed_sockaddrlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, 532 &cfg_rep_list, &cfg_type_sockaddr 533}; 534 535static const char *autodnssec_enums[] = { "allow", "maintain", "off", NULL }; 536static cfg_type_t cfg_type_autodnssec = { 537 "autodnssec", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, 538 &cfg_rep_string, &autodnssec_enums 539}; 540 541static cfg_type_t cfg_type_rrsetorder = { 542 "rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, 543 &cfg_rep_list, &cfg_type_rrsetorderingelement 544}; 545 546static keyword_type_t port_kw = { "port", &cfg_type_uint32 }; 547 548static cfg_type_t cfg_type_optional_port = { 549 "optional_port", parse_optional_keyvalue, print_keyvalue, 550 doc_optional_keyvalue, &cfg_rep_uint32, &port_kw 551}; 552 553/*% A list of keys, as in the "key" clause of the controls statement. */ 554static cfg_type_t cfg_type_keylist = { 555 "keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list, 556 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring 557}; 558 559/*% A list of dnssec keys, as in "trusted-keys" */ 560static cfg_type_t cfg_type_dnsseckeys = { 561 "dnsseckeys", cfg_parse_bracketed_list, cfg_print_bracketed_list, 562 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_dnsseckey 563}; 564 565/*% 566 * A list of managed key entries, as in "trusted-keys". Currently 567 * (9.7.0) this has a format similar to dnssec keys, except the keyname 568 * is followed by the keyword "initial-key". In future releases, this 569 * keyword may take other values indicating different methods for the 570 * key to be initialized. 571 */ 572 573static cfg_type_t cfg_type_managedkeys = { 574 "managedkeys", cfg_parse_bracketed_list, cfg_print_bracketed_list, 575 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_managedkey 576}; 577 578static const char *forwardtype_enums[] = { "first", "only", NULL }; 579static cfg_type_t cfg_type_forwardtype = { 580 "forwardtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string, 581 &forwardtype_enums 582}; 583 584static const char *zonetype_enums[] = { 585 "master", "slave", "stub", "static-stub", "hint", "forward", 586 "delegation-only", NULL }; 587static cfg_type_t cfg_type_zonetype = { 588 "zonetype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, 589 &cfg_rep_string, &zonetype_enums 590}; 591 592static const char *loglevel_enums[] = { 593 "critical", "error", "warning", "notice", "info", "dynamic", NULL }; 594static cfg_type_t cfg_type_loglevel = { 595 "loglevel", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string, 596 &loglevel_enums 597}; 598 599static const char *transferformat_enums[] = { 600 "many-answers", "one-answer", NULL }; 601static cfg_type_t cfg_type_transferformat = { 602 "transferformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string, 603 &transferformat_enums 604}; 605 606/*% 607 * The special keyword "none", as used in the pid-file option. 608 */ 609 610static void 611print_none(cfg_printer_t *pctx, const cfg_obj_t *obj) { 612 UNUSED(obj); 613 cfg_print_cstr(pctx, "none"); 614} 615 616static cfg_type_t cfg_type_none = { 617 "none", NULL, print_none, NULL, &cfg_rep_void, NULL 618}; 619 620/*% 621 * A quoted string or the special keyword "none". Used in the pid-file option. 622 */ 623static isc_result_t 624parse_qstringornone(cfg_parser_t *pctx, const cfg_type_t *type, 625 cfg_obj_t **ret) 626{ 627 isc_result_t result; 628 629 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); 630 if (pctx->token.type == isc_tokentype_string && 631 strcasecmp(TOKEN_STRING(pctx), "none") == 0) 632 return (cfg_create_obj(pctx, &cfg_type_none, ret)); 633 cfg_ungettoken(pctx); 634 return (cfg_parse_qstring(pctx, type, ret)); 635 cleanup: 636 return (result); 637} 638 639static void 640doc_qstringornone(cfg_printer_t *pctx, const cfg_type_t *type) { 641 UNUSED(type); 642 cfg_print_cstr(pctx, "( <quoted_string> | none )"); 643} 644 645static cfg_type_t cfg_type_qstringornone = { 646 "qstringornone", parse_qstringornone, NULL, doc_qstringornone, 647 NULL, NULL 648}; 649 650/*% 651 * A boolean ("yes" or "no"), or the special keyword "auto". 652 * Used in the dnssec-validation option. 653 */ 654static void 655print_auto(cfg_printer_t *pctx, const cfg_obj_t *obj) { 656 UNUSED(obj); 657 cfg_print_cstr(pctx, "auto"); 658} 659 660static cfg_type_t cfg_type_auto = { 661 "auto", NULL, print_auto, NULL, &cfg_rep_void, NULL 662}; 663 664static isc_result_t 665parse_boolorauto(cfg_parser_t *pctx, const cfg_type_t *type, 666 cfg_obj_t **ret) 667{ 668 isc_result_t result; 669 670 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); 671 if (pctx->token.type == isc_tokentype_string && 672 strcasecmp(TOKEN_STRING(pctx), "auto") == 0) 673 return (cfg_create_obj(pctx, &cfg_type_auto, ret)); 674 cfg_ungettoken(pctx); 675 return (cfg_parse_boolean(pctx, type, ret)); 676 cleanup: 677 return (result); 678} 679 680static void 681print_boolorauto(cfg_printer_t *pctx, const cfg_obj_t *obj) { 682 if (obj->type->rep == &cfg_rep_void) 683 cfg_print_chars(pctx, "auto", 4); 684 else if (obj->value.boolean) 685 cfg_print_chars(pctx, "yes", 3); 686 else 687 cfg_print_chars(pctx, "no", 2); 688} 689 690static void 691doc_boolorauto(cfg_printer_t *pctx, const cfg_type_t *type) { 692 UNUSED(type); 693 cfg_print_cstr(pctx, "( yes | no | auto )"); 694} 695 696static cfg_type_t cfg_type_boolorauto = { 697 "boolorauto", parse_boolorauto, print_boolorauto, 698 doc_boolorauto, NULL, NULL 699}; 700 701/*% 702 * keyword hostname 703 */ 704static void 705print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) { 706 UNUSED(obj); 707 cfg_print_cstr(pctx, "hostname"); 708} 709 710static cfg_type_t cfg_type_hostname = { 711 "hostname", NULL, print_hostname, NULL, &cfg_rep_boolean, NULL 712}; 713 714/*% 715 * "server-id" argument. 716 */ 717 718static isc_result_t 719parse_serverid(cfg_parser_t *pctx, const cfg_type_t *type, 720 cfg_obj_t **ret) 721{ 722 isc_result_t result; 723 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); 724 if (pctx->token.type == isc_tokentype_string && 725 strcasecmp(TOKEN_STRING(pctx), "none") == 0) 726 return (cfg_create_obj(pctx, &cfg_type_none, ret)); 727 if (pctx->token.type == isc_tokentype_string && 728 strcasecmp(TOKEN_STRING(pctx), "hostname") == 0) { 729 return (cfg_create_obj(pctx, &cfg_type_hostname, ret)); 730 } 731 cfg_ungettoken(pctx); 732 return (cfg_parse_qstring(pctx, type, ret)); 733 cleanup: 734 return (result); 735} 736 737static void 738doc_serverid(cfg_printer_t *pctx, const cfg_type_t *type) { 739 UNUSED(type); 740 cfg_print_cstr(pctx, "( <quoted_string> | none | hostname )"); 741} 742 743static cfg_type_t cfg_type_serverid = { 744 "serverid", parse_serverid, NULL, doc_serverid, NULL, NULL }; 745 746/*% 747 * Port list. 748 */ 749static cfg_tuplefielddef_t porttuple_fields[] = { 750 { "loport", &cfg_type_uint32, 0 }, 751 { "hiport", &cfg_type_uint32, 0 }, 752 { NULL, NULL, 0 } 753}; 754static cfg_type_t cfg_type_porttuple = { 755 "porttuple", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 756 &cfg_rep_tuple, porttuple_fields 757}; 758 759static isc_result_t 760parse_port(cfg_parser_t *pctx, cfg_obj_t **ret) { 761 isc_result_t result; 762 763 CHECK(cfg_parse_uint32(pctx, NULL, ret)); 764 if ((*ret)->value.uint32 > 0xffff) { 765 cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid port"); 766 cfg_obj_destroy(pctx, ret); 767 result = ISC_R_RANGE; 768 } 769 770 cleanup: 771 return (result); 772} 773 774static isc_result_t 775parse_portrange(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 776 isc_result_t result; 777 cfg_obj_t *obj = NULL; 778 779 UNUSED(type); 780 781 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); 782 if (pctx->token.type == isc_tokentype_number) 783 CHECK(parse_port(pctx, ret)); 784 else { 785 CHECK(cfg_gettoken(pctx, 0)); 786 if (pctx->token.type != isc_tokentype_string || 787 strcasecmp(TOKEN_STRING(pctx), "range") != 0) { 788 cfg_parser_error(pctx, CFG_LOG_NEAR, 789 "expected integer or 'range'"); 790 return (ISC_R_UNEXPECTEDTOKEN); 791 } 792 CHECK(cfg_create_tuple(pctx, &cfg_type_porttuple, &obj)); 793 CHECK(parse_port(pctx, &obj->value.tuple[0])); 794 CHECK(parse_port(pctx, &obj->value.tuple[1])); 795 if (obj->value.tuple[0]->value.uint32 > 796 obj->value.tuple[1]->value.uint32) { 797 cfg_parser_error(pctx, CFG_LOG_NOPREP, 798 "low port '%u' must not be larger " 799 "than high port", 800 obj->value.tuple[0]->value.uint32); 801 result = ISC_R_RANGE; 802 goto cleanup; 803 } 804 *ret = obj; 805 obj = NULL; 806 } 807 808 cleanup: 809 if (obj != NULL) 810 cfg_obj_destroy(pctx, &obj); 811 return (result); 812} 813 814static cfg_type_t cfg_type_portrange = { 815 "portrange", parse_portrange, NULL, cfg_doc_terminal, 816 NULL, NULL 817}; 818 819static cfg_type_t cfg_type_bracketed_portlist = { 820 "bracketed_sockaddrlist", cfg_parse_bracketed_list, 821 cfg_print_bracketed_list, cfg_doc_bracketed_list, 822 &cfg_rep_list, &cfg_type_portrange 823}; 824 825/*% 826 * Clauses that can be found within the top level of the named.conf 827 * file only. 828 */ 829static cfg_clausedef_t 830namedconf_clauses[] = { 831 { "options", &cfg_type_options, 0 }, 832 { "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI }, 833 { "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI }, 834 { "masters", &cfg_type_masters, CFG_CLAUSEFLAG_MULTI }, 835 { "logging", &cfg_type_logging, 0 }, 836 { "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI }, 837 { "lwres", &cfg_type_lwres, CFG_CLAUSEFLAG_MULTI }, 838 { "statistics-channels", &cfg_type_statschannels, 839 CFG_CLAUSEFLAG_MULTI }, 840 { NULL, NULL, 0 } 841}; 842 843/*% 844 * Clauses that can occur at the top level or in the view 845 * statement, but not in the options block. 846 */ 847static cfg_clausedef_t 848namedconf_or_view_clauses[] = { 849 { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI }, 850 { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI }, 851 /* only 1 DLZ per view allowed */ 852 { "dlz", &cfg_type_dynamically_loadable_zones, 0 }, 853 { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI }, 854 { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI }, 855 { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI }, 856 { NULL, NULL, 0 } 857}; 858 859/*% 860 * Clauses that can occur in the bind.keys file. 861 */ 862static cfg_clausedef_t 863bindkeys_clauses[] = { 864 { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI }, 865 { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI }, 866 { NULL, NULL, 0 } 867}; 868 869/*% 870 * Clauses that can be found within the 'options' statement. 871 */ 872static cfg_clausedef_t 873options_clauses[] = { 874 { "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 }, 875 { "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 }, 876 { "bindkeys-file", &cfg_type_qstring, 0 }, 877 { "blackhole", &cfg_type_bracketed_aml, 0 }, 878 { "coresize", &cfg_type_size, 0 }, 879 { "datasize", &cfg_type_size, 0 }, 880 { "session-keyfile", &cfg_type_qstringornone, 0 }, 881 { "session-keyname", &cfg_type_astring, 0 }, 882 { "session-keyalg", &cfg_type_astring, 0 }, 883 { "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 884 { "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK }, 885 { "dump-file", &cfg_type_qstring, 0 }, 886 { "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 887 { "files", &cfg_type_size, 0 }, 888 { "flush-zones-on-shutdown", &cfg_type_boolean, 0 }, 889 { "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 890 { "heartbeat-interval", &cfg_type_uint32, 0 }, 891 { "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP }, 892 { "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP }, 893 { "hostname", &cfg_type_qstringornone, 0 }, 894 { "interface-interval", &cfg_type_uint32, 0 }, 895 { "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI }, 896 { "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI }, 897 { "managed-keys-directory", &cfg_type_qstring, 0 }, 898 { "match-mapped-addresses", &cfg_type_boolean, 0 }, 899 { "memstatistics-file", &cfg_type_qstring, 0 }, 900 { "memstatistics", &cfg_type_boolean, 0 }, 901 { "multiple-cnames", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 902 { "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE }, 903 { "pid-file", &cfg_type_qstringornone, 0 }, 904 { "port", &cfg_type_uint32, 0 }, 905 { "querylog", &cfg_type_boolean, 0 }, 906 { "recursing-file", &cfg_type_qstring, 0 }, 907 { "random-device", &cfg_type_qstring, 0 }, 908 { "recursive-clients", &cfg_type_uint32, 0 }, 909 { "reserved-sockets", &cfg_type_uint32, 0 }, 910 { "secroots-file", &cfg_type_qstring, 0 }, 911 { "serial-queries", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE }, 912 { "serial-query-rate", &cfg_type_uint32, 0 }, 913 { "server-id", &cfg_type_serverid, 0 }, 914 { "stacksize", &cfg_type_size, 0 }, 915 { "statistics-file", &cfg_type_qstring, 0 }, 916 { "statistics-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_NYI }, 917 { "tcp-clients", &cfg_type_uint32, 0 }, 918 { "tcp-listen-queue", &cfg_type_uint32, 0 }, 919 { "tkey-dhkey", &cfg_type_tkey_dhkey, 0 }, 920 { "tkey-gssapi-credential", &cfg_type_qstring, 0 }, 921 { "tkey-gssapi-keytab", &cfg_type_qstring, 0 }, 922 { "tkey-domain", &cfg_type_qstring, 0 }, 923 { "transfers-per-ns", &cfg_type_uint32, 0 }, 924 { "transfers-in", &cfg_type_uint32, 0 }, 925 { "transfers-out", &cfg_type_uint32, 0 }, 926 { "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 927 { "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 928 { "use-ixfr", &cfg_type_boolean, 0 }, 929 { "use-v4-udp-ports", &cfg_type_bracketed_portlist, 0 }, 930 { "use-v6-udp-ports", &cfg_type_bracketed_portlist, 0 }, 931 { "version", &cfg_type_qstringornone, 0 }, 932 { NULL, NULL, 0 } 933}; 934 935static cfg_type_t cfg_type_namelist = { 936 "namelist", cfg_parse_bracketed_list, cfg_print_bracketed_list, 937 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_qstring }; 938 939static keyword_type_t exclude_kw = { "exclude", &cfg_type_namelist }; 940 941static cfg_type_t cfg_type_optional_exclude = { 942 "optional_exclude", parse_optional_keyvalue, print_keyvalue, 943 doc_optional_keyvalue, &cfg_rep_list, &exclude_kw }; 944 945static keyword_type_t exceptionnames_kw = { "except-from", &cfg_type_namelist }; 946 947static cfg_type_t cfg_type_optional_exceptionnames = { 948 "optional_allow", parse_optional_keyvalue, print_keyvalue, 949 doc_optional_keyvalue, &cfg_rep_list, &exceptionnames_kw }; 950 951static cfg_tuplefielddef_t denyaddresses_fields[] = { 952 { "acl", &cfg_type_bracketed_aml, 0 }, 953 { "except-from", &cfg_type_optional_exceptionnames, 0 }, 954 { NULL, NULL, 0 } 955}; 956 957static cfg_type_t cfg_type_denyaddresses = { 958 "denyaddresses", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 959 &cfg_rep_tuple, denyaddresses_fields 960}; 961 962static cfg_tuplefielddef_t denyaliases_fields[] = { 963 { "name", &cfg_type_namelist, 0 }, 964 { "except-from", &cfg_type_optional_exceptionnames, 0 }, 965 { NULL, NULL, 0 } 966}; 967 968static cfg_type_t cfg_type_denyaliases = { 969 "denyaliases", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 970 &cfg_rep_tuple, denyaliases_fields 971}; 972 973static cfg_type_t cfg_type_algorithmlist = { 974 "algorithmlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, 975 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring }; 976 977static cfg_tuplefielddef_t disablealgorithm_fields[] = { 978 { "name", &cfg_type_astring, 0 }, 979 { "algorithms", &cfg_type_algorithmlist, 0 }, 980 { NULL, NULL, 0 } 981}; 982 983static cfg_type_t cfg_type_disablealgorithm = { 984 "disablealgorithm", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 985 &cfg_rep_tuple, disablealgorithm_fields 986}; 987 988static cfg_tuplefielddef_t mustbesecure_fields[] = { 989 { "name", &cfg_type_astring, 0 }, 990 { "value", &cfg_type_boolean, 0 }, 991 { NULL, NULL, 0 } 992}; 993 994static cfg_type_t cfg_type_mustbesecure = { 995 "mustbesecure", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 996 &cfg_rep_tuple, mustbesecure_fields 997}; 998 999static const char *masterformat_enums[] = { "text", "raw", NULL }; 1000static cfg_type_t cfg_type_masterformat = { 1001 "masterformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, 1002 &cfg_rep_string, &masterformat_enums 1003}; 1004 1005 1006 1007/* 1008 * response-policy { 1009 * zone <string> [ policy (given|disabled|passthru| 1010 * nxdomain|nodata|cname <domain> ) ]; 1011 * }; 1012 * 1013 * this is a chimera of doc_optional_keyvalue() and cfg_doc_enum() 1014 */ 1015static void 1016doc_rpz_policies(cfg_printer_t *pctx, const cfg_type_t *type) { 1017 const keyword_type_t *kw; 1018 const char * const *p; 1019 1020 kw = type->of; 1021 cfg_print_chars(pctx, "[ ", 2); 1022 cfg_print_cstr(pctx, kw->name); 1023 cfg_print_chars(pctx, " ", 1); 1024 1025 cfg_print_chars(pctx, "( ", 2); 1026 for (p = kw->type->of; *p != NULL; p++) { 1027 cfg_print_cstr(pctx, *p); 1028 if (p[1] != NULL) 1029 cfg_print_chars(pctx, " | ", 3); 1030 } 1031} 1032 1033/* 1034 * print_qstring() from parser.c 1035 */ 1036static void 1037print_rpz_cname(cfg_printer_t *pctx, const cfg_obj_t *obj) 1038{ 1039 cfg_print_chars(pctx, "\"", 1); 1040 cfg_print_ustring(pctx, obj); 1041 cfg_print_chars(pctx, "\"", 1); 1042} 1043 1044static void 1045doc_rpz_cname(cfg_printer_t *pctx, const cfg_type_t *type) { 1046 cfg_doc_terminal(pctx, type); 1047 cfg_print_chars(pctx, " ) ]", 4); 1048} 1049 1050static isc_result_t 1051parse_rpz(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1052 isc_result_t result; 1053 cfg_obj_t *obj = NULL; 1054 const cfg_tuplefielddef_t *fields = type->of; 1055 1056 CHECK(cfg_create_tuple(pctx, type, &obj)); 1057 CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0])); 1058 CHECK(cfg_parse_obj(pctx, fields[1].type, &obj->value.tuple[1])); 1059 /* 1060 * parse cname domain only after "policy cname" 1061 */ 1062 if (cfg_obj_isvoid(obj->value.tuple[1]) || 1063 strcasecmp("cname", cfg_obj_asstring(obj->value.tuple[1]))) { 1064 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2])); 1065 } else { 1066 CHECK(cfg_parse_obj(pctx, fields[2].type, &obj->value.tuple[2])); 1067 } 1068 1069 *ret = obj; 1070 return (ISC_R_SUCCESS); 1071 1072cleanup: 1073 CLEANUP_OBJ(obj); 1074 return (result); 1075} 1076 1077static const char *rpz_policies[] = { 1078 "given", "disabled", "passthru", "no-op", "nxdomain", "nodata", 1079 "cname", NULL 1080}; 1081static cfg_type_t cfg_type_rpz_policylist = { 1082 "policies", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, 1083 &cfg_rep_string, &rpz_policies 1084}; 1085static keyword_type_t rpz_policies_kw = { 1086 "policy", &cfg_type_rpz_policylist 1087}; 1088static cfg_type_t cfg_type_rpz_policy = { 1089 "optional_policy", parse_optional_keyvalue, print_keyvalue, 1090 doc_rpz_policies, &cfg_rep_string, &rpz_policies_kw 1091}; 1092static cfg_type_t cfg_type_cname = { 1093 "domain", cfg_parse_astring, print_rpz_cname, doc_rpz_cname, 1094 &cfg_rep_string, NULL 1095}; 1096static cfg_tuplefielddef_t rpzone_fields[] = { 1097 { "name", &cfg_type_astring, 0 }, 1098 { "policy", &cfg_type_rpz_policy, 0 }, 1099 { "cname", &cfg_type_cname, 0 }, 1100 { NULL, NULL, 0 } 1101}; 1102static cfg_type_t cfg_type_rpzone = { 1103 "rpzone", parse_rpz, cfg_print_tuple, cfg_doc_tuple, 1104 &cfg_rep_tuple, rpzone_fields 1105}; 1106static cfg_clausedef_t rpz_clauses[] = { 1107 { "zone", &cfg_type_rpzone, CFG_CLAUSEFLAG_MULTI }, 1108 { NULL, NULL, 0 } 1109}; 1110static cfg_clausedef_t *rpz_clausesets[] = { 1111 rpz_clauses, 1112 NULL 1113}; 1114static cfg_type_t cfg_type_rpz = { 1115 "rpz", cfg_parse_map, cfg_print_map, cfg_doc_map, 1116 &cfg_rep_map, rpz_clausesets 1117}; 1118 1119 1120 1121/*% 1122 * dnssec-lookaside 1123 */ 1124 1125static void 1126print_lookaside(cfg_printer_t *pctx, const cfg_obj_t *obj) 1127{ 1128 const cfg_obj_t *domain = obj->value.tuple[0]; 1129 1130 if (domain->value.string.length == 4 && 1131 strncmp(domain->value.string.base, "auto", 4) == 0) 1132 cfg_print_cstr(pctx, "auto"); 1133 else 1134 cfg_print_tuple(pctx, obj); 1135} 1136 1137static void 1138doc_lookaside(cfg_printer_t *pctx, const cfg_type_t *type) { 1139 UNUSED(type); 1140 cfg_print_cstr(pctx, "( <string> trust-anchor <string> | auto | no )"); 1141} 1142 1143static keyword_type_t trustanchor_kw = { "trust-anchor", &cfg_type_astring }; 1144 1145static cfg_type_t cfg_type_optional_trustanchor = { 1146 "optional_trustanchor", parse_optional_keyvalue, print_keyvalue, 1147 doc_keyvalue, &cfg_rep_string, &trustanchor_kw 1148}; 1149 1150static cfg_tuplefielddef_t lookaside_fields[] = { 1151 { "domain", &cfg_type_astring, 0 }, 1152 { "trust-anchor", &cfg_type_optional_trustanchor, 0 }, 1153 { NULL, NULL, 0 } 1154}; 1155 1156static cfg_type_t cfg_type_lookaside = { 1157 "lookaside", cfg_parse_tuple, print_lookaside, doc_lookaside, 1158 &cfg_rep_tuple, lookaside_fields 1159}; 1160 1161/* 1162 * DNS64. 1163 */ 1164static cfg_clausedef_t 1165dns64_clauses[] = { 1166 { "clients", &cfg_type_bracketed_aml, 0 }, 1167 { "mapped", &cfg_type_bracketed_aml, 0 }, 1168 { "exclude", &cfg_type_bracketed_aml, 0 }, 1169 { "suffix", &cfg_type_netaddr6, 0 }, 1170 { "recursive-only", &cfg_type_boolean, 0 }, 1171 { "break-dnssec", &cfg_type_boolean, 0 }, 1172 { NULL, NULL, 0 }, 1173}; 1174 1175static cfg_clausedef_t * 1176dns64_clausesets[] = { 1177 dns64_clauses, 1178 NULL 1179}; 1180 1181static cfg_type_t cfg_type_dns64 = { 1182 "dns64", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map, 1183 &cfg_rep_map, dns64_clausesets 1184}; 1185 1186/*% 1187 * Clauses that can be found within the 'view' statement, 1188 * with defaults in the 'options' statement. 1189 */ 1190 1191static cfg_clausedef_t 1192view_clauses[] = { 1193 { "acache-cleaning-interval", &cfg_type_uint32, 0 }, 1194 { "acache-enable", &cfg_type_boolean, 0 }, 1195 { "additional-from-auth", &cfg_type_boolean, 0 }, 1196 { "additional-from-cache", &cfg_type_boolean, 0 }, 1197 { "allow-new-zones", &cfg_type_boolean, 0 }, 1198 { "allow-query-cache", &cfg_type_bracketed_aml, 0 }, 1199 { "allow-query-cache-on", &cfg_type_bracketed_aml, 0 }, 1200 { "allow-recursion", &cfg_type_bracketed_aml, 0 }, 1201 { "allow-recursion-on", &cfg_type_bracketed_aml, 0 }, 1202 { "allow-v6-synthesis", &cfg_type_bracketed_aml, 1203 CFG_CLAUSEFLAG_OBSOLETE }, 1204 { "attach-cache", &cfg_type_astring, 0 }, 1205 { "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT }, 1206 { "cache-file", &cfg_type_qstring, 0 }, 1207 { "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI }, 1208 { "cleaning-interval", &cfg_type_uint32, 0 }, 1209 { "clients-per-query", &cfg_type_uint32, 0 }, 1210 { "deny-answer-addresses", &cfg_type_denyaddresses, 0 }, 1211 { "deny-answer-aliases", &cfg_type_denyaliases, 0 }, 1212 { "disable-algorithms", &cfg_type_disablealgorithm, 1213 CFG_CLAUSEFLAG_MULTI }, 1214 { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI }, 1215 { "dns64", &cfg_type_dns64, CFG_CLAUSEFLAG_MULTI }, 1216 { "dns64-server", &cfg_type_astring, 0 }, 1217 { "dns64-contact", &cfg_type_astring, 0 }, 1218 { "dnssec-accept-expired", &cfg_type_boolean, 0 }, 1219 { "dnssec-enable", &cfg_type_boolean, 0 }, 1220 { "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI }, 1221 { "dnssec-must-be-secure", &cfg_type_mustbesecure, 1222 CFG_CLAUSEFLAG_MULTI }, 1223 { "dnssec-validation", &cfg_type_boolorauto, 0 }, 1224 { "dual-stack-servers", &cfg_type_nameportiplist, 0 }, 1225 { "edns-udp-size", &cfg_type_uint32, 0 }, 1226 { "empty-contact", &cfg_type_astring, 0 }, 1227 { "empty-server", &cfg_type_astring, 0 }, 1228 { "empty-zones-enable", &cfg_type_boolean, 0 }, 1229 { "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 1230 { "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 }, 1231 { "lame-ttl", &cfg_type_uint32, 0 }, 1232 { "max-acache-size", &cfg_type_sizenodefault, 0 }, 1233 { "max-cache-size", &cfg_type_sizenodefault, 0 }, 1234 { "max-cache-ttl", &cfg_type_uint32, 0 }, 1235 { "max-clients-per-query", &cfg_type_uint32, 0 }, 1236 { "max-ncache-ttl", &cfg_type_uint32, 0 }, 1237 { "max-udp-size", &cfg_type_uint32, 0 }, 1238 { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP }, 1239 { "minimal-responses", &cfg_type_boolean, 0 }, 1240 { "preferred-glue", &cfg_type_astring, 0 }, 1241 { "provide-ixfr", &cfg_type_boolean, 0 }, 1242 /* 1243 * Note that the query-source option syntax is different 1244 * from the other -source options. 1245 */ 1246 { "query-source", &cfg_type_querysource4, 0 }, 1247 { "query-source-v6", &cfg_type_querysource6, 0 }, 1248 { "queryport-pool-ports", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE }, 1249 { "queryport-pool-updateinterval", &cfg_type_uint32, 1250 CFG_CLAUSEFLAG_OBSOLETE }, 1251 { "recursion", &cfg_type_boolean, 0 }, 1252 { "request-ixfr", &cfg_type_boolean, 0 }, 1253 { "request-nsid", &cfg_type_boolean, 0 }, 1254 { "resolver-query-timeout", &cfg_type_uint32, 0 }, 1255 { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI }, 1256 { "root-delegation-only", &cfg_type_optional_exclude, 0 }, 1257 { "rrset-order", &cfg_type_rrsetorder, 0 }, 1258 { "sortlist", &cfg_type_bracketed_aml, 0 }, 1259 { "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI }, 1260 { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP }, 1261 { "transfer-format", &cfg_type_transferformat, 0 }, 1262 { "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 1263 { "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 }, 1264#ifdef ALLOW_FILTER_AAAA_ON_V4 1265 { "filter-aaaa", &cfg_type_bracketed_aml, 0 }, 1266 { "filter-aaaa-on-v4", &cfg_type_v4_aaaa, 0 }, 1267#else 1268 { "filter-aaaa", &cfg_type_bracketed_aml, 1269 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1270 { "filter-aaaa-on-v4", &cfg_type_v4_aaaa, 1271 CFG_CLAUSEFLAG_NOTCONFIGURED }, 1272#endif 1273 { "response-policy", &cfg_type_rpz, 0 }, 1274 { NULL, NULL, 0 } 1275}; 1276 1277/*% 1278 * Clauses that can be found within the 'view' statement only. 1279 */ 1280static cfg_clausedef_t 1281view_only_clauses[] = { 1282 { "match-clients", &cfg_type_bracketed_aml, 0 }, 1283 { "match-destinations", &cfg_type_bracketed_aml, 0 }, 1284 { "match-recursive-only", &cfg_type_boolean, 0 }, 1285 { NULL, NULL, 0 } 1286}; 1287 1288/*% 1289 * Sig-validity-interval. 1290 */ 1291static isc_result_t 1292parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type, 1293 cfg_obj_t **ret) 1294{ 1295 isc_result_t result; 1296 UNUSED(type); 1297 1298 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); 1299 if (pctx->token.type == isc_tokentype_number) { 1300 CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret)); 1301 } else { 1302 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret)); 1303 } 1304 cleanup: 1305 return (result); 1306} 1307 1308static void 1309doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) { 1310 UNUSED(type); 1311 cfg_print_cstr(pctx, "[ <integer> ]"); 1312} 1313 1314static cfg_type_t cfg_type_optional_uint32 = { 1315 "optional_uint32", parse_optional_uint32, NULL, doc_optional_uint32, 1316 NULL, NULL }; 1317 1318static cfg_tuplefielddef_t validityinterval_fields[] = { 1319 { "validity", &cfg_type_uint32, 0 }, 1320 { "re-sign", &cfg_type_optional_uint32, 0 }, 1321 { NULL, NULL, 0 } 1322}; 1323 1324static cfg_type_t cfg_type_validityinterval = { 1325 "validityinterval", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 1326 &cfg_rep_tuple, validityinterval_fields 1327}; 1328 1329/*% 1330 * Clauses that can be found in a 'zone' statement, 1331 * with defaults in the 'view' or 'options' statement. 1332 */ 1333static cfg_clausedef_t 1334zone_clauses[] = { 1335 { "allow-notify", &cfg_type_bracketed_aml, 0 }, 1336 { "allow-query", &cfg_type_bracketed_aml, 0 }, 1337 { "allow-query-on", &cfg_type_bracketed_aml, 0 }, 1338 { "allow-transfer", &cfg_type_bracketed_aml, 0 }, 1339 { "allow-update", &cfg_type_bracketed_aml, 0 }, 1340 { "allow-update-forwarding", &cfg_type_bracketed_aml, 0 }, 1341 { "also-notify", &cfg_type_portiplist, 0 }, 1342 { "alt-transfer-source", &cfg_type_sockaddr4wild, 0 }, 1343 { "alt-transfer-source-v6", &cfg_type_sockaddr6wild, 0 }, 1344 { "auto-dnssec", &cfg_type_autodnssec, 0 }, 1345 { "check-dup-records", &cfg_type_checkmode, 0 }, 1346 { "check-integrity", &cfg_type_boolean, 0 }, 1347 { "check-mx", &cfg_type_checkmode, 0 }, 1348 { "check-mx-cname", &cfg_type_checkmode, 0 }, 1349 { "check-sibling", &cfg_type_boolean, 0 }, 1350 { "check-srv-cname", &cfg_type_checkmode, 0 }, 1351 { "check-wildcard", &cfg_type_boolean, 0 }, 1352 { "dialup", &cfg_type_dialuptype, 0 }, 1353 { "dnssec-dnskey-kskonly", &cfg_type_boolean, 0 }, 1354 { "dnssec-secure-to-insecure", &cfg_type_boolean, 0 }, 1355 { "forward", &cfg_type_forwardtype, 0 }, 1356 { "forwarders", &cfg_type_portiplist, 0 }, 1357 { "key-directory", &cfg_type_qstring, 0 }, 1358 { "maintain-ixfr-base", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 1359 { "masterfile-format", &cfg_type_masterformat, 0 }, 1360 { "max-ixfr-log-size", &cfg_type_size, CFG_CLAUSEFLAG_OBSOLETE }, 1361 { "max-journal-size", &cfg_type_sizenodefault, 0 }, 1362 { "max-refresh-time", &cfg_type_uint32, 0 }, 1363 { "max-retry-time", &cfg_type_uint32, 0 }, 1364 { "max-transfer-idle-in", &cfg_type_uint32, 0 }, 1365 { "max-transfer-idle-out", &cfg_type_uint32, 0 }, 1366 { "max-transfer-time-in", &cfg_type_uint32, 0 }, 1367 { "max-transfer-time-out", &cfg_type_uint32, 0 }, 1368 { "min-refresh-time", &cfg_type_uint32, 0 }, 1369 { "min-retry-time", &cfg_type_uint32, 0 }, 1370 { "multi-master", &cfg_type_boolean, 0 }, 1371 { "notify", &cfg_type_notifytype, 0 }, 1372 { "notify-delay", &cfg_type_uint32, 0 }, 1373 { "notify-source", &cfg_type_sockaddr4wild, 0 }, 1374 { "notify-source-v6", &cfg_type_sockaddr6wild, 0 }, 1375 { "notify-to-soa", &cfg_type_boolean, 0 }, 1376 { "nsec3-test-zone", &cfg_type_boolean, CFG_CLAUSEFLAG_TESTONLY }, 1377 { "sig-signing-nodes", &cfg_type_uint32, 0 }, 1378 { "sig-signing-signatures", &cfg_type_uint32, 0 }, 1379 { "sig-signing-type", &cfg_type_uint32, 0 }, 1380 { "sig-validity-interval", &cfg_type_validityinterval, 0 }, 1381 { "transfer-source", &cfg_type_sockaddr4wild, 0 }, 1382 { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 }, 1383 { "try-tcp-refresh", &cfg_type_boolean, 0 }, 1384 { "update-check-ksk", &cfg_type_boolean, 0 }, 1385 { "use-alt-transfer-source", &cfg_type_boolean, 0 }, 1386 { "zero-no-soa-ttl", &cfg_type_boolean, 0 }, 1387 { "zone-statistics", &cfg_type_boolean, 0 }, 1388 { NULL, NULL, 0 } 1389}; 1390 1391/*% 1392 * Clauses that can be found in a 'zone' statement 1393 * only. 1394 */ 1395static cfg_clausedef_t 1396zone_only_clauses[] = { 1397 { "type", &cfg_type_zonetype, 0 }, 1398 { "file", &cfg_type_qstring, 0 }, 1399 { "journal", &cfg_type_qstring, 0 }, 1400 { "ixfr-base", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE }, 1401 { "ixfr-tmp-file", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE }, 1402 { "masters", &cfg_type_namesockaddrkeylist, 0 }, 1403 { "pubkey", &cfg_type_pubkey, 1404 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE }, 1405 { "update-policy", &cfg_type_updatepolicy, 0 }, 1406 { "database", &cfg_type_astring, 0 }, 1407 { "delegation-only", &cfg_type_boolean, 0 }, 1408 /* 1409 * Note that the format of the check-names option is different between 1410 * the zone options and the global/view options. Ugh. 1411 */ 1412 { "check-names", &cfg_type_checkmode, 0 }, 1413 { "ixfr-from-differences", &cfg_type_boolean, 0 }, 1414 { "server-addresses", &cfg_type_bracketed_sockaddrlist, 0 }, 1415 { "server-names", &cfg_type_namelist, 0 }, 1416 { NULL, NULL, 0 } 1417}; 1418 1419 1420/*% The top-level named.conf syntax. */ 1421 1422static cfg_clausedef_t * 1423namedconf_clausesets[] = { 1424 namedconf_clauses, 1425 namedconf_or_view_clauses, 1426 NULL 1427}; 1428LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = { 1429 "namedconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, 1430 &cfg_rep_map, namedconf_clausesets 1431}; 1432 1433/*% The bind.keys syntax (trusted-keys/managed-keys only). */ 1434static cfg_clausedef_t * 1435bindkeys_clausesets[] = { 1436 bindkeys_clauses, 1437 NULL 1438}; 1439LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bindkeys = { 1440 "bindkeys", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, 1441 &cfg_rep_map, bindkeys_clausesets 1442}; 1443 1444/*% The new-zone-file syntax (for zones added by 'rndc addzone') */ 1445static cfg_clausedef_t 1446newzones_clauses[] = { 1447 { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI }, 1448 { NULL, NULL, 0 } 1449}; 1450 1451static cfg_clausedef_t * 1452newzones_clausesets[] = { 1453 newzones_clauses, 1454 NULL 1455}; 1456 1457LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_newzones = { 1458 "newzones", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, 1459 &cfg_rep_map, newzones_clausesets 1460}; 1461 1462/*% The "options" statement syntax. */ 1463 1464static cfg_clausedef_t * 1465options_clausesets[] = { 1466 options_clauses, 1467 view_clauses, 1468 zone_clauses, 1469 NULL 1470}; 1471cfg_type_t cfg_type_options = { 1472 "options", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, options_clausesets }; 1473 1474/*% The "view" statement syntax. */ 1475 1476static cfg_clausedef_t * 1477view_clausesets[] = { 1478 view_only_clauses, 1479 namedconf_or_view_clauses, 1480 view_clauses, 1481 zone_clauses, 1482 dynamically_loadable_zones_clauses, 1483 NULL 1484}; 1485cfg_type_t cfg_type_viewopts = { 1486 "view", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, view_clausesets }; 1487 1488/*% The "zone" statement syntax. */ 1489 1490static cfg_clausedef_t * 1491zone_clausesets[] = { 1492 zone_only_clauses, 1493 zone_clauses, 1494 NULL 1495}; 1496cfg_type_t cfg_type_zoneopts = { 1497 "zoneopts", cfg_parse_map, cfg_print_map, 1498 cfg_doc_map, &cfg_rep_map, zone_clausesets }; 1499 1500/*% The "dynamically loadable zones" statement syntax. */ 1501 1502static cfg_clausedef_t * 1503dynamically_loadable_zones_clausesets[] = { 1504 dynamically_loadable_zones_clauses, 1505 NULL 1506}; 1507static cfg_type_t cfg_type_dynamically_loadable_zones_opts = { 1508 "dynamically_loadable_zones_opts", cfg_parse_map, 1509 cfg_print_map, cfg_doc_map, &cfg_rep_map, 1510 dynamically_loadable_zones_clausesets 1511}; 1512 1513/*% 1514 * Clauses that can be found within the 'key' statement. 1515 */ 1516static cfg_clausedef_t 1517key_clauses[] = { 1518 { "algorithm", &cfg_type_astring, 0 }, 1519 { "secret", &cfg_type_astring, 0 }, 1520 { NULL, NULL, 0 } 1521}; 1522 1523static cfg_clausedef_t * 1524key_clausesets[] = { 1525 key_clauses, 1526 NULL 1527}; 1528static cfg_type_t cfg_type_key = { 1529 "key", cfg_parse_named_map, cfg_print_map, 1530 cfg_doc_map, &cfg_rep_map, key_clausesets 1531}; 1532 1533 1534/*% 1535 * Clauses that can be found in a 'server' statement. 1536 */ 1537static cfg_clausedef_t 1538server_clauses[] = { 1539 { "bogus", &cfg_type_boolean, 0 }, 1540 { "provide-ixfr", &cfg_type_boolean, 0 }, 1541 { "request-ixfr", &cfg_type_boolean, 0 }, 1542 { "support-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, 1543 { "transfers", &cfg_type_uint32, 0 }, 1544 { "transfer-format", &cfg_type_transferformat, 0 }, 1545 { "keys", &cfg_type_server_key_kludge, 0 }, 1546 { "edns", &cfg_type_boolean, 0 }, 1547 { "edns-udp-size", &cfg_type_uint32, 0 }, 1548 { "max-udp-size", &cfg_type_uint32, 0 }, 1549 { "notify-source", &cfg_type_sockaddr4wild, 0 }, 1550 { "notify-source-v6", &cfg_type_sockaddr6wild, 0 }, 1551 { "query-source", &cfg_type_querysource4, 0 }, 1552 { "query-source-v6", &cfg_type_querysource6, 0 }, 1553 { "transfer-source", &cfg_type_sockaddr4wild, 0 }, 1554 { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 }, 1555 { NULL, NULL, 0 } 1556}; 1557static cfg_clausedef_t * 1558server_clausesets[] = { 1559 server_clauses, 1560 NULL 1561}; 1562static cfg_type_t cfg_type_server = { 1563 "server", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, 1564 server_clausesets 1565}; 1566 1567 1568/*% 1569 * Clauses that can be found in a 'channel' clause in the 1570 * 'logging' statement. 1571 * 1572 * These have some additional constraints that need to be 1573 * checked after parsing: 1574 * - There must exactly one of file/syslog/null/stderr 1575 * 1576 */ 1577static cfg_clausedef_t 1578channel_clauses[] = { 1579 /* Destinations. We no longer require these to be first. */ 1580 { "file", &cfg_type_logfile, 0 }, 1581 { "syslog", &cfg_type_optional_facility, 0 }, 1582 { "null", &cfg_type_void, 0 }, 1583 { "stderr", &cfg_type_void, 0 }, 1584 /* Options. We now accept these for the null channel, too. */ 1585 { "severity", &cfg_type_logseverity, 0 }, 1586 { "print-time", &cfg_type_boolean, 0 }, 1587 { "print-severity", &cfg_type_boolean, 0 }, 1588 { "print-category", &cfg_type_boolean, 0 }, 1589 { NULL, NULL, 0 } 1590}; 1591static cfg_clausedef_t * 1592channel_clausesets[] = { 1593 channel_clauses, 1594 NULL 1595}; 1596cfg_type_t cfg_type_channel = { 1597 "channel", cfg_parse_named_map, cfg_print_map, cfg_doc_map, 1598 &cfg_rep_map, channel_clausesets 1599}; 1600 1601/*% A list of log destination, used in the "category" clause. */ 1602cfg_type_t cfg_type_destinationlist = { 1603 "destinationlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, 1604 &cfg_rep_list, &cfg_type_astring }; 1605 1606/*% 1607 * Clauses that can be found in a 'logging' statement. 1608 */ 1609static cfg_clausedef_t 1610logging_clauses[] = { 1611 { "channel", &cfg_type_channel, CFG_CLAUSEFLAG_MULTI }, 1612 { "category", &cfg_type_category, CFG_CLAUSEFLAG_MULTI }, 1613 { NULL, NULL, 0 } 1614}; 1615static cfg_clausedef_t * 1616logging_clausesets[] = { 1617 logging_clauses, 1618 NULL 1619}; 1620cfg_type_t cfg_type_logging = { 1621 "logging", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, logging_clausesets }; 1622 1623 1624/*% 1625 * For parsing an 'addzone' statement 1626 */ 1627 1628static cfg_tuplefielddef_t addzone_fields[] = { 1629 { "name", &cfg_type_astring, 0 }, 1630 { "class", &cfg_type_optional_class, 0 }, 1631 { "view", &cfg_type_optional_class, 0 }, 1632 { "options", &cfg_type_zoneopts, 0 }, 1633 { NULL, NULL, 0 } 1634}; 1635static cfg_type_t cfg_type_addzone = { 1636 "addzone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, addzone_fields }; 1637 1638static cfg_clausedef_t 1639addzoneconf_clauses[] = { 1640 { "addzone", &cfg_type_addzone, 0 }, 1641 { NULL, NULL, 0 } 1642}; 1643 1644static cfg_clausedef_t * 1645addzoneconf_clausesets[] = { 1646 addzoneconf_clauses, 1647 NULL 1648}; 1649 1650LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_addzoneconf = { 1651 "addzoneconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, 1652 &cfg_rep_map, addzoneconf_clausesets 1653}; 1654 1655 1656static isc_result_t 1657parse_unitstring(char *str, isc_resourcevalue_t *valuep) { 1658 char *endp; 1659 unsigned int len; 1660 isc_uint64_t value; 1661 isc_uint64_t unit; 1662 1663 value = isc_string_touint64(str, &endp, 10); 1664 if (*endp == 0) { 1665 *valuep = value; 1666 return (ISC_R_SUCCESS); 1667 } 1668 1669 len = strlen(str); 1670 if (len < 2 || endp[1] != '\0') 1671 return (ISC_R_FAILURE); 1672 1673 switch (str[len - 1]) { 1674 case 'k': 1675 case 'K': 1676 unit = 1024; 1677 break; 1678 case 'm': 1679 case 'M': 1680 unit = 1024 * 1024; 1681 break; 1682 case 'g': 1683 case 'G': 1684 unit = 1024 * 1024 * 1024; 1685 break; 1686 default: 1687 return (ISC_R_FAILURE); 1688 } 1689 if (value > ISC_UINT64_MAX / unit) 1690 return (ISC_R_FAILURE); 1691 *valuep = value * unit; 1692 return (ISC_R_SUCCESS); 1693} 1694 1695static isc_result_t 1696parse_sizeval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1697 isc_result_t result; 1698 cfg_obj_t *obj = NULL; 1699 isc_uint64_t val; 1700 1701 UNUSED(type); 1702 1703 CHECK(cfg_gettoken(pctx, 0)); 1704 if (pctx->token.type != isc_tokentype_string) { 1705 result = ISC_R_UNEXPECTEDTOKEN; 1706 goto cleanup; 1707 } 1708 CHECK(parse_unitstring(TOKEN_STRING(pctx), &val)); 1709 1710 CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj)); 1711 obj->value.uint64 = val; 1712 *ret = obj; 1713 return (ISC_R_SUCCESS); 1714 1715 cleanup: 1716 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected integer and optional unit"); 1717 return (result); 1718} 1719 1720/*% 1721 * A size value (number + optional unit). 1722 */ 1723static cfg_type_t cfg_type_sizeval = { 1724 "sizeval", parse_sizeval, cfg_print_uint64, cfg_doc_terminal, 1725 &cfg_rep_uint64, NULL }; 1726 1727/*% 1728 * A size, "unlimited", or "default". 1729 */ 1730 1731static isc_result_t 1732parse_size(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1733 return (parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret)); 1734} 1735 1736static const char *size_enums[] = { "unlimited", "default", NULL }; 1737static cfg_type_t cfg_type_size = { 1738 "size", parse_size, cfg_print_ustring, cfg_doc_terminal, 1739 &cfg_rep_string, size_enums 1740}; 1741 1742/*% 1743 * A size or "unlimited", but not "default". 1744 */ 1745static const char *sizenodefault_enums[] = { "unlimited", NULL }; 1746static cfg_type_t cfg_type_sizenodefault = { 1747 "size_no_default", parse_size, cfg_print_ustring, cfg_doc_terminal, 1748 &cfg_rep_string, sizenodefault_enums 1749}; 1750 1751/*% 1752 * optional_keyvalue 1753 */ 1754static isc_result_t 1755parse_maybe_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, 1756 isc_boolean_t optional, cfg_obj_t **ret) 1757{ 1758 isc_result_t result; 1759 cfg_obj_t *obj = NULL; 1760 const keyword_type_t *kw = type->of; 1761 1762 CHECK(cfg_peektoken(pctx, 0)); 1763 if (pctx->token.type == isc_tokentype_string && 1764 strcasecmp(TOKEN_STRING(pctx), kw->name) == 0) { 1765 CHECK(cfg_gettoken(pctx, 0)); 1766 CHECK(kw->type->parse(pctx, kw->type, &obj)); 1767 obj->type = type; /* XXX kludge */ 1768 } else { 1769 if (optional) { 1770 CHECK(cfg_parse_void(pctx, NULL, &obj)); 1771 } else { 1772 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected '%s'", 1773 kw->name); 1774 result = ISC_R_UNEXPECTEDTOKEN; 1775 goto cleanup; 1776 } 1777 } 1778 *ret = obj; 1779 cleanup: 1780 return (result); 1781} 1782 1783static isc_result_t 1784parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype, 1785 const cfg_type_t *othertype, cfg_obj_t **ret) 1786{ 1787 isc_result_t result; 1788 CHECK(cfg_peektoken(pctx, 0)); 1789 if (pctx->token.type == isc_tokentype_string && 1790 cfg_is_enum(TOKEN_STRING(pctx), enumtype->of)) { 1791 CHECK(cfg_parse_enum(pctx, enumtype, ret)); 1792 } else { 1793 CHECK(cfg_parse_obj(pctx, othertype, ret)); 1794 } 1795 cleanup: 1796 return (result); 1797} 1798 1799static void 1800doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *type) { 1801 cfg_doc_terminal(pctx, type); 1802#if 0 /* XXX */ 1803 cfg_print_chars(pctx, "( ", 2);... 1804#endif 1805 1806} 1807 1808static isc_result_t 1809parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1810 return (parse_maybe_optional_keyvalue(pctx, type, ISC_FALSE, ret)); 1811} 1812 1813static isc_result_t 1814parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1815 return (parse_maybe_optional_keyvalue(pctx, type, ISC_TRUE, ret)); 1816} 1817 1818static void 1819print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj) { 1820 const keyword_type_t *kw = obj->type->of; 1821 cfg_print_cstr(pctx, kw->name); 1822 cfg_print_chars(pctx, " ", 1); 1823 kw->type->print(pctx, obj); 1824} 1825 1826static void 1827doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) { 1828 const keyword_type_t *kw = type->of; 1829 cfg_print_cstr(pctx, kw->name); 1830 cfg_print_chars(pctx, " ", 1); 1831 cfg_doc_obj(pctx, kw->type); 1832} 1833 1834static void 1835doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) { 1836 const keyword_type_t *kw = type->of; 1837 cfg_print_chars(pctx, "[ ", 2); 1838 cfg_print_cstr(pctx, kw->name); 1839 cfg_print_chars(pctx, " ", 1); 1840 cfg_doc_obj(pctx, kw->type); 1841 cfg_print_chars(pctx, " ]", 2); 1842} 1843 1844static const char *dialup_enums[] = { 1845 "notify", "notify-passive", "refresh", "passive", NULL }; 1846static isc_result_t 1847parse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1848 return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 1849} 1850static cfg_type_t cfg_type_dialuptype = { 1851 "dialuptype", parse_dialup_type, cfg_print_ustring, doc_enum_or_other, 1852 &cfg_rep_string, dialup_enums 1853}; 1854 1855static const char *notify_enums[] = { "explicit", "master-only", NULL }; 1856static isc_result_t 1857parse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1858 return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 1859} 1860static cfg_type_t cfg_type_notifytype = { 1861 "notifytype", parse_notify_type, cfg_print_ustring, doc_enum_or_other, 1862 &cfg_rep_string, notify_enums, 1863}; 1864 1865static const char *ixfrdiff_enums[] = { "master", "slave", NULL }; 1866static isc_result_t 1867parse_ixfrdiff_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1868 return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 1869} 1870static cfg_type_t cfg_type_ixfrdifftype = { 1871 "ixfrdiff", parse_ixfrdiff_type, cfg_print_ustring, doc_enum_or_other, 1872 &cfg_rep_string, ixfrdiff_enums, 1873}; 1874 1875static const char *v4_aaaa_enums[] = { "break-dnssec", NULL }; 1876static isc_result_t 1877parse_v4_aaaa(cfg_parser_t *pctx, const cfg_type_t *type, 1878 cfg_obj_t **ret) { 1879 return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); 1880} 1881static cfg_type_t cfg_type_v4_aaaa = { 1882 "v4_aaaa", parse_v4_aaaa, cfg_print_ustring, 1883 doc_enum_or_other, &cfg_rep_string, v4_aaaa_enums, 1884}; 1885 1886static keyword_type_t key_kw = { "key", &cfg_type_astring }; 1887 1888LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = { 1889 "keyref", parse_keyvalue, print_keyvalue, doc_keyvalue, 1890 &cfg_rep_string, &key_kw 1891}; 1892 1893cfg_type_t cfg_type_optional_keyref = { 1894 "optional_keyref", parse_optional_keyvalue, print_keyvalue, 1895 doc_optional_keyvalue, &cfg_rep_string, &key_kw 1896}; 1897 1898/*% 1899 * A "controls" statement is represented as a map with the multivalued 1900 * "inet" and "unix" clauses. 1901 */ 1902 1903static keyword_type_t controls_allow_kw = { 1904 "allow", &cfg_type_bracketed_aml }; 1905 1906static cfg_type_t cfg_type_controls_allow = { 1907 "controls_allow", parse_keyvalue, 1908 print_keyvalue, doc_keyvalue, 1909 &cfg_rep_list, &controls_allow_kw 1910}; 1911 1912static keyword_type_t controls_keys_kw = { 1913 "keys", &cfg_type_keylist }; 1914 1915static cfg_type_t cfg_type_controls_keys = { 1916 "controls_keys", parse_optional_keyvalue, 1917 print_keyvalue, doc_optional_keyvalue, 1918 &cfg_rep_list, &controls_keys_kw 1919}; 1920 1921static cfg_tuplefielddef_t inetcontrol_fields[] = { 1922 { "address", &cfg_type_controls_sockaddr, 0 }, 1923 { "allow", &cfg_type_controls_allow, 0 }, 1924 { "keys", &cfg_type_controls_keys, 0 }, 1925 { NULL, NULL, 0 } 1926}; 1927 1928static cfg_type_t cfg_type_inetcontrol = { 1929 "inetcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, 1930 inetcontrol_fields 1931}; 1932 1933static keyword_type_t controls_perm_kw = { 1934 "perm", &cfg_type_uint32 }; 1935 1936static cfg_type_t cfg_type_controls_perm = { 1937 "controls_perm", parse_keyvalue, 1938 print_keyvalue, doc_keyvalue, 1939 &cfg_rep_uint32, &controls_perm_kw 1940}; 1941 1942static keyword_type_t controls_owner_kw = { 1943 "owner", &cfg_type_uint32 }; 1944 1945static cfg_type_t cfg_type_controls_owner = { 1946 "controls_owner", parse_keyvalue, 1947 print_keyvalue, doc_keyvalue, 1948 &cfg_rep_uint32, &controls_owner_kw 1949}; 1950 1951static keyword_type_t controls_group_kw = { 1952 "group", &cfg_type_uint32 }; 1953 1954static cfg_type_t cfg_type_controls_group = { 1955 "controls_allow", parse_keyvalue, 1956 print_keyvalue, doc_keyvalue, 1957 &cfg_rep_uint32, &controls_group_kw 1958}; 1959 1960static cfg_tuplefielddef_t unixcontrol_fields[] = { 1961 { "path", &cfg_type_qstring, 0 }, 1962 { "perm", &cfg_type_controls_perm, 0 }, 1963 { "owner", &cfg_type_controls_owner, 0 }, 1964 { "group", &cfg_type_controls_group, 0 }, 1965 { "keys", &cfg_type_controls_keys, 0 }, 1966 { NULL, NULL, 0 } 1967}; 1968 1969static cfg_type_t cfg_type_unixcontrol = { 1970 "unixcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, 1971 unixcontrol_fields 1972}; 1973 1974static cfg_clausedef_t 1975controls_clauses[] = { 1976 { "inet", &cfg_type_inetcontrol, CFG_CLAUSEFLAG_MULTI }, 1977 { "unix", &cfg_type_unixcontrol, CFG_CLAUSEFLAG_MULTI }, 1978 { NULL, NULL, 0 } 1979}; 1980 1981static cfg_clausedef_t * 1982controls_clausesets[] = { 1983 controls_clauses, 1984 NULL 1985}; 1986static cfg_type_t cfg_type_controls = { 1987 "controls", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, &controls_clausesets 1988}; 1989 1990/*% 1991 * A "statistics-channels" statement is represented as a map with the 1992 * multivalued "inet" clauses. 1993 */ 1994static void 1995doc_optional_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) { 1996 const keyword_type_t *kw = type->of; 1997 cfg_print_chars(pctx, "[ ", 2); 1998 cfg_print_cstr(pctx, kw->name); 1999 cfg_print_chars(pctx, " ", 1); 2000 cfg_doc_obj(pctx, kw->type); 2001 cfg_print_chars(pctx, " ]", 2); 2002} 2003 2004static cfg_type_t cfg_type_optional_allow = { 2005 "optional_allow", parse_optional_keyvalue, print_keyvalue, 2006 doc_optional_bracketed_list, &cfg_rep_list, &controls_allow_kw 2007}; 2008 2009static cfg_tuplefielddef_t statserver_fields[] = { 2010 { "address", &cfg_type_controls_sockaddr, 0 }, /* reuse controls def */ 2011 { "allow", &cfg_type_optional_allow, 0 }, 2012 { NULL, NULL, 0 } 2013}; 2014 2015static cfg_type_t cfg_type_statschannel = { 2016 "statschannel", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 2017 &cfg_rep_tuple, statserver_fields 2018}; 2019 2020static cfg_clausedef_t 2021statservers_clauses[] = { 2022 { "inet", &cfg_type_statschannel, CFG_CLAUSEFLAG_MULTI }, 2023 { NULL, NULL, 0 } 2024}; 2025 2026static cfg_clausedef_t * 2027statservers_clausesets[] = { 2028 statservers_clauses, 2029 NULL 2030}; 2031 2032static cfg_type_t cfg_type_statschannels = { 2033 "statistics-channels", cfg_parse_map, cfg_print_map, cfg_doc_map, 2034 &cfg_rep_map, &statservers_clausesets 2035}; 2036 2037/*% 2038 * An optional class, as used in view and zone statements. 2039 */ 2040static isc_result_t 2041parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2042 isc_result_t result; 2043 UNUSED(type); 2044 CHECK(cfg_peektoken(pctx, 0)); 2045 if (pctx->token.type == isc_tokentype_string) 2046 CHECK(cfg_parse_obj(pctx, &cfg_type_ustring, ret)); 2047 else 2048 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret)); 2049 cleanup: 2050 return (result); 2051} 2052 2053static cfg_type_t cfg_type_optional_class = { 2054 "optional_class", parse_optional_class, NULL, cfg_doc_terminal, 2055 NULL, NULL 2056}; 2057 2058static isc_result_t 2059parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2060 isc_result_t result; 2061 cfg_obj_t *obj = NULL; 2062 isc_netaddr_t netaddr; 2063 in_port_t port; 2064 unsigned int have_address = 0; 2065 unsigned int have_port = 0; 2066 const unsigned int *flagp = type->of; 2067 2068 if ((*flagp & CFG_ADDR_V4OK) != 0) 2069 isc_netaddr_any(&netaddr); 2070 else if ((*flagp & CFG_ADDR_V6OK) != 0) 2071 isc_netaddr_any6(&netaddr); 2072 else 2073 INSIST(0); 2074 2075 port = 0; 2076 2077 for (;;) { 2078 CHECK(cfg_peektoken(pctx, 0)); 2079 if (pctx->token.type == isc_tokentype_string) { 2080 if (strcasecmp(TOKEN_STRING(pctx), 2081 "address") == 0) 2082 { 2083 /* read "address" */ 2084 CHECK(cfg_gettoken(pctx, 0)); 2085 CHECK(cfg_parse_rawaddr(pctx, *flagp, 2086 &netaddr)); 2087 have_address++; 2088 } else if (strcasecmp(TOKEN_STRING(pctx), "port") == 0) 2089 { 2090 /* read "port" */ 2091 CHECK(cfg_gettoken(pctx, 0)); 2092 CHECK(cfg_parse_rawport(pctx, 2093 CFG_ADDR_WILDOK, 2094 &port)); 2095 have_port++; 2096 } else if (have_port == 0 && have_address == 0) { 2097 return (cfg_parse_sockaddr(pctx, type, ret)); 2098 } else { 2099 cfg_parser_error(pctx, CFG_LOG_NEAR, 2100 "expected 'address' or 'port'"); 2101 return (ISC_R_UNEXPECTEDTOKEN); 2102 } 2103 } else 2104 break; 2105 } 2106 if (have_address > 1 || have_port > 1 || 2107 have_address + have_port == 0) { 2108 cfg_parser_error(pctx, 0, "expected one address and/or port"); 2109 return (ISC_R_UNEXPECTEDTOKEN); 2110 } 2111 2112 CHECK(cfg_create_obj(pctx, &cfg_type_querysource, &obj)); 2113 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); 2114 *ret = obj; 2115 return (ISC_R_SUCCESS); 2116 2117 cleanup: 2118 cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid query source"); 2119 CLEANUP_OBJ(obj); 2120 return (result); 2121} 2122 2123static void 2124print_querysource(cfg_printer_t *pctx, const cfg_obj_t *obj) { 2125 isc_netaddr_t na; 2126 isc_netaddr_fromsockaddr(&na, &obj->value.sockaddr); 2127 cfg_print_cstr(pctx, "address "); 2128 cfg_print_rawaddr(pctx, &na); 2129 cfg_print_cstr(pctx, " port "); 2130 cfg_print_rawuint(pctx, isc_sockaddr_getport(&obj->value.sockaddr)); 2131} 2132 2133static unsigned int sockaddr4wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V4OK; 2134static unsigned int sockaddr6wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V6OK; 2135 2136static cfg_type_t cfg_type_querysource4 = { 2137 "querysource4", parse_querysource, NULL, cfg_doc_terminal, 2138 NULL, &sockaddr4wild_flags 2139}; 2140 2141static cfg_type_t cfg_type_querysource6 = { 2142 "querysource6", parse_querysource, NULL, cfg_doc_terminal, 2143 NULL, &sockaddr6wild_flags 2144}; 2145 2146static cfg_type_t cfg_type_querysource = { 2147 "querysource", NULL, print_querysource, NULL, &cfg_rep_sockaddr, NULL 2148}; 2149 2150/*% addrmatchelt */ 2151 2152static isc_result_t 2153parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2154 isc_result_t result; 2155 UNUSED(type); 2156 2157 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); 2158 2159 if (pctx->token.type == isc_tokentype_string || 2160 pctx->token.type == isc_tokentype_qstring) { 2161 if (pctx->token.type == isc_tokentype_string && 2162 (strcasecmp(TOKEN_STRING(pctx), "key") == 0)) { 2163 CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret)); 2164 } else { 2165 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | 2166 CFG_ADDR_V4PREFIXOK | 2167 CFG_ADDR_V6OK)) 2168 { 2169 CHECK(cfg_parse_netprefix(pctx, NULL, ret)); 2170 } else { 2171 CHECK(cfg_parse_astring(pctx, NULL, ret)); 2172 } 2173 } 2174 } else if (pctx->token.type == isc_tokentype_special) { 2175 if (pctx->token.value.as_char == '{') { 2176 /* Nested match list. */ 2177 CHECK(cfg_parse_obj(pctx, &cfg_type_bracketed_aml, ret)); 2178 } else if (pctx->token.value.as_char == '!') { 2179 CHECK(cfg_gettoken(pctx, 0)); /* read "!" */ 2180 CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret)); 2181 } else { 2182 goto bad; 2183 } 2184 } else { 2185 bad: 2186 cfg_parser_error(pctx, CFG_LOG_NEAR, 2187 "expected IP match list element"); 2188 return (ISC_R_UNEXPECTEDTOKEN); 2189 } 2190 cleanup: 2191 return (result); 2192} 2193 2194/*% 2195 * A negated address match list element (like "! 10.0.0.1"). 2196 * Somewhat sneakily, the caller is expected to parse the 2197 * "!", but not to print it. 2198 */ 2199 2200static cfg_tuplefielddef_t negated_fields[] = { 2201 { "value", &cfg_type_addrmatchelt, 0 }, 2202 { NULL, NULL, 0 } 2203}; 2204 2205static void 2206print_negated(cfg_printer_t *pctx, const cfg_obj_t *obj) { 2207 cfg_print_chars(pctx, "!", 1); 2208 cfg_print_tuple(pctx, obj); 2209} 2210 2211static cfg_type_t cfg_type_negated = { 2212 "negated", cfg_parse_tuple, print_negated, NULL, &cfg_rep_tuple, 2213 &negated_fields 2214}; 2215 2216/*% An address match list element */ 2217 2218static cfg_type_t cfg_type_addrmatchelt = { 2219 "address_match_element", parse_addrmatchelt, NULL, cfg_doc_terminal, 2220 NULL, NULL 2221}; 2222 2223/*% A bracketed address match list */ 2224 2225cfg_type_t cfg_type_bracketed_aml = { 2226 "bracketed_aml", cfg_parse_bracketed_list, cfg_print_bracketed_list, 2227 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_addrmatchelt 2228}; 2229 2230/*% 2231 * The socket address syntax in the "controls" statement is silly. 2232 * It allows both socket address families, but also allows "*", 2233 * whis is gratuitously interpreted as the IPv4 wildcard address. 2234 */ 2235static unsigned int controls_sockaddr_flags = 2236 CFG_ADDR_V4OK | CFG_ADDR_V6OK | CFG_ADDR_WILDOK; 2237static cfg_type_t cfg_type_controls_sockaddr = { 2238 "controls_sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, 2239 cfg_doc_sockaddr, &cfg_rep_sockaddr, &controls_sockaddr_flags 2240}; 2241 2242/*% 2243 * Handle the special kludge syntax of the "keys" clause in the "server" 2244 * statement, which takes a single key with or without braces and semicolon. 2245 */ 2246static isc_result_t 2247parse_server_key_kludge(cfg_parser_t *pctx, const cfg_type_t *type, 2248 cfg_obj_t **ret) 2249{ 2250 isc_result_t result; 2251 isc_boolean_t braces = ISC_FALSE; 2252 UNUSED(type); 2253 2254 /* Allow opening brace. */ 2255 CHECK(cfg_peektoken(pctx, 0)); 2256 if (pctx->token.type == isc_tokentype_special && 2257 pctx->token.value.as_char == '{') { 2258 CHECK(cfg_gettoken(pctx, 0)); 2259 braces = ISC_TRUE; 2260 } 2261 2262 CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret)); 2263 2264 if (braces) { 2265 /* Skip semicolon if present. */ 2266 CHECK(cfg_peektoken(pctx, 0)); 2267 if (pctx->token.type == isc_tokentype_special && 2268 pctx->token.value.as_char == ';') 2269 CHECK(cfg_gettoken(pctx, 0)); 2270 2271 CHECK(cfg_parse_special(pctx, '}')); 2272 } 2273 cleanup: 2274 return (result); 2275} 2276static cfg_type_t cfg_type_server_key_kludge = { 2277 "server_key", parse_server_key_kludge, NULL, cfg_doc_terminal, 2278 NULL, NULL 2279}; 2280 2281 2282/*% 2283 * An optional logging facility. 2284 */ 2285 2286static isc_result_t 2287parse_optional_facility(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) 2288{ 2289 isc_result_t result; 2290 UNUSED(type); 2291 2292 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); 2293 if (pctx->token.type == isc_tokentype_string || 2294 pctx->token.type == isc_tokentype_qstring) { 2295 CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret)); 2296 } else { 2297 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret)); 2298 } 2299 cleanup: 2300 return (result); 2301} 2302 2303static cfg_type_t cfg_type_optional_facility = { 2304 "optional_facility", parse_optional_facility, NULL, cfg_doc_terminal, 2305 NULL, NULL }; 2306 2307 2308/*% 2309 * A log severity. Return as a string, except "debug N", 2310 * which is returned as a keyword object. 2311 */ 2312 2313static keyword_type_t debug_kw = { "debug", &cfg_type_uint32 }; 2314cfg_type_t cfg_type_debuglevel = { 2315 "debuglevel", parse_keyvalue, 2316 print_keyvalue, doc_keyvalue, 2317 &cfg_rep_uint32, &debug_kw 2318}; 2319 2320static isc_result_t 2321parse_logseverity(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2322 isc_result_t result; 2323 UNUSED(type); 2324 2325 CHECK(cfg_peektoken(pctx, 0)); 2326 if (pctx->token.type == isc_tokentype_string && 2327 strcasecmp(TOKEN_STRING(pctx), "debug") == 0) { 2328 CHECK(cfg_gettoken(pctx, 0)); /* read "debug" */ 2329 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER)); 2330 if (pctx->token.type == isc_tokentype_number) { 2331 CHECK(cfg_parse_uint32(pctx, NULL, ret)); 2332 } else { 2333 /* 2334 * The debug level is optional and defaults to 1. 2335 * This makes little sense, but we support it for 2336 * compatibility with BIND 8. 2337 */ 2338 CHECK(cfg_create_obj(pctx, &cfg_type_uint32, ret)); 2339 (*ret)->value.uint32 = 1; 2340 } 2341 (*ret)->type = &cfg_type_debuglevel; /* XXX kludge */ 2342 } else { 2343 CHECK(cfg_parse_obj(pctx, &cfg_type_loglevel, ret)); 2344 } 2345 cleanup: 2346 return (result); 2347} 2348 2349static cfg_type_t cfg_type_logseverity = { 2350 "log_severity", parse_logseverity, NULL, cfg_doc_terminal, 2351 NULL, NULL }; 2352 2353/*% 2354 * The "file" clause of the "channel" statement. 2355 * This is yet another special case. 2356 */ 2357 2358static const char *logversions_enums[] = { "unlimited", NULL }; 2359static isc_result_t 2360parse_logversions(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2361 return (parse_enum_or_other(pctx, type, &cfg_type_uint32, ret)); 2362} 2363 2364static cfg_type_t cfg_type_logversions = { 2365 "logversions", parse_logversions, cfg_print_ustring, cfg_doc_terminal, 2366 &cfg_rep_string, logversions_enums 2367}; 2368 2369static cfg_tuplefielddef_t logfile_fields[] = { 2370 { "file", &cfg_type_qstring, 0 }, 2371 { "versions", &cfg_type_logversions, 0 }, 2372 { "size", &cfg_type_size, 0 }, 2373 { NULL, NULL, 0 } 2374}; 2375 2376static isc_result_t 2377parse_logfile(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2378 isc_result_t result; 2379 cfg_obj_t *obj = NULL; 2380 const cfg_tuplefielddef_t *fields = type->of; 2381 2382 CHECK(cfg_create_tuple(pctx, type, &obj)); 2383 2384 /* Parse the mandatory "file" field */ 2385 CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0])); 2386 2387 /* Parse "versions" and "size" fields in any order. */ 2388 for (;;) { 2389 CHECK(cfg_peektoken(pctx, 0)); 2390 if (pctx->token.type == isc_tokentype_string) { 2391 CHECK(cfg_gettoken(pctx, 0)); 2392 if (strcasecmp(TOKEN_STRING(pctx), 2393 "versions") == 0 && 2394 obj->value.tuple[1] == NULL) { 2395 CHECK(cfg_parse_obj(pctx, fields[1].type, 2396 &obj->value.tuple[1])); 2397 } else if (strcasecmp(TOKEN_STRING(pctx), 2398 "size") == 0 && 2399 obj->value.tuple[2] == NULL) { 2400 CHECK(cfg_parse_obj(pctx, fields[2].type, 2401 &obj->value.tuple[2])); 2402 } else { 2403 break; 2404 } 2405 } else { 2406 break; 2407 } 2408 } 2409 2410 /* Create void objects for missing optional values. */ 2411 if (obj->value.tuple[1] == NULL) 2412 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1])); 2413 if (obj->value.tuple[2] == NULL) 2414 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2])); 2415 2416 *ret = obj; 2417 return (ISC_R_SUCCESS); 2418 2419 cleanup: 2420 CLEANUP_OBJ(obj); 2421 return (result); 2422} 2423 2424static void 2425print_logfile(cfg_printer_t *pctx, const cfg_obj_t *obj) { 2426 cfg_print_obj(pctx, obj->value.tuple[0]); /* file */ 2427 if (obj->value.tuple[1]->type->print != cfg_print_void) { 2428 cfg_print_cstr(pctx, " versions "); 2429 cfg_print_obj(pctx, obj->value.tuple[1]); 2430 } 2431 if (obj->value.tuple[2]->type->print != cfg_print_void) { 2432 cfg_print_cstr(pctx, " size "); 2433 cfg_print_obj(pctx, obj->value.tuple[2]); 2434 } 2435} 2436 2437 2438static void 2439doc_logfile(cfg_printer_t *pctx, const cfg_type_t *type) { 2440 UNUSED(type); 2441 cfg_print_cstr(pctx, "<quoted_string>"); 2442 cfg_print_chars(pctx, " ", 1); 2443 cfg_print_cstr(pctx, "[ versions ( \"unlimited\" | <integer> ) ]"); 2444 cfg_print_chars(pctx, " ", 1); 2445 cfg_print_cstr(pctx, "[ size <size> ]"); 2446} 2447 2448cfg_type_t cfg_type_logfile = { 2449 "log_file", parse_logfile, print_logfile, doc_logfile, 2450 &cfg_rep_tuple, logfile_fields 2451}; 2452 2453/*% An IPv4 address with optional port, "*" accepted as wildcard. */ 2454static cfg_type_t cfg_type_sockaddr4wild = { 2455 "sockaddr4wild", cfg_parse_sockaddr, cfg_print_sockaddr, 2456 cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr4wild_flags 2457}; 2458 2459/*% An IPv6 address with optional port, "*" accepted as wildcard. */ 2460static cfg_type_t cfg_type_sockaddr6wild = { 2461 "v6addrportwild", cfg_parse_sockaddr, cfg_print_sockaddr, 2462 cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr6wild_flags 2463}; 2464 2465/*% 2466 * lwres 2467 */ 2468 2469static cfg_tuplefielddef_t lwres_view_fields[] = { 2470 { "name", &cfg_type_astring, 0 }, 2471 { "class", &cfg_type_optional_class, 0 }, 2472 { NULL, NULL, 0 } 2473}; 2474static cfg_type_t cfg_type_lwres_view = { 2475 "lwres_view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, 2476 lwres_view_fields 2477}; 2478 2479static cfg_type_t cfg_type_lwres_searchlist = { 2480 "lwres_searchlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, 2481 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring }; 2482 2483static cfg_clausedef_t 2484lwres_clauses[] = { 2485 { "listen-on", &cfg_type_portiplist, 0 }, 2486 { "view", &cfg_type_lwres_view, 0 }, 2487 { "search", &cfg_type_lwres_searchlist, 0 }, 2488 { "ndots", &cfg_type_uint32, 0 }, 2489 { NULL, NULL, 0 } 2490}; 2491 2492static cfg_clausedef_t * 2493lwres_clausesets[] = { 2494 lwres_clauses, 2495 NULL 2496}; 2497static cfg_type_t cfg_type_lwres = { 2498 "lwres", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, 2499 lwres_clausesets 2500}; 2501 2502/*% 2503 * rndc 2504 */ 2505 2506static cfg_clausedef_t 2507rndcconf_options_clauses[] = { 2508 { "default-key", &cfg_type_astring, 0 }, 2509 { "default-port", &cfg_type_uint32, 0 }, 2510 { "default-server", &cfg_type_astring, 0 }, 2511 { "default-source-address", &cfg_type_netaddr4wild, 0 }, 2512 { "default-source-address-v6", &cfg_type_netaddr6wild, 0 }, 2513 { NULL, NULL, 0 } 2514}; 2515 2516static cfg_clausedef_t * 2517rndcconf_options_clausesets[] = { 2518 rndcconf_options_clauses, 2519 NULL 2520}; 2521 2522static cfg_type_t cfg_type_rndcconf_options = { 2523 "rndcconf_options", cfg_parse_map, cfg_print_map, cfg_doc_map, 2524 &cfg_rep_map, rndcconf_options_clausesets 2525}; 2526 2527static cfg_clausedef_t 2528rndcconf_server_clauses[] = { 2529 { "key", &cfg_type_astring, 0 }, 2530 { "port", &cfg_type_uint32, 0 }, 2531 { "source-address", &cfg_type_netaddr4wild, 0 }, 2532 { "source-address-v6", &cfg_type_netaddr6wild, 0 }, 2533 { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 }, 2534 { NULL, NULL, 0 } 2535}; 2536 2537static cfg_clausedef_t * 2538rndcconf_server_clausesets[] = { 2539 rndcconf_server_clauses, 2540 NULL 2541}; 2542 2543static cfg_type_t cfg_type_rndcconf_server = { 2544 "rndcconf_server", cfg_parse_named_map, cfg_print_map, cfg_doc_map, 2545 &cfg_rep_map, rndcconf_server_clausesets 2546}; 2547 2548static cfg_clausedef_t 2549rndcconf_clauses[] = { 2550 { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI }, 2551 { "server", &cfg_type_rndcconf_server, CFG_CLAUSEFLAG_MULTI }, 2552 { "options", &cfg_type_rndcconf_options, 0 }, 2553 { NULL, NULL, 0 } 2554}; 2555 2556static cfg_clausedef_t * 2557rndcconf_clausesets[] = { 2558 rndcconf_clauses, 2559 NULL 2560}; 2561 2562LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndcconf = { 2563 "rndcconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, 2564 &cfg_rep_map, rndcconf_clausesets 2565}; 2566 2567static cfg_clausedef_t 2568rndckey_clauses[] = { 2569 { "key", &cfg_type_key, 0 }, 2570 { NULL, NULL, 0 } 2571}; 2572 2573static cfg_clausedef_t * 2574rndckey_clausesets[] = { 2575 rndckey_clauses, 2576 NULL 2577}; 2578 2579LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndckey = { 2580 "rndckey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, 2581 &cfg_rep_map, rndckey_clausesets 2582}; 2583 2584/* 2585 * session.key has exactly the same syntax as rndc.key, but it's defined 2586 * separately for clarity (and so we can extend it someday, if needed). 2587 */ 2588LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sessionkey = { 2589 "sessionkey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, 2590 &cfg_rep_map, rndckey_clausesets 2591}; 2592 2593static cfg_tuplefielddef_t nameport_fields[] = { 2594 { "name", &cfg_type_astring, 0 }, 2595 { "port", &cfg_type_optional_port, 0 }, 2596 { NULL, NULL, 0 } 2597}; 2598static cfg_type_t cfg_type_nameport = { 2599 "nameport", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 2600 &cfg_rep_tuple, nameport_fields 2601}; 2602 2603static void 2604doc_sockaddrnameport(cfg_printer_t *pctx, const cfg_type_t *type) { 2605 UNUSED(type); 2606 cfg_print_chars(pctx, "( ", 2); 2607 cfg_print_cstr(pctx, "<quoted_string>"); 2608 cfg_print_chars(pctx, " ", 1); 2609 cfg_print_cstr(pctx, "[ port <integer> ]"); 2610 cfg_print_chars(pctx, " | ", 3); 2611 cfg_print_cstr(pctx, "<ipv4_address>"); 2612 cfg_print_chars(pctx, " ", 1); 2613 cfg_print_cstr(pctx, "[ port <integer> ]"); 2614 cfg_print_chars(pctx, " | ", 3); 2615 cfg_print_cstr(pctx, "<ipv6_address>"); 2616 cfg_print_chars(pctx, " ", 1); 2617 cfg_print_cstr(pctx, "[ port <integer> ]"); 2618 cfg_print_chars(pctx, " )", 2); 2619} 2620 2621static isc_result_t 2622parse_sockaddrnameport(cfg_parser_t *pctx, const cfg_type_t *type, 2623 cfg_obj_t **ret) 2624{ 2625 isc_result_t result; 2626 cfg_obj_t *obj = NULL; 2627 UNUSED(type); 2628 2629 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); 2630 if (pctx->token.type == isc_tokentype_string || 2631 pctx->token.type == isc_tokentype_qstring) { 2632 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK)) 2633 CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, ret)); 2634 else { 2635 const cfg_tuplefielddef_t *fields = 2636 cfg_type_nameport.of; 2637 CHECK(cfg_create_tuple(pctx, &cfg_type_nameport, 2638 &obj)); 2639 CHECK(cfg_parse_obj(pctx, fields[0].type, 2640 &obj->value.tuple[0])); 2641 CHECK(cfg_parse_obj(pctx, fields[1].type, 2642 &obj->value.tuple[1])); 2643 *ret = obj; 2644 obj = NULL; 2645 } 2646 } else { 2647 cfg_parser_error(pctx, CFG_LOG_NEAR, 2648 "expected IP address or hostname"); 2649 return (ISC_R_UNEXPECTEDTOKEN); 2650 } 2651 cleanup: 2652 CLEANUP_OBJ(obj); 2653 return (result); 2654} 2655 2656static cfg_type_t cfg_type_sockaddrnameport = { 2657 "sockaddrnameport_element", parse_sockaddrnameport, NULL, 2658 doc_sockaddrnameport, NULL, NULL 2659}; 2660 2661static cfg_type_t cfg_type_bracketed_sockaddrnameportlist = { 2662 "bracketed_sockaddrnameportlist", cfg_parse_bracketed_list, 2663 cfg_print_bracketed_list, cfg_doc_bracketed_list, 2664 &cfg_rep_list, &cfg_type_sockaddrnameport 2665}; 2666 2667/*% 2668 * A list of socket addresses or name with an optional default port, 2669 * as used in the dual-stack-servers option. E.g., 2670 * "port 1234 { dual-stack-servers.net; 10.0.0.1; 1::2 port 69; }" 2671 */ 2672static cfg_tuplefielddef_t nameportiplist_fields[] = { 2673 { "port", &cfg_type_optional_port, 0 }, 2674 { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 }, 2675 { NULL, NULL, 0 } 2676}; 2677 2678static cfg_type_t cfg_type_nameportiplist = { 2679 "nameportiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, 2680 &cfg_rep_tuple, nameportiplist_fields 2681}; 2682 2683/*% 2684 * masters element. 2685 */ 2686 2687static void 2688doc_masterselement(cfg_printer_t *pctx, const cfg_type_t *type) { 2689 UNUSED(type); 2690 cfg_print_chars(pctx, "( ", 2); 2691 cfg_print_cstr(pctx, "<masters>"); 2692 cfg_print_chars(pctx, " | ", 3); 2693 cfg_print_cstr(pctx, "<ipv4_address>"); 2694 cfg_print_chars(pctx, " ", 1); 2695 cfg_print_cstr(pctx, "[ port <integer> ]"); 2696 cfg_print_chars(pctx, " | ", 3); 2697 cfg_print_cstr(pctx, "<ipv6_address>"); 2698 cfg_print_chars(pctx, " ", 1); 2699 cfg_print_cstr(pctx, "[ port <integer> ]"); 2700 cfg_print_chars(pctx, " )", 2); 2701} 2702 2703static isc_result_t 2704parse_masterselement(cfg_parser_t *pctx, const cfg_type_t *type, 2705 cfg_obj_t **ret) 2706{ 2707 isc_result_t result; 2708 cfg_obj_t *obj = NULL; 2709 UNUSED(type); 2710 2711 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); 2712 if (pctx->token.type == isc_tokentype_string || 2713 pctx->token.type == isc_tokentype_qstring) { 2714 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK)) 2715 CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, ret)); 2716 else 2717 CHECK(cfg_parse_astring(pctx, &cfg_type_astring, ret)); 2718 } else { 2719 cfg_parser_error(pctx, CFG_LOG_NEAR, 2720 "expected IP address or masters name"); 2721 return (ISC_R_UNEXPECTEDTOKEN); 2722 } 2723 cleanup: 2724 CLEANUP_OBJ(obj); 2725 return (result); 2726} 2727 2728static cfg_type_t cfg_type_masterselement = { 2729 "masters_element", parse_masterselement, NULL, 2730 doc_masterselement, NULL, NULL 2731}; 2732