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