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