namedconf.c 118 KB
Newer Older
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
5
6
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8
9
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
10
11
 */

12
/*! \file */
13

14
#include <inttypes.h>
15
#include <stdbool.h>
Evan Hunt's avatar
Evan Hunt committed
16
#include <stdlib.h>
17
18
19
#include <string.h>

#include <isc/lex.h>
20
#include <isc/mem.h>
21
#include <isc/print.h>
22
23
24
25
#include <isc/result.h>
#include <isc/string.h>
#include <isc/util.h>

Evan Hunt's avatar
Evan Hunt committed
26
#include <dns/result.h>
27
#include <dns/ttl.h>
Evan Hunt's avatar
Evan Hunt committed
28

29
30
31
#include <isccfg/cfg.h>
#include <isccfg/grammar.h>
#include <isccfg/log.h>
32
#include <isccfg/namedconf.h>
33

34
35
#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)

36
/*% Check a return value. */
37
38
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
49
#define CLEANUP_OBJ(obj)                               \
	do {                                           \
		if ((obj) != NULL)                     \
			cfg_obj_destroy(pctx, &(obj)); \
	} while (0)
50

51
/*%
52
53
54
 * Forward declarations of static functions.
 */

Ondřej Surý's avatar
Ondřej Surý committed
55
56
static isc_result_t
parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
57

Ondřej Surý's avatar
Ondřej Surý committed
58
59
60
static isc_result_t
parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
			cfg_obj_t **ret);
61

Ondřej Surý's avatar
Ondřej Surý committed
62
63
64
65
static isc_result_t
parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
static void
print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj);
66

Ondřej Surý's avatar
Ondřej Surý committed
67
68
static void
doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type);
69

Ondřej Surý's avatar
Ondřej Surý committed
70
71
static void
print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj);
72

Ondřej Surý's avatar
Ondřej Surý committed
73
74
static void
doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
75

Ondřej Surý's avatar
Ondřej Surý committed
76
77
static void
doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
78
79

static cfg_type_t cfg_type_acl;
Evan Hunt's avatar
Evan Hunt committed
80
static cfg_type_t cfg_type_bracketed_dscpsockaddrlist;
81
static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
82
static cfg_type_t cfg_type_bracketed_netaddrlist;
83
static cfg_type_t cfg_type_bracketed_sockaddrnameportlist;
84
85
86
87
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;
88
static cfg_type_t cfg_type_dlz;
89
static cfg_type_t cfg_type_dnssecpolicy;
90
91
92
static cfg_type_t cfg_type_dnstap;
static cfg_type_t cfg_type_dnstapoutput;
static cfg_type_t cfg_type_dyndb;
93
static cfg_type_t cfg_type_plugin;
94
static cfg_type_t cfg_type_ixfrdifftype;
95
static cfg_type_t cfg_type_ixfrratio;
96
97
98
99
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;
100
static cfg_type_t cfg_type_logsuffix;
101
static cfg_type_t cfg_type_logversions;
102
static cfg_type_t cfg_type_masterselement;
103
static cfg_type_t cfg_type_maxduration;
104
static cfg_type_t cfg_type_minimal;
105
106
static cfg_type_t cfg_type_nameportiplist;
static cfg_type_t cfg_type_notifytype;
107
static cfg_type_t cfg_type_optional_allow;
108
static cfg_type_t cfg_type_optional_class;
109
static cfg_type_t cfg_type_optional_dscp;
110
static cfg_type_t cfg_type_optional_facility;
111
static cfg_type_t cfg_type_optional_keyref;
112
static cfg_type_t cfg_type_optional_port;
Evan Hunt's avatar
Evan Hunt committed
113
static cfg_type_t cfg_type_optional_uint32;
114
static cfg_type_t cfg_type_options;
115
static cfg_type_t cfg_type_portiplist;
116
static cfg_type_t cfg_type_printtime;
Witold Krecicki's avatar
Witold Krecicki committed
117
static cfg_type_t cfg_type_qminmethod;
118
119
120
static cfg_type_t cfg_type_querysource4;
static cfg_type_t cfg_type_querysource6;
static cfg_type_t cfg_type_querysource;
121
122
123
124
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;
125
static cfg_type_t cfg_type_sizeorpercent;
126
static cfg_type_t cfg_type_sizeval;
127
128
static cfg_type_t cfg_type_sockaddr4wild;
static cfg_type_t cfg_type_sockaddr6wild;
129
static cfg_type_t cfg_type_statschannels;
130
131
static cfg_type_t cfg_type_view;
static cfg_type_t cfg_type_viewopts;
132
133
static cfg_type_t cfg_type_zone;

134
/*% tkey-dhkey */
135
136
137
138
139
140
141

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

142
143
144
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 };
145

146
/*% listen-on */
147
148
149

