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