namedconf.c 111 KB
Newer Older
1
/*
2
 * Copyright (C) 2002-2017  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
/*! \file */
10
11
12

#include <config.h>

Evan Hunt's avatar
Evan Hunt committed
13
#include <stdlib.h>
14
15
16
#include <string.h>

#include <isc/lex.h>
17
#include <isc/mem.h>
18
19
20
21
#include <isc/result.h>
#include <isc/string.h>
#include <isc/util.h>

Evan Hunt's avatar
Evan Hunt committed
22
23
24
#include <dns/ttl.h>
#include <dns/result.h>

25
26
27
#include <isccfg/cfg.h>
#include <isccfg/grammar.h>
#include <isccfg/log.h>
28
#include <isccfg/namedconf.h>
29

30
31
#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)

32
/*% Check a return value. */
33
34
35
#define CHECK(op)						\
	do { result = (op);					\
		if (result != ISC_R_SUCCESS) goto cleanup;	\
36
37
	} while (0)

38
/*% Clean up a configuration object if non-NULL. */
39
40
41
42
#define CLEANUP_OBJ(obj) \
	do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)


43
/*%
44
45
46
47
48
49
50
 * 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);

51
static void
52
53
doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype,
		  const cfg_type_t *othertype);
54

55
56
57
58
static isc_result_t
parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);

static isc_result_t
59
60
61
62
63
64
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);
Mark Andrews's avatar
Mark Andrews committed
65
66
static void
print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj);
67
68
69

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

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);

80
#ifdef HAVE_GEOIP
Evan Hunt's avatar
Evan Hunt committed
81
82
83
84
85
86
87
88
static isc_result_t
parse_geoip(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);

static void
print_geoip(cfg_printer_t *pctx, const cfg_obj_t *obj);

static void
doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type);
89
#endif /* HAVE_GEOIP */
Evan Hunt's avatar
Evan Hunt committed
90

91
static cfg_type_t cfg_type_acl;
92
93
static cfg_type_t cfg_type_addrmatchelt;
static cfg_type_t cfg_type_bracketed_aml;
Evan Hunt's avatar
Evan Hunt committed
94
static cfg_type_t cfg_type_bracketed_dscpsockaddrlist;
95
static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
96
static cfg_type_t cfg_type_bracketed_sockaddrlist;
97
static cfg_type_t cfg_type_bracketed_sockaddrnameportlist;
98
99
100
101
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;
102
103
104
105
106
static cfg_type_t cfg_type_dlz;
static cfg_type_t cfg_type_dnstap;
static cfg_type_t cfg_type_dnstapoutput;
static cfg_type_t cfg_type_dyndb;
static cfg_type_t cfg_type_filter_aaaa;
107
static cfg_type_t cfg_type_ixfrdifftype;
108
109
110
111
112
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;
113
static cfg_type_t cfg_type_masterselement;
Evan Hunt's avatar
Evan Hunt committed
114
static cfg_type_t cfg_type_maxttl;
115
static cfg_type_t cfg_type_minimal;
116
117
118
static cfg_type_t cfg_type_nameportiplist;
static cfg_type_t cfg_type_negated;
static cfg_type_t cfg_type_notifytype;
119
static cfg_type_t cfg_type_optional_allow;
120
static cfg_type_t cfg_type_optional_class;
121
static cfg_type_t cfg_type_optional_dscp;
122
static cfg_type_t cfg_type_optional_facility;
123
static cfg_type_t cfg_type_optional_keyref;
124
static cfg_type_t cfg_type_optional_port;
Evan Hunt's avatar
Evan Hunt committed
125
static cfg_type_t cfg_type_optional_uint32;
126
static cfg_type_t cfg_type_options;
127
static cfg_type_t cfg_type_portiplist;
128
129
130
static cfg_type_t cfg_type_querysource4;
static cfg_type_t cfg_type_querysource6;
static cfg_type_t cfg_type_querysource;
131
132
133
134
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;
135
static cfg_type_t cfg_type_sizeorpercent;
136
static cfg_type_t cfg_type_sizeval;
137
138
static cfg_type_t cfg_type_sockaddr4wild;
static cfg_type_t cfg_type_sockaddr6wild;
139
static cfg_type_t cfg_type_statschannels;
Evan Hunt's avatar
Evan Hunt committed
140
static cfg_type_t cfg_type_ttlval;
141
142
static cfg_type_t cfg_type_view;
static cfg_type_t cfg_type_viewopts;
143
144
static cfg_type_t cfg_type_zone;

