namedconf.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2002, 2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*! \file */
00019 
00020 #include <config.h>
00021 
00022 #include <string.h>
00023 
00024 #include <isc/lex.h>
00025 #include <isc/mem.h>
00026 #include <isc/result.h>
00027 #include <isc/string.h>
00028 #include <isc/util.h>
00029 
00030 #include <dns/ttl.h>
00031 #include <dns/result.h>
00032 
00033 #include <isccfg/cfg.h>
00034 #include <isccfg/grammar.h>
00035 #include <isccfg/log.h>
00036 
00037 #define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
00038 
00039 /*% Check a return value. */
00040 #define CHECK(op)                                               \
00041         do { result = (op);                                     \
00042                 if (result != ISC_R_SUCCESS) goto cleanup;      \
00043         } while (0)
00044 
00045 /*% Clean up a configuration object if non-NULL. */
00046 #define CLEANUP_OBJ(obj) \
00047         do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
00048 
00049 
00050 /*%
00051  * Forward declarations of static functions.
00052  */
00053 
00054 static isc_result_t
00055 parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
00056                     const cfg_type_t *othertype, cfg_obj_t **ret);
00057 
00058 static void
00059 doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *type);
00060 
00061 static isc_result_t
00062 parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
00063 
00064 static isc_result_t
00065 parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
00066                         cfg_obj_t **ret);
00067 
00068 static isc_result_t
00069 parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
00070                    cfg_obj_t **ret);
00071 static void
00072 print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj);
00073 
00074 static void
00075 doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type);
00076 
00077 static void
00078 print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj);
00079 
00080 static void
00081 doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
00082 
00083 static void
00084 doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
00085 
00086 #ifdef HAVE_GEOIP
00087 static isc_result_t
00088 parse_geoip(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
00089 
00090 static void
00091 print_geoip(cfg_printer_t *pctx, const cfg_obj_t *obj);
00092 
00093 static void
00094 doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type);
00095 #endif /* HAVE_GEOIP */
00096 
00097 static cfg_type_t cfg_type_acl;
00098 static cfg_type_t cfg_type_addrmatchelt;
00099 static cfg_type_t cfg_type_bracketed_aml;
00100 static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
00101 static cfg_type_t cfg_type_bracketed_dscpsockaddrlist;
00102 static cfg_type_t cfg_type_bracketed_sockaddrlist;
00103 static cfg_type_t cfg_type_bracketed_sockaddrnameportlist;
00104 static cfg_type_t cfg_type_controls;
00105 static cfg_type_t cfg_type_controls_sockaddr;
00106 static cfg_type_t cfg_type_destinationlist;
00107 static cfg_type_t cfg_type_dialuptype;
00108 static cfg_type_t cfg_type_ixfrdifftype;
00109 static cfg_type_t cfg_type_key;
00110 static cfg_type_t cfg_type_logfile;
00111 static cfg_type_t cfg_type_logging;
00112 static cfg_type_t cfg_type_logseverity;
00113 static cfg_type_t cfg_type_lwres;
00114 static cfg_type_t cfg_type_masterselement;
00115 static cfg_type_t cfg_type_maxttl;
00116 static cfg_type_t cfg_type_nameportiplist;
00117 static cfg_type_t cfg_type_negated;
00118 static cfg_type_t cfg_type_notifytype;
00119 static cfg_type_t cfg_type_optional_allow;
00120 static cfg_type_t cfg_type_optional_class;
00121 static cfg_type_t cfg_type_optional_facility;
00122 static cfg_type_t cfg_type_optional_keyref;
00123 static cfg_type_t cfg_type_optional_port;
00124 static cfg_type_t cfg_type_optional_dscp;
00125 static cfg_type_t cfg_type_options;
00126 static cfg_type_t cfg_type_portiplist;
00127 static cfg_type_t cfg_type_querysource4;
00128 static cfg_type_t cfg_type_querysource6;
00129 static cfg_type_t cfg_type_querysource;
00130 static cfg_type_t cfg_type_server;
00131 static cfg_type_t cfg_type_server_key_kludge;
00132 static cfg_type_t cfg_type_size;
00133 static cfg_type_t cfg_type_sizenodefault;
00134 static cfg_type_t cfg_type_sockaddr4wild;
00135 static cfg_type_t cfg_type_sockaddr6wild;
00136 static cfg_type_t cfg_type_statschannels;
00137 static cfg_type_t cfg_type_ttlval;
00138 static cfg_type_t cfg_type_view;
00139 static cfg_type_t cfg_type_viewopts;
00140 static cfg_type_t cfg_type_zone;
00141 static cfg_type_t cfg_type_zoneopts;
00142 static cfg_type_t cfg_type_filter_aaaa;
00143 static cfg_type_t cfg_type_dlz;
00144 
00145 /*% tkey-dhkey */
00146 
00147 static cfg_tuplefielddef_t tkey_dhkey_fields[] = {
00148         { "name", &cfg_type_qstring, 0 },
00149         { "keyid", &cfg_type_uint32, 0 },
00150         { NULL, NULL, 0 }
00151 };
00152 
00153 static cfg_type_t cfg_type_tkey_dhkey = {
00154         "tkey-dhkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
00155         tkey_dhkey_fields
00156 };
00157 
00158 /*% listen-on */
00159 
00160 static cfg_tuplefielddef_t listenon_fields[] = {
00161         { "port", &cfg_type_optional_port, 0 },
00162         { "dscp", &cfg_type_optional_dscp, 0 },
00163         { "acl", &cfg_type_bracketed_aml, 0 },
00164         { NULL, NULL, 0 }
00165 };
00166 
00167 static cfg_type_t cfg_type_listenon = {
00168         "listenon", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
00169         &cfg_rep_tuple, listenon_fields
00170 };
00171 
00172 /*% acl */
00173 
00174 static cfg_tuplefielddef_t acl_fields[] = {
00175         { "name", &cfg_type_astring, 0 },
00176         { "value", &cfg_type_bracketed_aml, 0 },
00177         { NULL, NULL, 0 }
00178 };
00179 
00180 static cfg_type_t cfg_type_acl = {
00181         "acl", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, acl_fields };
00182 
00183 /*% masters */
00184 static cfg_tuplefielddef_t masters_fields[] = {
00185         { "name", &cfg_type_astring, 0 },
00186         { "port", &cfg_type_optional_port, 0 },
00187         { "dscp", &cfg_type_optional_dscp, 0 },
00188         { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
00189         { NULL, NULL, 0 }
00190 };
00191 
00192 static cfg_type_t cfg_type_masters = {
00193         "masters", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, masters_fields };
00194 
00195 /*%
00196  * "sockaddrkeylist", a list of socket addresses with optional keys
00197  * and an optional default port, as used in the masters option.
00198  * E.g.,
00199  *   "port 1234 { mymasters; 10.0.0.1 key foo; 1::2 port 69; }"
00200  */
00201 
00202 static cfg_tuplefielddef_t namesockaddrkey_fields[] = {
00203         { "masterselement", &cfg_type_masterselement, 0 },
00204         { "key", &cfg_type_optional_keyref, 0 },
00205         { NULL, NULL, 0 },
00206 };
00207 
00208 static cfg_type_t cfg_type_namesockaddrkey = {
00209         "namesockaddrkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
00210         namesockaddrkey_fields
00211 };
00212 
00213 static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = {
00214         "bracketed_namesockaddrkeylist", cfg_parse_bracketed_list,
00215         cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_namesockaddrkey
00216 };
00217 
00218 static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = {
00219         { "port", &cfg_type_optional_port, 0 },
00220         { "dscp", &cfg_type_optional_dscp, 0 },
00221         { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
00222         { NULL, NULL, 0 }
00223 };
00224 static cfg_type_t cfg_type_namesockaddrkeylist = {
00225         "sockaddrkeylist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
00226         namesockaddrkeylist_fields
00227 };
00228 
00229 /*%
00230  * A list of socket addresses with an optional default port, as used
00231  * in the lwresd 'listen-on' option.  E.g., "{ 10.0.0.1; 1::2 port 69; }"
00232  */
00233 static cfg_tuplefielddef_t portiplist_fields[] = {
00234         { "port", &cfg_type_optional_port, 0 },
00235         { "dscp", &cfg_type_optional_dscp, 0 },
00236         { "addresses", &cfg_type_bracketed_dscpsockaddrlist, 0 },
00237         { NULL, NULL, 0 }
00238 };
00239 static cfg_type_t cfg_type_portiplist = {
00240         "portiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
00241         &cfg_rep_tuple, portiplist_fields
00242 };
00243 
00244 /*%
00245  * A public key, as in the "pubkey" statement.
00246  */
00247 static cfg_tuplefielddef_t pubkey_fields[] = {
00248         { "flags", &cfg_type_uint32, 0 },
00249         { "protocol", &cfg_type_uint32, 0 },
00250         { "algorithm", &cfg_type_uint32, 0 },
00251         { "key", &cfg_type_qstring, 0 },
00252         { NULL, NULL, 0 }
00253 };
00254 static cfg_type_t cfg_type_pubkey = {
00255         "pubkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
00256         &cfg_rep_tuple, pubkey_fields };
00257 
00258 /*%
00259  * A list of RR types, used in grant statements.
00260  * Note that the old parser allows quotes around the RR type names.
00261  */
00262 static cfg_type_t cfg_type_rrtypelist = {
00263         "rrtypelist", cfg_parse_spacelist, cfg_print_spacelist,
00264         cfg_doc_terminal, &cfg_rep_list, &cfg_type_astring
00265 };
00266 
00267 static const char *mode_enums[] = { "grant", "deny", NULL };
00268 static cfg_type_t cfg_type_mode = {
00269         "mode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
00270         &cfg_rep_string, &mode_enums
00271 };
00272 
00273 static isc_result_t
00274 parse_matchtype(cfg_parser_t *pctx, const cfg_type_t *type,
00275                 cfg_obj_t **ret) {
00276         isc_result_t result;
00277 
00278         CHECK(cfg_peektoken(pctx, 0));
00279         if (pctx->token.type == isc_tokentype_string &&
00280             strcasecmp(TOKEN_STRING(pctx), "zonesub") == 0) {
00281                 pctx->flags |= CFG_PCTX_SKIP;
00282         }
00283         return (cfg_parse_enum(pctx, type, ret));
00284 
00285  cleanup:
00286         return (result);
00287 }
00288 
00289 static isc_result_t
00290 parse_matchname(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
00291         isc_result_t result;
00292         cfg_obj_t *obj = NULL;
00293 
00294         if ((pctx->flags & CFG_PCTX_SKIP) != 0) {
00295                 pctx->flags &= ~CFG_PCTX_SKIP;
00296                 CHECK(cfg_parse_void(pctx, NULL, &obj));
00297         } else
00298                 result = cfg_parse_astring(pctx, type, &obj);
00299 
00300         *ret = obj;
00301  cleanup:
00302         return (result);
00303 }
00304 
00305 static void
00306 doc_matchname(cfg_printer_t *pctx, const cfg_type_t *type) {
00307         cfg_print_cstr(pctx, "[ ");
00308         cfg_doc_obj(pctx, type->of);
00309         cfg_print_cstr(pctx, " ]");
00310 }
00311 
00312 static const char *matchtype_enums[] = {
00313         "name", "subdomain", "wildcard", "self", "selfsub", "selfwild",
00314         "krb5-self", "ms-self", "krb5-subdomain", "ms-subdomain",
00315         "tcp-self", "6to4-self", "zonesub", "external", NULL };
00316 
00317 static cfg_type_t cfg_type_matchtype = {
00318         "matchtype", parse_matchtype, cfg_print_ustring,
00319         cfg_doc_enum, &cfg_rep_string, &matchtype_enums
00320 };
00321 
00322 static cfg_type_t cfg_type_matchname = {
00323         "optional_matchname", parse_matchname, cfg_print_ustring,
00324         &doc_matchname, &cfg_rep_tuple, &cfg_type_ustring
00325 };
00326 
00327 /*%
00328  * A grant statement, used in the update policy.
00329  */
00330 static cfg_tuplefielddef_t grant_fields[] = {
00331         { "mode", &cfg_type_mode, 0 },
00332         { "identity", &cfg_type_astring, 0 }, /* domain name */
00333         { "matchtype", &cfg_type_matchtype, 0 },
00334         { "name", &cfg_type_matchname, 0 }, /* domain name */
00335         { "types", &cfg_type_rrtypelist, 0 },
00336         { NULL, NULL, 0 }
00337 };
00338 static cfg_type_t cfg_type_grant = {
00339         "grant", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
00340          &cfg_rep_tuple, grant_fields
00341 };
00342 
00343 static cfg_type_t cfg_type_updatepolicy = {
00344         "update_policy", parse_updatepolicy, print_updatepolicy,
00345         doc_updatepolicy, &cfg_rep_list, &cfg_type_grant
00346 };
00347 
00348 static isc_result_t
00349 parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
00350                    cfg_obj_t **ret) {
00351         isc_result_t result;
00352         CHECK(cfg_gettoken(pctx, 0));
00353         if (pctx->token.type == isc_tokentype_special &&
00354             pctx->token.value.as_char == '{') {
00355                 cfg_ungettoken(pctx);
00356                 return (cfg_parse_bracketed_list(pctx, type, ret));
00357         }
00358 
00359         if (pctx->token.type == isc_tokentype_string &&
00360             strcasecmp(TOKEN_STRING(pctx), "local") == 0) {
00361                 cfg_obj_t *obj = NULL;
00362                 CHECK(cfg_create_obj(pctx, &cfg_type_ustring, &obj));
00363                 obj->value.string.length = strlen("local");
00364                 obj->value.string.base  = isc_mem_get(pctx->mctx,
00365                                                 obj->value.string.length + 1);
00366                 if (obj->value.string.base == NULL) {
00367                         isc_mem_put(pctx->mctx, obj, sizeof(*obj));
00368                         return (ISC_R_NOMEMORY);
00369                 }
00370                 memmove(obj->value.string.base, "local", 5);
00371                 obj->value.string.base[5] = '\0';
00372                 *ret = obj;
00373                 return (ISC_R_SUCCESS);
00374         }
00375 
00376         cfg_ungettoken(pctx);
00377         return (ISC_R_UNEXPECTEDTOKEN);
00378 
00379  cleanup:
00380         return (result);
00381 }
00382 
00383 static void
00384 print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00385         if (cfg_obj_isstring(obj))
00386                 cfg_print_ustring(pctx, obj);
00387         else
00388                 cfg_print_bracketed_list(pctx, obj);
00389 }
00390 
00391 static void
00392 doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type) {
00393         cfg_print_cstr(pctx, "( local | { ");
00394         cfg_doc_obj(pctx, type->of);
00395         cfg_print_cstr(pctx, "; ... }");
00396 }
00397 
00398 /*%
00399  * A view statement.
00400  */
00401 static cfg_tuplefielddef_t view_fields[] = {
00402         { "name", &cfg_type_astring, 0 },
00403         { "class", &cfg_type_optional_class, 0 },
00404         { "options", &cfg_type_viewopts, 0 },
00405         { NULL, NULL, 0 }
00406 };
00407 static cfg_type_t cfg_type_view = {
00408         "view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
00409          &cfg_rep_tuple, view_fields
00410 };
00411 
00412 /*%
00413  * A zone statement.
00414  */
00415 static cfg_tuplefielddef_t zone_fields[] = {
00416         { "name", &cfg_type_astring, 0 },
00417         { "class", &cfg_type_optional_class, 0 },
00418         { "options", &cfg_type_zoneopts, 0 },
00419         { NULL, NULL, 0 }
00420 };
00421 static cfg_type_t cfg_type_zone = {
00422         "zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
00423         &cfg_rep_tuple, zone_fields
00424 };
00425 
00426 /*%
00427  * A "category" clause in the "logging" statement.
00428  */
00429 static cfg_tuplefielddef_t category_fields[] = {
00430         { "name", &cfg_type_astring, 0 },
00431         { "destinations", &cfg_type_destinationlist,0 },
00432         { NULL, NULL, 0 }
00433 };
00434 static cfg_type_t cfg_type_category = {
00435         "category", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
00436         &cfg_rep_tuple, category_fields
00437 };
00438 
00439 
00440 /*%
00441  * A dnssec key, as used in the "trusted-keys" statement.
00442  */
00443 static cfg_tuplefielddef_t dnsseckey_fields[] = {
00444         { "name", &cfg_type_astring, 0 },
00445         { "flags", &cfg_type_uint32, 0 },
00446         { "protocol", &cfg_type_uint32, 0 },
00447         { "algorithm", &cfg_type_uint32, 0 },
00448         { "key", &cfg_type_qstring, 0 },
00449         { NULL, NULL, 0 }
00450 };
00451 static cfg_type_t cfg_type_dnsseckey = {
00452         "dnsseckey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
00453         &cfg_rep_tuple, dnsseckey_fields
00454 };
00455 
00456 /*%
00457  * A managed key initialization specifier, as used in the
00458  * "managed-keys" statement.
00459  */
00460 static cfg_tuplefielddef_t managedkey_fields[] = {
00461         { "name", &cfg_type_astring, 0 },
00462         { "init", &cfg_type_ustring, 0 },   /* must be literal "initial-key" */
00463         { "flags", &cfg_type_uint32, 0 },
00464         { "protocol", &cfg_type_uint32, 0 },
00465         { "algorithm", &cfg_type_uint32, 0 },
00466         { "key", &cfg_type_qstring, 0 },
00467         { NULL, NULL, 0 }
00468 };
00469 static cfg_type_t cfg_type_managedkey = {
00470         "managedkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
00471         &cfg_rep_tuple, managedkey_fields
00472 };
00473 
00474 static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring };
00475 
00476 static cfg_type_t cfg_type_optional_wild_class = {
00477         "optional_wild_class", parse_optional_keyvalue, print_keyvalue,
00478         doc_optional_keyvalue, &cfg_rep_string, &wild_class_kw
00479 };
00480 
00481 static keyword_type_t wild_type_kw = { "type", &cfg_type_ustring };
00482 
00483 static cfg_type_t cfg_type_optional_wild_type = {
00484         "optional_wild_type", parse_optional_keyvalue,
00485         print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_type_kw
00486 };
00487 
00488 static keyword_type_t wild_name_kw = { "name", &cfg_type_qstring };
00489 
00490 static cfg_type_t cfg_type_optional_wild_name = {
00491         "optional_wild_name", parse_optional_keyvalue,
00492         print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_name_kw
00493 };
00494 
00495 /*%
00496  * An rrset ordering element.
00497  */
00498 static cfg_tuplefielddef_t rrsetorderingelement_fields[] = {
00499         { "class", &cfg_type_optional_wild_class, 0 },
00500         { "type", &cfg_type_optional_wild_type, 0 },
00501         { "name", &cfg_type_optional_wild_name, 0 },
00502         { "order", &cfg_type_ustring, 0 }, /* must be literal "order" */
00503         { "ordering", &cfg_type_ustring, 0 },
00504         { NULL, NULL, 0 }
00505 };
00506 static cfg_type_t cfg_type_rrsetorderingelement = {
00507         "rrsetorderingelement", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
00508         rrsetorderingelement_fields
00509 };
00510 
00511 /*%
00512  * A global or view "check-names" option.  Note that the zone
00513  * "check-names" option has a different syntax.
00514  */
00515 
00516 static const char *checktype_enums[] = { "master", "slave", "response", NULL };
00517 static cfg_type_t cfg_type_checktype = {
00518         "checktype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
00519         &cfg_rep_string, &checktype_enums
00520 };
00521 
00522 static const char *checkmode_enums[] = { "fail", "warn", "ignore", NULL };
00523 static cfg_type_t cfg_type_checkmode = {
00524         "checkmode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
00525         &cfg_rep_string, &checkmode_enums
00526 };
00527 
00528 static const char *warn_enums[] = { "warn", "ignore", NULL };
00529 static cfg_type_t cfg_type_warn = {
00530         "warn", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
00531         &cfg_rep_string, &warn_enums
00532 };
00533 
00534 static cfg_tuplefielddef_t checknames_fields[] = {
00535         { "type", &cfg_type_checktype, 0 },
00536         { "mode", &cfg_type_checkmode, 0 },
00537         { NULL, NULL, 0 }
00538 };
00539 
00540 static cfg_type_t cfg_type_checknames = {
00541         "checknames", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
00542         &cfg_rep_tuple, checknames_fields
00543 };
00544 
00545 static cfg_type_t cfg_type_bracketed_dscpsockaddrlist = {
00546         "bracketed_sockaddrlist", cfg_parse_bracketed_list,
00547         cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list,
00548         &cfg_type_sockaddrdscp
00549 };
00550 
00551 static cfg_type_t cfg_type_bracketed_sockaddrlist = {
00552         "bracketed_sockaddrlist", cfg_parse_bracketed_list,
00553         cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list,
00554         &cfg_type_sockaddr
00555 };
00556 
00557 static const char *autodnssec_enums[] = { "allow", "maintain", "off", NULL };
00558 static cfg_type_t cfg_type_autodnssec = {
00559         "autodnssec", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
00560         &cfg_rep_string, &autodnssec_enums
00561 };
00562 
00563 static const char *dnssecupdatemode_enums[] = { "maintain", "no-resign", NULL };
00564 static cfg_type_t cfg_type_dnssecupdatemode = {
00565         "dnssecupdatemode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
00566         &cfg_rep_string, &dnssecupdatemode_enums
00567 };
00568 
00569 static const char *updatemethods_enums[] = {
00570         "increment", "unixtime", "date", NULL };
00571 static cfg_type_t cfg_type_updatemethod = {
00572         "updatemethod", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
00573         &cfg_rep_string, &updatemethods_enums
00574 };
00575 
00576 /*
00577  * zone-statistics: full, terse, or none.
00578  *
00579  * for backward compatibility, we also support boolean values.
00580  * yes represents "full", no represents "terse". in the future we
00581  * may change no to mean "none".
00582  */
00583 static const char *zonestat_enums[] = { "full", "terse", "none", NULL };
00584 static isc_result_t
00585 parse_zonestat(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
00586         return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
00587 }
00588 static cfg_type_t cfg_type_zonestat = {
00589         "zonestat", parse_zonestat, cfg_print_ustring, doc_enum_or_other,
00590         &cfg_rep_string, zonestat_enums
00591 };
00592 
00593 static cfg_type_t cfg_type_rrsetorder = {
00594         "rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list,
00595         cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_rrsetorderingelement
00596 };
00597 
00598 static keyword_type_t dscp_kw = { "dscp", &cfg_type_uint32 };
00599 
00600 static cfg_type_t cfg_type_optional_dscp = {
00601         "optional_dscp", parse_optional_keyvalue, print_keyvalue,
00602         doc_optional_keyvalue, &cfg_rep_uint32, &dscp_kw
00603 };
00604 
00605 static keyword_type_t port_kw = { "port", &cfg_type_uint32 };
00606 
00607 static cfg_type_t cfg_type_optional_port = {
00608         "optional_port", parse_optional_keyvalue, print_keyvalue,
00609         doc_optional_keyvalue, &cfg_rep_uint32, &port_kw
00610 };
00611 
00612 /*% A list of keys, as in the "key" clause of the controls statement. */
00613 static cfg_type_t cfg_type_keylist = {
00614         "keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
00615         cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring
00616 };
00617 
00618 /*% A list of dnssec keys, as in "trusted-keys" */
00619 static cfg_type_t cfg_type_dnsseckeys = {
00620         "dnsseckeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
00621         cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_dnsseckey
00622 };
00623 
00624 /*%
00625  * A list of managed key entries, as in "trusted-keys".  Currently
00626  * (9.7.0) this has a format similar to dnssec keys, except the keyname
00627  * is followed by the keyword "initial-key".  In future releases, this
00628  * keyword may take other values indicating different methods for the
00629  * key to be initialized.
00630  */
00631 
00632 static cfg_type_t cfg_type_managedkeys = {
00633         "managedkeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
00634         cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_managedkey
00635 };
00636 
00637 static const char *forwardtype_enums[] = { "first", "only", NULL };
00638 static cfg_type_t cfg_type_forwardtype = {
00639         "forwardtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
00640         &forwardtype_enums
00641 };
00642 
00643 static const char *zonetype_enums[] = {
00644         "master", "slave", "stub", "static-stub", "hint", "forward",
00645         "delegation-only", "redirect", NULL };
00646 static cfg_type_t cfg_type_zonetype = {
00647         "zonetype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
00648         &cfg_rep_string, &zonetype_enums
00649 };
00650 
00651 static const char *loglevel_enums[] = {
00652         "critical", "error", "warning", "notice", "info", "dynamic", NULL };
00653 static cfg_type_t cfg_type_loglevel = {
00654         "loglevel", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
00655         &loglevel_enums
00656 };
00657 
00658 static const char *transferformat_enums[] = {
00659         "many-answers", "one-answer", NULL };
00660 static cfg_type_t cfg_type_transferformat = {
00661         "transferformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
00662         &transferformat_enums
00663 };
00664 
00665 /*%
00666  * The special keyword "none", as used in the pid-file option.
00667  */
00668 
00669 static void
00670 print_none(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00671         UNUSED(obj);
00672         cfg_print_cstr(pctx, "none");
00673 }
00674 
00675 static cfg_type_t cfg_type_none = {
00676         "none", NULL, print_none, NULL, &cfg_rep_void, NULL
00677 };
00678 
00679 /*%
00680  * A quoted string or the special keyword "none".  Used in the pid-file option.
00681  */
00682 static isc_result_t
00683 parse_qstringornone(cfg_parser_t *pctx, const cfg_type_t *type,
00684                     cfg_obj_t **ret)
00685 {
00686         isc_result_t result;
00687 
00688         CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
00689         if (pctx->token.type == isc_tokentype_string &&
00690             strcasecmp(TOKEN_STRING(pctx), "none") == 0)
00691                 return (cfg_create_obj(pctx, &cfg_type_none, ret));
00692         cfg_ungettoken(pctx);
00693         return (cfg_parse_qstring(pctx, type, ret));
00694  cleanup:
00695         return (result);
00696 }
00697 
00698 static void
00699 doc_qstringornone(cfg_printer_t *pctx, const cfg_type_t *type) {
00700         UNUSED(type);
00701         cfg_print_cstr(pctx, "( <quoted_string> | none )");
00702 }
00703 
00704 static cfg_type_t cfg_type_qstringornone = {
00705         "qstringornone", parse_qstringornone, NULL, doc_qstringornone,
00706         NULL, NULL
00707 };
00708 
00709 /*%
00710  * A boolean ("yes" or "no"), or the special keyword "auto".
00711  * Used in the dnssec-validation option.
00712  */
00713 static void
00714 print_auto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00715         UNUSED(obj);
00716         cfg_print_cstr(pctx, "auto");
00717 }
00718 
00719 static cfg_type_t cfg_type_auto = {
00720         "auto", NULL, print_auto, NULL, &cfg_rep_void, NULL
00721 };
00722 
00723 static isc_result_t
00724 parse_boolorauto(cfg_parser_t *pctx, const cfg_type_t *type,
00725                     cfg_obj_t **ret)
00726 {
00727         isc_result_t result;
00728 
00729         CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
00730         if (pctx->token.type == isc_tokentype_string &&
00731             strcasecmp(TOKEN_STRING(pctx), "auto") == 0)
00732                 return (cfg_create_obj(pctx, &cfg_type_auto, ret));
00733         cfg_ungettoken(pctx);
00734         return (cfg_parse_boolean(pctx, type, ret));
00735  cleanup:
00736         return (result);
00737 }
00738 
00739 static void
00740 print_boolorauto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00741         if (obj->type->rep == &cfg_rep_void)
00742                 cfg_print_cstr(pctx, "auto");
00743         else if (obj->value.boolean)
00744                 cfg_print_cstr(pctx, "yes");
00745         else
00746                 cfg_print_cstr(pctx, "no");
00747 }
00748 
00749 static void
00750 doc_boolorauto(cfg_printer_t *pctx, const cfg_type_t *type) {
00751         UNUSED(type);
00752         cfg_print_cstr(pctx, "( yes | no | auto )");
00753 }
00754 
00755 static cfg_type_t cfg_type_boolorauto = {
00756         "boolorauto", parse_boolorauto, print_boolorauto,
00757         doc_boolorauto, NULL, NULL
00758 };
00759 
00760 /*%
00761  * keyword hostname
00762  */
00763 static void
00764 print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) {
00765         UNUSED(obj);
00766         cfg_print_cstr(pctx, "hostname");
00767 }
00768 
00769 static cfg_type_t cfg_type_hostname = {
00770         "hostname", NULL, print_hostname, NULL, &cfg_rep_boolean, NULL
00771 };
00772 
00773 /*%
00774  * "server-id" argument.
00775  */
00776 
00777 static isc_result_t
00778 parse_serverid(cfg_parser_t *pctx, const cfg_type_t *type,
00779                     cfg_obj_t **ret)
00780 {
00781         isc_result_t result;
00782         CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
00783         if (pctx->token.type == isc_tokentype_string &&
00784             strcasecmp(TOKEN_STRING(pctx), "none") == 0)
00785                 return (cfg_create_obj(pctx, &cfg_type_none, ret));
00786         if (pctx->token.type == isc_tokentype_string &&
00787             strcasecmp(TOKEN_STRING(pctx), "hostname") == 0) {
00788                 result = cfg_create_obj(pctx, &cfg_type_hostname, ret);
00789                 if (result == ISC_R_SUCCESS)
00790                         (*ret)->value.boolean = ISC_TRUE;
00791                 return (result);
00792         }
00793         cfg_ungettoken(pctx);
00794         return (cfg_parse_qstring(pctx, type, ret));
00795  cleanup:
00796         return (result);
00797 }
00798 
00799 static void
00800 doc_serverid(cfg_printer_t *pctx, const cfg_type_t *type) {
00801         UNUSED(type);
00802         cfg_print_cstr(pctx, "( <quoted_string> | none | hostname )");
00803 }
00804 
00805 static cfg_type_t cfg_type_serverid = {
00806         "serverid", parse_serverid, NULL, doc_serverid, NULL, NULL };
00807 
00808 /*%
00809  * Port list.
00810  */
00811 static cfg_tuplefielddef_t porttuple_fields[] = {
00812         { "loport", &cfg_type_uint32, 0 },
00813         { "hiport", &cfg_type_uint32, 0 },
00814         { NULL, NULL, 0 }
00815 };
00816 static cfg_type_t cfg_type_porttuple = {
00817         "porttuple", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
00818         &cfg_rep_tuple, porttuple_fields
00819 };
00820 
00821 static isc_result_t
00822 parse_port(cfg_parser_t *pctx, cfg_obj_t **ret) {
00823         isc_result_t result;
00824 
00825         CHECK(cfg_parse_uint32(pctx, NULL, ret));
00826         if ((*ret)->value.uint32 > 0xffff) {
00827                 cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid port");
00828                 cfg_obj_destroy(pctx, ret);
00829                 result = ISC_R_RANGE;
00830         }
00831 
00832  cleanup:
00833         return (result);
00834 }
00835 
00836 static isc_result_t
00837 parse_portrange(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
00838         isc_result_t result;
00839         cfg_obj_t *obj = NULL;
00840 
00841         UNUSED(type);
00842 
00843         CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
00844         if (pctx->token.type == isc_tokentype_number)
00845                 CHECK(parse_port(pctx, ret));
00846         else {
00847                 CHECK(cfg_gettoken(pctx, 0));
00848                 if (pctx->token.type != isc_tokentype_string ||
00849                     strcasecmp(TOKEN_STRING(pctx), "range") != 0) {
00850                         cfg_parser_error(pctx, CFG_LOG_NEAR,
00851                                          "expected integer or 'range'");
00852                         return (ISC_R_UNEXPECTEDTOKEN);
00853                 }
00854                 CHECK(cfg_create_tuple(pctx, &cfg_type_porttuple, &obj));
00855                 CHECK(parse_port(pctx, &obj->value.tuple[0]));
00856                 CHECK(parse_port(pctx, &obj->value.tuple[1]));
00857                 if (obj->value.tuple[0]->value.uint32 >
00858                     obj->value.tuple[1]->value.uint32) {
00859                         cfg_parser_error(pctx, CFG_LOG_NOPREP,
00860                                          "low port '%u' must not be larger "
00861                                          "than high port",
00862                                          obj->value.tuple[0]->value.uint32);
00863                         result = ISC_R_RANGE;
00864                         goto cleanup;
00865                 }
00866                 *ret = obj;
00867                 obj = NULL;
00868         }
00869 
00870  cleanup:
00871         if (obj != NULL)
00872                 cfg_obj_destroy(pctx, &obj);
00873         return (result);
00874 }
00875 
00876 static cfg_type_t cfg_type_portrange = {
00877         "portrange", parse_portrange, NULL, cfg_doc_terminal,
00878         NULL, NULL
00879 };
00880 
00881 static cfg_type_t cfg_type_bracketed_portlist = {
00882         "bracketed_sockaddrlist", cfg_parse_bracketed_list,
00883         cfg_print_bracketed_list, cfg_doc_bracketed_list,
00884         &cfg_rep_list, &cfg_type_portrange
00885 };
00886 
00887 /*%
00888  * Clauses that can be found within the top level of the named.conf
00889  * file only.
00890  */
00891 static cfg_clausedef_t
00892 namedconf_clauses[] = {
00893         { "options", &cfg_type_options, 0 },
00894         { "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
00895         { "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
00896         { "masters", &cfg_type_masters, CFG_CLAUSEFLAG_MULTI },
00897         { "logging", &cfg_type_logging, 0 },
00898         { "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI },
00899         { "lwres", &cfg_type_lwres, CFG_CLAUSEFLAG_MULTI },
00900         { "statistics-channels", &cfg_type_statschannels,
00901           CFG_CLAUSEFLAG_MULTI },
00902         { NULL, NULL, 0 }
00903 };
00904 
00905 /*%
00906  * Clauses that can occur at the top level or in the view
00907  * statement, but not in the options block.
00908  */
00909 static cfg_clausedef_t
00910 namedconf_or_view_clauses[] = {
00911         { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
00912         { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
00913         { "dlz", &cfg_type_dlz, CFG_CLAUSEFLAG_MULTI },
00914         { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI },
00915         { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
00916         { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
00917         { NULL, NULL, 0 }
00918 };
00919 
00920 /*%
00921  * Clauses that can occur in the bind.keys file.
00922  */
00923 static cfg_clausedef_t
00924 bindkeys_clauses[] = {
00925         { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
00926         { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
00927         { NULL, NULL, 0 }
00928 };
00929 
00930 /*%
00931  * Clauses that can be found within the 'options' statement.
00932  */
00933 static cfg_clausedef_t
00934 options_clauses[] = {
00935         { "automatic-interface-scan", &cfg_type_boolean, 0 },
00936         { "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
00937         { "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
00938         { "bindkeys-file", &cfg_type_qstring, 0 },
00939         { "blackhole", &cfg_type_bracketed_aml, 0 },
00940         { "coresize", &cfg_type_size, 0 },
00941         { "datasize", &cfg_type_size, 0 },
00942         { "session-keyfile", &cfg_type_qstringornone, 0 },
00943         { "session-keyname", &cfg_type_astring, 0 },
00944         { "session-keyalg", &cfg_type_astring, 0 },
00945         { "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
00946         { "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK },
00947         { "dscp", &cfg_type_uint32, 0 },
00948         { "dump-file", &cfg_type_qstring, 0 },
00949         { "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
00950         { "files", &cfg_type_size, 0 },
00951         { "flush-zones-on-shutdown", &cfg_type_boolean, 0 },
00952 #ifdef HAVE_GEOIP
00953         { "geoip-directory", &cfg_type_qstringornone, 0 },
00954         { "geoip-use-ecs", &cfg_type_boolean, 0 },
00955 #else
00956         { "geoip-directory", &cfg_type_qstringornone,
00957           CFG_CLAUSEFLAG_NOTCONFIGURED },
00958         { "geoip-use-ecs", &cfg_type_qstringornone,
00959           CFG_CLAUSEFLAG_NOTCONFIGURED },
00960 #endif /* HAVE_GEOIP */
00961         { "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
00962         { "heartbeat-interval", &cfg_type_uint32, 0 },
00963         { "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP },
00964         { "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
00965         { "hostname", &cfg_type_qstringornone, 0 },
00966         { "interface-interval", &cfg_type_uint32, 0 },
00967         { "keep-response-order", &cfg_type_bracketed_aml, 0 },
00968         { "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
00969         { "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
00970         { "lock-file", &cfg_type_qstringornone, 0 },
00971 #ifdef ISC_PLATFORM_USESIT
00972         { "sit-secret", &cfg_type_sstring, 0 },
00973 #else
00974         { "sit-secret", &cfg_type_sstring, CFG_CLAUSEFLAG_NOTCONFIGURED },
00975 #endif
00976         { "managed-keys-directory", &cfg_type_qstring, 0 },
00977         { "match-mapped-addresses", &cfg_type_boolean, 0 },
00978         { "max-rsa-exponent-size", &cfg_type_uint32, 0 },
00979         { "memstatistics-file", &cfg_type_qstring, 0 },
00980         { "memstatistics", &cfg_type_boolean, 0 },
00981         { "multiple-cnames", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
00982         { "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
00983         { "notify-rate", &cfg_type_uint32, 0 },
00984         { "pid-file", &cfg_type_qstringornone, 0 },
00985         { "port", &cfg_type_uint32, 0 },
00986         { "querylog", &cfg_type_boolean, 0 },
00987         { "recursing-file", &cfg_type_qstring, 0 },
00988         { "random-device", &cfg_type_qstring, 0 },
00989         { "recursive-clients", &cfg_type_uint32, 0 },
00990         { "reserved-sockets", &cfg_type_uint32, 0 },
00991         { "secroots-file", &cfg_type_qstring, 0 },
00992         { "serial-queries", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
00993         { "serial-query-rate", &cfg_type_uint32, 0 },
00994         { "server-id", &cfg_type_serverid, 0 },
00995         { "stacksize", &cfg_type_size, 0 },
00996         { "startup-notify-rate", &cfg_type_uint32, 0 },
00997         { "statistics-file", &cfg_type_qstring, 0 },
00998         { "statistics-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_NYI },
00999         { "tcp-clients", &cfg_type_uint32, 0 },
01000         { "tcp-listen-queue", &cfg_type_uint32, 0 },
01001         { "tkey-dhkey", &cfg_type_tkey_dhkey, 0 },
01002         { "tkey-gssapi-credential", &cfg_type_qstring, 0 },
01003         { "tkey-gssapi-keytab", &cfg_type_qstring, 0 },
01004         { "tkey-domain", &cfg_type_qstring, 0 },
01005         { "transfers-per-ns", &cfg_type_uint32, 0 },
01006         { "transfers-in", &cfg_type_uint32, 0 },
01007         { "transfers-out", &cfg_type_uint32, 0 },
01008         { "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
01009         { "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
01010         { "use-ixfr", &cfg_type_boolean, 0 },
01011         { "use-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
01012         { "use-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
01013         { "version", &cfg_type_qstringornone, 0 },
01014         { NULL, NULL, 0 }
01015 };
01016 
01017 static cfg_type_t cfg_type_namelist = {
01018         "namelist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
01019         cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_qstring };
01020 
01021 static keyword_type_t exclude_kw = { "exclude", &cfg_type_namelist };
01022 
01023 static cfg_type_t cfg_type_optional_exclude = {
01024         "optional_exclude", parse_optional_keyvalue, print_keyvalue,
01025         doc_optional_keyvalue, &cfg_rep_list, &exclude_kw };
01026 
01027 static keyword_type_t exceptionnames_kw = { "except-from", &cfg_type_namelist };
01028 
01029 static cfg_type_t cfg_type_optional_exceptionnames = {
01030         "optional_allow", parse_optional_keyvalue, print_keyvalue,
01031         doc_optional_keyvalue, &cfg_rep_list, &exceptionnames_kw };
01032 
01033 static cfg_tuplefielddef_t denyaddresses_fields[] = {
01034         { "acl", &cfg_type_bracketed_aml, 0 },
01035         { "except-from", &cfg_type_optional_exceptionnames, 0 },
01036         { NULL, NULL, 0 }
01037 };
01038 
01039 static cfg_type_t cfg_type_denyaddresses = {
01040         "denyaddresses", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
01041         &cfg_rep_tuple, denyaddresses_fields
01042 };
01043 
01044 static cfg_tuplefielddef_t denyaliases_fields[] = {
01045         { "name", &cfg_type_namelist, 0 },
01046         { "except-from", &cfg_type_optional_exceptionnames, 0 },
01047         { NULL, NULL, 0 }
01048 };
01049 
01050 static cfg_type_t cfg_type_denyaliases = {
01051         "denyaliases", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
01052         &cfg_rep_tuple, denyaliases_fields
01053 };
01054 
01055 static cfg_type_t cfg_type_algorithmlist = {
01056         "algorithmlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
01057         cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring };
01058 
01059 static cfg_tuplefielddef_t disablealgorithm_fields[] = {
01060         { "name", &cfg_type_astring, 0 },
01061         { "algorithms", &cfg_type_algorithmlist, 0 },
01062         { NULL, NULL, 0 }
01063 };
01064 
01065 static cfg_type_t cfg_type_disablealgorithm = {
01066         "disablealgorithm", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
01067         &cfg_rep_tuple, disablealgorithm_fields
01068 };
01069 
01070 static cfg_type_t cfg_type_dsdigestlist = {
01071         "dsdigestlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
01072         cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring };
01073 
01074 static cfg_tuplefielddef_t disabledsdigest_fields[] = {
01075         { "name", &cfg_type_astring, 0 },
01076         { "digests", &cfg_type_dsdigestlist, 0 },
01077         { NULL, NULL, 0 }
01078 };
01079 
01080 static cfg_type_t cfg_type_disabledsdigest = {
01081         "disabledsdigest", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
01082         &cfg_rep_tuple, disabledsdigest_fields
01083 };
01084 
01085 static cfg_tuplefielddef_t mustbesecure_fields[] = {
01086         { "name", &cfg_type_astring, 0 },
01087         { "value", &cfg_type_boolean, 0 },
01088         { NULL, NULL, 0 }
01089 };
01090 
01091 static cfg_type_t cfg_type_mustbesecure = {
01092         "mustbesecure", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
01093         &cfg_rep_tuple, mustbesecure_fields
01094 };
01095 
01096 static const char *masterformat_enums[] = { "text", "raw", "map", NULL };
01097 static cfg_type_t cfg_type_masterformat = {
01098         "masterformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
01099         &cfg_rep_string, &masterformat_enums
01100 };
01101 
01102 static const char *masterstyle_enums[] = { "full", "relative", NULL };
01103 static cfg_type_t cfg_type_masterstyle = {
01104         "masterstyle", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
01105         &cfg_rep_string, &masterstyle_enums
01106 };
01107 
01108 
01109 /*%
01110  *  response-policy {
01111  *      zone <string> [ policy (given|disabled|passthru|drop|tcp-only|
01112  *                                      nxdomain|nodata|cname <domain> ) ]
01113  *                    [ recursive-only yes|no ] [ max-policy-ttl number ] ;
01114  *  } [ recursive-only yes|no ] [ max-policy-ttl number ] ;
01115  *       [ break-dnssec yes|no ] [ min-ns-dots number ]
01116  *       [ qname-wait-recurse yes|no ]
01117  */
01118 
01119 static void
01120 doc_rpz_policy(cfg_printer_t *pctx, const cfg_type_t *type) {
01121         const char * const *p;
01122         /*
01123          * This is cfg_doc_enum() without the trailing " )".
01124          */
01125         cfg_print_cstr(pctx, "( ");
01126         for (p = type->of; *p != NULL; p++) {
01127                 cfg_print_cstr(pctx, *p);
01128                 if (p[1] != NULL)
01129                         cfg_print_cstr(pctx, " | ");
01130         }
01131 }
01132 
01133 static void
01134 doc_rpz_cname(cfg_printer_t *pctx, const cfg_type_t *type) {
01135         cfg_doc_terminal(pctx, type);
01136         cfg_print_cstr(pctx, " )");
01137 }
01138 
01139 /*
01140  * Parse
01141  *      given|disabled|passthru|drop|tcp-only|nxdomain|nodata|cname <domain>
01142  */
01143 static isc_result_t
01144 cfg_parse_rpz_policy(cfg_parser_t *pctx, const cfg_type_t *type,
01145                      cfg_obj_t **ret)
01146 {
01147         isc_result_t result;
01148         cfg_obj_t *obj;
01149         const cfg_tuplefielddef_t *fields;
01150 
01151         CHECK(cfg_create_tuple(pctx, type, &obj));
01152 
01153         fields = type->of;
01154         CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
01155         /*
01156          * parse cname domain only after "policy cname"
01157          */
01158         if (strcasecmp("cname", cfg_obj_asstring(obj->value.tuple[0])) != 0) {
01159                 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1]));
01160         } else {
01161                 CHECK(cfg_parse_obj(pctx, fields[1].type,
01162                                     &obj->value.tuple[1]));
01163         }
01164 
01165         *ret = obj;
01166         return (ISC_R_SUCCESS);
01167 
01168 cleanup:
01169         CLEANUP_OBJ(obj);
01170         return (result);
01171 }
01172 
01173 /*
01174  * Parse a tuple consisting of any kind of  required field followed
01175  * by 2 or more optional keyvalues that can be in any order.
01176  */
01177 static isc_result_t
01178 cfg_parse_kv_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
01179         const cfg_tuplefielddef_t *fields, *f;
01180         cfg_obj_t *obj;
01181         int fn;
01182         isc_result_t result;
01183 
01184         obj = NULL;
01185         CHECK(cfg_create_tuple(pctx, type, &obj));
01186 
01187         /*
01188          * The zone first field is required and always first.
01189          */
01190         fields = type->of;
01191         CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
01192 
01193         for (;;) {
01194                 CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
01195                 if (pctx->token.type != isc_tokentype_string)
01196                         break;
01197 
01198                 for (fn = 1, f = &fields[1]; ; ++fn, ++f) {
01199                         if (f->name == NULL) {
01200                                 cfg_parser_error(pctx, 0, "unexpected '%s'",
01201                                                  TOKEN_STRING(pctx));
01202                                 result = ISC_R_UNEXPECTEDTOKEN;
01203                                 goto cleanup;
01204                         }
01205                         if (obj->value.tuple[fn] == NULL &&
01206                             strcasecmp(f->name, TOKEN_STRING(pctx)) == 0)
01207                                 break;
01208                 }
01209 
01210                 CHECK(cfg_gettoken(pctx, 0));
01211                 CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[fn]));
01212         }
01213 
01214         for (fn = 1, f = &fields[1]; f->name != NULL; ++fn, ++f) {
01215                 if (obj->value.tuple[fn] == NULL)
01216                         CHECK(cfg_parse_void(pctx, NULL,
01217                                              &obj->value.tuple[fn]));
01218         }
01219 
01220         *ret = obj;
01221         return (ISC_R_SUCCESS);
01222 
01223 cleanup:
01224         CLEANUP_OBJ(obj);
01225         return (result);
01226 }
01227 
01228 static void
01229 cfg_print_kv_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
01230         unsigned int i;
01231         const cfg_tuplefielddef_t *fields, *f;
01232         const cfg_obj_t *fieldobj;
01233 
01234         fields = obj->type->of;
01235         for (f = fields, i = 0; f->name != NULL; f++, i++) {
01236                 fieldobj = obj->value.tuple[i];
01237                 if (fieldobj->type->print == cfg_print_void)
01238                         continue;
01239                 if (i != 0) {
01240                         cfg_print_cstr(pctx, " ");
01241                         cfg_print_cstr(pctx, f->name);
01242                         cfg_print_cstr(pctx, " ");
01243                 }
01244                 cfg_print_obj(pctx, fieldobj);
01245         }
01246 }
01247 
01248 static void
01249 cfg_doc_kv_tuple(cfg_printer_t *pctx, const cfg_type_t *type) {
01250         const cfg_tuplefielddef_t *fields, *f;
01251 
01252         fields = type->of;
01253         for (f = fields; f->name != NULL; f++) {
01254                 if (f != fields) {
01255                         cfg_print_cstr(pctx, " [ ");
01256                         cfg_print_cstr(pctx, f->name);
01257                         if (f->type->doc != cfg_doc_void)
01258                                 cfg_print_cstr(pctx, " ");
01259                 }
01260                 cfg_doc_obj(pctx, f->type);
01261                 if (f != fields)
01262                         cfg_print_cstr(pctx, " ]");
01263         }
01264 }
01265 
01266 static keyword_type_t zone_kw = {"zone", &cfg_type_qstring};
01267 static cfg_type_t cfg_type_rpz_zone = {
01268         "zone", parse_keyvalue, print_keyvalue,
01269         doc_keyvalue, &cfg_rep_string,
01270         &zone_kw
01271 };
01272 /*
01273  * "no-op" is an obsolete equivalent of "passthru".
01274  */
01275 static const char *rpz_policies[] = {
01276         "given", "disabled", "passthru", "no-op", "drop", "tcp-only",
01277         "nxdomain", "nodata", "cname", NULL
01278 };
01279 static cfg_type_t cfg_type_rpz_policy_name = {
01280         "policy name", cfg_parse_enum, cfg_print_ustring,
01281         doc_rpz_policy, &cfg_rep_string,
01282         &rpz_policies
01283 };
01284 static cfg_type_t cfg_type_rpz_cname = {
01285         "quoted_string", cfg_parse_astring, NULL,
01286         doc_rpz_cname, &cfg_rep_string,
01287         NULL
01288 };
01289 static cfg_tuplefielddef_t rpz_policy_fields[] = {
01290         { "policy name", &cfg_type_rpz_policy_name, 0 },
01291         { "cname", &cfg_type_rpz_cname, 0 },
01292         { NULL, NULL, 0 }
01293 };
01294 static cfg_type_t cfg_type_rpz_policy = {
01295         "policy tuple", cfg_parse_rpz_policy,
01296         cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
01297         rpz_policy_fields
01298 };
01299 static cfg_tuplefielddef_t rpz_zone_fields[] = {
01300         { "zone name", &cfg_type_rpz_zone, 0 },
01301         { "policy", &cfg_type_rpz_policy, 0 },
01302         { "recursive-only", &cfg_type_boolean, 0 },
01303         { "max-policy-ttl", &cfg_type_uint32, 0 },
01304         { NULL, NULL, 0 }
01305 };
01306 static cfg_type_t cfg_type_rpz_tuple = {
01307         "rpz tuple", cfg_parse_kv_tuple,
01308         cfg_print_kv_tuple, cfg_doc_kv_tuple, &cfg_rep_tuple,
01309         rpz_zone_fields
01310 };
01311 static cfg_type_t cfg_type_rpz_list = {
01312         "zone list", cfg_parse_bracketed_list, cfg_print_bracketed_list,
01313         cfg_doc_bracketed_list, &cfg_rep_list,
01314         &cfg_type_rpz_tuple
01315 };
01316 static cfg_tuplefielddef_t rpz_fields[] = {
01317         { "zone list", &cfg_type_rpz_list, 0 },
01318         { "recursive-only", &cfg_type_boolean, 0 },
01319         { "break-dnssec", &cfg_type_boolean, 0 },
01320         { "max-policy-ttl", &cfg_type_uint32, 0 },
01321         { "min-ns-dots", &cfg_type_uint32, 0 },
01322         { "qname-wait-recurse", &cfg_type_boolean, 0 },
01323         { NULL, NULL, 0 }
01324 };
01325 static cfg_type_t cfg_type_rpz = {
01326         "rpz", cfg_parse_kv_tuple,
01327         cfg_print_kv_tuple, cfg_doc_kv_tuple, &cfg_rep_tuple,
01328         rpz_fields
01329 };
01330 
01331 
01332 /*
01333  * rate-limit
01334  */
01335 static cfg_clausedef_t rrl_clauses[] = {
01336         { "responses-per-second", &cfg_type_uint32, 0 },
01337         { "referrals-per-second", &cfg_type_uint32, 0 },
01338         { "nodata-per-second", &cfg_type_uint32, 0 },
01339         { "nxdomains-per-second", &cfg_type_uint32, 0 },
01340         { "errors-per-second", &cfg_type_uint32, 0 },
01341         { "all-per-second", &cfg_type_uint32, 0 },
01342         { "slip", &cfg_type_uint32, 0 },
01343         { "window", &cfg_type_uint32, 0 },
01344         { "log-only", &cfg_type_boolean, 0 },
01345         { "qps-scale", &cfg_type_uint32, 0 },
01346         { "ipv4-prefix-length", &cfg_type_uint32, 0 },
01347         { "ipv6-prefix-length", &cfg_type_uint32, 0 },
01348         { "exempt-clients", &cfg_type_bracketed_aml, 0 },
01349         { "max-table-size", &cfg_type_uint32, 0 },
01350         { "min-table-size", &cfg_type_uint32, 0 },
01351         { NULL, NULL, 0 }
01352 };
01353 
01354 static cfg_clausedef_t *rrl_clausesets[] = {
01355         rrl_clauses,
01356         NULL
01357 };
01358 
01359 static cfg_type_t cfg_type_rrl = {
01360         "rate-limit", cfg_parse_map, cfg_print_map, cfg_doc_map,
01361         &cfg_rep_map, rrl_clausesets
01362 };
01363 
01364 
01365 
01366 /*%
01367  * dnssec-lookaside
01368  */
01369 
01370 static void
01371 print_lookaside(cfg_printer_t *pctx, const cfg_obj_t *obj)
01372 {
01373         const cfg_obj_t *domain = obj->value.tuple[0];
01374 
01375         if (domain->value.string.length == 4 &&
01376             strncmp(domain->value.string.base, "auto", 4) == 0)
01377                 cfg_print_cstr(pctx, "auto");
01378         else
01379                 cfg_print_tuple(pctx, obj);
01380 }
01381 
01382 static void
01383 doc_lookaside(cfg_printer_t *pctx, const cfg_type_t *type) {
01384         UNUSED(type);
01385         cfg_print_cstr(pctx, "( <string> trust-anchor <string> | auto | no )");
01386 }
01387 
01388 static keyword_type_t trustanchor_kw = { "trust-anchor", &cfg_type_astring };
01389 
01390 static cfg_type_t cfg_type_optional_trustanchor = {
01391         "optional_trustanchor", parse_optional_keyvalue, print_keyvalue,
01392         doc_keyvalue, &cfg_rep_string, &trustanchor_kw
01393 };
01394 
01395 static cfg_tuplefielddef_t lookaside_fields[] = {
01396         { "domain", &cfg_type_astring, 0 },
01397         { "trust-anchor", &cfg_type_optional_trustanchor, 0 },
01398         { NULL, NULL, 0 }
01399 };
01400 
01401 static cfg_type_t cfg_type_lookaside = {
01402         "lookaside", cfg_parse_tuple, print_lookaside, doc_lookaside,
01403         &cfg_rep_tuple, lookaside_fields
01404 };
01405 
01406 static isc_result_t
01407 parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type,
01408                       cfg_obj_t **ret)
01409 {
01410         isc_result_t result;
01411         UNUSED(type);
01412 
01413         CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
01414         if (pctx->token.type == isc_tokentype_number) {
01415                 CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret));
01416         } else {
01417                 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
01418         }
01419  cleanup:
01420         return (result);
01421 }
01422 
01423 static void
01424 doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) {
01425         UNUSED(type);
01426         cfg_print_cstr(pctx, "[ <integer> ]");
01427 }
01428 
01429 static cfg_type_t cfg_type_optional_uint32 = {
01430         "optional_uint32", parse_optional_uint32, NULL, doc_optional_uint32,
01431         NULL, NULL };
01432 
01433 static cfg_tuplefielddef_t prefetch_fields[] = {
01434         { "trigger", &cfg_type_uint32, 0 },
01435         { "eligible", &cfg_type_optional_uint32, 0 },
01436         { NULL, NULL, 0 }
01437 };
01438 
01439 static cfg_type_t cfg_type_prefetch = {
01440         "prefetch", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
01441         &cfg_rep_tuple, prefetch_fields
01442 };
01443 /*
01444  * DNS64.
01445  */
01446 static cfg_clausedef_t
01447 dns64_clauses[] = {
01448         { "clients", &cfg_type_bracketed_aml, 0 },
01449         { "mapped", &cfg_type_bracketed_aml, 0 },
01450         { "exclude", &cfg_type_bracketed_aml, 0 },
01451         { "suffix", &cfg_type_netaddr6, 0 },
01452         { "recursive-only", &cfg_type_boolean, 0 },
01453         { "break-dnssec", &cfg_type_boolean, 0 },
01454         { NULL, NULL, 0 },
01455 };
01456 
01457 static cfg_clausedef_t *
01458 dns64_clausesets[] = {
01459         dns64_clauses,
01460         NULL
01461 };
01462 
01463 static cfg_type_t cfg_type_dns64 = {
01464         "dns64", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map,
01465         &cfg_rep_map, dns64_clausesets
01466 };
01467 
01468 /*%
01469  * Clauses that can be found within the 'view' statement,
01470  * with defaults in the 'options' statement.
01471  */
01472 
01473 static cfg_clausedef_t
01474 view_clauses[] = {
01475         { "acache-cleaning-interval", &cfg_type_uint32, 0 },
01476         { "acache-enable", &cfg_type_boolean, 0 },
01477         { "additional-from-auth", &cfg_type_boolean, 0 },
01478         { "additional-from-cache", &cfg_type_boolean, 0 },
01479         { "allow-new-zones", &cfg_type_boolean, 0 },
01480         { "allow-query-cache", &cfg_type_bracketed_aml, 0 },
01481         { "allow-query-cache-on", &cfg_type_bracketed_aml, 0 },
01482         { "allow-recursion", &cfg_type_bracketed_aml, 0 },
01483         { "allow-recursion-on", &cfg_type_bracketed_aml, 0 },
01484         { "allow-v6-synthesis", &cfg_type_bracketed_aml,
01485           CFG_CLAUSEFLAG_OBSOLETE },
01486         { "attach-cache", &cfg_type_astring, 0 },
01487         { "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT },
01488         { "cache-file", &cfg_type_qstring, 0 },
01489         { "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
01490         { "cleaning-interval", &cfg_type_uint32, 0 },
01491         { "clients-per-query", &cfg_type_uint32, 0 },
01492         { "deny-answer-addresses", &cfg_type_denyaddresses, 0 },
01493         { "deny-answer-aliases", &cfg_type_denyaliases, 0 },
01494         { "disable-algorithms", &cfg_type_disablealgorithm,
01495           CFG_CLAUSEFLAG_MULTI },
01496         { "disable-ds-digests", &cfg_type_disabledsdigest,
01497           CFG_CLAUSEFLAG_MULTI },
01498         { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI },
01499         { "dns64", &cfg_type_dns64, CFG_CLAUSEFLAG_MULTI },
01500         { "dns64-server", &cfg_type_astring, 0 },
01501         { "dns64-contact", &cfg_type_astring, 0 },
01502         { "dnssec-accept-expired", &cfg_type_boolean, 0 },
01503         { "dnssec-enable", &cfg_type_boolean, 0 },
01504         { "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI },
01505         { "dnssec-must-be-secure",  &cfg_type_mustbesecure,
01506           CFG_CLAUSEFLAG_MULTI },
01507         { "dnssec-validation", &cfg_type_boolorauto, 0 },
01508         { "dual-stack-servers", &cfg_type_nameportiplist, 0 },
01509         { "edns-udp-size", &cfg_type_uint32, 0 },
01510         { "empty-contact", &cfg_type_astring, 0 },
01511         { "empty-server", &cfg_type_astring, 0 },
01512         { "empty-zones-enable", &cfg_type_boolean, 0 },
01513         { "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
01514         { "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 },
01515         { "lame-ttl", &cfg_type_ttlval, 0 },
01516 #ifdef ISC_PLATFORM_USESIT
01517         { "nosit-udp-size", &cfg_type_uint32, 0 },
01518 #else
01519         { "nosit-udp-size", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTCONFIGURED },
01520 #endif
01521         { "max-acache-size", &cfg_type_sizenodefault, 0 },
01522         { "max-cache-size", &cfg_type_sizenodefault, 0 },
01523         { "max-cache-ttl", &cfg_type_uint32, 0 },
01524         { "max-clients-per-query", &cfg_type_uint32, 0 },
01525         { "max-ncache-ttl", &cfg_type_uint32, 0 },
01526         { "max-recursion-depth", &cfg_type_uint32, 0 },
01527         { "max-recursion-queries", &cfg_type_uint32, 0 },
01528         { "max-udp-size", &cfg_type_uint32, 0 },
01529         { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
01530         { "minimal-responses", &cfg_type_boolean, 0 },
01531         { "nta-recheck", &cfg_type_ttlval, 0 },
01532         { "nta-lifetime", &cfg_type_ttlval, 0 },
01533         { "nxdomain-redirect", &cfg_type_astring, 0 },
01534         { "prefetch", &cfg_type_prefetch, 0 },
01535         { "preferred-glue", &cfg_type_astring, 0 },
01536         { "no-case-compress", &cfg_type_bracketed_aml, 0 },
01537         { "provide-ixfr", &cfg_type_boolean, 0 },
01538         /*
01539          * Note that the query-source option syntax is different
01540          * from the other -source options.
01541          */
01542         { "query-source", &cfg_type_querysource4, 0 },
01543         { "query-source-v6", &cfg_type_querysource6, 0 },
01544         { "queryport-pool-ports", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
01545         { "queryport-pool-updateinterval", &cfg_type_uint32,
01546           CFG_CLAUSEFLAG_OBSOLETE },
01547         { "recursion", &cfg_type_boolean, 0 },
01548 #ifdef ISC_PLATFORM_USESIT
01549         { "request-sit", &cfg_type_boolean, 0 },
01550 #else
01551         { "request-sit", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTCONFIGURED },
01552 #endif
01553         { "request-nsid", &cfg_type_boolean, 0 },
01554         { "resolver-query-timeout", &cfg_type_uint32, 0 },
01555         { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
01556         { "root-delegation-only",  &cfg_type_optional_exclude, 0 },
01557         { "rrset-order", &cfg_type_rrsetorder, 0 },
01558         { "servfail-ttl", &cfg_type_ttlval, 0 },
01559         { "sortlist", &cfg_type_bracketed_aml, 0 },
01560         { "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
01561         { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP },
01562         { "transfer-format", &cfg_type_transferformat, 0 },
01563         { "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
01564         { "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
01565 #ifdef ALLOW_FILTER_AAAA
01566         { "filter-aaaa", &cfg_type_bracketed_aml, 0 },
01567         { "filter-aaaa-on-v4", &cfg_type_filter_aaaa, 0 },
01568         { "filter-aaaa-on-v6", &cfg_type_filter_aaaa, 0 },
01569 #else
01570         { "filter-aaaa", &cfg_type_bracketed_aml,
01571            CFG_CLAUSEFLAG_NOTCONFIGURED },
01572         { "filter-aaaa-on-v4", &cfg_type_filter_aaaa,
01573            CFG_CLAUSEFLAG_NOTCONFIGURED },
01574         { "filter-aaaa-on-v6", &cfg_type_filter_aaaa,
01575            CFG_CLAUSEFLAG_NOTCONFIGURED },
01576 #endif
01577         { "response-policy", &cfg_type_rpz, 0 },
01578         { "rate-limit", &cfg_type_rrl, 0 },
01579         { NULL, NULL, 0 }
01580 };
01581 
01582 /*%
01583  * Clauses that can be found within the 'view' statement only.
01584  */
01585 static cfg_clausedef_t
01586 view_only_clauses[] = {
01587         { "match-clients", &cfg_type_bracketed_aml, 0 },
01588         { "match-destinations", &cfg_type_bracketed_aml, 0 },
01589         { "match-recursive-only", &cfg_type_boolean, 0 },
01590         { NULL, NULL, 0 }
01591 };
01592 
01593 /*%
01594  * Sig-validity-interval.
01595  */
01596 
01597 static cfg_tuplefielddef_t validityinterval_fields[] = {
01598         { "validity", &cfg_type_uint32, 0 },
01599         { "re-sign", &cfg_type_optional_uint32, 0 },
01600         { NULL, NULL, 0 }
01601 };
01602 
01603 static cfg_type_t cfg_type_validityinterval = {
01604         "validityinterval", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
01605         &cfg_rep_tuple, validityinterval_fields
01606 };
01607 
01608 /*%
01609  * Clauses that can be found in a 'zone' statement,
01610  * with defaults in the 'view' or 'options' statement.
01611  */
01612 static cfg_clausedef_t
01613 zone_clauses[] = {
01614         { "allow-notify", &cfg_type_bracketed_aml, 0 },
01615         { "allow-query", &cfg_type_bracketed_aml, 0 },
01616         { "allow-query-on", &cfg_type_bracketed_aml, 0 },
01617         { "allow-transfer", &cfg_type_bracketed_aml, 0 },
01618         { "allow-update", &cfg_type_bracketed_aml, 0 },
01619         { "allow-update-forwarding", &cfg_type_bracketed_aml, 0 },
01620         { "also-notify", &cfg_type_namesockaddrkeylist, 0 },
01621         { "alt-transfer-source", &cfg_type_sockaddr4wild, 0 },
01622         { "alt-transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
01623         { "auto-dnssec", &cfg_type_autodnssec, 0 },
01624         { "check-dup-records", &cfg_type_checkmode, 0 },
01625         { "check-integrity", &cfg_type_boolean, 0 },
01626         { "check-mx", &cfg_type_checkmode, 0 },
01627         { "check-mx-cname", &cfg_type_checkmode, 0 },
01628         { "check-sibling", &cfg_type_boolean, 0 },
01629         { "check-spf", &cfg_type_warn, 0 },
01630         { "check-srv-cname", &cfg_type_checkmode, 0 },
01631         { "check-wildcard", &cfg_type_boolean, 0 },
01632         { "dialup", &cfg_type_dialuptype, 0 },
01633         { "dnssec-dnskey-kskonly", &cfg_type_boolean, 0 },
01634         { "dnssec-loadkeys-interval", &cfg_type_uint32, 0 },
01635         { "dnssec-secure-to-insecure", &cfg_type_boolean, 0 },
01636         { "dnssec-update-mode", &cfg_type_dnssecupdatemode, 0 },
01637         { "forward", &cfg_type_forwardtype, 0 },
01638         { "forwarders", &cfg_type_portiplist, 0 },
01639         { "inline-signing", &cfg_type_boolean, 0 },
01640         { "key-directory", &cfg_type_qstring, 0 },
01641         { "maintain-ixfr-base", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
01642         { "masterfile-format", &cfg_type_masterformat, 0 },
01643         { "masterfile-style", &cfg_type_masterstyle, 0 },
01644         { "max-ixfr-log-size", &cfg_type_size, CFG_CLAUSEFLAG_OBSOLETE },
01645         { "max-journal-size", &cfg_type_sizenodefault, 0 },
01646         { "max-refresh-time", &cfg_type_uint32, 0 },
01647         { "max-retry-time", &cfg_type_uint32, 0 },
01648         { "max-transfer-idle-in", &cfg_type_uint32, 0 },
01649         { "max-transfer-idle-out", &cfg_type_uint32, 0 },
01650         { "max-transfer-time-in", &cfg_type_uint32, 0 },
01651         { "max-transfer-time-out", &cfg_type_uint32, 0 },
01652         { "max-zone-ttl", &cfg_type_maxttl, 0 },
01653         { "min-refresh-time", &cfg_type_uint32, 0 },
01654         { "min-retry-time", &cfg_type_uint32, 0 },
01655         { "multi-master", &cfg_type_boolean, 0 },
01656         { "notify", &cfg_type_notifytype, 0 },
01657         { "notify-delay", &cfg_type_uint32, 0 },
01658         { "notify-source", &cfg_type_sockaddr4wild, 0 },
01659         { "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
01660         { "notify-to-soa", &cfg_type_boolean, 0 },
01661         { "nsec3-test-zone", &cfg_type_boolean, CFG_CLAUSEFLAG_TESTONLY },
01662         { "request-expire", &cfg_type_boolean, 0 },
01663         { "request-ixfr", &cfg_type_boolean, 0 },
01664         { "serial-update-method", &cfg_type_updatemethod, 0 },
01665         { "sig-signing-nodes", &cfg_type_uint32, 0 },
01666         { "sig-signing-signatures", &cfg_type_uint32, 0 },
01667         { "sig-signing-type", &cfg_type_uint32, 0 },
01668         { "sig-validity-interval", &cfg_type_validityinterval, 0 },
01669         { "transfer-source", &cfg_type_sockaddr4wild, 0 },
01670         { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
01671         { "try-tcp-refresh", &cfg_type_boolean, 0 },
01672         { "update-check-ksk", &cfg_type_boolean, 0 },
01673         { "use-alt-transfer-source", &cfg_type_boolean, 0 },
01674         { "zero-no-soa-ttl", &cfg_type_boolean, 0 },
01675         { "zone-statistics", &cfg_type_zonestat, 0 },
01676         { NULL, NULL, 0 }
01677 };
01678 
01679 /*%
01680  * Clauses that can be found in a 'zone' statement
01681  * only.
01682  */
01683 static cfg_clausedef_t
01684 zone_only_clauses[] = {
01685         { "type", &cfg_type_zonetype, 0 },
01686         { "file", &cfg_type_qstring, 0 },
01687         { "journal", &cfg_type_qstring, 0 },
01688         { "ixfr-base", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
01689         { "ixfr-tmp-file", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
01690         { "masters", &cfg_type_namesockaddrkeylist, 0 },
01691         { "pubkey", &cfg_type_pubkey,
01692           CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE },
01693         { "update-policy", &cfg_type_updatepolicy, 0 },
01694         { "database", &cfg_type_astring, 0 },
01695         { "dlz", &cfg_type_astring, 0 },
01696         { "delegation-only", &cfg_type_boolean, 0 },
01697         /*
01698          * Note that the format of the check-names option is different between
01699          * the zone options and the global/view options.  Ugh.
01700          */
01701         { "check-names", &cfg_type_checkmode, 0 },
01702         { "in-view", &cfg_type_astring, 0 },
01703         { "ixfr-from-differences", &cfg_type_boolean, 0 },
01704         { "server-addresses", &cfg_type_bracketed_sockaddrlist, 0 },
01705         { "server-names", &cfg_type_namelist, 0 },
01706         { NULL, NULL, 0 }
01707 };
01708 
01709 
01710 /*% The top-level named.conf syntax. */
01711 
01712 static cfg_clausedef_t *
01713 namedconf_clausesets[] = {
01714         namedconf_clauses,
01715         namedconf_or_view_clauses,
01716         NULL
01717 };
01718 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = {
01719         "namedconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
01720         &cfg_rep_map, namedconf_clausesets
01721 };
01722 
01723 /*% The bind.keys syntax (trusted-keys/managed-keys only). */
01724 static cfg_clausedef_t *
01725 bindkeys_clausesets[] = {
01726         bindkeys_clauses,
01727         NULL
01728 };
01729 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bindkeys = {
01730         "bindkeys", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
01731         &cfg_rep_map, bindkeys_clausesets
01732 };
01733 
01734 /*% The new-zone-file syntax (for zones added by 'rndc addzone') */
01735 static cfg_clausedef_t
01736 newzones_clauses[] = {
01737         { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
01738         { NULL, NULL, 0 }
01739 };
01740 
01741 static cfg_clausedef_t *
01742 newzones_clausesets[] = {
01743         newzones_clauses,
01744         NULL
01745 };
01746 
01747 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_newzones = {
01748         "newzones", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
01749         &cfg_rep_map, newzones_clausesets
01750 };
01751 
01752 /*% The "options" statement syntax. */
01753 
01754 static cfg_clausedef_t *
01755 options_clausesets[] = {
01756         options_clauses,
01757         view_clauses,
01758         zone_clauses,
01759         NULL
01760 };
01761 static cfg_type_t cfg_type_options = {
01762         "options", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, options_clausesets };
01763 
01764 /*% The "view" statement syntax. */
01765 
01766 static cfg_clausedef_t *
01767 view_clausesets[] = {
01768         view_only_clauses,
01769         namedconf_or_view_clauses,
01770         view_clauses,
01771         zone_clauses,
01772         NULL
01773 };
01774 static cfg_type_t cfg_type_viewopts = {
01775         "view", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, view_clausesets };
01776 
01777 /*% The "zone" statement syntax. */
01778 
01779 static cfg_clausedef_t *
01780 zone_clausesets[] = {
01781         zone_only_clauses,
01782         zone_clauses,
01783         NULL
01784 };
01785 static cfg_type_t cfg_type_zoneopts = {
01786         "zoneopts", cfg_parse_map, cfg_print_map,
01787         cfg_doc_map, &cfg_rep_map, zone_clausesets };
01788 
01789 /*% The "dynamically loadable zones" statement syntax. */
01790 
01791 static cfg_clausedef_t
01792 dlz_clauses[] = {
01793         { "database", &cfg_type_astring, 0 },
01794         { "search", &cfg_type_boolean, 0 },
01795         { NULL, NULL, 0 }
01796 };
01797 static cfg_clausedef_t *
01798 dlz_clausesets[] = {
01799         dlz_clauses,
01800         NULL
01801 };
01802 static cfg_type_t cfg_type_dlz = {
01803         "dlz", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
01804          &cfg_rep_map, dlz_clausesets
01805 };
01806 
01807 /*%
01808  * Clauses that can be found within the 'key' statement.
01809  */
01810 static cfg_clausedef_t
01811 key_clauses[] = {
01812         { "algorithm", &cfg_type_astring, 0 },
01813         { "secret", &cfg_type_sstring, 0 },
01814         { NULL, NULL, 0 }
01815 };
01816 
01817 static cfg_clausedef_t *
01818 key_clausesets[] = {
01819         key_clauses,
01820         NULL
01821 };
01822 static cfg_type_t cfg_type_key = {
01823         "key", cfg_parse_named_map, cfg_print_map,
01824         cfg_doc_map, &cfg_rep_map, key_clausesets
01825 };
01826 
01827 
01828 /*%
01829  * Clauses that can be found in a 'server' statement.
01830  */
01831 static cfg_clausedef_t
01832 server_clauses[] = {
01833         { "bogus", &cfg_type_boolean, 0 },
01834         { "edns", &cfg_type_boolean, 0 },
01835         { "edns-udp-size", &cfg_type_uint32, 0 },
01836         { "edns-version", &cfg_type_uint32, 0 },
01837         { "keys", &cfg_type_server_key_kludge, 0 },
01838         { "max-udp-size", &cfg_type_uint32, 0 },
01839         { "tcp-only", &cfg_type_boolean, 0 },
01840         { "notify-source", &cfg_type_sockaddr4wild, 0 },
01841         { "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
01842         { "provide-ixfr", &cfg_type_boolean, 0 },
01843         { "query-source", &cfg_type_querysource4, 0 },
01844         { "query-source-v6", &cfg_type_querysource6, 0 },
01845         { "request-expire", &cfg_type_boolean, 0 },
01846         { "request-ixfr", &cfg_type_boolean, 0 },
01847         { "request-nsid", &cfg_type_boolean, 0 },
01848 #ifdef ISC_PLATFORM_USESIT
01849         { "request-sit", &cfg_type_boolean, 0 },
01850 #else
01851         { "request-sit", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTCONFIGURED },
01852 #endif
01853         { "support-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
01854         { "transfer-format", &cfg_type_transferformat, 0 },
01855         { "transfer-source", &cfg_type_sockaddr4wild, 0 },
01856         { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
01857         { "transfers", &cfg_type_uint32, 0 },
01858         { NULL, NULL, 0 }
01859 };
01860 static cfg_clausedef_t *
01861 server_clausesets[] = {
01862         server_clauses,
01863         NULL
01864 };
01865 static cfg_type_t cfg_type_server = {
01866         "server", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
01867         server_clausesets
01868 };
01869 
01870 
01871 /*%
01872  * Clauses that can be found in a 'channel' clause in the
01873  * 'logging' statement.
01874  *
01875  * These have some additional constraints that need to be
01876  * checked after parsing:
01877  *  - There must exactly one of file/syslog/null/stderr
01878  *
01879  */
01880 static cfg_clausedef_t
01881 channel_clauses[] = {
01882         /* Destinations.  We no longer require these to be first. */
01883         { "file", &cfg_type_logfile, 0 },
01884         { "syslog", &cfg_type_optional_facility, 0 },
01885         { "null", &cfg_type_void, 0 },
01886         { "stderr", &cfg_type_void, 0 },
01887         /* Options.  We now accept these for the null channel, too. */
01888         { "severity", &cfg_type_logseverity, 0 },
01889         { "print-time", &cfg_type_boolean, 0 },
01890         { "print-severity", &cfg_type_boolean, 0 },
01891         { "print-category", &cfg_type_boolean, 0 },
01892         { "buffered", &cfg_type_boolean, 0 },
01893         { NULL, NULL, 0 }
01894 };
01895 static cfg_clausedef_t *
01896 channel_clausesets[] = {
01897         channel_clauses,
01898         NULL
01899 };
01900 static cfg_type_t cfg_type_channel = {
01901         "channel", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
01902         &cfg_rep_map, channel_clausesets
01903 };
01904 
01905 /*% A list of log destination, used in the "category" clause. */
01906 static cfg_type_t cfg_type_destinationlist = {
01907         "destinationlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
01908         &cfg_rep_list, &cfg_type_astring };
01909 
01910 /*%
01911  * Clauses that can be found in a 'logging' statement.
01912  */
01913 static cfg_clausedef_t
01914 logging_clauses[] = {
01915         { "channel", &cfg_type_channel, CFG_CLAUSEFLAG_MULTI },
01916         { "category", &cfg_type_category, CFG_CLAUSEFLAG_MULTI },
01917         { NULL, NULL, 0 }
01918 };
01919 static cfg_clausedef_t *
01920 logging_clausesets[] = {
01921         logging_clauses,
01922         NULL
01923 };
01924 static cfg_type_t cfg_type_logging = {
01925         "logging", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, logging_clausesets };
01926 
01927 
01928 /*%
01929  * For parsing an 'addzone' statement
01930  */
01931 
01932 static cfg_tuplefielddef_t addzone_fields[] = {
01933         { "name", &cfg_type_astring, 0 },
01934         { "class", &cfg_type_optional_class, 0 },
01935         { "view", &cfg_type_optional_class, 0 },
01936         { "options", &cfg_type_zoneopts, 0 },
01937         { NULL, NULL, 0 }
01938 };
01939 static cfg_type_t cfg_type_addzone = {
01940         "zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, addzone_fields };
01941 
01942 static cfg_clausedef_t
01943 addzoneconf_clauses[] = {
01944         { "zone", &cfg_type_addzone, CFG_CLAUSEFLAG_MULTI },
01945         { NULL, NULL, 0 }
01946 };
01947 
01948 static cfg_clausedef_t *
01949 addzoneconf_clausesets[] = {
01950         addzoneconf_clauses,
01951         NULL
01952 };
01953 
01954 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_addzoneconf = {
01955         "addzoneconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
01956         &cfg_rep_map, addzoneconf_clausesets
01957 };
01958 
01959 
01960 static isc_result_t
01961 parse_unitstring(char *str, isc_resourcevalue_t *valuep) {
01962         char *endp;
01963         unsigned int len;
01964         isc_uint64_t value;
01965         isc_uint64_t unit;
01966 
01967         value = isc_string_touint64(str, &endp, 10);
01968         if (*endp == 0) {
01969                 *valuep = value;
01970                 return (ISC_R_SUCCESS);
01971         }
01972 
01973         len = strlen(str);
01974         if (len < 2 || endp[1] != '\0')
01975                 return (ISC_R_FAILURE);
01976 
01977         switch (str[len - 1]) {
01978         case 'k':
01979         case 'K':
01980                 unit = 1024;
01981                 break;
01982         case 'm':
01983         case 'M':
01984                 unit = 1024 * 1024;
01985                 break;
01986         case 'g':
01987         case 'G':
01988                 unit = 1024 * 1024 * 1024;
01989                 break;
01990         default:
01991                 return (ISC_R_FAILURE);
01992         }
01993         if (value > ISC_UINT64_MAX / unit)
01994                 return (ISC_R_FAILURE);
01995         *valuep = value * unit;
01996         return (ISC_R_SUCCESS);
01997 }
01998 
01999 static isc_result_t
02000 parse_sizeval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02001         isc_result_t result;
02002         cfg_obj_t *obj = NULL;
02003         isc_uint64_t val;
02004 
02005         UNUSED(type);
02006 
02007         CHECK(cfg_gettoken(pctx, 0));
02008         if (pctx->token.type != isc_tokentype_string) {
02009                 result = ISC_R_UNEXPECTEDTOKEN;
02010                 goto cleanup;
02011         }
02012         CHECK(parse_unitstring(TOKEN_STRING(pctx), &val));
02013 
02014         CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj));
02015         obj->value.uint64 = val;
02016         *ret = obj;
02017         return (ISC_R_SUCCESS);
02018 
02019  cleanup:
02020         cfg_parser_error(pctx, CFG_LOG_NEAR, "expected integer and optional unit");
02021         return (result);
02022 }
02023 
02024 /*%
02025  * A size value (number + optional unit).
02026  */
02027 static cfg_type_t cfg_type_sizeval = {
02028         "sizeval", parse_sizeval, cfg_print_uint64, cfg_doc_terminal,
02029         &cfg_rep_uint64, NULL };
02030 
02031 /*%
02032  * A size, "unlimited", or "default".
02033  */
02034 
02035 static isc_result_t
02036 parse_size(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02037         return (parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret));
02038 }
02039 
02040 static const char *size_enums[] = { "unlimited", "default", NULL };
02041 static cfg_type_t cfg_type_size = {
02042         "size", parse_size, cfg_print_ustring, cfg_doc_terminal,
02043         &cfg_rep_string, size_enums
02044 };
02045 
02046 /*%
02047  * A size or "unlimited", but not "default".
02048  */
02049 static const char *sizenodefault_enums[] = { "unlimited", NULL };
02050 static cfg_type_t cfg_type_sizenodefault = {
02051         "size_no_default", parse_size, cfg_print_ustring, cfg_doc_terminal,
02052         &cfg_rep_string, sizenodefault_enums
02053 };
02054 
02055 /*%
02056  * optional_keyvalue
02057  */
02058 static isc_result_t
02059 parse_maybe_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
02060                               isc_boolean_t optional, cfg_obj_t **ret)
02061 {
02062         isc_result_t result;
02063         cfg_obj_t *obj = NULL;
02064         const keyword_type_t *kw = type->of;
02065 
02066         CHECK(cfg_peektoken(pctx, 0));
02067         if (pctx->token.type == isc_tokentype_string &&
02068             strcasecmp(TOKEN_STRING(pctx), kw->name) == 0) {
02069                 CHECK(cfg_gettoken(pctx, 0));
02070                 CHECK(kw->type->parse(pctx, kw->type, &obj));
02071                 obj->type = type; /* XXX kludge */
02072         } else {
02073                 if (optional) {
02074                         CHECK(cfg_parse_void(pctx, NULL, &obj));
02075                 } else {
02076                         cfg_parser_error(pctx, CFG_LOG_NEAR, "expected '%s'",
02077                                      kw->name);
02078                         result = ISC_R_UNEXPECTEDTOKEN;
02079                         goto cleanup;
02080                 }
02081         }
02082         *ret = obj;
02083  cleanup:
02084         return (result);
02085 }
02086 
02087 static isc_result_t
02088 parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
02089                     const cfg_type_t *othertype, cfg_obj_t **ret)
02090 {
02091         isc_result_t result;
02092         CHECK(cfg_peektoken(pctx, 0));
02093         if (pctx->token.type == isc_tokentype_string &&
02094             cfg_is_enum(TOKEN_STRING(pctx), enumtype->of)) {
02095                 CHECK(cfg_parse_enum(pctx, enumtype, ret));
02096         } else {
02097                 CHECK(cfg_parse_obj(pctx, othertype, ret));
02098         }
02099  cleanup:
02100         return (result);
02101 }
02102 
02103 static void
02104 doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *type) {
02105         cfg_doc_terminal(pctx, type);
02106 #if 0 /* XXX */
02107         cfg_print_chars(pctx, "( ", 2);...
02108 #endif
02109 
02110 }
02111 
02112 static isc_result_t
02113 parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02114         return (parse_maybe_optional_keyvalue(pctx, type, ISC_FALSE, ret));
02115 }
02116 
02117 static isc_result_t
02118 parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
02119                         cfg_obj_t **ret)
02120 {
02121         return (parse_maybe_optional_keyvalue(pctx, type, ISC_TRUE, ret));
02122 }
02123 
02124 static void
02125 print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj) {
02126         const keyword_type_t *kw = obj->type->of;
02127         cfg_print_cstr(pctx, kw->name);
02128         cfg_print_cstr(pctx, " ");
02129         kw->type->print(pctx, obj);
02130 }
02131 
02132 static void
02133 doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
02134         const keyword_type_t *kw = type->of;
02135         cfg_print_cstr(pctx, kw->name);
02136         cfg_print_cstr(pctx, " ");
02137         cfg_doc_obj(pctx, kw->type);
02138 }
02139 
02140 static void
02141 doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
02142         const keyword_type_t *kw = type->of;
02143         cfg_print_cstr(pctx, "[ ");
02144         cfg_print_cstr(pctx, kw->name);
02145         cfg_print_cstr(pctx, " ");
02146         cfg_doc_obj(pctx, kw->type);
02147         cfg_print_cstr(pctx, " ]");
02148 }
02149 
02150 static const char *dialup_enums[] = {
02151         "notify", "notify-passive", "refresh", "passive", NULL };
02152 static isc_result_t
02153 parse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02154         return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
02155 }
02156 static cfg_type_t cfg_type_dialuptype = {
02157         "dialuptype", parse_dialup_type, cfg_print_ustring, doc_enum_or_other,
02158         &cfg_rep_string, dialup_enums
02159 };
02160 
02161 static const char *notify_enums[] = { "explicit", "master-only", NULL };
02162 static isc_result_t
02163 parse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02164         return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
02165 }
02166 static cfg_type_t cfg_type_notifytype = {
02167         "notifytype", parse_notify_type, cfg_print_ustring, doc_enum_or_other,
02168         &cfg_rep_string, notify_enums,
02169 };
02170 
02171 static const char *ixfrdiff_enums[] = { "master", "slave", NULL };
02172 static isc_result_t
02173 parse_ixfrdiff_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02174         return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
02175 }
02176 static cfg_type_t cfg_type_ixfrdifftype = {
02177         "ixfrdiff", parse_ixfrdiff_type, cfg_print_ustring, doc_enum_or_other,
02178         &cfg_rep_string, ixfrdiff_enums,
02179 };
02180 
02181 static const char *filter_aaaa_enums[] = { "break-dnssec", NULL };
02182 static isc_result_t
02183 parse_filter_aaaa(cfg_parser_t *pctx, const cfg_type_t *type,
02184                      cfg_obj_t **ret) {
02185         return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
02186 }
02187 static cfg_type_t cfg_type_filter_aaaa = {
02188         "filter_aaaa", parse_filter_aaaa, cfg_print_ustring,
02189         doc_enum_or_other, &cfg_rep_string, filter_aaaa_enums,
02190 };
02191 
02192 static keyword_type_t key_kw = { "key", &cfg_type_astring };
02193 
02194 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = {
02195         "keyref", parse_keyvalue, print_keyvalue, doc_keyvalue,
02196         &cfg_rep_string, &key_kw
02197 };
02198 
02199 static cfg_type_t cfg_type_optional_keyref = {
02200         "optional_keyref", parse_optional_keyvalue, print_keyvalue,
02201         doc_optional_keyvalue, &cfg_rep_string, &key_kw
02202 };
02203 
02204 #ifdef HAVE_GEOIP
02205 /*
02206  * "geoip" ACL element:
02207  * geoip [ db <database> ] search-type <string>
02208  */
02209 static const char *geoiptype_enums[] = {
02210         "country", "country3", "countryname", "region", "regionname",
02211         "city", "postal", "metrocode", "areacode", "timezone", "continent",
02212         "isp", "domain", "asnum", "org", "netspeed", NULL
02213 };
02214 static cfg_type_t cfg_type_geoiptype = {
02215         "geoiptype", cfg_parse_enum, cfg_print_ustring,
02216         cfg_doc_enum, &cfg_rep_string, &geoiptype_enums
02217 };
02218 
02219 static const char *geoipdb_enums[] = {
02220         "country", "region", "city",
02221         "isp", "domain", "asnum", "org", "netspeed", NULL
02222 };
02223 static cfg_type_t cfg_type_geoipdb = {
02224         "geoipdb", cfg_parse_enum, cfg_print_ustring,
02225         cfg_doc_enum, &cfg_rep_string, &geoipdb_enums
02226 };
02227 
02228 static cfg_tuplefielddef_t geoip_fields[] = {
02229         { "negated", &cfg_type_void, 0 },
02230         { "db", &cfg_type_geoipdb, 0 },
02231         { "subtype", &cfg_type_geoiptype, 0 },
02232         { "search", &cfg_type_astring, 0 },
02233         { NULL, NULL, 0 }
02234 };
02235 
02236 static cfg_type_t cfg_type_geoip = {
02237         "geoip", parse_geoip, print_geoip, doc_geoip,
02238         &cfg_rep_tuple, geoip_fields
02239 };
02240 
02241 static isc_result_t
02242 parse_geoip(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02243         isc_result_t result;
02244         cfg_obj_t *obj = NULL;
02245         const cfg_tuplefielddef_t *fields = type->of;
02246 
02247         CHECK(cfg_create_tuple(pctx, type, &obj));
02248         CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[0]));
02249 
02250         /* Parse the optional "db" field. */
02251         CHECK(cfg_peektoken(pctx, 0));
02252         if (pctx->token.type == isc_tokentype_string) {
02253                 CHECK(cfg_gettoken(pctx, 0));
02254                 if (strcasecmp(TOKEN_STRING(pctx), "db") == 0 &&
02255                     obj->value.tuple[1] == NULL) {
02256                         CHECK(cfg_parse_obj(pctx, fields[1].type,
02257                                     &obj->value.tuple[1]));
02258                 } else {
02259                         CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1]));
02260                         cfg_ungettoken(pctx);
02261                 }
02262         }
02263 
02264         CHECK(cfg_parse_obj(pctx, fields[2].type, &obj->value.tuple[2]));
02265         CHECK(cfg_parse_obj(pctx, fields[3].type, &obj->value.tuple[3]));
02266 
02267         *ret = obj;
02268         return (ISC_R_SUCCESS);
02269 
02270  cleanup:
02271         CLEANUP_OBJ(obj);
02272         return (result);
02273 }
02274 
02275 static void
02276 print_geoip(cfg_printer_t *pctx, const cfg_obj_t *obj) {
02277         if (obj->value.tuple[1]->type->print != cfg_print_void) {
02278                 cfg_print_cstr(pctx, " db ");
02279                 cfg_print_obj(pctx, obj->value.tuple[1]);
02280         }
02281         cfg_print_obj(pctx, obj->value.tuple[2]);
02282         cfg_print_obj(pctx, obj->value.tuple[3]);
02283 }
02284 
02285 
02286 static void
02287 doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type) {
02288         UNUSED(type);
02289         cfg_print_cstr(pctx, "[ db ");
02290         cfg_doc_enum(pctx, &cfg_type_geoipdb);
02291         cfg_print_cstr(pctx, " ]");
02292         cfg_print_cstr(pctx, " ");
02293         cfg_doc_enum(pctx, &cfg_type_geoiptype);
02294         cfg_print_cstr(pctx, " ");
02295         cfg_print_cstr(pctx, "<quoted_string>");
02296 }
02297 #endif /* HAVE_GEOIP */
02298 
02299 /*%
02300  * An EDNS client subnet address
02301  */
02302 
02303 static keyword_type_t ecs_kw = { "ecs", &cfg_type_netprefix };
02304 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_ecsprefix = {
02305         "edns_client_subnet", parse_keyvalue, print_keyvalue, doc_keyvalue,
02306         &cfg_rep_netprefix, &ecs_kw
02307 };
02308 
02309 /*%
02310  * A "controls" statement is represented as a map with the multivalued
02311  * "inet" and "unix" clauses.
02312  */
02313 
02314 static keyword_type_t controls_allow_kw = {
02315         "allow", &cfg_type_bracketed_aml };
02316 
02317 static cfg_type_t cfg_type_controls_allow = {
02318         "controls_allow", parse_keyvalue,
02319         print_keyvalue, doc_keyvalue,
02320         &cfg_rep_list, &controls_allow_kw
02321 };
02322 
02323 static keyword_type_t controls_keys_kw = {
02324         "keys", &cfg_type_keylist };
02325 
02326 static cfg_type_t cfg_type_controls_keys = {
02327         "controls_keys", parse_optional_keyvalue,
02328         print_keyvalue, doc_optional_keyvalue,
02329         &cfg_rep_list, &controls_keys_kw
02330 };
02331 
02332 static cfg_tuplefielddef_t inetcontrol_fields[] = {
02333         { "address", &cfg_type_controls_sockaddr, 0 },
02334         { "allow", &cfg_type_controls_allow, 0 },
02335         { "keys", &cfg_type_controls_keys, 0 },
02336         { NULL, NULL, 0 }
02337 };
02338 
02339 static cfg_type_t cfg_type_inetcontrol = {
02340         "inetcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
02341         inetcontrol_fields
02342 };
02343 
02344 static keyword_type_t controls_perm_kw = {
02345         "perm", &cfg_type_uint32 };
02346 
02347 static cfg_type_t cfg_type_controls_perm = {
02348         "controls_perm", parse_keyvalue,
02349         print_keyvalue, doc_keyvalue,
02350         &cfg_rep_uint32, &controls_perm_kw
02351 };
02352 
02353 static keyword_type_t controls_owner_kw = {
02354         "owner", &cfg_type_uint32 };
02355 
02356 static cfg_type_t cfg_type_controls_owner = {
02357         "controls_owner", parse_keyvalue,
02358         print_keyvalue, doc_keyvalue,
02359         &cfg_rep_uint32, &controls_owner_kw
02360 };
02361 
02362 static keyword_type_t controls_group_kw = {
02363         "group", &cfg_type_uint32 };
02364 
02365 static cfg_type_t cfg_type_controls_group = {
02366         "controls_allow", parse_keyvalue,
02367         print_keyvalue, doc_keyvalue,
02368         &cfg_rep_uint32, &controls_group_kw
02369 };
02370 
02371 static cfg_tuplefielddef_t unixcontrol_fields[] = {
02372         { "path", &cfg_type_qstring, 0 },
02373         { "perm", &cfg_type_controls_perm, 0 },
02374         { "owner", &cfg_type_controls_owner, 0 },
02375         { "group", &cfg_type_controls_group, 0 },
02376         { "keys", &cfg_type_controls_keys, 0 },
02377         { NULL, NULL, 0 }
02378 };
02379 
02380 static cfg_type_t cfg_type_unixcontrol = {
02381         "unixcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
02382         unixcontrol_fields
02383 };
02384 
02385 static cfg_clausedef_t
02386 controls_clauses[] = {
02387         { "inet", &cfg_type_inetcontrol, CFG_CLAUSEFLAG_MULTI },
02388         { "unix", &cfg_type_unixcontrol, CFG_CLAUSEFLAG_MULTI },
02389         { NULL, NULL, 0 }
02390 };
02391 
02392 static cfg_clausedef_t *
02393 controls_clausesets[] = {
02394         controls_clauses,
02395         NULL
02396 };
02397 static cfg_type_t cfg_type_controls = {
02398         "controls", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,    &controls_clausesets
02399 };
02400 
02401 /*%
02402  * A "statistics-channels" statement is represented as a map with the
02403  * multivalued "inet" clauses.
02404  */
02405 static void
02406 doc_optional_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
02407         const keyword_type_t *kw = type->of;
02408         cfg_print_cstr(pctx, "[ ");
02409         cfg_print_cstr(pctx, kw->name);
02410         cfg_print_cstr(pctx, " ");
02411         cfg_doc_obj(pctx, kw->type);
02412         cfg_print_cstr(pctx, " ]");
02413 }
02414 
02415 static cfg_type_t cfg_type_optional_allow = {
02416         "optional_allow", parse_optional_keyvalue, print_keyvalue,
02417         doc_optional_bracketed_list, &cfg_rep_list, &controls_allow_kw
02418 };
02419 
02420 static cfg_tuplefielddef_t statserver_fields[] = {
02421         { "address", &cfg_type_controls_sockaddr, 0 }, /* reuse controls def */
02422         { "allow", &cfg_type_optional_allow, 0 },
02423         { NULL, NULL, 0 }
02424 };
02425 
02426 static cfg_type_t cfg_type_statschannel = {
02427         "statschannel", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
02428         &cfg_rep_tuple, statserver_fields
02429 };
02430 
02431 static cfg_clausedef_t
02432 statservers_clauses[] = {
02433         { "inet", &cfg_type_statschannel, CFG_CLAUSEFLAG_MULTI },
02434         { NULL, NULL, 0 }
02435 };
02436 
02437 static cfg_clausedef_t *
02438 statservers_clausesets[] = {
02439         statservers_clauses,
02440         NULL
02441 };
02442 
02443 static cfg_type_t cfg_type_statschannels = {
02444         "statistics-channels", cfg_parse_map, cfg_print_map, cfg_doc_map,
02445         &cfg_rep_map,   &statservers_clausesets
02446 };
02447 
02448 /*%
02449  * An optional class, as used in view and zone statements.
02450  */
02451 static isc_result_t
02452 parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type,
02453                      cfg_obj_t **ret)
02454 {
02455         isc_result_t result;
02456         UNUSED(type);
02457         CHECK(cfg_peektoken(pctx, 0));
02458         if (pctx->token.type == isc_tokentype_string)
02459                 CHECK(cfg_parse_obj(pctx, &cfg_type_ustring, ret));
02460         else
02461                 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
02462  cleanup:
02463         return (result);
02464 }
02465 
02466 static cfg_type_t cfg_type_optional_class = {
02467         "optional_class", parse_optional_class, NULL, cfg_doc_terminal,
02468         NULL, NULL
02469 };
02470 
02471 static isc_result_t
02472 parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02473         isc_result_t result;
02474         cfg_obj_t *obj = NULL;
02475         isc_netaddr_t netaddr;
02476         in_port_t port = 0;
02477         isc_dscp_t dscp = -1;
02478         unsigned int have_address = 0;
02479         unsigned int have_port = 0;
02480         unsigned int have_dscp = 0;
02481         const unsigned int *flagp = type->of;
02482 
02483         if ((*flagp & CFG_ADDR_V4OK) != 0)
02484                 isc_netaddr_any(&netaddr);
02485         else if ((*flagp & CFG_ADDR_V6OK) != 0)
02486                 isc_netaddr_any6(&netaddr);
02487         else
02488                 INSIST(0);
02489 
02490         for (;;) {
02491                 CHECK(cfg_peektoken(pctx, 0));
02492                 if (pctx->token.type == isc_tokentype_string) {
02493                         if (strcasecmp(TOKEN_STRING(pctx),
02494                                        "address") == 0)
02495                         {
02496                                 /* read "address" */
02497                                 CHECK(cfg_gettoken(pctx, 0));
02498                                 CHECK(cfg_parse_rawaddr(pctx, *flagp,
02499                                                         &netaddr));
02500                                 have_address++;
02501                         } else if (strcasecmp(TOKEN_STRING(pctx), "port") == 0)
02502                         {
02503                                 /* read "port" */
02504                                 CHECK(cfg_gettoken(pctx, 0));
02505                                 CHECK(cfg_parse_rawport(pctx,
02506                                                         CFG_ADDR_WILDOK,
02507                                                         &port));
02508                                 have_port++;
02509                         } else if (strcasecmp(TOKEN_STRING(pctx), "dscp") == 0)
02510                         {
02511                                 /* read "dscp" */
02512                                 CHECK(cfg_gettoken(pctx, 0));
02513                                 CHECK(cfg_parse_dscp(pctx, &dscp));
02514                                 have_dscp++;
02515                         } else if (have_port == 0 && have_dscp == 0 &&
02516                                    have_address == 0)
02517                         {
02518                                 return (cfg_parse_sockaddr(pctx, type, ret));
02519                         } else {
02520                                 cfg_parser_error(pctx, CFG_LOG_NEAR,
02521                                              "expected 'address', 'port', "
02522                                              "or 'dscp'");
02523                                 return (ISC_R_UNEXPECTEDTOKEN);
02524                         }
02525                 } else
02526                         break;
02527         }
02528         if (have_address > 1 || have_port > 1 ||
02529             have_address + have_port == 0) {
02530                 cfg_parser_error(pctx, 0, "expected one address and/or port");
02531                 return (ISC_R_UNEXPECTEDTOKEN);
02532         }
02533 
02534         if (have_dscp > 1) {
02535                 cfg_parser_error(pctx, 0, "expected at most one dscp");
02536                 return (ISC_R_UNEXPECTEDTOKEN);
02537         }
02538 
02539         CHECK(cfg_create_obj(pctx, &cfg_type_querysource, &obj));
02540         isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
02541         obj->value.sockaddrdscp.dscp = dscp;
02542         *ret = obj;
02543         return (ISC_R_SUCCESS);
02544 
02545  cleanup:
02546         cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid query source");
02547         CLEANUP_OBJ(obj);
02548         return (result);
02549 }
02550 
02551 static void
02552 print_querysource(cfg_printer_t *pctx, const cfg_obj_t *obj) {
02553         isc_netaddr_t na;
02554         isc_netaddr_fromsockaddr(&na, &obj->value.sockaddr);
02555         cfg_print_cstr(pctx, "address ");
02556         cfg_print_rawaddr(pctx, &na);
02557         cfg_print_cstr(pctx, " port ");
02558         cfg_print_rawuint(pctx, isc_sockaddr_getport(&obj->value.sockaddr));
02559         if (obj->value.sockaddrdscp.dscp != -1) {
02560                 cfg_print_cstr(pctx, " dscp ");
02561                 cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp);
02562         }
02563 }
02564 
02565 static unsigned int sockaddr4wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V4OK |
02566                                           CFG_ADDR_DSCPOK;
02567 static unsigned int sockaddr6wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V6OK |
02568                                           CFG_ADDR_DSCPOK;
02569 
02570 static cfg_type_t cfg_type_querysource4 = {
02571         "querysource4", parse_querysource, NULL, cfg_doc_terminal,
02572         NULL, &sockaddr4wild_flags
02573 };
02574 
02575 static cfg_type_t cfg_type_querysource6 = {
02576         "querysource6", parse_querysource, NULL, cfg_doc_terminal,
02577         NULL, &sockaddr6wild_flags
02578 };
02579 
02580 static cfg_type_t cfg_type_querysource = {
02581         "querysource", NULL, print_querysource, NULL, &cfg_rep_sockaddr, NULL
02582 };
02583 
02584 /*% addrmatchelt */
02585 
02586 static isc_result_t
02587 parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02588         isc_result_t result;
02589         UNUSED(type);
02590 
02591         CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
02592 
02593         if (pctx->token.type == isc_tokentype_string ||
02594             pctx->token.type == isc_tokentype_qstring) {
02595                 if (pctx->token.type == isc_tokentype_string &&
02596                     (strcasecmp(TOKEN_STRING(pctx), "key") == 0)) {
02597                         CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret));
02598                 } else if (pctx->token.type == isc_tokentype_string &&
02599                            (strcasecmp(TOKEN_STRING(pctx), "ecs") == 0)) {
02600                         CHECK(cfg_parse_obj(pctx, &cfg_type_ecsprefix, ret));
02601                 } else if (pctx->token.type == isc_tokentype_string &&
02602                            (strcasecmp(TOKEN_STRING(pctx), "geoip") == 0)) {
02603 #ifdef HAVE_GEOIP
02604                         CHECK(cfg_gettoken(pctx, 0));
02605                         CHECK(cfg_parse_obj(pctx, &cfg_type_geoip, ret));
02606 #else
02607                         cfg_parser_error(pctx, CFG_LOG_NEAR,
02608                                          "'geoip' not supported in this build");
02609                         return (ISC_R_UNEXPECTEDTOKEN);
02610 #endif
02611                 } else {
02612                         if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK |
02613                                                   CFG_ADDR_V4PREFIXOK |
02614                                                   CFG_ADDR_V6OK))
02615                         {
02616                                 CHECK(cfg_parse_netprefix(pctx, NULL, ret));
02617                         } else {
02618                                 CHECK(cfg_parse_astring(pctx, NULL, ret));
02619                         }
02620                 }
02621         } else if (pctx->token.type == isc_tokentype_special) {
02622                 if (pctx->token.value.as_char == '{') {
02623                         /* Nested match list. */
02624                         CHECK(cfg_parse_obj(pctx,
02625                                             &cfg_type_bracketed_aml, ret));
02626                 } else if (pctx->token.value.as_char == '!') {
02627                         CHECK(cfg_gettoken(pctx, 0)); /* read "!" */
02628                         CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret));
02629                 } else {
02630                         goto bad;
02631                 }
02632         } else {
02633         bad:
02634                 cfg_parser_error(pctx, CFG_LOG_NEAR,
02635                              "expected IP match list element");
02636                 return (ISC_R_UNEXPECTEDTOKEN);
02637         }
02638  cleanup:
02639         return (result);
02640 }
02641 
02642 /*%
02643  * A negated address match list element (like "! 10.0.0.1").
02644  * Somewhat sneakily, the caller is expected to parse the
02645  * "!", but not to print it.
02646  */
02647 
02648 static cfg_tuplefielddef_t negated_fields[] = {
02649         { "negated", &cfg_type_addrmatchelt, 0 },
02650         { NULL, NULL, 0 }
02651 };
02652 
02653 static void
02654 print_negated(cfg_printer_t *pctx, const cfg_obj_t *obj) {
02655         cfg_print_cstr(pctx, "!");
02656         cfg_print_tuple(pctx, obj);
02657 }
02658 
02659 static cfg_type_t cfg_type_negated = {
02660         "negated", cfg_parse_tuple, print_negated, NULL, &cfg_rep_tuple,
02661         &negated_fields
02662 };
02663 
02664 /*% An address match list element */
02665 
02666 static cfg_type_t cfg_type_addrmatchelt = {
02667         "address_match_element", parse_addrmatchelt, NULL, cfg_doc_terminal,
02668         NULL, NULL
02669 };
02670 
02671 /*% A bracketed address match list */
02672 
02673 static cfg_type_t cfg_type_bracketed_aml = {
02674         "bracketed_aml", cfg_parse_bracketed_list, cfg_print_bracketed_list,
02675         cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_addrmatchelt
02676 };
02677 
02678 /*%
02679  * The socket address syntax in the "controls" statement is silly.
02680  * It allows both socket address families, but also allows "*",
02681  * whis is gratuitously interpreted as the IPv4 wildcard address.
02682  */
02683 static unsigned int controls_sockaddr_flags =
02684         CFG_ADDR_V4OK | CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
02685 static cfg_type_t cfg_type_controls_sockaddr = {
02686         "controls_sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr,
02687         cfg_doc_sockaddr, &cfg_rep_sockaddr, &controls_sockaddr_flags
02688 };
02689 
02690 /*%
02691  * Handle the special kludge syntax of the "keys" clause in the "server"
02692  * statement, which takes a single key with or without braces and semicolon.
02693  */
02694 static isc_result_t
02695 parse_server_key_kludge(cfg_parser_t *pctx, const cfg_type_t *type,
02696                         cfg_obj_t **ret)
02697 {
02698         isc_result_t result;
02699         isc_boolean_t braces = ISC_FALSE;
02700         UNUSED(type);
02701 
02702         /* Allow opening brace. */
02703         CHECK(cfg_peektoken(pctx, 0));
02704         if (pctx->token.type == isc_tokentype_special &&
02705             pctx->token.value.as_char == '{') {
02706                 CHECK(cfg_gettoken(pctx, 0));
02707                 braces = ISC_TRUE;
02708         }
02709 
02710         CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
02711 
02712         if (braces) {
02713                 /* Skip semicolon if present. */
02714                 CHECK(cfg_peektoken(pctx, 0));
02715                 if (pctx->token.type == isc_tokentype_special &&
02716                     pctx->token.value.as_char == ';')
02717                         CHECK(cfg_gettoken(pctx, 0));
02718 
02719                 CHECK(cfg_parse_special(pctx, '}'));
02720         }
02721  cleanup:
02722         return (result);
02723 }
02724 static cfg_type_t cfg_type_server_key_kludge = {
02725         "server_key", parse_server_key_kludge, NULL, cfg_doc_terminal,
02726         NULL, NULL
02727 };
02728 
02729 
02730 /*%
02731  * An optional logging facility.
02732  */
02733 
02734 static isc_result_t
02735 parse_optional_facility(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
02736 {
02737         isc_result_t result;
02738         UNUSED(type);
02739 
02740         CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
02741         if (pctx->token.type == isc_tokentype_string ||
02742             pctx->token.type == isc_tokentype_qstring) {
02743                 CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
02744         } else {
02745                 CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
02746         }
02747  cleanup:
02748         return (result);
02749 }
02750 
02751 static cfg_type_t cfg_type_optional_facility = {
02752         "optional_facility", parse_optional_facility, NULL, cfg_doc_terminal,
02753         NULL, NULL };
02754 
02755 
02756 /*%
02757  * A log severity.  Return as a string, except "debug N",
02758  * which is returned as a keyword object.
02759  */
02760 
02761 static keyword_type_t debug_kw = { "debug", &cfg_type_uint32 };
02762 static cfg_type_t cfg_type_debuglevel = {
02763         "debuglevel", parse_keyvalue,
02764         print_keyvalue, doc_keyvalue,
02765         &cfg_rep_uint32, &debug_kw
02766 };
02767 
02768 static isc_result_t
02769 parse_logseverity(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02770         isc_result_t result;
02771         UNUSED(type);
02772 
02773         CHECK(cfg_peektoken(pctx, 0));
02774         if (pctx->token.type == isc_tokentype_string &&
02775             strcasecmp(TOKEN_STRING(pctx), "debug") == 0) {
02776                 CHECK(cfg_gettoken(pctx, 0)); /* read "debug" */
02777                 CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER));
02778                 if (pctx->token.type == isc_tokentype_number) {
02779                         CHECK(cfg_parse_uint32(pctx, NULL, ret));
02780                 } else {
02781                         /*
02782                          * The debug level is optional and defaults to 1.
02783                          * This makes little sense, but we support it for
02784                          * compatibility with BIND 8.
02785                          */
02786                         CHECK(cfg_create_obj(pctx, &cfg_type_uint32, ret));
02787                         (*ret)->value.uint32 = 1;
02788                 }
02789                 (*ret)->type = &cfg_type_debuglevel; /* XXX kludge */
02790         } else {
02791                 CHECK(cfg_parse_obj(pctx, &cfg_type_loglevel, ret));
02792         }
02793  cleanup:
02794         return (result);
02795 }
02796 
02797 static cfg_type_t cfg_type_logseverity = {
02798         "log_severity", parse_logseverity, NULL, cfg_doc_terminal,
02799         NULL, NULL };
02800 
02801 /*%
02802  * The "file" clause of the "channel" statement.
02803  * This is yet another special case.
02804  */
02805 
02806 static const char *logversions_enums[] = { "unlimited", NULL };
02807 static isc_result_t
02808 parse_logversions(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02809         return (parse_enum_or_other(pctx, type, &cfg_type_uint32, ret));
02810 }
02811 
02812 static cfg_type_t cfg_type_logversions = {
02813         "logversions", parse_logversions, cfg_print_ustring, cfg_doc_terminal,
02814         &cfg_rep_string, logversions_enums
02815 };
02816 
02817 static cfg_tuplefielddef_t logfile_fields[] = {
02818         { "file", &cfg_type_qstring, 0 },
02819         { "versions", &cfg_type_logversions, 0 },
02820         { "size", &cfg_type_size, 0 },
02821         { NULL, NULL, 0 }
02822 };
02823 
02824 static isc_result_t
02825 parse_logfile(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
02826         isc_result_t result;
02827         cfg_obj_t *obj = NULL;
02828         const cfg_tuplefielddef_t *fields = type->of;
02829 
02830         CHECK(cfg_create_tuple(pctx, type, &obj));
02831 
02832         /* Parse the mandatory "file" field */
02833         CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
02834 
02835         /* Parse "versions" and "size" fields in any order. */
02836         for (;;) {
02837                 CHECK(cfg_peektoken(pctx, 0));
02838                 if (pctx->token.type == isc_tokentype_string) {
02839                         CHECK(cfg_gettoken(pctx, 0));
02840                         if (strcasecmp(TOKEN_STRING(pctx),
02841                                        "versions") == 0 &&
02842                             obj->value.tuple[1] == NULL) {
02843                                 CHECK(cfg_parse_obj(pctx, fields[1].type,
02844                                             &obj->value.tuple[1]));
02845                         } else if (strcasecmp(TOKEN_STRING(pctx),
02846                                               "size") == 0 &&
02847                                    obj->value.tuple[2] == NULL) {
02848                                 CHECK(cfg_parse_obj(pctx, fields[2].type,
02849                                             &obj->value.tuple[2]));
02850                         } else {
02851                                 break;
02852                         }
02853                 } else {
02854                         break;
02855                 }
02856         }
02857 
02858         /* Create void objects for missing optional values. */
02859         if (obj->value.tuple[1] == NULL)
02860                 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1]));
02861         if (obj->value.tuple[2] == NULL)
02862                 CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2]));
02863 
02864         *ret = obj;
02865         return (ISC_R_SUCCESS);
02866 
02867  cleanup:
02868         CLEANUP_OBJ(obj);
02869         return (result);
02870 }
02871 
02872 static void
02873 print_logfile(cfg_printer_t *pctx, const cfg_obj_t *obj) {
02874         cfg_print_obj(pctx, obj->value.tuple[0]); /* file */
02875         if (obj->value.tuple[1]->type->print != cfg_print_void) {
02876                 cfg_print_cstr(pctx, " versions ");
02877                 cfg_print_obj(pctx, obj->value.tuple[1]);
02878         }
02879         if (obj->value.tuple[2]->type->print != cfg_print_void) {
02880                 cfg_print_cstr(pctx, " size ");
02881                 cfg_print_obj(pctx, obj->value.tuple[2]);
02882         }
02883 }
02884 
02885 
02886 static void
02887 doc_logfile(cfg_printer_t *pctx, const cfg_type_t *type) {
02888         UNUSED(type);
02889         cfg_print_cstr(pctx, "<quoted_string>");
02890         cfg_print_cstr(pctx, " ");
02891         cfg_print_cstr(pctx, "[ versions ( \"unlimited\" | <integer> ) ]");
02892         cfg_print_cstr(pctx, " ");
02893         cfg_print_cstr(pctx, "[ size <size> ]");
02894 }
02895 
02896 static cfg_type_t cfg_type_logfile = {
02897         "log_file", parse_logfile, print_logfile, doc_logfile,
02898         &cfg_rep_tuple, logfile_fields
02899 };
02900 
02901 /*% An IPv4 address with optional dscp and port, "*" accepted as wildcard. */
02902 static cfg_type_t cfg_type_sockaddr4wild = {
02903         "sockaddr4wild", cfg_parse_sockaddr, cfg_print_sockaddr,
02904         cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr4wild_flags
02905 };
02906 
02907 /*% An IPv6 address with optional port, "*" accepted as wildcard. */
02908 static cfg_type_t cfg_type_sockaddr6wild = {
02909         "v6addrportwild", cfg_parse_sockaddr, cfg_print_sockaddr,
02910         cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr6wild_flags
02911 };
02912 
02913 /*%
02914  * lwres
02915  */
02916 
02917 static cfg_tuplefielddef_t lwres_view_fields[] = {
02918         { "name", &cfg_type_astring, 0 },
02919         { "class", &cfg_type_optional_class, 0 },
02920         { NULL, NULL, 0 }
02921 };
02922 static cfg_type_t cfg_type_lwres_view = {
02923         "lwres_view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
02924         lwres_view_fields
02925 };
02926 
02927 static cfg_type_t cfg_type_lwres_searchlist = {
02928         "lwres_searchlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
02929         cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring };
02930 
02931 static cfg_clausedef_t
02932 lwres_clauses[] = {
02933         { "listen-on", &cfg_type_portiplist, 0 },
02934         { "view", &cfg_type_lwres_view, 0 },
02935         { "search", &cfg_type_lwres_searchlist, 0 },
02936         { "ndots", &cfg_type_uint32, 0 },
02937         { "lwres-tasks", &cfg_type_uint32, 0},
02938         { "lwres-clients", &cfg_type_uint32, 0},
02939         { NULL, NULL, 0 }
02940 };
02941 
02942 static cfg_clausedef_t *
02943 lwres_clausesets[] = {
02944         lwres_clauses,
02945         NULL
02946 };
02947 static cfg_type_t cfg_type_lwres = {
02948         "lwres", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
02949         lwres_clausesets
02950 };
02951 
02952 /*%
02953  * rndc
02954  */
02955 
02956 static cfg_clausedef_t
02957 rndcconf_options_clauses[] = {
02958         { "default-key", &cfg_type_astring, 0 },
02959         { "default-port", &cfg_type_uint32, 0 },
02960         { "default-server", &cfg_type_astring, 0 },
02961         { "default-source-address", &cfg_type_netaddr4wild, 0 },
02962         { "default-source-address-v6", &cfg_type_netaddr6wild, 0 },
02963         { NULL, NULL, 0 }
02964 };
02965 
02966 static cfg_clausedef_t *
02967 rndcconf_options_clausesets[] = {
02968         rndcconf_options_clauses,
02969         NULL
02970 };
02971 
02972 static cfg_type_t cfg_type_rndcconf_options = {
02973         "rndcconf_options", cfg_parse_map, cfg_print_map, cfg_doc_map,
02974         &cfg_rep_map, rndcconf_options_clausesets
02975 };
02976 
02977 static cfg_clausedef_t
02978 rndcconf_server_clauses[] = {
02979         { "key", &cfg_type_astring, 0 },
02980         { "port", &cfg_type_uint32, 0 },
02981         { "source-address", &cfg_type_netaddr4wild, 0 },
02982         { "source-address-v6", &cfg_type_netaddr6wild, 0 },
02983         { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 },
02984         { NULL, NULL, 0 }
02985 };
02986 
02987 static cfg_clausedef_t *
02988 rndcconf_server_clausesets[] = {
02989         rndcconf_server_clauses,
02990         NULL
02991 };
02992 
02993 static cfg_type_t cfg_type_rndcconf_server = {
02994         "rndcconf_server", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
02995         &cfg_rep_map, rndcconf_server_clausesets
02996 };
02997 
02998 static cfg_clausedef_t
02999 rndcconf_clauses[] = {
03000         { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
03001         { "server", &cfg_type_rndcconf_server, CFG_CLAUSEFLAG_MULTI },
03002         { "options", &cfg_type_rndcconf_options, 0 },
03003         { NULL, NULL, 0 }
03004 };
03005 
03006 static cfg_clausedef_t *
03007 rndcconf_clausesets[] = {
03008         rndcconf_clauses,
03009         NULL
03010 };
03011 
03012 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndcconf = {
03013         "rndcconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
03014         &cfg_rep_map, rndcconf_clausesets
03015 };
03016 
03017 static cfg_clausedef_t
03018 rndckey_clauses[] = {
03019         { "key", &cfg_type_key, 0 },
03020         { NULL, NULL, 0 }
03021 };
03022 
03023 static cfg_clausedef_t *
03024 rndckey_clausesets[] = {
03025         rndckey_clauses,
03026         NULL
03027 };
03028 
03029 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndckey = {
03030         "rndckey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
03031         &cfg_rep_map, rndckey_clausesets
03032 };
03033 
03034 /*
03035  * session.key has exactly the same syntax as rndc.key, but it's defined
03036  * separately for clarity (and so we can extend it someday, if needed).
03037  */
03038 LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sessionkey = {
03039         "sessionkey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
03040         &cfg_rep_map, rndckey_clausesets
03041 };
03042 
03043 static cfg_tuplefielddef_t nameport_fields[] = {
03044         { "name", &cfg_type_astring, 0 },
03045         { "port", &cfg_type_optional_port, 0 },
03046         { "dscp", &cfg_type_optional_dscp, 0 },
03047         { NULL, NULL, 0 }
03048 };
03049 
03050 static cfg_type_t cfg_type_nameport = {
03051         "nameport", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
03052         &cfg_rep_tuple, nameport_fields
03053 };
03054 
03055 static void
03056 doc_sockaddrnameport(cfg_printer_t *pctx, const cfg_type_t *type) {
03057         UNUSED(type);
03058         cfg_print_cstr(pctx, "( ");
03059         cfg_print_cstr(pctx, "<quoted_string>");
03060         cfg_print_cstr(pctx, " ");
03061         cfg_print_cstr(pctx, "[ port <integer> ]");
03062         cfg_print_cstr(pctx, " ");
03063         cfg_print_cstr(pctx, "[ dscp <integer> ]");
03064         cfg_print_cstr(pctx, " | ");
03065         cfg_print_cstr(pctx, "<ipv4_address>");
03066         cfg_print_cstr(pctx, " ");
03067         cfg_print_cstr(pctx, "[ port <integer> ]");
03068         cfg_print_cstr(pctx, " ");
03069         cfg_print_cstr(pctx, "[ dscp <integer> ]");
03070         cfg_print_cstr(pctx, " | ");
03071         cfg_print_cstr(pctx, "<ipv6_address>");
03072         cfg_print_cstr(pctx, " ");
03073         cfg_print_cstr(pctx, "[ port <integer> ]");
03074         cfg_print_cstr(pctx, " ");
03075         cfg_print_cstr(pctx, "[ dscp <integer> ]");
03076         cfg_print_cstr(pctx, " )");
03077 }
03078 
03079 static isc_result_t
03080 parse_sockaddrnameport(cfg_parser_t *pctx, const cfg_type_t *type,
03081                        cfg_obj_t **ret)
03082 {
03083         isc_result_t result;
03084         cfg_obj_t *obj = NULL;
03085         UNUSED(type);
03086 
03087         CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
03088         if (pctx->token.type == isc_tokentype_string ||
03089             pctx->token.type == isc_tokentype_qstring) {
03090                 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
03091                         CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, ret));
03092                 else {
03093                         const cfg_tuplefielddef_t *fields =
03094                                                    cfg_type_nameport.of;
03095                         CHECK(cfg_create_tuple(pctx, &cfg_type_nameport,
03096                                                &obj));
03097                         CHECK(cfg_parse_obj(pctx, fields[0].type,
03098                                             &obj->value.tuple[0]));
03099                         CHECK(cfg_parse_obj(pctx, fields[1].type,
03100                                             &obj->value.tuple[1]));
03101                         CHECK(cfg_parse_obj(pctx, fields[2].type,
03102                                             &obj->value.tuple[2]));
03103                         *ret = obj;
03104                         obj = NULL;
03105                 }
03106         } else {
03107                 cfg_parser_error(pctx, CFG_LOG_NEAR,
03108                              "expected IP address or hostname");
03109                 return (ISC_R_UNEXPECTEDTOKEN);
03110         }
03111  cleanup:
03112         CLEANUP_OBJ(obj);
03113         return (result);
03114 }
03115 
03116 static cfg_type_t cfg_type_sockaddrnameport = {
03117         "sockaddrnameport_element", parse_sockaddrnameport, NULL,
03118          doc_sockaddrnameport, NULL, NULL
03119 };
03120 
03121 static cfg_type_t cfg_type_bracketed_sockaddrnameportlist = {
03122         "bracketed_sockaddrnameportlist", cfg_parse_bracketed_list,
03123         cfg_print_bracketed_list, cfg_doc_bracketed_list,
03124         &cfg_rep_list, &cfg_type_sockaddrnameport
03125 };
03126 
03127 /*%
03128  * A list of socket addresses or name with an optional default port,
03129  * as used in the dual-stack-servers option.  E.g.,
03130  * "port 1234 { dual-stack-servers.net; 10.0.0.1; 1::2 port 69; }"
03131  */
03132 static cfg_tuplefielddef_t nameportiplist_fields[] = {
03133         { "port", &cfg_type_optional_port, 0 },
03134         { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 },
03135         { NULL, NULL, 0 }
03136 };
03137 
03138 static cfg_type_t cfg_type_nameportiplist = {
03139         "nameportiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
03140         &cfg_rep_tuple, nameportiplist_fields
03141 };
03142 
03143 /*%
03144  * masters element.
03145  */
03146 
03147 static void
03148 doc_masterselement(cfg_printer_t *pctx, const cfg_type_t *type) {
03149         UNUSED(type);
03150         cfg_print_cstr(pctx, "( ");
03151         cfg_print_cstr(pctx, "<masters>");
03152         cfg_print_cstr(pctx, " | ");
03153         cfg_print_cstr(pctx, "<ipv4_address>");
03154         cfg_print_cstr(pctx, " ");
03155         cfg_print_cstr(pctx, "[ port <integer> ]");
03156         cfg_print_cstr(pctx, " | ");
03157         cfg_print_cstr(pctx, "<ipv6_address>");
03158         cfg_print_cstr(pctx, " ");
03159         cfg_print_cstr(pctx, "[ port <integer> ]");
03160         cfg_print_cstr(pctx, " )");
03161 }
03162 
03163 static isc_result_t
03164 parse_masterselement(cfg_parser_t *pctx, const cfg_type_t *type,
03165                      cfg_obj_t **ret)
03166 {
03167         isc_result_t result;
03168         cfg_obj_t *obj = NULL;
03169         UNUSED(type);
03170 
03171         CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
03172         if (pctx->token.type == isc_tokentype_string ||
03173             pctx->token.type == isc_tokentype_qstring) {
03174                 if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
03175                         CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, ret));
03176                 else
03177                         CHECK(cfg_parse_astring(pctx, &cfg_type_astring, ret));
03178         } else {
03179                 cfg_parser_error(pctx, CFG_LOG_NEAR,
03180                              "expected IP address or masters name");
03181                 return (ISC_R_UNEXPECTEDTOKEN);
03182         }
03183  cleanup:
03184         CLEANUP_OBJ(obj);
03185         return (result);
03186 }
03187 
03188 static cfg_type_t cfg_type_masterselement = {
03189         "masters_element", parse_masterselement, NULL,
03190          doc_masterselement, NULL, NULL
03191 };
03192 
03193 static isc_result_t
03194 parse_ttlval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
03195         isc_result_t result;
03196         cfg_obj_t *obj = NULL;
03197         isc_uint32_t ttl;
03198 
03199         UNUSED(type);
03200 
03201         CHECK(cfg_gettoken(pctx, 0));
03202         if (pctx->token.type != isc_tokentype_string) {
03203                 result = ISC_R_UNEXPECTEDTOKEN;
03204                 goto cleanup;
03205         }
03206 
03207         result = dns_ttl_fromtext(&pctx->token.value.as_textregion, &ttl);
03208         if (result == ISC_R_RANGE ) {
03209                 cfg_parser_error(pctx, CFG_LOG_NEAR, "TTL out of range ");
03210                 return (result);
03211         } else if (result != ISC_R_SUCCESS)
03212                 goto cleanup;
03213 
03214         CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj));
03215         obj->value.uint32 = ttl;
03216         *ret = obj;
03217         return (ISC_R_SUCCESS);
03218 
03219  cleanup:
03220         cfg_parser_error(pctx, CFG_LOG_NEAR, "expected integer and optional unit");
03221         return (result);
03222 }
03223 
03224 /*%
03225  * A TTL value (number + optional unit).
03226  */
03227 static cfg_type_t cfg_type_ttlval = {
03228         "ttlval", parse_ttlval, cfg_print_uint64, cfg_doc_terminal,
03229         &cfg_rep_uint64, NULL
03230 };
03231 
03232 static isc_result_t
03233 parse_maxttl(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
03234         return (parse_enum_or_other(pctx, type, &cfg_type_ttlval, ret));
03235 }
03236 
03237 /*%
03238  * A size or "unlimited", but not "default".
03239  */
03240 static const char *maxttl_enums[] = { "unlimited", NULL };
03241 static cfg_type_t cfg_type_maxttl = {
03242         "maxttl_no_default", parse_maxttl, cfg_print_ustring, cfg_doc_terminal,
03243         &cfg_rep_string, maxttl_enums
03244 };

Generated on Tue Apr 28 17:41:06 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha