No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / isccfg / namedconf.c
blobc2421c9141e18f51a52ac528bd6bfc42f9279de3
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2002, 2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: namedconf.c,v 1.113 2009/12/04 21:09:34 marka Exp */
22 /*! \file */
24 #include <config.h>
26 #include <string.h>
28 #include <isc/lex.h>
29 #include <isc/mem.h>
30 #include <isc/result.h>
31 #include <isc/string.h>
32 #include <isc/util.h>
34 #include <isccfg/cfg.h>
35 #include <isccfg/grammar.h>
36 #include <isccfg/log.h>
38 #define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
40 /*% Check a return value. */
41 #define CHECK(op) \
42 do { result = (op); \
43 if (result != ISC_R_SUCCESS) goto cleanup; \
44 } while (0)
46 /*% Clean up a configuration object if non-NULL. */
47 #define CLEANUP_OBJ(obj) \
48 do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
51 /*%
52 * Forward declarations of static functions.
55 static isc_result_t
56 parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
57 const cfg_type_t *othertype, cfg_obj_t **ret);
59 static isc_result_t
60 parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
62 static isc_result_t
63 parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
64 cfg_obj_t **ret);
66 static isc_result_t
67 parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
68 cfg_obj_t **ret);
70 static void
71 doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type);
73 static void
74 print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj);
76 static void
77 doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
79 static void
80 doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
82 static cfg_type_t cfg_type_acl;
83 static cfg_type_t cfg_type_addrmatchelt;
84 static cfg_type_t cfg_type_bracketed_aml;
85 static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
86 static cfg_type_t cfg_type_bracketed_sockaddrlist;
87 static cfg_type_t cfg_type_bracketed_sockaddrnameportlist;
88 static cfg_type_t cfg_type_controls;
89 static cfg_type_t cfg_type_controls_sockaddr;
90 static cfg_type_t cfg_type_destinationlist;
91 static cfg_type_t cfg_type_dialuptype;
92 static cfg_type_t cfg_type_ixfrdifftype;
93 static cfg_type_t cfg_type_key;
94 static cfg_type_t cfg_type_logfile;
95 static cfg_type_t cfg_type_logging;
96 static cfg_type_t cfg_type_logseverity;
97 static cfg_type_t cfg_type_lwres;
98 static cfg_type_t cfg_type_masterselement;
99 static cfg_type_t cfg_type_nameportiplist;
100 static cfg_type_t cfg_type_negated;
101 static cfg_type_t cfg_type_notifytype;
102 static cfg_type_t cfg_type_optional_allow;
103 static cfg_type_t cfg_type_optional_class;
104 static cfg_type_t cfg_type_optional_facility;
105 static cfg_type_t cfg_type_optional_keyref;
106 static cfg_type_t cfg_type_optional_port;
107 static cfg_type_t cfg_type_options;
108 static cfg_type_t cfg_type_portiplist;
109 static cfg_type_t cfg_type_querysource4;
110 static cfg_type_t cfg_type_querysource6;
111 static cfg_type_t cfg_type_querysource;
112 static cfg_type_t cfg_type_server;
113 static cfg_type_t cfg_type_server_key_kludge;
114 static cfg_type_t cfg_type_size;
115 static cfg_type_t cfg_type_sizenodefault;
116 static cfg_type_t cfg_type_sockaddr4wild;
117 static cfg_type_t cfg_type_sockaddr6wild;
118 static cfg_type_t cfg_type_statschannels;
119 static cfg_type_t cfg_type_view;
120 static cfg_type_t cfg_type_viewopts;
121 static cfg_type_t cfg_type_zone;
122 static cfg_type_t cfg_type_zoneopts;
123 static cfg_type_t cfg_type_dynamically_loadable_zones;
124 static cfg_type_t cfg_type_dynamically_loadable_zones_opts;
125 #ifdef ALLOW_FILTER_AAAA_ON_V4
126 static cfg_type_t cfg_type_v4_aaaa;
127 #endif
130 * Clauses that can be found in a 'dynamically loadable zones' statement
132 static cfg_clausedef_t
133 dynamically_loadable_zones_clauses[] = {
134 { "database", &cfg_type_astring, 0 },
135 { NULL, NULL, 0 }
139 * A dynamically loadable zones statement.
141 static cfg_tuplefielddef_t dynamically_loadable_zones_fields[] = {
142 { "name", &cfg_type_astring, 0 },
143 { "options", &cfg_type_dynamically_loadable_zones_opts, 0 },
144 { NULL, NULL, 0 }
147 static cfg_type_t cfg_type_dynamically_loadable_zones = {
148 "dlz", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
149 &cfg_rep_tuple,
150 dynamically_loadable_zones_fields
154 /*% tkey-dhkey */
156 static cfg_tuplefielddef_t tkey_dhkey_fields[] = {
157 { "name", &cfg_type_qstring, 0 },
158 { "keyid", &cfg_type_uint32, 0 },
159 { NULL, NULL, 0 }
162 static cfg_type_t cfg_type_tkey_dhkey = {
163 "tkey-dhkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
164 tkey_dhkey_fields
167 /*% listen-on */
169 static cfg_tuplefielddef_t listenon_fields[] = {
170 { "port", &cfg_type_optional_port, 0 },
171 { "acl", &cfg_type_bracketed_aml, 0 },
172 { NULL, NULL, 0 }
174 static cfg_type_t cfg_type_listenon = {
175 "listenon", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, listenon_fields };
177 /*% acl */
179 static cfg_tuplefielddef_t acl_fields[] = {
180 { "name", &cfg_type_astring, 0 },
181 { "value", &cfg_type_bracketed_aml, 0 },
182 { NULL, NULL, 0 }
185 static cfg_type_t cfg_type_acl = {
186 "acl", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, acl_fields };
188 /*% masters */
189 static cfg_tuplefielddef_t masters_fields[] = {
190 { "name", &cfg_type_astring, 0 },
191 { "port", &cfg_type_optional_port, 0 },
192 { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
193 { NULL, NULL, 0 }
196 static cfg_type_t cfg_type_masters = {
197 "masters", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, masters_fields };
200 * "sockaddrkeylist", a list of socket addresses with optional keys
201 * and an optional default port, as used in the masters option.
202 * E.g.,
203 * "port 1234 { mymasters; 10.0.0.1 key foo; 1::2 port 69; }"
206 static cfg_tuplefielddef_t namesockaddrkey_fields[] = {
207 { "masterselement", &cfg_type_masterselement, 0 },
208 { "key", &cfg_type_optional_keyref, 0 },
209 { NULL, NULL, 0 },
212 static cfg_type_t cfg_type_namesockaddrkey = {
213 "namesockaddrkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
214 namesockaddrkey_fields
217 static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = {
218 "bracketed_namesockaddrkeylist", cfg_parse_bracketed_list,
219 cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_namesockaddrkey
222 static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = {
223 { "port", &cfg_type_optional_port, 0 },
224 { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
225 { NULL, NULL, 0 }
227 static cfg_type_t cfg_type_namesockaddrkeylist = {
228 "sockaddrkeylist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
229 namesockaddrkeylist_fields
233 * A list of socket addresses with an optional default port,
234 * as used in the also-notify option. E.g.,
235 * "port 1234 { 10.0.0.1; 1::2 port 69; }"
237 static cfg_tuplefielddef_t portiplist_fields[] = {
238 { "port", &cfg_type_optional_port, 0 },
239 { "addresses", &cfg_type_bracketed_sockaddrlist, 0 },
240 { NULL, NULL, 0 }
242 static cfg_type_t cfg_type_portiplist = {
243 "portiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
244 portiplist_fields
248 * A public key, as in the "pubkey" statement.
250 static cfg_tuplefielddef_t pubkey_fields[] = {
251 { "flags", &cfg_type_uint32, 0 },
252 { "protocol", &cfg_type_uint32, 0 },
253 { "algorithm", &cfg_type_uint32, 0 },
254 { "key", &cfg_type_qstring, 0 },
255 { NULL, NULL, 0 }
257 static cfg_type_t cfg_type_pubkey = {
258 "pubkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
259 &cfg_rep_tuple, pubkey_fields };
262 * A list of RR types, used in grant statements.
263 * Note that the old parser allows quotes around the RR type names.
265 static cfg_type_t cfg_type_rrtypelist = {
266 "rrtypelist", cfg_parse_spacelist, cfg_print_spacelist,
267 cfg_doc_terminal, &cfg_rep_list, &cfg_type_astring
270 static const char *mode_enums[] = { "grant", "deny", NULL };
271 static cfg_type_t cfg_type_mode = {
272 "mode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
273 &cfg_rep_string, &mode_enums
276 static isc_result_t
277 parse_matchtype(cfg_parser_t *pctx, const cfg_type_t *type,
278 cfg_obj_t **ret) {
279 isc_result_t result;
281 CHECK(cfg_peektoken(pctx, 0));
282 if (pctx->token.type == isc_tokentype_string &&
283 strcasecmp(TOKEN_STRING(pctx), "zonesub") == 0) {
284 pctx->flags |= CFG_PCTX_SKIP;
286 return (cfg_parse_enum(pctx, type, ret));
288 cleanup:
289 return (result);
292 static isc_result_t
293 parse_matchname(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
294 isc_result_t result;
295 cfg_obj_t *obj = NULL;
297 if ((pctx->flags & CFG_PCTX_SKIP) != 0) {
298 pctx->flags &= ~CFG_PCTX_SKIP;
299 CHECK(cfg_parse_void(pctx, NULL, &obj));
300 } else
301 result = cfg_parse_astring(pctx, type, &obj);
303 *ret = obj;
304 cleanup:
305 return (result);
308 static void
309 doc_matchname(cfg_printer_t *pctx, const cfg_type_t *type) {
310 cfg_print_chars(pctx, "[ ", 2);
311 cfg_doc_obj(pctx, type->of);
312 cfg_print_chars(pctx, " ]", 2);
315 static const char *matchtype_enums[] = {
316 "name", "subdomain", "wildcard", "self", "selfsub", "selfwild",
317 "krb5-self", "ms-self", "krb5-subdomain", "ms-subdomain",
318 "tcp-self", "6to4-self", "zonesub", NULL };
320 static cfg_type_t cfg_type_matchtype = {
321 "matchtype", parse_matchtype, cfg_print_ustring,
322 cfg_doc_enum, &cfg_rep_string, &matchtype_enums
325 static cfg_type_t cfg_type_matchname = {
326 "optional_matchname", parse_matchname, cfg_print_ustring,
327 &doc_matchname, &cfg_rep_tuple, &cfg_type_ustring
331 * A grant statement, used in the update policy.
333 static cfg_tuplefielddef_t grant_fields[] = {
334 { "mode", &cfg_type_mode, 0 },
335 { "identity", &cfg_type_astring, 0 }, /* domain name */
336 { "matchtype", &cfg_type_matchtype, 0 },
337 { "name", &cfg_type_matchname, 0 }, /* domain name */
338 { "types", &cfg_type_rrtypelist, 0 },
339 { NULL, NULL, 0 }
341 static cfg_type_t cfg_type_grant = {
342 "grant", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
343 &cfg_rep_tuple, grant_fields
346 static cfg_type_t cfg_type_updatepolicy = {
347 "update_policy", parse_updatepolicy, NULL, doc_updatepolicy,
348 &cfg_rep_list, &cfg_type_grant
351 static isc_result_t
352 parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
353 cfg_obj_t **ret) {
354 isc_result_t result;
355 CHECK(cfg_gettoken(pctx, 0));
356 if (pctx->token.type == isc_tokentype_special &&
357 pctx->token.value.as_char == '{') {
358 cfg_ungettoken(pctx);
359 return (cfg_parse_bracketed_list(pctx, type, ret));
362 if (pctx->token.type == isc_tokentype_string &&
363 strcasecmp(TOKEN_STRING(pctx), "local") == 0) {
364 cfg_obj_t *obj = NULL;
365 CHECK(cfg_create_obj(pctx, &cfg_type_ustring, &obj));
366 obj->value.string.length = strlen("local");
367 obj->value.string.base = isc_mem_get(pctx->mctx,
368 obj->value.string.length + 1);
369 if (obj->value.string.base == NULL) {
370 isc_mem_put(pctx->mctx, obj, sizeof(*obj));
371 return (ISC_R_NOMEMORY);
373 memcpy(obj->value.string.base, "local", 5);
374 obj->value.string.base[5] = '\0';
375 *ret = obj;
376 return (ISC_R_SUCCESS);
379 cfg_ungettoken(pctx);
380 return (ISC_R_UNEXPECTEDTOKEN);
382 cleanup:
383 return (result);
386 static void
387 doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type) {
388 cfg_print_chars(pctx, "( local | { ", 12);
389 cfg_doc_obj(pctx, type->of);
390 cfg_print_chars(pctx, "; ... }", 7);
394 * A view statement.
396 static cfg_tuplefielddef_t view_fields[] = {
397 { "name", &cfg_type_astring, 0 },
398 { "class", &cfg_type_optional_class, 0 },
399 { "options", &cfg_type_viewopts, 0 },
400 { NULL, NULL, 0 }
402 static cfg_type_t cfg_type_view = {
403 "view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
404 &cfg_rep_tuple, view_fields
408 * A zone statement.
410 static cfg_tuplefielddef_t zone_fields[] = {
411 { "name", &cfg_type_astring, 0 },
412 { "class", &cfg_type_optional_class, 0 },
413 { "options", &cfg_type_zoneopts, 0 },
414 { NULL, NULL, 0 }
416 static cfg_type_t cfg_type_zone = {
417 "zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
418 &cfg_rep_tuple, zone_fields
422 * A "category" clause in the "logging" statement.
424 static cfg_tuplefielddef_t category_fields[] = {
425 { "name", &cfg_type_astring, 0 },
426 { "destinations", &cfg_type_destinationlist,0 },
427 { NULL, NULL, 0 }
429 static cfg_type_t cfg_type_category = {
430 "category", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
431 &cfg_rep_tuple, category_fields
436 * A dnssec key, as used in the "trusted-keys" statement.
438 static cfg_tuplefielddef_t dnsseckey_fields[] = {
439 { "name", &cfg_type_astring, 0 },
440 { "flags", &cfg_type_uint32, 0 },
441 { "protocol", &cfg_type_uint32, 0 },
442 { "algorithm", &cfg_type_uint32, 0 },
443 { "key", &cfg_type_qstring, 0 },
444 { NULL, NULL, 0 }
446 static cfg_type_t cfg_type_dnsseckey = {
447 "dnsseckey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
448 &cfg_rep_tuple, dnsseckey_fields
452 * A managed key initialization specifier, as used in the
453 * "managed-keys" statement.
455 static cfg_tuplefielddef_t managedkey_fields[] = {
456 { "name", &cfg_type_astring, 0 },
457 { "init", &cfg_type_ustring, 0 }, /* must be literal "initial-key" */
458 { "flags", &cfg_type_uint32, 0 },
459 { "protocol", &cfg_type_uint32, 0 },
460 { "algorithm", &cfg_type_uint32, 0 },
461 { "key", &cfg_type_qstring, 0 },
462 { NULL, NULL, 0 }
464 static cfg_type_t cfg_type_managedkey = {
465 "managedkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
466 &cfg_rep_tuple, managedkey_fields
469 static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring };
471 static cfg_type_t cfg_type_optional_wild_class = {
472 "optional_wild_class", parse_optional_keyvalue, print_keyvalue,
473 doc_optional_keyvalue, &cfg_rep_string, &wild_class_kw
476 static keyword_type_t wild_type_kw = { "type", &cfg_type_ustring };
478 static cfg_type_t cfg_type_optional_wild_type = {
479 "optional_wild_type", parse_optional_keyvalue,
480 print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_type_kw
483 static keyword_type_t wild_name_kw = { "name", &cfg_type_qstring };
485 static cfg_type_t cfg_type_optional_wild_name = {
486 "optional_wild_name", parse_optional_keyvalue,
487 print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_name_kw
491 * An rrset ordering element.
493 static cfg_tuplefielddef_t rrsetorderingelement_fields[] = {
494 { "class", &cfg_type_optional_wild_class, 0 },
495 { "type", &cfg_type_optional_wild_type, 0 },
496 { "name", &cfg_type_optional_wild_name, 0 },
497 { "order", &cfg_type_ustring, 0 }, /* must be literal "order" */
498 { "ordering", &cfg_type_ustring, 0 },
499 { NULL, NULL, 0 }
501 static cfg_type_t cfg_type_rrsetorderingelement = {
502 "rrsetorderingelement", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
503 rrsetorderingelement_fields
507 * A global or view "check-names" option. Note that the zone
508 * "check-names" option has a different syntax.
511 static const char *checktype_enums[] = { "master", "slave", "response", NULL };
512 static cfg_type_t cfg_type_checktype = {
513 "checktype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
514 &cfg_rep_string, &checktype_enums
517 static const char *checkmode_enums[] = { "fail", "warn", "ignore", NULL };
518 static cfg_type_t cfg_type_checkmode = {
519 "checkmode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
520 &cfg_rep_string, &checkmode_enums
523 static cfg_tuplefielddef_t checknames_fields[] = {
524 { "type", &cfg_type_checktype, 0 },
525 { "mode", &cfg_type_checkmode, 0 },
526 { NULL, NULL, 0 }
529 static cfg_type_t cfg_type_checknames = {
530 "checknames", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
531 checknames_fields
534 static cfg_type_t cfg_type_bracketed_sockaddrlist = {
535 "bracketed_sockaddrlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
536 &cfg_rep_list, &cfg_type_sockaddr
539 static const char *autodnssec_enums[] = { "allow", "maintain", "create",
540 "off", NULL };
541 static cfg_type_t cfg_type_autodnssec = {
542 "autodnssec", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
543 &cfg_rep_string, &autodnssec_enums
546 static cfg_type_t cfg_type_rrsetorder = {
547 "rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
548 &cfg_rep_list, &cfg_type_rrsetorderingelement
551 static keyword_type_t port_kw = { "port", &cfg_type_uint32 };
553 static cfg_type_t cfg_type_optional_port = {
554 "optional_port", parse_optional_keyvalue, print_keyvalue,
555 doc_optional_keyvalue, &cfg_rep_uint32, &port_kw
558 /*% A list of keys, as in the "key" clause of the controls statement. */
559 static cfg_type_t cfg_type_keylist = {
560 "keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
561 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring
564 /*% A list of dnssec keys, as in "trusted-keys" */
565 static cfg_type_t cfg_type_dnsseckeys = {
566 "dnsseckeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
567 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_dnsseckey
571 * A list of managed key entries, as in "trusted-keys". Currently
572 * (9.7.0) this has a format similar to dnssec keys, except the keyname
573 * is followed by the keyword "initial-key". In future releases, this
574 * keyword may take other values indicating different methods for the
575 * key to be initialized.
578 static cfg_type_t cfg_type_managedkeys = {
579 "managedkeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
580 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_managedkey
583 static const char *forwardtype_enums[] = { "first", "only", NULL };
584 static cfg_type_t cfg_type_forwardtype = {
585 "forwardtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
586 &forwardtype_enums
589 static const char *zonetype_enums[] = {
590 "master", "slave", "stub", "hint", "forward", "delegation-only", NULL };
591 static cfg_type_t cfg_type_zonetype = {
592 "zonetype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
593 &cfg_rep_string, &zonetype_enums
596 static const char *loglevel_enums[] = {
597 "critical", "error", "warning", "notice", "info", "dynamic", NULL };
598 static cfg_type_t cfg_type_loglevel = {
599 "loglevel", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
600 &loglevel_enums
603 static const char *transferformat_enums[] = {
604 "many-answers", "one-answer", NULL };
605 static cfg_type_t cfg_type_transferformat = {
606 "transferformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
607 &transferformat_enums
611 * The special keyword "none", as used in the pid-file option.
614 static void
615 print_none(cfg_printer_t *pctx, const cfg_obj_t *obj) {
616 UNUSED(obj);
617 cfg_print_chars(pctx, "none", 4);
620 static cfg_type_t cfg_type_none = {
621 "none", NULL, print_none, NULL, &cfg_rep_void, NULL
625 * A quoted string or the special keyword "none". Used in the pid-file option.
627 static isc_result_t
628 parse_qstringornone(cfg_parser_t *pctx, const cfg_type_t *type,
629 cfg_obj_t **ret)
631 isc_result_t result;
633 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
634 if (pctx->token.type == isc_tokentype_string &&
635 strcasecmp(TOKEN_STRING(pctx), "none") == 0)
636 return (cfg_create_obj(pctx, &cfg_type_none, ret));
637 cfg_ungettoken(pctx);
638 return (cfg_parse_qstring(pctx, type, ret));
639 cleanup:
640 return (result);
643 static void
644 doc_qstringornone(cfg_printer_t *pctx, const cfg_type_t *type) {
645 UNUSED(type);
646 cfg_print_chars(pctx, "( <quoted_string> | none )", 26);
649 static cfg_type_t cfg_type_qstringornone = {
650 "qstringornone", parse_qstringornone, NULL, doc_qstringornone,
651 NULL, NULL
655 * keyword hostname
658 static void
659 print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) {
660 UNUSED(obj);
661 cfg_print_chars(pctx, "hostname", 4);
664 static cfg_type_t cfg_type_hostname = {
665 "hostname", NULL, print_hostname, NULL, &cfg_rep_boolean, NULL
669 * "server-id" argument.
672 static isc_result_t
673 parse_serverid(cfg_parser_t *pctx, const cfg_type_t *type,
674 cfg_obj_t **ret)
676 isc_result_t result;
677 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
678 if (pctx->token.type == isc_tokentype_string &&
679 strcasecmp(TOKEN_STRING(pctx), "none") == 0)
680 return (cfg_create_obj(pctx, &cfg_type_none, ret));
681 if (pctx->token.type == isc_tokentype_string &&
682 strcasecmp(TOKEN_STRING(pctx), "hostname") == 0) {
683 return (cfg_create_obj(pctx, &cfg_type_hostname, ret));
685 cfg_ungettoken(pctx);
686 return (cfg_parse_qstring(pctx, type, ret));
687 cleanup:
688 return (result);
691 static void
692 doc_serverid(cfg_printer_t *pctx, const cfg_type_t *type) {
693 UNUSED(type);
694 cfg_print_chars(pctx, "( <quoted_string> | none | hostname )", 26);
697 static cfg_type_t cfg_type_serverid = {
698 "serverid", parse_serverid, NULL, doc_serverid, NULL, NULL };
701 * Port list.
703 static cfg_tuplefielddef_t porttuple_fields[] = {
704 { "loport", &cfg_type_uint32, 0 },
705 { "hiport", &cfg_type_uint32, 0 },
706 { NULL, NULL, 0 }
708 static cfg_type_t cfg_type_porttuple = {
709 "porttuple", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
710 &cfg_rep_tuple, porttuple_fields
713 static isc_result_t
714 parse_port(cfg_parser_t *pctx, cfg_obj_t **ret) {
715 isc_result_t result;
717 CHECK(cfg_parse_uint32(pctx, NULL, ret));
718 if ((*ret)->value.uint32 > 0xffff) {
719 cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid port");
720 cfg_obj_destroy(pctx, ret);
721 result = ISC_R_RANGE;
724 cleanup:
725 return (result);
728 static isc_result_t
729 parse_portrange(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
730 isc_result_t result;
731 cfg_obj_t *obj = NULL;
733 UNUSED(type);
735 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
736 if (pctx->token.type == isc_tokentype_number)
737 CHECK(parse_port(pctx, ret));
738 else {
739 CHECK(cfg_gettoken(pctx, 0));
740 if (pctx->token.type != isc_tokentype_string ||
741 strcasecmp(TOKEN_STRING(pctx), "range") != 0) {
742 cfg_parser_error(pctx, CFG_LOG_NEAR,
743 "expected integer or 'range'");
744 return (ISC_R_UNEXPECTEDTOKEN);
746 CHECK(cfg_create_tuple(pctx, &cfg_type_porttuple, &obj));
747 CHECK(parse_port(pctx, &obj->value.tuple[0]));
748 CHECK(parse_port(pctx, &obj->value.tuple[1]));
749 if (obj->value.tuple[0]->value.uint32 >
750 obj->value.tuple[1]->value.uint32) {
751 cfg_parser_error(pctx, CFG_LOG_NOPREP,
752 "low port '%u' must not be larger "
753 "than high port",
754 obj->value.tuple[0]->value.uint32);
755 result = ISC_R_RANGE;
756 goto cleanup;
758 *ret = obj;
759 obj = NULL;
762 cleanup:
763 if (obj != NULL)
764 cfg_obj_destroy(pctx, &obj);
765 return (result);
768 static cfg_type_t cfg_type_portrange = {
769 "portrange", parse_portrange, NULL, cfg_doc_terminal,
770 NULL, NULL
773 static cfg_type_t cfg_type_bracketed_portlist = {
774 "bracketed_sockaddrlist", cfg_parse_bracketed_list,
775 cfg_print_bracketed_list, cfg_doc_bracketed_list,
776 &cfg_rep_list, &cfg_type_portrange
780 * Clauses that can be found within the top level of the named.conf
781 * file only.
783 static cfg_clausedef_t
784 namedconf_clauses[] = {
785 { "options", &cfg_type_options, 0 },
786 { "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
787 { "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
788 { "masters", &cfg_type_masters, CFG_CLAUSEFLAG_MULTI },
789 { "logging", &cfg_type_logging, 0 },
790 { "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI },
791 { "lwres", &cfg_type_lwres, CFG_CLAUSEFLAG_MULTI },
792 { "statistics-channels", &cfg_type_statschannels,
793 CFG_CLAUSEFLAG_MULTI },
794 { NULL, NULL, 0 }
798 * Clauses that can occur at the top level or in the view
799 * statement, but not in the options block.
801 static cfg_clausedef_t
802 namedconf_or_view_clauses[] = {
803 { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
804 { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
805 /* only 1 DLZ per view allowed */
806 { "dlz", &cfg_type_dynamically_loadable_zones, 0 },
807 { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI },
808 { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
809 { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
810 { NULL, NULL, 0 }
814 * Clauses that can occur in the bind.keys file.
816 static cfg_clausedef_t
817 bindkeys_clauses[] = {
818 { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
819 { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
820 { NULL, NULL, 0 }
824 * Clauses that can be found within the 'options' statement.
826 static cfg_clausedef_t
827 options_clauses[] = {
828 { "use-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
829 { "use-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
830 { "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
831 { "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
832 { "bindkeys-file", &cfg_type_qstring, 0 },
833 { "blackhole", &cfg_type_bracketed_aml, 0 },
834 { "coresize", &cfg_type_size, 0 },
835 { "datasize", &cfg_type_size, 0 },
836 { "session-keyfile", &cfg_type_qstringornone, 0 },
837 { "session-keyname", &cfg_type_astring, 0 },
838 { "session-keyalg", &cfg_type_astring, 0 },
839 { "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
840 { "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK },
841 { "dump-file", &cfg_type_qstring, 0 },
842 { "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
843 { "files", &cfg_type_size, 0 },
844 { "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
845 { "heartbeat-interval", &cfg_type_uint32, 0 },
846 { "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP },
847 { "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
848 { "hostname", &cfg_type_qstringornone, 0 },
849 { "interface-interval", &cfg_type_uint32, 0 },
850 { "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
851 { "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
852 { "match-mapped-addresses", &cfg_type_boolean, 0 },
853 { "memstatistics-file", &cfg_type_qstring, 0 },
854 { "memstatistics", &cfg_type_boolean, 0 },
855 { "multiple-cnames", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
856 { "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
857 { "pid-file", &cfg_type_qstringornone, 0 },
858 { "port", &cfg_type_uint32, 0 },
859 { "querylog", &cfg_type_boolean, 0 },
860 { "recursing-file", &cfg_type_qstring, 0 },
861 { "random-device", &cfg_type_qstring, 0 },
862 { "recursive-clients", &cfg_type_uint32, 0 },
863 { "reserved-sockets", &cfg_type_uint32, 0 },
864 { "serial-queries", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
865 { "serial-query-rate", &cfg_type_uint32, 0 },
866 { "server-id", &cfg_type_serverid, 0 },
867 { "stacksize", &cfg_type_size, 0 },
868 { "statistics-file", &cfg_type_qstring, 0 },
869 { "statistics-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_NYI },
870 { "tcp-clients", &cfg_type_uint32, 0 },
871 { "tcp-listen-queue", &cfg_type_uint32, 0 },
872 { "tkey-dhkey", &cfg_type_tkey_dhkey, 0 },
873 { "tkey-gssapi-credential", &cfg_type_qstring, 0 },
874 { "tkey-domain", &cfg_type_qstring, 0 },
875 { "transfers-per-ns", &cfg_type_uint32, 0 },
876 { "transfers-in", &cfg_type_uint32, 0 },
877 { "transfers-out", &cfg_type_uint32, 0 },
878 { "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
879 { "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
880 { "use-ixfr", &cfg_type_boolean, 0 },
881 { "version", &cfg_type_qstringornone, 0 },
882 { "flush-zones-on-shutdown", &cfg_type_boolean, 0 },
883 { NULL, NULL, 0 }
887 static cfg_type_t cfg_type_namelist = {
888 "namelist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
889 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_qstring };
891 static keyword_type_t exclude_kw = { "exclude", &cfg_type_namelist };
893 static cfg_type_t cfg_type_optional_exclude = {
894 "optional_exclude", parse_optional_keyvalue, print_keyvalue,
895 doc_optional_keyvalue, &cfg_rep_list, &exclude_kw };
897 static keyword_type_t exceptionnames_kw = { "except-from", &cfg_type_namelist };
899 static cfg_type_t cfg_type_optional_exceptionnames = {
900 "optional_allow", parse_optional_keyvalue, print_keyvalue,
901 doc_optional_keyvalue, &cfg_rep_list, &exceptionnames_kw };
903 static cfg_tuplefielddef_t denyaddresses_fields[] = {
904 { "acl", &cfg_type_bracketed_aml, 0 },
905 { "except-from", &cfg_type_optional_exceptionnames, 0 },
906 { NULL, NULL, 0 }
909 static cfg_type_t cfg_type_denyaddresses = {
910 "denyaddresses", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
911 &cfg_rep_tuple, denyaddresses_fields
914 static cfg_tuplefielddef_t denyaliases_fields[] = {
915 { "name", &cfg_type_namelist, 0 },
916 { "except-from", &cfg_type_optional_exceptionnames, 0 },
917 { NULL, NULL, 0 }
920 static cfg_type_t cfg_type_denyaliases = {
921 "denyaliases", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
922 &cfg_rep_tuple, denyaliases_fields
925 static cfg_type_t cfg_type_algorithmlist = {
926 "algorithmlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
927 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring };
929 static cfg_tuplefielddef_t disablealgorithm_fields[] = {
930 { "name", &cfg_type_astring, 0 },
931 { "algorithms", &cfg_type_algorithmlist, 0 },
932 { NULL, NULL, 0 }
935 static cfg_type_t cfg_type_disablealgorithm = {
936 "disablealgorithm", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
937 &cfg_rep_tuple, disablealgorithm_fields
940 static cfg_tuplefielddef_t mustbesecure_fields[] = {
941 { "name", &cfg_type_astring, 0 },
942 { "value", &cfg_type_boolean, 0 },
943 { NULL, NULL, 0 }
946 static cfg_type_t cfg_type_mustbesecure = {
947 "mustbesecure", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
948 &cfg_rep_tuple, mustbesecure_fields
951 static const char *masterformat_enums[] = { "text", "raw", NULL };
952 static cfg_type_t cfg_type_masterformat = {
953 "masterformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
954 &cfg_rep_string, &masterformat_enums
958 * dnssec-lookaside
961 static keyword_type_t trustanchor_kw = { "trust-anchor", &cfg_type_astring };
963 static cfg_type_t cfg_type_optional_trustanchor = {
964 "optional_trustanchor", parse_optional_keyvalue, print_keyvalue,
965 doc_keyvalue, &cfg_rep_string, &trustanchor_kw
968 static cfg_tuplefielddef_t lookaside_fields[] = {
969 { "domain", &cfg_type_astring, 0 },
970 { "trust-anchor", &cfg_type_optional_trustanchor, 0 },
971 { NULL, NULL, 0 }
974 static cfg_type_t cfg_type_lookaside = {
975 "lookaside", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
976 &cfg_rep_tuple, lookaside_fields
980 * Clauses that can be found within the 'view' statement,
981 * with defaults in the 'options' statement.
984 static cfg_clausedef_t
985 view_clauses[] = {
986 { "acache-cleaning-interval", &cfg_type_uint32, 0 },
987 { "acache-enable", &cfg_type_boolean, 0 },
988 { "additional-from-auth", &cfg_type_boolean, 0 },
989 { "additional-from-cache", &cfg_type_boolean, 0 },
990 { "allow-query-cache", &cfg_type_bracketed_aml, 0 },
991 { "allow-query-cache-on", &cfg_type_bracketed_aml, 0 },
992 { "allow-recursion", &cfg_type_bracketed_aml, 0 },
993 { "allow-recursion-on", &cfg_type_bracketed_aml, 0 },
994 { "allow-v6-synthesis", &cfg_type_bracketed_aml,
995 CFG_CLAUSEFLAG_OBSOLETE },
996 { "attach-cache", &cfg_type_astring, 0 },
997 { "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT },
998 { "cache-file", &cfg_type_qstring, 0 },
999 { "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
1000 { "cleaning-interval", &cfg_type_uint32, 0 },
1001 { "clients-per-query", &cfg_type_uint32, 0 },
1002 { "deny-answer-addresses", &cfg_type_denyaddresses, 0 },
1003 { "deny-answer-aliases", &cfg_type_denyaliases, 0 },
1004 { "disable-algorithms", &cfg_type_disablealgorithm,
1005 CFG_CLAUSEFLAG_MULTI },
1006 { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI },
1007 { "dnssec-accept-expired", &cfg_type_boolean, 0 },
1008 { "dnssec-enable", &cfg_type_boolean, 0 },
1009 { "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI },
1010 { "dnssec-must-be-secure", &cfg_type_mustbesecure,
1011 CFG_CLAUSEFLAG_MULTI },
1012 { "dnssec-validation", &cfg_type_boolean, 0 },
1013 { "dual-stack-servers", &cfg_type_nameportiplist, 0 },
1014 { "edns-udp-size", &cfg_type_uint32, 0 },
1015 { "empty-contact", &cfg_type_astring, 0 },
1016 { "empty-server", &cfg_type_astring, 0 },
1017 { "empty-zones-enable", &cfg_type_boolean, 0 },
1018 { "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1019 { "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 },
1020 { "lame-ttl", &cfg_type_uint32, 0 },
1021 { "max-acache-size", &cfg_type_sizenodefault, 0 },
1022 { "max-cache-size", &cfg_type_sizenodefault, 0 },
1023 { "max-cache-ttl", &cfg_type_uint32, 0 },
1024 { "max-clients-per-query", &cfg_type_uint32, 0 },
1025 { "max-ncache-ttl", &cfg_type_uint32, 0 },
1026 { "max-udp-size", &cfg_type_uint32, 0 },
1027 { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
1028 { "minimal-responses", &cfg_type_boolean, 0 },
1029 { "preferred-glue", &cfg_type_astring, 0 },
1030 { "provide-ixfr", &cfg_type_boolean, 0 },
1032 * Note that the query-source option syntax is different
1033 * from the other -source options.
1035 { "query-source", &cfg_type_querysource4, 0 },
1036 { "query-source-v6", &cfg_type_querysource6, 0 },
1037 { "queryport-pool-ports", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
1038 { "queryport-pool-updateinterval", &cfg_type_uint32,
1039 CFG_CLAUSEFLAG_OBSOLETE },
1040 { "recursion", &cfg_type_boolean, 0 },
1041 { "request-ixfr", &cfg_type_boolean, 0 },
1042 { "request-nsid", &cfg_type_boolean, 0 },
1043 { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
1044 { "root-delegation-only", &cfg_type_optional_exclude, 0 },
1045 { "rrset-order", &cfg_type_rrsetorder, 0 },
1046 { "sortlist", &cfg_type_bracketed_aml, 0 },
1047 { "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
1048 { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP },
1049 { "transfer-format", &cfg_type_transferformat, 0 },
1050 { "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1051 { "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
1052 #ifdef ALLOW_FILTER_AAAA_ON_V4
1053 { "filter-aaaa-on-v4", &cfg_type_v4_aaaa, 0 },
1054 #endif
1055 { NULL, NULL, 0 }
1059 * Clauses that can be found within the 'view' statement only.
1061 static cfg_clausedef_t
1062 view_only_clauses[] = {
1063 { "match-clients", &cfg_type_bracketed_aml, 0 },
1064 { "match-destinations", &cfg_type_bracketed_aml, 0 },
1065 { "match-recursive-only", &cfg_type_boolean, 0 },
1066 { NULL, NULL, 0 }
1070 * Sig-validity-interval.
1072 static isc_result_t
1073 parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type,
1074 cfg_obj_t **ret)
1076 isc_result_t result;
1077 UNUSED(type);
1079 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
1080 if (pctx->token.type == isc_tokentype_number) {
1081 CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret));
1082 } else {
1083 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
1085 cleanup:
1086 return (result);
1089 static void
1090 doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) {
1091 UNUSED(type);
1092 cfg_print_chars(pctx, "[ <integer> ]", 13);
1095 static cfg_type_t cfg_type_optional_uint32 = {
1096 "optional_uint32", parse_optional_uint32, NULL, doc_optional_uint32,
1097 NULL, NULL };
1099 static cfg_tuplefielddef_t validityinterval_fields[] = {
1100 { "validity", &cfg_type_uint32, 0 },
1101 { "re-sign", &cfg_type_optional_uint32, 0 },
1102 { NULL, NULL, 0 }
1105 static cfg_type_t cfg_type_validityinterval = {
1106 "validityinterval", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
1107 &cfg_rep_tuple, validityinterval_fields
1111 * Clauses that can be found in a 'zone' statement,
1112 * with defaults in the 'view' or 'options' statement.
1114 static cfg_clausedef_t
1115 zone_clauses[] = {
1116 { "allow-notify", &cfg_type_bracketed_aml, 0 },
1117 { "allow-query", &cfg_type_bracketed_aml, 0 },
1118 { "allow-query-on", &cfg_type_bracketed_aml, 0 },
1119 { "allow-transfer", &cfg_type_bracketed_aml, 0 },
1120 { "allow-update", &cfg_type_bracketed_aml, 0 },
1121 { "allow-update-forwarding", &cfg_type_bracketed_aml, 0 },
1122 { "also-notify", &cfg_type_portiplist, 0 },
1123 { "alt-transfer-source", &cfg_type_sockaddr4wild, 0 },
1124 { "alt-transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
1125 { "check-dup-records", &cfg_type_checkmode, 0 },
1126 { "check-integrity", &cfg_type_boolean, 0 },
1127 { "check-mx", &cfg_type_checkmode, 0 },
1128 { "check-mx-cname", &cfg_type_checkmode, 0 },
1129 { "check-sibling", &cfg_type_boolean, 0 },
1130 { "check-srv-cname", &cfg_type_checkmode, 0 },
1131 { "check-wildcard", &cfg_type_boolean, 0 },
1132 { "dialup", &cfg_type_dialuptype, 0 },
1133 { "dnssec-dnskey-kskonly", &cfg_type_boolean, 0 },
1134 { "dnssec-secure-to-insecure", &cfg_type_boolean, 0 },
1135 { "forward", &cfg_type_forwardtype, 0 },
1136 { "forwarders", &cfg_type_portiplist, 0 },
1137 { "key-directory", &cfg_type_qstring, 0 },
1138 { "maintain-ixfr-base", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1139 { "masterfile-format", &cfg_type_masterformat, 0 },
1140 { "max-ixfr-log-size", &cfg_type_size, CFG_CLAUSEFLAG_OBSOLETE },
1141 { "max-journal-size", &cfg_type_sizenodefault, 0 },
1142 { "max-refresh-time", &cfg_type_uint32, 0 },
1143 { "max-retry-time", &cfg_type_uint32, 0 },
1144 { "max-transfer-idle-in", &cfg_type_uint32, 0 },
1145 { "max-transfer-idle-out", &cfg_type_uint32, 0 },
1146 { "max-transfer-time-in", &cfg_type_uint32, 0 },
1147 { "max-transfer-time-out", &cfg_type_uint32, 0 },
1148 { "min-refresh-time", &cfg_type_uint32, 0 },
1149 { "min-retry-time", &cfg_type_uint32, 0 },
1150 { "multi-master", &cfg_type_boolean, 0 },
1151 { "notify", &cfg_type_notifytype, 0 },
1152 { "notify-delay", &cfg_type_uint32, 0 },
1153 { "notify-source", &cfg_type_sockaddr4wild, 0 },
1154 { "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
1155 { "notify-to-soa", &cfg_type_boolean, 0 },
1156 { "nsec3-test-zone", &cfg_type_boolean, CFG_CLAUSEFLAG_TESTONLY },
1157 { "sig-signing-nodes", &cfg_type_uint32, 0 },
1158 { "sig-signing-signatures", &cfg_type_uint32, 0 },
1159 { "sig-signing-type", &cfg_type_uint32, 0 },
1160 { "sig-validity-interval", &cfg_type_validityinterval, 0 },
1161 { "transfer-source", &cfg_type_sockaddr4wild, 0 },
1162 { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
1163 { "try-tcp-refresh", &cfg_type_boolean, 0 },
1164 { "update-check-ksk", &cfg_type_boolean, 0 },
1165 { "use-alt-transfer-source", &cfg_type_boolean, 0 },
1166 { "zero-no-soa-ttl", &cfg_type_boolean, 0 },
1167 { "zone-statistics", &cfg_type_boolean, 0 },
1168 { NULL, NULL, 0 }
1172 * Clauses that can be found in a 'zone' statement
1173 * only.
1175 static cfg_clausedef_t
1176 zone_only_clauses[] = {
1177 { "type", &cfg_type_zonetype, 0 },
1178 { "file", &cfg_type_qstring, 0 },
1179 { "journal", &cfg_type_qstring, 0 },
1180 { "ixfr-base", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
1181 { "ixfr-tmp-file", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
1182 { "masters", &cfg_type_namesockaddrkeylist, 0 },
1183 { "pubkey", &cfg_type_pubkey,
1184 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE },
1185 { "update-policy", &cfg_type_updatepolicy, 0 },
1186 { "database", &cfg_type_astring, 0 },
1187 { "delegation-only", &cfg_type_boolean, 0 },
1189 * Note that the format of the check-names option is different between
1190 * the zone options and the global/view options. Ugh.
1192 { "check-names", &cfg_type_checkmode, 0 },
1193 { "ixfr-from-differences", &cfg_type_boolean, 0 },
1194 { "auto-dnssec", &cfg_type_autodnssec, 0 },
1195 { NULL, NULL, 0 }
1199 /*% The top-level named.conf syntax. */
1201 static cfg_clausedef_t *
1202 namedconf_clausesets[] = {
1203 namedconf_clauses,
1204 namedconf_or_view_clauses,
1205 NULL
1207 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = {
1208 "namedconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
1209 &cfg_rep_map, namedconf_clausesets
1212 /*% The bind.keys syntax (trusted-keys/managed-keys only). */
1213 static cfg_clausedef_t *
1214 bindkeys_clausesets[] = {
1215 bindkeys_clauses,
1216 NULL
1218 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bindkeys = {
1219 "bindkeys", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
1220 &cfg_rep_map, bindkeys_clausesets
1223 /*% The "options" statement syntax. */
1225 static cfg_clausedef_t *
1226 options_clausesets[] = {
1227 options_clauses,
1228 view_clauses,
1229 zone_clauses,
1230 NULL
1232 static cfg_type_t cfg_type_options = {
1233 "options", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, options_clausesets };
1235 /*% The "view" statement syntax. */
1237 static cfg_clausedef_t *
1238 view_clausesets[] = {
1239 view_only_clauses,
1240 namedconf_or_view_clauses,
1241 view_clauses,
1242 zone_clauses,
1243 dynamically_loadable_zones_clauses,
1244 NULL
1246 static cfg_type_t cfg_type_viewopts = {
1247 "view", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, view_clausesets };
1249 /*% The "zone" statement syntax. */
1251 static cfg_clausedef_t *
1252 zone_clausesets[] = {
1253 zone_only_clauses,
1254 zone_clauses,
1255 NULL
1257 static cfg_type_t cfg_type_zoneopts = {
1258 "zoneopts", cfg_parse_map, cfg_print_map,
1259 cfg_doc_map, &cfg_rep_map, zone_clausesets };
1261 /*% The "dynamically loadable zones" statement syntax. */
1263 static cfg_clausedef_t *
1264 dynamically_loadable_zones_clausesets[] = {
1265 dynamically_loadable_zones_clauses,
1266 NULL
1268 static cfg_type_t cfg_type_dynamically_loadable_zones_opts = {
1269 "dynamically_loadable_zones_opts", cfg_parse_map,
1270 cfg_print_map, cfg_doc_map, &cfg_rep_map,
1271 dynamically_loadable_zones_clausesets
1275 * Clauses that can be found within the 'key' statement.
1277 static cfg_clausedef_t
1278 key_clauses[] = {
1279 { "algorithm", &cfg_type_astring, 0 },
1280 { "secret", &cfg_type_astring, 0 },
1281 { NULL, NULL, 0 }
1284 static cfg_clausedef_t *
1285 key_clausesets[] = {
1286 key_clauses,
1287 NULL
1289 static cfg_type_t cfg_type_key = {
1290 "key", cfg_parse_named_map, cfg_print_map,
1291 cfg_doc_map, &cfg_rep_map, key_clausesets
1296 * Clauses that can be found in a 'server' statement.
1298 static cfg_clausedef_t
1299 server_clauses[] = {
1300 { "bogus", &cfg_type_boolean, 0 },
1301 { "provide-ixfr", &cfg_type_boolean, 0 },
1302 { "request-ixfr", &cfg_type_boolean, 0 },
1303 { "support-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
1304 { "transfers", &cfg_type_uint32, 0 },
1305 { "transfer-format", &cfg_type_transferformat, 0 },
1306 { "keys", &cfg_type_server_key_kludge, 0 },
1307 { "edns", &cfg_type_boolean, 0 },
1308 { "edns-udp-size", &cfg_type_uint32, 0 },
1309 { "max-udp-size", &cfg_type_uint32, 0 },
1310 { "notify-source", &cfg_type_sockaddr4wild, 0 },
1311 { "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
1312 { "query-source", &cfg_type_querysource4, 0 },
1313 { "query-source-v6", &cfg_type_querysource6, 0 },
1314 { "transfer-source", &cfg_type_sockaddr4wild, 0 },
1315 { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
1316 { NULL, NULL, 0 }
1318 static cfg_clausedef_t *
1319 server_clausesets[] = {
1320 server_clauses,
1321 NULL
1323 static cfg_type_t cfg_type_server = {
1324 "server", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
1325 server_clausesets
1330 * Clauses that can be found in a 'channel' clause in the
1331 * 'logging' statement.
1333 * These have some additional constraints that need to be
1334 * checked after parsing:
1335 * - There must exactly one of file/syslog/null/stderr
1338 static cfg_clausedef_t
1339 channel_clauses[] = {
1340 /* Destinations. We no longer require these to be first. */
1341 { "file", &cfg_type_logfile, 0 },
1342 { "syslog", &cfg_type_optional_facility, 0 },
1343 { "null", &cfg_type_void, 0 },
1344 { "stderr", &cfg_type_void, 0 },
1345 /* Options. We now accept these for the null channel, too. */
1346 { "severity", &cfg_type_logseverity, 0 },
1347 { "print-time", &cfg_type_boolean, 0 },
1348 { "print-severity", &cfg_type_boolean, 0 },
1349 { "print-category", &cfg_type_boolean, 0 },
1350 { NULL, NULL, 0 }
1352 static cfg_clausedef_t *
1353 channel_clausesets[] = {
1354 channel_clauses,
1355 NULL
1357 static cfg_type_t cfg_type_channel = {
1358 "channel", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
1359 &cfg_rep_map, channel_clausesets
1362 /*% A list of log destination, used in the "category" clause. */
1363 static cfg_type_t cfg_type_destinationlist = {
1364 "destinationlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
1365 &cfg_rep_list, &cfg_type_astring };
1368 * Clauses that can be found in a 'logging' statement.
1370 static cfg_clausedef_t
1371 logging_clauses[] = {
1372 { "channel", &cfg_type_channel, CFG_CLAUSEFLAG_MULTI },
1373 { "category", &cfg_type_category, CFG_CLAUSEFLAG_MULTI },
1374 { NULL, NULL, 0 }
1376 static cfg_clausedef_t *
1377 logging_clausesets[] = {
1378 logging_clauses,
1379 NULL
1381 static cfg_type_t cfg_type_logging = {
1382 "logging", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, logging_clausesets };
1385 static isc_result_t
1386 parse_unitstring(char *str, isc_resourcevalue_t *valuep) {
1387 char *endp;
1388 unsigned int len;
1389 isc_uint64_t value;
1390 isc_uint64_t unit;
1392 value = isc_string_touint64(str, &endp, 10);
1393 if (*endp == 0) {
1394 *valuep = value;
1395 return (ISC_R_SUCCESS);
1398 len = strlen(str);
1399 if (len < 2 || endp[1] != '\0')
1400 return (ISC_R_FAILURE);
1402 switch (str[len - 1]) {
1403 case 'k':
1404 case 'K':
1405 unit = 1024;
1406 break;
1407 case 'm':
1408 case 'M':
1409 unit = 1024 * 1024;
1410 break;
1411 case 'g':
1412 case 'G':
1413 unit = 1024 * 1024 * 1024;
1414 break;
1415 default:
1416 return (ISC_R_FAILURE);
1418 if (value > ISC_UINT64_MAX / unit)
1419 return (ISC_R_FAILURE);
1420 *valuep = value * unit;
1421 return (ISC_R_SUCCESS);
1424 static isc_result_t
1425 parse_sizeval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1426 isc_result_t result;
1427 cfg_obj_t *obj = NULL;
1428 isc_uint64_t val;
1430 UNUSED(type);
1432 CHECK(cfg_gettoken(pctx, 0));
1433 if (pctx->token.type != isc_tokentype_string) {
1434 result = ISC_R_UNEXPECTEDTOKEN;
1435 goto cleanup;
1437 CHECK(parse_unitstring(TOKEN_STRING(pctx), &val));
1439 CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj));
1440 obj->value.uint64 = val;
1441 *ret = obj;
1442 return (ISC_R_SUCCESS);
1444 cleanup:
1445 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected integer and optional unit");
1446 return (result);
1450 * A size value (number + optional unit).
1452 static cfg_type_t cfg_type_sizeval = {
1453 "sizeval", parse_sizeval, cfg_print_uint64, cfg_doc_terminal,
1454 &cfg_rep_uint64, NULL };
1457 * A size, "unlimited", or "default".
1460 static isc_result_t
1461 parse_size(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1462 return (parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret));
1465 static const char *size_enums[] = { "unlimited", "default", NULL };
1466 static cfg_type_t cfg_type_size = {
1467 "size", parse_size, cfg_print_ustring, cfg_doc_terminal,
1468 &cfg_rep_string, size_enums
1472 * A size or "unlimited", but not "default".
1474 static const char *sizenodefault_enums[] = { "unlimited", NULL };
1475 static cfg_type_t cfg_type_sizenodefault = {
1476 "size_no_default", parse_size, cfg_print_ustring, cfg_doc_terminal,
1477 &cfg_rep_string, sizenodefault_enums
1481 * optional_keyvalue
1483 static isc_result_t
1484 parse_maybe_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
1485 isc_boolean_t optional, cfg_obj_t **ret)
1487 isc_result_t result;
1488 cfg_obj_t *obj = NULL;
1489 const keyword_type_t *kw = type->of;
1491 CHECK(cfg_peektoken(pctx, 0));
1492 if (pctx->token.type == isc_tokentype_string &&
1493 strcasecmp(TOKEN_STRING(pctx), kw->name) == 0) {
1494 CHECK(cfg_gettoken(pctx, 0));
1495 CHECK(kw->type->parse(pctx, kw->type, &obj));
1496 obj->type = type; /* XXX kludge */
1497 } else {
1498 if (optional) {
1499 CHECK(cfg_parse_void(pctx, NULL, &obj));
1500 } else {
1501 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected '%s'",
1502 kw->name);
1503 result = ISC_R_UNEXPECTEDTOKEN;
1504 goto cleanup;
1507 *ret = obj;
1508 cleanup:
1509 return (result);
1512 static isc_result_t
1513 parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
1514 const cfg_type_t *othertype, cfg_obj_t **ret)
1516 isc_result_t result;
1517 CHECK(cfg_peektoken(pctx, 0));
1518 if (pctx->token.type == isc_tokentype_string &&
1519 cfg_is_enum(TOKEN_STRING(pctx), enumtype->of)) {
1520 CHECK(cfg_parse_enum(pctx, enumtype, ret));
1521 } else {
1522 CHECK(cfg_parse_obj(pctx, othertype, ret));
1524 cleanup:
1525 return (result);
1528 static void
1529 doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *type) {
1530 cfg_doc_terminal(pctx, type);
1531 #if 0 /* XXX */
1532 cfg_print_chars(pctx, "( ", 2);...
1533 #endif
1537 static isc_result_t
1538 parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1539 return (parse_maybe_optional_keyvalue(pctx, type, ISC_FALSE, ret));
1542 static isc_result_t
1543 parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1544 return (parse_maybe_optional_keyvalue(pctx, type, ISC_TRUE, ret));
1547 static void
1548 print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1549 const keyword_type_t *kw = obj->type->of;
1550 cfg_print_cstr(pctx, kw->name);
1551 cfg_print_chars(pctx, " ", 1);
1552 kw->type->print(pctx, obj);
1555 static void
1556 doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
1557 const keyword_type_t *kw = type->of;
1558 cfg_print_cstr(pctx, kw->name);
1559 cfg_print_chars(pctx, " ", 1);
1560 cfg_doc_obj(pctx, kw->type);
1563 static void
1564 doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
1565 const keyword_type_t *kw = type->of;
1566 cfg_print_chars(pctx, "[ ", 2);
1567 cfg_print_cstr(pctx, kw->name);
1568 cfg_print_chars(pctx, " ", 1);
1569 cfg_doc_obj(pctx, kw->type);
1570 cfg_print_chars(pctx, " ]", 2);
1573 static const char *dialup_enums[] = {
1574 "notify", "notify-passive", "refresh", "passive", NULL };
1575 static isc_result_t
1576 parse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1577 return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
1579 static cfg_type_t cfg_type_dialuptype = {
1580 "dialuptype", parse_dialup_type, cfg_print_ustring, doc_enum_or_other,
1581 &cfg_rep_string, dialup_enums
1584 static const char *notify_enums[] = { "explicit", "master-only", NULL };
1585 static isc_result_t
1586 parse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1587 return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
1589 static cfg_type_t cfg_type_notifytype = {
1590 "notifytype", parse_notify_type, cfg_print_ustring, doc_enum_or_other,
1591 &cfg_rep_string, notify_enums,
1594 static const char *ixfrdiff_enums[] = { "master", "slave", NULL };
1595 static isc_result_t
1596 parse_ixfrdiff_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1597 return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
1599 static cfg_type_t cfg_type_ixfrdifftype = {
1600 "ixfrdiff", parse_ixfrdiff_type, cfg_print_ustring, doc_enum_or_other,
1601 &cfg_rep_string, ixfrdiff_enums,
1604 #ifdef ALLOW_FILTER_AAAA_ON_V4
1605 static const char *v4_aaaa_enums[] = { "break-dnssec", NULL };
1606 static isc_result_t
1607 parse_v4_aaaa(cfg_parser_t *pctx, const cfg_type_t *type,
1608 cfg_obj_t **ret) {
1609 return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
1611 static cfg_type_t cfg_type_v4_aaaa = {
1612 "v4_aaaa", parse_v4_aaaa, cfg_print_ustring,
1613 doc_enum_or_other, &cfg_rep_string, v4_aaaa_enums,
1616 #endif
1617 static keyword_type_t key_kw = { "key", &cfg_type_astring };
1619 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = {
1620 "keyref", parse_keyvalue, print_keyvalue, doc_keyvalue,
1621 &cfg_rep_string, &key_kw
1624 static cfg_type_t cfg_type_optional_keyref = {
1625 "optional_keyref", parse_optional_keyvalue, print_keyvalue,
1626 doc_optional_keyvalue, &cfg_rep_string, &key_kw
1630 * A "controls" statement is represented as a map with the multivalued
1631 * "inet" and "unix" clauses.
1634 static keyword_type_t controls_allow_kw = {
1635 "allow", &cfg_type_bracketed_aml };
1637 static cfg_type_t cfg_type_controls_allow = {
1638 "controls_allow", parse_keyvalue,
1639 print_keyvalue, doc_keyvalue,
1640 &cfg_rep_list, &controls_allow_kw
1643 static keyword_type_t controls_keys_kw = {
1644 "keys", &cfg_type_keylist };
1646 static cfg_type_t cfg_type_controls_keys = {
1647 "controls_keys", parse_optional_keyvalue,
1648 print_keyvalue, doc_optional_keyvalue,
1649 &cfg_rep_list, &controls_keys_kw
1652 static cfg_tuplefielddef_t inetcontrol_fields[] = {
1653 { "address", &cfg_type_controls_sockaddr, 0 },
1654 { "allow", &cfg_type_controls_allow, 0 },
1655 { "keys", &cfg_type_controls_keys, 0 },
1656 { NULL, NULL, 0 }
1659 static cfg_type_t cfg_type_inetcontrol = {
1660 "inetcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
1661 inetcontrol_fields
1664 static keyword_type_t controls_perm_kw = {
1665 "perm", &cfg_type_uint32 };
1667 static cfg_type_t cfg_type_controls_perm = {
1668 "controls_perm", parse_keyvalue,
1669 print_keyvalue, doc_keyvalue,
1670 &cfg_rep_uint32, &controls_perm_kw
1673 static keyword_type_t controls_owner_kw = {
1674 "owner", &cfg_type_uint32 };
1676 static cfg_type_t cfg_type_controls_owner = {
1677 "controls_owner", parse_keyvalue,
1678 print_keyvalue, doc_keyvalue,
1679 &cfg_rep_uint32, &controls_owner_kw
1682 static keyword_type_t controls_group_kw = {
1683 "group", &cfg_type_uint32 };
1685 static cfg_type_t cfg_type_controls_group = {
1686 "controls_allow", parse_keyvalue,
1687 print_keyvalue, doc_keyvalue,
1688 &cfg_rep_uint32, &controls_group_kw
1691 static cfg_tuplefielddef_t unixcontrol_fields[] = {
1692 { "path", &cfg_type_qstring, 0 },
1693 { "perm", &cfg_type_controls_perm, 0 },
1694 { "owner", &cfg_type_controls_owner, 0 },
1695 { "group", &cfg_type_controls_group, 0 },
1696 { "keys", &cfg_type_controls_keys, 0 },
1697 { NULL, NULL, 0 }
1700 static cfg_type_t cfg_type_unixcontrol = {
1701 "unixcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
1702 unixcontrol_fields
1705 static cfg_clausedef_t
1706 controls_clauses[] = {
1707 { "inet", &cfg_type_inetcontrol, CFG_CLAUSEFLAG_MULTI },
1708 { "unix", &cfg_type_unixcontrol, CFG_CLAUSEFLAG_MULTI },
1709 { NULL, NULL, 0 }
1712 static cfg_clausedef_t *
1713 controls_clausesets[] = {
1714 controls_clauses,
1715 NULL
1717 static cfg_type_t cfg_type_controls = {
1718 "controls", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, &controls_clausesets
1722 * A "statistics-channels" statement is represented as a map with the
1723 * multivalued "inet" clauses.
1725 static void
1726 doc_optional_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
1727 const keyword_type_t *kw = type->of;
1728 cfg_print_chars(pctx, "[ ", 2);
1729 cfg_print_cstr(pctx, kw->name);
1730 cfg_print_chars(pctx, " ", 1);
1731 cfg_doc_obj(pctx, kw->type);
1732 cfg_print_chars(pctx, " ]", 2);
1735 static cfg_type_t cfg_type_optional_allow = {
1736 "optional_allow", parse_optional_keyvalue, print_keyvalue,
1737 doc_optional_bracketed_list, &cfg_rep_list, &controls_allow_kw
1740 static cfg_tuplefielddef_t statserver_fields[] = {
1741 { "address", &cfg_type_controls_sockaddr, 0 }, /* reuse controls def */
1742 { "allow", &cfg_type_optional_allow, 0 },
1743 { NULL, NULL, 0 }
1746 static cfg_type_t cfg_type_statschannel = {
1747 "statschannel", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
1748 &cfg_rep_tuple, statserver_fields
1751 static cfg_clausedef_t
1752 statservers_clauses[] = {
1753 { "inet", &cfg_type_statschannel, CFG_CLAUSEFLAG_MULTI },
1754 { NULL, NULL, 0 }
1757 static cfg_clausedef_t *
1758 statservers_clausesets[] = {
1759 statservers_clauses,
1760 NULL
1763 static cfg_type_t cfg_type_statschannels = {
1764 "statistics-channels", cfg_parse_map, cfg_print_map, cfg_doc_map,
1765 &cfg_rep_map, &statservers_clausesets
1769 * An optional class, as used in view and zone statements.
1771 static isc_result_t
1772 parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1773 isc_result_t result;
1774 UNUSED(type);
1775 CHECK(cfg_peektoken(pctx, 0));
1776 if (pctx->token.type == isc_tokentype_string)
1777 CHECK(cfg_parse_obj(pctx, &cfg_type_ustring, ret));
1778 else
1779 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
1780 cleanup:
1781 return (result);
1784 static cfg_type_t cfg_type_optional_class = {
1785 "optional_class", parse_optional_class, NULL, cfg_doc_terminal,
1786 NULL, NULL
1789 static isc_result_t
1790 parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1791 isc_result_t result;
1792 cfg_obj_t *obj = NULL;
1793 isc_netaddr_t netaddr;
1794 in_port_t port;
1795 unsigned int have_address = 0;
1796 unsigned int have_port = 0;
1797 const unsigned int *flagp = type->of;
1799 if ((*flagp & CFG_ADDR_V4OK) != 0)
1800 isc_netaddr_any(&netaddr);
1801 else if ((*flagp & CFG_ADDR_V6OK) != 0)
1802 isc_netaddr_any6(&netaddr);
1803 else
1804 INSIST(0);
1806 port = 0;
1808 for (;;) {
1809 CHECK(cfg_peektoken(pctx, 0));
1810 if (pctx->token.type == isc_tokentype_string) {
1811 if (strcasecmp(TOKEN_STRING(pctx),
1812 "address") == 0)
1814 /* read "address" */
1815 CHECK(cfg_gettoken(pctx, 0));
1816 CHECK(cfg_parse_rawaddr(pctx, *flagp,
1817 &netaddr));
1818 have_address++;
1819 } else if (strcasecmp(TOKEN_STRING(pctx), "port") == 0)
1821 /* read "port" */
1822 CHECK(cfg_gettoken(pctx, 0));
1823 CHECK(cfg_parse_rawport(pctx,
1824 CFG_ADDR_WILDOK,
1825 &port));
1826 have_port++;
1827 } else if (have_port == 0 && have_address == 0) {
1828 return (cfg_parse_sockaddr(pctx, type, ret));
1829 } else {
1830 cfg_parser_error(pctx, CFG_LOG_NEAR,
1831 "expected 'address' or 'port'");
1832 return (ISC_R_UNEXPECTEDTOKEN);
1834 } else
1835 break;
1837 if (have_address > 1 || have_port > 1 ||
1838 have_address + have_port == 0) {
1839 cfg_parser_error(pctx, 0, "expected one address and/or port");
1840 return (ISC_R_UNEXPECTEDTOKEN);
1843 CHECK(cfg_create_obj(pctx, &cfg_type_querysource, &obj));
1844 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
1845 *ret = obj;
1846 return (ISC_R_SUCCESS);
1848 cleanup:
1849 cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid query source");
1850 CLEANUP_OBJ(obj);
1851 return (result);
1854 static void
1855 print_querysource(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1856 isc_netaddr_t na;
1857 isc_netaddr_fromsockaddr(&na, &obj->value.sockaddr);
1858 cfg_print_chars(pctx, "address ", 8);
1859 cfg_print_rawaddr(pctx, &na);
1860 cfg_print_chars(pctx, " port ", 6);
1861 cfg_print_rawuint(pctx, isc_sockaddr_getport(&obj->value.sockaddr));
1864 static unsigned int sockaddr4wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V4OK;
1865 static unsigned int sockaddr6wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V6OK;
1867 static cfg_type_t cfg_type_querysource4 = {
1868 "querysource4", parse_querysource, NULL, cfg_doc_terminal,
1869 NULL, &sockaddr4wild_flags
1872 static cfg_type_t cfg_type_querysource6 = {
1873 "querysource6", parse_querysource, NULL, cfg_doc_terminal,
1874 NULL, &sockaddr6wild_flags
1877 static cfg_type_t cfg_type_querysource = {
1878 "querysource", NULL, print_querysource, NULL, &cfg_rep_sockaddr, NULL
1881 /*% addrmatchelt */
1883 static isc_result_t
1884 parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1885 isc_result_t result;
1886 UNUSED(type);
1888 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
1890 if (pctx->token.type == isc_tokentype_string ||
1891 pctx->token.type == isc_tokentype_qstring) {
1892 if (pctx->token.type == isc_tokentype_string &&
1893 (strcasecmp(TOKEN_STRING(pctx), "key") == 0)) {
1894 CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret));
1895 } else {
1896 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK |
1897 CFG_ADDR_V4PREFIXOK |
1898 CFG_ADDR_V6OK))
1900 CHECK(cfg_parse_netprefix(pctx, NULL, ret));
1901 } else {
1902 CHECK(cfg_parse_astring(pctx, NULL, ret));
1905 } else if (pctx->token.type == isc_tokentype_special) {
1906 if (pctx->token.value.as_char == '{') {
1907 /* Nested match list. */
1908 CHECK(cfg_parse_obj(pctx, &cfg_type_bracketed_aml, ret));
1909 } else if (pctx->token.value.as_char == '!') {
1910 CHECK(cfg_gettoken(pctx, 0)); /* read "!" */
1911 CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret));
1912 } else {
1913 goto bad;
1915 } else {
1916 bad:
1917 cfg_parser_error(pctx, CFG_LOG_NEAR,
1918 "expected IP match list element");
1919 return (ISC_R_UNEXPECTEDTOKEN);
1921 cleanup:
1922 return (result);
1926 * A negated address match list element (like "! 10.0.0.1").
1927 * Somewhat sneakily, the caller is expected to parse the
1928 * "!", but not to print it.
1931 static cfg_tuplefielddef_t negated_fields[] = {
1932 { "value", &cfg_type_addrmatchelt, 0 },
1933 { NULL, NULL, 0 }
1936 static void
1937 print_negated(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1938 cfg_print_chars(pctx, "!", 1);
1939 cfg_print_tuple(pctx, obj);
1942 static cfg_type_t cfg_type_negated = {
1943 "negated", cfg_parse_tuple, print_negated, NULL, &cfg_rep_tuple,
1944 &negated_fields
1947 /*% An address match list element */
1949 static cfg_type_t cfg_type_addrmatchelt = {
1950 "address_match_element", parse_addrmatchelt, NULL, cfg_doc_terminal,
1951 NULL, NULL
1954 /*% A bracketed address match list */
1956 static cfg_type_t cfg_type_bracketed_aml = {
1957 "bracketed_aml", cfg_parse_bracketed_list, cfg_print_bracketed_list,
1958 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_addrmatchelt
1962 * The socket address syntax in the "controls" statement is silly.
1963 * It allows both socket address families, but also allows "*",
1964 * whis is gratuitously interpreted as the IPv4 wildcard address.
1966 static unsigned int controls_sockaddr_flags =
1967 CFG_ADDR_V4OK | CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
1968 static cfg_type_t cfg_type_controls_sockaddr = {
1969 "controls_sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr,
1970 cfg_doc_sockaddr, &cfg_rep_sockaddr, &controls_sockaddr_flags
1974 * Handle the special kludge syntax of the "keys" clause in the "server"
1975 * statement, which takes a single key with or without braces and semicolon.
1977 static isc_result_t
1978 parse_server_key_kludge(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
1980 isc_result_t result;
1981 isc_boolean_t braces = ISC_FALSE;
1982 UNUSED(type);
1984 /* Allow opening brace. */
1985 CHECK(cfg_peektoken(pctx, 0));
1986 if (pctx->token.type == isc_tokentype_special &&
1987 pctx->token.value.as_char == '{') {
1988 result = cfg_gettoken(pctx, 0);
1989 braces = ISC_TRUE;
1992 CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
1994 if (braces) {
1995 /* Skip semicolon if present. */
1996 CHECK(cfg_peektoken(pctx, 0));
1997 if (pctx->token.type == isc_tokentype_special &&
1998 pctx->token.value.as_char == ';')
1999 CHECK(cfg_gettoken(pctx, 0));
2001 CHECK(cfg_parse_special(pctx, '}'));
2003 cleanup:
2004 return (result);
2006 static cfg_type_t cfg_type_server_key_kludge = {
2007 "server_key", parse_server_key_kludge, NULL, cfg_doc_terminal,
2008 NULL, NULL
2013 * An optional logging facility.
2016 static isc_result_t
2017 parse_optional_facility(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
2019 isc_result_t result;
2020 UNUSED(type);
2022 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
2023 if (pctx->token.type == isc_tokentype_string ||
2024 pctx->token.type == isc_tokentype_qstring) {
2025 CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
2026 } else {
2027 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
2029 cleanup:
2030 return (result);
2033 static cfg_type_t cfg_type_optional_facility = {
2034 "optional_facility", parse_optional_facility, NULL, cfg_doc_terminal,
2035 NULL, NULL };
2039 * A log severity. Return as a string, except "debug N",
2040 * which is returned as a keyword object.
2043 static keyword_type_t debug_kw = { "debug", &cfg_type_uint32 };
2044 static cfg_type_t cfg_type_debuglevel = {
2045 "debuglevel", parse_keyvalue,
2046 print_keyvalue, doc_keyvalue,
2047 &cfg_rep_uint32, &debug_kw
2050 static isc_result_t
2051 parse_logseverity(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2052 isc_result_t result;
2053 UNUSED(type);
2055 CHECK(cfg_peektoken(pctx, 0));
2056 if (pctx->token.type == isc_tokentype_string &&
2057 strcasecmp(TOKEN_STRING(pctx), "debug") == 0) {
2058 CHECK(cfg_gettoken(pctx, 0)); /* read "debug" */
2059 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER));
2060 if (pctx->token.type == isc_tokentype_number) {
2061 CHECK(cfg_parse_uint32(pctx, NULL, ret));
2062 } else {
2064 * The debug level is optional and defaults to 1.
2065 * This makes little sense, but we support it for
2066 * compatibility with BIND 8.
2068 CHECK(cfg_create_obj(pctx, &cfg_type_uint32, ret));
2069 (*ret)->value.uint32 = 1;
2071 (*ret)->type = &cfg_type_debuglevel; /* XXX kludge */
2072 } else {
2073 CHECK(cfg_parse_obj(pctx, &cfg_type_loglevel, ret));
2075 cleanup:
2076 return (result);
2079 static cfg_type_t cfg_type_logseverity = {
2080 "log_severity", parse_logseverity, NULL, cfg_doc_terminal,
2081 NULL, NULL };
2084 * The "file" clause of the "channel" statement.
2085 * This is yet another special case.
2088 static const char *logversions_enums[] = { "unlimited", NULL };
2089 static isc_result_t
2090 parse_logversions(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2091 return (parse_enum_or_other(pctx, type, &cfg_type_uint32, ret));
2094 static cfg_type_t cfg_type_logversions = {
2095 "logversions", parse_logversions, cfg_print_ustring, cfg_doc_terminal,
2096 &cfg_rep_string, logversions_enums
2099 static cfg_tuplefielddef_t logfile_fields[] = {
2100 { "file", &cfg_type_qstring, 0 },
2101 { "versions", &cfg_type_logversions, 0 },
2102 { "size", &cfg_type_size, 0 },
2103 { NULL, NULL, 0 }
2106 static isc_result_t
2107 parse_logfile(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2108 isc_result_t result;
2109 cfg_obj_t *obj = NULL;
2110 const cfg_tuplefielddef_t *fields = type->of;
2112 CHECK(cfg_create_tuple(pctx, type, &obj));
2114 /* Parse the mandatory "file" field */
2115 CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
2117 /* Parse "versions" and "size" fields in any order. */
2118 for (;;) {
2119 CHECK(cfg_peektoken(pctx, 0));
2120 if (pctx->token.type == isc_tokentype_string) {
2121 CHECK(cfg_gettoken(pctx, 0));
2122 if (strcasecmp(TOKEN_STRING(pctx),
2123 "versions") == 0 &&
2124 obj->value.tuple[1] == NULL) {
2125 CHECK(cfg_parse_obj(pctx, fields[1].type,
2126 &obj->value.tuple[1]));
2127 } else if (strcasecmp(TOKEN_STRING(pctx),
2128 "size") == 0 &&
2129 obj->value.tuple[2] == NULL) {
2130 CHECK(cfg_parse_obj(pctx, fields[2].type,
2131 &obj->value.tuple[2]));
2132 } else {
2133 break;
2135 } else {
2136 break;
2140 /* Create void objects for missing optional values. */
2141 if (obj->value.tuple[1] == NULL)
2142 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1]));
2143 if (obj->value.tuple[2] == NULL)
2144 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2]));
2146 *ret = obj;
2147 return (ISC_R_SUCCESS);
2149 cleanup:
2150 CLEANUP_OBJ(obj);
2151 return (result);
2154 static void
2155 print_logfile(cfg_printer_t *pctx, const cfg_obj_t *obj) {
2156 cfg_print_obj(pctx, obj->value.tuple[0]); /* file */
2157 if (obj->value.tuple[1]->type->print != cfg_print_void) {
2158 cfg_print_chars(pctx, " versions ", 10);
2159 cfg_print_obj(pctx, obj->value.tuple[1]);
2161 if (obj->value.tuple[2]->type->print != cfg_print_void) {
2162 cfg_print_chars(pctx, " size ", 6);
2163 cfg_print_obj(pctx, obj->value.tuple[2]);
2168 static void
2169 doc_logfile(cfg_printer_t *pctx, const cfg_type_t *type) {
2170 UNUSED(type);
2171 cfg_print_cstr(pctx, "<quoted_string>");
2172 cfg_print_chars(pctx, " ", 1);
2173 cfg_print_cstr(pctx, "[ versions ( \"unlimited\" | <integer> ) ]");
2174 cfg_print_chars(pctx, " ", 1);
2175 cfg_print_cstr(pctx, "[ size <size> ]");
2178 static cfg_type_t cfg_type_logfile = {
2179 "log_file", parse_logfile, print_logfile, doc_logfile,
2180 &cfg_rep_tuple, logfile_fields
2183 /*% An IPv4 address with optional port, "*" accepted as wildcard. */
2184 static cfg_type_t cfg_type_sockaddr4wild = {
2185 "sockaddr4wild", cfg_parse_sockaddr, cfg_print_sockaddr,
2186 cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr4wild_flags
2189 /*% An IPv6 address with optional port, "*" accepted as wildcard. */
2190 static cfg_type_t cfg_type_sockaddr6wild = {
2191 "v6addrportwild", cfg_parse_sockaddr, cfg_print_sockaddr,
2192 cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr6wild_flags
2196 * lwres
2199 static cfg_tuplefielddef_t lwres_view_fields[] = {
2200 { "name", &cfg_type_astring, 0 },
2201 { "class", &cfg_type_optional_class, 0 },
2202 { NULL, NULL, 0 }
2204 static cfg_type_t cfg_type_lwres_view = {
2205 "lwres_view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
2206 lwres_view_fields
2209 static cfg_type_t cfg_type_lwres_searchlist = {
2210 "lwres_searchlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
2211 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring };
2213 static cfg_clausedef_t
2214 lwres_clauses[] = {
2215 { "listen-on", &cfg_type_portiplist, 0 },
2216 { "view", &cfg_type_lwres_view, 0 },
2217 { "search", &cfg_type_lwres_searchlist, 0 },
2218 { "ndots", &cfg_type_uint32, 0 },
2219 { NULL, NULL, 0 }
2222 static cfg_clausedef_t *
2223 lwres_clausesets[] = {
2224 lwres_clauses,
2225 NULL
2227 static cfg_type_t cfg_type_lwres = {
2228 "lwres", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
2229 lwres_clausesets
2233 * rndc
2236 static cfg_clausedef_t
2237 rndcconf_options_clauses[] = {
2238 { "default-key", &cfg_type_astring, 0 },
2239 { "default-port", &cfg_type_uint32, 0 },
2240 { "default-server", &cfg_type_astring, 0 },
2241 { "default-source-address", &cfg_type_netaddr4wild, 0 },
2242 { "default-source-address-v6", &cfg_type_netaddr6wild, 0 },
2243 { NULL, NULL, 0 }
2246 static cfg_clausedef_t *
2247 rndcconf_options_clausesets[] = {
2248 rndcconf_options_clauses,
2249 NULL
2252 static cfg_type_t cfg_type_rndcconf_options = {
2253 "rndcconf_options", cfg_parse_map, cfg_print_map, cfg_doc_map,
2254 &cfg_rep_map, rndcconf_options_clausesets
2257 static cfg_clausedef_t
2258 rndcconf_server_clauses[] = {
2259 { "key", &cfg_type_astring, 0 },
2260 { "port", &cfg_type_uint32, 0 },
2261 { "source-address", &cfg_type_netaddr4wild, 0 },
2262 { "source-address-v6", &cfg_type_netaddr6wild, 0 },
2263 { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 },
2264 { NULL, NULL, 0 }
2267 static cfg_clausedef_t *
2268 rndcconf_server_clausesets[] = {
2269 rndcconf_server_clauses,
2270 NULL
2273 static cfg_type_t cfg_type_rndcconf_server = {
2274 "rndcconf_server", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
2275 &cfg_rep_map, rndcconf_server_clausesets
2278 static cfg_clausedef_t
2279 rndcconf_clauses[] = {
2280 { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
2281 { "server", &cfg_type_rndcconf_server, CFG_CLAUSEFLAG_MULTI },
2282 { "options", &cfg_type_rndcconf_options, 0 },
2283 { NULL, NULL, 0 }
2286 static cfg_clausedef_t *
2287 rndcconf_clausesets[] = {
2288 rndcconf_clauses,
2289 NULL
2292 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndcconf = {
2293 "rndcconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
2294 &cfg_rep_map, rndcconf_clausesets
2297 static cfg_clausedef_t
2298 rndckey_clauses[] = {
2299 { "key", &cfg_type_key, 0 },
2300 { NULL, NULL, 0 }
2303 static cfg_clausedef_t *
2304 rndckey_clausesets[] = {
2305 rndckey_clauses,
2306 NULL
2309 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndckey = {
2310 "rndckey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
2311 &cfg_rep_map, rndckey_clausesets
2315 * session.key has exactly the same syntax as rndc.key, but it's defined
2316 * separately for clarity (and so we can extend it someday, if needed).
2318 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sessionkey = {
2319 "sessionkey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
2320 &cfg_rep_map, rndckey_clausesets
2323 static cfg_tuplefielddef_t nameport_fields[] = {
2324 { "name", &cfg_type_astring, 0 },
2325 { "port", &cfg_type_optional_port, 0 },
2326 { NULL, NULL, 0 }
2328 static cfg_type_t cfg_type_nameport = {
2329 "nameport", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
2330 &cfg_rep_tuple, nameport_fields
2333 static void
2334 doc_sockaddrnameport(cfg_printer_t *pctx, const cfg_type_t *type) {
2335 UNUSED(type);
2336 cfg_print_chars(pctx, "( ", 2);
2337 cfg_print_cstr(pctx, "<quoted_string>");
2338 cfg_print_chars(pctx, " ", 1);
2339 cfg_print_cstr(pctx, "[ port <integer> ]");
2340 cfg_print_chars(pctx, " | ", 3);
2341 cfg_print_cstr(pctx, "<ipv4_address>");
2342 cfg_print_chars(pctx, " ", 1);
2343 cfg_print_cstr(pctx, "[ port <integer> ]");
2344 cfg_print_chars(pctx, " | ", 3);
2345 cfg_print_cstr(pctx, "<ipv6_address>");
2346 cfg_print_chars(pctx, " ", 1);
2347 cfg_print_cstr(pctx, "[ port <integer> ]");
2348 cfg_print_chars(pctx, " )", 2);
2351 static isc_result_t
2352 parse_sockaddrnameport(cfg_parser_t *pctx, const cfg_type_t *type,
2353 cfg_obj_t **ret)
2355 isc_result_t result;
2356 cfg_obj_t *obj = NULL;
2357 UNUSED(type);
2359 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
2360 if (pctx->token.type == isc_tokentype_string ||
2361 pctx->token.type == isc_tokentype_qstring) {
2362 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
2363 CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, ret));
2364 else {
2365 const cfg_tuplefielddef_t *fields =
2366 cfg_type_nameport.of;
2367 CHECK(cfg_create_tuple(pctx, &cfg_type_nameport,
2368 &obj));
2369 CHECK(cfg_parse_obj(pctx, fields[0].type,
2370 &obj->value.tuple[0]));
2371 CHECK(cfg_parse_obj(pctx, fields[1].type,
2372 &obj->value.tuple[1]));
2373 *ret = obj;
2374 obj = NULL;
2376 } else {
2377 cfg_parser_error(pctx, CFG_LOG_NEAR,
2378 "expected IP address or hostname");
2379 return (ISC_R_UNEXPECTEDTOKEN);
2381 cleanup:
2382 CLEANUP_OBJ(obj);
2383 return (result);
2386 static cfg_type_t cfg_type_sockaddrnameport = {
2387 "sockaddrnameport_element", parse_sockaddrnameport, NULL,
2388 doc_sockaddrnameport, NULL, NULL
2391 static cfg_type_t cfg_type_bracketed_sockaddrnameportlist = {
2392 "bracketed_sockaddrnameportlist", cfg_parse_bracketed_list,
2393 cfg_print_bracketed_list, cfg_doc_bracketed_list,
2394 &cfg_rep_list, &cfg_type_sockaddrnameport
2398 * A list of socket addresses or name with an optional default port,
2399 * as used in the dual-stack-servers option. E.g.,
2400 * "port 1234 { dual-stack-servers.net; 10.0.0.1; 1::2 port 69; }"
2402 static cfg_tuplefielddef_t nameportiplist_fields[] = {
2403 { "port", &cfg_type_optional_port, 0 },
2404 { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 },
2405 { NULL, NULL, 0 }
2408 static cfg_type_t cfg_type_nameportiplist = {
2409 "nameportiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
2410 &cfg_rep_tuple, nameportiplist_fields
2414 * masters element.
2417 static void
2418 doc_masterselement(cfg_printer_t *pctx, const cfg_type_t *type) {
2419 UNUSED(type);
2420 cfg_print_chars(pctx, "( ", 2);
2421 cfg_print_cstr(pctx, "<masters>");
2422 cfg_print_chars(pctx, " | ", 3);
2423 cfg_print_cstr(pctx, "<ipv4_address>");
2424 cfg_print_chars(pctx, " ", 1);
2425 cfg_print_cstr(pctx, "[ port <integer> ]");
2426 cfg_print_chars(pctx, " | ", 3);
2427 cfg_print_cstr(pctx, "<ipv6_address>");
2428 cfg_print_chars(pctx, " ", 1);
2429 cfg_print_cstr(pctx, "[ port <integer> ]");
2430 cfg_print_chars(pctx, " )", 2);
2433 static isc_result_t
2434 parse_masterselement(cfg_parser_t *pctx, const cfg_type_t *type,
2435 cfg_obj_t **ret)
2437 isc_result_t result;
2438 cfg_obj_t *obj = NULL;
2439 UNUSED(type);
2441 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
2442 if (pctx->token.type == isc_tokentype_string ||
2443 pctx->token.type == isc_tokentype_qstring) {
2444 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
2445 CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, ret));
2446 else
2447 CHECK(cfg_parse_astring(pctx, &cfg_type_astring, ret));
2448 } else {
2449 cfg_parser_error(pctx, CFG_LOG_NEAR,
2450 "expected IP address or masters name");
2451 return (ISC_R_UNEXPECTEDTOKEN);
2453 cleanup:
2454 CLEANUP_OBJ(obj);
2455 return (result);
2458 static cfg_type_t cfg_type_masterselement = {
2459 "masters_element", parse_masterselement, NULL,
2460 doc_masterselement, NULL, NULL