static cfg_tuplefielddef_t listenon_fields[] = {
	{ "port", &cfg_type_optional_port, 0 },
Evan Hunt's avatar
Evan Hunt committed
150
	{ "dscp", &cfg_type_optional_dscp, 0 },
151
152
153
	{ "acl", &cfg_type_bracketed_aml, 0 },
	{ NULL, NULL, 0 }
};
Evan Hunt's avatar
Evan Hunt committed
154

155
156
157
static cfg_type_t cfg_type_listenon = { "listenon",	 cfg_parse_tuple,
					cfg_print_tuple, cfg_doc_tuple,
					&cfg_rep_tuple,	 listenon_fields };
158

159
/*% acl */
160

161
162
163
164
static cfg_tuplefielddef_t acl_fields[] = { { "name", &cfg_type_astring, 0 },
					    { "value", &cfg_type_bracketed_aml,
					      0 },
					    { NULL, NULL, 0 } };
165

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

170
/*% masters */
171
172
173
static cfg_tuplefielddef_t masters_fields[] = {
	{ "name", &cfg_type_astring, 0 },
	{ "port", &cfg_type_optional_port, 0 },
Evan Hunt's avatar
Evan Hunt committed
174
	{ "dscp", &cfg_type_optional_dscp, 0 },
175
176
177
178
	{ "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
	{ NULL, NULL, 0 }
};

179
180
181
static cfg_type_t cfg_type_masters = { "masters",	cfg_parse_tuple,
				       cfg_print_tuple, cfg_doc_tuple,
				       &cfg_rep_tuple,	masters_fields };
182

183
/*%
184
185
186
 * "sockaddrkeylist", a list of socket addresses with optional keys
 * and an optional default port, as used in the masters option.
 * E.g.,
187
 *   "port 1234 { mymasters; 10.0.0.1 key foo; 1::2 port 69; }"
188
189
 */

190
191
static cfg_tuplefielddef_t namesockaddrkey_fields[] = {
	{ "masterselement", &cfg_type_masterselement, 0 },
192
193
194
195
	{ "key", &cfg_type_optional_keyref, 0 },
	{ NULL, NULL, 0 },
};

196
static cfg_type_t cfg_type_namesockaddrkey = {
197
198
	"namesockaddrkey", cfg_parse_tuple, cfg_print_tuple,
	cfg_doc_tuple,	   &cfg_rep_tuple,  namesockaddrkey_fields
199
200
};

201
static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = {
202
203
204
205
206
	"bracketed_namesockaddrkeylist",
	cfg_parse_bracketed_list,
	cfg_print_bracketed_list,
	cfg_doc_bracketed_list,
	&cfg_rep_list,
207
	&cfg_type_namesockaddrkey
208
209
};

210
static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = {
211
	{ "port", &cfg_type_optional_port, 0 },
Evan Hunt's avatar
Evan Hunt committed
212
	{ "dscp", &cfg_type_optional_dscp, 0 },
213
	{ "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
214
215
	{ NULL, NULL, 0 }
};
216
static cfg_type_t cfg_type_namesockaddrkeylist = {
217
218
	"sockaddrkeylist", cfg_parse_tuple, cfg_print_tuple,
	cfg_doc_tuple,	   &cfg_rep_tuple,  namesockaddrkeylist_fields
219
220
};

221
/*%
222
 * A list of socket addresses with an optional default port, as used
223
 * in the 'listen-on' option.  E.g., "{ 10.0.0.1; 1::2 port 69; }"
224
225
226
 */
static cfg_tuplefielddef_t portiplist_fields[] = {
	{ "port", &cfg_type_optional_port, 0 },
Evan Hunt's avatar
Evan Hunt committed
227
228
	{ "dscp", &cfg_type_optional_dscp, 0 },
	{ "addresses", &cfg_type_bracketed_dscpsockaddrlist, 0 },
229
230
	{ NULL, NULL, 0 }
};
231
232
233
static cfg_type_t cfg_type_portiplist = { "portiplist",	   cfg_parse_tuple,
					  cfg_print_tuple, cfg_doc_tuple,
					  &cfg_rep_tuple,  portiplist_fields };
234

235
236
/*
 * Obsolete format for the "pubkey" statement.
237
238
 */
static cfg_tuplefielddef_t pubkey_fields[] = {
239
240
241
242
243
	{ "flags", &cfg_type_uint32, 0 },
	{ "protocol", &cfg_type_uint32, 0 },
	{ "algorithm", &cfg_type_uint32, 0 },
	{ "key", &cfg_type_qstring, 0 },
	{ NULL, NULL, 0 }
244
};
245
246
247
static cfg_type_t cfg_type_pubkey = { "pubkey",	       cfg_parse_tuple,
				      cfg_print_tuple, cfg_doc_tuple,
				      &cfg_rep_tuple,  pubkey_fields };
248

249
/*%
250
251
252
253
 * 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 = {
254
255
	"rrtypelist",	  cfg_parse_spacelist, cfg_print_spacelist,
	cfg_doc_terminal, &cfg_rep_list,       &cfg_type_astring
256
257
};

258
static const char *mode_enums[] = { "deny", "grant", NULL };
Evan Hunt's avatar
Evan Hunt committed
259
260
261
static cfg_type_t cfg_type_mode = {
	"mode",	      cfg_parse_enum,  cfg_print_ustring,
	cfg_doc_enum, &cfg_rep_string, &mode_enums
262
263
};

264
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
265
parse_matchtype(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
266
267
268
269
	isc_result_t result;

	CHECK(cfg_peektoken(pctx, 0));
	if (pctx->token.type == isc_tokentype_string &&
Evan Hunt's avatar
Evan Hunt committed
270
271
	    strcasecmp(TOKEN_STRING(pctx), "zonesub") == 0)
	{
Automatic Updater's avatar
Automatic Updater committed
272
		pctx->flags |= CFG_PCTX_SKIP;
273
274
275
	}
	return (cfg_parse_enum(pctx, type, ret));

276
cleanup:
277
278
279
280
	return (result);
}

static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
281
parse_matchname(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
282
	isc_result_t result;
Evan Hunt's avatar
Evan Hunt committed
283
	cfg_obj_t *obj = NULL;
284
285
286
287

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

	*ret = obj;
293
cleanup:
294
295
296
	return (result);
}

297
static void
Evan Hunt's avatar
Evan Hunt committed
298
doc_matchname(cfg_printer_t *pctx, const cfg_type_t *type) {
299
	cfg_print_cstr(pctx, "[ ");
300
	cfg_doc_obj(pctx, type->of);
301
	cfg_print_cstr(pctx, " ]");
302
303
}

304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
static const char *matchtype_enums[] = { "6to4-self",
					 "external",
					 "krb5-self",
					 "krb5-selfsub",
					 "krb5-subdomain",
					 "ms-self",
					 "ms-selfsub",
					 "ms-subdomain",
					 "name",
					 "self",
					 "selfsub",
					 "selfwild",
					 "subdomain",
					 "tcp-self",
					 "wildcard",
					 "zonesub",
					 NULL };

static cfg_type_t cfg_type_matchtype = { "matchtype",	    parse_matchtype,
					 cfg_print_ustring, cfg_doc_enum,
					 &cfg_rep_string,   &matchtype_enums };
325
326
327

static cfg_type_t cfg_type_matchname = {
	"optional_matchname", parse_matchname, cfg_print_ustring,
328
	doc_matchname,	      &cfg_rep_tuple,  &cfg_type_ustring
329
330
};

331
/*%
332
333
334
335
 * 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
336
	{ "identity", &cfg_type_astring, 0 }, /* domain name */
337
	{ "matchtype", &cfg_type_matchtype, 0 },
338
	{ "name", &cfg_type_matchname, 0 }, /* domain name */
339
340
341
	{ "types", &cfg_type_rrtypelist, 0 },
	{ NULL, NULL, 0 }
};
342
343
344
static cfg_type_t cfg_type_grant = { "grant",	      cfg_parse_tuple,
				     cfg_print_tuple, cfg_doc_tuple,
				     &cfg_rep_tuple,  grant_fields };
345
346

static cfg_type_t cfg_type_updatepolicy = {
347
348
	"update_policy",  parse_updatepolicy, print_updatepolicy,
	doc_updatepolicy, &cfg_rep_list,      &cfg_type_grant
349
350
};

351
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
352
353
parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
		   cfg_obj_t **ret) {
354
355
356
	isc_result_t result;
	CHECK(cfg_gettoken(pctx, 0));
	if (pctx->token.type == isc_tokentype_special &&
Evan Hunt's avatar
Evan Hunt committed
357
358
	    pctx->token.value.as_char == '{')
	{
359
		cfg_ungettoken(pctx);
360
361
362
363
		return (cfg_parse_bracketed_list(pctx, type, ret));
	}

	if (pctx->token.type == isc_tokentype_string &&
Evan Hunt's avatar
Evan Hunt committed
364
365
	    strcasecmp(TOKEN_STRING(pctx), "local") == 0)
	{
366
367
368
		cfg_obj_t *obj = NULL;
		CHECK(cfg_create_obj(pctx, &cfg_type_ustring, &obj));
		obj->value.string.length = strlen("local");
369
370
		obj->value.string.base =
			isc_mem_get(pctx->mctx, obj->value.string.length + 1);
371
		memmove(obj->value.string.base, "local", 5);
372
373
374
375
376
377
378
379
		obj->value.string.base[5] = '\0';
		*ret = obj;
		return (ISC_R_SUCCESS);
	}

	cfg_ungettoken(pctx);
	return (ISC_R_UNEXPECTEDTOKEN);

380
cleanup:
381
382
383
	return (result);
}

