namedconf.c revision 1.8 1 /* $NetBSD: namedconf.c,v 1.8 2020/05/24 19:46:29 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 */
13
14 /*! \file */
15
16 #include <inttypes.h>
17 #include <stdbool.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include <isc/lex.h>
22 #include <isc/mem.h>
23 #include <isc/print.h>
24 #include <isc/result.h>
25 #include <isc/string.h>
26 #include <isc/util.h>
27
28 #include <dns/result.h>
29 #include <dns/ttl.h>
30
31 #include <isccfg/cfg.h>
32 #include <isccfg/grammar.h>
33 #include <isccfg/log.h>
34 #include <isccfg/namedconf.h>
35
36 #define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
37
38 /*% Check a return value. */
39 #define CHECK(op) \
40 do { \
41 result = (op); \
42 if (result != ISC_R_SUCCESS) \
43 goto cleanup; \
44 } while (/*CONSTCOND*/0)
45
46 /*% Clean up a configuration object if non-NULL. */
47 #define CLEANUP_OBJ(obj) \
48 do { \
49 if ((obj) != NULL) \
50 cfg_obj_destroy(pctx, &(obj)); \
51 } while (/*CONSTCOND*/0)
52
53 /*%
54 * Forward declarations of static functions.
55 */
56
57 static isc_result_t
58 parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
59
60 static isc_result_t
61 parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
62 cfg_obj_t **ret);
63
64 static isc_result_t
65 parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
66 static void
67 print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj);
68
69 static void
70 doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type);
71
72 static void
73 print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj);
74
75 static void
76 doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
77
78 static void
79 doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
80
81 static cfg_type_t cfg_type_acl;
82 static cfg_type_t cfg_type_bracketed_dscpsockaddrlist;
83 static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
84 static cfg_type_t cfg_type_bracketed_netaddrlist;
85 static cfg_type_t cfg_type_bracketed_sockaddrnameportlist;
86 static cfg_type_t cfg_type_controls;
87 static cfg_type_t cfg_type_controls_sockaddr;
88 static cfg_type_t cfg_type_destinationlist;
89 static cfg_type_t cfg_type_dialuptype;
90 static cfg_type_t cfg_type_dlz;
91 static cfg_type_t cfg_type_dnssecpolicy;
92 static cfg_type_t cfg_type_dnstap;
93 static cfg_type_t cfg_type_dnstapoutput;
94 static cfg_type_t cfg_type_dyndb;
95 static cfg_type_t cfg_type_plugin;
96 static cfg_type_t cfg_type_ixfrdifftype;
97 static cfg_type_t cfg_type_key;
98 static cfg_type_t cfg_type_logfile;
99 static cfg_type_t cfg_type_logging;
100 static cfg_type_t cfg_type_logseverity;
101 static cfg_type_t cfg_type_logsuffix;
102 static cfg_type_t cfg_type_logversions;
103 static cfg_type_t cfg_type_masterselement;
104 static cfg_type_t cfg_type_maxduration;
105 static cfg_type_t cfg_type_minimal;
106 static cfg_type_t cfg_type_nameportiplist;
107 static cfg_type_t cfg_type_notifytype;
108 static cfg_type_t cfg_type_optional_allow;
109 static cfg_type_t cfg_type_optional_class;
110 static cfg_type_t cfg_type_optional_dscp;
111 static cfg_type_t cfg_type_optional_facility;
112 static cfg_type_t cfg_type_optional_keyref;
113 static cfg_type_t cfg_type_optional_port;
114 static cfg_type_t cfg_type_optional_uint32;
115 static cfg_type_t cfg_type_options;
116 static cfg_type_t cfg_type_portiplist;
117 static cfg_type_t cfg_type_printtime;
118 static cfg_type_t cfg_type_qminmethod;
119 static cfg_type_t cfg_type_querysource4;
120 static cfg_type_t cfg_type_querysource6;
121 static cfg_type_t cfg_type_querysource;
122 static cfg_type_t cfg_type_server;
123 static cfg_type_t cfg_type_server_key_kludge;
124 static cfg_type_t cfg_type_size;
125 static cfg_type_t cfg_type_sizenodefault;
126 static cfg_type_t cfg_type_sizeorpercent;
127 static cfg_type_t cfg_type_sizeval;
128 static cfg_type_t cfg_type_sockaddr4wild;
129 static cfg_type_t cfg_type_sockaddr6wild;
130 static cfg_type_t cfg_type_statschannels;
131 static cfg_type_t cfg_type_view;
132 static cfg_type_t cfg_type_viewopts;
133 static cfg_type_t cfg_type_zone;
134
135 /*% tkey-dhkey */
136
137 static cfg_tuplefielddef_t tkey_dhkey_fields[] = {
138 { "name", &cfg_type_qstring, 0 },
139 { "keyid", &cfg_type_uint32, 0 },
140 { NULL, NULL, 0 }
141 };
142
143 static cfg_type_t cfg_type_tkey_dhkey = { "tkey-dhkey", cfg_parse_tuple,
144 cfg_print_tuple, cfg_doc_tuple,
145 &cfg_rep_tuple, tkey_dhkey_fields };
146
147 /*% listen-on */
148
149 static cfg_tuplefielddef_t listenon_fields[] = {
150 { "port", &cfg_type_optional_port, 0 },
151 { "dscp", &cfg_type_optional_dscp, 0 },
152 { "acl", &cfg_type_bracketed_aml, 0 },
153 { NULL, NULL, 0 }
154 };
155
156 static cfg_type_t cfg_type_listenon = { "listenon", cfg_parse_tuple,
157 cfg_print_tuple, cfg_doc_tuple,
158 &cfg_rep_tuple, listenon_fields };
159
160 /*% acl */
161
162 static cfg_tuplefielddef_t acl_fields[] = { { "name", &cfg_type_astring, 0 },
163 { "value", &cfg_type_bracketed_aml,
164 0 },
165 { NULL, NULL, 0 } };
166
167 static cfg_type_t cfg_type_acl = { "acl", cfg_parse_tuple,
168 cfg_print_tuple, cfg_doc_tuple,
169 &cfg_rep_tuple, acl_fields };
170
171 /*% masters */
172 static cfg_tuplefielddef_t masters_fields[] = {
173 { "name", &cfg_type_astring, 0 },
174 { "port", &cfg_type_optional_port, 0 },
175 { "dscp", &cfg_type_optional_dscp, 0 },
176 { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
177 { NULL, NULL, 0 }
178 };
179
180 static cfg_type_t cfg_type_masters = { "masters", cfg_parse_tuple,
181 cfg_print_tuple, cfg_doc_tuple,
182 &cfg_rep_tuple, masters_fields };
183
184 /*%
185 * "sockaddrkeylist", a list of socket addresses with optional keys
186 * and an optional default port, as used in the masters option.
187 * E.g.,
188 * "port 1234 { mymasters; 10.0.0.1 key foo; 1::2 port 69; }"
189 */
190
191 static cfg_tuplefielddef_t namesockaddrkey_fields[] = {
192 { "masterselement", &cfg_type_masterselement, 0 },
193 { "key", &cfg_type_optional_keyref, 0 },
194 { NULL, NULL, 0 },
195 };
196
197 static cfg_type_t cfg_type_namesockaddrkey = {
198 "namesockaddrkey", cfg_parse_tuple, cfg_print_tuple,
199 cfg_doc_tuple, &cfg_rep_tuple, namesockaddrkey_fields
200 };
201
202 static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = {
203 "bracketed_namesockaddrkeylist",
204 cfg_parse_bracketed_list,
205 cfg_print_bracketed_list,
206 cfg_doc_bracketed_list,
207 &cfg_rep_list,
208 &cfg_type_namesockaddrkey
209 };
210
211 static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = {
212 { "port", &cfg_type_optional_port, 0 },
213 { "dscp", &cfg_type_optional_dscp, 0 },
214 { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
215 { NULL, NULL, 0 }
216 };
217 static cfg_type_t cfg_type_namesockaddrkeylist = {
218 "sockaddrkeylist", cfg_parse_tuple, cfg_print_tuple,
219 cfg_doc_tuple, &cfg_rep_tuple, namesockaddrkeylist_fields
220 };
221
222 /*%
223 * A list of socket addresses with an optional default port, as used
224 * in the 'listen-on' option. E.g., "{ 10.0.0.1; 1::2 port 69; }"
225 */
226 static cfg_tuplefielddef_t portiplist_fields[] = {
227 { "port", &cfg_type_optional_port, 0 },
228 { "dscp", &cfg_type_optional_dscp, 0 },
229 { "addresses", &cfg_type_bracketed_dscpsockaddrlist, 0 },
230 { NULL, NULL, 0 }
231 };
232 static cfg_type_t cfg_type_portiplist = { "portiplist", cfg_parse_tuple,
233 cfg_print_tuple, cfg_doc_tuple,
234 &cfg_rep_tuple, portiplist_fields };
235
236 /*
237 * Obsolete format for the "pubkey" statement.
238 */
239 static cfg_tuplefielddef_t pubkey_fields[] = {
240 { "flags", &cfg_type_uint32, 0 },
241 { "protocol", &cfg_type_uint32, 0 },
242 { "algorithm", &cfg_type_uint32, 0 },
243 { "key", &cfg_type_qstring, 0 },
244 { NULL, NULL, 0 }
245 };
246 static cfg_type_t cfg_type_pubkey = { "pubkey", cfg_parse_tuple,
247 cfg_print_tuple, cfg_doc_tuple,
248 &cfg_rep_tuple, pubkey_fields };
249
250 /*%
251 * A list of RR types, used in grant statements.
252 * Note that the old parser allows quotes around the RR type names.
253 */
254 static cfg_type_t cfg_type_rrtypelist = {
255 "rrtypelist", cfg_parse_spacelist, cfg_print_spacelist,
256 cfg_doc_terminal, &cfg_rep_list, &cfg_type_astring
257 };
258
259 static const char *mode_enums[] = { "deny", "grant", NULL };
260 static cfg_type_t cfg_type_mode = {
261 "mode", cfg_parse_enum, cfg_print_ustring,
262 cfg_doc_enum, &cfg_rep_string, &mode_enums
263 };
264
265 static isc_result_t
266 parse_matchtype(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
267 isc_result_t result;
268
269 CHECK(cfg_peektoken(pctx, 0));
270 if (pctx->token.type == isc_tokentype_string &&
271 strcasecmp(TOKEN_STRING(pctx), "zonesub") == 0)
272 {
273 pctx->flags |= CFG_PCTX_SKIP;
274 }
275 return (cfg_parse_enum(pctx, type, ret));
276
277 cleanup:
278 return (result);
279 }
280
281 static isc_result_t
282 parse_matchname(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
283 isc_result_t result;
284 cfg_obj_t *obj = NULL;
285
286 if ((pctx->flags & CFG_PCTX_SKIP) != 0) {
287 pctx->flags &= ~CFG_PCTX_SKIP;
288 CHECK(cfg_parse_void(pctx, NULL, &obj));
289 } else {
290 result = cfg_parse_astring(pctx, type, &obj);
291 }
292
293 *ret = obj;
294 cleanup:
295 return (result);
296 }
297
298 static void
299 doc_matchname(cfg_printer_t *pctx, const cfg_type_t *type) {
300 cfg_print_cstr(pctx, "[ ");
301 cfg_doc_obj(pctx, type->of);
302 cfg_print_cstr(pctx, " ]");
303 }
304
305 static const char *matchtype_enums[] = { "6to4-self",
306 "external",
307 "krb5-self",
308 "krb5-selfsub",
309 "krb5-subdomain",
310 "ms-self",
311 "ms-selfsub",
312 "ms-subdomain",
313 "name",
314 "self",
315 "selfsub",
316 "selfwild",
317 "subdomain",
318 "tcp-self",
319 "wildcard",
320 "zonesub",
321 NULL };
322
323 static cfg_type_t cfg_type_matchtype = { "matchtype", parse_matchtype,
324 cfg_print_ustring, cfg_doc_enum,
325 &cfg_rep_string, &matchtype_enums };
326
327 static cfg_type_t cfg_type_matchname = {
328 "optional_matchname", parse_matchname, cfg_print_ustring,
329 doc_matchname, &cfg_rep_tuple, &cfg_type_ustring
330 };
331
332 /*%
333 * A grant statement, used in the update policy.
334 */
335 static cfg_tuplefielddef_t grant_fields[] = {
336 { "mode", &cfg_type_mode, 0 },
337 { "identity", &cfg_type_astring, 0 }, /* domain name */
338 { "matchtype", &cfg_type_matchtype, 0 },
339 { "name", &cfg_type_matchname, 0 }, /* domain name */
340 { "types", &cfg_type_rrtypelist, 0 },
341 { NULL, NULL, 0 }
342 };
343 static cfg_type_t cfg_type_grant = { "grant", cfg_parse_tuple,
344 cfg_print_tuple, cfg_doc_tuple,
345 &cfg_rep_tuple, grant_fields };
346
347 static cfg_type_t cfg_type_updatepolicy = {
348 "update_policy", parse_updatepolicy, print_updatepolicy,
349 doc_updatepolicy, &cfg_rep_list, &cfg_type_grant
350 };
351
352 static isc_result_t
353 parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
354 cfg_obj_t **ret) {
355 isc_result_t result;
356 CHECK(cfg_gettoken(pctx, 0));
357 if (pctx->token.type == isc_tokentype_special &&
358 pctx->token.value.as_char == '{')
359 {
360 cfg_ungettoken(pctx);
361 return (cfg_parse_bracketed_list(pctx, type, ret));
362 }
363
364 if (pctx->token.type == isc_tokentype_string &&
365 strcasecmp(TOKEN_STRING(pctx), "local") == 0)
366 {
367 cfg_obj_t *obj = NULL;
368 CHECK(cfg_create_obj(pctx, &cfg_type_ustring, &obj));
369 obj->value.string.length = strlen("local");
370 obj->value.string.base =
371 isc_mem_get(pctx->mctx, obj->value.string.length + 1);
372 memmove(obj->value.string.base, "local", 5);
373 obj->value.string.base[5] = '\0';
374 *ret = obj;
375 return (ISC_R_SUCCESS);
376 }
377
378 cfg_ungettoken(pctx);
379 return (ISC_R_UNEXPECTEDTOKEN);
380
381 cleanup:
382 return (result);
383 }
384
385 static void
386 print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj) {
387 if (cfg_obj_isstring(obj)) {
388 cfg_print_ustring(pctx, obj);
389 } else {
390 cfg_print_bracketed_list(pctx, obj);
391 }
392 }
393
394 static void
395 doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type) {
396 cfg_print_cstr(pctx, "( local | { ");
397 cfg_doc_obj(pctx, type->of);
398 cfg_print_cstr(pctx, "; ... }");
399 }
400
401 /*%
402 * A view statement.
403 */
404 static cfg_tuplefielddef_t view_fields[] = {
405 { "name", &cfg_type_astring, 0 },
406 { "class", &cfg_type_optional_class, 0 },
407 { "options", &cfg_type_viewopts, 0 },
408 { NULL, NULL, 0 }
409 };
410 static cfg_type_t cfg_type_view = { "view", cfg_parse_tuple,
411 cfg_print_tuple, cfg_doc_tuple,
412 &cfg_rep_tuple, view_fields };
413
414 /*%
415 * A zone statement.
416 */
417 static cfg_tuplefielddef_t zone_fields[] = {
418 { "name", &cfg_type_astring, 0 },
419 { "class", &cfg_type_optional_class, 0 },
420 { "options", &cfg_type_zoneopts, 0 },
421 { NULL, NULL, 0 }
422 };
423 static cfg_type_t cfg_type_zone = { "zone", cfg_parse_tuple,
424 cfg_print_tuple, cfg_doc_tuple,
425 &cfg_rep_tuple, zone_fields };
426
427 /*%
428 * A dnssec-policy statement.
429 */
430 static cfg_tuplefielddef_t dnssecpolicy_fields[] = {
431 { "name", &cfg_type_astring, 0 },
432 { "options", &cfg_type_dnssecpolicyopts, 0 },
433 { NULL, NULL, 0 }
434 };
435
436 static cfg_type_t cfg_type_dnssecpolicy = {
437 "dnssec-policy", cfg_parse_tuple, cfg_print_tuple,
438 cfg_doc_tuple, &cfg_rep_tuple, dnssecpolicy_fields
439 };
440
441 /*%
442 * A "category" clause in the "logging" statement.
443 */
444 static cfg_tuplefielddef_t category_fields[] = {
445 { "name", &cfg_type_astring, 0 },
446 { "destinations", &cfg_type_destinationlist, 0 },
447 { NULL, NULL, 0 }
448 };
449 static cfg_type_t cfg_type_category = { "category", cfg_parse_tuple,
450 cfg_print_tuple, cfg_doc_tuple,
451 &cfg_rep_tuple, category_fields };
452
453 static isc_result_t
454 parse_maxduration(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
455 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_duration, ret));
456 }
457
458 static void
459 doc_maxduration(cfg_printer_t *pctx, const cfg_type_t *type) {
460 cfg_doc_enum_or_other(pctx, type, &cfg_type_duration);
461 }
462
463 /*%
464 * A duration or "unlimited", but not "default".
465 */
466 static const char *maxduration_enums[] = { "unlimited", NULL };
467 static cfg_type_t cfg_type_maxduration = {
468 "maxduration_no_default", parse_maxduration, cfg_print_ustring,
469 doc_maxduration, &cfg_rep_duration, maxduration_enums
470 };
471
472 /*%
473 * A dnssec key, as used in the "trusted-keys" statement.
474 */
475 static cfg_tuplefielddef_t dnsseckey_fields[] = {
476 { "name", &cfg_type_astring, 0 },
477 { "anchortype", &cfg_type_void, 0 },
478 { "rdata1", &cfg_type_uint32, 0 },
479 { "rdata2", &cfg_type_uint32, 0 },
480 { "rdata3", &cfg_type_uint32, 0 },
481 { "data", &cfg_type_qstring, 0 },
482 { NULL, NULL, 0 }
483 };
484 static cfg_type_t cfg_type_dnsseckey = { "dnsseckey", cfg_parse_tuple,
485 cfg_print_tuple, cfg_doc_tuple,
486 &cfg_rep_tuple, dnsseckey_fields };
487
488 /*%
489 * Optional enums.
490 *
491 */
492 static isc_result_t
493 parse_optional_enum(cfg_parser_t *pctx, const cfg_type_t *type,
494 cfg_obj_t **ret) {
495 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_void, ret));
496 }
497
498 static void
499 doc_optional_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
500 UNUSED(type);
501 cfg_print_cstr(pctx, "[ ");
502 cfg_doc_enum(pctx, type);
503 cfg_print_cstr(pctx, " ]");
504 }
505
506 /*%
507 * A key initialization specifier, as used in the
508 * "trust-anchors" (or synonymous "managed-keys") statement.
509 */
510 static const char *anchortype_enums[] = { "static-key", "initial-key",
511 "static-ds", "initial-ds", NULL };
512 static cfg_type_t cfg_type_anchortype = { "anchortype", cfg_parse_enum,
513 cfg_print_ustring, cfg_doc_enum,
514 &cfg_rep_string, anchortype_enums };
515 static cfg_tuplefielddef_t managedkey_fields[] = {
516 { "name", &cfg_type_astring, 0 },
517 { "anchortype", &cfg_type_anchortype, 0 },
518 { "rdata1", &cfg_type_uint32, 0 },
519 { "rdata2", &cfg_type_uint32, 0 },
520 { "rdata3", &cfg_type_uint32, 0 },
521 { "data", &cfg_type_qstring, 0 },
522 { NULL, NULL, 0 }
523 };
524 static cfg_type_t cfg_type_managedkey = { "managedkey", cfg_parse_tuple,
525 cfg_print_tuple, cfg_doc_tuple,
526 &cfg_rep_tuple, managedkey_fields };
527
528 /*%
529 * DNSSEC key roles.
530 */
531 static const char *dnsseckeyrole_enums[] = { "csk", "ksk", "zsk", NULL };
532 static cfg_type_t cfg_type_dnsseckeyrole = {
533 "dnssec-key-role", cfg_parse_enum, cfg_print_ustring,
534 cfg_doc_enum, &cfg_rep_string, &dnsseckeyrole_enums
535 };
536
537 /*%
538 * DNSSEC key storage types.
539 */
540 static const char *dnsseckeystore_enums[] = { "key-directory", NULL };
541 static cfg_type_t cfg_type_dnsseckeystore = {
542 "dnssec-key-storage", parse_optional_enum, cfg_print_ustring,
543 doc_optional_enum, &cfg_rep_string, dnsseckeystore_enums
544 };
545
546 /*%
547 * A dnssec key, as used in the "keys" statement in a "dnssec-policy".
548 */
549 static keyword_type_t algorithm_kw = { "algorithm", &cfg_type_ustring };
550 static cfg_type_t cfg_type_algorithm = { "algorithm", parse_keyvalue,
551 print_keyvalue, doc_keyvalue,
552 &cfg_rep_string, &algorithm_kw };
553
554 static keyword_type_t lifetime_kw = { "lifetime",
555 &cfg_type_duration_or_unlimited };
556 static cfg_type_t cfg_type_lifetime = { "lifetime", parse_keyvalue,
557 print_keyvalue, doc_keyvalue,
558 &cfg_rep_duration, &lifetime_kw };
559
560 static cfg_tuplefielddef_t kaspkey_fields[] = {
561 { "role", &cfg_type_dnsseckeyrole, 0 },
562 { "keystore-type", &cfg_type_dnsseckeystore, 0 },
563 { "lifetime", &cfg_type_lifetime, 0 },
564 { "algorithm", &cfg_type_algorithm, 0 },
565 { "length", &cfg_type_optional_uint32, 0 },
566 { NULL, NULL, 0 }
567 };
568 static cfg_type_t cfg_type_kaspkey = { "kaspkey", cfg_parse_tuple,
569 cfg_print_tuple, cfg_doc_tuple,
570 &cfg_rep_tuple, kaspkey_fields };
571
572 /*%
573 * Wild class, type, name.
574 */
575 static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring };
576
577 static cfg_type_t cfg_type_optional_wild_class = {
578 "optional_wild_class", parse_optional_keyvalue, print_keyvalue,
579 doc_optional_keyvalue, &cfg_rep_string, &wild_class_kw
580 };
581
582 static keyword_type_t wild_type_kw = { "type", &cfg_type_ustring };
583
584 static cfg_type_t cfg_type_optional_wild_type = {
585 "optional_wild_type", parse_optional_keyvalue, print_keyvalue,
586 doc_optional_keyvalue, &cfg_rep_string, &wild_type_kw
587 };
588
589 static keyword_type_t wild_name_kw = { "name", &cfg_type_qstring };
590
591 static cfg_type_t cfg_type_optional_wild_name = {
592 "optional_wild_name", parse_optional_keyvalue, print_keyvalue,
593 doc_optional_keyvalue, &cfg_rep_string, &wild_name_kw
594 };
595
596 /*%
597 * An rrset ordering element.
598 */
599 static cfg_tuplefielddef_t rrsetorderingelement_fields[] = {
600 { "class", &cfg_type_optional_wild_class, 0 },
601 { "type", &cfg_type_optional_wild_type, 0 },
602 { "name", &cfg_type_optional_wild_name, 0 },
603 { "order", &cfg_type_ustring, 0 }, /* must be literal "order" */
604 { "ordering", &cfg_type_ustring, 0 },
605 { NULL, NULL, 0 }
606 };
607 static cfg_type_t cfg_type_rrsetorderingelement = {
608 "rrsetorderingelement", cfg_parse_tuple, cfg_print_tuple,
609 cfg_doc_tuple, &cfg_rep_tuple, rrsetorderingelement_fields
610 };
611
612 /*%
613 * A global or view "check-names" option. Note that the zone
614 * "check-names" option has a different syntax.
615 */
616
617 static const char *checktype_enums[] = { "primary", "master", "secondary",
618 "slave", "response", NULL };
619 static cfg_type_t cfg_type_checktype = { "checktype", cfg_parse_enum,
620 cfg_print_ustring, cfg_doc_enum,
621 &cfg_rep_string, &checktype_enums };
622
623 static const char *checkmode_enums[] = { "fail", "warn", "ignore", NULL };
624 static cfg_type_t cfg_type_checkmode = { "checkmode", cfg_parse_enum,
625 cfg_print_ustring, cfg_doc_enum,
626 &cfg_rep_string, &checkmode_enums };
627
628 static const char *warn_enums[] = { "warn", "ignore", NULL };
629 static cfg_type_t cfg_type_warn = {
630 "warn", cfg_parse_enum, cfg_print_ustring,
631 cfg_doc_enum, &cfg_rep_string, &warn_enums
632 };
633
634 static cfg_tuplefielddef_t checknames_fields[] = {
635 { "type", &cfg_type_checktype, 0 },
636 { "mode", &cfg_type_checkmode, 0 },
637 { NULL, NULL, 0 }
638 };
639
640 static cfg_type_t cfg_type_checknames = { "checknames", cfg_parse_tuple,
641 cfg_print_tuple, cfg_doc_tuple,
642 &cfg_rep_tuple, checknames_fields };
643
644 static cfg_type_t cfg_type_bracketed_dscpsockaddrlist = {
645 "bracketed_sockaddrlist",
646 cfg_parse_bracketed_list,
647 cfg_print_bracketed_list,
648 cfg_doc_bracketed_list,
649 &cfg_rep_list,
650 &cfg_type_sockaddrdscp
651 };
652
653 static cfg_type_t cfg_type_bracketed_netaddrlist = { "bracketed_netaddrlist",
654 cfg_parse_bracketed_list,
655 cfg_print_bracketed_list,
656 cfg_doc_bracketed_list,
657 &cfg_rep_list,
658 &cfg_type_netaddr };
659
660 static const char *autodnssec_enums[] = { "allow", "maintain", "off", NULL };
661 static cfg_type_t cfg_type_autodnssec = {
662 "autodnssec", cfg_parse_enum, cfg_print_ustring,
663 cfg_doc_enum, &cfg_rep_string, &autodnssec_enums
664 };
665
666 static const char *dnssecupdatemode_enums[] = { "maintain", "no-resign", NULL };
667 static cfg_type_t cfg_type_dnssecupdatemode = {
668 "dnssecupdatemode", cfg_parse_enum, cfg_print_ustring,
669 cfg_doc_enum, &cfg_rep_string, &dnssecupdatemode_enums
670 };
671
672 static const char *updatemethods_enums[] = { "date", "increment", "unixtime",
673 NULL };
674 static cfg_type_t cfg_type_updatemethod = {
675 "updatemethod", cfg_parse_enum, cfg_print_ustring,
676 cfg_doc_enum, &cfg_rep_string, &updatemethods_enums
677 };
678
679 /*
680 * zone-statistics: full, terse, or none.
681 *
682 * for backward compatibility, we also support boolean values.
683 * yes represents "full", no represents "terse". in the future we
684 * may change no to mean "none".
685 */
686 static const char *zonestat_enums[] = { "full", "terse", "none", NULL };
687 static isc_result_t
688 parse_zonestat(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
689 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
690 }
691 static void
692 doc_zonestat(cfg_printer_t *pctx, const cfg_type_t *type) {
693 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
694 }
695 static cfg_type_t cfg_type_zonestat = { "zonestat", parse_zonestat,
696 cfg_print_ustring, doc_zonestat,
697 &cfg_rep_string, zonestat_enums };
698
699 static cfg_type_t cfg_type_rrsetorder = { "rrsetorder",
700 cfg_parse_bracketed_list,
701 cfg_print_bracketed_list,
702 cfg_doc_bracketed_list,
703 &cfg_rep_list,
704 &cfg_type_rrsetorderingelement };
705
706 static keyword_type_t dscp_kw = { "dscp", &cfg_type_uint32 };
707
708 static cfg_type_t cfg_type_optional_dscp = {
709 "optional_dscp", parse_optional_keyvalue, print_keyvalue,
710 doc_optional_keyvalue, &cfg_rep_uint32, &dscp_kw
711 };
712
713 static keyword_type_t port_kw = { "port", &cfg_type_uint32 };
714
715 static cfg_type_t cfg_type_optional_port = {
716 "optional_port", parse_optional_keyvalue, print_keyvalue,
717 doc_optional_keyvalue, &cfg_rep_uint32, &port_kw
718 };
719
720 /*% A list of keys, as in the "key" clause of the controls statement. */
721 static cfg_type_t cfg_type_keylist = { "keylist",
722 cfg_parse_bracketed_list,
723 cfg_print_bracketed_list,
724 cfg_doc_bracketed_list,
725 &cfg_rep_list,
726 &cfg_type_astring };
727
728 /*% A list of dnssec keys, as in "trusted-keys". Deprecated. */
729 static cfg_type_t cfg_type_trustedkeys = { "trustedkeys",
730 cfg_parse_bracketed_list,
731 cfg_print_bracketed_list,
732 cfg_doc_bracketed_list,
733 &cfg_rep_list,
734 &cfg_type_dnsseckey };
735
736 /*%
737 * A list of managed trust anchors. Each entry contains a name, a keyword
738 * ("static-key", initial-key", "static-ds" or "initial-ds"), and the
739 * fields associated with either a DNSKEY or a DS record.
740 */
741 static cfg_type_t cfg_type_dnsseckeys = { "dnsseckeys",
742 cfg_parse_bracketed_list,
743 cfg_print_bracketed_list,
744 cfg_doc_bracketed_list,
745 &cfg_rep_list,
746 &cfg_type_managedkey };
747
748 /*%
749 * A list of key entries, used in a DNSSEC Key and Signing Policy.
750 */
751 static cfg_type_t cfg_type_kaspkeys = { "kaspkeys",
752 cfg_parse_bracketed_list,
753 cfg_print_bracketed_list,
754 cfg_doc_bracketed_list,
755 &cfg_rep_list,
756 &cfg_type_kaspkey };
757
758 static const char *forwardtype_enums[] = { "first", "only", NULL };
759 static cfg_type_t cfg_type_forwardtype = {
760 "forwardtype", cfg_parse_enum, cfg_print_ustring,
761 cfg_doc_enum, &cfg_rep_string, &forwardtype_enums
762 };
763
764 static const char *zonetype_enums[] = {
765 "primary", "master", "secondary", "slave",
766 "mirror", "delegation-only", "forward", "hint",
767 "redirect", "static-stub", "stub", NULL
768 };
769 static cfg_type_t cfg_type_zonetype = { "zonetype", cfg_parse_enum,
770 cfg_print_ustring, cfg_doc_enum,
771 &cfg_rep_string, &zonetype_enums };
772
773 static const char *loglevel_enums[] = { "critical", "error", "warning",
774 "notice", "info", "dynamic",
775 NULL };
776 static cfg_type_t cfg_type_loglevel = { "loglevel", cfg_parse_enum,
777 cfg_print_ustring, cfg_doc_enum,
778 &cfg_rep_string, &loglevel_enums };
779
780 static const char *transferformat_enums[] = { "many-answers", "one-answer",
781 NULL };
782 static cfg_type_t cfg_type_transferformat = {
783 "transferformat", cfg_parse_enum, cfg_print_ustring,
784 cfg_doc_enum, &cfg_rep_string, &transferformat_enums
785 };
786
787 /*%
788 * The special keyword "none", as used in the pid-file option.
789 */
790
791 static void
792 print_none(cfg_printer_t *pctx, const cfg_obj_t *obj) {
793 UNUSED(obj);
794 cfg_print_cstr(pctx, "none");
795 }
796
797 static cfg_type_t cfg_type_none = { "none", NULL, print_none,
798 NULL, &cfg_rep_void, NULL };
799
800 /*%
801 * A quoted string or the special keyword "none". Used in the pid-file option.
802 */
803 static isc_result_t
804 parse_qstringornone(cfg_parser_t *pctx, const cfg_type_t *type,
805 cfg_obj_t **ret) {
806 isc_result_t result;
807
808 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
809 if (pctx->token.type == isc_tokentype_string &&
810 strcasecmp(TOKEN_STRING(pctx), "none") == 0)
811 {
812 return (cfg_create_obj(pctx, &cfg_type_none, ret));
813 }
814 cfg_ungettoken(pctx);
815 return (cfg_parse_qstring(pctx, type, ret));
816 cleanup:
817 return (result);
818 }
819
820 static void
821 doc_qstringornone(cfg_printer_t *pctx, const cfg_type_t *type) {
822 UNUSED(type);
823 cfg_print_cstr(pctx, "( <quoted_string> | none )");
824 }
825
826 static cfg_type_t cfg_type_qstringornone = { "qstringornone",
827 parse_qstringornone,
828 NULL,
829 doc_qstringornone,
830 NULL,
831 NULL };
832
833 /*%
834 * A boolean ("yes" or "no"), or the special keyword "auto".
835 * Used in the dnssec-validation option.
836 */
837 static void
838 print_auto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
839 UNUSED(obj);
840 cfg_print_cstr(pctx, "auto");
841 }
842
843 static cfg_type_t cfg_type_auto = { "auto", NULL, print_auto,
844 NULL, &cfg_rep_void, NULL };
845
846 static isc_result_t
847 parse_boolorauto(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
848 isc_result_t result;
849
850 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
851 if (pctx->token.type == isc_tokentype_string &&
852 strcasecmp(TOKEN_STRING(pctx), "auto") == 0)
853 {
854 return (cfg_create_obj(pctx, &cfg_type_auto, ret));
855 }
856 cfg_ungettoken(pctx);
857 return (cfg_parse_boolean(pctx, type, ret));
858 cleanup:
859 return (result);
860 }
861
862 static void
863 print_boolorauto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
864 if (obj->type->rep == &cfg_rep_void) {
865 cfg_print_cstr(pctx, "auto");
866 } else if (obj->value.boolean) {
867 cfg_print_cstr(pctx, "yes");
868 } else {
869 cfg_print_cstr(pctx, "no");
870 }
871 }
872
873 static void
874 doc_boolorauto(cfg_printer_t *pctx, const cfg_type_t *type) {
875 UNUSED(type);
876 cfg_print_cstr(pctx, "( yes | no | auto )");
877 }
878
879 static cfg_type_t cfg_type_boolorauto = {
880 "boolorauto", parse_boolorauto, print_boolorauto, doc_boolorauto, NULL,
881 NULL
882 };
883
884 /*%
885 * keyword hostname
886 */
887 static void
888 print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) {
889 UNUSED(obj);
890 cfg_print_cstr(pctx, "hostname");
891 }
892
893 static cfg_type_t cfg_type_hostname = { "hostname", NULL,
894 print_hostname, NULL,
895 &cfg_rep_boolean, NULL };
896
897 /*%
898 * "server-id" argument.
899 */
900
901 static isc_result_t
902 parse_serverid(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
903 isc_result_t result;
904 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
905 if (pctx->token.type == isc_tokentype_string &&
906 strcasecmp(TOKEN_STRING(pctx), "none") == 0)
907 {
908 return (cfg_create_obj(pctx, &cfg_type_none, ret));
909 }
910 if (pctx->token.type == isc_tokentype_string &&
911 strcasecmp(TOKEN_STRING(pctx), "hostname") == 0)
912 {
913 result = cfg_create_obj(pctx, &cfg_type_hostname, ret);
914 if (result == ISC_R_SUCCESS) {
915 (*ret)->value.boolean = true;
916 }
917 return (result);
918 }
919 cfg_ungettoken(pctx);
920 return (cfg_parse_qstring(pctx, type, ret));
921 cleanup:
922 return (result);
923 }
924
925 static void
926 doc_serverid(cfg_printer_t *pctx, const cfg_type_t *type) {
927 UNUSED(type);
928 cfg_print_cstr(pctx, "( <quoted_string> | none | hostname )");
929 }
930
931 static cfg_type_t cfg_type_serverid = { "serverid", parse_serverid, NULL,
932 doc_serverid, NULL, NULL };
933
934 /*%
935 * Port list.
936 */
937 static void
938 print_porttuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
939 cfg_print_cstr(pctx, "range ");
940 cfg_print_tuple(pctx, obj);
941 }
942 static cfg_tuplefielddef_t porttuple_fields[] = {
943 { "loport", &cfg_type_uint32, 0 },
944 { "hiport", &cfg_type_uint32, 0 },
945 { NULL, NULL, 0 }
946 };
947 static cfg_type_t cfg_type_porttuple = { "porttuple", cfg_parse_tuple,
948 print_porttuple, cfg_doc_tuple,
949 &cfg_rep_tuple, porttuple_fields };
950
951 static isc_result_t
952 parse_port(cfg_parser_t *pctx, cfg_obj_t **ret) {
953 isc_result_t result;
954
955 CHECK(cfg_parse_uint32(pctx, NULL, ret));
956 if ((*ret)->value.uint32 > 0xffff) {
957 cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid port");
958 cfg_obj_destroy(pctx, ret);
959 result = ISC_R_RANGE;
960 }
961
962 cleanup:
963 return (result);
964 }
965
966 static isc_result_t
967 parse_portrange(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
968 isc_result_t result;
969 cfg_obj_t *obj = NULL;
970
971 UNUSED(type);
972
973 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
974 if (pctx->token.type == isc_tokentype_number) {
975 CHECK(parse_port(pctx, ret));
976 } else {
977 CHECK(cfg_gettoken(pctx, 0));
978 if (pctx->token.type != isc_tokentype_string ||
979 strcasecmp(TOKEN_STRING(pctx), "range") != 0)
980 {
981 cfg_parser_error(pctx, CFG_LOG_NEAR,
982 "expected integer or 'range'");
983 return (ISC_R_UNEXPECTEDTOKEN);
984 }
985 CHECK(cfg_create_tuple(pctx, &cfg_type_porttuple, &obj));
986 CHECK(parse_port(pctx, &obj->value.tuple[0]));
987 CHECK(parse_port(pctx, &obj->value.tuple[1]));
988 if (obj->value.tuple[0]->value.uint32 >
989 obj->value.tuple[1]->value.uint32) {
990 cfg_parser_error(pctx, CFG_LOG_NOPREP,
991 "low port '%u' must not be larger "
992 "than high port",
993 obj->value.tuple[0]->value.uint32);
994 result = ISC_R_RANGE;
995 goto cleanup;
996 }
997 *ret = obj;
998 obj = NULL;
999 }
1000
1001 cleanup:
1002 if (obj != NULL) {
1003 cfg_obj_destroy(pctx, &obj);
1004 }
1005 return (result);
1006 }
1007
1008 static cfg_type_t cfg_type_portrange = { "portrange", parse_portrange,
1009 NULL, cfg_doc_terminal,
1010 NULL, NULL };
1011
1012 static cfg_type_t cfg_type_bracketed_portlist = { "bracketed_sockaddrlist",
1013 cfg_parse_bracketed_list,
1014 cfg_print_bracketed_list,
1015 cfg_doc_bracketed_list,
1016 &cfg_rep_list,
1017 &cfg_type_portrange };
1018
1019 static const char *cookiealg_enums[] = { "aes", "siphash24", NULL };
1020 static cfg_type_t cfg_type_cookiealg = { "cookiealg", cfg_parse_enum,
1021 cfg_print_ustring, cfg_doc_enum,
1022 &cfg_rep_string, &cookiealg_enums };
1023
1024 /*%
1025 * fetch-quota-params
1026 */
1027
1028 static cfg_tuplefielddef_t fetchquota_fields[] = {
1029 { "frequency", &cfg_type_uint32, 0 },
1030 { "low", &cfg_type_fixedpoint, 0 },
1031 { "high", &cfg_type_fixedpoint, 0 },
1032 { "discount", &cfg_type_fixedpoint, 0 },
1033 { NULL, NULL, 0 }
1034 };
1035
1036 static cfg_type_t cfg_type_fetchquota = { "fetchquota", cfg_parse_tuple,
1037 cfg_print_tuple, cfg_doc_tuple,
1038 &cfg_rep_tuple, fetchquota_fields };
1039
1040 /*%
1041 * fetches-per-server or fetches-per-zone
1042 */
1043
1044 static const char *response_enums[] = { "drop", "fail", NULL };
1045
1046 static cfg_type_t cfg_type_responsetype = {
1047 "responsetype", parse_optional_enum, cfg_print_ustring,
1048 doc_optional_enum, &cfg_rep_string, response_enums
1049 };
1050
1051 static cfg_tuplefielddef_t fetchesper_fields[] = {
1052 { "fetches", &cfg_type_uint32, 0 },
1053 { "response", &cfg_type_responsetype, 0 },
1054 { NULL, NULL, 0 }
1055 };
1056
1057 static cfg_type_t cfg_type_fetchesper = { "fetchesper", cfg_parse_tuple,
1058 cfg_print_tuple, cfg_doc_tuple,
1059 &cfg_rep_tuple, fetchesper_fields };
1060
1061 /*%
1062 * Clauses that can be found within the top level of the named.conf
1063 * file only.
1064 */
1065 static cfg_clausedef_t namedconf_clauses[] = {
1066 { "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
1067 { "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
1068 { "dnssec-policy", &cfg_type_dnssecpolicy, CFG_CLAUSEFLAG_MULTI },
1069 { "logging", &cfg_type_logging, 0 },
1070 { "lwres", &cfg_type_bracketed_text,
1071 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE },
1072 { "masters", &cfg_type_masters, CFG_CLAUSEFLAG_MULTI },
1073 { "options", &cfg_type_options, 0 },
1074 { "statistics-channels", &cfg_type_statschannels,
1075 CFG_CLAUSEFLAG_MULTI },
1076 { "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI },
1077 { NULL, NULL, 0 }
1078 };
1079
1080 /*%
1081 * Clauses that can occur at the top level or in the view
1082 * statement, but not in the options block.
1083 */
1084 static cfg_clausedef_t namedconf_or_view_clauses[] = {
1085 { "dlz", &cfg_type_dlz, CFG_CLAUSEFLAG_MULTI },
1086 { "dyndb", &cfg_type_dyndb, CFG_CLAUSEFLAG_MULTI },
1087 { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
1088 { "managed-keys", &cfg_type_dnsseckeys,
1089 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_DEPRECATED },
1090 { "plugin", &cfg_type_plugin, CFG_CLAUSEFLAG_MULTI },
1091 { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI },
1092 { "trust-anchors", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
1093 { "trusted-keys", &cfg_type_trustedkeys,
1094 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_DEPRECATED },
1095 { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
1096 { NULL, NULL, 0 }
1097 };
1098
1099 /*%
1100 * Clauses that can occur in the bind.keys file.
1101 */
1102 static cfg_clausedef_t bindkeys_clauses[] = {
1103 { "managed-keys", &cfg_type_dnsseckeys,
1104 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_DEPRECATED },
1105 { "trust-anchors", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
1106 { "trusted-keys", &cfg_type_trustedkeys,
1107 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_DEPRECATED },
1108 { NULL, NULL, 0 }
1109 };
1110
1111 static const char *fstrm_model_enums[] = { "mpsc", "spsc", NULL };
1112 static cfg_type_t cfg_type_fstrm_model = {
1113 "model", cfg_parse_enum, cfg_print_ustring,
1114 cfg_doc_enum, &cfg_rep_string, &fstrm_model_enums
1115 };
1116
1117 /*%
1118 * Clauses that can be found within the 'options' statement.
1119 */
1120 static cfg_clausedef_t options_clauses[] = {
1121 { "answer-cookie", &cfg_type_boolean, 0 },
1122 { "automatic-interface-scan", &cfg_type_boolean, 0 },
1123 { "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
1124 { "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
1125 { "bindkeys-file", &cfg_type_qstring, 0 },
1126 { "blackhole", &cfg_type_bracketed_aml, 0 },
1127 { "cookie-algorithm", &cfg_type_cookiealg, 0 },
1128 { "cookie-secret", &cfg_type_sstring, CFG_CLAUSEFLAG_MULTI },
1129 { "coresize", &cfg_type_size, 0 },
1130 { "datasize", &cfg_type_size, 0 },
1131 { "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT },
1132 { "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK },
1133 #ifdef HAVE_DNSTAP
1134 { "dnstap-output", &cfg_type_dnstapoutput, 0 },
1135 { "dnstap-identity", &cfg_type_serverid, 0 },
1136 { "dnstap-version", &cfg_type_qstringornone, 0 },
1137 #else /* ifdef HAVE_DNSTAP */
1138 { "dnstap-output", &cfg_type_dnstapoutput,
1139 CFG_CLAUSEFLAG_NOTCONFIGURED },
1140 { "dnstap-identity", &cfg_type_serverid, CFG_CLAUSEFLAG_NOTCONFIGURED },
1141 { "dnstap-version", &cfg_type_qstringornone,
1142 CFG_CLAUSEFLAG_NOTCONFIGURED },
1143 #endif /* ifdef HAVE_DNSTAP */
1144 { "dscp", &cfg_type_uint32, 0 },
1145 { "dump-file", &cfg_type_qstring, 0 },
1146 { "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT },
1147 { "files", &cfg_type_size, 0 },
1148 { "flush-zones-on-shutdown", &cfg_type_boolean, 0 },
1149 #ifdef HAVE_DNSTAP
1150 { "fstrm-set-buffer-hint", &cfg_type_uint32, 0 },
1151 { "fstrm-set-flush-timeout", &cfg_type_uint32, 0 },
1152 { "fstrm-set-input-queue-size", &cfg_type_uint32, 0 },
1153 { "fstrm-set-output-notify-threshold", &cfg_type_uint32, 0 },
1154 { "fstrm-set-output-queue-model", &cfg_type_fstrm_model, 0 },
1155 { "fstrm-set-output-queue-size", &cfg_type_uint32, 0 },
1156 { "fstrm-set-reopen-interval", &cfg_type_duration, 0 },
1157 #else /* ifdef HAVE_DNSTAP */
1158 { "fstrm-set-buffer-hint", &cfg_type_uint32,
1159 CFG_CLAUSEFLAG_NOTCONFIGURED },
1160 { "fstrm-set-flush-timeout", &cfg_type_uint32,
1161 CFG_CLAUSEFLAG_NOTCONFIGURED },
1162 { "fstrm-set-input-queue-size", &cfg_type_uint32,
1163 CFG_CLAUSEFLAG_NOTCONFIGURED },
1164 { "fstrm-set-output-notify-threshold", &cfg_type_uint32,
1165 CFG_CLAUSEFLAG_NOTCONFIGURED },
1166 { "fstrm-set-output-queue-model", &cfg_type_fstrm_model,
1167 CFG_CLAUSEFLAG_NOTCONFIGURED },
1168 { "fstrm-set-output-queue-size", &cfg_type_uint32,
1169 CFG_CLAUSEFLAG_NOTCONFIGURED },
1170 { "fstrm-set-reopen-interval", &cfg_type_duration,
1171 CFG_CLAUSEFLAG_NOTCONFIGURED },
1172 #endif /* HAVE_DNSTAP */
1173 #if defined(HAVE_GEOIP2)
1174 { "geoip-directory", &cfg_type_qstringornone, 0 },
1175 #else /* if defined(HAVE_GEOIP2) */
1176 { "geoip-directory", &cfg_type_qstringornone,
1177 CFG_CLAUSEFLAG_NOTCONFIGURED },
1178 #endif /* HAVE_GEOIP2 */
1179 { "geoip-use-ecs", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1180 { "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT },
1181 { "heartbeat-interval", &cfg_type_uint32, 0 },
1182 { "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT },
1183 { "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_ANCIENT },
1184 { "hostname", &cfg_type_qstringornone, 0 },
1185 { "interface-interval", &cfg_type_duration, 0 },
1186 { "keep-response-order", &cfg_type_bracketed_aml, 0 },
1187 { "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
1188 { "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
1189 { "lock-file", &cfg_type_qstringornone, 0 },
1190 { "managed-keys-directory", &cfg_type_qstring, 0 },
1191 { "match-mapped-addresses", &cfg_type_boolean, 0 },
1192 { "max-rsa-exponent-size", &cfg_type_uint32, 0 },
1193 { "memstatistics", &cfg_type_boolean, 0 },
1194 { "memstatistics-file", &cfg_type_qstring, 0 },
1195 { "multiple-cnames", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT },
1196 { "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_ANCIENT },
1197 { "notify-rate", &cfg_type_uint32, 0 },
1198 { "pid-file", &cfg_type_qstringornone, 0 },
1199 { "port", &cfg_type_uint32, 0 },
1200 { "querylog", &cfg_type_boolean, 0 },
1201 { "random-device", &cfg_type_qstringornone, 0 },
1202 { "recursing-file", &cfg_type_qstring, 0 },
1203 { "recursive-clients", &cfg_type_uint32, 0 },
1204 { "reserved-sockets", &cfg_type_uint32, 0 },
1205 { "secroots-file", &cfg_type_qstring, 0 },
1206 { "serial-queries", &cfg_type_uint32, CFG_CLAUSEFLAG_ANCIENT },
1207 { "serial-query-rate", &cfg_type_uint32, 0 },
1208 { "server-id", &cfg_type_serverid, 0 },
1209 { "session-keyalg", &cfg_type_astring, 0 },
1210 { "session-keyfile", &cfg_type_qstringornone, 0 },
1211 { "session-keyname", &cfg_type_astring, 0 },
1212 { "sit-secret", &cfg_type_sstring, CFG_CLAUSEFLAG_OBSOLETE },
1213 { "stacksize", &cfg_type_size, 0 },
1214 { "startup-notify-rate", &cfg_type_uint32, 0 },
1215 { "statistics-file", &cfg_type_qstring, 0 },
1216 { "statistics-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_ANCIENT },
1217 { "tcp-advertised-timeout", &cfg_type_uint32, 0 },
1218 { "tcp-clients", &cfg_type_uint32, 0 },
1219 { "tcp-idle-timeout", &cfg_type_uint32, 0 },
1220 { "tcp-initial-timeout", &cfg_type_uint32, 0 },
1221 { "tcp-keepalive-timeout", &cfg_type_uint32, 0 },
1222 { "tcp-listen-queue", &cfg_type_uint32, 0 },
1223 { "tkey-dhkey", &cfg_type_tkey_dhkey, 0 },
1224 { "tkey-domain", &cfg_type_qstring, 0 },
1225 { "tkey-gssapi-credential", &cfg_type_qstring, 0 },
1226 { "tkey-gssapi-keytab", &cfg_type_qstring, 0 },
1227 { "transfer-message-size", &cfg_type_uint32, 0 },
1228 { "transfers-in", &cfg_type_uint32, 0 },
1229 { "transfers-out", &cfg_type_uint32, 0 },
1230 { "transfers-per-ns", &cfg_type_uint32, 0 },
1231 { "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT },
1232 { "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT },
1233 { "use-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1234 { "use-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
1235 { "use-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
1236 { "version", &cfg_type_qstringornone, 0 },
1237 { NULL, NULL, 0 }
1238 };
1239
1240 static cfg_type_t cfg_type_namelist = { "namelist",
1241 cfg_parse_bracketed_list,
1242 cfg_print_bracketed_list,
1243 cfg_doc_bracketed_list,
1244 &cfg_rep_list,
1245 &cfg_type_astring };
1246
1247 static keyword_type_t exclude_kw = { "exclude", &cfg_type_namelist };
1248
1249 static cfg_type_t cfg_type_optional_exclude = {
1250 "optional_exclude", parse_optional_keyvalue, print_keyvalue,
1251 doc_optional_keyvalue, &cfg_rep_list, &exclude_kw
1252 };
1253
1254 static keyword_type_t exceptionnames_kw = { "except-from", &cfg_type_namelist };
1255
1256 static cfg_type_t cfg_type_optional_exceptionnames = {
1257 "optional_allow", parse_optional_keyvalue, print_keyvalue,
1258 doc_optional_keyvalue, &cfg_rep_list, &exceptionnames_kw
1259 };
1260
1261 static cfg_tuplefielddef_t denyaddresses_fields[] = {
1262 { "acl", &cfg_type_bracketed_aml, 0 },
1263 { "except-from", &cfg_type_optional_exceptionnames, 0 },
1264 { NULL, NULL, 0 }
1265 };
1266
1267 static cfg_type_t cfg_type_denyaddresses = {
1268 "denyaddresses", cfg_parse_tuple, cfg_print_tuple,
1269 cfg_doc_tuple, &cfg_rep_tuple, denyaddresses_fields
1270 };
1271
1272 static cfg_tuplefielddef_t denyaliases_fields[] = {
1273 { "name", &cfg_type_namelist, 0 },
1274 { "except-from", &cfg_type_optional_exceptionnames, 0 },
1275 { NULL, NULL, 0 }
1276 };
1277
1278 static cfg_type_t cfg_type_denyaliases = {
1279 "denyaliases", cfg_parse_tuple, cfg_print_tuple,
1280 cfg_doc_tuple, &cfg_rep_tuple, denyaliases_fields
1281 };
1282
1283 static cfg_type_t cfg_type_algorithmlist = { "algorithmlist",
1284 cfg_parse_bracketed_list,
1285 cfg_print_bracketed_list,
1286 cfg_doc_bracketed_list,
1287 &cfg_rep_list,
1288 &cfg_type_astring };
1289
1290 static cfg_tuplefielddef_t disablealgorithm_fields[] = {
1291 { "name", &cfg_type_astring, 0 },
1292 { "algorithms", &cfg_type_algorithmlist, 0 },
1293 { NULL, NULL, 0 }
1294 };
1295
1296 static cfg_type_t cfg_type_disablealgorithm = {
1297 "disablealgorithm", cfg_parse_tuple, cfg_print_tuple,
1298 cfg_doc_tuple, &cfg_rep_tuple, disablealgorithm_fields
1299 };
1300
1301 static cfg_type_t cfg_type_dsdigestlist = { "dsdigestlist",
1302 cfg_parse_bracketed_list,
1303 cfg_print_bracketed_list,
1304 cfg_doc_bracketed_list,
1305 &cfg_rep_list,
1306 &cfg_type_astring };
1307
1308 static cfg_tuplefielddef_t disabledsdigest_fields[] = {
1309 { "name", &cfg_type_astring, 0 },
1310 { "digests", &cfg_type_dsdigestlist, 0 },
1311 { NULL, NULL, 0 }
1312 };
1313
1314 static cfg_type_t cfg_type_disabledsdigest = {
1315 "disabledsdigest", cfg_parse_tuple, cfg_print_tuple,
1316 cfg_doc_tuple, &cfg_rep_tuple, disabledsdigest_fields
1317 };
1318
1319 static cfg_tuplefielddef_t mustbesecure_fields[] = {
1320 { "name", &cfg_type_astring, 0 },
1321 { "value", &cfg_type_boolean, 0 },
1322 { NULL, NULL, 0 }
1323 };
1324
1325 static cfg_type_t cfg_type_mustbesecure = {
1326 "mustbesecure", cfg_parse_tuple, cfg_print_tuple,
1327 cfg_doc_tuple, &cfg_rep_tuple, mustbesecure_fields
1328 };
1329
1330 static const char *masterformat_enums[] = { "map", "raw", "text", NULL };
1331 static cfg_type_t cfg_type_masterformat = {
1332 "masterformat", cfg_parse_enum, cfg_print_ustring,
1333 cfg_doc_enum, &cfg_rep_string, &masterformat_enums
1334 };
1335
1336 static const char *masterstyle_enums[] = { "full", "relative", NULL };
1337 static cfg_type_t cfg_type_masterstyle = {
1338 "masterstyle", cfg_parse_enum, cfg_print_ustring,
1339 cfg_doc_enum, &cfg_rep_string, &masterstyle_enums
1340 };
1341
1342 static keyword_type_t blocksize_kw = { "block-size", &cfg_type_uint32 };
1343
1344 static cfg_type_t cfg_type_blocksize = { "blocksize", parse_keyvalue,
1345 print_keyvalue, doc_keyvalue,
1346 &cfg_rep_uint32, &blocksize_kw };
1347
1348 static cfg_tuplefielddef_t resppadding_fields[] = {
1349 { "acl", &cfg_type_bracketed_aml, 0 },
1350 { "block-size", &cfg_type_blocksize, 0 },
1351 { NULL, NULL, 0 }
1352 };
1353
1354 static cfg_type_t cfg_type_resppadding = {
1355 "resppadding", cfg_parse_tuple, cfg_print_tuple,
1356 cfg_doc_tuple, &cfg_rep_tuple, resppadding_fields
1357 };
1358
1359 /*%
1360 * dnstap {
1361 * <message type> [query | response] ;
1362 * ...
1363 * }
1364 *
1365 * ... where message type is one of: client, resolver, auth, forwarder,
1366 * update, all
1367 */
1368 static const char *dnstap_types[] = { "all", "auth", "client",
1369 "forwarder", "resolver", "update",
1370 NULL };
1371
1372 static const char *dnstap_modes[] = { "query", "response", NULL };
1373
1374 static cfg_type_t cfg_type_dnstap_type = { "dnstap_type", cfg_parse_enum,
1375 cfg_print_ustring, cfg_doc_enum,
1376 &cfg_rep_string, dnstap_types };
1377
1378 static cfg_type_t cfg_type_dnstap_mode = {
1379 "dnstap_mode", parse_optional_enum, cfg_print_ustring,
1380 doc_optional_enum, &cfg_rep_string, dnstap_modes
1381 };
1382
1383 static cfg_tuplefielddef_t dnstap_fields[] = {
1384 { "type", &cfg_type_dnstap_type, 0 },
1385 { "mode", &cfg_type_dnstap_mode, 0 },
1386 { NULL, NULL, 0 }
1387 };
1388
1389 static cfg_type_t cfg_type_dnstap_entry = { "dnstap_value", cfg_parse_tuple,
1390 cfg_print_tuple, cfg_doc_tuple,
1391 &cfg_rep_tuple, dnstap_fields };
1392
1393 static cfg_type_t cfg_type_dnstap = { "dnstap",
1394 cfg_parse_bracketed_list,
1395 cfg_print_bracketed_list,
1396 cfg_doc_bracketed_list,
1397 &cfg_rep_list,
1398 &cfg_type_dnstap_entry };
1399
1400 /*%
1401 * dnstap-output
1402 */
1403 static isc_result_t
1404 parse_dtout(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1405 isc_result_t result;
1406 cfg_obj_t *obj = NULL;
1407 const cfg_tuplefielddef_t *fields = type->of;
1408
1409 CHECK(cfg_create_tuple(pctx, type, &obj));
1410
1411 /* Parse the mandatory "mode" and "path" fields */
1412 CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
1413 CHECK(cfg_parse_obj(pctx, fields[1].type, &obj->value.tuple[1]));
1414
1415 /* Parse "versions" and "size" fields in any order. */
1416 for (;;) {
1417 CHECK(cfg_peektoken(pctx, 0));
1418 if (pctx->token.type == isc_tokentype_string) {
1419 CHECK(cfg_gettoken(pctx, 0));
1420 if (strcasecmp(TOKEN_STRING(pctx), "size") == 0 &&
1421 obj->value.tuple[2] == NULL) {
1422 CHECK(cfg_parse_obj(pctx, fields[2].type,
1423 &obj->value.tuple[2]));
1424 } else if (strcasecmp(TOKEN_STRING(pctx), "versions") ==
1425 0 &&
1426 obj->value.tuple[3] == NULL)
1427 {
1428 CHECK(cfg_parse_obj(pctx, fields[3].type,
1429 &obj->value.tuple[3]));
1430 } else if (strcasecmp(TOKEN_STRING(pctx), "suffix") ==
1431 0 &&
1432 obj->value.tuple[4] == NULL)
1433 {
1434 CHECK(cfg_parse_obj(pctx, fields[4].type,
1435 &obj->value.tuple[4]));
1436 } else {
1437 cfg_parser_error(pctx, CFG_LOG_NEAR,
1438 "unexpected token");
1439 result = ISC_R_UNEXPECTEDTOKEN;
1440 goto cleanup;
1441 }
1442 } else {
1443 break;
1444 }
1445 }
1446
1447 /* Create void objects for missing optional values. */
1448 if (obj->value.tuple[2] == NULL) {
1449 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2]));
1450 }
1451 if (obj->value.tuple[3] == NULL) {
1452 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[3]));
1453 }
1454 if (obj->value.tuple[4] == NULL) {
1455 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[4]));
1456 }
1457
1458 *ret = obj;
1459 return (ISC_R_SUCCESS);
1460
1461 cleanup:
1462 CLEANUP_OBJ(obj);
1463 return (result);
1464 }
1465
1466 static void
1467 print_dtout(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1468 cfg_print_obj(pctx, obj->value.tuple[0]); /* mode */
1469 cfg_print_obj(pctx, obj->value.tuple[1]); /* file */
1470 if (obj->value.tuple[2]->type->print != cfg_print_void) {
1471 cfg_print_cstr(pctx, " size ");
1472 cfg_print_obj(pctx, obj->value.tuple[2]);
1473 }
1474 if (obj->value.tuple[3]->type->print != cfg_print_void) {
1475 cfg_print_cstr(pctx, " versions ");
1476 cfg_print_obj(pctx, obj->value.tuple[3]);
1477 }
1478 if (obj->value.tuple[4]->type->print != cfg_print_void) {
1479 cfg_print_cstr(pctx, " suffix ");
1480 cfg_print_obj(pctx, obj->value.tuple[4]);
1481 }
1482 }
1483
1484 static void
1485 doc_dtout(cfg_printer_t *pctx, const cfg_type_t *type) {
1486 UNUSED(type);
1487 cfg_print_cstr(pctx, "( file | unix ) <quoted_string>");
1488 cfg_print_cstr(pctx, " ");
1489 cfg_print_cstr(pctx, "[ size ( unlimited | <size> ) ]");
1490 cfg_print_cstr(pctx, " ");
1491 cfg_print_cstr(pctx, "[ versions ( unlimited | <integer> ) ]");
1492 cfg_print_cstr(pctx, " ");
1493 cfg_print_cstr(pctx, "[ suffix ( increment | timestamp ) ]");
1494 }
1495
1496 static const char *dtoutmode_enums[] = { "file", "unix", NULL };
1497 static cfg_type_t cfg_type_dtmode = { "dtmode", cfg_parse_enum,
1498 cfg_print_ustring, cfg_doc_enum,
1499 &cfg_rep_string, &dtoutmode_enums };
1500
1501 static cfg_tuplefielddef_t dtout_fields[] = {
1502 { "mode", &cfg_type_dtmode, 0 },
1503 { "path", &cfg_type_qstring, 0 },
1504 { "size", &cfg_type_sizenodefault, 0 },
1505 { "versions", &cfg_type_logversions, 0 },
1506 { "suffix", &cfg_type_logsuffix, 0 },
1507 { NULL, NULL, 0 }
1508 };
1509
1510 static cfg_type_t cfg_type_dnstapoutput = { "dnstapoutput", parse_dtout,
1511 print_dtout, doc_dtout,
1512 &cfg_rep_tuple, dtout_fields };
1513
1514 /*%
1515 * response-policy {
1516 * zone <string> [ policy (given|disabled|passthru|drop|tcp-only|
1517 * nxdomain|nodata|cname <domain> ) ]
1518 * [ recursive-only yes|no ] [ log yes|no ]
1519 * [ max-policy-ttl number ]
1520 * [ nsip-enable yes|no ] [ nsdname-enable yes|no ];
1521 * } [ recursive-only yes|no ] [ max-policy-ttl number ]
1522 * [ min-update-interval number ]
1523 * [ break-dnssec yes|no ] [ min-ns-dots number ]
1524 * [ qname-wait-recurse yes|no ]
1525 * [ nsip-enable yes|no ] [ nsdname-enable yes|no ]
1526 * [ dnsrps-enable yes|no ]
1527 * [ dnsrps-options { DNSRPS configuration string } ];
1528 */
1529
1530 static void
1531 doc_rpz_policy(cfg_printer_t *pctx, const cfg_type_t *type) {
1532 const char *const *p;
1533 /*
1534 * This is cfg_doc_enum() without the trailing " )".
1535 */
1536 cfg_print_cstr(pctx, "( ");
1537 for (p = type->of; *p != NULL; p++) {
1538 cfg_print_cstr(pctx, *p);
1539 if (p[1] != NULL) {
1540 cfg_print_cstr(pctx, " | ");
1541 }
1542 }
1543 }
1544
1545 static void
1546 doc_rpz_cname(cfg_printer_t *pctx, const cfg_type_t *type) {
1547 cfg_doc_terminal(pctx, type);
1548 cfg_print_cstr(pctx, " )");
1549 }
1550
1551 /*
1552 * Parse
1553 * given|disabled|passthru|drop|tcp-only|nxdomain|nodata|cname <domain>
1554 */
1555 static isc_result_t
1556 cfg_parse_rpz_policy(cfg_parser_t *pctx, const cfg_type_t *type,
1557 cfg_obj_t **ret) {
1558 isc_result_t result;
1559 cfg_obj_t *obj = NULL;
1560 const cfg_tuplefielddef_t *fields;
1561
1562 CHECK(cfg_create_tuple(pctx, type, &obj));
1563
1564 fields = type->of;
1565 CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
1566 /*
1567 * parse cname domain only after "policy cname"
1568 */
1569 if (strcasecmp("cname", cfg_obj_asstring(obj->value.tuple[0])) != 0) {
1570 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1]));
1571 } else {
1572 CHECK(cfg_parse_obj(pctx, fields[1].type,
1573 &obj->value.tuple[1]));
1574 }
1575
1576 *ret = obj;
1577 return (ISC_R_SUCCESS);
1578
1579 cleanup:
1580 CLEANUP_OBJ(obj);
1581 return (result);
1582 }
1583
1584 /*
1585 * Parse a tuple consisting of any kind of required field followed
1586 * by 2 or more optional keyvalues that can be in any order.
1587 */
1588 static isc_result_t
1589 cfg_parse_kv_tuple(cfg_parser_t *pctx, const cfg_type_t *type,
1590 cfg_obj_t **ret) {
1591 const cfg_tuplefielddef_t *fields, *f;
1592 cfg_obj_t *obj = NULL;
1593 int fn;
1594 isc_result_t result;
1595
1596 CHECK(cfg_create_tuple(pctx, type, &obj));
1597
1598 /*
1599 * The zone first field is required and always first.
1600 */
1601 fields = type->of;
1602 CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
1603
1604 for (;;) {
1605 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
1606 if (pctx->token.type != isc_tokentype_string) {
1607 break;
1608 }
1609
1610 for (fn = 1, f = &fields[1];; ++fn, ++f) {
1611 if (f->name == NULL) {
1612 cfg_parser_error(pctx, 0, "unexpected '%s'",
1613 TOKEN_STRING(pctx));
1614 result = ISC_R_UNEXPECTEDTOKEN;
1615 goto cleanup;
1616 }
1617 if (obj->value.tuple[fn] == NULL &&
1618 strcasecmp(f->name, TOKEN_STRING(pctx)) == 0)
1619 {
1620 break;
1621 }
1622 }
1623
1624 CHECK(cfg_gettoken(pctx, 0));
1625 CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[fn]));
1626 }
1627
1628 for (fn = 1, f = &fields[1]; f->name != NULL; ++fn, ++f) {
1629 if (obj->value.tuple[fn] == NULL) {
1630 CHECK(cfg_parse_void(pctx, NULL,
1631 &obj->value.tuple[fn]));
1632 }
1633 }
1634
1635 *ret = obj;
1636 return (ISC_R_SUCCESS);
1637
1638 cleanup:
1639 CLEANUP_OBJ(obj);
1640 return (result);
1641 }
1642
1643 static void
1644 cfg_print_kv_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1645 unsigned int i;
1646 const cfg_tuplefielddef_t *fields, *f;
1647 const cfg_obj_t *fieldobj;
1648
1649 fields = obj->type->of;
1650 for (f = fields, i = 0; f->name != NULL; f++, i++) {
1651 fieldobj = obj->value.tuple[i];
1652 if (fieldobj->type->print == cfg_print_void) {
1653 continue;
1654 }
1655 if (i != 0) {
1656 cfg_print_cstr(pctx, " ");
1657 cfg_print_cstr(pctx, f->name);
1658 cfg_print_cstr(pctx, " ");
1659 }
1660 cfg_print_obj(pctx, fieldobj);
1661 }
1662 }
1663
1664 static void
1665 cfg_doc_kv_tuple(cfg_printer_t *pctx, const cfg_type_t *type) {
1666 const cfg_tuplefielddef_t *fields, *f;
1667
1668 fields = type->of;
1669 for (f = fields; f->name != NULL; f++) {
1670 if (f != fields) {
1671 cfg_print_cstr(pctx, " [ ");
1672 cfg_print_cstr(pctx, f->name);
1673 if (f->type->doc != cfg_doc_void) {
1674 cfg_print_cstr(pctx, " ");
1675 }
1676 }
1677 cfg_doc_obj(pctx, f->type);
1678 if (f != fields) {
1679 cfg_print_cstr(pctx, " ]");
1680 }
1681 }
1682 }
1683
1684 static keyword_type_t zone_kw = { "zone", &cfg_type_astring };
1685 static cfg_type_t cfg_type_rpz_zone = { "zone", parse_keyvalue,
1686 print_keyvalue, doc_keyvalue,
1687 &cfg_rep_string, &zone_kw };
1688 /*
1689 * "no-op" is an obsolete equivalent of "passthru".
1690 */
1691 static const char *rpz_policies[] = { "cname", "disabled", "drop",
1692 "given", "no-op", "nodata",
1693 "nxdomain", "passthru", "tcp-only",
1694 NULL };
1695 static cfg_type_t cfg_type_rpz_policy_name = {
1696 "policy name", cfg_parse_enum, cfg_print_ustring,
1697 doc_rpz_policy, &cfg_rep_string, &rpz_policies
1698 };
1699 static cfg_type_t cfg_type_rpz_cname = {
1700 "quoted_string", cfg_parse_astring, NULL,
1701 doc_rpz_cname, &cfg_rep_string, NULL
1702 };
1703 static cfg_tuplefielddef_t rpz_policy_fields[] = {
1704 { "policy name", &cfg_type_rpz_policy_name, 0 },
1705 { "cname", &cfg_type_rpz_cname, 0 },
1706 { NULL, NULL, 0 }
1707 };
1708 static cfg_type_t cfg_type_rpz_policy = { "policy tuple", cfg_parse_rpz_policy,
1709 cfg_print_tuple, cfg_doc_tuple,
1710 &cfg_rep_tuple, rpz_policy_fields };
1711 static cfg_tuplefielddef_t rpz_zone_fields[] = {
1712 { "zone name", &cfg_type_rpz_zone, 0 },
1713 { "add-soa", &cfg_type_boolean, 0 },
1714 { "log", &cfg_type_boolean, 0 },
1715 { "max-policy-ttl", &cfg_type_duration, 0 },
1716 { "min-update-interval", &cfg_type_duration, 0 },
1717 { "policy", &cfg_type_rpz_policy, 0 },
1718 { "recursive-only", &cfg_type_boolean, 0 },
1719 { "nsip-enable", &cfg_type_boolean, 0 },
1720 { "nsdname-enable", &cfg_type_boolean, 0 },
1721 { NULL, NULL, 0 }
1722 };
1723 static cfg_type_t cfg_type_rpz_tuple = { "rpz tuple", cfg_parse_kv_tuple,
1724 cfg_print_kv_tuple, cfg_doc_kv_tuple,
1725 &cfg_rep_tuple, rpz_zone_fields };
1726 static cfg_type_t cfg_type_rpz_list = { "zone list",
1727 cfg_parse_bracketed_list,
1728 cfg_print_bracketed_list,
1729 cfg_doc_bracketed_list,
1730 &cfg_rep_list,
1731 &cfg_type_rpz_tuple };
1732 static cfg_tuplefielddef_t rpz_fields[] = {
1733 { "zone list", &cfg_type_rpz_list, 0 },
1734 { "add-soa", &cfg_type_boolean, 0 },
1735 { "break-dnssec", &cfg_type_boolean, 0 },
1736 { "max-policy-ttl", &cfg_type_duration, 0 },
1737 { "min-update-interval", &cfg_type_duration, 0 },
1738 { "min-ns-dots", &cfg_type_uint32, 0 },
1739 { "nsip-wait-recurse", &cfg_type_boolean, 0 },
1740 { "qname-wait-recurse", &cfg_type_boolean, 0 },
1741 { "recursive-only", &cfg_type_boolean, 0 },
1742 { "nsip-enable", &cfg_type_boolean, 0 },
1743 { "nsdname-enable", &cfg_type_boolean, 0 },
1744 #ifdef USE_DNSRPS
1745 { "dnsrps-enable", &cfg_type_boolean, 0 },
1746 { "dnsrps-options", &cfg_type_bracketed_text, 0 },
1747 #else /* ifdef USE_DNSRPS */
1748 { "dnsrps-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTCONFIGURED },
1749 { "dnsrps-options", &cfg_type_bracketed_text,
1750 CFG_CLAUSEFLAG_NOTCONFIGURED },
1751 #endif /* ifdef USE_DNSRPS */
1752 { NULL, NULL, 0 }
1753 };
1754 static cfg_type_t cfg_type_rpz = { "rpz",
1755 cfg_parse_kv_tuple,
1756 cfg_print_kv_tuple,
1757 cfg_doc_kv_tuple,
1758 &cfg_rep_tuple,
1759 rpz_fields };
1760
1761 /*
1762 * Catalog zones
1763 */
1764 static cfg_type_t cfg_type_catz_zone = { "zone", parse_keyvalue,
1765 print_keyvalue, doc_keyvalue,
1766 &cfg_rep_string, &zone_kw };
1767
1768 static cfg_tuplefielddef_t catz_zone_fields[] = {
1769 { "zone name", &cfg_type_catz_zone, 0 },
1770 { "default-masters", &cfg_type_namesockaddrkeylist, 0 },
1771 { "zone-directory", &cfg_type_qstring, 0 },
1772 { "in-memory", &cfg_type_boolean, 0 },
1773 { "min-update-interval", &cfg_type_duration, 0 },
1774 { NULL, NULL, 0 }
1775 };
1776 static cfg_type_t cfg_type_catz_tuple = {
1777 "catz tuple", cfg_parse_kv_tuple, cfg_print_kv_tuple,
1778 cfg_doc_kv_tuple, &cfg_rep_tuple, catz_zone_fields
1779 };
1780 static cfg_type_t cfg_type_catz_list = { "zone list",
1781 cfg_parse_bracketed_list,
1782 cfg_print_bracketed_list,
1783 cfg_doc_bracketed_list,
1784 &cfg_rep_list,
1785 &cfg_type_catz_tuple };
1786 static cfg_tuplefielddef_t catz_fields[] = {
1787 { "zone list", &cfg_type_catz_list, 0 }, { NULL, NULL, 0 }
1788 };
1789 static cfg_type_t cfg_type_catz = {
1790 "catz", cfg_parse_kv_tuple, cfg_print_kv_tuple,
1791 cfg_doc_kv_tuple, &cfg_rep_tuple, catz_fields
1792 };
1793
1794 /*
1795 * rate-limit
1796 */
1797 static cfg_clausedef_t rrl_clauses[] = {
1798 { "all-per-second", &cfg_type_uint32, 0 },
1799 { "errors-per-second", &cfg_type_uint32, 0 },
1800 { "exempt-clients", &cfg_type_bracketed_aml, 0 },
1801 { "ipv4-prefix-length", &cfg_type_uint32, 0 },
1802 { "ipv6-prefix-length", &cfg_type_uint32, 0 },
1803 { "log-only", &cfg_type_boolean, 0 },
1804 { "max-table-size", &cfg_type_uint32, 0 },
1805 { "min-table-size", &cfg_type_uint32, 0 },
1806 { "nodata-per-second", &cfg_type_uint32, 0 },
1807 { "nxdomains-per-second", &cfg_type_uint32, 0 },
1808 { "qps-scale", &cfg_type_uint32, 0 },
1809 { "referrals-per-second", &cfg_type_uint32, 0 },
1810 { "responses-per-second", &cfg_type_uint32, 0 },
1811 { "slip", &cfg_type_uint32, 0 },
1812 { "window", &cfg_type_uint32, 0 },
1813 { NULL, NULL, 0 }
1814 };
1815
1816 static cfg_clausedef_t *rrl_clausesets[] = { rrl_clauses, NULL };
1817
1818 static cfg_type_t cfg_type_rrl = { "rate-limit", cfg_parse_map, cfg_print_map,
1819 cfg_doc_map, &cfg_rep_map, rrl_clausesets };
1820
1821 /*%
1822 * dnssec-lookaside
1823 */
1824
1825 static void
1826 print_lookaside(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1827 const cfg_obj_t *domain = obj->value.tuple[0];
1828
1829 if (domain->value.string.length == 4 &&
1830 strncmp(domain->value.string.base, "auto", 4) == 0)
1831 {
1832 cfg_print_cstr(pctx, "auto");
1833 } else {
1834 cfg_print_tuple(pctx, obj);
1835 }
1836 }
1837
1838 static void
1839 doc_lookaside(cfg_printer_t *pctx, const cfg_type_t *type) {
1840 UNUSED(type);
1841 cfg_print_cstr(pctx, "( <string> trust-anchor <string> | auto | no )");
1842 }
1843
1844 static keyword_type_t trustanchor_kw = { "trust-anchor", &cfg_type_astring };
1845
1846 static cfg_type_t cfg_type_optional_trustanchor = {
1847 "optional_trustanchor", parse_optional_keyvalue, print_keyvalue,
1848 doc_keyvalue, &cfg_rep_string, &trustanchor_kw
1849 };
1850
1851 static cfg_tuplefielddef_t lookaside_fields[] = {
1852 { "domain", &cfg_type_astring, 0 },
1853 { "trust-anchor", &cfg_type_optional_trustanchor, 0 },
1854 { NULL, NULL, 0 }
1855 };
1856
1857 static cfg_type_t cfg_type_lookaside = { "lookaside", cfg_parse_tuple,
1858 print_lookaside, doc_lookaside,
1859 &cfg_rep_tuple, lookaside_fields };
1860
1861 static isc_result_t
1862 parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type,
1863 cfg_obj_t **ret) {
1864 isc_result_t result;
1865 UNUSED(type);
1866
1867 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
1868 if (pctx->token.type == isc_tokentype_number) {
1869 CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret));
1870 } else {
1871 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
1872 }
1873 cleanup:
1874 return (result);
1875 }
1876
1877 static void
1878 doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) {
1879 UNUSED(type);
1880 cfg_print_cstr(pctx, "[ <integer> ]");
1881 }
1882
1883 static cfg_type_t cfg_type_optional_uint32 = { "optional_uint32",
1884 parse_optional_uint32,
1885 NULL,
1886 doc_optional_uint32,
1887 NULL,
1888 NULL };
1889
1890 static cfg_tuplefielddef_t prefetch_fields[] = {
1891 { "trigger", &cfg_type_uint32, 0 },
1892 { "eligible", &cfg_type_optional_uint32, 0 },
1893 { NULL, NULL, 0 }
1894 };
1895
1896 static cfg_type_t cfg_type_prefetch = { "prefetch", cfg_parse_tuple,
1897 cfg_print_tuple, cfg_doc_tuple,
1898 &cfg_rep_tuple, prefetch_fields };
1899 /*
1900 * DNS64.
1901 */
1902 static cfg_clausedef_t dns64_clauses[] = {
1903 { "break-dnssec", &cfg_type_boolean, 0 },
1904 { "clients", &cfg_type_bracketed_aml, 0 },
1905 { "exclude", &cfg_type_bracketed_aml, 0 },
1906 { "mapped", &cfg_type_bracketed_aml, 0 },
1907 { "recursive-only", &cfg_type_boolean, 0 },
1908 { "suffix", &cfg_type_netaddr6, 0 },
1909 { NULL, NULL, 0 },
1910 };
1911
1912 static cfg_clausedef_t *dns64_clausesets[] = { dns64_clauses, NULL };
1913
1914 static cfg_type_t cfg_type_dns64 = { "dns64", cfg_parse_netprefix_map,
1915 cfg_print_map, cfg_doc_map,
1916 &cfg_rep_map, dns64_clausesets };
1917
1918 /*%
1919 * Clauses that can be found within the 'view' statement,
1920 * with defaults in the 'options' statement.
1921 */
1922
1923 static cfg_clausedef_t view_clauses[] = {
1924 { "acache-cleaning-interval", &cfg_type_uint32,
1925 CFG_CLAUSEFLAG_OBSOLETE },
1926 { "acache-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1927 { "additional-from-auth", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1928 { "additional-from-cache", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1929 { "allow-new-zones", &cfg_type_boolean, 0 },
1930 { "allow-query-cache", &cfg_type_bracketed_aml, 0 },
1931 { "allow-query-cache-on", &cfg_type_bracketed_aml, 0 },
1932 { "allow-recursion", &cfg_type_bracketed_aml, 0 },
1933 { "allow-recursion-on", &cfg_type_bracketed_aml, 0 },
1934 { "allow-v6-synthesis", &cfg_type_bracketed_aml,
1935 CFG_CLAUSEFLAG_OBSOLETE },
1936 { "attach-cache", &cfg_type_astring, 0 },
1937 { "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT },
1938 { "cache-file", &cfg_type_qstring, 0 },
1939 { "catalog-zones", &cfg_type_catz, 0 },
1940 { "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
1941 { "cleaning-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
1942 { "clients-per-query", &cfg_type_uint32, 0 },
1943 { "deny-answer-addresses", &cfg_type_denyaddresses, 0 },
1944 { "deny-answer-aliases", &cfg_type_denyaliases, 0 },
1945 { "disable-algorithms", &cfg_type_disablealgorithm,
1946 CFG_CLAUSEFLAG_MULTI },
1947 { "disable-ds-digests", &cfg_type_disabledsdigest,
1948 CFG_CLAUSEFLAG_MULTI },
1949 { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI },
1950 { "dns64", &cfg_type_dns64, CFG_CLAUSEFLAG_MULTI },
1951 { "dns64-contact", &cfg_type_astring, 0 },
1952 { "dns64-server", &cfg_type_astring, 0 },
1953 #ifdef USE_DNSRPS
1954 { "dnsrps-enable", &cfg_type_boolean, 0 },
1955 { "dnsrps-options", &cfg_type_bracketed_text, 0 },
1956 #else /* ifdef USE_DNSRPS */
1957 { "dnsrps-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTCONFIGURED },
1958 { "dnsrps-options", &cfg_type_bracketed_text,
1959 CFG_CLAUSEFLAG_NOTCONFIGURED },
1960 #endif /* ifdef USE_DNSRPS */
1961 { "dnssec-accept-expired", &cfg_type_boolean, 0 },
1962 { "dnssec-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1963 { "dnssec-lookaside", &cfg_type_lookaside,
1964 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE },
1965 { "dnssec-must-be-secure", &cfg_type_mustbesecure,
1966 CFG_CLAUSEFLAG_MULTI },
1967 { "dnssec-validation", &cfg_type_boolorauto, 0 },
1968 #ifdef HAVE_DNSTAP
1969 { "dnstap", &cfg_type_dnstap, 0 },
1970 #else /* ifdef HAVE_DNSTAP */
1971 { "dnstap", &cfg_type_dnstap, CFG_CLAUSEFLAG_NOTCONFIGURED },
1972 #endif /* HAVE_DNSTAP */
1973 { "dual-stack-servers", &cfg_type_nameportiplist, 0 },
1974 { "edns-udp-size", &cfg_type_uint32, 0 },
1975 { "empty-contact", &cfg_type_astring, 0 },
1976 { "empty-server", &cfg_type_astring, 0 },
1977 { "empty-zones-enable", &cfg_type_boolean, 0 },
1978 { "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT },
1979 { "fetch-quota-params", &cfg_type_fetchquota, 0 },
1980 { "fetches-per-server", &cfg_type_fetchesper, 0 },
1981 { "fetches-per-zone", &cfg_type_fetchesper, 0 },
1982 { "filter-aaaa", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_OBSOLETE },
1983 { "filter-aaaa-on-v4", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1984 { "filter-aaaa-on-v6", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1985 { "glue-cache", &cfg_type_boolean, 0 },
1986 { "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 },
1987 { "lame-ttl", &cfg_type_duration, 0 },
1988 #ifdef HAVE_LMDB
1989 { "lmdb-mapsize", &cfg_type_sizeval, 0 },
1990 #else /* ifdef HAVE_LMDB */
1991 { "lmdb-mapsize", &cfg_type_sizeval, CFG_CLAUSEFLAG_NOOP },
1992 #endif /* ifdef HAVE_LMDB */
1993 { "max-acache-size", &cfg_type_sizenodefault, CFG_CLAUSEFLAG_OBSOLETE },
1994 { "max-cache-size", &cfg_type_sizeorpercent, 0 },
1995 { "max-cache-ttl", &cfg_type_duration, 0 },
1996 { "max-clients-per-query", &cfg_type_uint32, 0 },
1997 { "max-ncache-ttl", &cfg_type_duration, 0 },
1998 { "max-recursion-depth", &cfg_type_uint32, 0 },
1999 { "max-recursion-queries", &cfg_type_uint32, 0 },
2000 { "max-stale-ttl", &cfg_type_duration, 0 },
2001 { "max-udp-size", &cfg_type_uint32, 0 },
2002 { "message-compression", &cfg_type_boolean, 0 },
2003 { "min-cache-ttl", &cfg_type_duration, 0 },
2004 { "min-ncache-ttl", &cfg_type_duration, 0 },
2005 { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_ANCIENT },
2006 { "minimal-any", &cfg_type_boolean, 0 },
2007 { "minimal-responses", &cfg_type_minimal, 0 },
2008 { "new-zones-directory", &cfg_type_qstring, 0 },
2009 { "no-case-compress", &cfg_type_bracketed_aml, 0 },
2010 { "nocookie-udp-size", &cfg_type_uint32, 0 },
2011 { "nosit-udp-size", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
2012 { "nta-lifetime", &cfg_type_duration, 0 },
2013 { "nta-recheck", &cfg_type_duration, 0 },
2014 { "nxdomain-redirect", &cfg_type_astring, 0 },
2015 { "preferred-glue", &cfg_type_astring, 0 },
2016 { "prefetch", &cfg_type_prefetch, 0 },
2017 { "provide-ixfr", &cfg_type_boolean, 0 },
2018 { "qname-minimization", &cfg_type_qminmethod, 0 },
2019 /*
2020 * Note that the query-source option syntax is different
2021 * from the other -source options.
2022 */
2023 { "query-source", &cfg_type_querysource4, 0 },
2024 { "query-source-v6", &cfg_type_querysource6, 0 },
2025 { "queryport-pool-ports", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
2026 { "queryport-pool-updateinterval", &cfg_type_uint32,
2027 CFG_CLAUSEFLAG_OBSOLETE },
2028 { "rate-limit", &cfg_type_rrl, 0 },
2029 { "recursion", &cfg_type_boolean, 0 },
2030 { "request-nsid", &cfg_type_boolean, 0 },
2031 { "request-sit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
2032 { "require-server-cookie", &cfg_type_boolean, 0 },
2033 { "resolver-nonbackoff-tries", &cfg_type_uint32, 0 },
2034 { "resolver-query-timeout", &cfg_type_uint32, 0 },
2035 { "resolver-retry-interval", &cfg_type_uint32, 0 },
2036 { "response-padding", &cfg_type_resppadding, 0 },
2037 { "response-policy", &cfg_type_rpz, 0 },
2038 { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT },
2039 { "root-delegation-only", &cfg_type_optional_exclude, 0 },
2040 { "root-key-sentinel", &cfg_type_boolean, 0 },
2041 { "rrset-order", &cfg_type_rrsetorder, 0 },
2042 { "send-cookie", &cfg_type_boolean, 0 },
2043 { "servfail-ttl", &cfg_type_duration, 0 },
2044 { "sortlist", &cfg_type_bracketed_aml, 0 },
2045 { "stale-answer-enable", &cfg_type_boolean, 0 },
2046 { "stale-answer-ttl", &cfg_type_duration, 0 },
2047 { "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
2048 { "synth-from-dnssec", &cfg_type_boolean, 0 },
2049 { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_ANCIENT },
2050 { "transfer-format", &cfg_type_transferformat, 0 },
2051 { "trust-anchor-telemetry", &cfg_type_boolean,
2052 CFG_CLAUSEFLAG_EXPERIMENTAL },
2053 { "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
2054 { "validate-except", &cfg_type_namelist, 0 },
2055 { "v6-bias", &cfg_type_uint32, 0 },
2056 { "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
2057 { NULL, NULL, 0 }
2058 };
2059
2060 /*%
2061 * Clauses that can be found within the 'view' statement only.
2062 */
2063 static cfg_clausedef_t view_only_clauses[] = {
2064 { "match-clients", &cfg_type_bracketed_aml, 0 },
2065 { "match-destinations", &cfg_type_bracketed_aml, 0 },
2066 { "match-recursive-only", &cfg_type_boolean, 0 },
2067 { NULL, NULL, 0 }
2068 };
2069
2070 /*%
2071 * Sig-validity-interval.
2072 */
2073
2074 static cfg_tuplefielddef_t validityinterval_fields[] = {
2075 { "validity", &cfg_type_uint32, 0 },
2076 { "re-sign", &cfg_type_optional_uint32, 0 },
2077 { NULL, NULL, 0 }
2078 };
2079
2080 static cfg_type_t cfg_type_validityinterval = {
2081 "validityinterval", cfg_parse_tuple, cfg_print_tuple,
2082 cfg_doc_tuple, &cfg_rep_tuple, validityinterval_fields
2083 };
2084
2085 /*%
2086 * Clauses that can be found in a 'dnssec-policy' statement.
2087 */
2088 static cfg_clausedef_t dnssecpolicy_clauses[] = {
2089 { "dnskey-ttl", &cfg_type_duration, 0 },
2090 { "keys", &cfg_type_kaspkeys, 0 },
2091 { "max-zone-ttl", &cfg_type_duration, 0 },
2092 { "parent-ds-ttl", &cfg_type_duration, 0 },
2093 { "parent-propagation-delay", &cfg_type_duration, 0 },
2094 { "parent-registration-delay", &cfg_type_duration, 0 },
2095 { "publish-safety", &cfg_type_duration, 0 },
2096 { "retire-safety", &cfg_type_duration, 0 },
2097 { "signatures-refresh", &cfg_type_duration, 0 },
2098 { "signatures-validity", &cfg_type_duration, 0 },
2099 { "signatures-validity-dnskey", &cfg_type_duration, 0 },
2100 { "zone-propagation-delay", &cfg_type_duration, 0 },
2101 { NULL, NULL, 0 }
2102 };
2103
2104 /*%
2105 * Clauses that can be found in a 'zone' statement,
2106 * with defaults in the 'view' or 'options' statement.
2107 *
2108 * Note: CFG_ZONE_* options indicate in which zone types this clause is
2109 * legal.
2110 */
2111 static cfg_clausedef_t zone_clauses[] = {
2112 { "allow-notify", &cfg_type_bracketed_aml,
2113 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2114 { "allow-query", &cfg_type_bracketed_aml,
2115 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB |
2116 CFG_ZONE_REDIRECT | CFG_ZONE_STATICSTUB },
2117 { "allow-query-on", &cfg_type_bracketed_aml,
2118 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB |
2119 CFG_ZONE_REDIRECT | CFG_ZONE_STATICSTUB },
2120 { "allow-transfer", &cfg_type_bracketed_aml,
2121 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2122 { "allow-update", &cfg_type_bracketed_aml, CFG_ZONE_MASTER },
2123 { "allow-update-forwarding", &cfg_type_bracketed_aml,
2124 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2125 { "also-notify", &cfg_type_namesockaddrkeylist,
2126 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2127 { "alt-transfer-source", &cfg_type_sockaddr4wild,
2128 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2129 { "alt-transfer-source-v6", &cfg_type_sockaddr6wild,
2130 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2131 { "auto-dnssec", &cfg_type_autodnssec,
2132 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2133 { "check-dup-records", &cfg_type_checkmode, CFG_ZONE_MASTER },
2134 { "check-integrity", &cfg_type_boolean, CFG_ZONE_MASTER },
2135 { "check-mx", &cfg_type_checkmode, CFG_ZONE_MASTER },
2136 { "check-mx-cname", &cfg_type_checkmode, CFG_ZONE_MASTER },
2137 { "check-sibling", &cfg_type_boolean, CFG_ZONE_MASTER },
2138 { "check-spf", &cfg_type_warn, CFG_ZONE_MASTER },
2139 { "check-srv-cname", &cfg_type_checkmode, CFG_ZONE_MASTER },
2140 { "check-wildcard", &cfg_type_boolean, CFG_ZONE_MASTER },
2141 { "dialup", &cfg_type_dialuptype,
2142 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB },
2143 { "dnssec-dnskey-kskonly", &cfg_type_boolean,
2144 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2145 { "dnssec-loadkeys-interval", &cfg_type_uint32,
2146 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2147 { "dnssec-policy", &cfg_type_astring,
2148 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2149 { "dnssec-secure-to-insecure", &cfg_type_boolean, CFG_ZONE_MASTER },
2150 { "dnssec-update-mode", &cfg_type_dnssecupdatemode,
2151 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2152 { "forward", &cfg_type_forwardtype,
2153 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB |
2154 CFG_ZONE_STATICSTUB | CFG_ZONE_FORWARD },
2155 { "forwarders", &cfg_type_portiplist,
2156 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_STUB |
2157 CFG_ZONE_STATICSTUB | CFG_ZONE_FORWARD },
2158 { "inline-signing", &cfg_type_boolean,
2159 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2160 { "key-directory", &cfg_type_qstring,
2161 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2162 { "maintain-ixfr-base", &cfg_type_boolean, CFG_CLAUSEFLAG_ANCIENT },
2163 { "masterfile-format", &cfg_type_masterformat,
2164 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB |
2165 CFG_ZONE_REDIRECT },
2166 { "masterfile-style", &cfg_type_masterstyle,
2167 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB |
2168 CFG_ZONE_REDIRECT },
2169 { "max-ixfr-log-size", &cfg_type_size, CFG_CLAUSEFLAG_ANCIENT },
2170 { "max-journal-size", &cfg_type_size,
2171 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2172 { "max-records", &cfg_type_uint32,
2173 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB |
2174 CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT },
2175 { "max-refresh-time", &cfg_type_uint32,
2176 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
2177 { "max-retry-time", &cfg_type_uint32,
2178 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
2179 { "max-transfer-idle-in", &cfg_type_uint32,
2180 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
2181 { "max-transfer-idle-out", &cfg_type_uint32,
2182 CFG_ZONE_MASTER | CFG_ZONE_MIRROR | CFG_ZONE_SLAVE },
2183 { "max-transfer-time-in", &cfg_type_uint32,
2184 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
2185 { "max-transfer-time-out", &cfg_type_uint32,
2186 CFG_ZONE_MASTER | CFG_ZONE_MIRROR | CFG_ZONE_SLAVE },
2187 { "max-zone-ttl", &cfg_type_maxduration,
2188 CFG_ZONE_MASTER | CFG_ZONE_REDIRECT },
2189 { "min-refresh-time", &cfg_type_uint32,
2190 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
2191 { "min-retry-time", &cfg_type_uint32,
2192 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
2193 { "multi-master", &cfg_type_boolean,
2194 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
2195 { "notify", &cfg_type_notifytype,
2196 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2197 { "notify-delay", &cfg_type_uint32,
2198 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2199 { "notify-source", &cfg_type_sockaddr4wild,
2200 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2201 { "notify-source-v6", &cfg_type_sockaddr6wild,
2202 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2203 { "notify-to-soa", &cfg_type_boolean,
2204 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2205 { "nsec3-test-zone", &cfg_type_boolean,
2206 CFG_CLAUSEFLAG_TESTONLY | CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2207 { "request-expire", &cfg_type_boolean,
2208 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2209 { "request-ixfr", &cfg_type_boolean, CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2210 { "serial-update-method", &cfg_type_updatemethod, CFG_ZONE_MASTER },
2211 { "sig-signing-nodes", &cfg_type_uint32,
2212 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2213 { "sig-signing-signatures", &cfg_type_uint32,
2214 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2215 { "sig-signing-type", &cfg_type_uint32,
2216 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2217 { "sig-validity-interval", &cfg_type_validityinterval,
2218 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2219 { "dnskey-sig-validity", &cfg_type_uint32,
2220 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2221 { "transfer-source", &cfg_type_sockaddr4wild,
2222 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
2223 { "transfer-source-v6", &cfg_type_sockaddr6wild,
2224 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
2225 { "try-tcp-refresh", &cfg_type_boolean,
2226 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2227 { "update-check-ksk", &cfg_type_boolean,
2228 CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2229 { "use-alt-transfer-source", &cfg_type_boolean,
2230 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
2231 { "zero-no-soa-ttl", &cfg_type_boolean,
2232 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2233 { "zone-statistics", &cfg_type_zonestat,
2234 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB |
2235 CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT },
2236 { NULL, NULL, 0 }
2237 };
2238
2239 /*%
2240 * Clauses that can be found in a 'zone' statement only.
2241 *
2242 * Note: CFG_ZONE_* options indicate in which zone types this clause is
2243 * legal.
2244 */
2245 static cfg_clausedef_t zone_only_clauses[] = {
2246 /*
2247 * Note that the format of the check-names option is different between
2248 * the zone options and the global/view options. Ugh.
2249 */
2250 { "type", &cfg_type_zonetype,
2251 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB |
2252 CFG_ZONE_STATICSTUB | CFG_ZONE_DELEGATION | CFG_ZONE_HINT |
2253 CFG_ZONE_REDIRECT | CFG_ZONE_FORWARD },
2254 { "check-names", &cfg_type_checkmode,
2255 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_HINT |
2256 CFG_ZONE_STUB },
2257 { "database", &cfg_type_astring,
2258 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
2259 { "delegation-only", &cfg_type_boolean,
2260 CFG_ZONE_HINT | CFG_ZONE_STUB | CFG_ZONE_FORWARD },
2261 { "dlz", &cfg_type_astring,
2262 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_REDIRECT },
2263 { "file", &cfg_type_qstring,
2264 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB |
2265 CFG_ZONE_HINT | CFG_ZONE_REDIRECT },
2266 { "in-view", &cfg_type_astring, CFG_ZONE_INVIEW },
2267 { "ixfr-base", &cfg_type_qstring, CFG_CLAUSEFLAG_ANCIENT },
2268 { "ixfr-from-differences", &cfg_type_boolean,
2269 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2270 { "ixfr-tmp-file", &cfg_type_qstring, CFG_CLAUSEFLAG_ANCIENT },
2271 { "journal", &cfg_type_qstring,
2272 CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
2273 { "masters", &cfg_type_namesockaddrkeylist,
2274 CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB |
2275 CFG_ZONE_REDIRECT },
2276 { "pubkey", &cfg_type_pubkey, CFG_CLAUSEFLAG_ANCIENT },
2277 { "server-addresses", &cfg_type_bracketed_netaddrlist,
2278 CFG_ZONE_STATICSTUB },
2279 { "server-names", &cfg_type_namelist, CFG_ZONE_STATICSTUB },
2280 { "update-policy", &cfg_type_updatepolicy, CFG_ZONE_MASTER },
2281 { NULL, NULL, 0 }
2282 };
2283
2284 /*% The top-level named.conf syntax. */
2285
2286 static cfg_clausedef_t *namedconf_clausesets[] = { namedconf_clauses,
2287 namedconf_or_view_clauses,
2288 NULL };
2289 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = {
2290 "namedconf", cfg_parse_mapbody, cfg_print_mapbody,
2291 cfg_doc_mapbody, &cfg_rep_map, namedconf_clausesets
2292 };
2293
2294 /*% The bind.keys syntax (trust-anchors/managed-keys/trusted-keys only). */
2295 static cfg_clausedef_t *bindkeys_clausesets[] = { bindkeys_clauses, NULL };
2296 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bindkeys = {
2297 "bindkeys", cfg_parse_mapbody, cfg_print_mapbody,
2298 cfg_doc_mapbody, &cfg_rep_map, bindkeys_clausesets
2299 };
2300
2301 /*% The "options" statement syntax. */
2302
2303 static cfg_clausedef_t *options_clausesets[] = { options_clauses, view_clauses,
2304 zone_clauses, NULL };
2305 static cfg_type_t cfg_type_options = { "options", cfg_parse_map,
2306 cfg_print_map, cfg_doc_map,
2307 &cfg_rep_map, options_clausesets };
2308
2309 /*% The "view" statement syntax. */
2310
2311 static cfg_clausedef_t *view_clausesets[] = { view_only_clauses,
2312 namedconf_or_view_clauses,
2313 view_clauses, zone_clauses,
2314 NULL };
2315
2316 static cfg_type_t cfg_type_viewopts = { "view", cfg_parse_map,
2317 cfg_print_map, cfg_doc_map,
2318 &cfg_rep_map, view_clausesets };
2319
2320 /*% The "zone" statement syntax. */
2321
2322 static cfg_clausedef_t *zone_clausesets[] = { zone_only_clauses, zone_clauses,
2323 NULL };
2324 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_zoneopts = {
2325 "zoneopts", cfg_parse_map, cfg_print_map,
2326 cfg_doc_map, &cfg_rep_map, zone_clausesets
2327 };
2328
2329 /*% The "dnssec-policy" statement syntax. */
2330 static cfg_clausedef_t *dnssecpolicy_clausesets[] = { dnssecpolicy_clauses,
2331 NULL };
2332 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_dnssecpolicyopts = {
2333 "dnssecpolicyopts", cfg_parse_map, cfg_print_map,
2334 cfg_doc_map, &cfg_rep_map, dnssecpolicy_clausesets
2335 };
2336
2337 /*% The "dynamically loadable zones" statement syntax. */
2338
2339 static cfg_clausedef_t dlz_clauses[] = { { "database", &cfg_type_astring, 0 },
2340 { "search", &cfg_type_boolean, 0 },
2341 { NULL, NULL, 0 } };
2342 static cfg_clausedef_t *dlz_clausesets[] = { dlz_clauses, NULL };
2343 static cfg_type_t cfg_type_dlz = { "dlz", cfg_parse_named_map,
2344 cfg_print_map, cfg_doc_map,
2345 &cfg_rep_map, dlz_clausesets };
2346
2347 /*%
2348 * The "dyndb" statement syntax.
2349 */
2350
2351 static cfg_tuplefielddef_t dyndb_fields[] = {
2352 { "name", &cfg_type_astring, 0 },
2353 { "library", &cfg_type_qstring, 0 },
2354 { "parameters", &cfg_type_bracketed_text, 0 },
2355 { NULL, NULL, 0 }
2356 };
2357
2358 static cfg_type_t cfg_type_dyndb = { "dyndb", cfg_parse_tuple,
2359 cfg_print_tuple, cfg_doc_tuple,
2360 &cfg_rep_tuple, dyndb_fields };
2361
2362 /*%
2363 * The "plugin" statement syntax.
2364 * Currently only one plugin type is supported: query.
2365 */
2366
2367 static const char *plugin_enums[] = { "query", NULL };
2368 static cfg_type_t cfg_type_plugintype = { "plugintype", cfg_parse_enum,
2369 cfg_print_ustring, cfg_doc_enum,
2370 &cfg_rep_string, plugin_enums };
2371 static cfg_tuplefielddef_t plugin_fields[] = {
2372 { "type", &cfg_type_plugintype, 0 },
2373 { "library", &cfg_type_astring, 0 },
2374 { "parameters", &cfg_type_optional_bracketed_text, 0 },
2375 { NULL, NULL, 0 }
2376 };
2377 static cfg_type_t cfg_type_plugin = { "plugin", cfg_parse_tuple,
2378 cfg_print_tuple, cfg_doc_tuple,
2379 &cfg_rep_tuple, plugin_fields };
2380
2381 /*%
2382 * Clauses that can be found within the 'key' statement.
2383 */
2384 static cfg_clausedef_t key_clauses[] = { { "algorithm", &cfg_type_astring, 0 },
2385 { "secret", &cfg_type_sstring, 0 },
2386 { NULL, NULL, 0 } };
2387
2388 static cfg_clausedef_t *key_clausesets[] = { key_clauses, NULL };
2389 static cfg_type_t cfg_type_key = { "key", cfg_parse_named_map,
2390 cfg_print_map, cfg_doc_map,
2391 &cfg_rep_map, key_clausesets };
2392
2393 /*%
2394 * Clauses that can be found in a 'server' statement.
2395 */
2396 static cfg_clausedef_t server_clauses[] = {
2397 { "bogus", &cfg_type_boolean, 0 },
2398 { "edns", &cfg_type_boolean, 0 },
2399 { "edns-udp-size", &cfg_type_uint32, 0 },
2400 { "edns-version", &cfg_type_uint32, 0 },
2401 { "keys", &cfg_type_server_key_kludge, 0 },
2402 { "max-udp-size", &cfg_type_uint32, 0 },
2403 { "notify-source", &cfg_type_sockaddr4wild, 0 },
2404 { "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
2405 { "padding", &cfg_type_uint32, 0 },
2406 { "provide-ixfr", &cfg_type_boolean, 0 },
2407 { "query-source", &cfg_type_querysource4, 0 },
2408 { "query-source-v6", &cfg_type_querysource6, 0 },
2409 { "request-expire", &cfg_type_boolean, 0 },
2410 { "request-ixfr", &cfg_type_boolean, 0 },
2411 { "request-nsid", &cfg_type_boolean, 0 },
2412 { "request-sit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
2413 { "send-cookie", &cfg_type_boolean, 0 },
2414 { "support-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
2415 { "tcp-keepalive", &cfg_type_boolean, 0 },
2416 { "tcp-only", &cfg_type_boolean, 0 },
2417 { "transfer-format", &cfg_type_transferformat, 0 },
2418 { "transfer-source", &cfg_type_sockaddr4wild, 0 },
2419 { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
2420 { "transfers", &cfg_type_uint32, 0 },
2421 { NULL, NULL, 0 }
2422 };
2423 static cfg_clausedef_t *server_clausesets[] = { server_clauses, NULL };
2424 static cfg_type_t cfg_type_server = { "server", cfg_parse_netprefix_map,
2425 cfg_print_map, cfg_doc_map,
2426 &cfg_rep_map, server_clausesets };
2427
2428 /*%
2429 * Clauses that can be found in a 'channel' clause in the
2430 * 'logging' statement.
2431 *
2432 * These have some additional constraints that need to be
2433 * checked after parsing:
2434 * - There must exactly one of file/syslog/null/stderr
2435 */
2436
2437 static const char *printtime_enums[] = { "iso8601", "iso8601-utc", "local",
2438 NULL };
2439 static isc_result_t
2440 parse_printtime(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2441 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
2442 }
2443 static void
2444 doc_printtime(cfg_printer_t *pctx, const cfg_type_t *type) {
2445 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
2446 }
2447 static cfg_type_t cfg_type_printtime = { "printtime", parse_printtime,
2448 cfg_print_ustring, doc_printtime,
2449 &cfg_rep_string, printtime_enums };
2450
2451 static cfg_clausedef_t channel_clauses[] = {
2452 /* Destinations. We no longer require these to be first. */
2453 { "file", &cfg_type_logfile, 0 },
2454 { "syslog", &cfg_type_optional_facility, 0 },
2455 { "null", &cfg_type_void, 0 },
2456 { "stderr", &cfg_type_void, 0 },
2457 /* Options. We now accept these for the null channel, too. */
2458 { "severity", &cfg_type_logseverity, 0 },
2459 { "print-time", &cfg_type_printtime, 0 },
2460 { "print-severity", &cfg_type_boolean, 0 },
2461 { "print-category", &cfg_type_boolean, 0 },
2462 { "buffered", &cfg_type_boolean, 0 },
2463 { NULL, NULL, 0 }
2464 };
2465 static cfg_clausedef_t *channel_clausesets[] = { channel_clauses, NULL };
2466 static cfg_type_t cfg_type_channel = { "channel", cfg_parse_named_map,
2467 cfg_print_map, cfg_doc_map,
2468 &cfg_rep_map, channel_clausesets };
2469
2470 /*% A list of log destination, used in the "category" clause. */
2471 static cfg_type_t cfg_type_destinationlist = { "destinationlist",
2472 cfg_parse_bracketed_list,
2473 cfg_print_bracketed_list,
2474 cfg_doc_bracketed_list,
2475 &cfg_rep_list,
2476 &cfg_type_astring };
2477
2478 /*%
2479 * Clauses that can be found in a 'logging' statement.
2480 */
2481 static cfg_clausedef_t logging_clauses[] = {
2482 { "channel", &cfg_type_channel, CFG_CLAUSEFLAG_MULTI },
2483 { "category", &cfg_type_category, CFG_CLAUSEFLAG_MULTI },
2484 { NULL, NULL, 0 }
2485 };
2486 static cfg_clausedef_t *logging_clausesets[] = { logging_clauses, NULL };
2487 static cfg_type_t cfg_type_logging = { "logging", cfg_parse_map,
2488 cfg_print_map, cfg_doc_map,
2489 &cfg_rep_map, logging_clausesets };
2490
2491 /*%
2492 * For parsing an 'addzone' statement
2493 */
2494 static cfg_tuplefielddef_t addzone_fields[] = {
2495 { "name", &cfg_type_astring, 0 },
2496 { "class", &cfg_type_optional_class, 0 },
2497 { "view", &cfg_type_optional_class, 0 },
2498 { "options", &cfg_type_zoneopts, 0 },
2499 { NULL, NULL, 0 }
2500 };
2501 static cfg_type_t cfg_type_addzone = { "zone", cfg_parse_tuple,
2502 cfg_print_tuple, cfg_doc_tuple,
2503 &cfg_rep_tuple, addzone_fields };
2504
2505 static cfg_clausedef_t addzoneconf_clauses[] = {
2506 { "zone", &cfg_type_addzone, CFG_CLAUSEFLAG_MULTI }, { NULL, NULL, 0 }
2507 };
2508
2509 static cfg_clausedef_t *addzoneconf_clausesets[] = { addzoneconf_clauses,
2510 NULL };
2511
2512 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_addzoneconf = {
2513 "addzoneconf", cfg_parse_mapbody, cfg_print_mapbody,
2514 cfg_doc_mapbody, &cfg_rep_map, addzoneconf_clausesets
2515 };
2516
2517 static isc_result_t
2518 parse_unitstring(char *str, isc_resourcevalue_t *valuep) {
2519 char *endp;
2520 unsigned int len;
2521 uint64_t value;
2522 uint64_t unit;
2523
2524 value = strtoull(str, &endp, 10);
2525 if (*endp == 0) {
2526 *valuep = value;
2527 return (ISC_R_SUCCESS);
2528 }
2529
2530 len = strlen(str);
2531 if (len < 2 || endp[1] != '\0') {
2532 return (ISC_R_FAILURE);
2533 }
2534
2535 switch (str[len - 1]) {
2536 case 'k':
2537 case 'K':
2538 unit = 1024;
2539 break;
2540 case 'm':
2541 case 'M':
2542 unit = 1024 * 1024;
2543 break;
2544 case 'g':
2545 case 'G':
2546 unit = 1024 * 1024 * 1024;
2547 break;
2548 default:
2549 return (ISC_R_FAILURE);
2550 }
2551 if (value > ((uint64_t)UINT64_MAX / unit)) {
2552 return (ISC_R_FAILURE);
2553 }
2554 *valuep = value * unit;
2555 return (ISC_R_SUCCESS);
2556 }
2557
2558 static isc_result_t
2559 parse_sizeval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2560 isc_result_t result;
2561 cfg_obj_t *obj = NULL;
2562 uint64_t val;
2563
2564 UNUSED(type);
2565
2566 CHECK(cfg_gettoken(pctx, 0));
2567 if (pctx->token.type != isc_tokentype_string) {
2568 result = ISC_R_UNEXPECTEDTOKEN;
2569 goto cleanup;
2570 }
2571 CHECK(parse_unitstring(TOKEN_STRING(pctx), &val));
2572
2573 CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj));
2574 obj->value.uint64 = val;
2575 *ret = obj;
2576 return (ISC_R_SUCCESS);
2577
2578 cleanup:
2579 cfg_parser_error(pctx, CFG_LOG_NEAR,
2580 "expected integer and optional unit");
2581 return (result);
2582 }
2583
2584 static isc_result_t
2585 parse_sizeval_percent(cfg_parser_t *pctx, const cfg_type_t *type,
2586 cfg_obj_t **ret) {
2587 char *endp;
2588 isc_result_t result;
2589 cfg_obj_t *obj = NULL;
2590 uint64_t val;
2591 uint64_t percent;
2592
2593 UNUSED(type);
2594
2595 CHECK(cfg_gettoken(pctx, 0));
2596 if (pctx->token.type != isc_tokentype_string) {
2597 result = ISC_R_UNEXPECTEDTOKEN;
2598 goto cleanup;
2599 }
2600
2601 percent = strtoull(TOKEN_STRING(pctx), &endp, 10);
2602
2603 if (*endp == '%' && *(endp + 1) == 0) {
2604 CHECK(cfg_create_obj(pctx, &cfg_type_percentage, &obj));
2605 obj->value.uint32 = (uint32_t)percent;
2606 *ret = obj;
2607 return (ISC_R_SUCCESS);
2608 } else {
2609 CHECK(parse_unitstring(TOKEN_STRING(pctx), &val));
2610 CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj));
2611 obj->value.uint64 = val;
2612 *ret = obj;
2613 return (ISC_R_SUCCESS);
2614 }
2615
2616 cleanup:
2617 cfg_parser_error(pctx, CFG_LOG_NEAR,
2618 "expected integer and optional unit or percent");
2619 return (result);
2620 }
2621
2622 static void
2623 doc_sizeval_percent(cfg_printer_t *pctx, const cfg_type_t *type) {
2624 UNUSED(type);
2625
2626 cfg_print_cstr(pctx, "( ");
2627 cfg_doc_terminal(pctx, &cfg_type_size);
2628 cfg_print_cstr(pctx, " | ");
2629 cfg_doc_terminal(pctx, &cfg_type_percentage);
2630 cfg_print_cstr(pctx, " )");
2631 }
2632
2633 /*%
2634 * A size value (number + optional unit).
2635 */
2636 static cfg_type_t cfg_type_sizeval = { "sizeval", parse_sizeval,
2637 cfg_print_uint64, cfg_doc_terminal,
2638 &cfg_rep_uint64, NULL };
2639
2640 /*%
2641 * A size, "unlimited", or "default".
2642 */
2643
2644 static isc_result_t
2645 parse_size(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2646 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret));
2647 }
2648
2649 static void
2650 doc_size(cfg_printer_t *pctx, const cfg_type_t *type) {
2651 cfg_doc_enum_or_other(pctx, type, &cfg_type_sizeval);
2652 }
2653
2654 static const char *size_enums[] = { "default", "unlimited", NULL };
2655 static cfg_type_t cfg_type_size = {
2656 "size", parse_size, cfg_print_ustring,
2657 doc_size, &cfg_rep_string, size_enums
2658 };
2659
2660 /*%
2661 * A size or "unlimited", but not "default".
2662 */
2663 static const char *sizenodefault_enums[] = { "unlimited", NULL };
2664 static cfg_type_t cfg_type_sizenodefault = {
2665 "size_no_default", parse_size, cfg_print_ustring,
2666 doc_size, &cfg_rep_string, sizenodefault_enums
2667 };
2668
2669 /*%
2670 * A size in absolute values or percents.
2671 */
2672 static cfg_type_t cfg_type_sizeval_percent = {
2673 "sizeval_percent", parse_sizeval_percent, cfg_print_ustring,
2674 doc_sizeval_percent, &cfg_rep_string, NULL
2675 };
2676
2677 /*%
2678 * A size in absolute values or percents, or "unlimited", or "default"
2679 */
2680
2681 static isc_result_t
2682 parse_size_or_percent(cfg_parser_t *pctx, const cfg_type_t *type,
2683 cfg_obj_t **ret) {
2684 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_sizeval_percent,
2685 ret));
2686 }
2687
2688 static void
2689 doc_parse_size_or_percent(cfg_printer_t *pctx, const cfg_type_t *type) {
2690 UNUSED(type);
2691 cfg_print_cstr(pctx, "( default | unlimited | ");
2692 cfg_doc_terminal(pctx, &cfg_type_sizeval);
2693 cfg_print_cstr(pctx, " | ");
2694 cfg_doc_terminal(pctx, &cfg_type_percentage);
2695 cfg_print_cstr(pctx, " )");
2696 }
2697
2698 static const char *sizeorpercent_enums[] = { "default", "unlimited", NULL };
2699 static cfg_type_t cfg_type_sizeorpercent = {
2700 "size_or_percent", parse_size_or_percent, cfg_print_ustring,
2701 doc_parse_size_or_percent, &cfg_rep_string, sizeorpercent_enums
2702 };
2703
2704 /*%
2705 * optional_keyvalue
2706 */
2707 static isc_result_t
2708 parse_maybe_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
2709 bool optional, cfg_obj_t **ret) {
2710 isc_result_t result;
2711 cfg_obj_t *obj = NULL;
2712 const keyword_type_t *kw = type->of;
2713
2714 CHECK(cfg_peektoken(pctx, 0));
2715 if (pctx->token.type == isc_tokentype_string &&
2716 strcasecmp(TOKEN_STRING(pctx), kw->name) == 0)
2717 {
2718 CHECK(cfg_gettoken(pctx, 0));
2719 CHECK(kw->type->parse(pctx, kw->type, &obj));
2720 obj->type = type; /* XXX kludge */
2721 } else {
2722 if (optional) {
2723 CHECK(cfg_parse_void(pctx, NULL, &obj));
2724 } else {
2725 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected '%s'",
2726 kw->name);
2727 result = ISC_R_UNEXPECTEDTOKEN;
2728 goto cleanup;
2729 }
2730 }
2731 *ret = obj;
2732 cleanup:
2733 return (result);
2734 }
2735
2736 static isc_result_t
2737 parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2738 return (parse_maybe_optional_keyvalue(pctx, type, false, ret));
2739 }
2740
2741 static isc_result_t
2742 parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
2743 cfg_obj_t **ret) {
2744 return (parse_maybe_optional_keyvalue(pctx, type, true, ret));
2745 }
2746
2747 static void
2748 print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj) {
2749 const keyword_type_t *kw = obj->type->of;
2750 cfg_print_cstr(pctx, kw->name);
2751 cfg_print_cstr(pctx, " ");
2752 kw->type->print(pctx, obj);
2753 }
2754
2755 static void
2756 doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
2757 const keyword_type_t *kw = type->of;
2758 cfg_print_cstr(pctx, kw->name);
2759 cfg_print_cstr(pctx, " ");
2760 cfg_doc_obj(pctx, kw->type);
2761 }
2762
2763 static void
2764 doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
2765 const keyword_type_t *kw = type->of;
2766 cfg_print_cstr(pctx, "[ ");
2767 cfg_print_cstr(pctx, kw->name);
2768 cfg_print_cstr(pctx, " ");
2769 cfg_doc_obj(pctx, kw->type);
2770 cfg_print_cstr(pctx, " ]");
2771 }
2772
2773 static const char *dialup_enums[] = { "notify", "notify-passive", "passive",
2774 "refresh", NULL };
2775 static isc_result_t
2776 parse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2777 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
2778 }
2779 static void
2780 doc_dialup_type(cfg_printer_t *pctx, const cfg_type_t *type) {
2781 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
2782 }
2783 static cfg_type_t cfg_type_dialuptype = { "dialuptype", parse_dialup_type,
2784 cfg_print_ustring, doc_dialup_type,
2785 &cfg_rep_string, dialup_enums };
2786
2787 static const char *notify_enums[] = { "explicit", "master-only", NULL };
2788 static isc_result_t
2789 parse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2790 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
2791 }
2792 static void
2793 doc_notify_type(cfg_printer_t *pctx, const cfg_type_t *type) {
2794 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
2795 }
2796 static cfg_type_t cfg_type_notifytype = {
2797 "notifytype", parse_notify_type, cfg_print_ustring,
2798 doc_notify_type, &cfg_rep_string, notify_enums,
2799 };
2800
2801 static const char *minimal_enums[] = { "no-auth", "no-auth-recursive", NULL };
2802 static isc_result_t
2803 parse_minimal(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2804 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
2805 }
2806 static void
2807 doc_minimal(cfg_printer_t *pctx, const cfg_type_t *type) {
2808 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
2809 }
2810 static cfg_type_t cfg_type_minimal = {
2811 "minimal", parse_minimal, cfg_print_ustring,
2812 doc_minimal, &cfg_rep_string, minimal_enums,
2813 };
2814
2815 static const char *ixfrdiff_enums[] = { "primary", "master", "secondary",
2816 "slave", NULL };
2817 static isc_result_t
2818 parse_ixfrdiff_type(cfg_parser_t *pctx, const cfg_type_t *type,
2819 cfg_obj_t **ret) {
2820 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
2821 }
2822 static void
2823 doc_ixfrdiff_type(cfg_printer_t *pctx, const cfg_type_t *type) {
2824 cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
2825 }
2826 static cfg_type_t cfg_type_ixfrdifftype = {
2827 "ixfrdiff", parse_ixfrdiff_type, cfg_print_ustring,
2828 doc_ixfrdiff_type, &cfg_rep_string, ixfrdiff_enums,
2829 };
2830
2831 static keyword_type_t key_kw = { "key", &cfg_type_astring };
2832
2833 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = {
2834 "keyref", parse_keyvalue, print_keyvalue,
2835 doc_keyvalue, &cfg_rep_string, &key_kw
2836 };
2837
2838 static cfg_type_t cfg_type_optional_keyref = {
2839 "optional_keyref", parse_optional_keyvalue, print_keyvalue,
2840 doc_optional_keyvalue, &cfg_rep_string, &key_kw
2841 };
2842
2843 static const char *qminmethod_enums[] = { "strict", "relaxed", "disabled",
2844 "off", NULL };
2845
2846 static cfg_type_t cfg_type_qminmethod = { "qminmethod", cfg_parse_enum,
2847 cfg_print_ustring, cfg_doc_enum,
2848 &cfg_rep_string, qminmethod_enums };
2849
2850 /*%
2851 * A "controls" statement is represented as a map with the multivalued
2852 * "inet" and "unix" clauses.
2853 */
2854
2855 static keyword_type_t controls_allow_kw = { "allow", &cfg_type_bracketed_aml };
2856
2857 static cfg_type_t cfg_type_controls_allow = {
2858 "controls_allow", parse_keyvalue, print_keyvalue,
2859 doc_keyvalue, &cfg_rep_list, &controls_allow_kw
2860 };
2861
2862 static keyword_type_t controls_keys_kw = { "keys", &cfg_type_keylist };
2863
2864 static cfg_type_t cfg_type_controls_keys = {
2865 "controls_keys", parse_optional_keyvalue, print_keyvalue,
2866 doc_optional_keyvalue, &cfg_rep_list, &controls_keys_kw
2867 };
2868
2869 static keyword_type_t controls_readonly_kw = { "read-only", &cfg_type_boolean };
2870
2871 static cfg_type_t cfg_type_controls_readonly = {
2872 "controls_readonly", parse_optional_keyvalue, print_keyvalue,
2873 doc_optional_keyvalue, &cfg_rep_boolean, &controls_readonly_kw
2874 };
2875
2876 static cfg_tuplefielddef_t inetcontrol_fields[] = {
2877 { "address", &cfg_type_controls_sockaddr, 0 },
2878 { "allow", &cfg_type_controls_allow, 0 },
2879 { "keys", &cfg_type_controls_keys, 0 },
2880 { "read-only", &cfg_type_controls_readonly, 0 },
2881 { NULL, NULL, 0 }
2882 };
2883
2884 static cfg_type_t cfg_type_inetcontrol = {
2885 "inetcontrol", cfg_parse_tuple, cfg_print_tuple,
2886 cfg_doc_tuple, &cfg_rep_tuple, inetcontrol_fields
2887 };
2888
2889 static keyword_type_t controls_perm_kw = { "perm", &cfg_type_uint32 };
2890
2891 static cfg_type_t cfg_type_controls_perm = {
2892 "controls_perm", parse_keyvalue, print_keyvalue,
2893 doc_keyvalue, &cfg_rep_uint32, &controls_perm_kw
2894 };
2895
2896 static keyword_type_t controls_owner_kw = { "owner", &cfg_type_uint32 };
2897
2898 static cfg_type_t cfg_type_controls_owner = {
2899 "controls_owner", parse_keyvalue, print_keyvalue,
2900 doc_keyvalue, &cfg_rep_uint32, &controls_owner_kw
2901 };
2902
2903 static keyword_type_t controls_group_kw = { "group", &cfg_type_uint32 };
2904
2905 static cfg_type_t cfg_type_controls_group = {
2906 "controls_allow", parse_keyvalue, print_keyvalue,
2907 doc_keyvalue, &cfg_rep_uint32, &controls_group_kw
2908 };
2909
2910 static cfg_tuplefielddef_t unixcontrol_fields[] = {
2911 { "path", &cfg_type_qstring, 0 },
2912 { "perm", &cfg_type_controls_perm, 0 },
2913 { "owner", &cfg_type_controls_owner, 0 },
2914 { "group", &cfg_type_controls_group, 0 },
2915 { "keys", &cfg_type_controls_keys, 0 },
2916 { "read-only", &cfg_type_controls_readonly, 0 },
2917 { NULL, NULL, 0 }
2918 };
2919
2920 static cfg_type_t cfg_type_unixcontrol = {
2921 "unixcontrol", cfg_parse_tuple, cfg_print_tuple,
2922 cfg_doc_tuple, &cfg_rep_tuple, unixcontrol_fields
2923 };
2924
2925 static cfg_clausedef_t controls_clauses[] = {
2926 { "inet", &cfg_type_inetcontrol, CFG_CLAUSEFLAG_MULTI },
2927 { "unix", &cfg_type_unixcontrol, CFG_CLAUSEFLAG_MULTI },
2928 { NULL, NULL, 0 }
2929 };
2930
2931 static cfg_clausedef_t *controls_clausesets[] = { controls_clauses, NULL };
2932 static cfg_type_t cfg_type_controls = { "controls", cfg_parse_map,
2933 cfg_print_map, cfg_doc_map,
2934 &cfg_rep_map, &controls_clausesets };
2935
2936 /*%
2937 * A "statistics-channels" statement is represented as a map with the
2938 * multivalued "inet" clauses.
2939 */
2940 static void
2941 doc_optional_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
2942 const keyword_type_t *kw = type->of;
2943 cfg_print_cstr(pctx, "[ ");
2944 cfg_print_cstr(pctx, kw->name);
2945 cfg_print_cstr(pctx, " ");
2946 cfg_doc_obj(pctx, kw->type);
2947 cfg_print_cstr(pctx, " ]");
2948 }
2949
2950 static cfg_type_t cfg_type_optional_allow = {
2951 "optional_allow", parse_optional_keyvalue,
2952 print_keyvalue, doc_optional_bracketed_list,
2953 &cfg_rep_list, &controls_allow_kw
2954 };
2955
2956 static cfg_tuplefielddef_t statserver_fields[] = {
2957 { "address", &cfg_type_controls_sockaddr, 0 }, /* reuse controls def */
2958 { "allow", &cfg_type_optional_allow, 0 },
2959 { NULL, NULL, 0 }
2960 };
2961
2962 static cfg_type_t cfg_type_statschannel = {
2963 "statschannel", cfg_parse_tuple, cfg_print_tuple,
2964 cfg_doc_tuple, &cfg_rep_tuple, statserver_fields
2965 };
2966
2967 static cfg_clausedef_t statservers_clauses[] = {
2968 { "inet", &cfg_type_statschannel, CFG_CLAUSEFLAG_MULTI },
2969 { NULL, NULL, 0 }
2970 };
2971
2972 static cfg_clausedef_t *statservers_clausesets[] = { statservers_clauses,
2973 NULL };
2974
2975 static cfg_type_t cfg_type_statschannels = {
2976 "statistics-channels", cfg_parse_map, cfg_print_map,
2977 cfg_doc_map, &cfg_rep_map, &statservers_clausesets
2978 };
2979
2980 /*%
2981 * An optional class, as used in view and zone statements.
2982 */
2983 static isc_result_t
2984 parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type,
2985 cfg_obj_t **ret) {
2986 isc_result_t result;
2987 UNUSED(type);
2988 CHECK(cfg_peektoken(pctx, 0));
2989 if (pctx->token.type == isc_tokentype_string) {
2990 CHECK(cfg_parse_obj(pctx, &cfg_type_ustring, ret));
2991 } else {
2992 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
2993 }
2994 cleanup:
2995 return (result);
2996 }
2997
2998 static void
2999 doc_optional_class(cfg_printer_t *pctx, const cfg_type_t *type) {
3000 UNUSED(type);
3001 cfg_print_cstr(pctx, "[ <class> ]");
3002 }
3003
3004 static cfg_type_t cfg_type_optional_class = { "optional_class",
3005 parse_optional_class,
3006 NULL,
3007 doc_optional_class,
3008 NULL,
3009 NULL };
3010
3011 static isc_result_t
3012 parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
3013 isc_result_t result;
3014 cfg_obj_t *obj = NULL;
3015 isc_netaddr_t netaddr;
3016 in_port_t port = 0;
3017 isc_dscp_t dscp = -1;
3018 unsigned int have_address = 0;
3019 unsigned int have_port = 0;
3020 unsigned int have_dscp = 0;
3021 const unsigned int *flagp = type->of;
3022
3023 if ((*flagp & CFG_ADDR_V4OK) != 0) {
3024 isc_netaddr_any(&netaddr);
3025 } else if ((*flagp & CFG_ADDR_V6OK) != 0) {
3026 isc_netaddr_any6(&netaddr);
3027 } else {
3028 INSIST(0);
3029 ISC_UNREACHABLE();
3030 }
3031
3032 for (;;) {
3033 CHECK(cfg_peektoken(pctx, 0));
3034 if (pctx->token.type == isc_tokentype_string) {
3035 if (strcasecmp(TOKEN_STRING(pctx), "address") == 0) {
3036 /* read "address" */
3037 CHECK(cfg_gettoken(pctx, 0));
3038 CHECK(cfg_parse_rawaddr(pctx, *flagp,
3039 &netaddr));
3040 have_address++;
3041 } else if (strcasecmp(TOKEN_STRING(pctx), "port") == 0)
3042 {
3043 /* read "port" */
3044 CHECK(cfg_gettoken(pctx, 0));
3045 CHECK(cfg_parse_rawport(pctx, CFG_ADDR_WILDOK,
3046 &port));
3047 have_port++;
3048 } else if (strcasecmp(TOKEN_STRING(pctx), "dscp") == 0)
3049 {
3050 /* read "dscp" */
3051 CHECK(cfg_gettoken(pctx, 0));
3052 CHECK(cfg_parse_dscp(pctx, &dscp));
3053 have_dscp++;
3054 } else if (have_port == 0 && have_dscp == 0 &&
3055 have_address == 0) {
3056 return (cfg_parse_sockaddr(pctx, type, ret));
3057 } else {
3058 cfg_parser_error(pctx, CFG_LOG_NEAR,
3059 "expected 'address', 'port', "
3060 "or 'dscp'");
3061 return (ISC_R_UNEXPECTEDTOKEN);
3062 }
3063 } else {
3064 break;
3065 }
3066 }
3067 if (have_address > 1 || have_port > 1 || have_address + have_port == 0)
3068 {
3069 cfg_parser_error(pctx, 0, "expected one address and/or port");
3070 return (ISC_R_UNEXPECTEDTOKEN);
3071 }
3072
3073 if (have_dscp > 1) {
3074 cfg_parser_error(pctx, 0, "expected at most one dscp");
3075 return (ISC_R_UNEXPECTEDTOKEN);
3076 }
3077
3078 CHECK(cfg_create_obj(pctx, &cfg_type_querysource, &obj));
3079 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
3080 obj->value.sockaddrdscp.dscp = dscp;
3081 *ret = obj;
3082 return (ISC_R_SUCCESS);
3083
3084 cleanup:
3085 cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid query source");
3086 CLEANUP_OBJ(obj);
3087 return (result);
3088 }
3089
3090 static void
3091 print_querysource(cfg_printer_t *pctx, const cfg_obj_t *obj) {
3092 isc_netaddr_t na;
3093 isc_netaddr_fromsockaddr(&na, &obj->value.sockaddr);
3094 cfg_print_cstr(pctx, "address ");
3095 cfg_print_rawaddr(pctx, &na);
3096 cfg_print_cstr(pctx, " port ");
3097 cfg_print_rawuint(pctx, isc_sockaddr_getport(&obj->value.sockaddr));
3098 if (obj->value.sockaddrdscp.dscp != -1) {
3099 cfg_print_cstr(pctx, " dscp ");
3100 cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp);
3101 }
3102 }
3103
3104 static void
3105 doc_querysource(cfg_printer_t *pctx, const cfg_type_t *type) {
3106 const unsigned int *flagp = type->of;
3107
3108 cfg_print_cstr(pctx, "( ( [ address ] ( ");
3109 if ((*flagp & CFG_ADDR_V4OK) != 0) {
3110 cfg_print_cstr(pctx, "<ipv4_address>");
3111 } else if ((*flagp & CFG_ADDR_V6OK) != 0) {
3112 cfg_print_cstr(pctx, "<ipv6_address>");
3113 } else {
3114 INSIST(0);
3115 ISC_UNREACHABLE();
3116 }
3117 cfg_print_cstr(pctx, " | * ) [ port ( <integer> | * ) ] ) | "
3118 "( [ [ address ] ( ");
3119 if ((*flagp & CFG_ADDR_V4OK) != 0) {
3120 cfg_print_cstr(pctx, "<ipv4_address>");
3121 } else if ((*flagp & CFG_ADDR_V6OK) != 0) {
3122 cfg_print_cstr(pctx, "<ipv6_address>");
3123 } else {
3124 INSIST(0);
3125 ISC_UNREACHABLE();
3126 }
3127 cfg_print_cstr(pctx, " | * ) ] port ( <integer> | * ) ) )"
3128 " [ dscp <integer> ]");
3129 }
3130
3131 static unsigned int sockaddr4wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V4OK |
3132 CFG_ADDR_DSCPOK;
3133 static unsigned int sockaddr6wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V6OK |
3134 CFG_ADDR_DSCPOK;
3135
3136 static cfg_type_t cfg_type_querysource4 = {
3137 "querysource4", parse_querysource, NULL, doc_querysource,
3138 NULL, &sockaddr4wild_flags
3139 };
3140
3141 static cfg_type_t cfg_type_querysource6 = {
3142 "querysource6", parse_querysource, NULL, doc_querysource,
3143 NULL, &sockaddr6wild_flags
3144 };
3145
3146 static cfg_type_t cfg_type_querysource = { "querysource", NULL,
3147 print_querysource, NULL,
3148 &cfg_rep_sockaddr, NULL };
3149
3150 /*%
3151 * The socket address syntax in the "controls" statement is silly.
3152 * It allows both socket address families, but also allows "*",
3153 * which is gratuitously interpreted as the IPv4 wildcard address.
3154 */
3155 static unsigned int controls_sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK |
3156 CFG_ADDR_WILDOK;
3157 static cfg_type_t cfg_type_controls_sockaddr = {
3158 "controls_sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr,
3159 cfg_doc_sockaddr, &cfg_rep_sockaddr, &controls_sockaddr_flags
3160 };
3161
3162 /*%
3163 * Handle the special kludge syntax of the "keys" clause in the "server"
3164 * statement, which takes a single key with or without braces and semicolon.
3165 */
3166 static isc_result_t
3167 parse_server_key_kludge(cfg_parser_t *pctx, const cfg_type_t *type,
3168 cfg_obj_t **ret) {
3169 isc_result_t result;
3170 bool braces = false;
3171 UNUSED(type);
3172
3173 /* Allow opening brace. */
3174 CHECK(cfg_peektoken(pctx, 0));
3175 if (pctx->token.type == isc_tokentype_special &&
3176 pctx->token.value.as_char == '{')
3177 {
3178 CHECK(cfg_gettoken(pctx, 0));
3179 braces = true;
3180 }
3181
3182 CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
3183
3184 if (braces) {
3185 /* Skip semicolon if present. */
3186 CHECK(cfg_peektoken(pctx, 0));
3187 if (pctx->token.type == isc_tokentype_special &&
3188 pctx->token.value.as_char == ';')
3189 {
3190 CHECK(cfg_gettoken(pctx, 0));
3191 }
3192
3193 CHECK(cfg_parse_special(pctx, '}'));
3194 }
3195 cleanup:
3196 return (result);
3197 }
3198 static cfg_type_t cfg_type_server_key_kludge = {
3199 "server_key", parse_server_key_kludge, NULL, cfg_doc_terminal, NULL,
3200 NULL
3201 };
3202
3203 /*%
3204 * An optional logging facility.
3205 */
3206
3207 static isc_result_t
3208 parse_optional_facility(cfg_parser_t *pctx, const cfg_type_t *type,
3209 cfg_obj_t **ret) {
3210 isc_result_t result;
3211 UNUSED(type);
3212
3213 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
3214 if (pctx->token.type == isc_tokentype_string ||
3215 pctx->token.type == isc_tokentype_qstring)
3216 {
3217 CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
3218 } else {
3219 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
3220 }
3221 cleanup:
3222 return (result);
3223 }
3224
3225 static void
3226 doc_optional_facility(cfg_printer_t *pctx, const cfg_type_t *type) {
3227 UNUSED(type);
3228 cfg_print_cstr(pctx, "[ <syslog_facility> ]");
3229 }
3230
3231 static cfg_type_t cfg_type_optional_facility = { "optional_facility",
3232 parse_optional_facility,
3233 NULL,
3234 doc_optional_facility,
3235 NULL,
3236 NULL };
3237
3238 /*%
3239 * A log severity. Return as a string, except "debug N",
3240 * which is returned as a keyword object.
3241 */
3242
3243 static keyword_type_t debug_kw = { "debug", &cfg_type_uint32 };
3244 static cfg_type_t cfg_type_debuglevel = { "debuglevel", parse_keyvalue,
3245 print_keyvalue, doc_keyvalue,
3246 &cfg_rep_uint32, &debug_kw };
3247
3248 static isc_result_t
3249 parse_logseverity(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
3250 isc_result_t result;
3251 UNUSED(type);
3252
3253 CHECK(cfg_peektoken(pctx, 0));
3254 if (pctx->token.type == isc_tokentype_string &&
3255 strcasecmp(TOKEN_STRING(pctx), "debug") == 0)
3256 {
3257 CHECK(cfg_gettoken(pctx, 0)); /* read "debug" */
3258 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER));
3259 if (pctx->token.type == isc_tokentype_number) {
3260 CHECK(cfg_parse_uint32(pctx, NULL, ret));
3261 } else {
3262 /*
3263 * The debug level is optional and defaults to 1.
3264 * This makes little sense, but we support it for
3265 * compatibility with BIND 8.
3266 */
3267 CHECK(cfg_create_obj(pctx, &cfg_type_uint32, ret));
3268 (*ret)->value.uint32 = 1;
3269 }
3270 (*ret)->type = &cfg_type_debuglevel; /* XXX kludge */
3271 } else {
3272 CHECK(cfg_parse_obj(pctx, &cfg_type_loglevel, ret));
3273 }
3274 cleanup:
3275 return (result);
3276 }
3277
3278 static cfg_type_t cfg_type_logseverity = { "log_severity", parse_logseverity,
3279 NULL, cfg_doc_terminal,
3280 NULL, NULL };
3281
3282 /*%
3283 * The "file" clause of the "channel" statement.
3284 * This is yet another special case.
3285 */
3286
3287 static const char *logversions_enums[] = { "unlimited", NULL };
3288 static isc_result_t
3289 parse_logversions(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
3290 return (cfg_parse_enum_or_other(pctx, type, &cfg_type_uint32, ret));
3291 }
3292
3293 static void
3294 doc_logversions(cfg_printer_t *pctx, const cfg_type_t *type) {
3295 cfg_doc_enum_or_other(pctx, type, &cfg_type_uint32);
3296 }
3297
3298 static cfg_type_t cfg_type_logversions = {
3299 "logversions", parse_logversions, cfg_print_ustring,
3300 doc_logversions, &cfg_rep_string, logversions_enums
3301 };
3302
3303 static const char *logsuffix_enums[] = { "increment", "timestamp", NULL };
3304 static cfg_type_t cfg_type_logsuffix = { "logsuffix", cfg_parse_enum,
3305 cfg_print_ustring, cfg_doc_enum,
3306 &cfg_rep_string, &logsuffix_enums };
3307
3308 static cfg_tuplefielddef_t logfile_fields[] = {
3309 { "file", &cfg_type_qstring, 0 },
3310 { "versions", &cfg_type_logversions, 0 },
3311 { "size", &cfg_type_size, 0 },
3312 { "suffix", &cfg_type_logsuffix, 0 },
3313 { NULL, NULL, 0 }
3314 };
3315
3316 static isc_result_t
3317 parse_logfile(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
3318 isc_result_t result;
3319 cfg_obj_t *obj = NULL;
3320 const cfg_tuplefielddef_t *fields = type->of;
3321
3322 CHECK(cfg_create_tuple(pctx, type, &obj));
3323
3324 /* Parse the mandatory "file" field */
3325 CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
3326
3327 /* Parse "versions" and "size" fields in any order. */
3328 for (;;) {
3329 CHECK(cfg_peektoken(pctx, 0));
3330 if (pctx->token.type == isc_tokentype_string) {
3331 CHECK(cfg_gettoken(pctx, 0));
3332 if (strcasecmp(TOKEN_STRING(pctx), "versions") == 0 &&
3333 obj->value.tuple[1] == NULL)
3334 {
3335 CHECK(cfg_parse_obj(pctx, fields[1].type,
3336 &obj->value.tuple[1]));
3337 } else if (strcasecmp(TOKEN_STRING(pctx), "size") ==
3338 0 &&
3339 obj->value.tuple[2] == NULL)
3340 {
3341 CHECK(cfg_parse_obj(pctx, fields[2].type,
3342 &obj->value.tuple[2]));
3343 } else if (strcasecmp(TOKEN_STRING(pctx), "suffix") ==
3344 0 &&
3345 obj->value.tuple[3] == NULL)
3346 {
3347 CHECK(cfg_parse_obj(pctx, fields[3].type,
3348 &obj->value.tuple[3]));
3349 } else {
3350 break;
3351 }
3352 } else {
3353 break;
3354 }
3355 }
3356
3357 /* Create void objects for missing optional values. */
3358 if (obj->value.tuple[1] == NULL) {
3359 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1]));
3360 }
3361 if (obj->value.tuple[2] == NULL) {
3362 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2]));
3363 }
3364 if (obj->value.tuple[3] == NULL) {
3365 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[3]));
3366 }
3367
3368 *ret = obj;
3369 return (ISC_R_SUCCESS);
3370
3371 cleanup:
3372 CLEANUP_OBJ(obj);
3373 return (result);
3374 }
3375
3376 static void
3377 print_logfile(cfg_printer_t *pctx, const cfg_obj_t *obj) {
3378 cfg_print_obj(pctx, obj->value.tuple[0]); /* file */
3379 if (obj->value.tuple[1]->type->print != cfg_print_void) {
3380 cfg_print_cstr(pctx, " versions ");
3381 cfg_print_obj(pctx, obj->value.tuple[1]);
3382 }
3383 if (obj->value.tuple[2]->type->print != cfg_print_void) {
3384 cfg_print_cstr(pctx, " size ");
3385 cfg_print_obj(pctx, obj->value.tuple[2]);
3386 }
3387 if (obj->value.tuple[3]->type->print != cfg_print_void) {
3388 cfg_print_cstr(pctx, " suffix ");
3389 cfg_print_obj(pctx, obj->value.tuple[3]);
3390 }
3391 }
3392
3393 static void
3394 doc_logfile(cfg_printer_t *pctx, const cfg_type_t *type) {
3395 UNUSED(type);
3396 cfg_print_cstr(pctx, "<quoted_string>");
3397 cfg_print_cstr(pctx, " ");
3398 cfg_print_cstr(pctx, "[ versions ( unlimited | <integer> ) ]");
3399 cfg_print_cstr(pctx, " ");
3400 cfg_print_cstr(pctx, "[ size <size> ]");
3401 cfg_print_cstr(pctx, " ");
3402 cfg_print_cstr(pctx, "[ suffix ( increment | timestamp ) ]");
3403 }
3404
3405 static cfg_type_t cfg_type_logfile = { "log_file", parse_logfile,
3406 print_logfile, doc_logfile,
3407 &cfg_rep_tuple, logfile_fields };
3408
3409 /*% An IPv4 address with optional dscp and port, "*" accepted as wildcard. */
3410 static cfg_type_t cfg_type_sockaddr4wild = {
3411 "sockaddr4wild", cfg_parse_sockaddr, cfg_print_sockaddr,
3412 cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr4wild_flags
3413 };
3414
3415 /*% An IPv6 address with optional port, "*" accepted as wildcard. */
3416 static cfg_type_t cfg_type_sockaddr6wild = {
3417 "v6addrportwild", cfg_parse_sockaddr, cfg_print_sockaddr,
3418 cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr6wild_flags
3419 };
3420
3421 /*%
3422 * rndc
3423 */
3424
3425 static cfg_clausedef_t rndcconf_options_clauses[] = {
3426 { "default-key", &cfg_type_astring, 0 },
3427 { "default-port", &cfg_type_uint32, 0 },
3428 { "default-server", &cfg_type_astring, 0 },
3429 { "default-source-address", &cfg_type_netaddr4wild, 0 },
3430 { "default-source-address-v6", &cfg_type_netaddr6wild, 0 },
3431 { NULL, NULL, 0 }
3432 };
3433
3434 static cfg_clausedef_t *rndcconf_options_clausesets[] = {
3435 rndcconf_options_clauses, NULL
3436 };
3437
3438 static cfg_type_t cfg_type_rndcconf_options = {
3439 "rndcconf_options", cfg_parse_map, cfg_print_map,
3440 cfg_doc_map, &cfg_rep_map, rndcconf_options_clausesets
3441 };
3442
3443 static cfg_clausedef_t rndcconf_server_clauses[] = {
3444 { "key", &cfg_type_astring, 0 },
3445 { "port", &cfg_type_uint32, 0 },
3446 { "source-address", &cfg_type_netaddr4wild, 0 },
3447 { "source-address-v6", &cfg_type_netaddr6wild, 0 },
3448 { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 },
3449 { NULL, NULL, 0 }
3450 };
3451
3452 static cfg_clausedef_t *rndcconf_server_clausesets[] = {
3453 rndcconf_server_clauses, NULL
3454 };
3455
3456 static cfg_type_t cfg_type_rndcconf_server = {
3457 "rndcconf_server", cfg_parse_named_map, cfg_print_map,
3458 cfg_doc_map, &cfg_rep_map, rndcconf_server_clausesets
3459 };
3460
3461 static cfg_clausedef_t rndcconf_clauses[] = {
3462 { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
3463 { "server", &cfg_type_rndcconf_server, CFG_CLAUSEFLAG_MULTI },
3464 { "options", &cfg_type_rndcconf_options, 0 },
3465 { NULL, NULL, 0 }
3466 };
3467
3468 static cfg_clausedef_t *rndcconf_clausesets[] = { rndcconf_clauses, NULL };
3469
3470 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndcconf = {
3471 "rndcconf", cfg_parse_mapbody, cfg_print_mapbody,
3472 cfg_doc_mapbody, &cfg_rep_map, rndcconf_clausesets
3473 };
3474
3475 static cfg_clausedef_t rndckey_clauses[] = { { "key", &cfg_type_key, 0 },
3476 { NULL, NULL, 0 } };
3477
3478 static cfg_clausedef_t *rndckey_clausesets[] = { rndckey_clauses, NULL };
3479
3480 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndckey = {
3481 "rndckey", cfg_parse_mapbody, cfg_print_mapbody,
3482 cfg_doc_mapbody, &cfg_rep_map, rndckey_clausesets
3483 };
3484
3485 /*
3486 * session.key has exactly the same syntax as rndc.key, but it's defined
3487 * separately for clarity (and so we can extend it someday, if needed).
3488 */
3489 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sessionkey = {
3490 "sessionkey", cfg_parse_mapbody, cfg_print_mapbody,
3491 cfg_doc_mapbody, &cfg_rep_map, rndckey_clausesets
3492 };
3493
3494 static cfg_tuplefielddef_t nameport_fields[] = {
3495 { "name", &cfg_type_astring, 0 },
3496 { "port", &cfg_type_optional_port, 0 },
3497 { "dscp", &cfg_type_optional_dscp, 0 },
3498 { NULL, NULL, 0 }
3499 };
3500
3501 static cfg_type_t cfg_type_nameport = { "nameport", cfg_parse_tuple,
3502 cfg_print_tuple, cfg_doc_tuple,
3503 &cfg_rep_tuple, nameport_fields };
3504
3505 static void
3506 doc_sockaddrnameport(cfg_printer_t *pctx, const cfg_type_t *type) {
3507 UNUSED(type);
3508 cfg_print_cstr(pctx, "( ");
3509 cfg_print_cstr(pctx, "<quoted_string>");
3510 cfg_print_cstr(pctx, " ");
3511 cfg_print_cstr(pctx, "[ port <integer> ]");
3512 cfg_print_cstr(pctx, " ");
3513 cfg_print_cstr(pctx, "[ dscp <integer> ]");
3514 cfg_print_cstr(pctx, " | ");
3515 cfg_print_cstr(pctx, "<ipv4_address>");
3516 cfg_print_cstr(pctx, " ");
3517 cfg_print_cstr(pctx, "[ port <integer> ]");
3518 cfg_print_cstr(pctx, " ");
3519 cfg_print_cstr(pctx, "[ dscp <integer> ]");
3520 cfg_print_cstr(pctx, " | ");
3521 cfg_print_cstr(pctx, "<ipv6_address>");
3522 cfg_print_cstr(pctx, " ");
3523 cfg_print_cstr(pctx, "[ port <integer> ]");
3524 cfg_print_cstr(pctx, " ");
3525 cfg_print_cstr(pctx, "[ dscp <integer> ]");
3526 cfg_print_cstr(pctx, " )");
3527 }
3528
3529 static isc_result_t
3530 parse_sockaddrnameport(cfg_parser_t *pctx, const cfg_type_t *type,
3531 cfg_obj_t **ret) {
3532 isc_result_t result;
3533 cfg_obj_t *obj = NULL;
3534 UNUSED(type);
3535
3536 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
3537 if (pctx->token.type == isc_tokentype_string ||
3538 pctx->token.type == isc_tokentype_qstring)
3539 {
3540 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
3541 {
3542 CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr,
3543 ret));
3544 } else {
3545 const cfg_tuplefielddef_t *fields =
3546 cfg_type_nameport.of;
3547 CHECK(cfg_create_tuple(pctx, &cfg_type_nameport, &obj));
3548 CHECK(cfg_parse_obj(pctx, fields[0].type,
3549 &obj->value.tuple[0]));
3550 CHECK(cfg_parse_obj(pctx, fields[1].type,
3551 &obj->value.tuple[1]));
3552 CHECK(cfg_parse_obj(pctx, fields[2].type,
3553 &obj->value.tuple[2]));
3554 *ret = obj;
3555 obj = NULL;
3556 }
3557 } else {
3558 cfg_parser_error(pctx, CFG_LOG_NEAR,
3559 "expected IP address or hostname");
3560 return (ISC_R_UNEXPECTEDTOKEN);
3561 }
3562 cleanup:
3563 CLEANUP_OBJ(obj);
3564 return (result);
3565 }
3566
3567 static cfg_type_t cfg_type_sockaddrnameport = { "sockaddrnameport_element",
3568 parse_sockaddrnameport,
3569 NULL,
3570 doc_sockaddrnameport,
3571 NULL,
3572 NULL };
3573
3574 static cfg_type_t cfg_type_bracketed_sockaddrnameportlist = {
3575 "bracketed_sockaddrnameportlist",
3576 cfg_parse_bracketed_list,
3577 cfg_print_bracketed_list,
3578 cfg_doc_bracketed_list,
3579 &cfg_rep_list,
3580 &cfg_type_sockaddrnameport
3581 };
3582
3583 /*%
3584 * A list of socket addresses or name with an optional default port,
3585 * as used in the dual-stack-servers option. E.g.,
3586 * "port 1234 { dual-stack-servers.net; 10.0.0.1; 1::2 port 69; }"
3587 */
3588 static cfg_tuplefielddef_t nameportiplist_fields[] = {
3589 { "port", &cfg_type_optional_port, 0 },
3590 { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 },
3591 { NULL, NULL, 0 }
3592 };
3593
3594 static cfg_type_t cfg_type_nameportiplist = {
3595 "nameportiplist", cfg_parse_tuple, cfg_print_tuple,
3596 cfg_doc_tuple, &cfg_rep_tuple, nameportiplist_fields
3597 };
3598
3599 /*%
3600 * masters element.
3601 */
3602
3603 static void
3604 doc_masterselement(cfg_printer_t *pctx, const cfg_type_t *type) {
3605 UNUSED(type);
3606 cfg_print_cstr(pctx, "( ");
3607 cfg_print_cstr(pctx, "<masters>");
3608 cfg_print_cstr(pctx, " | ");
3609 cfg_print_cstr(pctx, "<ipv4_address>");
3610 cfg_print_cstr(pctx, " ");
3611 cfg_print_cstr(pctx, "[ port <integer> ]");
3612 cfg_print_cstr(pctx, " | ");
3613 cfg_print_cstr(pctx, "<ipv6_address>");
3614 cfg_print_cstr(pctx, " ");
3615 cfg_print_cstr(pctx, "[ port <integer> ]");
3616 cfg_print_cstr(pctx, " )");
3617 }
3618
3619 static isc_result_t
3620 parse_masterselement(cfg_parser_t *pctx, const cfg_type_t *type,
3621 cfg_obj_t **ret) {
3622 isc_result_t result;
3623 cfg_obj_t *obj = NULL;
3624 UNUSED(type);
3625
3626 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
3627 if (pctx->token.type == isc_tokentype_string ||
3628 pctx->token.type == isc_tokentype_qstring)
3629 {
3630 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
3631 {
3632 CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr,
3633 ret));
3634 } else {
3635 CHECK(cfg_parse_astring(pctx, &cfg_type_astring, ret));
3636 }
3637 } else {
3638 cfg_parser_error(pctx, CFG_LOG_NEAR,
3639 "expected IP address or masters name");
3640 return (ISC_R_UNEXPECTEDTOKEN);
3641 }
3642 cleanup:
3643 CLEANUP_OBJ(obj);
3644 return (result);
3645 }
3646
3647 static cfg_type_t cfg_type_masterselement = { "masters_element",
3648 parse_masterselement,
3649 NULL,
3650 doc_masterselement,
3651 NULL,
3652 NULL };
3653
3654 static int
3655 cmp_clause(const void *ap, const void *bp) {
3656 const cfg_clausedef_t *a = (const cfg_clausedef_t *)ap;
3657 const cfg_clausedef_t *b = (const cfg_clausedef_t *)bp;
3658 return (strcmp(a->name, b->name));
3659 }
3660
3661 bool
3662 cfg_clause_validforzone(const char *name, unsigned int ztype) {
3663 const cfg_clausedef_t *clause;
3664 bool valid = false;
3665
3666 for (clause = zone_clauses; clause->name != NULL; clause++) {
3667 if ((clause->flags & ztype) == 0 ||
3668 strcmp(clause->name, name) != 0) {
3669 continue;
3670 }
3671 valid = true;
3672 }
3673 for (clause = zone_only_clauses; clause->name != NULL; clause++) {
3674 if ((clause->flags & ztype) == 0 ||
3675 strcmp(clause->name, name) != 0) {
3676 continue;
3677 }
3678 valid = true;
3679 }
3680
3681 return (valid);
3682 }
3683
3684 void
3685 cfg_print_zonegrammar(const unsigned int zonetype, unsigned int flags,
3686 void (*f)(void *closure, const char *text, int textlen),
3687 void *closure) {
3688 #define NCLAUSES \
3689 (((sizeof(zone_clauses) + sizeof(zone_only_clauses)) / \
3690 sizeof(clause[0])) - \
3691 1)
3692
3693 cfg_printer_t pctx;
3694 cfg_clausedef_t *clause = NULL;
3695 cfg_clausedef_t clauses[NCLAUSES];
3696
3697 pctx.f = f;
3698 pctx.closure = closure;
3699 pctx.indent = 0;
3700 pctx.flags = flags;
3701
3702 memmove(clauses, zone_clauses, sizeof(zone_clauses));
3703 memmove(clauses + sizeof(zone_clauses) / sizeof(zone_clauses[0]) - 1,
3704 zone_only_clauses, sizeof(zone_only_clauses));
3705 qsort(clauses, NCLAUSES - 1, sizeof(clause[0]), cmp_clause);
3706
3707 cfg_print_cstr(&pctx, "zone <string> [ <class> ] {\n");
3708 pctx.indent++;
3709
3710 switch (zonetype) {
3711 case CFG_ZONE_MASTER:
3712 cfg_print_indent(&pctx);
3713 cfg_print_cstr(&pctx, "type ( master | primary );\n");
3714 break;
3715 case CFG_ZONE_SLAVE:
3716 cfg_print_indent(&pctx);
3717 cfg_print_cstr(&pctx, "type ( slave | secondary );\n");
3718 break;
3719 case CFG_ZONE_MIRROR:
3720 cfg_print_indent(&pctx);
3721 cfg_print_cstr(&pctx, "type mirror;\n");
3722 break;
3723 case CFG_ZONE_STUB:
3724 cfg_print_indent(&pctx);
3725 cfg_print_cstr(&pctx, "type stub;\n");
3726 break;
3727 case CFG_ZONE_HINT:
3728 cfg_print_indent(&pctx);
3729 cfg_print_cstr(&pctx, "type hint;\n");
3730 break;
3731 case CFG_ZONE_FORWARD:
3732 cfg_print_indent(&pctx);
3733 cfg_print_cstr(&pctx, "type forward;\n");
3734 break;
3735 case CFG_ZONE_STATICSTUB:
3736 cfg_print_indent(&pctx);
3737 cfg_print_cstr(&pctx, "type static-stub;\n");
3738 break;
3739 case CFG_ZONE_REDIRECT:
3740 cfg_print_indent(&pctx);
3741 cfg_print_cstr(&pctx, "type redirect;\n");
3742 break;
3743 case CFG_ZONE_DELEGATION:
3744 cfg_print_indent(&pctx);
3745 cfg_print_cstr(&pctx, "type delegation-only;\n");
3746 break;
3747 case CFG_ZONE_INVIEW:
3748 /* no zone type is specified for these */
3749 break;
3750 default:
3751 INSIST(0);
3752 ISC_UNREACHABLE();
3753 }
3754
3755 for (clause = clauses; clause->name != NULL; clause++) {
3756 if (((pctx.flags & CFG_PRINTER_ACTIVEONLY) != 0) &&
3757 (((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0) ||
3758 ((clause->flags & CFG_CLAUSEFLAG_ANCIENT) != 0) ||
3759 ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0) ||
3760 ((clause->flags & CFG_CLAUSEFLAG_TESTONLY) != 0)))
3761 {
3762 continue;
3763 }
3764 if ((clause->flags & zonetype) == 0 ||
3765 strcasecmp(clause->name, "type") == 0) {
3766 continue;
3767 }
3768 cfg_print_indent(&pctx);
3769 cfg_print_cstr(&pctx, clause->name);
3770 cfg_print_cstr(&pctx, " ");
3771 cfg_doc_obj(&pctx, clause->type);
3772 cfg_print_cstr(&pctx, ";");
3773 cfg_print_clauseflags(&pctx, clause->flags);
3774 cfg_print_cstr(&pctx, "\n");
3775 }
3776
3777 pctx.indent--;
3778 cfg_print_cstr(&pctx, "};\n");
3779 }
3780