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