Mark Andrews's avatar
Mark Andrews committed
384
static void
Evan Hunt's avatar
Evan Hunt committed
385
print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj) {
386
	if (cfg_obj_isstring(obj)) {
Mark Andrews's avatar
Mark Andrews committed
387
		cfg_print_ustring(pctx, obj);
388
	} else {
Mark Andrews's avatar
Mark Andrews committed
389
		cfg_print_bracketed_list(pctx, obj);
390
	}
Mark Andrews's avatar
Mark Andrews committed
391
392
}

393
static void
Evan Hunt's avatar
Evan Hunt committed
394
doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type) {
395
	cfg_print_cstr(pctx, "( local | { ");
396
	cfg_doc_obj(pctx, type->of);
397
	cfg_print_cstr(pctx, "; ... }");
398
399
}

400
/*%
401
402
403
404
405
406
407
408
 * 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 }
};
409
410
411
static cfg_type_t cfg_type_view = { "view",	     cfg_parse_tuple,
				    cfg_print_tuple, cfg_doc_tuple,
				    &cfg_rep_tuple,  view_fields };
412

413
/*%
414
415
416
417
418
419
420
421
 * 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 }
};
422
423
424
static cfg_type_t cfg_type_zone = { "zone",	     cfg_parse_tuple,
				    cfg_print_tuple, cfg_doc_tuple,
				    &cfg_rep_tuple,  zone_fields };
425

426
427
428
429
430
431
432
433
434
435
/*%
 * A dnssec-policy statement.
 */
