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