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