static cfg_tuplefielddef_t dnssecpolicy_fields[] = {
	{ "name", &cfg_type_astring, 0 },
	{ "options", &cfg_type_dnssecpolicyopts, 0 },
	{ NULL, NULL, 0 }
};

static cfg_type_t cfg_type_dnssecpolicy = {
436
437
	"dnssec-policy", cfg_parse_tuple, cfg_print_tuple,
	cfg_doc_tuple,	 &cfg_rep_tuple,  dnssecpolicy_fields
438
439
};

440
/*%
441
442
443
444
 * A "category" clause in the "logging" statement.
 */
static cfg_tuplefielddef_t category_fields[] = {
	{ "name", &cfg_type_astring, 0 },
445
	{ "destinations", &cfg_type_destinationlist, 0 },
446
447
	{ NULL, NULL, 0 }
};
448
449
450
static cfg_type_t cfg_type_category = { "category",	 cfg_parse_tuple,
					cfg_print_tuple, cfg_doc_tuple,
					&cfg_rep_tuple,	 category_fields };
451

452
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
453
parse_maxduration(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
454
455
456
457
	return (cfg_parse_enum_or_other(pctx, type, &cfg_type_duration, ret));
}

static void
Evan Hunt's avatar
Evan Hunt committed
458
doc_maxduration(cfg_printer_t *pctx, const cfg_type_t *type) {
459
460
461
462
463
464
465
	cfg_doc_enum_or_other(pctx, type, &cfg_type_duration);
}

/*%
 * A duration or "unlimited", but not "default".
 */
static const char *maxduration_enums[] = { "unlimited", NULL };
Evan Hunt's avatar
Evan Hunt committed
466
467
468
static cfg_type_t cfg_type_maxduration = {
	"maxduration_no_default", parse_maxduration, cfg_print_ustring,
	doc_maxduration,	  &cfg_rep_duration, maxduration_enums
469
};
470

471
/*%
472
 * A dnssec key, as used in the "trusted-keys" statement.
473
 */
474
static cfg_tuplefielddef_t dnsseckey_fields[] = {
475
	{ "name", &cfg_type_astring, 0 },
476
	{ "anchortype", &cfg_type_void, 0 },
477
478
479
	{ "rdata1", &cfg_type_uint32, 0 },
	{ "rdata2", &cfg_type_uint32, 0 },
	{ "rdata3", &cfg_type_uint32, 0 },
480
	{ "data", &cfg_type_qstring, 0 },
481
482
	{ NULL, NULL, 0 }
};
483
484
485
static cfg_type_t cfg_type_dnsseckey = { "dnsseckey",	  cfg_parse_tuple,
					 cfg_print_tuple, cfg_doc_tuple,
					 &cfg_rep_tuple,  dnsseckey_fields };
486

Matthijs Mekking's avatar
Matthijs Mekking committed
487
488
489
490
491
/*%
 * Optional enums.
 *
 */
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
492
493
parse_optional_enum(cfg_parser_t *pctx, const cfg_type_t *type,
		    cfg_obj_t **ret) {
Matthijs Mekking's avatar
Matthijs Mekking committed
494
495
496
497
	return (cfg_parse_enum_or_other(pctx, type, &cfg_type_void, ret));
}

