PageRenderTime 149ms CodeModel.GetById 35ms app.highlight 102ms RepoModel.GetById 0ms app.codeStats 1ms

/contrib/bind9/lib/isccfg/namedconf.c

https://bitbucket.org/freebsd/freebsd-head/
C | 2741 lines | 2107 code | 353 blank | 281 comment | 168 complexity | 34ffe94fa630a73157ebddc734461e61 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
   3 * Copyright (C) 2002, 2003  Internet Software Consortium.
   4 *
   5 * Permission to use, copy, modify, and/or distribute this software for any
   6 * purpose with or without fee is hereby granted, provided that the above
   7 * copyright notice and this permission notice appear in all copies.
   8 *
   9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  15 * PERFORMANCE OF THIS SOFTWARE.
  16 */
  17
  18/* $Id$ */
  19
  20/*! \file */
  21
  22#include <config.h>
  23
  24#include <string.h>
  25
  26#include <isc/lex.h>
  27#include <isc/mem.h>
  28#include <isc/result.h>
  29#include <isc/string.h>
  30#include <isc/util.h>
  31
  32#include <isccfg/cfg.h>
  33#include <isccfg/grammar.h>
  34#include <isccfg/log.h>
  35
  36#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
  37
  38/*% Check a return value. */
  39#define CHECK(op)						\
  40	do { result = (op);					\
  41		if (result != ISC_R_SUCCESS) goto cleanup;	\
  42	} while (0)
  43
  44/*% Clean up a configuration object if non-NULL. */
  45#define CLEANUP_OBJ(obj) \
  46	do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
  47
  48
  49/*%
  50 * Forward declarations of static functions.
  51 */
  52
  53static isc_result_t
  54parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
  55		    const cfg_type_t *othertype, cfg_obj_t **ret);
  56
  57static isc_result_t
  58parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
  59
  60static isc_result_t
  61parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
  62			cfg_obj_t **ret);
  63
  64static isc_result_t
  65parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
  66		   cfg_obj_t **ret);
  67static void
  68print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj);
  69
  70static void
  71doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type);
  72
  73static void
  74print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj);
  75
  76static void
  77doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
  78
  79static void
  80doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
  81
  82static cfg_type_t cfg_type_acl;
  83static cfg_type_t cfg_type_addrmatchelt;
  84static cfg_type_t cfg_type_bracketed_aml;
  85static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
  86static cfg_type_t cfg_type_bracketed_sockaddrlist;
  87static cfg_type_t cfg_type_bracketed_sockaddrnameportlist;
  88static cfg_type_t cfg_type_controls;
  89static cfg_type_t cfg_type_controls_sockaddr;
  90static cfg_type_t cfg_type_destinationlist;
  91static cfg_type_t cfg_type_dialuptype;
  92static cfg_type_t cfg_type_ixfrdifftype;
  93static cfg_type_t cfg_type_key;
  94static cfg_type_t cfg_type_logfile;
  95static cfg_type_t cfg_type_logging;
  96static cfg_type_t cfg_type_logseverity;
  97static cfg_type_t cfg_type_lwres;
  98static cfg_type_t cfg_type_masterselement;
  99static cfg_type_t cfg_type_nameportiplist;
 100static cfg_type_t cfg_type_negated;
 101static cfg_type_t cfg_type_notifytype;
 102static cfg_type_t cfg_type_optional_allow;
 103static cfg_type_t cfg_type_optional_class;
 104static cfg_type_t cfg_type_optional_facility;
 105static cfg_type_t cfg_type_optional_keyref;
 106static cfg_type_t cfg_type_optional_port;
 107static cfg_type_t cfg_type_options;
 108static cfg_type_t cfg_type_portiplist;
 109static cfg_type_t cfg_type_querysource4;
 110static cfg_type_t cfg_type_querysource6;
 111static cfg_type_t cfg_type_querysource;
 112static cfg_type_t cfg_type_server;
 113static cfg_type_t cfg_type_server_key_kludge;
 114static cfg_type_t cfg_type_size;
 115static cfg_type_t cfg_type_sizenodefault;
 116static cfg_type_t cfg_type_sockaddr4wild;
 117static cfg_type_t cfg_type_sockaddr6wild;
 118static cfg_type_t cfg_type_statschannels;
 119static cfg_type_t cfg_type_view;
 120static cfg_type_t cfg_type_viewopts;
 121static cfg_type_t cfg_type_zone;
 122static cfg_type_t cfg_type_zoneopts;
 123static cfg_type_t cfg_type_dynamically_loadable_zones;
 124static cfg_type_t cfg_type_dynamically_loadable_zones_opts;
 125static cfg_type_t cfg_type_v4_aaaa;
 126
 127/*
 128 * Clauses that can be found in a 'dynamically loadable zones' statement
 129 */
 130static cfg_clausedef_t
 131dynamically_loadable_zones_clauses[] = {
 132	{ "database", &cfg_type_astring, 0 },
 133	{ NULL, NULL, 0 }
 134};
 135
 136/*
 137 * A dynamically loadable zones statement.
 138 */
 139static cfg_tuplefielddef_t dynamically_loadable_zones_fields[] = {
 140	{ "name", &cfg_type_astring, 0 },
 141	{ "options", &cfg_type_dynamically_loadable_zones_opts, 0 },
 142	{ NULL, NULL, 0 }
 143};
 144
 145static cfg_type_t cfg_type_dynamically_loadable_zones = {
 146	"dlz", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
 147	&cfg_rep_tuple,
 148	dynamically_loadable_zones_fields
 149	};
 150
 151
 152/*% tkey-dhkey */
 153
 154static cfg_tuplefielddef_t tkey_dhkey_fields[] = {
 155	{ "name", &cfg_type_qstring, 0 },
 156	{ "keyid", &cfg_type_uint32, 0 },
 157	{ NULL, NULL, 0 }
 158};
 159
 160static cfg_type_t cfg_type_tkey_dhkey = {
 161	"tkey-dhkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
 162	tkey_dhkey_fields
 163};
 164
 165/*% listen-on */
 166
 167static cfg_tuplefielddef_t listenon_fields[] = {
 168	{ "port", &cfg_type_optional_port, 0 },
 169	{ "acl", &cfg_type_bracketed_aml, 0 },
 170	{ NULL, NULL, 0 }
 171};
 172static cfg_type_t cfg_type_listenon = {
 173	"listenon", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, listenon_fields };
 174
 175/*% acl */
 176
 177static cfg_tuplefielddef_t acl_fields[] = {
 178	{ "name", &cfg_type_astring, 0 },
 179	{ "value", &cfg_type_bracketed_aml, 0 },
 180	{ NULL, NULL, 0 }
 181};
 182
 183static cfg_type_t cfg_type_acl = {
 184	"acl", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, acl_fields };
 185
 186/*% masters */
 187static cfg_tuplefielddef_t masters_fields[] = {
 188	{ "name", &cfg_type_astring, 0 },
 189	{ "port", &cfg_type_optional_port, 0 },
 190	{ "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
 191	{ NULL, NULL, 0 }
 192};
 193
 194static cfg_type_t cfg_type_masters = {
 195	"masters", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, masters_fields };
 196
 197/*%
 198 * "sockaddrkeylist", a list of socket addresses with optional keys
 199 * and an optional default port, as used in the masters option.
 200 * E.g.,
 201 *   "port 1234 { mymasters; 10.0.0.1 key foo; 1::2 port 69; }"
 202 */
 203
 204static cfg_tuplefielddef_t namesockaddrkey_fields[] = {
 205	{ "masterselement", &cfg_type_masterselement, 0 },
 206	{ "key", &cfg_type_optional_keyref, 0 },
 207	{ NULL, NULL, 0 },
 208};
 209
 210static cfg_type_t cfg_type_namesockaddrkey = {
 211	"namesockaddrkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
 212	namesockaddrkey_fields
 213};
 214
 215static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = {
 216	"bracketed_namesockaddrkeylist", cfg_parse_bracketed_list,
 217	cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_namesockaddrkey
 218};
 219
 220static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = {
 221	{ "port", &cfg_type_optional_port, 0 },
 222	{ "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
 223	{ NULL, NULL, 0 }
 224};
 225static 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,
 232 * as used in the also-notify option.  E.g.,
 233 * "port 1234 { 10.0.0.1; 1::2 port 69; }"
 234 */
 235static cfg_tuplefielddef_t portiplist_fields[] = {
 236	{ "port", &cfg_type_optional_port, 0 },
 237	{ "addresses", &cfg_type_bracketed_sockaddrlist, 0 },
 238	{ NULL, NULL, 0 }
 239};
 240static cfg_type_t cfg_type_portiplist = {
 241	"portiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
 242	portiplist_fields
 243};
 244
 245/*%
 246 * A public key, as in the "pubkey" statement.
 247 */
 248static 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};
 255static 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 */
 263static 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
 268static const char *mode_enums[] = { "grant", "deny", NULL };
 269static 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
 274static isc_result_t
 275parse_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
 290static isc_result_t
 291parse_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
 306static void
 307doc_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
 313static 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
 318static cfg_type_t cfg_type_matchtype = {
 319	"matchtype", parse_matchtype, cfg_print_ustring,
 320	cfg_doc_enum, &cfg_rep_string, &matchtype_enums
 321};
 322
 323static 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 */
 331static 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};
 339static 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
 344static cfg_type_t cfg_type_updatepolicy = {
 345	"update_policy", parse_updatepolicy, print_updatepolicy,
 346	doc_updatepolicy, &cfg_rep_list, &cfg_type_grant
 347};
 348
 349static isc_result_t
 350parse_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		memcpy(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
 384static void
 385print_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
 392static void
 393doc_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 */
 402static 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};
 408static 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 */
 416static 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};
 422static 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 */
 430static cfg_tuplefielddef_t category_fields[] = {
 431	{ "name", &cfg_type_astring, 0 },
 432	{ "destinations", &cfg_type_destinationlist,0 },
 433	{ NULL, NULL, 0 }
 434};
 435static 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 */
 444static 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};
 452static 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 */
 461static 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};
 470static 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
 475static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring };
 476
 477static 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
 482static keyword_type_t wild_type_kw = { "type", &cfg_type_ustring };
 483
 484static 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
 489static keyword_type_t wild_name_kw = { "name", &cfg_type_qstring };
 490
 491static 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 */
 499static 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};
 507static 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
 517static const char *checktype_enums[] = { "master", "slave", "response", NULL };
 518static 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
 523static const char *checkmode_enums[] = { "fail", "warn", "ignore", NULL };
 524static 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
 529static cfg_tuplefielddef_t checknames_fields[] = {
 530	{ "type", &cfg_type_checktype, 0 },
 531	{ "mode", &cfg_type_checkmode, 0 },
 532	{ NULL, NULL, 0 }
 533};
 534
 535static cfg_type_t cfg_type_checknames = {
 536	"checknames", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
 537	checknames_fields
 538};
 539
 540static cfg_type_t cfg_type_bracketed_sockaddrlist = {
 541	"bracketed_sockaddrlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
 542	&cfg_rep_list, &cfg_type_sockaddr
 543};
 544
 545static const char *autodnssec_enums[] = { "allow", "maintain", "off", NULL };
 546static cfg_type_t cfg_type_autodnssec = {
 547	"autodnssec", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
 548	&cfg_rep_string, &autodnssec_enums
 549};
 550
 551static cfg_type_t cfg_type_rrsetorder = {
 552	"rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
 553	&cfg_rep_list, &cfg_type_rrsetorderingelement
 554};
 555
 556static keyword_type_t port_kw = { "port", &cfg_type_uint32 };
 557
 558static cfg_type_t cfg_type_optional_port = {
 559	"optional_port", parse_optional_keyvalue, print_keyvalue,
 560	doc_optional_keyvalue, &cfg_rep_uint32, &port_kw
 561};
 562
 563/*% A list of keys, as in the "key" clause of the controls statement. */
 564static cfg_type_t cfg_type_keylist = {
 565	"keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
 566	cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring
 567};
 568
 569/*% A list of dnssec keys, as in "trusted-keys" */
 570static cfg_type_t cfg_type_dnsseckeys = {
 571	"dnsseckeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
 572	cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_dnsseckey
 573};
 574
 575/*%
 576 * A list of managed key entries, as in "trusted-keys".  Currently
 577 * (9.7.0) this has a format similar to dnssec keys, except the keyname
 578 * is followed by the keyword "initial-key".  In future releases, this
 579 * keyword may take other values indicating different methods for the
 580 * key to be initialized.
 581 */
 582
 583static cfg_type_t cfg_type_managedkeys = {
 584	"managedkeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
 585	cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_managedkey
 586};
 587
 588static const char *forwardtype_enums[] = { "first", "only", NULL };
 589static cfg_type_t cfg_type_forwardtype = {
 590	"forwardtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
 591	&forwardtype_enums
 592};
 593
 594static const char *zonetype_enums[] = {
 595	"master", "slave", "stub", "static-stub", "hint", "forward",
 596	"delegation-only", NULL };
 597static cfg_type_t cfg_type_zonetype = {
 598	"zonetype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
 599	&cfg_rep_string, &zonetype_enums
 600};
 601
 602static const char *loglevel_enums[] = {
 603	"critical", "error", "warning", "notice", "info", "dynamic", NULL };
 604static cfg_type_t cfg_type_loglevel = {
 605	"loglevel", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
 606	&loglevel_enums
 607};
 608
 609static const char *transferformat_enums[] = {
 610	"many-answers", "one-answer", NULL };
 611static cfg_type_t cfg_type_transferformat = {
 612	"transferformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
 613	&transferformat_enums
 614};
 615
 616/*%
 617 * The special keyword "none", as used in the pid-file option.
 618 */
 619
 620static void
 621print_none(cfg_printer_t *pctx, const cfg_obj_t *obj) {
 622	UNUSED(obj);
 623	cfg_print_cstr(pctx, "none");
 624}
 625
 626static cfg_type_t cfg_type_none = {
 627	"none", NULL, print_none, NULL, &cfg_rep_void, NULL
 628};
 629
 630/*%
 631 * A quoted string or the special keyword "none".  Used in the pid-file option.
 632 */
 633static isc_result_t
 634parse_qstringornone(cfg_parser_t *pctx, const cfg_type_t *type,
 635		    cfg_obj_t **ret)
 636{
 637	isc_result_t result;
 638
 639	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
 640	if (pctx->token.type == isc_tokentype_string &&
 641	    strcasecmp(TOKEN_STRING(pctx), "none") == 0)
 642		return (cfg_create_obj(pctx, &cfg_type_none, ret));
 643	cfg_ungettoken(pctx);
 644	return (cfg_parse_qstring(pctx, type, ret));
 645 cleanup:
 646	return (result);
 647}
 648
 649static void
 650doc_qstringornone(cfg_printer_t *pctx, const cfg_type_t *type) {
 651	UNUSED(type);
 652	cfg_print_cstr(pctx, "( <quoted_string> | none )");
 653}
 654
 655static cfg_type_t cfg_type_qstringornone = {
 656	"qstringornone", parse_qstringornone, NULL, doc_qstringornone,
 657	NULL, NULL
 658};
 659
 660/*%
 661 * A boolean ("yes" or "no"), or the special keyword "auto".
 662 * Used in the dnssec-validation option.
 663 */
 664static void
 665print_auto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
 666	UNUSED(obj);
 667	cfg_print_cstr(pctx, "auto");
 668}
 669
 670static cfg_type_t cfg_type_auto = {
 671	"auto", NULL, print_auto, NULL, &cfg_rep_void, NULL
 672};
 673
 674static isc_result_t
 675parse_boolorauto(cfg_parser_t *pctx, const cfg_type_t *type,
 676		    cfg_obj_t **ret)
 677{
 678	isc_result_t result;
 679
 680	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
 681	if (pctx->token.type == isc_tokentype_string &&
 682	    strcasecmp(TOKEN_STRING(pctx), "auto") == 0)
 683		return (cfg_create_obj(pctx, &cfg_type_auto, ret));
 684	cfg_ungettoken(pctx);
 685	return (cfg_parse_boolean(pctx, type, ret));
 686 cleanup:
 687	return (result);
 688}
 689
 690static void
 691print_boolorauto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
 692	if (obj->type->rep == &cfg_rep_void)
 693		cfg_print_chars(pctx, "auto", 4);
 694	else if (obj->value.boolean)
 695		cfg_print_chars(pctx, "yes", 3);
 696	else
 697		cfg_print_chars(pctx, "no", 2);
 698}
 699
 700static void
 701doc_boolorauto(cfg_printer_t *pctx, const cfg_type_t *type) {
 702	UNUSED(type);
 703	cfg_print_cstr(pctx, "( yes | no | auto )");
 704}
 705
 706static cfg_type_t cfg_type_boolorauto = {
 707	"boolorauto", parse_boolorauto, print_boolorauto,
 708	doc_boolorauto, NULL, NULL
 709};
 710
 711/*%
 712 * keyword hostname
 713 */
 714static void
 715print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) {
 716	UNUSED(obj);
 717	cfg_print_cstr(pctx, "hostname");
 718}
 719
 720static cfg_type_t cfg_type_hostname = {
 721	"hostname", NULL, print_hostname, NULL, &cfg_rep_boolean, NULL
 722};
 723
 724/*%
 725 * "server-id" argument.
 726 */
 727
 728static isc_result_t
 729parse_serverid(cfg_parser_t *pctx, const cfg_type_t *type,
 730		    cfg_obj_t **ret)
 731{
 732	isc_result_t result;
 733	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
 734	if (pctx->token.type == isc_tokentype_string &&
 735	    strcasecmp(TOKEN_STRING(pctx), "none") == 0)
 736		return (cfg_create_obj(pctx, &cfg_type_none, ret));
 737	if (pctx->token.type == isc_tokentype_string &&
 738	    strcasecmp(TOKEN_STRING(pctx), "hostname") == 0) {
 739		return (cfg_create_obj(pctx, &cfg_type_hostname, ret));
 740	}
 741	cfg_ungettoken(pctx);
 742	return (cfg_parse_qstring(pctx, type, ret));
 743 cleanup:
 744	return (result);
 745}
 746
 747static void
 748doc_serverid(cfg_printer_t *pctx, const cfg_type_t *type) {
 749	UNUSED(type);
 750	cfg_print_cstr(pctx, "( <quoted_string> | none | hostname )");
 751}
 752
 753static cfg_type_t cfg_type_serverid = {
 754	"serverid", parse_serverid, NULL, doc_serverid, NULL, NULL };
 755
 756/*%
 757 * Port list.
 758 */
 759static cfg_tuplefielddef_t porttuple_fields[] = {
 760	{ "loport", &cfg_type_uint32, 0 },
 761	{ "hiport", &cfg_type_uint32, 0 },
 762	{ NULL, NULL, 0 }
 763};
 764static cfg_type_t cfg_type_porttuple = {
 765	"porttuple", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
 766	&cfg_rep_tuple, porttuple_fields
 767};
 768
 769static isc_result_t
 770parse_port(cfg_parser_t *pctx, cfg_obj_t **ret) {
 771	isc_result_t result;
 772
 773	CHECK(cfg_parse_uint32(pctx, NULL, ret));
 774	if ((*ret)->value.uint32 > 0xffff) {
 775		cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid port");
 776		cfg_obj_destroy(pctx, ret);
 777		result = ISC_R_RANGE;
 778	}
 779
 780 cleanup:
 781	return (result);
 782}
 783
 784static isc_result_t
 785parse_portrange(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
 786	isc_result_t result;
 787	cfg_obj_t *obj = NULL;
 788
 789	UNUSED(type);
 790
 791	CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
 792	if (pctx->token.type == isc_tokentype_number)
 793		CHECK(parse_port(pctx, ret));
 794	else {
 795		CHECK(cfg_gettoken(pctx, 0));
 796		if (pctx->token.type != isc_tokentype_string ||
 797		    strcasecmp(TOKEN_STRING(pctx), "range") != 0) {
 798			cfg_parser_error(pctx, CFG_LOG_NEAR,
 799					 "expected integer or 'range'");
 800			return (ISC_R_UNEXPECTEDTOKEN);
 801		}
 802		CHECK(cfg_create_tuple(pctx, &cfg_type_porttuple, &obj));
 803		CHECK(parse_port(pctx, &obj->value.tuple[0]));
 804		CHECK(parse_port(pctx, &obj->value.tuple[1]));
 805		if (obj->value.tuple[0]->value.uint32 >
 806		    obj->value.tuple[1]->value.uint32) {
 807			cfg_parser_error(pctx, CFG_LOG_NOPREP,
 808					 "low port '%u' must not be larger "
 809					 "than high port",
 810					 obj->value.tuple[0]->value.uint32);
 811			result = ISC_R_RANGE;
 812			goto cleanup;
 813		}
 814		*ret = obj;
 815		obj = NULL;
 816	}
 817
 818 cleanup:
 819	if (obj != NULL)
 820		cfg_obj_destroy(pctx, &obj);
 821	return (result);
 822}
 823
 824static cfg_type_t cfg_type_portrange = {
 825	"portrange", parse_portrange, NULL, cfg_doc_terminal,
 826	NULL, NULL
 827};
 828
 829static cfg_type_t cfg_type_bracketed_portlist = {
 830	"bracketed_sockaddrlist", cfg_parse_bracketed_list,
 831	cfg_print_bracketed_list, cfg_doc_bracketed_list,
 832	&cfg_rep_list, &cfg_type_portrange
 833};
 834
 835/*%
 836 * Clauses that can be found within the top level of the named.conf
 837 * file only.
 838 */
 839static cfg_clausedef_t
 840namedconf_clauses[] = {
 841	{ "options", &cfg_type_options, 0 },
 842	{ "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
 843	{ "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
 844	{ "masters", &cfg_type_masters, CFG_CLAUSEFLAG_MULTI },
 845	{ "logging", &cfg_type_logging, 0 },
 846	{ "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI },
 847	{ "lwres", &cfg_type_lwres, CFG_CLAUSEFLAG_MULTI },
 848	{ "statistics-channels", &cfg_type_statschannels,
 849	  CFG_CLAUSEFLAG_MULTI },
 850	{ NULL, NULL, 0 }
 851};
 852
 853/*%
 854 * Clauses that can occur at the top level or in the view
 855 * statement, but not in the options block.
 856 */
 857static cfg_clausedef_t
 858namedconf_or_view_clauses[] = {
 859	{ "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
 860	{ "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
 861	/* only 1 DLZ per view allowed */
 862	{ "dlz", &cfg_type_dynamically_loadable_zones, 0 },
 863	{ "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI },
 864	{ "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
 865	{ "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
 866	{ NULL, NULL, 0 }
 867};
 868
 869/*%
 870 * Clauses that can occur in the bind.keys file.
 871 */
 872static cfg_clausedef_t
 873bindkeys_clauses[] = {
 874	{ "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
 875	{ "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
 876	{ NULL, NULL, 0 }
 877};
 878
 879/*%
 880 * Clauses that can be found within the 'options' statement.
 881 */
 882static cfg_clausedef_t
 883options_clauses[] = {
 884	{ "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
 885	{ "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
 886	{ "bindkeys-file", &cfg_type_qstring, 0 },
 887	{ "blackhole", &cfg_type_bracketed_aml, 0 },
 888	{ "coresize", &cfg_type_size, 0 },
 889	{ "datasize", &cfg_type_size, 0 },
 890	{ "session-keyfile", &cfg_type_qstringornone, 0 },
 891	{ "session-keyname", &cfg_type_astring, 0 },
 892	{ "session-keyalg", &cfg_type_astring, 0 },
 893	{ "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
 894	{ "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK },
 895	{ "dump-file", &cfg_type_qstring, 0 },
 896	{ "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
 897	{ "files", &cfg_type_size, 0 },
 898	{ "flush-zones-on-shutdown", &cfg_type_boolean, 0 },
 899	{ "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
 900	{ "heartbeat-interval", &cfg_type_uint32, 0 },
 901	{ "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP },
 902	{ "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
 903	{ "hostname", &cfg_type_qstringornone, 0 },
 904	{ "interface-interval", &cfg_type_uint32, 0 },
 905	{ "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
 906	{ "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
 907	{ "managed-keys-directory", &cfg_type_qstring, 0 },
 908	{ "match-mapped-addresses", &cfg_type_boolean, 0 },
 909	{ "memstatistics-file", &cfg_type_qstring, 0 },
 910	{ "memstatistics", &cfg_type_boolean, 0 },
 911	{ "multiple-cnames", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
 912	{ "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
 913	{ "pid-file", &cfg_type_qstringornone, 0 },
 914	{ "port", &cfg_type_uint32, 0 },
 915	{ "querylog", &cfg_type_boolean, 0 },
 916	{ "recursing-file", &cfg_type_qstring, 0 },
 917	{ "random-device", &cfg_type_qstring, 0 },
 918	{ "recursive-clients", &cfg_type_uint32, 0 },
 919	{ "reserved-sockets", &cfg_type_uint32, 0 },
 920	{ "secroots-file", &cfg_type_qstring, 0 },
 921	{ "serial-queries", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
 922	{ "serial-query-rate", &cfg_type_uint32, 0 },
 923	{ "server-id", &cfg_type_serverid, 0 },
 924	{ "stacksize", &cfg_type_size, 0 },
 925	{ "statistics-file", &cfg_type_qstring, 0 },
 926	{ "statistics-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_NYI },
 927	{ "tcp-clients", &cfg_type_uint32, 0 },
 928	{ "tcp-listen-queue", &cfg_type_uint32, 0 },
 929	{ "tkey-dhkey", &cfg_type_tkey_dhkey, 0 },
 930	{ "tkey-gssapi-credential", &cfg_type_qstring, 0 },
 931	{ "tkey-gssapi-keytab", &cfg_type_qstring, 0 },
 932	{ "tkey-domain", &cfg_type_qstring, 0 },
 933	{ "transfers-per-ns", &cfg_type_uint32, 0 },
 934	{ "transfers-in", &cfg_type_uint32, 0 },
 935	{ "transfers-out", &cfg_type_uint32, 0 },
 936	{ "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
 937	{ "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
 938	{ "use-ixfr", &cfg_type_boolean, 0 },
 939	{ "use-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
 940	{ "use-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
 941	{ "version", &cfg_type_qstringornone, 0 },
 942	{ NULL, NULL, 0 }
 943};
 944
 945static cfg_type_t cfg_type_namelist = {
 946	"namelist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
 947	cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_qstring };
 948
 949static keyword_type_t exclude_kw = { "exclude", &cfg_type_namelist };
 950
 951static cfg_type_t cfg_type_optional_exclude = {
 952	"optional_exclude", parse_optional_keyvalue, print_keyvalue,
 953	doc_optional_keyvalue, &cfg_rep_list, &exclude_kw };
 954
 955static keyword_type_t exceptionnames_kw = { "except-from", &cfg_type_namelist };
 956
 957static cfg_type_t cfg_type_optional_exceptionnames = {
 958	"optional_allow", parse_optional_keyvalue, print_keyvalue,
 959	doc_optional_keyvalue, &cfg_rep_list, &exceptionnames_kw };
 960
 961static cfg_tuplefielddef_t denyaddresses_fields[] = {
 962	{ "acl", &cfg_type_bracketed_aml, 0 },
 963	{ "except-from", &cfg_type_optional_exceptionnames, 0 },
 964	{ NULL, NULL, 0 }
 965};
 966
 967static cfg_type_t cfg_type_denyaddresses = {
 968	"denyaddresses", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
 969	&cfg_rep_tuple, denyaddresses_fields
 970};
 971
 972static cfg_tuplefielddef_t denyaliases_fields[] = {
 973	{ "name", &cfg_type_namelist, 0 },
 974	{ "except-from", &cfg_type_optional_exceptionnames, 0 },
 975	{ NULL, NULL, 0 }
 976};
 977
 978static cfg_type_t cfg_type_denyaliases = {
 979	"denyaliases", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
 980	&cfg_rep_tuple, denyaliases_fields
 981};
 982
 983static cfg_type_t cfg_type_algorithmlist = {
 984	"algorithmlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
 985	cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring };
 986
 987static cfg_tuplefielddef_t disablealgorithm_fields[] = {
 988	{ "name", &cfg_type_astring, 0 },
 989	{ "algorithms", &cfg_type_algorithmlist, 0 },
 990	{ NULL, NULL, 0 }
 991};
 992
 993static cfg_type_t cfg_type_disablealgorithm = {
 994	"disablealgorithm", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
 995	&cfg_rep_tuple, disablealgorithm_fields
 996};
 997
 998static cfg_tuplefielddef_t mustbesecure_fields[] = {
 999	{ "name", &cfg_type_astring, 0 },
1000	{ "value", &cfg_type_boolean, 0 },
1001	{ NULL, NULL, 0 }
1002};
1003
1004static cfg_type_t cfg_type_mustbesecure = {
1005	"mustbesecure", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
1006	&cfg_rep_tuple, mustbesecure_fields
1007};
1008
1009static const char *masterformat_enums[] = { "text", "raw", NULL };
1010static cfg_type_t cfg_type_masterformat = {
1011	"masterformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
1012	&cfg_rep_string, &masterformat_enums
1013};
1014
1015
1016
1017/*
1018 *  response-policy {
1019 *	zone <string> [ policy (given|disabled|passthru|
1020 *					nxdomain|nodata|cname <domain> ) ];
1021 *  };
1022 *
1023 * this is a chimera of doc_optional_keyvalue() and cfg_doc_enum()
1024 */
1025static void
1026doc_rpz_policies(cfg_printer_t *pctx, const cfg_type_t *type) {
1027	const keyword_type_t *kw;
1028	const char * const *p;
1029
1030	kw = type->of;
1031	cfg_print_chars(pctx, "[ ", 2);
1032	cfg_print_cstr(pctx, kw->name);
1033	cfg_print_chars(pctx, " ", 1);
1034
1035	cfg_print_chars(pctx, "( ", 2);
1036	for (p = kw->type->of; *p != NULL; p++) {
1037		cfg_print_cstr(pctx, *p);
1038		if (p[1] != NULL)
1039			cfg_print_chars(pctx, " | ", 3);
1040	}
1041}
1042
1043/*
1044 * print_qstring() from parser.c
1045 */
1046static void
1047print_rpz_cname(cfg_printer_t *pctx, const cfg_obj_t *obj)
1048{
1049	cfg_print_chars(pctx, "\"", 1);
1050	cfg_print_ustring(pctx, obj);
1051	cfg_print_chars(pctx, "\"", 1);
1052}
1053
1054static void
1055doc_rpz_cname(cfg_printer_t *pctx, const cfg_type_t *type) {
1056	cfg_doc_terminal(pctx, type);
1057	cfg_print_chars(pctx, " ) ]", 4);
1058}
1059
1060static isc_result_t
1061parse_rpz(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1062	isc_result_t result;
1063	cfg_obj_t *obj = NULL;
1064	const cfg_tuplefielddef_t *fields = type->of;
1065
1066	CHECK(cfg_create_tuple(pctx, type, &obj));
1067	CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
1068	CHECK(cfg_parse_obj(pctx, fields[1].type, &obj->value.tuple[1]));
1069	/*
1070	 * parse cname domain only after "policy cname"
1071	 */
1072	if (cfg_obj_isvoid(obj->value.tuple[1]) ||
1073	    strcasecmp("cname", cfg_obj_asstring(obj->value.tuple[1]))) {
1074		CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2]));
1075	} else {
1076		CHECK(cfg_parse_obj(pctx, fields[2].type, &obj->value.tuple[2]));
1077	}
1078
1079	*ret = obj;
1080	return (ISC_R_SUCCESS);
1081
1082cleanup:
1083	CLEANUP_OBJ(obj);
1084	return (result);
1085}
1086
1087static const char *rpz_policies[] = {
1088	"given", "disabled", "passthru", "no-op", "nxdomain", "nodata",
1089	"cname", NULL
1090};
1091static cfg_type_t cfg_type_rpz_policylist = {
1092	"policies", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
1093	&cfg_rep_string, &rpz_policies
1094};
1095static keyword_type_t rpz_policies_kw = {
1096	"policy", &cfg_type_rpz_policylist
1097};
1098static cfg_type_t cfg_type_rpz_policy = {
1099	"optional_policy", parse_optional_keyvalue, print_keyvalue,
1100	doc_rpz_policies, &cfg_rep_string, &rpz_policies_kw
1101};
1102static cfg_type_t cfg_type_cname = {
1103	"domain", cfg_parse_astring, print_rpz_cname, doc_rpz_cname,
1104	&cfg_rep_string, NULL
1105};
1106static cfg_tuplefielddef_t rpzone_fields[] = {
1107	{ "name", &cfg_type_astring, 0 },
1108	{ "policy", &cfg_type_rpz_policy, 0 },
1109	{ "cname", &cfg_type_cname, 0 },
1110	{ NULL, NULL, 0 }
1111};
1112static cfg_type_t cfg_type_rpzone = {
1113	"rpzone", parse_rpz, cfg_print_tuple, cfg_doc_tuple,
1114	&cfg_rep_tuple, rpzone_fields
1115};
1116static cfg_clausedef_t rpz_clauses[] = {
1117	{ "zone", &cfg_type_rpzone, CFG_CLAUSEFLAG_MULTI },
1118	{ NULL, NULL, 0 }
1119};
1120static cfg_clausedef_t *rpz_clausesets[] = {
1121	rpz_clauses,
1122	NULL
1123};
1124static cfg_type_t cfg_type_rpz = {
1125	"rpz", cfg_parse_map, cfg_print_map, cfg_doc_map,
1126	&cfg_rep_map, rpz_clausesets
1127};
1128
1129
1130
1131/*%
1132 * dnssec-lookaside
1133 */
1134
1135static void
1136print_lookaside(cfg_printer_t *pctx, const cfg_obj_t *obj)
1137{
1138	const cfg_obj_t *domain = obj->value.tuple[0];
1139
1140	if (domain->value.string.length == 4 &&
1141	    strncmp(domain->value.string.base, "auto", 4) == 0)
1142		cfg_print_cstr(pctx, "auto");
1143	else
1144		cfg_print_tuple(pctx, obj);
1145}
1146
1147static void
1148doc_lookaside(cfg_printer_t *pctx, const cfg_type_t *type) {
1149	UNUSED(type);
1150	cfg_print_cstr(pctx, "( <string> trust-anchor <string> | auto | no )");
1151}
1152
1153static keyword_type_t trustanchor_kw = { "trust-anchor", &cfg_type_astring };
1154
1155static cfg_type_t cfg_type_optional_trustanchor = {
1156	"optional_trustanchor", parse_optional_keyvalue, print_keyvalue,
1157	doc_keyvalue, &cfg_rep_string, &trustanchor_kw
1158};
1159
1160static cfg_tuplefielddef_t lookaside_fields[] = {
1161	{ "domain", &cfg_type_astring, 0 },
1162	{ "trust-anchor", &cfg_type_optional_trustanchor, 0 },
1163	{ NULL, NULL, 0 }
1164};
1165
1166static cfg_type_t cfg_type_lookaside = {
1167	"lookaside", cfg_parse_tuple, print_lookaside, doc_lookaside,
1168	&cfg_rep_tuple, lookaside_fields
1169};
1170
1171/*
1172 * DNS64.
1173 */
1174static cfg_clausedef_t
1175dns64_clauses[] = {
1176	{ "clients", &cfg_type_bracketed_aml, 0 },
1177	{ "mapped", &cfg_type_bracketed_aml, 0 },
1178	{ "exclude", &cfg_type_bracketed_aml, 0 },
1179	{ "suffix", &cfg_type_netaddr6, 0 },
1180	{ "recursive-only", &cfg_type_boolean, 0 },
1181	{ "break-dnssec", &cfg_type_boolean, 0 },
1182	{ NULL, NULL, 0 },
1183};
1184
1185static cfg_clausedef_t *
1186dns64_clausesets[] = {
1187	dns64_clauses,
1188	NULL
1189};
1190
1191static cfg_type_t cfg_type_dns64 = {
1192	"dns64", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map,
1193	&cfg_rep_map, dns64_clausesets
1194};
1195
1196/*%
1197 * Clauses that can be found within the 'view' statement,
1198 * with defaults in the 'options' statement.
1199 */
1200
1201static cfg_clausedef_t
1202view_clauses[] = {
1203	{ "acache-cleaning-interval", &cfg_type_uint32, 0 },
1204	{ "acache-enable", &cfg_type_boolean, 0 },
1205	{ "additional-from-auth", &cfg_type_boolean, 0 },
1206	{ "additional-from-cache", &cfg_type_boolean, 0 },
1207	{ "allow-new-zones", &cfg_type_boolean, 0 },
1208	{ "allow-query-cache", &cfg_type_bracketed_aml, 0 },
1209	{ "allow-query-cache-on", &cfg_type_bracketed_aml, 0 },
1210	{ "allow-recursion", &cfg_type_bracketed_aml, 0 },
1211	{ "allow-recursion-on", &cfg_type_bracketed_aml, 0 },
1212	{ "allow-v6-synthesis", &cfg_type_bracketed_aml,
1213	  CFG_CLAUSEFLAG_OBSOLETE },
1214	{ "attach-cache", &cfg_type_astring, 0 },
1215	{ "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT },
1216	{ "cache-file", &cfg_type_qstring, 0 },
1217	{ "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
1218	{ "cleaning-interval", &cfg_type_uint32, 0 },
1219	{ "clients-per-query", &cfg_type_uint32, 0 },
1220	{ "deny-answer-addresses", &cfg_type_denyaddresses, 0 },
1221	{ "deny-answer-aliases", &cfg_type_denyaliases, 0 },
1222	{ "disable-algorithms", &cfg_type_disablealgorithm,
1223	  CFG_CLAUSEFLAG_MULTI },
1224	{ "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI },
1225	{ "dns64", &cfg_type_dns64, CFG_CLAUSEFLAG_MULTI },
1226	{ "dns64-server", &cfg_type_astring, 0 },
1227	{ "dns64-contact", &cfg_type_astring, 0 },
1228	{ "dnssec-accept-expired", &cfg_type_boolean, 0 },
1229	{ "dnssec-enable", &cfg_type_boolean, 0 },
1230	{ "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI },
1231	{ "dnssec-must-be-secure",  &cfg_type_mustbesecure,
1232	  CFG_CLAUSEFLAG_MULTI },
1233	{ "dnssec-validation", &cfg_type_boolorauto, 0 },
1234	{ "dual-stack-servers", &cfg_type_nameportiplist, 0 },
1235	{ "edns-udp-size", &cfg_type_uint32, 0 },
1236	{ "empty-contact", &cfg_type_astring, 0 },
1237	{ "empty-server", &cfg_type_astring, 0 },
1238	{ "empty-zones-enable", &cfg_type_boolean, 0 },
1239	{ "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1240	{ "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 },
1241	{ "lame-ttl", &cfg_type_uint32, 0 },
1242	{ "max-acache-size", &cfg_type_sizenodefault, 0 },
1243	{ "max-cache-size", &cfg_type_sizenodefault, 0 },
1244	{ "max-cache-ttl", &cfg_type_uint32, 0 },
1245	{ "max-clients-per-query", &cfg_type_uint32, 0 },
1246	{ "max-ncache-ttl", &cfg_type_uint32, 0 },
1247	{ "max-udp-size", &cfg_type_uint32, 0 },
1248	{ "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
1249	{ "minimal-responses", &cfg_type_boolean, 0 },
1250	{ "preferred-glue", &cfg_type_astring, 0 },
1251	{ "provide-ixfr", &cfg_type_boolean, 0 },
1252	/*
1253	 * Note that the query-source option syntax is different
1254	 * from the other -source options.
1255	 */
1256	{ "query-source", &cfg_type_querysource4, 0 },
1257	{ "query-source-v6", &cfg_type_querysource6, 0 },
1258	{ "queryport-pool-ports", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
1259	{ "queryport-pool-updateinterval", &cfg_type_uint32,
1260	  CFG_CLAUSEFLAG_OBSOLETE },
1261	{ "recursion", &cfg_type_boolean, 0 },
1262	{ "request-ixfr", &cfg_type_boolean, 0 },
1263	{ "request-nsid", &cfg_type_boolean, 0 },
1264	{ "resolver-query-timeout", &cfg_type_uint32, 0 },
1265	{ "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
1266	{ "root-delegation-only",  &cfg_type_optional_exclude, 0 },
1267	{ "rrset-order", &cfg_type_rrsetorder, 0 },
1268	{ "sortlist", &cfg_type_bracketed_aml, 0 },
1269	{ "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
1270	{ "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP },
1271	{ "transfer-format", &cfg_type_transferformat, 0 },
1272	{ "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1273	{ "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
1274#ifdef ALLOW_FILTER_AAAA_ON_V4
1275	{ "filter-aaaa", &cfg_type_bracketed_aml, 0 },
1276	{ "filter-aaaa-on-v4", &cfg_type_v4_aaaa, 0 },
1277#else
1278	{ "filter-aaaa", &cfg_type_bracketed_aml,
1279	   CFG_CLAUSEFLAG_NOTCONFIGURED },
1280	{ "filter-aaaa-on-v4", &cfg_type_v4_aaaa,
1281	   CFG_CLAUSEFLAG_NOTCONFIGURED },
1282#endif
1283	{ "response-policy", &cfg_type_rpz, 0 },
1284	{ NULL, NULL, 0 }
1285};
1286
1287/*%
1288 * Clauses that can be found within the 'view' statement only.
1289 */
1290static cfg_clausedef_t
1291view_only_clauses[] = {
1292	{ "match-clients", &cfg_type_bracketed_aml, 0 },
1293	{ "match-destinations", &cfg_type_bracketed_aml, 0 },
1294	{ "match-recursive-only", &cfg_type_boolean, 0 },
1295	{ NULL, NULL, 0 }
1296};
1297
1298/*%
1299 * Sig-validity-interval.
1300 */
1301static isc_result_t
1302parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type,
1303		      cfg_obj_t **ret)
1304{
1305	isc_result_t result;
1306	UNUSED(type);
1307
1308	CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
1309	if (pctx->token.type == isc_tokentype_number) {
1310		CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret));
1311	} else {
1312		CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
1313	}
1314 cleanup:
1315	return (result);
1316}
1317
1318static void
1319doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) {
1320	UNUSED(type);
1321	cfg_print_cstr(pctx, "[ <integer> ]");
1322}
1323
1324static cfg_type_t cfg_type_optional_uint32 = {
1325	"optional_uint32", parse_optional_uint32, NULL, doc_optional_uint32,
1326	NULL, NULL };
1327
1328static cfg_tuplefielddef_t validityinterval_fields[] = {
1329	{ "validity", &cfg_type_uint32, 0 },
1330	{ "re-sign", &cfg_type_optional_uint32, 0 },
1331	{ NULL, NULL, 0 }
1332};
1333
1334static cfg_type_t cfg_type_validityinterval = {
1335	"validityinterval", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
1336	&cfg_rep_tuple, validityinterval_fields
1337};
1338
1339/*%
1340 * Clauses that can be found in a 'zone' statement,
1341 * with defaults in the 'view' or 'options' statement.
1342 */
1343static cfg_clausedef_t
1344zone_clauses[] = {
1345	{ "allow-notify", &cfg_type_bracketed_aml, 0 },
1346	{ "allow-query", &cfg_type_bracketed_aml, 0 },
1347	{ "allow-query-on", &cfg_type_bracketed_aml, 0 },
1348	{ "allow-transfer", &cfg_type_bracketed_aml, 0 },
1349	{ "allow-update", &cfg_type_bracketed_aml, 0 },
1350	{ "allow-update-forwarding", &cfg_type_bracketed_aml, 0 },
1351	{ "also-notify", &cfg_type_portiplist, 0 },
1352	{ "alt-transfer-source", &cfg_type_sockaddr4wild, 0 },
1353	{ "alt-transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
1354	{ "auto-dnssec", &cfg_type_autodnssec, 0 },
1355	{ "check-dup-records", &cfg_type_checkmode, 0 },
1356	{ "check-integrity", &cfg_type_boolean, 0 },
1357	{ "check-mx", &cfg_type_checkmode, 0 },
1358	{ "check-mx-cname", &cfg_type_checkmode, 0 },
1359	{ "check-sibling", &cfg_type_boolean, 0 },
1360	{ "check-srv-cname", &cfg_type_checkmode, 0 },
1361	{ "check-wildcard", &cfg_type_boolean, 0 },
1362	{ "dialup", &cfg_type_dialuptype, 0 },
1363	{ "dnssec-dnskey-kskonly", &cfg_type_boolean, 0 },
1364	{ "dnssec-secure-to-insecure", &cfg_type_boolean, 0 },
1365	{ "forward", &cfg_type_forwardtype, 0 },
1366	{ "forwarders", &cfg_type_portiplist, 0 },
1367	{ "key-directory", &cfg_type_qstring, 0 },
1368	{ "maintain-ixfr-base", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1369	{ "masterfile-format", &cfg_type_masterformat, 0 },
1370	{ "max-ixfr-log-size", &cfg_type_size, CFG_CLAUSEFLAG_OBSOLETE },
1371	{ "max-journal-size", &cfg_type_sizenodefault, 0 },
1372	{ "max-refresh-time", &cfg_type_uint32, 0 },
1373	{ "max-retry-time", &cfg_type_uint32, 0 },
1374	{ "max-transfer-idle-in", &cfg_type_uint32, 0 },
1375	{ "max-transfer-idle-out", &cfg_type_uint32, 0 },
1376	{ "max-transfer-time-in", &cfg_type_uint32, 0 },
1377	{ "max-transfer-time-out", &cfg_type_uint32, 0 },
1378	{ "min-refresh-time", &cfg_type_uint32, 0 },
1379	{ "min-retry-time", &cfg_type_uint32, 0 },
1380	{ "multi-master", &cfg_type_boolean, 0 },
1381	{ "notify", &cfg_type_notifytype, 0 },
1382	{ "notify-delay", &cfg_type_uint32, 0 },
1383	{ "notify-source", &cfg_type_sockaddr4wild, 0 },
1384	{ "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
1385	{ "notify-to-soa", &cfg_type_boolean, 0 },
1386	{ "nsec3-test-zone", &cfg_type_boolean, CFG_CLAUSEFLAG_TESTONLY },
1387	{ "sig-signing-nodes", &cfg_type_uint32, 0 },
1388	{ "sig-signing-signatures", &cfg_type_uint32, 0 },
1389	{ "sig-signing-type", &cfg_type_uint32, 0 },
1390	{ "sig-validity-interval", &cfg_type_validityinterval, 0 },
1391	{ "transfer-source", &cfg_type_sockaddr4wild, 0 },
1392	{ "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
1393	{ "try-tcp-refresh", &cfg_type_boolean, 0 },
1394	{ "update-check-ksk", &cfg_type_boolean, 0 },
1395	{ "use-alt-transfer-source", &cfg_type_boolean, 0 },
1396	{ "zero-no-soa-ttl", &cfg_type_boolean, 0 },
1397	{ "zone-statistics", &cfg_type_boolean, 0 },
1398	{ NULL, NULL, 0 }
1399};
1400
1401/*%
1402 * Clauses that can be found in a 'zone' statement
1403 * only.
1404 */
1405static cfg_clausedef_t
1406zone_only_clauses[] = {
1407	{ "type", &cfg_type_zonetype, 0 },
1408	{ "file", &cfg_type_qstring, 0 },
1409	{ "journal", &cfg_type_qstring, 0 },
1410	{ "ixfr-base", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
1411	{ "ixfr-tmp-file", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
1412	{ "masters", &cfg_type_namesockaddrkeylist, 0 },
1413	{ "pubkey", &cfg_type_pubkey,
1414	  CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE },
1415	{ "update-policy", &cfg_type_updatepolicy, 0 },
1416	{ "database", &cfg_type_astring, 0 },
1417	{ "delegation-only", &cfg_type_boolean, 0 },
1418	/*
1419	 * Note that the format of the check-names option is different between
1420	 * the zone options and the global/view options.  Ugh.
1421	 */
1422	{ "check-names", &cfg_type_checkmode, 0 },
1423	{ "ixfr-from-differences", &cfg_type_boolean, 0 },
1424	{ "server-addresses", &cfg_type_bracketed_sockaddrlist, 0 },
1425	{ "server-names", &cfg_type_namelist, 0 },
1426	{ NULL, NULL, 0 }
1427};
1428
1429
1430/*% The top-level named.conf syntax. */
1431
1432static cfg_clausedef_t *
1433namedconf_clausesets[] = {
1434	namedconf_clauses,
1435	namedconf_or_view_clauses,
1436	NULL
1437};
1438LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = {
1439	"namedconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
1440	&cfg_rep_map, namedconf_clausesets
1441};
1442
1443/*% The bind.keys syntax (trusted-keys/managed-keys only). */
1444static cfg_clausedef_t *
1445bindkeys_clausesets[] = {
1446	bindkeys_clauses,
1447	NULL
1448};
1449LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bindkeys = {
1450	"bindkeys", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
1451	&cfg_rep_map, bindkeys_clausesets
1452};
1453
1454/*% The new-zone-file syntax (for zones added by 'rndc addzone') */
1455static cfg_clausedef_t
1456newzones_clauses[] = {
1457	{ "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
1458	{ NULL, NULL, 0 }
1459};
1460
1461static cfg_clausedef_t *
1462newzones_clausesets[] = {
1463	newzones_clauses,
1464	NULL
1465};
1466
1467LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_newzones = {
1468	"newzones", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
1469	&cfg_rep_map, newzones_clausesets
1470};
1471
1472/*% The "options" statement syntax. */
1473
1474static cfg_clausedef_t *
1475options_clausesets[] = {
1476	options_clauses,
1477	view_clauses,
1478	zone_clauses,
1479	NULL
1480};
1481static cfg_type_t cfg_type_options = {
1482	"options", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, options_clausesets };
1483
1484/*% The "view" statement syntax. */
1485
1486static cfg_clausedef_t *
1487view_clausesets[] = {
1488	view_only_clauses,
1489	namedconf_or_view_clauses,
1490	view_clauses,
1491	zone_clauses,
1492	dynamically_loadable_zones_clauses,
1493	NULL
1494};
1495static cfg_type_t cfg_type_viewopts = {
1496	"view", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, view_clausesets };
1497
1498/*% The "zone" statement syntax. */
1499
1500static cfg_clausedef_t *
1501zone_clausesets[] = {
1502	zone_only_clauses,
1503	zone_clauses,
1504	NULL
1505};
1506static cfg_type_t cfg_type_zoneopts = {
1507	"zoneopts", cfg_parse_map, cfg_print_map,
1508	cfg_doc_map, &cfg_rep_map, zone_clausesets };
1509
1510/*% The "dynamically loadable zones" statement syntax. */
1511
1512static cfg_clausedef_t *
1513dynamically_loadable_zones_clausesets[] = {
1514	dynamically_loadable_zones_clauses,
1515	NULL
1516};
1517static cfg_type_t cfg_type_dynamically_loadable_zones_opts = {
1518	"dynamically_loadable_zones_opts", cfg_parse_map,
1519	cfg_print_map, cfg_doc_map, &cfg_rep_map,
1520	dynamically_loadable_zones_clausesets
1521};
1522
1523/*%
1524 * Clauses that can be found within the 'key' statement.
1525 */
1526static cfg_clausedef_t
1527key_clauses[] = {
1528	{ "algorithm", &cfg_type_astring, 0 },
1529	{ "secret", &cfg_type_astring, 0 },
1530	{ NULL, NULL, 0 }
1531};
1532
1533static cfg_clausedef_t *
1534key_clausesets[] = {
1535	key_clauses,
1536	NULL
1537};
1538static cfg_type_t cfg_type_key = {
1539	"key", cfg_parse_named_map, cfg_print_map,
1540	cfg_doc_map, &cfg_rep_map, key_clausesets
1541};
1542
1543
1544/*%
1545 * Clauses that can be found in a 'server' statement.
1546 */
1547static cfg_clausedef_t
1548server_clauses[] = {
1549	{ "bogus", &cfg_type_boolean, 0 },
1550	{ "provide-ixfr", &cfg_type_boolean, 0 },
1551	{ "request-ixfr", &cfg_type_boolean, 0 },
1552	{ "support-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1553	{ "transfers", &cfg_type_uint32, 0 },
1554	{ "transfer-format", &cfg_type_transferformat, 0 },
1555	{ "keys", &cfg_type_server_key_kludge, 0 },
1556	{ "edns", &cfg_type_boolean, 0 },
1557	{ "edns-udp-size", &cfg_type_uint32, 0 },
1558	{ "max-udp-size", &cfg_type_uint32, 0 },
1559	{ "notify-source", &cfg_type_sockaddr4wild, 0 },
1560	{ "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
1561	{ "query-source", &cfg_type_querysource4, 0 },
1562	{ "query-source-v6", &cfg_type_querysource6, 0 },
1563	{ "transfer-source", &cfg_type_sockaddr4wild, 0 },
1564	{ "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
1565	{ NULL, NULL, 0 }
1566};
1567static cfg_clausedef_t *
1568server_clausesets[] = {
1569	server_clauses,
1570	NULL
1571};
1572static cfg_type_t cfg_type_server = {
1573	"server", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
1574	server_clausesets
1575};
1576
1577
1578/*%
1579 * Clauses that can be found in a 'channel' clause in the
1580 * 'logging' statement.
1581 *
1582 * These have some additional constraints that need to be
1583 * checked after parsing:
1584 *  - There must exactly one of file/syslog/null/stderr
1585 *
1586 */
1587static cfg_clausedef_t
1588channel_clauses[] = {
1589	/* Destinations.  We no longer require these to be first. */
1590	{ "file", &cfg_type_logfile, 0 },
1591	{ "syslog", &cfg_type_optional_facility, 0 },
1592	{ "null", &cfg_type_void, 0 },
1593	{ "stderr", &cfg_type_void, 0 },
1594	/* Options.  We now accept these for the null channel, too. */
1595	{ "severity", &cfg_type_logseverity, 0 },
1596	{ "print-time", &cfg_type_boolean, 0 },
1597	{ "print-severity", &cfg_type_boolean, 0 },
1598	{ "print-category", &cfg_type_boolean, 0 },
1599	{ NULL, NULL, 0 }
1600};
1601static cfg_clausedef_t *
1602channel_clausesets[] = {
1603	channel_clauses,
1604	NULL
1605};
1606static cfg_type_t cfg_type_channel = {
1607	"channel", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
1608	&cfg_rep_map, channel_clausesets
1609};
1610
1611/*% A list of log destination, used in the "category" clause. */
1612static cfg_type_t cfg_type_destinationlist = {
1613	"destinationlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
1614	&cfg_rep_list, &cfg_type_astring };
1615
1616/*%
1617 * Clauses that can be found in a 'logging' statement.
1618 */
1619static cfg_clausede

Large files files are truncated, but you can click here to view the full file