namedconf.c 71.6 KB
Newer Older
1
/*
Automatic Updater's avatar
Automatic Updater committed
2
 * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 2002, 2003  Internet Software Consortium.
4
 *
Automatic Updater's avatar
Automatic Updater committed
5
 * Permission to use, copy, modify, and/or distribute this software for any
6 7 8
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
16 17
 */

18
/* $Id: namedconf.c,v 1.110 2009/10/26 23:14:54 each Exp $ */
19 20

/*! \file */
21 22 23 24 25 26

#include <config.h>

#include <string.h>

#include <isc/lex.h>
27
#include <isc/mem.h>
28 29 30 31 32 33 34 35
#include <isc/result.h>
#include <isc/string.h>
#include <isc/util.h>

#include <isccfg/cfg.h>
#include <isccfg/grammar.h>
#include <isccfg/log.h>

36 37
#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)

38
/*% Check a return value. */
39 40 41
#define CHECK(op)						\
	do { result = (op);					\
		if (result != ISC_R_SUCCESS) goto cleanup;	\
42 43
	} while (0)

44
/*% Clean up a configuration object if non-NULL. */
45 46 47 48
#define CLEANUP_OBJ(obj) \
	do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)


49
/*%
50 51 52 53 54 55 56 57 58 59 60
 * Forward declarations of static functions.
 */

static isc_result_t
parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
		    const cfg_type_t *othertype, cfg_obj_t **ret);

static isc_result_t
parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);

static isc_result_t
61 62 63 64 65 66 67 68 69
parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
			cfg_obj_t **ret);

static isc_result_t
parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
		   cfg_obj_t **ret);

static void
doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type);
70 71

static void
72
print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj);
73 74 75 76 77 78 79 80

static void
doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);

static void
doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);

static cfg_type_t cfg_type_acl;
81 82
static cfg_type_t cfg_type_addrmatchelt;
static cfg_type_t cfg_type_bracketed_aml;
83
static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
84
static cfg_type_t cfg_type_bracketed_sockaddrlist;
85
static cfg_type_t cfg_type_bracketed_sockaddrnameportlist;
86 87 88 89
static cfg_type_t cfg_type_controls;
static cfg_type_t cfg_type_controls_sockaddr;
static cfg_type_t cfg_type_destinationlist;
static cfg_type_t cfg_type_dialuptype;
90
static cfg_type_t cfg_type_ixfrdifftype;
91 92 93 94 95
static cfg_type_t cfg_type_key;
static cfg_type_t cfg_type_logfile;
static cfg_type_t cfg_type_logging;
static cfg_type_t cfg_type_logseverity;
static cfg_type_t cfg_type_lwres;
96
static cfg_type_t cfg_type_masterselement;
97 98 99
static cfg_type_t cfg_type_nameportiplist;
static cfg_type_t cfg_type_negated;
static cfg_type_t cfg_type_notifytype;
100
static cfg_type_t cfg_type_optional_allow;
101 102
static cfg_type_t cfg_type_optional_class;
static cfg_type_t cfg_type_optional_facility;
103
static cfg_type_t cfg_type_optional_keyref;
104
static cfg_type_t cfg_type_optional_port;
105
static cfg_type_t cfg_type_options;
106
static cfg_type_t cfg_type_portiplist;
107 108 109
static cfg_type_t cfg_type_querysource4;
static cfg_type_t cfg_type_querysource6;
static cfg_type_t cfg_type_querysource;
110 111 112 113
static cfg_type_t cfg_type_server;
static cfg_type_t cfg_type_server_key_kludge;
static cfg_type_t cfg_type_size;
static cfg_type_t cfg_type_sizenodefault;
114 115
static cfg_type_t cfg_type_sockaddr4wild;
static cfg_type_t cfg_type_sockaddr6wild;
116
static cfg_type_t cfg_type_statschannels;
117 118
static cfg_type_t cfg_type_view;
static cfg_type_t cfg_type_viewopts;
119 120
static cfg_type_t cfg_type_zone;
static cfg_type_t cfg_type_zoneopts;
121 122
static cfg_type_t cfg_type_dynamically_loadable_zones;
static cfg_type_t cfg_type_dynamically_loadable_zones_opts;
123 124 125
#ifdef ALLOW_FILTER_AAAA_ON_V4
static cfg_type_t cfg_type_v4_aaaa;
#endif
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150

/*
 * Clauses that can be found in a 'dynamically loadable zones' statement
 */
static cfg_clausedef_t
dynamically_loadable_zones_clauses[] = {
	{ "database", &cfg_type_astring, 0 },
	{ NULL, NULL, 0 }
};

/*
 * A dynamically loadable zones statement.
 */
static cfg_tuplefielddef_t dynamically_loadable_zones_fields[] = {
	{ "name", &cfg_type_astring, 0 },
	{ "options", &cfg_type_dynamically_loadable_zones_opts, 0 },
	{ NULL, NULL, 0 }
};

static cfg_type_t cfg_type_dynamically_loadable_zones = {
	"dlz", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple,
	dynamically_loadable_zones_fields
	};

151

152
/*% tkey-dhkey */
153 154 155 156 157 158 159 160 161 162 163 164

static cfg_tuplefielddef_t tkey_dhkey_fields[] = {
	{ "name", &cfg_type_qstring, 0 },
	{ "keyid", &cfg_type_uint32, 0 },
	{ NULL, NULL, 0 }
};

static cfg_type_t cfg_type_tkey_dhkey = {
	"tkey-dhkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
	tkey_dhkey_fields
};

165
/*% listen-on */
166 167 168 169 170 171 172 173 174