static void
Evan Hunt's avatar
Evan Hunt committed
498
doc_optional_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
Matthijs Mekking's avatar
Matthijs Mekking committed
499
500
501
502
503
504
	UNUSED(type);
	cfg_print_cstr(pctx, "[ ");
	cfg_doc_enum(pctx, type);
	cfg_print_cstr(pctx, " ]");
}

505
/*%
506
 * A key initialization specifier, as used in the
507
 * "trust-anchors" (or synonymous "managed-keys") statement.
508
 */
509
510
static const char *anchortype_enums[] = { "static-key", "initial-key",
					  "static-ds", "initial-ds", NULL };
Evan Hunt's avatar
Evan Hunt committed
511
512
513
static cfg_type_t cfg_type_anchortype = { "anchortype",	     cfg_parse_enum,
					  cfg_print_ustring, cfg_doc_enum,
					  &cfg_rep_string,   anchortype_enums };
514
515
static cfg_tuplefielddef_t managedkey_fields[] = {
	{ "name", &cfg_type_astring, 0 },
516
	{ "anchortype", &cfg_type_anchortype, 0 },
517
518
519
	{ "rdata1", &cfg_type_uint32, 0 },
	{ "rdata2", &cfg_type_uint32, 0 },
	{ "rdata3", &cfg_type_uint32, 0 },
520
	{ "data", &cfg_type_qstring, 0 },
521
522
	{ NULL, NULL, 0 }
};
523
524
525
static cfg_type_t cfg_type_managedkey = { "managedkey",	   cfg_parse_tuple,
					  cfg_print_tuple, cfg_doc_tuple,
					  &cfg_rep_tuple,  managedkey_fields };
526

527
528
529
530
/*%
 * DNSSEC key roles.
 */
static const char *dnsseckeyrole_enums[] = { "csk", "ksk", "zsk", NULL };
Evan Hunt's avatar
Evan Hunt committed
531
532
533
static cfg_type_t cfg_type_dnsseckeyrole = {
	"dnssec-key-role", cfg_parse_enum,  cfg_print_ustring,
	cfg_doc_enum,	   &cfg_rep_string, &dnsseckeyrole_enums
534
535
536
537
538
539
};

/*%
 * DNSSEC key storage types.
 */
static const char *dnsseckeystore_enums[] = { "key-directory", NULL };
Evan Hunt's avatar
Evan Hunt committed
540
541
542
static cfg_type_t cfg_type_dnsseckeystore = {
	"dnssec-key-storage", parse_optional_enum, cfg_print_ustring,
	doc_optional_enum,    &cfg_rep_string,	   dnsseckeystore_enums
543
544
545
546
547
};

/*%
 * A dnssec key, as used in the "keys" statement in a "dnssec-policy".
 */
548
static keyword_type_t algorithm_kw = { "algorithm", &cfg_type_ustring };
Evan Hunt's avatar
Evan Hunt committed
549
550
551
static cfg_type_t cfg_type_algorithm = { "algorithm",	  parse_keyvalue,
					 print_keyvalue,  doc_keyvalue,
					 &cfg_rep_string, &algorithm_kw };
552

553
554
static keyword_type_t lifetime_kw = { "lifetime",
				      &cfg_type_duration_or_unlimited };
Evan Hunt's avatar
Evan Hunt committed
555
556
557
static cfg_type_t cfg_type_lifetime = { "lifetime",	   parse_keyvalue,
					print_keyvalue,	   doc_keyvalue,
					&cfg_rep_duration, &lifetime_kw };
558

559
560
561
static cfg_tuplefielddef_t kaspkey_fields[] = {
	{ "role", &cfg_type_dnsseckeyrole, 0 },
	{ "keystore-type", &cfg_type_dnsseckeystore, 0 },
562
563
	{ "lifetime", &cfg_type_lifetime, 0 },
	{ "algorithm", &cfg_type_algorithm, 0 },
564
565
566
	{ "length", &cfg_type_optional_uint32, 0 },
	{ NULL, NULL, 0 }
};
567
568
569
static cfg_type_t cfg_type_kaspkey = { "kaspkey",	cfg_parse_tuple,
				       cfg_print_tuple, cfg_doc_tuple,
				       &cfg_rep_tuple,	kaspkey_fields };
570

571
572
573
/*%
 * Wild class, type, name.
 */
574
575
576
577
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,
578
	doc_optional_keyvalue, &cfg_rep_string,		&wild_class_kw
579
580
581
582
583
};

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

static cfg_type_t cfg_type_optional_wild_type = {
584
585
	"optional_wild_type",  parse_optional_keyvalue, print_keyvalue,
	doc_optional_keyvalue, &cfg_rep_string,		&wild_type_kw
586
587
588
589
590
};

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

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

595
/*%
596
597
598
599
600
601
 * 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
602
	{ "order", &cfg_type_ustring, 0 }, /* must be literal "order" */
