2 * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2002, 2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: namedconf.c,v 1.21.44.34 2006/03/02 00:37:20 marka Exp $ */
25 #include <isc/result.h>
26 #include <isc/string.h>
29 #include <isccfg/cfg.h>
30 #include <isccfg/grammar.h>
31 #include <isccfg/log.h>
33 #define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
35 /* Check a return value. */
38 if (result != ISC_R_SUCCESS) goto cleanup; \
41 /* Clean up a configuration object if non-NULL. */
42 #define CLEANUP_OBJ(obj) \
43 do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
47 * Forward declarations of static functions.
51 parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
52 const cfg_type_t *othertype, cfg_obj_t **ret);
55 parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
58 parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
61 print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj);
64 doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
67 doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
69 static cfg_type_t cfg_type_acl;
70 static cfg_type_t cfg_type_addrmatchelt;
71 static cfg_type_t cfg_type_bracketed_aml;
72 static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
73 static cfg_type_t cfg_type_bracketed_sockaddrlist;
74 static cfg_type_t cfg_type_controls;
75 static cfg_type_t cfg_type_controls_sockaddr;
76 static cfg_type_t cfg_type_destinationlist;
77 static cfg_type_t cfg_type_dialuptype;
78 static cfg_type_t cfg_type_key;
79 static cfg_type_t cfg_type_logfile;
80 static cfg_type_t cfg_type_logging;
81 static cfg_type_t cfg_type_logseverity;
82 static cfg_type_t cfg_type_lwres;
83 static cfg_type_t cfg_type_masterselement;
84 static cfg_type_t cfg_type_nameportiplist;
85 static cfg_type_t cfg_type_negated;
86 static cfg_type_t cfg_type_notifytype;
87 static cfg_type_t cfg_type_optional_class;
88 static cfg_type_t cfg_type_optional_facility;
89 static cfg_type_t cfg_type_optional_facility;
90 static cfg_type_t cfg_type_optional_keyref;
91 static cfg_type_t cfg_type_optional_port;
92 static cfg_type_t cfg_type_options;
93 static cfg_type_t cfg_type_portiplist;
94 static cfg_type_t cfg_type_querysource4;
95 static cfg_type_t cfg_type_querysource6;
96 static cfg_type_t cfg_type_querysource;
97 static cfg_type_t cfg_type_server;
98 static cfg_type_t cfg_type_server_key_kludge;
99 static cfg_type_t cfg_type_size;
100 static cfg_type_t cfg_type_sizenodefault;
101 static cfg_type_t cfg_type_sockaddr4wild;
102 static cfg_type_t cfg_type_sockaddr6wild;
103 static cfg_type_t cfg_type_view;
104 static cfg_type_t cfg_type_viewopts;
105 static cfg_type_t cfg_type_zone;
106 static cfg_type_t cfg_type_zoneopts;
110 static cfg_tuplefielddef_t tkey_dhkey_fields[] = {
111 { "name", &cfg_type_qstring, 0 },
112 { "keyid", &cfg_type_uint32, 0 },
116 static cfg_type_t cfg_type_tkey_dhkey = {
117 "tkey-dhkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
123 static cfg_tuplefielddef_t listenon_fields[] = {
124 { "port", &cfg_type_optional_port, 0 },
125 { "acl", &cfg_type_bracketed_aml, 0 },
128 static cfg_type_t cfg_type_listenon = {
129 "listenon", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, listenon_fields };
133 static cfg_tuplefielddef_t acl_fields[] = {
134 { "name", &cfg_type_astring, 0 },
135 { "value", &cfg_type_bracketed_aml, 0 },
139 static cfg_type_t cfg_type_acl = {
140 "acl", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, acl_fields };
143 static cfg_tuplefielddef_t masters_fields[] = {
144 { "name", &cfg_type_astring, 0 },
145 { "port", &cfg_type_optional_port, 0 },
146 { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
150 static cfg_type_t cfg_type_masters = {
151 "masters", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, masters_fields };
154 * "sockaddrkeylist", a list of socket addresses with optional keys
155 * and an optional default port, as used in the masters option.
157 * "port 1234 { mymasters; 10.0.0.1 key foo; 1::2 port 69; }"
160 static cfg_tuplefielddef_t namesockaddrkey_fields[] = {
161 { "masterselement", &cfg_type_masterselement, 0 },
162 { "key", &cfg_type_optional_keyref, 0 },
166 static cfg_type_t cfg_type_namesockaddrkey = {
167 "namesockaddrkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
168 namesockaddrkey_fields
171 static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = {
172 "bracketed_namesockaddrkeylist", cfg_parse_bracketed_list,
173 cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_namesockaddrkey
176 static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = {
177 { "port", &cfg_type_optional_port, 0 },
178 { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
181 static cfg_type_t cfg_type_namesockaddrkeylist = {
182 "sockaddrkeylist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
183 namesockaddrkeylist_fields
187 * A list of socket addresses with an optional default port,
188 * as used in the also-notify option. E.g.,
189 * "port 1234 { 10.0.0.1; 1::2 port 69; }"
191 static cfg_tuplefielddef_t portiplist_fields[] = {
192 { "port", &cfg_type_optional_port, 0 },
193 { "addresses", &cfg_type_bracketed_sockaddrlist, 0 },
196 static cfg_type_t cfg_type_portiplist = {
197 "portiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
202 * A public key, as in the "pubkey" statement.
204 static cfg_tuplefielddef_t pubkey_fields[] = {
205 { "flags", &cfg_type_uint32, 0 },
206 { "protocol", &cfg_type_uint32, 0 },
207 { "algorithm", &cfg_type_uint32, 0 },
208 { "key", &cfg_type_qstring, 0 },
211 static cfg_type_t cfg_type_pubkey = {
212 "pubkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, pubkey_fields };
215 * A list of RR types, used in grant statements.
216 * Note that the old parser allows quotes around the RR type names.
218 static cfg_type_t cfg_type_rrtypelist = {
219 "rrtypelist", cfg_parse_spacelist, cfg_print_spacelist, cfg_doc_terminal,
220 &cfg_rep_list, &cfg_type_astring
223 static const char *mode_enums[] = { "grant", "deny", NULL };
224 static cfg_type_t cfg_type_mode = {
225 "mode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
229 static const char *matchtype_enums[] = {
230 "name", "subdomain", "wildcard", "self", NULL };
231 static cfg_type_t cfg_type_matchtype = {
232 "matchtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
237 * A grant statement, used in the update policy.
239 static cfg_tuplefielddef_t grant_fields[] = {
240 { "mode", &cfg_type_mode, 0 },
241 { "identity", &cfg_type_astring, 0 }, /* domain name */
242 { "matchtype", &cfg_type_matchtype, 0 },
243 { "name", &cfg_type_astring, 0 }, /* domain name */
244 { "types", &cfg_type_rrtypelist, 0 },
247 static cfg_type_t cfg_type_grant = {
248 "grant", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, grant_fields };
250 static cfg_type_t cfg_type_updatepolicy = {
251 "update_policy", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
252 &cfg_rep_list, &cfg_type_grant
258 static cfg_tuplefielddef_t view_fields[] = {
259 { "name", &cfg_type_astring, 0 },
260 { "class", &cfg_type_optional_class, 0 },
261 { "options", &cfg_type_viewopts, 0 },
264 static cfg_type_t cfg_type_view = {
265 "view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, view_fields };
270 static cfg_tuplefielddef_t zone_fields[] = {
271 { "name", &cfg_type_astring, 0 },
272 { "class", &cfg_type_optional_class, 0 },
273 { "options", &cfg_type_zoneopts, 0 },
276 static cfg_type_t cfg_type_zone = {
277 "zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, zone_fields };
280 * A "category" clause in the "logging" statement.
282 static cfg_tuplefielddef_t category_fields[] = {
283 { "name", &cfg_type_astring, 0 },
284 { "destinations", &cfg_type_destinationlist,0 },
287 static cfg_type_t cfg_type_category = {
288 "category", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, category_fields };
292 * A trusted key, as used in the "trusted-keys" statement.
294 static cfg_tuplefielddef_t trustedkey_fields[] = {
295 { "name", &cfg_type_astring, 0 },
296 { "flags", &cfg_type_uint32, 0 },
297 { "protocol", &cfg_type_uint32, 0 },
298 { "algorithm", &cfg_type_uint32, 0 },
299 { "key", &cfg_type_qstring, 0 },
302 static cfg_type_t cfg_type_trustedkey = {
303 "trustedkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
307 static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring };
309 static cfg_type_t cfg_type_optional_wild_class = {
310 "optional_wild_class", parse_optional_keyvalue, print_keyvalue,
311 doc_optional_keyvalue, &cfg_rep_string, &wild_class_kw
314 static keyword_type_t wild_type_kw = { "type", &cfg_type_ustring };
316 static cfg_type_t cfg_type_optional_wild_type = {
317 "optional_wild_type", parse_optional_keyvalue,
318 print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_type_kw
321 static keyword_type_t wild_name_kw = { "name", &cfg_type_qstring };
323 static cfg_type_t cfg_type_optional_wild_name = {
324 "optional_wild_name", parse_optional_keyvalue,
325 print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_name_kw
329 * An rrset ordering element.
331 static cfg_tuplefielddef_t rrsetorderingelement_fields[] = {
332 { "class", &cfg_type_optional_wild_class, 0 },
333 { "type", &cfg_type_optional_wild_type, 0 },
334 { "name", &cfg_type_optional_wild_name, 0 },
335 { "order", &cfg_type_ustring, 0 }, /* must be literal "order" */
336 { "ordering", &cfg_type_ustring, 0 },
339 static cfg_type_t cfg_type_rrsetorderingelement = {
340 "rrsetorderingelement", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
341 rrsetorderingelement_fields
345 * A global or view "check-names" option. Note that the zone
346 * "check-names" option has a different syntax.
349 static const char *checktype_enums[] = { "master", "slave", "response", NULL };
350 static cfg_type_t cfg_type_checktype = {
351 "checktype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
352 &cfg_rep_string, &checktype_enums
355 static const char *checkmode_enums[] = { "fail", "warn", "ignore", NULL };
356 static cfg_type_t cfg_type_checkmode = {
357 "checkmode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
358 &cfg_rep_string, &checkmode_enums
361 static cfg_tuplefielddef_t checknames_fields[] = {
362 { "type", &cfg_type_checktype, 0 },
363 { "mode", &cfg_type_checkmode, 0 },
366 static cfg_type_t cfg_type_checknames = {
367 "checknames", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
371 static cfg_type_t cfg_type_bracketed_sockaddrlist = {
372 "bracketed_sockaddrlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
373 &cfg_rep_list, &cfg_type_sockaddr
376 static cfg_type_t cfg_type_rrsetorder = {
377 "rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
378 &cfg_rep_list, &cfg_type_rrsetorderingelement
381 static keyword_type_t port_kw = { "port", &cfg_type_uint32 };
383 static cfg_type_t cfg_type_optional_port = {
384 "optional_port", parse_optional_keyvalue, print_keyvalue,
385 doc_optional_keyvalue, &cfg_rep_uint32, &port_kw
388 /* A list of keys, as in the "key" clause of the controls statement. */
389 static cfg_type_t cfg_type_keylist = {
390 "keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list,
394 static cfg_type_t cfg_type_trustedkeys = {
395 "trusted-keys", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list,
399 static const char *forwardtype_enums[] = { "first", "only", NULL };
400 static cfg_type_t cfg_type_forwardtype = {
401 "forwardtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
405 static const char *zonetype_enums[] = {
406 "master", "slave", "stub", "hint", "forward", "delegation-only", NULL };
407 static cfg_type_t cfg_type_zonetype = {
408 "zonetype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
412 static const char *loglevel_enums[] = {
413 "critical", "error", "warning", "notice", "info", "dynamic", NULL };
414 static cfg_type_t cfg_type_loglevel = {
415 "loglevel", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
419 static const char *transferformat_enums[] = {
420 "many-answers", "one-answer", NULL };
421 static cfg_type_t cfg_type_transferformat = {
422 "transferformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
423 &transferformat_enums
427 * The special keyword "none", as used in the pid-file option.
431 print_none(cfg_printer_t *pctx, const cfg_obj_t *obj) {
433 cfg_print_chars(pctx, "none", 4);
436 static cfg_type_t cfg_type_none = {
437 "none", NULL, print_none, NULL, &cfg_rep_void, NULL
441 * A quoted string or the special keyword "none". Used in the pid-file option.
444 parse_qstringornone(cfg_parser_t *pctx, const cfg_type_t *type,
448 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
449 if (pctx->token.type == isc_tokentype_string &&
450 strcasecmp(TOKEN_STRING(pctx), "none") == 0)
451 return (cfg_create_obj(pctx, &cfg_type_none, ret));
452 cfg_ungettoken(pctx);
453 return (cfg_parse_qstring(pctx, type, ret));
459 doc_qstringornone(cfg_printer_t *pctx, const cfg_type_t *type) {
461 cfg_print_chars(pctx, "( <quoted_string> | none )", 26);
464 static cfg_type_t cfg_type_qstringornone = {
465 "qstringornone", parse_qstringornone, NULL, doc_qstringornone, NULL, NULL };
472 print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) {
474 cfg_print_chars(pctx, "hostname", 4);
477 static cfg_type_t cfg_type_hostname = {
478 "hostname", NULL, print_hostname, NULL, &cfg_rep_boolean, NULL
482 * "server-id" argument.
486 parse_serverid(cfg_parser_t *pctx, const cfg_type_t *type,
490 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
491 if (pctx->token.type == isc_tokentype_string &&
492 strcasecmp(TOKEN_STRING(pctx), "none") == 0)
493 return (cfg_create_obj(pctx, &cfg_type_none, ret));
494 if (pctx->token.type == isc_tokentype_string &&
495 strcasecmp(TOKEN_STRING(pctx), "hostname") == 0) {
496 return (cfg_create_obj(pctx, &cfg_type_hostname, ret));
498 cfg_ungettoken(pctx);
499 return (cfg_parse_qstring(pctx, type, ret));
505 doc_serverid(cfg_printer_t *pctx, const cfg_type_t *type) {
507 cfg_print_chars(pctx, "( <quoted_string> | none | hostname )", 26);
510 static cfg_type_t cfg_type_serverid = {
511 "serverid", parse_serverid, NULL, doc_serverid, NULL, NULL };
517 parse_port(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
522 CHECK(cfg_parse_uint32(pctx, NULL, ret));
523 if ((*ret)->value.uint32 > 0xffff) {
524 cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid port");
525 cfg_obj_destroy(pctx, ret);
526 result = ISC_R_RANGE;
532 static cfg_type_t cfg_type_port = {
533 "port", parse_port, NULL, cfg_doc_terminal,
537 static cfg_type_t cfg_type_bracketed_portlist = {
538 "bracketed_sockaddrlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
539 &cfg_rep_list, &cfg_type_port
543 * Clauses that can be found within the top level of the named.conf
546 static cfg_clausedef_t
547 namedconf_clauses[] = {
548 { "options", &cfg_type_options, 0 },
549 { "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
550 { "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
551 { "masters", &cfg_type_masters, CFG_CLAUSEFLAG_MULTI },
552 { "logging", &cfg_type_logging, 0 },
553 { "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI },
554 { "lwres", &cfg_type_lwres, CFG_CLAUSEFLAG_MULTI },
559 * Clauses that can occur at the top level or in the view
560 * statement, but not in the options block.
562 static cfg_clausedef_t
563 namedconf_or_view_clauses[] = {
564 { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
565 { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
566 { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI },
567 { "trusted-keys", &cfg_type_trustedkeys, CFG_CLAUSEFLAG_MULTI },
572 * Clauses that can be found within the 'options' statement.
574 static cfg_clausedef_t
575 options_clauses[] = {
576 { "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
577 { "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
578 { "blackhole", &cfg_type_bracketed_aml, 0 },
579 { "coresize", &cfg_type_size, 0 },
580 { "datasize", &cfg_type_size, 0 },
581 { "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
582 { "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK },
583 { "dump-file", &cfg_type_qstring, 0 },
584 { "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
585 { "files", &cfg_type_size, 0 },
586 { "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
587 { "heartbeat-interval", &cfg_type_uint32, 0 },
588 { "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP },
589 { "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
590 { "hostname", &cfg_type_qstringornone, 0 },
591 { "interface-interval", &cfg_type_uint32, 0 },
592 { "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
593 { "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
594 { "match-mapped-addresses", &cfg_type_boolean, 0 },
595 { "memstatistics-file", &cfg_type_qstring, 0 },
596 { "multiple-cnames", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
597 { "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
598 { "pid-file", &cfg_type_qstringornone, 0 },
599 { "port", &cfg_type_uint32, 0 },
600 { "querylog", &cfg_type_boolean, 0 },
601 { "recursing-file", &cfg_type_qstring, 0 },
602 { "random-device", &cfg_type_qstring, 0 },
603 { "recursive-clients", &cfg_type_uint32, 0 },
604 { "serial-queries", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
605 { "serial-query-rate", &cfg_type_uint32, 0 },
606 { "server-id", &cfg_type_serverid, 0 },
607 { "stacksize", &cfg_type_size, 0 },
608 { "statistics-file", &cfg_type_qstring, 0 },
609 { "statistics-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_NYI },
610 { "tcp-clients", &cfg_type_uint32, 0 },
611 { "tcp-listen-queue", &cfg_type_uint32, 0 },
612 { "tkey-dhkey", &cfg_type_tkey_dhkey, 0 },
613 { "tkey-gssapi-credential", &cfg_type_qstring, 0 },
614 { "tkey-domain", &cfg_type_qstring, 0 },
615 { "transfers-per-ns", &cfg_type_uint32, 0 },
616 { "transfers-in", &cfg_type_uint32, 0 },
617 { "transfers-out", &cfg_type_uint32, 0 },
618 { "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
619 { "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
620 { "use-ixfr", &cfg_type_boolean, 0 },
621 { "version", &cfg_type_qstringornone, 0 },
622 { "flush-zones-on-shutdown", &cfg_type_boolean, 0 },
627 static cfg_type_t cfg_type_namelist = {
628 "namelist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
629 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_qstring };
631 static keyword_type_t exclude_kw = { "exclude", &cfg_type_namelist };
633 static cfg_type_t cfg_type_optional_exclude = {
634 "optional_exclude", parse_optional_keyvalue, print_keyvalue,
635 doc_optional_keyvalue, &cfg_rep_list, &exclude_kw };
637 static cfg_type_t cfg_type_algorithmlist = {
638 "algorithmlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
639 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring };
641 static cfg_tuplefielddef_t disablealgorithm_fields[] = {
642 { "name", &cfg_type_astring, 0 },
643 { "algorithms", &cfg_type_algorithmlist, 0 },
647 static cfg_type_t cfg_type_disablealgorithm = {
648 "disablealgorithm", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
649 &cfg_rep_tuple, disablealgorithm_fields
652 static cfg_tuplefielddef_t mustbesecure_fields[] = {
653 { "name", &cfg_type_astring, 0 },
654 { "value", &cfg_type_boolean, 0 },
658 static cfg_type_t cfg_type_mustbesecure = {
659 "mustbesecure", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
660 &cfg_rep_tuple, mustbesecure_fields
667 static keyword_type_t trustanchor_kw = { "trust-anchor", &cfg_type_astring };
669 static cfg_type_t cfg_type_trustanchor = {
670 "trust-anchor", parse_keyvalue, print_keyvalue, doc_keyvalue,
671 &cfg_rep_string, &trustanchor_kw
674 static cfg_tuplefielddef_t lookaside_fields[] = {
675 { "domain", &cfg_type_astring, 0 },
676 { "trust-anchor", &cfg_type_trustanchor, 0 },
680 static cfg_type_t cfg_type_lookaside = {
681 "lookaside", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
682 &cfg_rep_tuple, lookaside_fields
686 * Clauses that can be found within the 'view' statement,
687 * with defaults in the 'options' statement.
690 static cfg_clausedef_t
692 { "allow-recursion", &cfg_type_bracketed_aml, 0 },
693 { "allow-v6-synthesis", &cfg_type_bracketed_aml,
694 CFG_CLAUSEFLAG_OBSOLETE },
695 { "sortlist", &cfg_type_bracketed_aml, 0 },
696 { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP },
697 { "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT },
698 { "minimal-responses", &cfg_type_boolean, 0 },
699 { "recursion", &cfg_type_boolean, 0 },
700 { "rrset-order", &cfg_type_rrsetorder, 0 },
701 { "provide-ixfr", &cfg_type_boolean, 0 },
702 { "request-ixfr", &cfg_type_boolean, 0 },
703 { "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
704 { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
705 { "additional-from-auth", &cfg_type_boolean, 0 },
706 { "additional-from-cache", &cfg_type_boolean, 0 },
708 * Note that the query-source option syntax is different
709 * from the other -source options.
711 { "query-source", &cfg_type_querysource4, 0 },
712 { "query-source-v6", &cfg_type_querysource6, 0 },
713 { "cleaning-interval", &cfg_type_uint32, 0 },
714 { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
715 { "lame-ttl", &cfg_type_uint32, 0 },
716 { "max-ncache-ttl", &cfg_type_uint32, 0 },
717 { "max-cache-ttl", &cfg_type_uint32, 0 },
718 { "transfer-format", &cfg_type_transferformat, 0 },
719 { "max-cache-size", &cfg_type_sizenodefault, 0 },
720 { "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
721 { "cache-file", &cfg_type_qstring, 0 },
722 { "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
723 { "preferred-glue", &cfg_type_astring, 0 },
724 { "dual-stack-servers", &cfg_type_nameportiplist, 0 },
725 { "edns-udp-size", &cfg_type_uint32, 0 },
726 { "root-delegation-only", &cfg_type_optional_exclude, 0 },
727 { "disable-algorithms", &cfg_type_disablealgorithm,
728 CFG_CLAUSEFLAG_MULTI },
729 { "dnssec-enable", &cfg_type_boolean, 0 },
730 { "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI },
731 { "dnssec-must-be-secure", &cfg_type_mustbesecure,
732 CFG_CLAUSEFLAG_MULTI },
737 * Clauses that can be found within the 'view' statement only.
739 static cfg_clausedef_t
740 view_only_clauses[] = {
741 { "match-clients", &cfg_type_bracketed_aml, 0 },
742 { "match-destinations", &cfg_type_bracketed_aml, 0 },
743 { "match-recursive-only", &cfg_type_boolean, 0 },
748 * Clauses that can be found in a 'zone' statement,
749 * with defaults in the 'view' or 'options' statement.
751 static cfg_clausedef_t
753 { "allow-query", &cfg_type_bracketed_aml, 0 },
754 { "allow-transfer", &cfg_type_bracketed_aml, 0 },
755 { "allow-update-forwarding", &cfg_type_bracketed_aml, 0 },
756 { "allow-notify", &cfg_type_bracketed_aml, 0 },
757 { "notify", &cfg_type_notifytype, 0 },
758 { "notify-source", &cfg_type_sockaddr4wild, 0 },
759 { "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
760 { "also-notify", &cfg_type_portiplist, 0 },
761 { "dialup", &cfg_type_dialuptype, 0 },
762 { "forward", &cfg_type_forwardtype, 0 },
763 { "forwarders", &cfg_type_portiplist, 0 },
764 { "ixfr-from-differences", &cfg_type_boolean, 0 },
765 { "maintain-ixfr-base", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
766 { "max-ixfr-log-size", &cfg_type_size, CFG_CLAUSEFLAG_OBSOLETE },
767 { "max-journal-size", &cfg_type_sizenodefault, 0 },
768 { "max-transfer-time-in", &cfg_type_uint32, 0 },
769 { "max-transfer-time-out", &cfg_type_uint32, 0 },
770 { "max-transfer-idle-in", &cfg_type_uint32, 0 },
771 { "max-transfer-idle-out", &cfg_type_uint32, 0 },
772 { "max-retry-time", &cfg_type_uint32, 0 },
773 { "min-retry-time", &cfg_type_uint32, 0 },
774 { "max-refresh-time", &cfg_type_uint32, 0 },
775 { "min-refresh-time", &cfg_type_uint32, 0 },
776 { "multi-master", &cfg_type_boolean, 0 },
777 { "sig-validity-interval", &cfg_type_uint32, 0 },
778 { "transfer-source", &cfg_type_sockaddr4wild, 0 },
779 { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
780 { "alt-transfer-source", &cfg_type_sockaddr4wild, 0 },
781 { "alt-transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
782 { "use-alt-transfer-source", &cfg_type_boolean, 0 },
783 { "zone-statistics", &cfg_type_boolean, 0 },
784 { "key-directory", &cfg_type_qstring, 0 },
789 * Clauses that can be found in a 'zone' statement
792 static cfg_clausedef_t
793 zone_only_clauses[] = {
794 { "type", &cfg_type_zonetype, 0 },
795 { "allow-update", &cfg_type_bracketed_aml, 0 },
796 { "file", &cfg_type_qstring, 0 },
797 { "ixfr-base", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
798 { "ixfr-tmp-file", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
799 { "masters", &cfg_type_namesockaddrkeylist, 0 },
800 { "pubkey", &cfg_type_pubkey,
801 CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE },
802 { "update-policy", &cfg_type_updatepolicy, 0 },
803 { "database", &cfg_type_astring, 0 },
804 { "delegation-only", &cfg_type_boolean, 0 },
806 * Note that the format of the check-names option is different between
807 * the zone options and the global/view options. Ugh.
809 { "check-names", &cfg_type_checkmode, 0 },
814 /* The top-level named.conf syntax. */
816 static cfg_clausedef_t *
817 namedconf_clausesets[] = {
819 namedconf_or_view_clauses,
823 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = {
824 "namedconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
825 &cfg_rep_map, namedconf_clausesets
828 /* The "options" statement syntax. */
830 static cfg_clausedef_t *
831 options_clausesets[] = {
837 static cfg_type_t cfg_type_options = {
838 "options", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, options_clausesets };
840 /* The "view" statement syntax. */
842 static cfg_clausedef_t *
843 view_clausesets[] = {
845 namedconf_or_view_clauses,
850 static cfg_type_t cfg_type_viewopts = {
851 "view", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, view_clausesets };
853 /* The "zone" statement syntax. */
855 static cfg_clausedef_t *
856 zone_clausesets[] = {
861 static cfg_type_t cfg_type_zoneopts = {
862 "zoneopts", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, zone_clausesets };
865 * Clauses that can be found within the 'key' statement.
867 static cfg_clausedef_t
869 { "algorithm", &cfg_type_astring, 0 },
870 { "secret", &cfg_type_astring, 0 },
874 static cfg_clausedef_t *
879 static cfg_type_t cfg_type_key = {
880 "key", cfg_parse_named_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, key_clausesets };
884 * Clauses that can be found in a 'server' statement.
886 static cfg_clausedef_t
888 { "bogus", &cfg_type_boolean, 0 },
889 { "provide-ixfr", &cfg_type_boolean, 0 },
890 { "request-ixfr", &cfg_type_boolean, 0 },
891 { "support-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
892 { "transfers", &cfg_type_uint32, 0 },
893 { "transfer-format", &cfg_type_transferformat, 0 },
894 { "keys", &cfg_type_server_key_kludge, 0 },
895 { "edns", &cfg_type_boolean, 0 },
896 { "transfer-source", &cfg_type_sockaddr4wild, 0 },
897 { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
900 static cfg_clausedef_t *
901 server_clausesets[] = {
905 static cfg_type_t cfg_type_server = {
906 "server", cfg_parse_addressed_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
912 * Clauses that can be found in a 'channel' clause in the
913 * 'logging' statement.
915 * These have some additional constraints that need to be
916 * checked after parsing:
917 * - There must exactly one of file/syslog/null/stderr
920 static cfg_clausedef_t
921 channel_clauses[] = {
922 /* Destinations. We no longer require these to be first. */
923 { "file", &cfg_type_logfile, 0 },
924 { "syslog", &cfg_type_optional_facility, 0 },
925 { "null", &cfg_type_void, 0 },
926 { "stderr", &cfg_type_void, 0 },
927 /* Options. We now accept these for the null channel, too. */
928 { "severity", &cfg_type_logseverity, 0 },
929 { "print-time", &cfg_type_boolean, 0 },
930 { "print-severity", &cfg_type_boolean, 0 },
931 { "print-category", &cfg_type_boolean, 0 },
934 static cfg_clausedef_t *
935 channel_clausesets[] = {
939 static cfg_type_t cfg_type_channel = {
940 "channel", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
941 &cfg_rep_map, channel_clausesets
944 /* A list of log destination, used in the "category" clause. */
945 static cfg_type_t cfg_type_destinationlist = {
946 "destinationlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
947 &cfg_rep_list, &cfg_type_astring };
950 * Clauses that can be found in a 'logging' statement.
952 static cfg_clausedef_t
953 logging_clauses[] = {
954 { "channel", &cfg_type_channel, CFG_CLAUSEFLAG_MULTI },
955 { "category", &cfg_type_category, CFG_CLAUSEFLAG_MULTI },
958 static cfg_clausedef_t *
959 logging_clausesets[] = {
963 static cfg_type_t cfg_type_logging = {
964 "logging", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, logging_clausesets };
968 parse_unitstring(char *str, isc_resourcevalue_t *valuep) {
974 value = isc_string_touint64(str, &endp, 10);
977 return (ISC_R_SUCCESS);
981 if (len < 2 || endp[1] != '\0')
982 return (ISC_R_FAILURE);
984 switch (str[len - 1]) {
995 unit = 1024 * 1024 * 1024;
998 return (ISC_R_FAILURE);
1000 if (value > ISC_UINT64_MAX / unit)
1001 return (ISC_R_FAILURE);
1002 *valuep = value * unit;
1003 return (ISC_R_SUCCESS);
1007 parse_sizeval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1008 isc_result_t result;
1009 cfg_obj_t *obj = NULL;
1014 CHECK(cfg_gettoken(pctx, 0));
1015 if (pctx->token.type != isc_tokentype_string) {
1016 result = ISC_R_UNEXPECTEDTOKEN;
1019 CHECK(parse_unitstring(TOKEN_STRING(pctx), &val));
1021 CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj));
1022 obj->value.uint64 = val;
1024 return (ISC_R_SUCCESS);
1027 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected integer and optional unit");
1032 * A size value (number + optional unit).
1034 static cfg_type_t cfg_type_sizeval = {
1035 "sizeval", parse_sizeval, cfg_print_uint64, cfg_doc_terminal,
1036 &cfg_rep_uint64, NULL };
1039 * A size, "unlimited", or "default".
1043 parse_size(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1044 return (parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret));
1047 static const char *size_enums[] = { "unlimited", "default", NULL };
1048 static cfg_type_t cfg_type_size = {
1049 "size", parse_size, cfg_print_ustring, cfg_doc_terminal,
1050 &cfg_rep_string, size_enums
1054 * A size or "unlimited", but not "default".
1056 static const char *sizenodefault_enums[] = { "unlimited", NULL };
1057 static cfg_type_t cfg_type_sizenodefault = {
1058 "size_no_default", parse_size, cfg_print_ustring, cfg_doc_terminal,
1059 &cfg_rep_string, sizenodefault_enums
1066 parse_maybe_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
1067 isc_boolean_t optional, cfg_obj_t **ret)
1069 isc_result_t result;
1070 cfg_obj_t *obj = NULL;
1071 const keyword_type_t *kw = type->of;
1073 CHECK(cfg_peektoken(pctx, 0));
1074 if (pctx->token.type == isc_tokentype_string &&
1075 strcasecmp(TOKEN_STRING(pctx), kw->name) == 0) {
1076 CHECK(cfg_gettoken(pctx, 0));
1077 CHECK(kw->type->parse(pctx, kw->type, &obj));
1078 obj->type = type; /* XXX kludge */
1081 CHECK(cfg_parse_void(pctx, NULL, &obj));
1083 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected '%s'",
1085 result = ISC_R_UNEXPECTEDTOKEN;
1095 parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
1096 const cfg_type_t *othertype, cfg_obj_t **ret)
1098 isc_result_t result;
1099 CHECK(cfg_peektoken(pctx, 0));
1100 if (pctx->token.type == isc_tokentype_string &&
1101 cfg_is_enum(TOKEN_STRING(pctx), enumtype->of)) {
1102 CHECK(cfg_parse_enum(pctx, enumtype, ret));
1104 CHECK(cfg_parse_obj(pctx, othertype, ret));
1111 doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *type) {
1112 cfg_doc_terminal(pctx, type);
1114 cfg_print_chars(pctx, "( ", 2);...
1120 parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1121 return (parse_maybe_optional_keyvalue(pctx, type, ISC_FALSE, ret));
1125 parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1126 return (parse_maybe_optional_keyvalue(pctx, type, ISC_TRUE, ret));
1130 print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1131 const keyword_type_t *kw = obj->type->of;
1132 cfg_print_cstr(pctx, kw->name);
1133 cfg_print_chars(pctx, " ", 1);
1134 kw->type->print(pctx, obj);
1138 doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
1139 const keyword_type_t *kw = type->of;
1140 cfg_print_cstr(pctx, kw->name);
1141 cfg_print_chars(pctx, " ", 1);
1142 cfg_doc_obj(pctx, kw->type);
1146 doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
1147 const keyword_type_t *kw = type->of;
1148 cfg_print_chars(pctx, "[ ", 2);
1149 cfg_print_cstr(pctx, kw->name);
1150 cfg_print_chars(pctx, " ", 1);
1151 cfg_doc_obj(pctx, kw->type);
1152 cfg_print_chars(pctx, " ]", 2);
1155 static const char *dialup_enums[] = {
1156 "notify", "notify-passive", "refresh", "passive", NULL };
1158 parse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1159 return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
1161 static cfg_type_t cfg_type_dialuptype = {
1162 "dialuptype", parse_dialup_type, cfg_print_ustring, doc_enum_or_other,
1163 &cfg_rep_string, dialup_enums
1166 static const char *notify_enums[] = { "explicit", NULL };
1168 parse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1169 return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
1171 static cfg_type_t cfg_type_notifytype = {
1172 "notifytype", parse_notify_type, cfg_print_ustring, doc_enum_or_other,
1173 &cfg_rep_string, notify_enums,
1176 static keyword_type_t key_kw = { "key", &cfg_type_astring };
1178 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = {
1179 "keyref", parse_keyvalue, print_keyvalue, doc_keyvalue,
1180 &cfg_rep_string, &key_kw
1183 static cfg_type_t cfg_type_optional_keyref = {
1184 "optional_keyref", parse_optional_keyvalue, print_keyvalue,
1185 doc_optional_keyvalue, &cfg_rep_string, &key_kw
1189 * A "controls" statement is represented as a map with the multivalued
1190 * "inet" and "unix" clauses. Inet controls are tuples; unix controls
1191 * are cfg_unsupported_t objects.
1194 static keyword_type_t controls_allow_kw = {
1195 "allow", &cfg_type_bracketed_aml };
1196 static cfg_type_t cfg_type_controls_allow = {
1197 "controls_allow", parse_keyvalue,
1198 print_keyvalue, doc_keyvalue,
1199 &cfg_rep_list, &controls_allow_kw
1202 static keyword_type_t controls_keys_kw = {
1203 "keys", &cfg_type_keylist };
1204 static cfg_type_t cfg_type_controls_keys = {
1205 "controls_keys", parse_optional_keyvalue,
1206 print_keyvalue, doc_optional_keyvalue,
1207 &cfg_rep_list, &controls_keys_kw
1210 static cfg_tuplefielddef_t inetcontrol_fields[] = {
1211 { "address", &cfg_type_controls_sockaddr, 0 },
1212 { "allow", &cfg_type_controls_allow, 0 },
1213 { "keys", &cfg_type_controls_keys, 0 },
1216 static cfg_type_t cfg_type_inetcontrol = {
1217 "inetcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
1221 static cfg_clausedef_t
1222 controls_clauses[] = {
1223 { "inet", &cfg_type_inetcontrol, CFG_CLAUSEFLAG_MULTI },
1224 { "unix", &cfg_type_unsupported,
1225 CFG_CLAUSEFLAG_MULTI|CFG_CLAUSEFLAG_NOTIMP },
1229 static cfg_clausedef_t *
1230 controls_clausesets[] = {
1234 static cfg_type_t cfg_type_controls = {
1235 "controls", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, &controls_clausesets
1239 * An optional class, as used in view and zone statements.
1242 parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1243 isc_result_t result;
1245 CHECK(cfg_peektoken(pctx, 0));
1246 if (pctx->token.type == isc_tokentype_string)
1247 CHECK(cfg_parse_obj(pctx, &cfg_type_ustring, ret));
1249 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
1254 static cfg_type_t cfg_type_optional_class = {
1255 "optional_class", parse_optional_class, NULL, cfg_doc_terminal,
1260 parse_querysource(cfg_parser_t *pctx, int flags, cfg_obj_t **ret) {
1261 isc_result_t result;
1262 cfg_obj_t *obj = NULL;
1263 isc_netaddr_t netaddr;
1265 unsigned int have_address = 0;
1266 unsigned int have_port = 0;
1268 if ((flags & CFG_ADDR_V4OK) != 0)
1269 isc_netaddr_any(&netaddr);
1270 else if ((flags & CFG_ADDR_V6OK) != 0)
1271 isc_netaddr_any6(&netaddr);
1277 CHECK(cfg_create_obj(pctx, &cfg_type_querysource, &obj));
1279 CHECK(cfg_peektoken(pctx, 0));
1280 if (pctx->token.type == isc_tokentype_string) {
1281 if (strcasecmp(TOKEN_STRING(pctx),
1284 /* read "address" */
1285 CHECK(cfg_gettoken(pctx, 0));
1286 CHECK(cfg_parse_rawaddr(pctx,
1287 flags | CFG_ADDR_WILDOK,
1290 } else if (strcasecmp(TOKEN_STRING(pctx), "port") == 0)
1293 CHECK(cfg_gettoken(pctx, 0));
1294 CHECK(cfg_parse_rawport(pctx,
1299 cfg_parser_error(pctx, CFG_LOG_NEAR,
1300 "expected 'address' or 'port'");
1301 return (ISC_R_UNEXPECTEDTOKEN);
1306 if (have_address > 1 || have_port > 1 ||
1307 have_address + have_port == 0) {
1308 cfg_parser_error(pctx, 0, "expected one address and/or port");
1309 return (ISC_R_UNEXPECTEDTOKEN);
1312 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
1314 return (ISC_R_SUCCESS);
1317 cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid query source");
1323 parse_querysource4(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1325 return (parse_querysource(pctx, CFG_ADDR_V4OK, ret));
1329 parse_querysource6(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1331 return (parse_querysource(pctx, CFG_ADDR_V6OK, ret));
1335 print_querysource(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1337 isc_netaddr_fromsockaddr(&na, &obj->value.sockaddr);
1338 cfg_print_chars(pctx, "address ", 8);
1339 cfg_print_rawaddr(pctx, &na);
1340 cfg_print_chars(pctx, " port ", 6);
1341 cfg_print_rawuint(pctx, isc_sockaddr_getport(&obj->value.sockaddr));
1344 static cfg_type_t cfg_type_querysource4 = {
1345 "querysource4", parse_querysource4, NULL, cfg_doc_terminal,
1348 static cfg_type_t cfg_type_querysource6 = {
1349 "querysource6", parse_querysource6, NULL, cfg_doc_terminal,
1352 static cfg_type_t cfg_type_querysource = {
1353 "querysource", NULL, print_querysource, NULL, &cfg_rep_sockaddr, NULL };
1358 parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1359 isc_result_t result;
1362 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
1364 if (pctx->token.type == isc_tokentype_string ||
1365 pctx->token.type == isc_tokentype_qstring) {
1366 if (pctx->token.type == isc_tokentype_string &&
1367 (strcasecmp(TOKEN_STRING(pctx), "key") == 0)) {
1368 CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret));
1370 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK |
1371 CFG_ADDR_V4PREFIXOK |
1374 CHECK(cfg_parse_netprefix(pctx, NULL, ret));
1376 CHECK(cfg_parse_astring(pctx, NULL, ret));
1379 } else if (pctx->token.type == isc_tokentype_special) {
1380 if (pctx->token.value.as_char == '{') {
1381 /* Nested match list. */
1382 CHECK(cfg_parse_obj(pctx, &cfg_type_bracketed_aml, ret));
1383 } else if (pctx->token.value.as_char == '!') {
1384 CHECK(cfg_gettoken(pctx, 0)); /* read "!" */
1385 CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret));
1391 cfg_parser_error(pctx, CFG_LOG_NEAR,
1392 "expected IP match list element");
1393 return (ISC_R_UNEXPECTEDTOKEN);
1400 * A negated address match list element (like "! 10.0.0.1").
1401 * Somewhat sneakily, the caller is expected to parse the
1402 * "!", but not to print it.
1405 static cfg_tuplefielddef_t negated_fields[] = {
1406 { "value", &cfg_type_addrmatchelt, 0 },
1411 print_negated(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1412 cfg_print_chars(pctx, "!", 1);
1413 cfg_print_tuple(pctx, obj);
1416 static cfg_type_t cfg_type_negated = {
1417 "negated", cfg_parse_tuple, print_negated, NULL, &cfg_rep_tuple,
1421 /* An address match list element */
1423 static cfg_type_t cfg_type_addrmatchelt = {
1424 "address_match_element", parse_addrmatchelt, NULL, cfg_doc_terminal,
1428 /* A bracketed address match list */
1430 static cfg_type_t cfg_type_bracketed_aml = {
1431 "bracketed_aml", cfg_parse_bracketed_list, cfg_print_bracketed_list,
1432 cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_addrmatchelt
1436 * The socket address syntax in the "controls" statement is silly.
1437 * It allows both socket address families, but also allows "*",
1438 * whis is gratuitously interpreted as the IPv4 wildcard address.
1440 static unsigned int controls_sockaddr_flags =
1441 CFG_ADDR_V4OK | CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
1442 static cfg_type_t cfg_type_controls_sockaddr = {
1443 "controls_sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr,
1444 cfg_doc_sockaddr, &cfg_rep_sockaddr, &controls_sockaddr_flags
1448 * Handle the special kludge syntax of the "keys" clause in the "server"
1449 * statement, which takes a single key with or without braces and semicolon.
1452 parse_server_key_kludge(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
1454 isc_result_t result;
1455 isc_boolean_t braces = ISC_FALSE;
1458 /* Allow opening brace. */
1459 CHECK(cfg_peektoken(pctx, 0));
1460 if (pctx->token.type == isc_tokentype_special &&
1461 pctx->token.value.as_char == '{') {
1462 result = cfg_gettoken(pctx, 0);
1466 CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
1469 /* Skip semicolon if present. */
1470 CHECK(cfg_peektoken(pctx, 0));
1471 if (pctx->token.type == isc_tokentype_special &&
1472 pctx->token.value.as_char == ';')
1473 CHECK(cfg_gettoken(pctx, 0));
1475 CHECK(cfg_parse_special(pctx, '}'));
1480 static cfg_type_t cfg_type_server_key_kludge = {
1481 "server_key", parse_server_key_kludge, NULL, cfg_doc_terminal,
1487 * An optional logging facility.
1491 parse_optional_facility(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
1493 isc_result_t result;
1496 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
1497 if (pctx->token.type == isc_tokentype_string ||
1498 pctx->token.type == isc_tokentype_qstring) {
1499 CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
1501 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
1507 static cfg_type_t cfg_type_optional_facility = {
1508 "optional_facility", parse_optional_facility, NULL, cfg_doc_terminal,
1513 * A log severity. Return as a string, except "debug N",
1514 * which is returned as a keyword object.
1517 static keyword_type_t debug_kw = { "debug", &cfg_type_uint32 };
1518 static cfg_type_t cfg_type_debuglevel = {
1519 "debuglevel", parse_keyvalue,
1520 print_keyvalue, doc_keyvalue,
1521 &cfg_rep_uint32, &debug_kw
1525 parse_logseverity(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1526 isc_result_t result;
1529 CHECK(cfg_peektoken(pctx, 0));
1530 if (pctx->token.type == isc_tokentype_string &&
1531 strcasecmp(TOKEN_STRING(pctx), "debug") == 0) {
1532 CHECK(cfg_gettoken(pctx, 0)); /* read "debug" */
1533 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER));
1534 if (pctx->token.type == isc_tokentype_number) {
1535 CHECK(cfg_parse_uint32(pctx, NULL, ret));
1538 * The debug level is optional and defaults to 1.
1539 * This makes little sense, but we support it for
1540 * compatibility with BIND 8.
1542 CHECK(cfg_create_obj(pctx, &cfg_type_uint32, ret));
1543 (*ret)->value.uint32 = 1;
1545 (*ret)->type = &cfg_type_debuglevel; /* XXX kludge */
1547 CHECK(cfg_parse_obj(pctx, &cfg_type_loglevel, ret));
1553 static cfg_type_t cfg_type_logseverity = {
1554 "log_severity", parse_logseverity, NULL, cfg_doc_terminal,
1558 * The "file" clause of the "channel" statement.
1559 * This is yet another special case.
1562 static const char *logversions_enums[] = { "unlimited", NULL };
1564 parse_logversions(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1565 return (parse_enum_or_other(pctx, type, &cfg_type_uint32, ret));
1567 static cfg_type_t cfg_type_logversions = {
1568 "logversions", parse_logversions, cfg_print_ustring, cfg_doc_terminal,
1569 &cfg_rep_string, logversions_enums
1572 static cfg_tuplefielddef_t logfile_fields[] = {
1573 { "file", &cfg_type_qstring, 0 },
1574 { "versions", &cfg_type_logversions, 0 },
1575 { "size", &cfg_type_size, 0 },
1580 parse_logfile(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1581 isc_result_t result;
1582 cfg_obj_t *obj = NULL;
1583 const cfg_tuplefielddef_t *fields = type->of;
1585 CHECK(cfg_create_tuple(pctx, type, &obj));
1587 /* Parse the mandatory "file" field */
1588 CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
1590 /* Parse "versions" and "size" fields in any order. */
1592 CHECK(cfg_peektoken(pctx, 0));
1593 if (pctx->token.type == isc_tokentype_string) {
1594 CHECK(cfg_gettoken(pctx, 0));
1595 if (strcasecmp(TOKEN_STRING(pctx),
1597 obj->value.tuple[1] == NULL) {
1598 CHECK(cfg_parse_obj(pctx, fields[1].type,
1599 &obj->value.tuple[1]));
1600 } else if (strcasecmp(TOKEN_STRING(pctx),
1602 obj->value.tuple[2] == NULL) {
1603 CHECK(cfg_parse_obj(pctx, fields[2].type,
1604 &obj->value.tuple[2]));
1613 /* Create void objects for missing optional values. */
1614 if (obj->value.tuple[1] == NULL)
1615 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1]));
1616 if (obj->value.tuple[2] == NULL)
1617 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2]));
1620 return (ISC_R_SUCCESS);
1628 print_logfile(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1629 cfg_print_obj(pctx, obj->value.tuple[0]); /* file */
1630 if (obj->value.tuple[1]->type->print != cfg_print_void) {
1631 cfg_print_chars(pctx, " versions ", 10);
1632 cfg_print_obj(pctx, obj->value.tuple[1]);
1634 if (obj->value.tuple[2]->type->print != cfg_print_void) {
1635 cfg_print_chars(pctx, " size ", 6);
1636 cfg_print_obj(pctx, obj->value.tuple[2]);
1640 static cfg_type_t cfg_type_logfile = {
1641 "log_file", parse_logfile, print_logfile, cfg_doc_terminal,
1642 &cfg_rep_tuple, logfile_fields
1645 /* An IPv4/IPv6 address with optional port, "*" accepted as wildcard. */
1646 static unsigned int sockaddr4wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V4OK;
1647 static cfg_type_t cfg_type_sockaddr4wild = {
1648 "sockaddr4wild", cfg_parse_sockaddr, cfg_print_sockaddr,
1649 cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr4wild_flags
1652 static unsigned int sockaddr6wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V6OK;
1653 static cfg_type_t cfg_type_sockaddr6wild = {
1654 "v6addrportwild", cfg_parse_sockaddr, cfg_print_sockaddr,
1655 cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr6wild_flags
1662 static cfg_tuplefielddef_t lwres_view_fields[] = {
1663 { "name", &cfg_type_astring, 0 },
1664 { "class", &cfg_type_optional_class, 0 },
1667 static cfg_type_t cfg_type_lwres_view = {
1668 "lwres_view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
1672 static cfg_type_t cfg_type_lwres_searchlist = {
1673 "lwres_searchlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
1674 &cfg_rep_list, &cfg_type_astring };
1676 static cfg_clausedef_t
1678 { "listen-on", &cfg_type_portiplist, 0 },
1679 { "view", &cfg_type_lwres_view, 0 },
1680 { "search", &cfg_type_lwres_searchlist, 0 },
1681 { "ndots", &cfg_type_uint32, 0 },
1685 static cfg_clausedef_t *
1686 lwres_clausesets[] = {
1690 static cfg_type_t cfg_type_lwres = {
1691 "lwres", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, lwres_clausesets };
1697 static cfg_clausedef_t
1698 rndcconf_options_clauses[] = {
1699 { "default-server", &cfg_type_astring, 0 },
1700 { "default-key", &cfg_type_astring, 0 },
1701 { "default-port", &cfg_type_uint32, 0 },
1705 static cfg_clausedef_t *
1706 rndcconf_options_clausesets[] = {
1707 rndcconf_options_clauses,
1711 static cfg_type_t cfg_type_rndcconf_options = {
1712 "rndcconf_options", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
1713 rndcconf_options_clausesets
1716 static cfg_clausedef_t
1717 rndcconf_server_clauses[] = {
1718 { "key", &cfg_type_astring, 0 },
1719 { "port", &cfg_type_uint32, 0 },
1723 static cfg_clausedef_t *
1724 rndcconf_server_clausesets[] = {
1725 rndcconf_server_clauses,
1729 static cfg_type_t cfg_type_rndcconf_server = {
1730 "rndcconf_server", cfg_parse_named_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
1731 rndcconf_server_clausesets
1734 static cfg_clausedef_t
1735 rndcconf_clauses[] = {
1736 { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
1737 { "server", &cfg_type_rndcconf_server, CFG_CLAUSEFLAG_MULTI },
1738 { "options", &cfg_type_rndcconf_options, 0 },
1742 static cfg_clausedef_t *
1743 rndcconf_clausesets[] = {
1748 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndcconf = {
1749 "rndcconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
1750 &cfg_rep_map, rndcconf_clausesets
1753 static cfg_clausedef_t
1754 rndckey_clauses[] = {
1755 { "key", &cfg_type_key, 0 },
1759 static cfg_clausedef_t *
1760 rndckey_clausesets[] = {
1765 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndckey = {
1766 "rndckey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
1767 &cfg_rep_map, rndckey_clausesets
1770 static cfg_tuplefielddef_t nameport_fields[] = {
1771 { "name", &cfg_type_astring, 0 },
1772 { "port", &cfg_type_optional_port, 0 },
1775 static cfg_type_t cfg_type_nameport = {
1776 "nameport", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
1777 &cfg_rep_tuple, nameport_fields
1781 doc_sockaddrnameport(cfg_printer_t *pctx, const cfg_type_t *type) {
1783 cfg_print_chars(pctx, "( ", 2);
1784 cfg_print_cstr(pctx, "<quoted_string>");
1785 cfg_print_chars(pctx, " ", 1);
1786 cfg_print_cstr(pctx, "[port <integer>]");
1787 cfg_print_chars(pctx, " | ", 3);
1788 cfg_print_cstr(pctx, "<ipv4_address>");
1789 cfg_print_chars(pctx, " ", 1);
1790 cfg_print_cstr(pctx, "[port <integer>]");
1791 cfg_print_chars(pctx, " | ", 3);
1792 cfg_print_cstr(pctx, "<ipv6_address>");
1793 cfg_print_chars(pctx, " ", 1);
1794 cfg_print_cstr(pctx, "[port <integer>]");
1795 cfg_print_chars(pctx, " )", 2);
1799 parse_sockaddrnameport(cfg_parser_t *pctx, const cfg_type_t *type,
1802 isc_result_t result;
1803 cfg_obj_t *obj = NULL;
1806 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
1807 if (pctx->token.type == isc_tokentype_string ||
1808 pctx->token.type == isc_tokentype_qstring) {
1809 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
1810 CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, ret));
1812 const cfg_tuplefielddef_t *fields =
1813 cfg_type_nameport.of;
1814 CHECK(cfg_create_tuple(pctx, &cfg_type_nameport,
1816 CHECK(cfg_parse_obj(pctx, fields[0].type,
1817 &obj->value.tuple[0]));
1818 CHECK(cfg_parse_obj(pctx, fields[1].type,
1819 &obj->value.tuple[1]));
1824 cfg_parser_error(pctx, CFG_LOG_NEAR,
1825 "expected IP address or hostname");
1826 return (ISC_R_UNEXPECTEDTOKEN);
1833 static cfg_type_t cfg_type_sockaddrnameport = {
1834 "sockaddrnameport_element", parse_sockaddrnameport, NULL,
1835 doc_sockaddrnameport, NULL, NULL
1838 static cfg_type_t cfg_type_bracketed_sockaddrnameportlist = {
1839 "bracketed_sockaddrnameportlist", cfg_parse_bracketed_list,
1840 cfg_print_bracketed_list, cfg_doc_bracketed_list,
1841 &cfg_rep_list, &cfg_type_sockaddrnameport
1845 * A list of socket addresses or name with an optional default port,
1846 * as used in the dual-stack-servers option. E.g.,
1847 * "port 1234 { dual-stack-servers.net; 10.0.0.1; 1::2 port 69; }"
1849 static cfg_tuplefielddef_t nameportiplist_fields[] = {
1850 { "port", &cfg_type_optional_port, 0 },
1851 { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 },
1855 static cfg_type_t cfg_type_nameportiplist = {
1856 "nameportiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
1857 &cfg_rep_tuple, nameportiplist_fields
1865 doc_masterselement(cfg_printer_t *pctx, const cfg_type_t *type) {
1867 cfg_print_chars(pctx, "( ", 2);
1868 cfg_print_cstr(pctx, "<masters>");
1869 cfg_print_chars(pctx, " | ", 3);
1870 cfg_print_cstr(pctx, "<ipv4_address>");
1871 cfg_print_chars(pctx, " ", 1);
1872 cfg_print_cstr(pctx, "[port <integer>]");
1873 cfg_print_chars(pctx, " | ", 3);
1874 cfg_print_cstr(pctx, "<ipv6_address>");
1875 cfg_print_chars(pctx, " ", 1);
1876 cfg_print_cstr(pctx, "[port <integer>]");
1877 cfg_print_chars(pctx, " )", 2);
1881 parse_masterselement(cfg_parser_t *pctx, const cfg_type_t *type,
1884 isc_result_t result;
1885 cfg_obj_t *obj = NULL;
1888 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
1889 if (pctx->token.type == isc_tokentype_string ||
1890 pctx->token.type == isc_tokentype_qstring) {
1891 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
1892 CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, ret));
1894 CHECK(cfg_parse_astring(pctx, &cfg_type_astring, ret));
1896 cfg_parser_error(pctx, CFG_LOG_NEAR,
1897 "expected IP address or masters name");
1898 return (ISC_R_UNEXPECTEDTOKEN);
1905 static cfg_type_t cfg_type_masterselement = {
1906 "masters_element", parse_masterselement, NULL,
1907 doc_masterselement, NULL, NULL