145
/*% tkey-dhkey */
146
147
148
149
150
151
152
153

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 = {
154
155
	"tkey-dhkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, tkey_dhkey_fields
156
157
};

158
/*% listen-on */
159
160
161

static cfg_tuplefielddef_t listenon_fields[] = {
	{ "port", &cfg_type_optional_port, 0 },
Evan Hunt's avatar
Evan Hunt committed
162
	{ "dscp", &cfg_type_optional_dscp, 0 },
163
164
165
	{ "acl", &cfg_type_bracketed_aml, 0 },
	{ NULL, NULL, 0 }
};
Evan Hunt's avatar
Evan Hunt committed
166

167
static cfg_type_t cfg_type_listenon = {
Evan Hunt's avatar
Evan Hunt committed
168
169
170
	"listenon", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, listenon_fields
};
171

172
/*% acl */
173
174
175
176
177
178
179
180

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 = {
181
182
183
	"acl", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, acl_fields
};
184

185
/*% masters */
186
187
188
static cfg_tuplefielddef_t masters_fields[] = {
	{ "name", &cfg_type_astring, 0 },
	{ "port", &cfg_type_optional_port, 0 },
Evan Hunt's avatar
Evan Hunt committed
189
	{ "dscp", &cfg_type_optional_dscp, 0 },
190
191
192
193
194
	{ "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
	{ NULL, NULL, 0 }
};

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

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

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

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

217
218
static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = {
	"bracketed_namesockaddrkeylist", cfg_parse_bracketed_list,
219
220
	cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list,
	&cfg_type_namesockaddrkey
221
222
};

223
static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = {
224
	{ "port", &cfg_type_optional_port, 0 },
Evan Hunt's avatar
Evan Hunt committed
225
	{ "dscp", &cfg_type_optional_dscp, 0 },
226
	{ "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
227
228
	{ NULL, NULL, 0 }
};
229
static cfg_type_t cfg_type_namesockaddrkeylist = {
230
231
	"sockaddrkeylist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, namesockaddrkeylist_fields
232
233
};

234
/*%
235
236
 * A list of socket addresses with an optional default port, as used
 * in the lwresd 'listen-on' option.  E.g., "{ 10.0.0.1; 1::2 port 69; }"
237
238
239
 */
static cfg_tuplefielddef_t portiplist_fields[] = {
	{ "port", &cfg_type_optional_port, 0 },
Evan Hunt's avatar
Evan Hunt committed
240
241
	{ "dscp", &cfg_type_optional_dscp, 0 },
	{ "addresses", &cfg_type_bracketed_dscpsockaddrlist, 0 },
242
243
244
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_portiplist = {
245
246
	"portiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, portiplist_fields
247
248
};

249
/*%
250
251
252
253
254
255
256
257
258
259
 * 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 = {
260
	"pubkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
261
262
	&cfg_rep_tuple, pubkey_fields
};
263

264
/*%
265
266
267
268
 * 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 = {
269
	"rrtypelist", cfg_parse_spacelist, cfg_print_spacelist,
Automatic Updater's avatar
Automatic Updater committed
270
	cfg_doc_terminal, &cfg_rep_list, &cfg_type_astring
271
272
};

273
static const char *mode_enums[] = { "deny", "grant", NULL };
274
static cfg_type_t cfg_type_mode = {
Automatic Updater's avatar
Automatic Updater committed
275
	"mode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
276
	&cfg_rep_string, &mode_enums
277
278
};

279
static isc_result_t
280
parse_matchtype(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
281
282
283
284
285
	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
286
		pctx->flags |= CFG_PCTX_SKIP;
287
288
289
290
291
292
293
294
	}
	return (cfg_parse_enum(pctx, type, ret));

 cleanup:
	return (result);
}

static isc_result_t
295
parse_matchname(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
296
297
298
299
300
301
302
303
304
305
306
307
308
309
	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);
}

310
311
static void
doc_matchname(cfg_printer_t *pctx, const cfg_type_t *type) {
312
	cfg_print_cstr(pctx, "[ ");
313
	cfg_doc_obj(pctx, type->of);
314
	cfg_print_cstr(pctx, " ]");
315
316
}

317
static const char *matchtype_enums[] = {
318
319
320
321
	"6to4-self", "external", "krb5-self", "krb5-subdomain", "ms-self",
	"ms-subdomain", "name", "self", "selfsub", "selfwild", "subdomain",
	"tcp-self", "wildcard", "zonesub", NULL
};
322

323
static cfg_type_t cfg_type_matchtype = {
324
	"matchtype", parse_matchtype, cfg_print_ustring,
Automatic Updater's avatar
Automatic Updater committed
325
	cfg_doc_enum, &cfg_rep_string, &matchtype_enums
326
327
328
329
};

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

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

static cfg_type_t cfg_type_updatepolicy = {
Mark Andrews's avatar
Mark Andrews committed
350
351
	"update_policy", parse_updatepolicy, print_updatepolicy,
	doc_updatepolicy, &cfg_rep_list, &cfg_type_grant
352
353
};

354
355
static isc_result_t
parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
356
357
		   cfg_obj_t **ret)
{
358
359
360
361
	isc_result_t result;
	CHECK(cfg_gettoken(pctx, 0));
	if (pctx->token.type == isc_tokentype_special &&
	    pctx->token.value.as_char == '{') {
362
		cfg_ungettoken(pctx);
363
364
365
366
367
368
369
370
371
372
373
374
375
376
		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);
		}
377
		memmove(obj->value.string.base, "local", 5);
378
379
380
381
382
383
384
385
386
387
388
389
		obj->value.string.base[5] = '\0';
		*ret = obj;
		return (ISC_R_SUCCESS);
	}

	cfg_ungettoken(pctx);
	return (ISC_R_UNEXPECTEDTOKEN);

 cleanup:
	return (result);
}

Mark Andrews's avatar
Mark Andrews committed
390
391
392
393
394
395
396
397
static void
print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj) {
	if (cfg_obj_isstring(obj))
		cfg_print_ustring(pctx, obj);
	else
		cfg_print_bracketed_list(pctx, obj);
}

398
399
static void
doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type) {
400
	cfg_print_cstr(pctx, "( local | { ");
401
	cfg_doc_obj(pctx, type->of);
402
	cfg_print_cstr(pctx, "; ... }");
403
404
}

405
/*%
406
407
408
409
410
411
412
413
414
 * 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 = {
415
416
417
	"view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	 &cfg_rep_tuple, view_fields
};
418

419
/*%
420
421
422
423
424
425
426
427
428
 * 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 = {
429
430
431
	"zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, zone_fields
};
432

433
/*%
434
435
436
437
438
439
440
441
 * 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 = {
442
443
444
	"category", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, category_fields
};
445
446


447
/*%
448
 * A dnssec key, as used in the "trusted-keys" statement.
449
 */
450
static cfg_tuplefielddef_t dnsseckey_fields[] = {
451
452
453
454
455
456
457
	{ "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 }
};
458
459
460
static cfg_type_t cfg_type_dnsseckey = {
	"dnsseckey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, dnsseckey_fields
461
462
};

463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
/*%
 * 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
};

481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
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 = {
498
499
	"optional_wild_name", parse_optional_keyvalue, print_keyvalue,
	doc_optional_keyvalue, &cfg_rep_string, &wild_name_kw
500
501
};

502
/*%
503
504
505
506
507
508
 * 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
509
	{ "order", &cfg_type_ustring, 0 }, /* must be literal "order" */
510
511
512
513
	{ "ordering", &cfg_type_ustring, 0 },
	{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_rrsetorderingelement = {
514
515
	"rrsetorderingelement", cfg_parse_tuple, cfg_print_tuple,
	cfg_doc_tuple, &cfg_rep_tuple, rrsetorderingelement_fields
516
517
};

518
/*%
519
520
521
 * A global or view "check-names" option.  Note that the zone
 * "check-names" option has a different syntax.
 */
522
523
524
525
526
527
528
529
530
531
532
533
534

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
};

535
536
537
538
539
540
static const char *warn_enums[] = { "warn", "ignore", NULL };
static cfg_type_t cfg_type_warn = {
	"warn", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
	&cfg_rep_string, &warn_enums
};

541
static cfg_tuplefielddef_t checknames_fields[] = {
542
543
	{ "type", &cfg_type_checktype, 0 },
	{ "mode", &cfg_type_checkmode, 0 },
544
545
	{ NULL, NULL, 0 }
};
546

547
static cfg_type_t cfg_type_checknames = {
Evan Hunt's avatar
Evan Hunt committed
548
549
550
551
552
553
554
555
	"checknames", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, checknames_fields
};

static cfg_type_t cfg_type_bracketed_dscpsockaddrlist = {
	"bracketed_sockaddrlist", cfg_parse_bracketed_list,
	cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list,
	&cfg_type_sockaddrdscp
556
557
558
};

static cfg_type_t cfg_type_bracketed_sockaddrlist = {
Evan Hunt's avatar
Evan Hunt committed
559
560
561
	"bracketed_sockaddrlist", cfg_parse_bracketed_list,
	cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list,
	&cfg_type_sockaddr
562
563
};

564
565
566
static const char *autodnssec_enums[] = {
	 "allow", "maintain", "off", NULL
};
567
568
569
570
571
static cfg_type_t cfg_type_autodnssec = {
	"autodnssec", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
	&cfg_rep_string, &autodnssec_enums
};

572
573
574
static const char *dnssecupdatemode_enums[] = {
	"maintain", "no-resign", NULL
};
575
576
577
578
579
static cfg_type_t cfg_type_dnssecupdatemode = {
	"dnssecupdatemode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
	&cfg_rep_string, &dnssecupdatemode_enums
};

580
static const char *updatemethods_enums[] = {
581
582
	"date", "increment", "unixtime", NULL
};
583
584
585
586
587
static cfg_type_t cfg_type_updatemethod = {
	"updatemethod", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
	&cfg_rep_string, &updatemethods_enums
};

588
589
590
591
592
593
594
595
596
597
598
599
/*
 * 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
parse_zonestat(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
	return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
}
600
601
602
603
static void
doc_zonestat(cfg_printer_t *pctx, const cfg_type_t *type) {
	doc_enum_or_other(pctx, type, &cfg_type_boolean);
}
604
static cfg_type_t cfg_type_zonestat = {
605
	"zonestat", parse_zonestat, cfg_print_ustring, doc_zonestat,
606
607
608
	&cfg_rep_string, zonestat_enums
};

609
static cfg_type_t cfg_type_rrsetorder = {
Evan Hunt's avatar
Evan Hunt committed
610
611
612
613
614
615
616
617
618
	"rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list,
	cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_rrsetorderingelement
};

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

static cfg_type_t cfg_type_optional_dscp = {
	"optional_dscp", parse_optional_keyvalue, print_keyvalue,
	doc_optional_keyvalue, &cfg_rep_uint32, &dscp_kw
619
620
621
622
623
624
625
626
627
};

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
};

628
/*% A list of keys, as in the "key" clause of the controls statement. */
629
static cfg_type_t cfg_type_keylist = {
630
631
	"keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
	cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring
632
633
};

634
/*% A list of dnssec keys, as in "trusted-keys" */
635
636
637
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
638
639
};

640
641
642
643
644
645
646
647
648
649
650
651
652
/*%
 * 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
};

653
654
static const char *forwardtype_enums[] = { "first", "only", NULL };
static cfg_type_t cfg_type_forwardtype = {
655
656
	"forwardtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
	&cfg_rep_string, &forwardtype_enums
657
658
659
};

static const char *zonetype_enums[] = {
660
661
662
	"delegation-only", "forward", "hint", "master", "redirect",
	"slave", "static-stub", "stub", NULL
};
663
static cfg_type_t cfg_type_zonetype = {
664
665
	"zonetype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
	&cfg_rep_string, &zonetype_enums
666
667
668
};

static const char *loglevel_enums[] = {
669
670
	"critical", "error", "warning", "notice", "info", "dynamic", NULL
};
671
static cfg_type_t cfg_type_loglevel = {
672
673
	"loglevel", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
	&cfg_rep_string, &loglevel_enums
674
675
676
};

static const char *transferformat_enums[] = {
677
678
	"many-answers", "one-answer", NULL
};
679
static cfg_type_t cfg_type_transferformat = {
680
681
	"transferformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
	&cfg_rep_string, &transferformat_enums
682
683
};

684
/*%
685
686
687
688
 * The special keyword "none", as used in the pid-file option.
 */

static void
689
print_none(cfg_printer_t *pctx, const cfg_obj_t *obj) {
690
	UNUSED(obj);
691
	cfg_print_cstr(pctx, "none");
692
693
694
695
696
697
}

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

698
/*%
699
700
701
702
703
704
705
 * 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;
706

707
708
	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
	if (pctx->token.type == isc_tokentype_string &&
709
	    strcasecmp(TOKEN_STRING(pctx), "none") == 0)
710
711
712
713
714
715
716
717
718
719
		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);
720
	cfg_print_cstr(pctx, "( <quoted_string> | none )");
721
722
723
}

static cfg_type_t cfg_type_qstringornone = {
724
725
726
	"qstringornone", parse_qstringornone, NULL, doc_qstringornone,
	NULL, NULL
};
727

728
/*%
729
730
 * A boolean ("yes" or "no"), or the special keyword "auto".
 * Used in the dnssec-validation option.
731
 */
732
733
734
735
736
737
738
739
740
741
742
static void
print_auto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
	UNUSED(obj);
	cfg_print_cstr(pctx, "auto");
}

static cfg_type_t cfg_type_auto = {
	"auto", NULL, print_auto, NULL, &cfg_rep_void, NULL
};

static isc_result_t
743
parse_boolorauto(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
	isc_result_t result;

	CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
	if (pctx->token.type == isc_tokentype_string &&
	    strcasecmp(TOKEN_STRING(pctx), "auto") == 0)
		return (cfg_create_obj(pctx, &cfg_type_auto, ret));
	cfg_ungettoken(pctx);
	return (cfg_parse_boolean(pctx, type, ret));
 cleanup:
	return (result);
}

static void
print_boolorauto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
	if (obj->type->rep == &cfg_rep_void)
759
		cfg_print_cstr(pctx, "auto");
760
	else if (obj->value.boolean)
761
		cfg_print_cstr(pctx, "yes");
762
	else
763
		cfg_print_cstr(pctx, "no");
764
765
766
767
768
769
770
771
772
773
774
775
}

static void
doc_boolorauto(cfg_printer_t *pctx, const cfg_type_t *type) {
	UNUSED(type);
	cfg_print_cstr(pctx, "( yes | no | auto )");
}

static cfg_type_t cfg_type_boolorauto = {
	"boolorauto", parse_boolorauto, print_boolorauto,
	doc_boolorauto, NULL, NULL
};
776

777
778
779
/*%
 * keyword hostname
 */
780
static void
781
print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) {
782
	UNUSED(obj);
783
	cfg_print_cstr(pctx, "hostname");
784
785
786
787
788
789
}

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