603
604
605
606
	{ "ordering", &cfg_type_ustring, 0 },
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_rrsetorderingelement = {
607
	"rrsetorderingelement", cfg_parse_tuple, cfg_print_tuple,
608
	cfg_doc_tuple,		&cfg_rep_tuple,	 rrsetorderingelement_fields
609
610
};

611
/*%
612
613
614
 * A global or view "check-names" option.  Note that the zone
 * "check-names" option has a different syntax.
 */
615

616
617
static const char *checktype_enums[] = { "primary", "master",	"secondary",
					 "slave",   "response", NULL };
Evan Hunt's avatar
Evan Hunt committed
618
619
620
static cfg_type_t cfg_type_checktype = { "checktype",	    cfg_parse_enum,
					 cfg_print_ustring, cfg_doc_enum,
					 &cfg_rep_string,   &checktype_enums };
621
622

static const char *checkmode_enums[] = { "fail", "warn", "ignore", NULL };
Evan Hunt's avatar
Evan Hunt committed
623
624
625
static cfg_type_t cfg_type_checkmode = { "checkmode",	    cfg_parse_enum,
					 cfg_print_ustring, cfg_doc_enum,
					 &cfg_rep_string,   &checkmode_enums };
626

627
static const char *warn_enums[] = { "warn", "ignore", NULL };
Evan Hunt's avatar
Evan Hunt committed
628
629
630
static cfg_type_t cfg_type_warn = {
	"warn",	      cfg_parse_enum,  cfg_print_ustring,
	cfg_doc_enum, &cfg_rep_string, &warn_enums
631
632
};

633
static cfg_tuplefielddef_t checknames_fields[] = {
634
635
	{ "type", &cfg_type_checktype, 0 },
	{ "mode", &cfg_type_checkmode, 0 },
636
637
	{ NULL, NULL, 0 }
};
638

639
640
641
static cfg_type_t cfg_type_checknames = { "checknames",	   cfg_parse_tuple,
					  cfg_print_tuple, cfg_doc_tuple,
					  &cfg_rep_tuple,  checknames_fields };
Evan Hunt's avatar
Evan Hunt committed
642
643

static cfg_type_t cfg_type_bracketed_dscpsockaddrlist = {
644
645
646
647
648
	"bracketed_sockaddrlist",
	cfg_parse_bracketed_list,
	cfg_print_bracketed_list,
	cfg_doc_bracketed_list,
	&cfg_rep_list,
Evan Hunt's avatar
Evan Hunt committed
649
	&cfg_type_sockaddrdscp
650
651
};

652
653
654
655
656
657
static cfg_type_t cfg_type_bracketed_netaddrlist = { "bracketed_netaddrlist",
						     cfg_parse_bracketed_list,
						     cfg_print_bracketed_list,
						     cfg_doc_bracketed_list,
						     &cfg_rep_list,
						     &cfg_type_netaddr };
658

659
static const char *autodnssec_enums[] = { "allow", "maintain", "off", NULL };
Evan Hunt's avatar
Evan Hunt committed
660
661
662
static cfg_type_t cfg_type_autodnssec = {
	"autodnssec", cfg_parse_enum,  cfg_print_ustring,
	cfg_doc_enum, &cfg_rep_string, &autodnssec_enums
663
664
};

665
static const char *dnssecupdatemode_enums[] = { "maintain", "no-resign", NULL };
Evan Hunt's avatar
Evan Hunt committed
666
667
668
static cfg_type_t cfg_type_dnssecupdatemode = {
	"dnssecupdatemode", cfg_parse_enum,  cfg_print_ustring,
	cfg_doc_enum,	    &cfg_rep_string, &dnssecupdatemode_enums
669
670
};

671
672
static const char *updatemethods_enums[] = { "date", "increment", "unixtime",
					     NULL };
Evan Hunt's avatar
Evan Hunt committed
673
674
675
static cfg_type_t cfg_type_updatemethod = {
	"updatemethod", cfg_parse_enum,	 cfg_print_ustring,
	cfg_doc_enum,	&cfg_rep_string, &updatemethods_enums
676
677
};

678
679
680
681
682
683
684
685
686
/*
 * zone-statistics: full, terse, or none.
 *
 * for backward compatibility, we also support boolean values.
 * yes represents "full", no represents "terse". in the future we
 * may change no to mean "none".
 */
static const char *zonestat_enums[] = { "full", "terse", "none", NULL };
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
687
parse_zonestat(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
688
	return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
689
}
690
static void
Evan Hunt's avatar
Evan Hunt committed
691
doc_zonestat(cfg_printer_t *pctx, const cfg_type_t *type) {
692
	cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
693
}
694
695
696
static cfg_type_t cfg_type_zonestat = { "zonestat",	   parse_zonestat,
					cfg_print_ustring, doc_zonestat,
					&cfg_rep_string,   zonestat_enums };
697

698
699
700
701
702
703
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 };
Evan Hunt's avatar
Evan Hunt committed
704
705
706
707