static cfg_tuplefielddef_t listenon_fields[] = {
	{ "port", &cfg_type_optional_port, 0 },
	{ "acl", &cfg_type_bracketed_aml, 0 },
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_listenon = {
	"listenon", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, listenon_fields };

175
/*% acl */
176 177 178 179 180 181 182 183 184 185

static cfg_tuplefielddef_t acl_fields[] = {
	{ "name", &cfg_type_astring, 0 },
	{ "value", &cfg_type_bracketed_aml, 0 },
	{ NULL, NULL, 0 }
};

static cfg_type_t cfg_type_acl = {
	"acl", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, acl_fields };

186
/*% masters */
187 188 189 190 191 192 193 194 195
static cfg_tuplefielddef_t masters_fields[] = {
	{ "name", &cfg_type_astring, 0 },
	{ "port", &cfg_type_optional_port, 0 },
	{ "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
	{ NULL, NULL, 0 }
};

static cfg_type_t cfg_type_masters = {
	"masters", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, masters_fields };
196

197
/*%
198 199 200
 * "sockaddrkeylist", a list of socket addresses with optional keys
 * and an optional default port, as used in the masters option.
 * E.g.,
201
 *   "port 1234 { mymasters; 10.0.0.1 key foo; 1::2 port 69; }"
202 203
 */

204 205
static cfg_tuplefielddef_t namesockaddrkey_fields[] = {
	{ "masterselement", &cfg_type_masterselement, 0 },
206 207 208 209
	{ "key", &cfg_type_optional_keyref, 0 },
	{ NULL, NULL, 0 },
};

210 211 212
static cfg_type_t cfg_type_namesockaddrkey = {
	"namesockaddrkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
	namesockaddrkey_fields
213 214
};

215 216 217
static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = {
	"bracketed_namesockaddrkeylist", cfg_parse_bracketed_list,
	cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_namesockaddrkey
218 219
};

220
static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = {
221
	{ "port", &cfg_type_optional_port, 0 },
222
	{ "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
223 224
	{ NULL, NULL, 0 }
};
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 232 233 234 235 236 237 238 239 240 241 242 243 244
 * A list of socket addresses with an optional default port,
 * as used in the also-notify option.  E.g.,
 * "port 1234 { 10.0.0.1; 1::2 port 69; }"
 */
static cfg_tuplefielddef_t portiplist_fields[] = {
	{ "port", &cfg_type_optional_port, 0 },
	{ "addresses", &cfg_type_bracketed_sockaddrlist, 0 },
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_portiplist = {
	"portiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
	portiplist_fields
};

245
/*%
246 247 248 249 250 251 252 253 254 255
 * A public key, as in the "pubkey" statement.
 */
static cfg_tuplefielddef_t pubkey_fields[] = {
	{ "flags", &cfg_type_uint32, 0 },
	{ "protocol", &cfg_type_uint32, 0 },
	{ "algorithm", &cfg_type_uint32, 0 },
	{ "key", &cfg_type_qstring, 0 },
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_pubkey = {
256 257
	"pubkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, pubkey_fields };
258

259
/*%
260 261 262 263
 * A list of RR types, used in grant statements.
 * Note that the old parser allows quotes around the RR type names.
 */
static cfg_type_t cfg_type_rrtypelist = {
264
	"rrtypelist", cfg_parse_spacelist, cfg_print_spacelist,
Automatic Updater's avatar
Automatic Updater committed
265
	cfg_doc_terminal, &cfg_rep_list, &cfg_type_astring
266 267 268 269
};

static const char *mode_enums[] = { "grant", "deny", NULL };
static cfg_type_t cfg_type_mode = {
Automatic Updater's avatar
Automatic Updater committed
270
	"mode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
271
	&cfg_rep_string, &mode_enums
272 273
};

274 275 276 277 278 279 280 281
static isc_result_t
parse_matchtype(cfg_parser_t *pctx, const cfg_type_t *type,
		cfg_obj_t **ret) {
	isc_result_t result;

	CHECK(cfg_peektoken(pctx, 0));
	if (pctx->token.type == isc_tokentype_string &&
	    strcasecmp(TOKEN_STRING(pctx), "zonesub") == 0) {
Automatic Updater's avatar
Automatic Updater committed
282
		pctx->flags |= CFG_PCTX_SKIP;
283 284 285 286 287 288 289 290
	}
	return (cfg_parse_enum(pctx, type, ret));

 cleanup:
	return (result);
}

static isc_result_t
291
parse_matchname(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
292 293 294 295 296 297 298 299 300 301 302 303 304 305
	isc_result_t result;
	cfg_obj_t *obj = NULL;

	if ((pctx->flags & CFG_PCTX_SKIP) != 0) {
		pctx->flags &= ~CFG_PCTX_SKIP;
		CHECK(cfg_parse_void(pctx, NULL, &obj));
	} else
		result = cfg_parse_astring(pctx, type, &obj);

	*ret = obj;
 cleanup:
	return (result);
}

306 307 308 309 310 311 312
static void
doc_matchname(cfg_printer_t *pctx, const cfg_type_t *type) {
	cfg_print_chars(pctx, "[ ", 2);
	cfg_doc_obj(pctx, type->of);
	cfg_print_chars(pctx, " ]", 2);
}

313
static const char *matchtype_enums[] = {
Automatic Updater's avatar
Automatic Updater committed
314
	"name", "subdomain", "wildcard", "self", "selfsub", "selfwild",
315
	"krb5-self", "ms-self", "krb5-subdomain", "ms-subdomain",
316
	"tcp-self", "6to4-self", "zonesub", NULL };
317

318
static cfg_type_t cfg_type_matchtype = {
319
	"matchtype", parse_matchtype, cfg_print_ustring,
Automatic Updater's avatar
Automatic Updater committed
320
	cfg_doc_enum, &cfg_rep_string, &matchtype_enums
321 322 323 324
};

static cfg_type_t cfg_type_matchname = {
	"optional_matchname", parse_matchname, cfg_print_ustring,
325
	&doc_matchname, &cfg_rep_tuple, &cfg_type_ustring
326 327
};

328
/*%
329 330 331 332
 * A grant statement, used in the update policy.
 */
static cfg_tuplefielddef_t grant_fields[] = {
	{ "mode", &cfg_type_mode, 0 },
Automatic Updater's avatar
Automatic Updater committed
333
	{ "identity", &cfg_type_astring, 0 }, /* domain name */
334
	{ "matchtype", &cfg_type_matchtype, 0 },
335
	{ "name", &cfg_type_matchname, 0 }, /* domain name */
336 337 338 339
	{ "types", &cfg_type_rrtypelist, 0 },
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_grant = {
340 341 342
	"grant", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	 &cfg_rep_tuple, grant_fields
};
343 344

static cfg_type_t cfg_type_updatepolicy = {
345 346
	"update_policy", parse_updatepolicy, NULL, doc_updatepolicy,
	&cfg_rep_list, &cfg_type_grant
347 348
};

349 350 351 352 353 354 355
static isc_result_t
parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
		   cfg_obj_t **ret) {
	isc_result_t result;
	CHECK(cfg_gettoken(pctx, 0));
	if (pctx->token.type == isc_tokentype_special &&
	    pctx->token.value.as_char == '{') {
356
		cfg_ungettoken(pctx);
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
		return (cfg_parse_bracketed_list(pctx, type, ret));
	}

	if (pctx->token.type == isc_tokentype_string &&
	    strcasecmp(TOKEN_STRING(pctx), "local") == 0) {
		cfg_obj_t *obj = NULL;
		CHECK(cfg_create_obj(pctx, &cfg_type_ustring, &obj));
		obj->value.string.length = strlen("local");
		obj->value.string.base	= isc_mem_get(pctx->mctx,
						obj->value.string.length + 1);
		if (obj->value.string.base == NULL) {
			isc_mem_put(pctx->mctx, obj, sizeof(*obj));
			return (ISC_R_NOMEMORY);
		}
		memcpy(obj->value.string.base, "local", 5);
		obj->value.string.base[5] = '\0';
		*ret = obj;
		return (ISC_R_SUCCESS);
	}

	cfg_ungettoken(pctx);
	return (ISC_R_UNEXPECTEDTOKEN);

 cleanup:
	return (result);
}

static void
doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type) {
	cfg_print_chars(pctx, "( local | { ", 12);
	cfg_doc_obj(pctx, type->of);
	cfg_print_chars(pctx, "; ... }", 7);
}

391
/*%
392 393 394 395 396 397 398 399 400
 * A view statement.
 */
static cfg_tuplefielddef_t view_fields[] = {
	{ "name", &cfg_type_astring, 0 },
	{ "class", &cfg_type_optional_class, 0 },
	{ "options", &cfg_type_viewopts, 0 },
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_view = {
401 402 403
	"view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	 &cfg_rep_tuple, view_fields
};
404

405
/*%
406 407 408 409 410 411 412 413 414
 * A zone statement.
 */
static cfg_tuplefielddef_t zone_fields[] = {
	{ "name", &cfg_type_astring, 0 },
	{ "class", &cfg_type_optional_class, 0 },
	{ "options", &cfg_type_zoneopts, 0 },
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_zone = {
415 416 417
	"zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, zone_fields
};
418

419
/*%
420 421 422 423 424 425 426 427
 * A "category" clause in the "logging" statement.
 */
static cfg_tuplefielddef_t category_fields[] = {
	{ "name", &cfg_type_astring, 0 },
	{ "destinations", &cfg_type_destinationlist,0 },
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_category = {
428 429 430
	"category", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, category_fields
};
431 432


433
/*%
434
 * A dnssec key, as used in the "trusted-keys" statement.
435
 */
436
static cfg_tuplefielddef_t dnsseckey_fields[] = {
437 438 439 440 441 442 443
	{ "name", &cfg_type_astring, 0 },
	{ "flags", &cfg_type_uint32, 0 },
	{ "protocol", &cfg_type_uint32, 0 },
	{ "algorithm", &cfg_type_uint32, 0 },
	{ "key", &cfg_type_qstring, 0 },
	{ NULL, NULL, 0 }
};
444 445 446
static cfg_type_t cfg_type_dnsseckey = {
	"dnsseckey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, dnsseckey_fields
447 448
};

449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
/*%
 * A managed key initialization specifier, as used in the
 * "managed-keys" statement.
 */
static cfg_tuplefielddef_t managedkey_fields[] = {
	{ "name", &cfg_type_astring, 0 },
	{ "init", &cfg_type_ustring, 0 },   /* must be literal "initial-key" */
	{ "flags", &cfg_type_uint32, 0 },
	{ "protocol", &cfg_type_uint32, 0 },
	{ "algorithm", &cfg_type_uint32, 0 },
	{ "key", &cfg_type_qstring, 0 },
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_managedkey = {
	"managedkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, managedkey_fields
};

467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring };

static cfg_type_t cfg_type_optional_wild_class = {
	"optional_wild_class", parse_optional_keyvalue, print_keyvalue,
	doc_optional_keyvalue, &cfg_rep_string, &wild_class_kw
};

static keyword_type_t wild_type_kw = { "type", &cfg_type_ustring };

static cfg_type_t cfg_type_optional_wild_type = {
	"optional_wild_type", parse_optional_keyvalue,
	print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_type_kw
};

static keyword_type_t wild_name_kw = { "name", &cfg_type_qstring };

static cfg_type_t cfg_type_optional_wild_name = {
	"optional_wild_name", parse_optional_keyvalue,
	print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_name_kw
};

488
/*%
489 490 491 492 493 494
 * An rrset ordering element.
 */
static cfg_tuplefielddef_t rrsetorderingelement_fields[] = {
	{ "class", &cfg_type_optional_wild_class, 0 },
	{ "type", &cfg_type_optional_wild_type, 0 },
	{ "name", &cfg_type_optional_wild_name, 0 },
Automatic Updater's avatar
Automatic Updater committed
495
	{ "order", &cfg_type_ustring, 0 }, /* must be literal "order" */
496 497 498 499 500 501 502 503
	{ "ordering", &cfg_type_ustring, 0 },
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_rrsetorderingelement = {
	"rrsetorderingelement", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
	rrsetorderingelement_fields
};

504
/*%
505 506 507
 * A global or view "check-names" option.  Note that the zone
 * "check-names" option has a different syntax.
 */
508 509 510 511 512 513 514 515 516 517 518 519 520

static const char *checktype_enums[] = { "master", "slave", "response", NULL };
static cfg_type_t cfg_type_checktype = {
	"checktype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
	&cfg_rep_string, &checktype_enums
};

static const char *checkmode_enums[] = { "fail", "warn", "ignore", NULL };
static cfg_type_t cfg_type_checkmode = {
	"checkmode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
	&cfg_rep_string, &checkmode_enums
};

521
static cfg_tuplefielddef_t checknames_fields[] = {
522 523
	{ "type", &cfg_type_checktype, 0 },
	{ "mode", &cfg_type_checkmode, 0 },
524 525 526 527 528 529 530 531 532 533 534 535
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_checknames = {
	"checknames", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
	checknames_fields
};

static cfg_type_t cfg_type_bracketed_sockaddrlist = {
	"bracketed_sockaddrlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
	&cfg_rep_list, &cfg_type_sockaddr
};

Automatic Updater's avatar
Automatic Updater committed
536
static const char *autodnssec_enums[] = { "allow", "maintain", "create",
537 538 539 540 541 542
					  "off", NULL };
static cfg_type_t cfg_type_autodnssec = {
	"autodnssec", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
	&cfg_rep_string, &autodnssec_enums
};

543 544 545 546 547 548 549 550 551 552 553 554
static cfg_type_t cfg_type_rrsetorder = {
	"rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
	&cfg_rep_list, &cfg_type_rrsetorderingelement
};

static keyword_type_t port_kw = { "port", &cfg_type_uint32 };

static cfg_type_t cfg_type_optional_port = {
	"optional_port", parse_optional_keyvalue, print_keyvalue,
	doc_optional_keyvalue, &cfg_rep_uint32, &port_kw
};

555
/*% A list of keys, as in the "key" clause of the controls statement. */
556
static cfg_type_t cfg_type_keylist = {
557 558
	"keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
	cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring
559 560
};

561
/*% A list of dnssec keys, as in "trusted-keys" */
562 563 564
static cfg_type_t cfg_type_dnsseckeys = {
	"dnsseckeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
	cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_dnsseckey
565 566
};

567 568 569 570 571 572 573 574 575 576 577 578 579
/*%
 * A list of managed key entries, as in "trusted-keys".  Currently
 * (9.7.0) this has a format similar to dnssec keys, except the keyname
 * is followed by the keyword "initial-key".  In future releases, this
 * keyword may take other values indicating different methods for the
 * key to be initialized.
 */

static cfg_type_t cfg_type_managedkeys = {
	"managedkeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
	cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_managedkey
};

580 581 582 583 584 585 586
static const char *forwardtype_enums[] = { "first", "only", NULL };
static cfg_type_t cfg_type_forwardtype = {
	"forwardtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
	&forwardtype_enums
};

static const char *zonetype_enums[] = {
587
	"master", "slave", "stub", "hint", "forward", "delegation-only", NULL };
588
static cfg_type_t cfg_type_zonetype = {
589 590
	"zonetype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
	&cfg_rep_string, &zonetype_enums
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
};

static const char *loglevel_enums[] = {
	"critical", "error", "warning", "notice", "info", "dynamic", NULL };
static cfg_type_t cfg_type_loglevel = {
	"loglevel", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
	&loglevel_enums
};

static const char *transferformat_enums[] = {
	"many-answers", "one-answer", NULL };
static cfg_type_t cfg_type_transferformat = {
	"transferformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
	&transferformat_enums
};

607
/*%
608 609 610 611
 * The special keyword "none", as used in the pid-file option.
 */

static void
612
print_none(cfg_printer_t *pctx, const cfg_obj_t *obj) {
613 614 615 616 617 618 619 620
	UNUSED(obj);
	cfg_print_chars(pctx, "none", 4);
}

static cfg_type_t cfg_type_none = {
	"none", NULL, print_none, NULL, &cfg_rep_void, NULL
};

621
/*%
622 623 624 625 626 627 628
 * A quoted string or the special keyword "none".  Used in the pid-file option.
 */
static isc_result_t
parse_qstringornone(cfg_parser_t *pctx, const cfg_type_t *type,
		    cfg_obj_t **ret)
{
	isc_result_t result;
629

630 631
	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
	if (pctx->token.type == isc_tokentype_string &&
632
	    strcasecmp(TOKEN_STRING(pctx), "none") == 0)
633 634 635 636 637 638 639 640 641 642 643 644 645 646
		return (cfg_create_obj(pctx, &cfg_type_none, ret));
	cfg_ungettoken(pctx);
	return (cfg_parse_qstring(pctx, type, ret));
 cleanup:
	return (result);
}

static void
doc_qstringornone(cfg_printer_t *pctx, const cfg_type_t *type) {
	UNUSED(type);
	cfg_print_chars(pctx, "( <quoted_string> | none )", 26);
}

static cfg_type_t cfg_type_qstringornone = {
647 648 649
	"qstringornone", parse_qstringornone, NULL, doc_qstringornone,
	NULL, NULL
};
650

651
/*%
652 653 654 655
 * keyword hostname
 */

static void
656
print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) {
657 658 659 660 661 662 663 664
	UNUSED(obj);
	cfg_print_chars(pctx, "hostname", 4);
}

static cfg_type_t cfg_type_hostname = {
	"hostname", NULL, print_hostname, NULL, &cfg_rep_boolean, NULL
};

665
/*%
Mark Andrews's avatar
Mark Andrews committed
666
 * "server-id" argument.
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
 */

static isc_result_t
parse_serverid(cfg_parser_t *pctx, const cfg_type_t *type,
		    cfg_obj_t **ret)
{
	isc_result_t result;
	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
	if (pctx->token.type == isc_tokentype_string &&
	    strcasecmp(TOKEN_STRING(pctx), "none") == 0)
		return (cfg_create_obj(pctx, &cfg_type_none, ret));
	if (pctx->token.type == isc_tokentype_string &&
	    strcasecmp(TOKEN_STRING(pctx), "hostname") == 0) {
		return (cfg_create_obj(pctx, &cfg_type_hostname, ret));
	}
	cfg_ungettoken(pctx);
	return (cfg_parse_qstring(pctx, type, ret));
 cleanup:
	return (result);
}

static void
doc_serverid(cfg_printer_t *pctx, const cfg_type_t *type) {
	UNUSED(type);
	cfg_print_chars(pctx, "( <quoted_string> | none | hostname )", 26);
}

static cfg_type_t cfg_type_serverid = {
	"serverid", parse_serverid, NULL, doc_serverid, NULL, NULL };

697
/*%
698 699
 * Port list.
 */
700 701 702 703 704 705 706 707 708 709
static cfg_tuplefielddef_t porttuple_fields[] = {
	{ "loport", &cfg_type_uint32, 0 },
	{ "hiport", &cfg_type_uint32, 0 },
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_porttuple = {
	"porttuple", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, porttuple_fields
};

710
static isc_result_t
711
parse_port(cfg_parser_t *pctx, cfg_obj_t **ret) {
712
	isc_result_t result;
Automatic Updater's avatar
Automatic Updater committed
713

714 715 716 717 718 719
	CHECK(cfg_parse_uint32(pctx, NULL, ret));
	if ((*ret)->value.uint32 > 0xffff) {
		cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid port");
		cfg_obj_destroy(pctx, ret);
		result = ISC_R_RANGE;
	}
Automatic Updater's avatar
Automatic Updater committed
720

721 722 723 724
 cleanup:
	return (result);
}

725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
static isc_result_t
parse_portrange(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
	isc_result_t result;
	cfg_obj_t *obj = NULL;

	UNUSED(type);

	CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
	if (pctx->token.type == isc_tokentype_number)
		CHECK(parse_port(pctx, ret));
	else {
		CHECK(cfg_gettoken(pctx, 0));
		if (pctx->token.type != isc_tokentype_string ||
		    strcasecmp(TOKEN_STRING(pctx), "range") != 0) {
			cfg_parser_error(pctx, CFG_LOG_NEAR,
					 "expected integer or 'range'");
			return (ISC_R_UNEXPECTEDTOKEN);
		}
		CHECK(cfg_create_tuple(pctx, &cfg_type_porttuple, &obj));
		CHECK(parse_port(pctx, &obj->value.tuple[0]));
		CHECK(parse_port(pctx, &obj->value.tuple[1]));
		if (obj->value.tuple[0]->value.uint32 >
		    obj->value.tuple[1]->value.uint32) {
			cfg_parser_error(pctx, CFG_LOG_NOPREP,
					 "low port '%u' must not be larger "
					 "than high port",
					 obj->value.tuple[0]->value.uint32);
			result = ISC_R_RANGE;
			goto cleanup;
		}
		*ret = obj;
		obj = NULL;
	}

 cleanup:
	if (obj != NULL)
		cfg_obj_destroy(pctx, &obj);
	return (result);
}

static cfg_type_t cfg_type_portrange = {
	"portrange", parse_portrange, NULL, cfg_doc_terminal,
767 768 769 770
	NULL, NULL
};

static cfg_type_t cfg_type_bracketed_portlist = {
771 772 773
	"bracketed_sockaddrlist", cfg_parse_bracketed_list,
	cfg_print_bracketed_list, cfg_doc_bracketed_list,
	&cfg_rep_list, &cfg_type_portrange
774 775
};

776
/*%
777 778 779 780 781 782 783 784
 * Clauses that can be found within the top level of the named.conf
 * file only.
 */
static cfg_clausedef_t
namedconf_clauses[] = {
	{ "options", &cfg_type_options, 0 },
	{ "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
	{ "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
785
	{ "masters", &cfg_type_masters, CFG_CLAUSEFLAG_MULTI },
786 787 788
	{ "logging", &cfg_type_logging, 0 },
	{ "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI },
	{ "lwres", &cfg_type_lwres, CFG_CLAUSEFLAG_MULTI },
789 790
	{ "statistics-channels", &cfg_type_statschannels,
	  CFG_CLAUSEFLAG_MULTI },
791 792 793
	{ NULL, NULL, 0 }
};

794
/*%
795 796 797 798 799 800 801
 * Clauses that can occur at the top level or in the view
 * statement, but not in the options block.
 */
static cfg_clausedef_t
namedconf_or_view_clauses[] = {
	{ "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
	{ "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
802
	/* only 1 DLZ per view allowed */
Automatic Updater's avatar
Automatic Updater committed
803
	{ "dlz", &cfg_type_dynamically_loadable_zones, 0 },
804
	{ "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI },
805
	{ "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
806
	{ "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
807 808 809
	{ NULL, NULL, 0 }
};

810 811 812 813 814
/*%
 * Clauses that can occur in the bind.keys file.
 */
static cfg_clausedef_t
bindkeys_clauses[] = {
815
	{ "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
816
	{ "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
817 818 819
	{ NULL, NULL, 0 }
};

820
/*%
821 822 823 824
 * Clauses that can be found within the 'options' statement.
 */
static cfg_clausedef_t
options_clauses[] = {
825 826
	{ "use-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
	{ "use-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
827 828
	{ "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
	{ "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
829
	{ "bindkeys-file", &cfg_type_qstring, 0 },
830 831 832
	{ "blackhole", &cfg_type_bracketed_aml, 0 },
	{ "coresize", &cfg_type_size, 0 },
	{ "datasize", &cfg_type_size, 0 },
833 834 835
	{ "session-keyfile", &cfg_type_qstringornone, 0 },
	{ "session-keyname", &cfg_type_astring, 0 },
	{ "session-keyalg", &cfg_type_astring, 0 },
836 837 838 839 840 841 842 843
	{ "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
	{ "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK },
	{ "dump-file", &cfg_type_qstring, 0 },
	{ "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
	{ "files", &cfg_type_size, 0 },
	{ "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
	{ "heartbeat-interval", &cfg_type_uint32, 0 },
	{ "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP },
844
	{ "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
845 846 847 848 849 850
	{ "hostname", &cfg_type_qstringornone, 0 },
	{ "interface-interval", &cfg_type_uint32, 0 },
	{ "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
	{ "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
	{ "match-mapped-addresses", &cfg_type_boolean, 0 },
	{ "memstatistics-file", &cfg_type_qstring, 0 },
851
	{ "memstatistics", &cfg_type_boolean, 0 },
852 853 854 855
	{ "multiple-cnames", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
	{ "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
	{ "pid-file", &cfg_type_qstringornone, 0 },
	{ "port", &cfg_type_uint32, 0 },
856
	{ "querylog", &cfg_type_boolean, 0 },
857
	{ "recursing-file", &cfg_type_qstring, 0 },
858 859
	{ "random-device", &cfg_type_qstring, 0 },
	{ "recursive-clients", &cfg_type_uint32, 0 },
860
	{ "reserved-sockets", &cfg_type_uint32, 0 },
861 862
	{ "serial-queries", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
	{ "serial-query-rate", &cfg_type_uint32, 0 },
863
	{ "server-id", &cfg_type_serverid, 0 },
864 865 866 867
	{ "stacksize", &cfg_type_size, 0 },
	{ "statistics-file", &cfg_type_qstring, 0 },
	{ "statistics-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_NYI },
	{ "tcp-clients", &cfg_type_uint32, 0 },
Michael Graff's avatar
Michael Graff committed
868
	{ "tcp-listen-queue", &cfg_type_uint32, 0 },
869 870 871 872 873 874 875 876 877 878
	{ "tkey-dhkey", &cfg_type_tkey_dhkey, 0 },
	{ "tkey-gssapi-credential", &cfg_type_qstring, 0 },
	{ "tkey-domain", &cfg_type_qstring, 0 },
	{ "transfers-per-ns", &cfg_type_uint32, 0 },
	{ "transfers-in", &cfg_type_uint32, 0 },
	{ "transfers-out", &cfg_type_uint32, 0 },
	{ "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
	{ "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
	{ "use-ixfr", &cfg_type_boolean, 0 },
	{ "version", &cfg_type_qstringornone, 0 },
879
	{ "flush-zones-on-shutdown", &cfg_type_boolean, 0 },
880 881 882
#ifdef ALLOW_FILTER_AAAA_ON_V4
	{ "filter-aaaa-on-v4", &cfg_type_v4_aaaa, 0 },
#endif
883 884 885
	{ NULL, NULL, 0 }
};

886 887 888 889 890 891 892 893 894 895 896

static cfg_type_t cfg_type_namelist = {
	"namelist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
	cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_qstring };

static keyword_type_t exclude_kw = { "exclude", &cfg_type_namelist };

static cfg_type_t cfg_type_optional_exclude = {
	"optional_exclude", parse_optional_keyvalue, print_keyvalue,
	doc_optional_keyvalue, &cfg_rep_list, &exclude_kw };

897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924
static keyword_type_t exceptionnames_kw = { "except-from", &cfg_type_namelist };

static cfg_type_t cfg_type_optional_exceptionnames = {
	"optional_allow", parse_optional_keyvalue, print_keyvalue,
	doc_optional_keyvalue, &cfg_rep_list, &exceptionnames_kw };

static cfg_tuplefielddef_t denyaddresses_fields[] = {
	{ "acl", &cfg_type_bracketed_aml, 0 },
	{ "except-from", &cfg_type_optional_exceptionnames, 0 },
	{ NULL, NULL, 0 }
};

static cfg_type_t cfg_type_denyaddresses = {
	"denyaddresses", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, denyaddresses_fields
};

static cfg_tuplefielddef_t denyaliases_fields[] = {
	{ "name", &cfg_type_namelist, 0 },
	{ "except-from", &cfg_type_optional_exceptionnames, 0 },
	{ NULL, NULL, 0 }
};

static cfg_type_t cfg_type_denyaliases = {
	"denyaliases", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, denyaliases_fields
};

925 926 927 928 929 930 931 932 933 934 935 936 937 938 939
static cfg_type_t cfg_type_algorithmlist = {
	"algorithmlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
	cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring };

static cfg_tuplefielddef_t disablealgorithm_fields[] = {
	{ "name", &cfg_type_astring, 0 },
	{ "algorithms", &cfg_type_algorithmlist, 0 },
	{ NULL, NULL, 0 }
};

static cfg_type_t cfg_type_disablealgorithm = {
	"disablealgorithm", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, disablealgorithm_fields
};

940
static cfg_tuplefielddef_t mustbesecure_fields[] = {
Automatic Updater's avatar
Automatic Updater committed
941 942 943
	{ "name", &cfg_type_astring, 0 },
	{ "value", &cfg_type_boolean, 0 },
	{ NULL, NULL, 0 }
944 945 946 947 948 949 950
};

static cfg_type_t cfg_type_mustbesecure = {
	"mustbesecure", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, mustbesecure_fields
};

951 952 953 954 955 956
static const char *masterformat_enums[] = { "text", "raw", NULL };
static cfg_type_t cfg_type_masterformat = {
	"masterformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
	&cfg_rep_string, &masterformat_enums
};

Mark Andrews's avatar
Mark Andrews committed
957
/*%
958 959 960 961 962
 * dnssec-lookaside
 */

static keyword_type_t trustanchor_kw = { "trust-anchor", &cfg_type_astring };

963 964 965
static cfg_type_t cfg_type_optional_trustanchor = {
	"optional_trustanchor", parse_optional_keyvalue, print_keyvalue,
	doc_keyvalue, &cfg_rep_string, &trustanchor_kw
966 967 968 969
};

static cfg_tuplefielddef_t lookaside_fields[] = {
	{ "domain", &cfg_type_astring, 0 },
970
	{ "trust-anchor", &cfg_type_optional_trustanchor, 0 },
971 972 973 974 975 976 977 978
	{ NULL, NULL, 0 }
};

static cfg_type_t cfg_type_lookaside = {
	"lookaside", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, lookaside_fields
};

979
/*%
980 981 982 983 984 985
 * Clauses that can be found within the 'view' statement,
 * with defaults in the 'options' statement.
 */

static cfg_clausedef_t
view_clauses[] = {
986 987 988 989
	{ "acache-cleaning-interval", &cfg_type_uint32, 0 },
	{ "acache-enable", &cfg_type_boolean, 0 },
	{ "additional-from-auth", &cfg_type_boolean, 0 },
	{ "additional-from-cache", &cfg_type_boolean, 0 },
990
	{ "allow-query-cache", &cfg_type_bracketed_aml, 0 },
991
	{ "allow-query-cache-on", &cfg_type_bracketed_aml, 0 },
992
	{ "allow-recursion", &cfg_type_bracketed_aml, 0 },
993
	{ "allow-recursion-on", &cfg_type_bracketed_aml, 0 },
994 995
	{ "allow-v6-synthesis", &cfg_type_bracketed_aml,
	  CFG_CLAUSEFLAG_OBSOLETE },
996
	{ "attach-cache", &cfg_type_astring, 0 },
997 998
	{ "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT },
	{ "cache-file", &cfg_type_qstring, 0 },
999 1000 1001
	{ "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
	{ "cleaning-interval", &cfg_type_uint32, 0 },
	{ "clients-per-query", &cfg_type_uint32, 0 },
1002 1003
	{ "deny-answer-addresses", &cfg_type_denyaddresses, 0 },
	{ "deny-answer-aliases", &cfg_type_denyaliases, 0 },
1004 1005
	{ "disable-algorithms", &cfg_type_disablealgorithm,
	  CFG_CLAUSEFLAG_MULTI },
1006 1007
	{ "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI },
	{ "dnssec-accept-expired", &cfg_type_boolean, 0 },
1008
	{ "dnssec-enable", &cfg_type_boolean, 0 },
1009
	{ "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI },
1010
	{ "dnssec-must-be-secure",  &cfg_type_mustbesecure,
1011 1012 1013 1014 1015 1016 1017 1018
	  CFG_CLAUSEFLAG_MULTI },
	{ "dnssec-validation", &cfg_type_boolean, 0 },
	{ "dual-stack-servers", &cfg_type_nameportiplist, 0 },
	{ "edns-udp-size", &cfg_type_uint32, 0 },
	{ "empty-contact", &cfg_type_astring, 0 },
	{ "empty-server", &cfg_type_astring, 0 },
	{ "empty-zones-enable", &cfg_type_boolean, 0 },
	{ "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1019
	{ "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 },
1020
	{ "lame-ttl", &cfg_type_uint32, 0 },
1021
	{ "max-acache-size", &cfg_type_sizenodefault, 0 },
1022
	{ "max-cache-size", &cfg_type_sizenodefault, 0 },
1023
	{ "max-cache-ttl", &cfg_type_uint32, 0 },
1024
	{ "max-clients-per-query", &cfg_type_uint32, 0 },
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
	{ "max-ncache-ttl", &cfg_type_uint32, 0 },
	{ "max-udp-size", &cfg_type_uint32, 0 },
	{ "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
	{ "minimal-responses", &cfg_type_boolean, 0 },
	{ "preferred-glue", &cfg_type_astring, 0 },
	{ "provide-ixfr", &cfg_type_boolean, 0 },
	/*
	 * Note that the query-source option syntax is different
	 * from the other -source options.
	 */
	{ "query-source", &cfg_type_querysource4, 0 },
	{ "query-source-v6", &cfg_type_querysource6, 0 },
1037 1038 1039
	{ "queryport-pool-ports", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
	{ "queryport-pool-updateinterval", &cfg_type_uint32,
	  CFG_CLAUSEFLAG_OBSOLETE },
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
	{ "recursion", &cfg_type_boolean, 0 },
	{ "request-ixfr", &cfg_type_boolean, 0 },
	{ "request-nsid", &cfg_type_boolean, 0 },
	{ "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
	{ "root-delegation-only",  &cfg_type_optional_exclude, 0 },
	{ "rrset-order", &cfg_type_rrsetorder, 0 },
	{ "sortlist", &cfg_type_bracketed_aml, 0 },
	{ "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
	{ "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP },
	{ "transfer-format", &cfg_type_transferformat, 0 },
1050
	{ "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1051
	{ "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
1052 1053 1054
	{ NULL, NULL, 0 }
};

1055
/*%
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
 * Clauses that can be found within the 'view' statement only.
 */
static cfg_clausedef_t
view_only_clauses[] = {
	{ "match-clients", &cfg_type_bracketed_aml, 0 },
	{ "match-destinations", &cfg_type_bracketed_aml, 0 },
	{ "match-recursive-only", &cfg_type_boolean, 0 },
	{ NULL, NULL, 0 }
};

1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
/*%
 * Sig-validity-interval.
 */
static isc_result_t
parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type,
		      cfg_obj_t **ret)
{
	isc_result_t result;
	UNUSED(type);

	CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
	if (pctx->token.type == isc_tokentype_number) {
		CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret));
	} else {
		CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
	}
 cleanup:
	return (result);
}

static void
doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) {
	UNUSED(type);
	cfg_print_chars(pctx, "[ <integer> ]", 13);
}

static cfg_type_t cfg_type_optional_uint32 = {
	"optional_uint32", parse_optional_uint32, NULL, doc_optional_uint32,
	NULL, NULL };

static cfg_tuplefielddef_t validityinterval_fields[] = {
	{ "validity", &cfg_type_uint32, 0 },
	{ "re-sign", &cfg_type_optional_uint32, 0 },
	{ NULL, NULL, 0 }
};

static cfg_type_t cfg_type_validityinterval = {
	"validityinterval", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, validityinterval_fields
};

1107
/*%
1108 1109 1110 1111 1112
 * Clauses that can be found in a 'zone' statement,
 * with defaults in the 'view' or 'options' statement.
 */
static cfg_clausedef_t
zone_clauses[] = {
1113
	{ "allow-notify", &cfg_type_bracketed_aml, 0 },
1114
	{ "allow-query", &cfg_type_bracketed_aml, 0 },
1115
	{ "allow-query-on", &cfg_type_bracketed_aml, 0 },
1116
	{ "allow-transfer", &cfg_type_bracketed_aml, 0 },
1117
	{ "allow-update", &cfg_type_bracketed_aml, 0 },
1118 1119
	{ "allow-update-forwarding", &cfg_type_bracketed_aml, 0 },
	{ "also-notify", &cfg_type_portiplist, 0 },
1120 1121 1122 1123 1124 1125 1126 1127
	{ "alt-transfer-source", &cfg_type_sockaddr4wild, 0 },
	{ "alt-transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
	{ "check-integrity", &cfg_type_boolean, 0 },
	{ "check-mx", &cfg_type_checkmode, 0 },
	{ "check-mx-cname", &cfg_type_checkmode, 0 },
	{ "check-sibling", &cfg_type_boolean, 0 },
	{ "check-srv-cname", &cfg_type_checkmode, 0 },
	{ "check-wildcard", &cfg_type_boolean, 0 },
1128
	{ "dialup", &cfg_type_dialuptype, 0 },
1129
	{ "dnskey-ksk-only", &cfg_type_boolean, 0 },
1130 1131
	{ "forward", &cfg_type_forwardtype, 0 },
	{ "forwarders", &cfg_type_portiplist, 0 },
1132
	{ "key-directory", &cfg_type_qstring, 0 },
1133
	{ "maintain-ixfr-base", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1134
	{ "masterfile-format", &cfg_type_masterformat, 0 },
1135
	{ "max-ixfr-log-size", &cfg_type_size, CFG_CLAUSEFLAG_OBSOLETE },
1136
	{ "max-journal-size", &cfg_type_sizenodefault, 0 },
1137 1138
	{ "max-refresh-time", &cfg_type_uint32, 0 },
	{ "max-retry-time", &cfg_type_uint32, 0 },
1139 1140
	{ "max-transfer-idle-in", &cfg_type_uint32, 0 },
	{ "max-transfer-idle-out", &cfg_type_uint32, 0 },
1141 1142
	{ "max-transfer-time-in", &cfg_type_uint32, 0 },
	{ "max-transfer-time-out", &cfg_type_uint32, 0 },
1143
	{ "min-refresh-time", &cfg_type_uint32, 0 },
1144
	{ "min-retry-time", &cfg_type_uint32, 0 },
1145
	{ "multi-master", &cfg_type_boolean, 0 },
1146 1147 1148 1149 1150
	{ "notify", &cfg_type_notifytype, 0 },
	{ "notify-delay", &cfg_type_uint32, 0 },
	{ "notify-source", &cfg_type_sockaddr4wild, 0 },
	{ "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
	{ "notify-to-soa", &cfg_type_boolean, 0 },
1151
	{ "nsec3-test-zone", &cfg_type_boolean, CFG_CLAUSEFLAG_TESTONLY },
1152
	{ "secure-to-insecure", &cfg_type_boolean, 0 },
1153 1154 1155 1156
	{ "sig-signing-nodes", &cfg_type_uint32, 0 },
	{ "sig-signing-signatures", &cfg_type_uint32, 0 },
	{ "sig-signing-type", &cfg_type_uint32, 0 },
	{ "sig-validity-interval", &cfg_type_validityinterval, 0 },
1157 1158
	{ "transfer-source", &cfg_type_sockaddr4wild, 0 },
	{ "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
1159 1160
	{ "try-tcp-refresh", &cfg_type_boolean, 0 },
	{ "update-check-ksk", &cfg_type_boolean, 0 },
1161
	{ "use-alt-transfer-source", &cfg_type_boolean, 0 },
1162
	{ "zero-no-soa-ttl", &cfg_type_boolean, 0 },
1163
	{ "zone-statistics", &cfg_type_boolean, 0 },
1164 1165 1166
	{ NULL, NULL, 0 }
};

1167
/*%
1168 1169 1170 1171 1172 1173 1174
 * Clauses that can be found in a 'zone' statement
 * only.
 */
static cfg_clausedef_t
zone_only_clauses[] = {
	{ "type", &cfg_type_zonetype, 0 },
	{ "file", &cfg_type_qstring, 0 },
1175
	{ "journal", &cfg_type_qstring, 0 },
1176 1177
	{ "ixfr-base", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
	{ "ixfr-tmp-file", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
1178
	{ "masters", &cfg_type_namesockaddrkeylist, 0 },
1179 1180 1181 1182
	{ "pubkey", &cfg_type_pubkey,
	  CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE },
	{ "update-policy", &cfg_type_updatepolicy, 0 },
	{ "database", &cfg_type_astring, 0 },
1183
	{ "delegation-only", &cfg_type_boolean, 0 },
1184 1185 1186