790
/*%
Mark Andrews's avatar
Mark Andrews committed
791
 * "server-id" argument.
792
793
794
795
796
797
798
799
800
801
802
803
804
 */

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) {
805
806
807
808
		result = cfg_create_obj(pctx, &cfg_type_hostname, ret);
		if (result == ISC_R_SUCCESS)
			(*ret)->value.boolean = ISC_TRUE;
		return (result);
809
810
811
812
813
814
815
816
817
818
	}
	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);
819
	cfg_print_cstr(pctx, "( <quoted_string> | none | hostname )");
820
821
822
823
824
}

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

825
/*%
826
827
 * Port list.
 */
828
829
830
831
832
static void
print_porttuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
	cfg_print_cstr(pctx, "range ");
	cfg_print_tuple(pctx, obj);
}
833
834
835
836
837
838
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 = {
839
	"porttuple", cfg_parse_tuple, print_porttuple, cfg_doc_tuple,
840
841
842
	&cfg_rep_tuple, porttuple_fields
};

843
static isc_result_t
844
parse_port(cfg_parser_t *pctx, cfg_obj_t **ret) {
845
	isc_result_t result;
Automatic Updater's avatar
Automatic Updater committed
846

847
848
849
850
851
852
	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
853

854
855
856
857
 cleanup:
	return (result);
}

