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