2 * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
24 #include <isc/buffer.h>
26 #include <isc/formatcheck.h>
31 #include <isc/netaddr.h>
32 #include <isc/netscope.h>
33 #include <isc/print.h>
34 #include <isc/string.h>
35 #include <isc/sockaddr.h>
36 #include <isc/symtab.h>
39 #include <isccfg/cfg.h>
40 #include <isccfg/grammar.h>
41 #include <isccfg/log.h>
44 #define CAT CFG_LOGCATEGORY_CONFIG
45 #define MOD CFG_LOGMODULE_PARSER
47 #define MAP_SYM 1 /* Unique type for isc_symtab */
49 #define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
51 /* Check a return value. */
54 if (result != ISC_R_SUCCESS) goto cleanup; \
57 /* Clean up a configuration object if non-NULL. */
58 #define CLEANUP_OBJ(obj) \
59 do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
63 * Forward declarations of static functions.
67 free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj);
70 parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
73 print_list(cfg_printer_t *pctx, const cfg_obj_t *obj);
76 free_list(cfg_parser_t *pctx, cfg_obj_t *obj);
79 create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp);
82 create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
86 free_string(cfg_parser_t *pctx, cfg_obj_t *obj);
89 create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
92 free_map(cfg_parser_t *pctx, cfg_obj_t *obj);
95 parse_symtab_elt(cfg_parser_t *pctx, const char *name,
96 cfg_type_t *elttype, isc_symtab_t *symtab,
97 isc_boolean_t callback);
100 free_noop(cfg_parser_t *pctx, cfg_obj_t *obj);
103 cfg_getstringtoken(cfg_parser_t *pctx);
106 parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning,
107 unsigned int flags, const char *format, va_list args);
110 * Data representations. These correspond to members of the
111 * "value" union in struct cfg_obj (except "void", which does
112 * not need a union member).
115 cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop };
116 cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop };
117 cfg_rep_t cfg_rep_string = { "string", free_string };
118 cfg_rep_t cfg_rep_boolean = { "boolean", free_noop };
119 cfg_rep_t cfg_rep_map = { "map", free_map };
120 cfg_rep_t cfg_rep_list = { "list", free_list };
121 cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple };
122 cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop };
123 cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop };
124 cfg_rep_t cfg_rep_void = { "void", free_noop };
127 * Configuration type definitions.
131 * An implicit list. These are formed by clauses that occur multiple times.
133 static cfg_type_t cfg_type_implicitlist = {
134 "implicitlist", NULL, print_list, NULL, &cfg_rep_list, NULL };
139 cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj) {
140 obj->type->print(pctx, obj);
144 cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) {
145 pctx->f(pctx->closure, text, len);
149 print_open(cfg_printer_t *pctx) {
150 cfg_print_chars(pctx, "{\n", 2);
155 print_indent(cfg_printer_t *pctx) {
156 int indent = pctx->indent;
158 cfg_print_chars(pctx, "\t", 1);
164 print_close(cfg_printer_t *pctx) {
167 cfg_print_chars(pctx, "}", 1);
171 cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
173 INSIST(ret != NULL && *ret == NULL);
174 result = type->parse(pctx, type, ret);
175 if (result != ISC_R_SUCCESS)
177 INSIST(*ret != NULL);
178 return (ISC_R_SUCCESS);
182 cfg_print(const cfg_obj_t *obj,
183 void (*f)(void *closure, const char *text, int textlen),
188 pctx.closure = closure;
190 obj->type->print(&pctx, obj);
197 cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
199 const cfg_tuplefielddef_t *fields = type->of;
200 const cfg_tuplefielddef_t *f;
201 cfg_obj_t *obj = NULL;
202 unsigned int nfields = 0;
205 for (f = fields; f->name != NULL; f++)
208 CHECK(cfg_create_obj(pctx, type, &obj));
209 obj->value.tuple = isc_mem_get(pctx->mctx,
210 nfields * sizeof(cfg_obj_t *));
211 if (obj->value.tuple == NULL) {
212 result = ISC_R_NOMEMORY;
215 for (f = fields, i = 0; f->name != NULL; f++, i++)
216 obj->value.tuple[i] = NULL;
218 return (ISC_R_SUCCESS);
222 isc_mem_put(pctx->mctx, obj, sizeof(*obj));
227 cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
230 const cfg_tuplefielddef_t *fields = type->of;
231 const cfg_tuplefielddef_t *f;
232 cfg_obj_t *obj = NULL;
235 CHECK(cfg_create_tuple(pctx, type, &obj));
236 for (f = fields, i = 0; f->name != NULL; f++, i++)
237 CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i]));
240 return (ISC_R_SUCCESS);
248 cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
250 const cfg_tuplefielddef_t *fields = obj->type->of;
251 const cfg_tuplefielddef_t *f;
252 isc_boolean_t need_space = ISC_FALSE;
254 for (f = fields, i = 0; f->name != NULL; f++, i++) {
255 const cfg_obj_t *fieldobj = obj->value.tuple[i];
257 cfg_print_chars(pctx, " ", 1);
258 cfg_print_obj(pctx, fieldobj);
259 need_space = ISC_TF(fieldobj->type->print != cfg_print_void);
264 cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) {
265 const cfg_tuplefielddef_t *fields = type->of;
266 const cfg_tuplefielddef_t *f;
267 isc_boolean_t need_space = ISC_FALSE;
269 for (f = fields; f->name != NULL; f++) {
271 cfg_print_chars(pctx, " ", 1);
272 cfg_doc_obj(pctx, f->type);
273 need_space = ISC_TF(f->type->print != cfg_print_void);
278 free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) {
280 const cfg_tuplefielddef_t *fields = obj->type->of;
281 const cfg_tuplefielddef_t *f;
282 unsigned int nfields = 0;
284 if (obj->value.tuple == NULL)
287 for (f = fields, i = 0; f->name != NULL; f++, i++) {
288 CLEANUP_OBJ(obj->value.tuple[i]);
291 isc_mem_put(pctx->mctx, obj->value.tuple,
292 nfields * sizeof(cfg_obj_t *));
296 cfg_obj_istuple(const cfg_obj_t *obj) {
297 REQUIRE(obj != NULL);
298 return (ISC_TF(obj->type->rep == &cfg_rep_tuple));
302 cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) {
304 const cfg_tuplefielddef_t *fields;
305 const cfg_tuplefielddef_t *f;
307 REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple);
309 fields = tupleobj->type->of;
310 for (f = fields, i = 0; f->name != NULL; f++, i++) {
311 if (strcmp(f->name, name) == 0)
312 return (tupleobj->value.tuple[i]);
319 cfg_parse_special(cfg_parser_t *pctx, int special) {
321 CHECK(cfg_gettoken(pctx, 0));
322 if (pctx->token.type == isc_tokentype_special &&
323 pctx->token.value.as_char == special)
324 return (ISC_R_SUCCESS);
326 cfg_parser_error(pctx, CFG_LOG_NEAR, "'%c' expected", special);
327 return (ISC_R_UNEXPECTEDTOKEN);
333 * Parse a required semicolon. If it is not there, log
334 * an error and increment the error count but continue
335 * parsing. Since the next token is pushed back,
336 * care must be taken to make sure it is eventually
337 * consumed or an infinite loop may result.
340 parse_semicolon(cfg_parser_t *pctx) {
342 CHECK(cfg_gettoken(pctx, 0));
343 if (pctx->token.type == isc_tokentype_special &&
344 pctx->token.value.as_char == ';')
345 return (ISC_R_SUCCESS);
347 cfg_parser_error(pctx, CFG_LOG_BEFORE, "missing ';'");
348 cfg_ungettoken(pctx);
354 * Parse EOF, logging and returning an error if not there.
357 parse_eof(cfg_parser_t *pctx) {
359 CHECK(cfg_gettoken(pctx, 0));
361 if (pctx->token.type == isc_tokentype_eof)
362 return (ISC_R_SUCCESS);
364 cfg_parser_error(pctx, CFG_LOG_NEAR, "syntax error");
365 return (ISC_R_UNEXPECTEDTOKEN);
370 /* A list of files, used internally for pctx->files. */
372 static cfg_type_t cfg_type_filelist = {
373 "filelist", NULL, print_list, NULL, &cfg_rep_list,
378 cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) {
381 isc_lexspecials_t specials;
383 REQUIRE(mctx != NULL);
384 REQUIRE(ret != NULL && *ret == NULL);
386 pctx = isc_mem_get(mctx, sizeof(*pctx));
388 return (ISC_R_NOMEMORY);
390 result = isc_refcount_init(&pctx->references, 1);
391 if (result != ISC_R_SUCCESS) {
392 isc_mem_put(mctx, pctx, sizeof(*pctx));
399 pctx->seen_eof = ISC_FALSE;
400 pctx->ungotten = ISC_FALSE;
403 pctx->open_files = NULL;
404 pctx->closed_files = NULL;
406 pctx->callback = NULL;
407 pctx->callbackarg = NULL;
408 pctx->token.type = isc_tokentype_unknown;
411 memset(specials, 0, sizeof(specials));
419 CHECK(isc_lex_create(pctx->mctx, 1024, &pctx->lexer));
421 isc_lex_setspecials(pctx->lexer, specials);
422 isc_lex_setcomments(pctx->lexer, (ISC_LEXCOMMENT_C |
423 ISC_LEXCOMMENT_CPLUSPLUS |
424 ISC_LEXCOMMENT_SHELL));
426 CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->open_files));
427 CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->closed_files));
430 return (ISC_R_SUCCESS);
433 if (pctx->lexer != NULL)
434 isc_lex_destroy(&pctx->lexer);
435 CLEANUP_OBJ(pctx->open_files);
436 CLEANUP_OBJ(pctx->closed_files);
437 isc_mem_put(mctx, pctx, sizeof(*pctx));
442 parser_openfile(cfg_parser_t *pctx, const char *filename) {
444 cfg_listelt_t *elt = NULL;
445 cfg_obj_t *stringobj = NULL;
447 result = isc_lex_openfile(pctx->lexer, filename);
448 if (result != ISC_R_SUCCESS) {
449 cfg_parser_error(pctx, 0, "open: %s: %s",
450 filename, isc_result_totext(result));
454 CHECK(create_string(pctx, filename, &cfg_type_qstring, &stringobj));
455 CHECK(create_listelt(pctx, &elt));
456 elt->obj = stringobj;
457 ISC_LIST_APPEND(pctx->open_files->value.list, elt, link);
459 return (ISC_R_SUCCESS);
461 CLEANUP_OBJ(stringobj);
466 cfg_parser_setcallback(cfg_parser_t *pctx,
467 cfg_parsecallback_t callback,
470 pctx->callback = callback;
471 pctx->callbackarg = arg;
475 * Parse a configuration using a pctx where a lexer has already
476 * been set up with a source.
479 parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
481 cfg_obj_t *obj = NULL;
483 result = cfg_parse_obj(pctx, type, &obj);
485 if (pctx->errors != 0) {
486 /* Errors have been logged. */
487 if (result == ISC_R_SUCCESS)
488 result = ISC_R_FAILURE;
492 if (result != ISC_R_SUCCESS) {
493 /* Parsing failed but no errors have been logged. */
494 cfg_parser_error(pctx, 0, "parsing failed");
498 CHECK(parse_eof(pctx));
501 return (ISC_R_SUCCESS);
509 cfg_parse_file(cfg_parser_t *pctx, const char *filename,
510 const cfg_type_t *type, cfg_obj_t **ret)
514 REQUIRE(filename != NULL);
516 CHECK(parser_openfile(pctx, filename));
517 CHECK(parse2(pctx, type, ret));
524 cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer,
525 const cfg_type_t *type, cfg_obj_t **ret)
528 REQUIRE(buffer != NULL);
529 CHECK(isc_lex_openbuffer(pctx->lexer, buffer));
530 CHECK(parse2(pctx, type, ret));
536 cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest) {
537 REQUIRE(src != NULL);
538 REQUIRE(dest != NULL && *dest == NULL);
539 isc_refcount_increment(&src->references, NULL);
544 cfg_parser_destroy(cfg_parser_t **pctxp) {
545 cfg_parser_t *pctx = *pctxp;
548 isc_refcount_decrement(&pctx->references, &refs);
550 isc_lex_destroy(&pctx->lexer);
552 * Cleaning up open_files does not
553 * close the files; that was already done
554 * by closing the lexer.
556 CLEANUP_OBJ(pctx->open_files);
557 CLEANUP_OBJ(pctx->closed_files);
558 isc_mem_put(pctx->mctx, pctx, sizeof(*pctx));
567 cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
569 return (cfg_create_obj(pctx, &cfg_type_void, ret));
573 cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj) {
579 cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) {
585 cfg_obj_isvoid(const cfg_obj_t *obj) {
586 REQUIRE(obj != NULL);
587 return (ISC_TF(obj->type->rep == &cfg_rep_void));
590 cfg_type_t cfg_type_void = {
591 "void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void,
599 cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
601 cfg_obj_t *obj = NULL;
604 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
605 if (pctx->token.type != isc_tokentype_number) {
606 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected number");
607 return (ISC_R_UNEXPECTEDTOKEN);
610 CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj));
612 obj->value.uint32 = pctx->token.value.as_ulong;
619 cfg_print_cstr(cfg_printer_t *pctx, const char *s) {
620 cfg_print_chars(pctx, s, strlen(s));
624 cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) {
626 snprintf(buf, sizeof(buf), "%u", u);
627 cfg_print_cstr(pctx, buf);
631 cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj) {
632 cfg_print_rawuint(pctx, obj->value.uint32);
636 cfg_obj_isuint32(const cfg_obj_t *obj) {
637 REQUIRE(obj != NULL);
638 return (ISC_TF(obj->type->rep == &cfg_rep_uint32));
642 cfg_obj_asuint32(const cfg_obj_t *obj) {
643 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32);
644 return (obj->value.uint32);
647 cfg_type_t cfg_type_uint32 = {
648 "integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal,
649 &cfg_rep_uint32, NULL
657 cfg_obj_isuint64(const cfg_obj_t *obj) {
658 REQUIRE(obj != NULL);
659 return (ISC_TF(obj->type->rep == &cfg_rep_uint64));
663 cfg_obj_asuint64(const cfg_obj_t *obj) {
664 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint64);
665 return (obj->value.uint64);
669 cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj) {
671 snprintf(buf, sizeof(buf), "%" ISC_PRINT_QUADFORMAT "u",
673 cfg_print_cstr(pctx, buf);
676 cfg_type_t cfg_type_uint64 = {
677 "64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal,
678 &cfg_rep_uint64, NULL
682 * qstring (quoted string), ustring (unquoted string), astring
686 /* Create a string object from a null-terminated C string. */
688 create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
692 cfg_obj_t *obj = NULL;
695 CHECK(cfg_create_obj(pctx, type, &obj));
696 len = strlen(contents);
697 obj->value.string.length = len;
698 obj->value.string.base = isc_mem_get(pctx->mctx, len + 1);
699 if (obj->value.string.base == 0) {
700 isc_mem_put(pctx->mctx, obj, sizeof(*obj));
701 return (ISC_R_NOMEMORY);
703 memcpy(obj->value.string.base, contents, len);
704 obj->value.string.base[len] = '\0';
712 cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
716 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
717 if (pctx->token.type != isc_tokentype_qstring) {
718 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string");
719 return (ISC_R_UNEXPECTEDTOKEN);
721 return (create_string(pctx,
730 parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
734 CHECK(cfg_gettoken(pctx, 0));
735 if (pctx->token.type != isc_tokentype_string) {
736 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected unquoted string");
737 return (ISC_R_UNEXPECTEDTOKEN);
739 return (create_string(pctx,
748 cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type,
754 CHECK(cfg_getstringtoken(pctx));
755 return (create_string(pctx,
764 cfg_is_enum(const char *s, const char *const *enums) {
765 const char * const *p;
766 for (p = enums; *p != NULL; p++) {
767 if (strcasecmp(*p, s) == 0)
774 check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) {
775 const char *s = obj->value.string.base;
776 if (cfg_is_enum(s, enums))
777 return (ISC_R_SUCCESS);
778 cfg_parser_error(pctx, 0, "'%s' unexpected", s);
779 return (ISC_R_UNEXPECTEDTOKEN);
783 cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
785 cfg_obj_t *obj = NULL;
786 CHECK(parse_ustring(pctx, NULL, &obj));
787 CHECK(check_enum(pctx, obj, type->of));
789 return (ISC_R_SUCCESS);
796 cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
797 const char * const *p;
798 cfg_print_chars(pctx, "( ", 2);
799 for (p = type->of; *p != NULL; p++) {
800 cfg_print_cstr(pctx, *p);
802 cfg_print_chars(pctx, " | ", 3);
804 cfg_print_chars(pctx, " )", 2);
808 cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
809 cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
813 print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
814 cfg_print_chars(pctx, "\"", 1);
815 cfg_print_ustring(pctx, obj);
816 cfg_print_chars(pctx, "\"", 1);
820 free_string(cfg_parser_t *pctx, cfg_obj_t *obj) {
821 isc_mem_put(pctx->mctx, obj->value.string.base,
822 obj->value.string.length + 1);
826 cfg_obj_isstring(const cfg_obj_t *obj) {
827 REQUIRE(obj != NULL);
828 return (ISC_TF(obj->type->rep == &cfg_rep_string));
832 cfg_obj_asstring(const cfg_obj_t *obj) {
833 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string);
834 return (obj->value.string.base);
837 /* Quoted string only */
838 cfg_type_t cfg_type_qstring = {
839 "quoted_string", cfg_parse_qstring, print_qstring, cfg_doc_terminal,
840 &cfg_rep_string, NULL
843 /* Unquoted string only */
844 cfg_type_t cfg_type_ustring = {
845 "string", parse_ustring, cfg_print_ustring, cfg_doc_terminal,
846 &cfg_rep_string, NULL
849 /* Any string (quoted or unquoted); printed with quotes */
850 cfg_type_t cfg_type_astring = {
851 "string", cfg_parse_astring, print_qstring, cfg_doc_terminal,
852 &cfg_rep_string, NULL
860 cfg_obj_isboolean(const cfg_obj_t *obj) {
861 REQUIRE(obj != NULL);
862 return (ISC_TF(obj->type->rep == &cfg_rep_boolean));
866 cfg_obj_asboolean(const cfg_obj_t *obj) {
867 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean);
868 return (obj->value.boolean);
872 cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
876 cfg_obj_t *obj = NULL;
879 result = cfg_gettoken(pctx, 0);
880 if (result != ISC_R_SUCCESS)
883 if (pctx->token.type != isc_tokentype_string)
886 if ((strcasecmp(TOKEN_STRING(pctx), "true") == 0) ||
887 (strcasecmp(TOKEN_STRING(pctx), "yes") == 0) ||
888 (strcmp(TOKEN_STRING(pctx), "1") == 0)) {
890 } else if ((strcasecmp(TOKEN_STRING(pctx), "false") == 0) ||
891 (strcasecmp(TOKEN_STRING(pctx), "no") == 0) ||
892 (strcmp(TOKEN_STRING(pctx), "0") == 0)) {
898 CHECK(cfg_create_obj(pctx, &cfg_type_boolean, &obj));
899 obj->value.boolean = value;
904 cfg_parser_error(pctx, CFG_LOG_NEAR, "boolean expected");
905 return (ISC_R_UNEXPECTEDTOKEN);
912 cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) {
913 if (obj->value.boolean)
914 cfg_print_chars(pctx, "yes", 3);
916 cfg_print_chars(pctx, "no", 2);
919 cfg_type_t cfg_type_boolean = {
920 "boolean", cfg_parse_boolean, cfg_print_boolean, cfg_doc_terminal,
921 &cfg_rep_boolean, NULL
929 cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) {
931 CHECK(cfg_create_obj(pctx, type, obj));
932 ISC_LIST_INIT((*obj)->value.list);
938 create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) {
940 elt = isc_mem_get(pctx->mctx, sizeof(*elt));
942 return (ISC_R_NOMEMORY);
944 ISC_LINK_INIT(elt, link);
946 return (ISC_R_SUCCESS);
950 free_list_elt(cfg_parser_t *pctx, cfg_listelt_t *elt) {
951 cfg_obj_destroy(pctx, &elt->obj);
952 isc_mem_put(pctx->mctx, elt, sizeof(*elt));
956 free_list(cfg_parser_t *pctx, cfg_obj_t *obj) {
957 cfg_listelt_t *elt, *next;
958 for (elt = ISC_LIST_HEAD(obj->value.list);
962 next = ISC_LIST_NEXT(elt, link);
963 free_list_elt(pctx, elt);
968 cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype,
972 cfg_listelt_t *elt = NULL;
973 cfg_obj_t *value = NULL;
975 CHECK(create_listelt(pctx, &elt));
977 result = cfg_parse_obj(pctx, elttype, &value);
978 if (result != ISC_R_SUCCESS)
984 return (ISC_R_SUCCESS);
987 isc_mem_put(pctx->mctx, elt, sizeof(*elt));
992 * Parse a homogeneous list whose elements are of type 'elttype'
993 * and where each element is terminated by a semicolon.
996 parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret)
998 cfg_obj_t *listobj = NULL;
999 const cfg_type_t *listof = listtype->of;
1000 isc_result_t result;
1001 cfg_listelt_t *elt = NULL;
1003 CHECK(cfg_create_list(pctx, listtype, &listobj));
1006 CHECK(cfg_peektoken(pctx, 0));
1007 if (pctx->token.type == isc_tokentype_special &&
1008 pctx->token.value.as_char == /*{*/ '}')
1010 CHECK(cfg_parse_listelt(pctx, listof, &elt));
1011 CHECK(parse_semicolon(pctx));
1012 ISC_LIST_APPEND(listobj->value.list, elt, link);
1016 return (ISC_R_SUCCESS);
1020 free_list_elt(pctx, elt);
1021 CLEANUP_OBJ(listobj);
1026 print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1027 const cfg_list_t *list = &obj->value.list;
1028 const cfg_listelt_t *elt;
1030 for (elt = ISC_LIST_HEAD(*list);
1032 elt = ISC_LIST_NEXT(elt, link)) {
1034 cfg_print_obj(pctx, elt->obj);
1035 cfg_print_chars(pctx, ";\n", 2);
1040 cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type,
1043 isc_result_t result;
1044 CHECK(cfg_parse_special(pctx, '{'));
1045 CHECK(parse_list(pctx, type, ret));
1046 CHECK(cfg_parse_special(pctx, '}'));
1052 cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1054 print_list(pctx, obj);
1059 cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
1060 cfg_print_chars(pctx, "{ ", 2);
1061 cfg_doc_obj(pctx, type->of);
1062 cfg_print_chars(pctx, "; ... }", 7);
1066 * Parse a homogeneous list whose elements are of type 'elttype'
1067 * and where elements are separated by space. The list ends
1068 * before the first semicolon.
1071 cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype,
1074 cfg_obj_t *listobj = NULL;
1075 const cfg_type_t *listof = listtype->of;
1076 isc_result_t result;
1078 CHECK(cfg_create_list(pctx, listtype, &listobj));
1081 cfg_listelt_t *elt = NULL;
1083 CHECK(cfg_peektoken(pctx, 0));
1084 if (pctx->token.type == isc_tokentype_special &&
1085 pctx->token.value.as_char == ';')
1087 CHECK(cfg_parse_listelt(pctx, listof, &elt));
1088 ISC_LIST_APPEND(listobj->value.list, elt, link);
1091 return (ISC_R_SUCCESS);
1094 CLEANUP_OBJ(listobj);
1099 cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1100 const cfg_list_t *list = &obj->value.list;
1101 const cfg_listelt_t *elt;
1103 for (elt = ISC_LIST_HEAD(*list);
1105 elt = ISC_LIST_NEXT(elt, link)) {
1106 cfg_print_obj(pctx, elt->obj);
1107 if (ISC_LIST_NEXT(elt, link) != NULL)
1108 cfg_print_chars(pctx, " ", 1);
1113 cfg_obj_islist(const cfg_obj_t *obj) {
1114 REQUIRE(obj != NULL);
1115 return (ISC_TF(obj->type->rep == &cfg_rep_list));
1118 const cfg_listelt_t *
1119 cfg_list_first(const cfg_obj_t *obj) {
1120 REQUIRE(obj == NULL || obj->type->rep == &cfg_rep_list);
1123 return (ISC_LIST_HEAD(obj->value.list));
1126 const cfg_listelt_t *
1127 cfg_list_next(const cfg_listelt_t *elt) {
1128 REQUIRE(elt != NULL);
1129 return (ISC_LIST_NEXT(elt, link));
1133 * Return the length of a list object. If obj is NULL or is not
1137 cfg_list_length(const cfg_obj_t *obj, isc_boolean_t recurse) {
1138 const cfg_listelt_t *elt;
1139 unsigned int count = 0;
1141 if (obj == NULL || !cfg_obj_islist(obj))
1143 for (elt = cfg_list_first(obj);
1145 elt = cfg_list_next(elt)) {
1146 if (recurse && cfg_obj_islist(elt->obj)) {
1147 count += cfg_list_length(elt->obj, recurse);
1156 cfg_listelt_value(const cfg_listelt_t *elt) {
1157 REQUIRE(elt != NULL);
1166 * Parse a map body. That's something like
1168 * "foo 1; bar { glub; }; zap true; zap false;"
1170 * i.e., a sequence of option names followed by values and
1171 * terminated by semicolons. Used for the top level of
1172 * the named.conf syntax, as well as for the body of the
1173 * options, view, zone, and other statements.
1176 cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
1178 const cfg_clausedef_t * const *clausesets = type->of;
1179 isc_result_t result;
1180 const cfg_clausedef_t * const *clauseset;
1181 const cfg_clausedef_t *clause;
1182 cfg_obj_t *value = NULL;
1183 cfg_obj_t *obj = NULL;
1184 cfg_obj_t *eltobj = NULL;
1185 cfg_obj_t *includename = NULL;
1186 isc_symvalue_t symval;
1187 cfg_list_t *list = NULL;
1189 CHECK(create_map(pctx, type, &obj));
1191 obj->value.map.clausesets = clausesets;
1198 * Parse the option name and see if it is known.
1200 CHECK(cfg_gettoken(pctx, 0));
1202 if (pctx->token.type != isc_tokentype_string) {
1203 cfg_ungettoken(pctx);
1208 * We accept "include" statements wherever a map body
1211 if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) {
1213 * Turn the file name into a temporary configuration
1214 * object just so that it is not overwritten by the
1217 CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename));
1218 CHECK(parse_semicolon(pctx));
1219 CHECK(parser_openfile(pctx, includename->
1220 value.string.base));
1221 cfg_obj_destroy(pctx, &includename);
1226 for (clauseset = clausesets; *clauseset != NULL; clauseset++) {
1227 for (clause = *clauseset;
1228 clause->name != NULL;
1230 if (strcasecmp(TOKEN_STRING(pctx),
1236 if (clause == NULL || clause->name == NULL) {
1237 cfg_parser_error(pctx, CFG_LOG_NOPREP, "unknown option");
1239 * Try to recover by parsing this option as an unknown
1240 * option and discarding it.
1242 CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported, &eltobj));
1243 cfg_obj_destroy(pctx, &eltobj);
1244 CHECK(parse_semicolon(pctx));
1248 /* Clause is known. */
1250 /* Issue warnings if appropriate */
1251 if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0)
1252 cfg_parser_warning(pctx, 0, "option '%s' is obsolete",
1254 if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0)
1255 cfg_parser_warning(pctx, 0, "option '%s' is "
1256 "not implemented", clause->name);
1257 if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0)
1258 cfg_parser_warning(pctx, 0, "option '%s' is "
1259 "not implemented", clause->name);
1261 if ((clause->flags & CFG_CLAUSEFLAG_NOTCONFIGURED) != 0) {
1262 cfg_parser_warning(pctx, 0, "option '%s' is not "
1263 "configured", clause->name);
1264 result = ISC_R_FAILURE;
1269 * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT
1270 * set here - we need to log the *lack* of such an option,
1274 /* See if the clause already has a value; if not create one. */
1275 result = isc_symtab_lookup(obj->value.map.symtab,
1276 clause->name, 0, &symval);
1278 if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
1279 /* Multivalued clause */
1280 cfg_obj_t *listobj = NULL;
1281 if (result == ISC_R_NOTFOUND) {
1282 CHECK(cfg_create_list(pctx,
1283 &cfg_type_implicitlist,
1285 symval.as_pointer = listobj;
1286 result = isc_symtab_define(obj->value.
1290 isc_symexists_reject);
1291 if (result != ISC_R_SUCCESS) {
1292 cfg_parser_error(pctx, CFG_LOG_NEAR,
1293 "isc_symtab_define(%s) "
1294 "failed", clause->name);
1295 isc_mem_put(pctx->mctx, list,
1296 sizeof(cfg_list_t));
1300 INSIST(result == ISC_R_SUCCESS);
1301 listobj = symval.as_pointer;
1305 CHECK(cfg_parse_listelt(pctx, clause->type, &elt));
1306 CHECK(parse_semicolon(pctx));
1308 ISC_LIST_APPEND(listobj->value.list, elt, link);
1310 /* Single-valued clause */
1311 if (result == ISC_R_NOTFOUND) {
1312 isc_boolean_t callback =
1313 ISC_TF((clause->flags &
1314 CFG_CLAUSEFLAG_CALLBACK) != 0);
1315 CHECK(parse_symtab_elt(pctx, clause->name,
1317 obj->value.map.symtab,
1319 CHECK(parse_semicolon(pctx));
1320 } else if (result == ISC_R_SUCCESS) {
1321 cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined",
1323 result = ISC_R_EXISTS;
1326 cfg_parser_error(pctx, CFG_LOG_NEAR,
1327 "isc_symtab_define() failed");
1335 return (ISC_R_SUCCESS);
1340 CLEANUP_OBJ(eltobj);
1341 CLEANUP_OBJ(includename);
1346 parse_symtab_elt(cfg_parser_t *pctx, const char *name,
1347 cfg_type_t *elttype, isc_symtab_t *symtab,
1348 isc_boolean_t callback)
1350 isc_result_t result;
1351 cfg_obj_t *obj = NULL;
1352 isc_symvalue_t symval;
1354 CHECK(cfg_parse_obj(pctx, elttype, &obj));
1356 if (callback && pctx->callback != NULL)
1357 CHECK(pctx->callback(name, obj, pctx->callbackarg));
1359 symval.as_pointer = obj;
1360 CHECK(isc_symtab_define(symtab, name,
1362 isc_symexists_reject));
1363 return (ISC_R_SUCCESS);
1371 * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
1374 cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1375 isc_result_t result;
1376 CHECK(cfg_parse_special(pctx, '{'));
1377 CHECK(cfg_parse_mapbody(pctx, type, ret));
1378 CHECK(cfg_parse_special(pctx, '}'));
1384 * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map().
1387 parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t *type,
1390 isc_result_t result;
1391 cfg_obj_t *idobj = NULL;
1392 cfg_obj_t *mapobj = NULL;
1394 CHECK(cfg_parse_obj(pctx, nametype, &idobj));
1395 CHECK(cfg_parse_map(pctx, type, &mapobj));
1396 mapobj->value.map.id = idobj;
1405 * Parse a map identified by a string name. E.g., "name { foo 1; }".
1406 * Used for the "key" and "channel" statements.
1409 cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1410 return (parse_any_named_map(pctx, &cfg_type_astring, type, ret));
1414 * Parse a map identified by a network address.
1415 * Used to be used for the "server" statement.
1418 cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1419 return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret));
1423 * Parse a map identified by a network prefix.
1424 * Used for the "server" statement.
1427 cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1428 return (parse_any_named_map(pctx, &cfg_type_netprefix, type, ret));
1432 cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1433 isc_result_t result = ISC_R_SUCCESS;
1435 const cfg_clausedef_t * const *clauseset;
1437 for (clauseset = obj->value.map.clausesets;
1441 isc_symvalue_t symval;
1442 const cfg_clausedef_t *clause;
1444 for (clause = *clauseset;
1445 clause->name != NULL;
1447 result = isc_symtab_lookup(obj->value.map.symtab,
1448 clause->name, 0, &symval);
1449 if (result == ISC_R_SUCCESS) {
1450 cfg_obj_t *obj = symval.as_pointer;
1451 if (obj->type == &cfg_type_implicitlist) {
1453 cfg_list_t *list = &obj->value.list;
1455 for (elt = ISC_LIST_HEAD(*list);
1457 elt = ISC_LIST_NEXT(elt, link)) {
1459 cfg_print_cstr(pctx, clause->name);
1460 cfg_print_chars(pctx, " ", 1);
1461 cfg_print_obj(pctx, elt->obj);
1462 cfg_print_chars(pctx, ";\n", 2);
1465 /* Single-valued. */
1467 cfg_print_cstr(pctx, clause->name);
1468 cfg_print_chars(pctx, " ", 1);
1469 cfg_print_obj(pctx, obj);
1470 cfg_print_chars(pctx, ";\n", 2);
1472 } else if (result == ISC_R_NOTFOUND) {
1482 cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) {
1483 const cfg_clausedef_t * const *clauseset;
1484 const cfg_clausedef_t *clause;
1486 for (clauseset = type->of; *clauseset != NULL; clauseset++) {
1487 for (clause = *clauseset;
1488 clause->name != NULL;
1490 cfg_print_cstr(pctx, clause->name);
1491 cfg_print_chars(pctx, " ", 1);
1492 cfg_doc_obj(pctx, clause->type);
1493 cfg_print_chars(pctx, ";", 1);
1494 /* XXX print flags here? */
1495 cfg_print_chars(pctx, "\n\n", 2);
1500 static struct flagtext {
1504 { CFG_CLAUSEFLAG_NOTIMP, "not implemented" },
1505 { CFG_CLAUSEFLAG_NYI, "not yet implemented" },
1506 { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" },
1507 { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" },
1508 { CFG_CLAUSEFLAG_TESTONLY, "test only" },
1509 { CFG_CLAUSEFLAG_NOTCONFIGURED, "not configured" },
1514 cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1515 if (obj->value.map.id != NULL) {
1516 cfg_print_obj(pctx, obj->value.map.id);
1517 cfg_print_chars(pctx, " ", 1);
1520 cfg_print_mapbody(pctx, obj);
1525 print_clause_flags(cfg_printer_t *pctx, unsigned int flags) {
1527 isc_boolean_t first = ISC_TRUE;
1528 for (p = flagtexts; p->flag != 0; p++) {
1529 if ((flags & p->flag) != 0) {
1531 cfg_print_chars(pctx, " // ", 4);
1533 cfg_print_chars(pctx, ", ", 2);
1534 cfg_print_cstr(pctx, p->text);
1541 cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) {
1542 const cfg_clausedef_t * const *clauseset;
1543 const cfg_clausedef_t *clause;
1545 if (type->parse == cfg_parse_named_map) {
1546 cfg_doc_obj(pctx, &cfg_type_astring);
1547 cfg_print_chars(pctx, " ", 1);
1548 } else if (type->parse == cfg_parse_addressed_map) {
1549 cfg_doc_obj(pctx, &cfg_type_netaddr);
1550 cfg_print_chars(pctx, " ", 1);
1551 } else if (type->parse == cfg_parse_netprefix_map) {
1552 cfg_doc_obj(pctx, &cfg_type_netprefix);
1553 cfg_print_chars(pctx, " ", 1);
1558 for (clauseset = type->of; *clauseset != NULL; clauseset++) {
1559 for (clause = *clauseset;
1560 clause->name != NULL;
1563 cfg_print_cstr(pctx, clause->name);
1564 if (clause->type->print != cfg_print_void)
1565 cfg_print_chars(pctx, " ", 1);
1566 cfg_doc_obj(pctx, clause->type);
1567 cfg_print_chars(pctx, ";", 1);
1568 print_clause_flags(pctx, clause->flags);
1569 cfg_print_chars(pctx, "\n", 1);
1576 cfg_obj_ismap(const cfg_obj_t *obj) {
1577 REQUIRE(obj != NULL);
1578 return (ISC_TF(obj->type->rep == &cfg_rep_map));
1582 cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) {
1583 isc_result_t result;
1585 const cfg_map_t *map;
1587 REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
1588 REQUIRE(name != NULL);
1589 REQUIRE(obj != NULL && *obj == NULL);
1591 map = &mapobj->value.map;
1593 result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val);
1594 if (result != ISC_R_SUCCESS)
1596 *obj = val.as_pointer;
1597 return (ISC_R_SUCCESS);
1601 cfg_map_getname(const cfg_obj_t *mapobj) {
1602 REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
1603 return (mapobj->value.map.id);
1607 /* Parse an arbitrary token, storing its raw text representation. */
1609 parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1610 cfg_obj_t *obj = NULL;
1611 isc_result_t result;
1616 CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj));
1617 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
1618 if (pctx->token.type == isc_tokentype_eof) {
1619 cfg_ungettoken(pctx);
1624 isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r);
1626 obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1);
1627 if (obj->value.string.base == NULL) {
1628 result = ISC_R_NOMEMORY;
1631 obj->value.string.length = r.length;
1632 memcpy(obj->value.string.base, r.base, r.length);
1633 obj->value.string.base[r.length] = '\0';
1639 isc_mem_put(pctx->mctx, obj, sizeof(*obj));
1643 cfg_type_t cfg_type_token = {
1644 "token", parse_token, cfg_print_ustring, cfg_doc_terminal,
1645 &cfg_rep_string, NULL
1649 * An unsupported option. This is just a list of tokens with balanced braces
1650 * ending in a semicolon.
1654 parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1655 cfg_obj_t *listobj = NULL;
1656 isc_result_t result;
1659 CHECK(cfg_create_list(pctx, type, &listobj));
1662 cfg_listelt_t *elt = NULL;
1664 CHECK(cfg_peektoken(pctx, 0));
1665 if (pctx->token.type == isc_tokentype_special) {
1666 if (pctx->token.value.as_char == '{')
1668 else if (pctx->token.value.as_char == '}')
1670 else if (pctx->token.value.as_char == ';')
1674 if (pctx->token.type == isc_tokentype_eof || braces < 0) {
1675 cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token");
1676 result = ISC_R_UNEXPECTEDTOKEN;
1680 CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt));
1681 ISC_LIST_APPEND(listobj->value.list, elt, link);
1683 INSIST(braces == 0);
1685 return (ISC_R_SUCCESS);
1688 CLEANUP_OBJ(listobj);
1692 cfg_type_t cfg_type_unsupported = {
1693 "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal,
1698 * Try interpreting the current token as a network address.
1700 * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard
1701 * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set. The
1702 * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is
1703 * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set),
1704 * and the IPv6 wildcard address otherwise.
1707 token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
1709 struct in_addr in4a;
1710 struct in6_addr in6a;
1712 if (pctx->token.type != isc_tokentype_string)
1713 return (ISC_R_UNEXPECTEDTOKEN);
1715 s = TOKEN_STRING(pctx);
1716 if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) {
1717 if ((flags & CFG_ADDR_V4OK) != 0) {
1718 isc_netaddr_any(na);
1719 return (ISC_R_SUCCESS);
1720 } else if ((flags & CFG_ADDR_V6OK) != 0) {
1721 isc_netaddr_any6(na);
1722 return (ISC_R_SUCCESS);
1727 if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) {
1728 if (inet_pton(AF_INET, s, &in4a) == 1) {
1729 isc_netaddr_fromin(na, &in4a);
1730 return (ISC_R_SUCCESS);
1733 if ((flags & CFG_ADDR_V4PREFIXOK) != 0 &&
1739 for (i = 0; i < 3; i++) {
1741 if (inet_pton(AF_INET, buf, &in4a) == 1) {
1742 isc_netaddr_fromin(na, &in4a);
1743 return (ISC_R_SUCCESS);
1747 if ((flags & CFG_ADDR_V6OK) != 0 &&
1748 strlen(s) <= 127U) {
1749 char buf[128]; /* see lib/bind9/getaddresses.c */
1750 char *d; /* zone delimiter */
1751 isc_uint32_t zone = 0; /* scope zone ID */
1754 d = strchr(buf, '%');
1758 if (inet_pton(AF_INET6, buf, &in6a) == 1) {
1760 #ifdef ISC_PLATFORM_HAVESCOPEID
1761 isc_result_t result;
1763 result = isc_netscope_pton(AF_INET6,
1767 if (result != ISC_R_SUCCESS)
1770 return (ISC_R_BADADDRESSFORM);
1774 isc_netaddr_fromin6(na, &in6a);
1775 isc_netaddr_setzone(na, zone);
1776 return (ISC_R_SUCCESS);
1780 return (ISC_R_UNEXPECTEDTOKEN);
1784 cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
1785 isc_result_t result;
1786 const char *wild = "";
1787 const char *prefix = "";
1789 CHECK(cfg_gettoken(pctx, 0));
1790 result = token_addr(pctx, flags, na);
1791 if (result == ISC_R_UNEXPECTEDTOKEN) {
1792 if ((flags & CFG_ADDR_WILDOK) != 0)
1794 if ((flags & CFG_ADDR_V4PREFIXOK) != 0)
1795 wild = " or IPv4 prefix";
1796 if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V4OK)
1797 cfg_parser_error(pctx, CFG_LOG_NEAR,
1798 "expected IPv4 address%s%s",
1800 else if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V6OK)
1801 cfg_parser_error(pctx, CFG_LOG_NEAR,
1802 "expected IPv6 address%s%s",
1805 cfg_parser_error(pctx, CFG_LOG_NEAR,
1806 "expected IP address%s%s",
1814 cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) {
1815 isc_result_t result;
1816 isc_netaddr_t na_dummy;
1817 result = token_addr(pctx, flags, &na_dummy);
1818 return (ISC_TF(result == ISC_R_SUCCESS));
1822 cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) {
1823 isc_result_t result;
1825 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
1827 if ((flags & CFG_ADDR_WILDOK) != 0 &&
1828 pctx->token.type == isc_tokentype_string &&
1829 strcmp(TOKEN_STRING(pctx), "*") == 0) {
1831 return (ISC_R_SUCCESS);
1833 if (pctx->token.type != isc_tokentype_number) {
1834 cfg_parser_error(pctx, CFG_LOG_NEAR,
1835 "expected port number or '*'");
1836 return (ISC_R_UNEXPECTEDTOKEN);
1838 if (pctx->token.value.as_ulong >= 65536U) {
1839 cfg_parser_error(pctx, CFG_LOG_NEAR,
1840 "port number out of range");
1841 return (ISC_R_UNEXPECTEDTOKEN);
1843 *port = (in_port_t)(pctx->token.value.as_ulong);
1844 return (ISC_R_SUCCESS);
1850 cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) {
1851 isc_result_t result;
1855 isc_buffer_init(&buf, text, sizeof(text));
1856 result = isc_netaddr_totext(na, &buf);
1857 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1858 cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf));
1863 static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
1864 static unsigned int netaddr4_flags = CFG_ADDR_V4OK;
1865 static unsigned int netaddr4wild_flags = CFG_ADDR_V4OK | CFG_ADDR_WILDOK;
1866 static unsigned int netaddr6_flags = CFG_ADDR_V6OK;
1867 static unsigned int netaddr6wild_flags = CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
1870 parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1871 isc_result_t result;
1872 cfg_obj_t *obj = NULL;
1873 isc_netaddr_t netaddr;
1874 unsigned int flags = *(const unsigned int *)type->of;
1876 CHECK(cfg_create_obj(pctx, type, &obj));
1877 CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
1878 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0);
1880 return (ISC_R_SUCCESS);
1887 cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
1888 const unsigned int *flagp = type->of;
1890 if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
1891 cfg_print_chars(pctx, "( ", 2);
1892 if (*flagp & CFG_ADDR_V4OK) {
1893 cfg_print_cstr(pctx, "<ipv4_address>");
1896 if (*flagp & CFG_ADDR_V6OK) {
1898 cfg_print_chars(pctx, " | ", 3);
1899 cfg_print_cstr(pctx, "<ipv6_address>");
1902 if (*flagp & CFG_ADDR_WILDOK) {
1904 cfg_print_chars(pctx, " | ", 3);
1905 cfg_print_chars(pctx, "*", 1);
1909 if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
1910 cfg_print_chars(pctx, " )", 2);
1913 cfg_type_t cfg_type_netaddr = {
1914 "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
1915 &cfg_rep_sockaddr, &netaddr_flags
1918 cfg_type_t cfg_type_netaddr4 = {
1919 "netaddr4", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
1920 &cfg_rep_sockaddr, &netaddr4_flags
1923 cfg_type_t cfg_type_netaddr4wild = {
1924 "netaddr4wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
1925 &cfg_rep_sockaddr, &netaddr4wild_flags
1928 cfg_type_t cfg_type_netaddr6 = {
1929 "netaddr6", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
1930 &cfg_rep_sockaddr, &netaddr6_flags
1933 cfg_type_t cfg_type_netaddr6wild = {
1934 "netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
1935 &cfg_rep_sockaddr, &netaddr6wild_flags
1941 cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type,
1944 cfg_obj_t *obj = NULL;
1945 isc_result_t result;
1946 isc_netaddr_t netaddr;
1947 unsigned int addrlen = 0, prefixlen;
1950 CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK |
1951 CFG_ADDR_V6OK, &netaddr));
1952 switch (netaddr.family) {
1963 CHECK(cfg_peektoken(pctx, 0));
1964 if (pctx->token.type == isc_tokentype_special &&
1965 pctx->token.value.as_char == '/') {
1966 CHECK(cfg_gettoken(pctx, 0)); /* read "/" */
1967 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
1968 if (pctx->token.type != isc_tokentype_number) {
1969 cfg_parser_error(pctx, CFG_LOG_NEAR,
1970 "expected prefix length");
1971 return (ISC_R_UNEXPECTEDTOKEN);
1973 prefixlen = pctx->token.value.as_ulong;
1974 if (prefixlen > addrlen) {
1975 cfg_parser_error(pctx, CFG_LOG_NOPREP,
1976 "invalid prefix length");
1977 return (ISC_R_RANGE);
1980 prefixlen = addrlen;
1982 CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj));
1983 obj->value.netprefix.address = netaddr;
1984 obj->value.netprefix.prefixlen = prefixlen;
1986 return (ISC_R_SUCCESS);
1988 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix");
1993 print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1994 const cfg_netprefix_t *p = &obj->value.netprefix;
1996 cfg_print_rawaddr(pctx, &p->address);
1997 cfg_print_chars(pctx, "/", 1);
1998 cfg_print_rawuint(pctx, p->prefixlen);
2002 cfg_obj_isnetprefix(const cfg_obj_t *obj) {
2003 REQUIRE(obj != NULL);
2004 return (ISC_TF(obj->type->rep == &cfg_rep_netprefix));
2008 cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr,
2009 unsigned int *prefixlen)
2011 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix);
2012 REQUIRE(netaddr != NULL);
2013 REQUIRE(prefixlen != NULL);
2015 *netaddr = obj->value.netprefix.address;
2016 *prefixlen = obj->value.netprefix.prefixlen;
2019 cfg_type_t cfg_type_netprefix = {
2020 "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal,
2021 &cfg_rep_netprefix, NULL
2025 parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type,
2026 int flags, cfg_obj_t **ret)
2028 isc_result_t result;
2029 isc_netaddr_t netaddr;
2031 cfg_obj_t *obj = NULL;
2033 CHECK(cfg_create_obj(pctx, type, &obj));
2034 CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
2035 CHECK(cfg_peektoken(pctx, 0));
2036 if (pctx->token.type == isc_tokentype_string &&
2037 strcasecmp(TOKEN_STRING(pctx), "port") == 0) {
2038 CHECK(cfg_gettoken(pctx, 0)); /* read "port" */
2039 CHECK(cfg_parse_rawport(pctx, flags, &port));
2041 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
2043 return (ISC_R_SUCCESS);
2050 static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
2051 cfg_type_t cfg_type_sockaddr = {
2052 "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr,
2053 &cfg_rep_sockaddr, &sockaddr_flags
2057 cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2058 const unsigned int *flagp = type->of;
2059 return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret));
2063 cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) {
2064 isc_netaddr_t netaddr;
2066 char buf[ISC_NETADDR_FORMATSIZE];
2068 isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr);
2069 isc_netaddr_format(&netaddr, buf, sizeof(buf));
2070 cfg_print_cstr(pctx, buf);
2071 port = isc_sockaddr_getport(&obj->value.sockaddr);
2073 cfg_print_chars(pctx, " port ", 6);
2074 cfg_print_rawuint(pctx, port);
2079 cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
2080 const unsigned int *flagp = type->of;
2082 cfg_print_chars(pctx, "( ", 2);
2083 if (*flagp & CFG_ADDR_V4OK) {
2084 cfg_print_cstr(pctx, "<ipv4_address>");
2087 if (*flagp & CFG_ADDR_V6OK) {
2089 cfg_print_chars(pctx, " | ", 3);
2090 cfg_print_cstr(pctx, "<ipv6_address>");
2093 if (*flagp & CFG_ADDR_WILDOK) {
2095 cfg_print_chars(pctx, " | ", 3);
2096 cfg_print_chars(pctx, "*", 1);
2100 cfg_print_chars(pctx, " ) ", 3);
2101 if (*flagp & CFG_ADDR_WILDOK) {
2102 cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]");
2104 cfg_print_cstr(pctx, "[ port <integer> ]");
2109 cfg_obj_issockaddr(const cfg_obj_t *obj) {
2110 REQUIRE(obj != NULL);
2111 return (ISC_TF(obj->type->rep == &cfg_rep_sockaddr));
2114 const isc_sockaddr_t *
2115 cfg_obj_assockaddr(const cfg_obj_t *obj) {
2116 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
2117 return (&obj->value.sockaddr);
2121 cfg_gettoken(cfg_parser_t *pctx, int options) {
2122 isc_result_t result;
2125 return (ISC_R_SUCCESS);
2127 options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE);
2130 pctx->token.type = isc_tokentype_unknown;
2131 result = isc_lex_gettoken(pctx->lexer, options, &pctx->token);
2132 pctx->ungotten = ISC_FALSE;
2133 pctx->line = isc_lex_getsourceline(pctx->lexer);
2137 if (pctx->token.type == isc_tokentype_eof) {
2138 result = isc_lex_close(pctx->lexer);
2139 INSIST(result == ISC_R_NOMORE ||
2140 result == ISC_R_SUCCESS);
2142 if (isc_lex_getsourcename(pctx->lexer) != NULL) {
2144 * Closed an included file, not the main file.
2147 elt = ISC_LIST_TAIL(pctx->open_files->
2149 INSIST(elt != NULL);
2150 ISC_LIST_UNLINK(pctx->open_files->
2151 value.list, elt, link);
2152 ISC_LIST_APPEND(pctx->closed_files->
2153 value.list, elt, link);
2156 pctx->seen_eof = ISC_TRUE;
2161 /* More understandable than "ran out of space". */
2162 cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big");
2166 cfg_parser_error(pctx, 0, "%s",
2167 isc_result_totext(result));
2171 cfg_parser_error(pctx, CFG_LOG_NEAR, "%s",
2172 isc_result_totext(result));
2179 cfg_ungettoken(cfg_parser_t *pctx) {
2182 isc_lex_ungettoken(pctx->lexer, &pctx->token);
2183 pctx->ungotten = ISC_TRUE;
2187 cfg_peektoken(cfg_parser_t *pctx, int options) {
2188 isc_result_t result;
2189 CHECK(cfg_gettoken(pctx, options));
2190 cfg_ungettoken(pctx);
2196 * Get a string token, accepting both the quoted and the unquoted form.
2197 * Log an error if the next token is not a string.
2200 cfg_getstringtoken(cfg_parser_t *pctx) {
2201 isc_result_t result;
2203 result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING);
2204 if (result != ISC_R_SUCCESS)
2207 if (pctx->token.type != isc_tokentype_string &&
2208 pctx->token.type != isc_tokentype_qstring) {
2209 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string");
2210 return (ISC_R_UNEXPECTEDTOKEN);
2212 return (ISC_R_SUCCESS);
2216 cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
2218 va_start(args, fmt);
2219 parser_complain(pctx, ISC_FALSE, flags, fmt, args);
2225 cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
2227 va_start(args, fmt);
2228 parser_complain(pctx, ISC_TRUE, flags, fmt, args);
2233 #define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */
2235 static isc_boolean_t
2236 have_current_file(cfg_parser_t *pctx) {
2238 if (pctx->open_files == NULL)
2241 elt = ISC_LIST_TAIL(pctx->open_files->value.list);
2249 current_file(cfg_parser_t *pctx) {
2250 static char none[] = "none";
2254 if (!have_current_file(pctx))
2257 elt = ISC_LIST_TAIL(pctx->open_files->value.list);
2258 if (elt == NULL) /* shouldn't be possible, but... */
2262 INSIST(fileobj->type == &cfg_type_qstring);
2263 return (fileobj->value.string.base);
2267 parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning,
2268 unsigned int flags, const char *format,
2271 char tokenbuf[MAX_LOG_TOKEN + 10];
2272 static char where[ISC_DIR_PATHMAX + 100];
2273 static char message[2048];
2274 int level = ISC_LOG_ERROR;
2275 const char *prep = "";
2279 level = ISC_LOG_WARNING;
2282 if (have_current_file(pctx))
2283 snprintf(where, sizeof(where), "%s:%u: ",
2284 current_file(pctx), pctx->line);
2286 len = vsnprintf(message, sizeof(message), format, args);
2287 if (len >= sizeof(message))
2288 FATAL_ERROR(__FILE__, __LINE__,
2289 "error message would overflow");
2291 if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) {
2295 (void)cfg_gettoken(pctx, 0);
2297 if (pctx->token.type == isc_tokentype_eof) {
2298 snprintf(tokenbuf, sizeof(tokenbuf), "end of file");
2299 } else if (pctx->token.type == isc_tokentype_unknown) {
2303 isc_lex_getlasttokentext(pctx->lexer,
2305 if (r.length > MAX_LOG_TOKEN)
2306 snprintf(tokenbuf, sizeof(tokenbuf),
2307 "'%.*s...'", MAX_LOG_TOKEN, r.base);
2309 snprintf(tokenbuf, sizeof(tokenbuf),
2310 "'%.*s'", (int)r.length, r.base);
2313 /* Choose a preposition. */
2314 if (flags & CFG_LOG_NEAR)
2316 else if (flags & CFG_LOG_BEFORE)
2323 isc_log_write(pctx->lctx, CAT, MOD, level,
2324 "%s%s%s%s", where, message, prep, tokenbuf);
2328 cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level,
2329 const char *fmt, ...) {
2333 if (! isc_log_wouldlog(lctx, level))
2338 vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
2339 isc_log_write(lctx, CAT, MOD, level,
2341 obj->file == NULL ? "<unknown file>" : obj->file,
2347 cfg_obj_file(const cfg_obj_t *obj) {
2352 cfg_obj_line(const cfg_obj_t *obj) {
2357 cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2358 isc_result_t result;
2361 obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t));
2363 return (ISC_R_NOMEMORY);
2365 obj->file = current_file(pctx);
2366 obj->line = pctx->line;
2367 result = isc_refcount_init(&obj->references, 1);
2368 if (result != ISC_R_SUCCESS) {
2369 isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
2373 return (ISC_R_SUCCESS);
2378 map_symtabitem_destroy(char *key, unsigned int type,
2379 isc_symvalue_t symval, void *userarg)
2381 cfg_obj_t *obj = symval.as_pointer;
2382 cfg_parser_t *pctx = (cfg_parser_t *)userarg;
2387 cfg_obj_destroy(pctx, &obj);
2392 create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2393 isc_result_t result;
2394 isc_symtab_t *symtab = NULL;
2395 cfg_obj_t *obj = NULL;
2397 CHECK(cfg_create_obj(pctx, type, &obj));
2398 CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */
2399 map_symtabitem_destroy,
2400 pctx, ISC_FALSE, &symtab));
2401 obj->value.map.symtab = symtab;
2402 obj->value.map.id = NULL;
2405 return (ISC_R_SUCCESS);
2409 isc_mem_put(pctx->mctx, obj, sizeof(*obj));
2414 free_map(cfg_parser_t *pctx, cfg_obj_t *obj) {
2415 CLEANUP_OBJ(obj->value.map.id);
2416 isc_symtab_destroy(&obj->value.map.symtab);
2420 cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) {
2421 return (ISC_TF(obj->type == type));
2425 * Destroy 'obj', a configuration object created in 'pctx'.
2428 cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) {
2429 cfg_obj_t *obj = *objp;
2432 isc_refcount_decrement(&obj->references, &refs);
2434 obj->type->rep->free(pctx, obj);
2435 isc_refcount_destroy(&obj->references);
2436 isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
2442 cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest) {
2443 REQUIRE(src != NULL);
2444 REQUIRE(dest != NULL && *dest == NULL);
2445 isc_refcount_increment(&src->references, NULL);
2450 free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) {
2456 cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) {
2457 type->doc(pctx, type);
2461 cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) {
2462 cfg_print_chars(pctx, "<", 1);
2463 cfg_print_cstr(pctx, type->name);
2464 cfg_print_chars(pctx, ">", 1);
2468 cfg_print_grammar(const cfg_type_t *type,
2469 void (*f)(void *closure, const char *text, int textlen),
2474 pctx.closure = closure;
2476 cfg_doc_obj(&pctx, type);