858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
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,
900
901
902
903
	NULL, NULL
};

static cfg_type_t cfg_type_bracketed_portlist = {
904
905
906
	"bracketed_sockaddrlist", cfg_parse_bracketed_list,
	cfg_print_bracketed_list, cfg_doc_bracketed_list,
	&cfg_rep_list, &cfg_type_portrange
907
908
};

909
910
911
static const char *cookiealg_enums[] = { "aes", "sha1", "sha256", NULL };
static cfg_type_t cfg_type_cookiealg = {
	"cookiealg", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
912
913
	&cfg_rep_string, &cookiealg_enums
};
914

Evan Hunt's avatar
Evan Hunt committed
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
/*%
 * fetch-quota-params
 */

static cfg_tuplefielddef_t fetchquota_fields[] = {
	{ "frequency", &cfg_type_uint32, 0 },
	{ "low", &cfg_type_fixedpoint, 0 },
	{ "high", &cfg_type_fixedpoint, 0 },
	{ "discount", &cfg_type_fixedpoint, 0 },
	{ NULL, NULL, 0 }
};

static cfg_type_t cfg_type_fetchquota = {
	"fetchquota", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, fetchquota_fields
};

/*%
 * fetches-per-server or fetches-per-zone
 */

static const char *response_enums[] = { "drop", "fail", NULL };

