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