static keyword_type_t dscp_kw = { "dscp", &cfg_type_uint32 };

static cfg_type_t cfg_type_optional_dscp = {
708
709
	"optional_dscp",       parse_optional_keyvalue, print_keyvalue,
	doc_optional_keyvalue, &cfg_rep_uint32,		&dscp_kw
710
711
712
713
714
};

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

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

719
/*% A list of keys, as in the "key" clause of the controls statement. */
720
721
722
723
724
725
static cfg_type_t cfg_type_keylist = { "keylist",
				       cfg_parse_bracketed_list,
				       cfg_print_bracketed_list,
				       cfg_doc_bracketed_list,
				       &cfg_rep_list,
				       &cfg_type_astring };
726

Evan Hunt's avatar
Evan Hunt committed
727
/*% A list of dnssec keys, as in "trusted-keys". Deprecated. */
728
729
730
731
732
733
static cfg_type_t cfg_type_trustedkeys = { "trustedkeys",
					   cfg_parse_bracketed_list,
					   cfg_print_bracketed_list,
					   cfg_doc_bracketed_list,
					   &cfg_rep_list,
					   &cfg_type_dnsseckey };
734

735
/*%
736
737
738
 * A list of managed trust anchors.  Each entry contains a name, a keyword
 * ("static-key", initial-key", "static-ds" or "initial-ds"), and the
 * fields associated with either a DNSKEY or a DS record.
739
 */
740
741
742
743
744
745
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_managedkey };
746

747
748
749
/*%
 * A list of key entries, used in a DNSSEC Key and Signing Policy.
 */
750
751
752
753
754
755
static cfg_type_t cfg_type_kaspkeys = { "kaspkeys",
					cfg_parse_bracketed_list,
					cfg_print_bracketed_list,
					cfg_doc_bracketed_list,
					&cfg_rep_list,
					&cfg_type_kaspkey };
756

757
static const char *forwardtype_enums[] = { "first", "only", NULL };
Evan Hunt's avatar
Evan Hunt committed
758
759
760
static cfg_type_t cfg_type_forwardtype = {
	"forwardtype", cfg_parse_enum,	cfg_print_ustring,
	cfg_doc_enum,  &cfg_rep_string, &forwardtype_enums
761
762
763
};

static const char *zonetype_enums[] = {
764
765
766
	"primary",  "master",	       "secondary", "slave",
	"mirror",   "delegation-only", "forward",   "hint",
	"redirect", "static-stub",     "stub",	    NULL
767
};
768
769
770
static cfg_type_t cfg_type_zonetype = { "zonetype",	   cfg_parse_enum,
					cfg_print_ustring, cfg_doc_enum,
					&cfg_rep_string,   &zonetype_enums };
771

772
773
774
static const char *loglevel_enums[] = { "critical", "error", "warning",
					"notice",   "info",  "dynamic",
					NULL };
Evan Hunt's avatar
Evan Hunt committed
775
776
777
static cfg_type_t cfg_type_loglevel = { "loglevel",	   cfg_parse_enum,
					cfg_print_ustring, cfg_doc_enum,
					&cfg_rep_string,   &loglevel_enums };
778

779
780
static const char *transferformat_enums[] = { "many-answers", "one-answer",
					      NULL };
Evan Hunt's avatar
Evan Hunt committed
781
782
783
static cfg_type_t cfg_type_transferformat = {
	"transferformat", cfg_parse_enum,  cfg_print_ustring,
	cfg_doc_enum,	  &cfg_rep_string, &transferformat_enums
784
785
};

786
/*%
787
788
789
790
 * The special keyword "none", as used in the pid-file option.
 */

static void
Evan Hunt's avatar
Evan Hunt committed
791
print_none(cfg_printer_t *pctx, const cfg_obj_t *obj) {
792
	UNUSED(obj);
793
	cfg_print_cstr(pctx, "none");
794
795
}

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

799
/*%
800
801
802
 * A quoted string or the special keyword "none".  Used in the pid-file option.
 */
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
803
804
parse_qstringornone(cfg_parser_t *pctx, const cfg_type_t *type,
		    cfg_obj_t **ret) {
805
	isc_result_t result;
806

807
808
	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
	if (pctx->token.type == isc_tokentype_string &&
Evan Hunt's avatar
Evan Hunt committed
809
810
	    strcasecmp(TOKEN_STRING(pctx), "none") == 0)
	{
811
		return (cfg_create_obj(pctx, &cfg_type_none, ret));
812
	}
813
814
	cfg_ungettoken(pctx);
	return (cfg_parse_qstring(pctx, type, ret));
815
cleanup:
816
817
818
819
	return (result);
}

static void
Evan Hunt's avatar
Evan Hunt committed
820
doc_qstringornone(cfg_printer_t *pctx, const cfg_type_t *type) {
821
	UNUSED(type);
822
	cfg_print_cstr(pctx, "( <quoted_string> | none )");
823
824
}