static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
939
940
parse_optional_enum(cfg_parser_t *pctx, const cfg_type_t *type,
		    cfg_obj_t **ret)
Evan Hunt's avatar
Evan Hunt committed
941
942
943
944
945
{
	return (parse_enum_or_other(pctx, type, &cfg_type_void, ret));
}

static void
Evan Hunt's avatar
Evan Hunt committed
946
947
948
949
950
doc_optional_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
	UNUSED(type);
	cfg_print_cstr(pctx, "[ ");
	cfg_doc_enum(pctx, type);
	cfg_print_cstr(pctx, " ]");
Evan Hunt's avatar
Evan Hunt committed
951
952
953
}

static cfg_type_t cfg_type_responsetype = {
Evan Hunt's avatar
Evan Hunt committed
954
955
	"responsetype", parse_optional_enum, cfg_print_ustring,
	doc_optional_enum, &cfg_rep_string, response_enums
Evan Hunt's avatar
Evan Hunt committed
956
957
958
959
960
961
962
963
964
965
966
967
968
};

static cfg_tuplefielddef_t fetchesper_fields[] = {
	{ "fetches", &cfg_type_uint32, 0 },
	{ "response", &cfg_type_responsetype, 0 },
	{ NULL, NULL, 0 }
};

static cfg_type_t cfg_type_fetchesper = {
	"fetchesper", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
	&cfg_rep_tuple, fetchesper_fields
};

969
/*%
970
971
972
973
974
975
 * Clauses that can be found within the top level of the named.conf
 * file only.
 */
static cfg_clausedef_t
namedconf_clauses[] = {
	{ "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
976
	{ "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
977
978
	{ "logging", &cfg_type_logging, 0 },
	{ "lwres", &cfg_type_lwres, CFG_CLAUSEFLAG_MULTI },
979
980
	{ "masters", &cfg_type_masters, CFG_CLAUSEFLAG_MULTI },
	{ "options", &cfg_type_options, 0 },
981
982
	{ "statistics-channels", &cfg_type_statschannels,
	  CFG_CLAUSEFLAG_MULTI },
983
	{ "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI },
984
985
986
	{ NULL, NULL, 0 }
};

987
/*%
988
989
990
991
992
 * 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[] = {
993
	{ "dlz", &cfg_type_dlz, CFG_CLAUSEFLAG_MULTI },
Evan Hunt's avatar
Evan Hunt committed
994
	{ "dyndb", &cfg_type_dyndb, CFG_CLAUSEFLAG_MULTI },
995
996
	{ "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
	{ "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
997
	{ "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI },
998
	{ "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
999
	{ "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
1000
	{ NULL, NULL, 0 }
For faster browsing, not all history is shown. View entire blame