825
826
827
828
829
830
static cfg_type_t cfg_type_qstringornone = { "qstringornone",
					     parse_qstringornone,
					     NULL,
					     doc_qstringornone,
					     NULL,
					     NULL };
831

832
/*%
833
834
 * A boolean ("yes" or "no"), or the special keyword "auto".
 * Used in the dnssec-validation option.
835
 */
836
static void
Evan Hunt's avatar
Evan Hunt committed
837
print_auto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
838
839
840
841
	UNUSED(obj);
	cfg_print_cstr(pctx, "auto");
}

842
843
static cfg_type_t cfg_type_auto = { "auto", NULL,	   print_auto,
				    NULL,   &cfg_rep_void, NULL };
844
845

static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
846
parse_boolorauto(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
847
848
849
850
	isc_result_t result;

	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
	if (pctx->token.type == isc_tokentype_string &&
Evan Hunt's avatar
Evan Hunt committed
851
852
	    strcasecmp(TOKEN_STRING(pctx), "auto") == 0)
	{
853
		return (cfg_create_obj(pctx, &cfg_type_auto, ret));
854
	}
855
856
	cfg_ungettoken(pctx);
	return (cfg_parse_boolean(pctx, type, ret));
857
cleanup:
858
859
860
861
	return (result);
}

static void
Evan Hunt's avatar
Evan Hunt committed
862
print_boolorauto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
863
	if (obj->type->rep == &cfg_rep_void) {
864
		cfg_print_cstr(pctx, "auto");
865
	} else if (obj->value.boolean) {
866
		cfg_print_cstr(pctx, "yes");
867
	} else {
868
		cfg_print_cstr(pctx, "no");
869
	}
870
871
872
}

static void
Evan Hunt's avatar
Evan Hunt committed
873
doc_boolorauto(cfg_printer_t *pctx, const cfg_type_t *type) {
874
875
876
877
878
	UNUSED(type);
	cfg_print_cstr(pctx, "( yes | no | auto )");
}

static cfg_type_t cfg_type_boolorauto = {
879
880
	"boolorauto", parse_boolorauto, print_boolorauto, doc_boolorauto, NULL,
	NULL
881
};
882

883
884
885
/*%
 * keyword hostname
 */
886
static void
Evan Hunt's avatar
Evan Hunt committed
887
print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) {
888
	UNUSED(obj);
889
	cfg_print_cstr(pctx, "hostname");
890
891
}

892
893
894
static cfg_type_t cfg_type_hostname = { "hostname",	  NULL,
					print_hostname,	  NULL,
					&cfg_rep_boolean, NULL };
895

896
/*%
Mark Andrews's avatar
Mark Andrews committed
897
 * "server-id" argument.
898
899
900
 */

static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
901
parse_serverid(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
902
903
904
	isc_result_t result;
	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
	if (pctx->token.type == isc_tokentype_string &&
Evan Hunt's avatar
Evan Hunt committed
905
906
	    strcasecmp(TOKEN_STRING(pctx), "none") == 0)
	{
907
		return (cfg_create_obj(pctx, &cfg_type_none, ret));
908
	}
909
	if (pctx->token.type == isc_tokentype_string &&
Evan Hunt's avatar
Evan Hunt committed
910
911
	    strcasecmp(TOKEN_STRING(pctx), "hostname") == 0)
	{
912
		result = cfg_create_obj(pctx, &cfg_type_hostname, ret);
913
		if (result == ISC_R_SUCCESS) {
914
			(*ret)->value.boolean = true;
915
		}
916
		return (result);
917
918
919
	}
	cfg_ungettoken(pctx);
	return (cfg_parse_qstring(pctx, type, ret));
920
cleanup:
921
922
923
924
	return (result);
}

static void
Evan Hunt's avatar
Evan Hunt committed
925
doc_serverid(cfg_printer_t *pctx, const cfg_type_t *type) {
926
	UNUSED(type);
927
	cfg_print_cstr(pctx, "( <quoted_string> | none | hostname )");
928
929
}

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

933
/*%
934
935
 * Port list.
 */
936
static void
Evan Hunt's avatar
Evan Hunt committed
937
print_porttuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
938
939
940
	cfg_print_cstr(pctx, "range ");
	cfg_print_tuple(pctx, obj);
}
941
942
943
944
945
static cfg_tuplefielddef_t porttuple_fields[] = {
	{ "loport", &cfg_type_uint32, 0 },
	{ "hiport", &cfg_type_uint32, 0 },
	{ NULL, NULL, 0 }
};
946
947
948
static cfg_type_t cfg_type_porttuple = { "porttuple",	  cfg_parse_tuple,
					 print_porttuple, cfg_doc_tuple,
					 &cfg_rep_tuple,  porttuple_fields };
949

950
static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
951
parse_port(cfg_parser_t *pctx,