diff options
author | Francis Dupont <fdupont@isc.org> | 2017-04-11 03:37:20 +0200 |
---|---|---|
committer | Francis Dupont <fdupont@isc.org> | 2018-11-29 16:42:12 +0100 |
commit | f7270ab1fd2b2933eaf179403a349170746c977c (patch) | |
tree | 40dddc0c2a9ffc5900b220fdef1c128f471f7138 | |
parent | 839fd6e7faf7890626ea9f7ad168af987044213b (diff) | |
download | isc-dhcp-f7270ab1fd2b2933eaf179403a349170746c977c.tar.gz |
Began 2nd pass
-rw-r--r-- | keama/Makefile.am | 2 | ||||
-rw-r--r-- | keama/Makefile.in | 10 | ||||
-rw-r--r-- | keama/confparse.c | 265 | ||||
-rw-r--r-- | keama/dhctoken.h | 388 | ||||
-rw-r--r-- | keama/json.c | 10 | ||||
-rw-r--r-- | keama/keama.c | 4 | ||||
-rw-r--r-- | keama/keama.h | 37 | ||||
-rw-r--r-- | keama/options.c | 491 | ||||
-rw-r--r-- | keama/parse.c | 423 |
9 files changed, 1324 insertions, 306 deletions
diff --git a/keama/Makefile.am b/keama/Makefile.am index c50cc048..595d497a 100644 --- a/keama/Makefile.am +++ b/keama/Makefile.am @@ -1,5 +1,5 @@ sbin_PROGRAMS = keama -keama_SOURCES = keama.c data.c conflex.c json.c confparse.c parse.c +keama_SOURCES = keama.c data.c conflex.c json.c confparse.c parse.c options.c man_MANS = keama.8 EXTRA_DIST = $(man_MANS) diff --git a/keama/Makefile.in b/keama/Makefile.in index 65c608cf..ba2171d7 100644 --- a/keama/Makefile.in +++ b/keama/Makefile.in @@ -101,7 +101,9 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)" PROGRAMS = $(sbin_PROGRAMS) -am_keama_OBJECTS = keama.$(OBJEXT) data.$(OBJEXT) conflex.$(OBJEXT) +am_keama_OBJECTS = keama.$(OBJEXT) data.$(OBJEXT) conflex.$(OBJEXT) \ + json.$(OBJEXT) confparse.$(OBJEXT) parse.$(OBJEXT) \ + options.$(OBJEXT) keama_OBJECTS = $(am_keama_OBJECTS) keama_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) @@ -312,7 +314,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -keama_SOURCES = keama.c data.c conflex.c +keama_SOURCES = keama.c data.c conflex.c json.c confparse.c parse.c options.c man_MANS = keama.8 EXTRA_DIST = $(man_MANS) all: all-am @@ -402,8 +404,12 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conflex.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/confparse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keama.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/keama/confparse.c b/keama/confparse.c index 699eb610..ad96c79d 100644 --- a/keama/confparse.c +++ b/keama/confparse.c @@ -32,21 +32,20 @@ #include <stdlib.h> #include <string.h> +isc_boolean_t got_authoritative = ISC_FALSE; + static void new_network_interface(struct parse *, struct element *); static struct string *addrmask(const struct string *, const struct string *); static int get_prefix_length(const char *, const char *); -/* conf-file :== parameters declarations END_OF_FILE - parameters :== <nil> | parameter | parameters parameter - declarations :== <nil> | declaration | declarations declaration - - Add head config file comments to the DHCP server map */ +/* Add head config file comments to the DHCP server map */ size_t conf_file_parse(struct parse *cfile) { struct element *top; struct element *dhcp; + size_t issues; top = createMap(); top->kind = TOPLEVEL; @@ -64,7 +63,13 @@ conf_file_parse(struct parse *cfile) else parse_error(cfile, "address family is not set"); - return conf_file_subparse(cfile, ROOT_GROUP); + issues = conf_file_subparse(cfile, ROOT_GROUP); + + if (!got_authoritative) + parse_error(cfile, + "missing top level authoritative statement"); + + return issues; } size_t @@ -157,13 +162,11 @@ parse_statement(struct parse *cfile, int type, int declaration) const char *val; struct element *hardware; struct element *cache; -#if 0 + struct element *et; isc_boolean_t lose; - char *n; -#endif + isc_boolean_t known; isc_boolean_t authoritative; - struct element *option; - unsigned code; + struct option *option; size_t host_decl = 0; size_t subnet = 0; size_t i; @@ -290,25 +293,26 @@ parse_statement(struct parse *cfile, int type, int declaration) parse_error(cfile, "fixed-address parameter not " "allowed here."); - if (((token == FIXED_ADDR) && - mapContains(cfile->stack[host_decl], "ip-address")) || - ((token == FIXED_ADDR6) && - mapContains(cfile->stack[host_decl], "ip-addresses"))) - parse_error(cfile, "Only one fixed address " - "declaration per host."); cache = parse_fixed_addr_param(cfile, token); if (token == FIXED_ADDR) { + if (mapContains(cfile->stack[host_decl], "ip-address")) + parse_error(cfile, "Only one fixed address " + "declaration per host."); mapSet(cfile->stack[host_decl], listGet(cache, 0), "ip-address"); - listRemove(cache, 0); if (listSize(cache) > 0) { cache->skip = ISC_TRUE; cfile->issue_counter++; mapSet(cfile->stack[host_decl], cache, "extra-ip-addresses"); } - } else + } else { + if (mapContains(cfile->stack[host_decl], + "ip-addresses")) + parse_error(cfile, "Only one fixed address " + "declaration per host."); mapSet(cfile->stack[host_decl], cache, "ip-addresses"); + } break; case POOL: @@ -422,8 +426,13 @@ parse_statement(struct parse *cfile, int type, int declaration) authoritative: if (type == HOST_DECL) parse_error(cfile, "authority makes no sense here."); + if (type == ROOT_GROUP) { + got_authoritative = authoritative; + break; + } cache = createBool(authoritative); cache->skip = ISC_TRUE; + TAILQ_CONCAT(&cache->comments, &cfile->comments, next); mapSet(cfile->stack[cfile->stack_top], cache, "authoritative"); cfile->issue_counter++; parse_semi(cfile); @@ -432,10 +441,8 @@ parse_statement(struct parse *cfile, int type, int declaration) /* "server-identifier" is a special hack, equivalent to "option dhcp-server-identifier". */ case SERVER_IDENTIFIER: - code = DHO_DHCP_SERVER_IDENTIFIER; - option = createMap(); - mapSet(option, createInt(code), "code"); - skip_token(&val, NULL, cfile); + option = option_lookup_code("dhcp4", + DHO_DHCP_SERVER_IDENTIFIER); goto finish_option; case OPTION: @@ -450,7 +457,7 @@ parse_statement(struct parse *cfile, int type, int declaration) return declaration; } - option = parse_option_name(cfile); + option = parse_option_name(cfile, ISC_TRUE, &known); token = peek_token(&val, NULL, cfile); if (token == CODE) { if (type != ROOT_GROUP) @@ -459,9 +466,15 @@ parse_statement(struct parse *cfile, int type, int declaration) " may not be scoped."); skip_token(&val, NULL, cfile); + /* next function must deal with redefinitions */ parse_option_code_definition(cfile, option); return declaration; } + /* If this wasn't an option code definition, don't + allow an unknown option. */ + if (!known) + parse_error(cfile, "unknown option %s.%s", + option->space, option->name); finish_option: parse_option_statement(NULL, cfile, option, supersede_option_statement); @@ -490,11 +503,10 @@ parse_statement(struct parse *cfile, int type, int declaration) default: unknown: -/* Kea todo */ -#if 0 - et = NULL; + et = createMap(); + TAILQ_CONCAT(&et->comments, &cfile->comments, next); lose = ISC_FALSE; - if (!parse_executable_statement(&et, cfile, &lose, + if (!parse_executable_statement(et, cfile, &lose, context_any)) { if (!lose) { if (declaration) @@ -507,9 +519,12 @@ parse_statement(struct parse *cfile, int type, int declaration) } return declaration; } - if (!et) -#endif + if (mapSize(et) == 0) return declaration; + + et->skip = ISC_TRUE; + cfile->issue_counter++; + mapSet(cfile->stack[cfile->stack_top], et, "statements"); } return 0; @@ -655,6 +670,7 @@ parse_pool_statement(struct parse *cfile, int type) pool = createMap(); pool->kind = POOL_DECL; + TAILQ_CONCAT(&pool->comments, &cfile->comments, next); if (type != SUBNET_DECL && type != SHARED_NET_DECL) parse_error(cfile, "Dynamic pools are only valid inside " @@ -756,19 +772,15 @@ parse_host_declaration(struct parse *cfile) int declaration = 0; isc_boolean_t dynamicp = ISC_FALSE; isc_boolean_t deleted = ISC_FALSE; -#if 0 - int known; - struct option *option; - struct expression *expr = NULL; -#endif + + host = createMap(); + host->kind = HOST_DECL; + TAILQ_CONCAT(&host->comments, &cfile->comments, next); name = parse_host_name(cfile); if (!name) parse_error(cfile, "expecting a name for host declaration."); - host = createMap(); - host->kind = HOST_DECL; - mapSet(host, createString(name), "hostname"); parse_lbrace(cfile); @@ -840,6 +852,7 @@ parse_host_declaration(struct parse *cfile) parse_error(cfile, "expecting hex list."); } + /* Kea todo: get text */ mapSet(host, createString(client_id), "client-id"); parse_semi(cfile); @@ -848,30 +861,61 @@ parse_host_declaration(struct parse *cfile) if (token == HOST_IDENTIFIER) { struct string *host_id; - struct element *elem; + isc_boolean_t known; + struct option *option; + struct element *expr; + int relays; if (mapContains(host, "host-identifier")) parse_error(cfile, "only one host-identifier allowed " "per host"); skip_token(&val, NULL, cfile); + save_parse_state(cfile); token = next_token(&val, NULL, cfile); host_id = makeString(-1, val); - if (token != V6RELOPT && token != OPTION) - parse_error(cfile, - "host-identifier must be an option" - " or v6relopt"); while (peek_raw_token(NULL, NULL, cfile) != SEMI) { next_raw_token(&val, NULL, cfile); appendString(host_id, val); } + restore_parse_state(cfile); + expr = createString(host_id); + expr->skip = ISC_TRUE; + cfile->issue_counter++; + mapSet(host, expr, "host-identifier"); + + token = next_token(&val, NULL, cfile); + if (token == V6RELOPT) { + token = next_token(&val, NULL, cfile); + + if (token != NUMBER) + parse_error(cfile, + "host-identifier v6relopt " + "must have a number"); + relays = atoi(val); + if (relays < 0) + parse_error(cfile, + "host-identifier v6relopt " + "must have a number >= 0"); + } else if (token != OPTION) + parse_error(cfile, + "host-identifier must be an option" + " or v6relopt"); + known = ISC_FALSE; + option = parse_option_name(cfile, ISC_TRUE, &known); + if (!known) + parse_error(cfile, "unknown option %s.%s", + option->space, option->name); + expr = createMap(); + if (!parse_option_data(expr, cfile, option)) + parse_error(cfile, "can't parse option data"); parse_semi(cfile); - elem = createString(host_id); - elem->skip = ISC_TRUE; - cfile->issue_counter++; - mapSet(host, elem, "host-identifier"); + /* Kea todo: map to flexible id "option=data' */ + if (expr->type != ELEMENT_STRING) + parse_error(cfile, "option must be a " + "string or binary option"); continue; } @@ -916,17 +960,15 @@ parse_class_declaration(struct parse *cfile, int type) struct element *class = NULL, *pc = NULL; struct element *children; struct element *lease_limit; + struct element *expr; int declaration = 0; struct string *data; char *name; const char *tname; isc_boolean_t new = ISC_TRUE; -#if 0 isc_boolean_t lose = ISC_FALSE; isc_boolean_t matchedonce = ISC_FALSE; isc_boolean_t submatchedonce = ISC_FALSE; - unsigned code; -#endif int i; isc_boolean_t has_superclass = ISC_FALSE; int flags = 0; @@ -1049,6 +1091,7 @@ parse_class_declaration(struct parse *cfile, int type) class = createMap(); class->kind = CLASS_DECL; class->skip = ISC_TRUE; + TAILQ_CONCAT(&class->comments, &cfile->comments, next); cfile->issue_counter++; if (type == CLASS_TYPE_SUBCLASS) { struct element *sub; @@ -1062,30 +1105,27 @@ parse_class_declaration(struct parse *cfile, int type) has_superclass = ISC_TRUE; } -/* Kea TODO */ -#if 0 /* If this is an implicit vendor or user class, add a statement that causes the vendor or user class ID to be sent back in the reply. */ if (type == CLASS_TYPE_VENDOR || type == CLASS_TYPE_USER) { - stmt = NULL; - if (!executable_statement_allocate(&stmt, MDL)) - log_fatal("no memory for class statement."); - stmt->op = supersede_option_statement; - if (option_cache_allocate(&stmt->data.option, - MDL)) { - stmt->data.option->data = data; - code = (type == CLASS_TYPE_VENDOR) - ? DHO_VENDOR_CLASS_IDENTIFIER - : DHO_USER_CLASS; - option_code_hash_lookup( - &stmt->data.option->option, - dhcp_universe.code_hash, - &code, 0, MDL); + struct element *opt_data; + struct element *opt_data_list; + int code; + + opt_data = createMap(); + code = (type == CLASS_TYPE_VENDOR) + ? DHO_VENDOR_CLASS_IDENTIFIER + : DHO_USER_CLASS; + mapSet(opt_data, createInt(code), "code"); + mapSet(opt_data, createString(data), "data"); + opt_data_list = mapGet(class, "option-data"); + if (opt_data_list == NULL) { + opt_data_list = createList(); + mapSet(class, opt_data_list, "option-data"); } - class->statements = stmt; + listPush(opt_data_list, opt_data); } -#endif /* Save the name, if there is one. */ if (mapContains(class, "name")) mapRemove(class, "name"); @@ -1134,8 +1174,6 @@ parse_class_declaration(struct parse *cfile, int type) } skip_token(&val, NULL, cfile); token = peek_token(&val, NULL, cfile); -/* Kea TODO */ -#if 0 if (token != IF) goto submatch; skip_token(&val, NULL, cfile); @@ -1143,22 +1181,23 @@ parse_class_declaration(struct parse *cfile, int type) parse_error(cfile, "A class may only have " "one 'match if' clause."); matchedonce = ISC_TRUE; - if (class->expr) - expression_dereference(&class->expr, MDL); - if (!parse_boolean_expression(&class->expr, cfile, - &lose)) { + expr = createMap(); + if (!parse_boolean_expression(expr, cfile, &lose)) { if (!lose) parse_error(cfile, "expecting boolean expr."); } else { + expr->skip = ISC_TRUE; + cfile->issue_counter++; + mapSet(class, expr, "match"); parse_semi(cfile); + /* kea todo: translate match into test */ } } else if (token == SPAWN) { skip_token(&val, NULL, cfile); if (pc) parse_error(cfile, "invalid spawn in subclass."); - class->spawning = 1; token = next_token(&val, NULL, cfile); if (token != WITH) parse_error(cfile, @@ -1169,17 +1208,17 @@ parse_class_declaration(struct parse *cfile, int type) "can't override existing %s.", "submatch/spawn"); submatchedonce = ISC_TRUE; - if (class->submatch) - expression_dereference(&class->submatch, MDL); - if (!parse_data_expression(&class->submatch, - cfile, &lose)) { + expr = createMap(); + if (!parse_data_expression(expr, cfile, &lose)) { if (!lose) parse_error(cfile, "expecting data expr."); } else { + expr->skip = ISC_TRUE; + cfile->issue_counter++; + mapSet(class, expr, "spawn"); parse_semi(cfile); } -#endif } else if (token == LEASE) { skip_token(&val, NULL, cfile); token = next_token(&val, NULL, cfile); @@ -1239,6 +1278,7 @@ parse_shared_net_declaration(struct parse *cfile) share = createMap(); share->skip = ISC_TRUE; share->kind = SHARED_NET_DECL; + TAILQ_CONCAT(&share->comments, &cfile->comments, next); /* Get the name of the shared network... */ token = peek_token(&val, NULL, cfile); @@ -1389,6 +1429,7 @@ parse_subnet_declaration(struct parse *cfile) subnet = createMap(); subnet->kind = SUBNET_DECL; + TAILQ_CONCAT(&subnet->comments, &cfile->comments, next); /* Find parent */ for (i = cfile->stack_top; i > 0; --i) { @@ -1457,6 +1498,7 @@ parse_subnet6_declaration(struct parse *cfile) { subnet = createMap(); subnet->kind = SUBNET_DECL; + TAILQ_CONCAT(&subnet->comments, &cfile->comments, next); /* Find parent */ for (i = cfile->stack_top; i > 0; --i) { @@ -1520,6 +1562,7 @@ parse_group_declaration(struct parse *cfile) group = createMap(); group->skip = ISC_TRUE; group->kind = GROUP_DECL; + TAILQ_CONCAT(&group->comments, &cfile->comments, next); token = peek_token(&val, NULL, cfile); if (is_identifier(token) || token == STRING) { @@ -1577,36 +1620,27 @@ struct element * parse_fixed_addr_param(struct parse *cfile, enum dhcp_token type) { const char *val; enum dhcp_token token; + struct element *addr; struct element *addresses; struct string *address; - isc_boolean_t ipaddr = ISC_TRUE; addresses = createList(); + TAILQ_CONCAT(&addresses->comments, &cfile->comments, next); do { address = NULL; if (type == FIXED_ADDR) - address = parse_ip_addr_or_hostname(cfile, &ipaddr); + address = parse_ip_addr_or_hostname(cfile, ISC_TRUE); else if (type == FIXED_ADDR6) address = parse_ip6_addr_txt(cfile); else parse_error(cfile, "requires FIXED_ADDR[6]"); if (address == NULL) parse_error(cfile, "can't parse fixed address"); - if (ipaddr) { - struct element *name; - struct comment *comment; - - name = createString(address); - ipaddr = ISC_TRUE; - name->skip = ISC_TRUE; - cfile->issue_counter++; - comment = createComment("### please resolve this " - "name into one address"); - TAILQ_INSERT_TAIL(&name->comments, comment, next); - listPush(addresses, name); - } else - listPush(addresses, createString(address)); + addr = createString(address); + /* Take the comment for resolution into multiple addresses */ + TAILQ_CONCAT(&addr->comments, &cfile->comments, next); + listPush(addresses, addr); token = peek_token(&val, NULL, cfile); if (token == COMMA) token = next_token(&val, NULL, cfile); @@ -1636,6 +1670,7 @@ parse_address_range(struct parse *cfile, int type, size_t where) isc_boolean_t dynamic = ISC_FALSE; struct element *pool; char taddr[40]; + struct element *r; if ((token = peek_token(&val, NULL, cfile)) == DYNAMIC_BOOTP) { @@ -1717,7 +1752,10 @@ parse_address_range(struct parse *cfile, int type, size_t where) parse_error(cfile, "can't print range address (high)"); appendString(range, taddr); - mapSet(pool, createString(range), "pool"); + r = createString(range); + TAILQ_CONCAT(&r->comments, &cfile->comments, next); + + mapSet(pool, r, "pool"); } /* address-range6-declaration :== ip-address6 ip-address6 SEMI @@ -1813,6 +1851,7 @@ parse_address_range6(struct parse *cfile, int type, size_t where) pool = cfile->stack[where]; range = createString(lo); + TAILQ_CONCAT(&range->comments, &cfile->comments, next); if (is_temporary) { range->skip = ISC_TRUE; cfile->issue_counter++; @@ -1831,6 +1870,7 @@ parse_prefix6(struct parse *cfile, int type, size_t where) enum dhcp_token token; const char *val; struct element *pool; + struct element *prefix; if (local_family != AF_INET6) parse_error(cfile, "prefix6 statement is only supported " @@ -1879,7 +1919,9 @@ parse_prefix6(struct parse *cfile, int type, size_t where) } else pool = cfile->stack[where]; - mapSet(pool, createString(lo), "prefix"); + prefix = createString(lo); + TAILQ_CONCAT(&prefix->comments, &cfile->comments, next); + mapSet(pool, prefix, "prefix"); mapSet(pool, createInt(bits), "delegated-len"); plen = get_prefix_length(lo->content, hi->content); if (plen >= 0) @@ -1902,6 +1944,7 @@ parse_fixed_prefix6(struct parse *cfile, size_t host_decl) const char *val; struct element *host; struct element *prefixes; + struct element *prefix; if (local_family != AF_INET6) parse_error(cfile, "fixed-prefix6 statement is only " @@ -1932,7 +1975,9 @@ parse_fixed_prefix6(struct parse *cfile, size_t host_decl) if (token != SEMI) parse_error(cfile, "semicolon expected."); - listPush(prefixes, createString(ia)); + prefix = createString(ia); + TAILQ_CONCAT(&prefix->comments, &cfile->comments, next); + listPush(prefixes, prefix); } /*! @@ -1976,6 +2021,7 @@ parse_pool6_statement(struct parse *cfile, int type) pool = createMap(); pool->kind = POOL_DECL; + TAILQ_CONCAT(&pool->comments, &cfile->comments, next); if (type != SUBNET_DECL) parse_error(cfile, "pool6s are only valid inside " @@ -2060,7 +2106,6 @@ parse_allow_deny(struct parse *cfile, int flag) const char *action; const char *option; struct element *sv_option; - struct element *expr; switch (flag) { case 0: @@ -2080,19 +2125,19 @@ parse_allow_deny(struct parse *cfile, int flag) token = next_token(&val, NULL, cfile); switch (token) { case TOKEN_BOOTP: - option = "allow bootp"; + option = "allow-bootp"; break; case BOOTING: - option = "allow booting"; + option = "allow-booting"; break; case DYNAMIC_BOOTP: - option = "dynamic bootp"; + option = "dynamic-bootp"; break; case UNKNOWN_CLIENTS: - option = "boot unknown clients"; + option = "boot-unknown-clients"; break; case DUPLICATES: @@ -2104,7 +2149,7 @@ parse_allow_deny(struct parse *cfile, int flag) break; case CLIENT_UPDATES: - option = "client updates"; + option = "client-updates"; break; case LEASEQUERY: @@ -2117,13 +2162,12 @@ parse_allow_deny(struct parse *cfile, int flag) parse_semi(cfile); sv_option = createMap(); - mapSet(sv_option, createString(makeString(-1, action)), "action"); + mapSet(sv_option, createString(makeString(-1, action)), "data"); mapSet(sv_option, createString(makeString(-1, option)), "name"); - expr = createMap(); - expr->skip = ISC_TRUE; + mapSet(sv_option, createString(makeString(-1, "_server_")), "space"); + sv_option->skip = ISC_TRUE; cfile->issue_counter++; - mapSet(expr, sv_option, "server-option"); - return expr; + return sv_option; } /* @@ -2269,6 +2313,7 @@ parse_server_duid_conf(struct parse *cfile) { sv_duid = createString(duid); sv_duid->skip = ISC_TRUE; + TAILQ_CONCAT(&sv_duid->comments, &cfile->comments, next); cfile->issue_counter++; mapSet(cfile->stack[cfile->stack_top], sv_duid, "server-duid"); } diff --git a/keama/dhctoken.h b/keama/dhctoken.h new file mode 100644 index 00000000..bcd75b96 --- /dev/null +++ b/keama/dhctoken.h @@ -0,0 +1,388 @@ +/* dhctoken.h + + Tokens for config file lexer and parser. */ + +/* + * Copyright (c) 2004-2016 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-2003 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Internet Systems Consortium, Inc. + * 950 Charter Street + * Redwood City, CA 94063 + * <info@isc.org> + * https://www.isc.org/ + * + */ + +/* + * The following tokens have been deprecated and aren't in use anymore. + * They have been left in place to avoid disturbing the code. + * DNS_UPDATE, DNS_DELETE, NS_UPDATE, UPDATED_DNS_RR + */ +/* + * For the Kea Migration Assistant only '[' and ']' where added for + * the JSON test parser (no required cast to int in switches on tokens) + */ +enum dhcp_token { + SEMI = ';', + DOT = '.', + COLON = ':', + COMMA = ',', + SLASH = '/', + LBRACE = '{', + RBRACE = '}', + LBRACKET = '[', + RBRACKET = ']', + LPAREN = '(', + RPAREN = ')', + EQUAL = '=', + TILDE = '~', + BANG = '!', + PERCENT = '%', + PLUS = '+', + MINUS = '-', + ASTERISK = '*', + AMPERSAND = '&', + PIPE = '|', + CARET = '^', + ENDOFLINE = '\n', + QUESTIONMARK = '?', + + HOST = 256, + FIRST_TOKEN = HOST, + HARDWARE = 257, + FILENAME = 258, + FIXED_ADDR = 259, + OPTION = 260, + ETHERNET = 261, + STRING = 262, + NUMBER = 263, + NUMBER_OR_NAME = 264, + NAME = 265, + TIMESTAMP = 266, + STARTS = 267, + ENDS = 268, + UID = 269, + CLASS = 270, + LEASE = 271, + RANGE = 272, + PACKET = 273, + CIADDR = 274, + YIADDR = 275, + SIADDR = 276, + GIADDR = 277, + SUBNET = 278, + NETMASK = 279, + DEFAULT_LEASE_TIME = 280, + MAX_LEASE_TIME = 281, + VENDOR_CLASS = 282, + USER_CLASS = 283, + SHARED_NETWORK = 284, + SERVER_NAME = 285, + DYNAMIC_BOOTP = 286, + SERVER_IDENTIFIER = 287, + DYNAMIC_BOOTP_LEASE_CUTOFF = 288, + DYNAMIC_BOOTP_LEASE_LENGTH = 289, + BOOT_UNKNOWN_CLIENTS = 290, + NEXT_SERVER = 291, + TOKEN_RING = 292, + GROUP = 293, + ONE_LEASE_PER_CLIENT = 294, + GET_LEASE_HOSTNAMES = 295, + USE_HOST_DECL_NAMES = 296, + SEND = 297, + CLIENT_IDENTIFIER = 298, + REQUEST = 299, + REQUIRE = 300, + TIMEOUT = 301, + RETRY = 302, + SELECT_TIMEOUT = 303, + SCRIPT = 304, + INTERFACE = 305, + RENEW = 306, + REBIND = 307, + EXPIRE = 308, + UNKNOWN_CLIENTS = 309, + ALLOW = 310, + DENY = 312, + BOOTING = 313, + DEFAULT = 314, + MEDIA = 315, + MEDIUM = 316, + ALIAS = 317, + REBOOT = 318, + TOKEN_ABANDONED = 319, + BACKOFF_CUTOFF = 320, + INITIAL_INTERVAL = 321, + NAMESERVER = 322, + DOMAIN = 323, + SEARCH = 324, + SUPERSEDE = 325, + APPEND = 326, + PREPEND = 327, + HOSTNAME = 328, + CLIENT_HOSTNAME = 329, + REJECT = 330, + USE_LEASE_ADDR_FOR_DEFAULT_ROUTE = 331, + MIN_LEASE_TIME = 332, + MIN_SECS = 333, + AND = 334, + OR = 335, + SUBSTRING = 337, + SUFFIX = 338, + CHECK = 339, + EXTRACT_INT = 340, + IF = 341, + TOKEN_ADD = 342, + BREAK = 343, + ELSE = 344, + ELSIF = 345, + SUBCLASS = 346, + MATCH = 347, + SPAWN = 348, + WITH = 349, + EXISTS = 350, + POOL = 351, + UNKNOWN = 352, + CLIENTS = 353, + KNOWN = 354, + AUTHENTICATED = 355, + UNAUTHENTICATED = 356, + ALL = 357, + DYNAMIC = 358, + MEMBERS = 359, + OF = 360, + PSEUDO = 361, + LIMIT = 362, + BILLING = 363, + PEER = 364, + FAILOVER = 365, + MY = 366, + PARTNER = 367, + PRIMARY = 368, + SECONDARY = 369, + IDENTIFIER = 370, + PORT = 371, + MAX_TRANSMIT_IDLE = 372, + MAX_RESPONSE_DELAY = 373, + PARTNER_DOWN = 374, + NORMAL = 375, + COMMUNICATIONS_INTERRUPTED = 376, + POTENTIAL_CONFLICT = 377, + RECOVER = 378, + TOKEN_FDDI = 379, + AUTHORITATIVE = 380, + TOKEN_NOT = 381, + AUTHENTICATION = 383, + IGNORE = 384, + ACCEPT = 385, + PREFER = 386, + DONT = 387, + CODE = 388, + ARRAY = 389, + BOOLEAN = 390, + INTEGER = 391, + SIGNED = 392, + UNSIGNED = 393, + IP_ADDRESS = 394, + TEXT = 395, + STRING_TOKEN = 396, + SPACE = 397, + CONCAT = 398, + ENCODE_INT = 399, + REVERSE = 402, + LEASED_ADDRESS = 403, + BINARY_TO_ASCII = 404, + PICK = 405, + CONFIG_OPTION = 406, + HOST_DECL_NAME = 407, + ON = 408, + EXPIRY = 409, + RELEASE = 410, + COMMIT = 411, + DNS_UPDATE = 412, + LEASE_TIME = 413, + STATIC = 414, + NEVER = 415, + INFINITE = 416, + TOKEN_DELETED = 417, + UPDATED_DNS_RR = 418, + DNS_DELETE = 419, + DUPLICATES = 420, + DECLINES = 421, + TSTP = 422, + TSFP = 423, + OWNER = 424, + IS = 425, + HBA = 426, + MAX_UNACKED_UPDATES = 427, + MCLT = 428, + SPLIT = 429, + AT = 430, + TOKEN_NO = 431, + TOKEN_DELETE = 432, + NS_UPDATE = 433, + UPDATE = 434, + SWITCH = 435, + CASE = 436, + NS_FORMERR = 437, + NS_NOERROR = 438, + NS_NOTAUTH = 439, + NS_NOTIMP = 440, + NS_NOTZONE = 441, + NS_NXDOMAIN = 442, + NS_NXRRSET = 443, + NS_REFUSED = 444, + NS_SERVFAIL = 445, + NS_YXDOMAIN = 446, + NS_YXRRSET = 447, + TOKEN_NULL = 448, + TOKEN_SET = 449, + DEFINED = 450, + UNSET = 451, + EVAL = 452, + LET = 453, + FUNCTION = 454, + DEFINE = 455, + ZONE = 456, + KEY = 457, + SECRET = 458, + ALGORITHM = 459, + LOAD = 460, + BALANCE = 461, + TOKEN_MAX = 462, + SECONDS = 463, + ADDRESS = 464, + RESOLUTION_INTERRUPTED = 465, + STATE = 466, + UNKNOWN_STATE = 567, + CLTT = 568, + INCLUDE = 569, + BINDING = 570, + TOKEN_FREE = 571, + TOKEN_ACTIVE = 572, + TOKEN_EXPIRED = 573, + TOKEN_RELEASED = 574, + TOKEN_RESET = 575, + TOKEN_BACKUP = 576, + TOKEN_RESERVED = 577, + TOKEN_BOOTP = 578, + TOKEN_NEXT = 579, + OMAPI = 580, + LOG = 581, + FATAL = 582, + ERROR = 583, + TOKEN_DEBUG = 584, + INFO = 585, + RETURN = 586, + PAUSED = 587, + RECOVER_DONE = 588, + SHUTDOWN = 589, + STARTUP = 590, + ENCAPSULATE = 591, + VENDOR = 592, + CLIENT_STATE = 593, + INIT_REBOOT = 594, + TOKEN_INIT = 595, + SELECT = 596, + BOUND = 597, + RENEWING = 598, + REBINDING = 599, + RECONTACT_INTERVAL = 600, + CLIENT_UPDATES = 601, + TOKEN_NEW = 601, + TRANSMISSION = 602, + TOKEN_CLOSE = 603, + TOKEN_CREATE = 604, + TOKEN_OPEN = 605, + TOKEN_HELP = 606, + END_OF_FILE = 607, + RECOVER_WAIT = 608, + TOKEN_SERVER = 609, + CONNECT = 610, + REMOVE = 611, + REFRESH = 612, + DOMAIN_NAME = 613, + DO_FORWARD_UPDATE = 614, + KNOWN_CLIENTS = 615, + ATSFP = 616, + LCASE = 617, + UCASE = 618, + WIDTH = 619, + LENGTH = 620, + HASH = 621, + SIZE = 622, + EPOCH = 623, + DB_TIME_FORMAT = 624, + LOCAL = 625, + MAX_LEASE_MISBALANCE = 626, + MAX_LEASE_OWNERSHIP = 627, + MAX_BALANCE = 628, + MIN_BALANCE = 629, + DOMAIN_LIST = 630, + LEASEQUERY = 631, + EXECUTE = 632, + IP6_ADDRESS = 633, + FIXED_ADDR6 = 634, + COMPRESSED = 635, + SUBNET6 = 636, + HOST_IDENTIFIER = 637, + IA_NA = 638, + IA_TA = 639, + IA_PD = 640, + IAADDR = 641, + IAPREFIX = 642, + LEASE6 = 643, + PREFERRED_LIFE = 644, + MAX_LIFE = 645, + DEFAULT_DUID = 646, + SERVER_DUID = 647, + LLT = 648, + EN = 649, + LL = 650, + RANGE6 = 651, + WHITESPACE = 652, + TOKEN_ALSO = 653, + AFTER = 654, + ZEROLEN = 655, + TEMPORARY = 656, + PREFIX6 = 657, + FIXED_PREFIX6 = 658, + ANYCAST_MAC = 659, + CONFLICT_DONE = 660, + AUTO_PARTNER_DOWN = 661, + GETHOSTNAME = 662, + REWIND = 663, + INITIAL_DELAY = 664, + GETHOSTBYNAME = 665, + PRIMARY6 = 666, + SECONDARY6 = 667, + TOKEN_INFINIBAND = 668, + POOL6 = 669, + V6RELAY = 670, + V6RELOPT = 671, + PARSE_VENDOR_OPT = 672, + AUTHORING_BYTE_ORDER = 673, + TOKEN_LITTLE_ENDIAN = 674, + TOKEN_BIG_ENDIAN = 675, + LEASE_ID_FORMAT = 676, + TOKEN_HEX = 677, + TOKEN_OCTAL = 678 +}; + +#define is_identifier(x) ((x) >= FIRST_TOKEN && \ + (x) != STRING && \ + (x) != NUMBER && \ + (x) != END_OF_FILE) diff --git a/keama/json.c b/keama/json.c index 34b7d48b..7ba6c87a 100644 --- a/keama/json.c +++ b/keama/json.c @@ -41,7 +41,7 @@ json_parse(struct parse *cfile) cfile->stack_top = 0; token = next_token(&val, NULL, cfile); - switch ((int)token) { + switch (token) { case NUMBER: elem = createInt(atoll(val)); TAILQ_CONCAT(&elem->comments, &cfile->comments, next); @@ -62,7 +62,7 @@ json_parse(struct parse *cfile) parse_error(cfile, "unknown name %s", val); TAILQ_CONCAT(&elem->comments, &cfile->comments, next); break; - case '[': + case LBRACKET: elem = json_list_parse(cfile); break; case LBRACE: @@ -90,8 +90,8 @@ json_list_parse(struct parse *cfile) stackPush(cfile, list); do { token = peek_token(&val, NULL, cfile); - switch ((int)token) { - case ']': + switch (token) { + case RBRACKET: done = ISC_TRUE; break; case END_OF_FILE: @@ -131,7 +131,7 @@ json_map_parse(struct parse *cfile) stackPush(cfile, map); do { token = peek_token(&val, NULL, cfile); - switch ((int)token) { + switch (token) { case RBRACE: done = ISC_TRUE; break; diff --git a/keama/keama.c b/keama/keama.c index 09b64dac..dd67b7eb 100644 --- a/keama/keama.c +++ b/keama/keama.c @@ -21,8 +21,6 @@ * */ -#include "keama.h" - #include <sys/errno.h> #include <arpa/inet.h> #include <assert.h> @@ -32,6 +30,8 @@ #include <string.h> #include <unistd.h> +#include "keama.h" + #define KEAMA_USAGE "Usage: keama [-4|-6] [-i input-file] [-o output-file]" static void diff --git a/keama/keama.h b/keama/keama.h index 0fe5b3fc..00802312 100644 --- a/keama/keama.h +++ b/keama/keama.h @@ -230,6 +230,23 @@ enum expr_op { expr_concat_dclist }; +/* options */ + +enum option_status { + kea_unknown = 0, /* known only by ISC DHCP */ + supported, /* known by both ISC DHCP and Kea, same name */ + must_renamed, /* known by both, different name */ + special /* requires special processing */ +}; + +struct option { + const char *name; /* option name */ + const char *format; /* ISC DHCP format string */ + const char *space; /* ISC DHCP space (aka universe) */ + unsigned code; /* code point */ + enum option_status status; /* status */ +}; + /* Kea parse tools */ void stackPush(struct parse *cfile, struct element *elem); @@ -284,7 +301,7 @@ void skip_to_rbrace(struct parse *, int); void parse_semi(struct parse *); void parse_string(struct parse *, char **, unsigned *); struct string *parse_host_name(struct parse *); -struct string *parse_ip_addr_or_hostname(struct parse *, isc_boolean_t *); +struct string *parse_ip_addr_or_hostname(struct parse *, isc_boolean_t); struct string *parse_ip_addr(struct parse *); struct string *parse_ip6_addr(struct parse *); struct string *parse_ip6_addr_txt(struct parse *); @@ -295,9 +312,10 @@ struct string *parse_numeric_aggregate(struct parse *, int, int, unsigned); void convert_num(struct parse *, unsigned char *, const char *, int, unsigned); -struct element *parse_option_name(struct parse *); +struct option *parse_option_name(struct parse *, isc_boolean_t, + isc_boolean_t *); void parse_option_space_decl(struct parse *); -void parse_option_code_definition(struct parse *, struct element *); +void parse_option_code_definition(struct parse *, struct option *); struct string *parse_base64(struct parse *); struct string *parse_cshl(struct parse *); isc_boolean_t parse_executable_statements(struct element *, @@ -329,11 +347,20 @@ isc_boolean_t parse_non_binary(struct element *, struct parse *, isc_boolean_t parse_expression(struct element *, struct parse *, isc_boolean_t *, enum expression_context, struct element *, enum expr_op); -isc_boolean_t parse_option_data(struct element *, struct parse *); +isc_boolean_t parse_option_data(struct element *, struct parse *, + struct option *); isc_boolean_t parse_option_statement(struct element *, struct parse *, - struct element *, enum statement_op); + struct option *, enum statement_op); + +/* options.c */ +const char *option_map_space(const char *); +struct option *option_lookup_name(const char *, const char *); +struct option *option_lookup_code(const char *, unsigned); +void option_map_name(struct option *); /* json.c */ struct element *json_parse(struct parse *); struct element *json_list_parse(struct parse *); struct element *json_map_parse(struct parse *); + +/* options.c */ diff --git a/keama/options.c b/keama/options.c new file mode 100644 index 00000000..b62fc65b --- /dev/null +++ b/keama/options.c @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2017 by Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Internet Systems Consortium, Inc. + * 950 Charter Street + * Redwood City, CA 94063 + * <info@isc.org> + * https://www.isc.org/ + * + */ + +#include <assert.h> +#include <string.h> + +#include "keama.h" + +/* From common/tables.c */ + +struct option options[] = { +/// DHCPv4 + + { "subnet-mask", "I", "dhcp", 1, 1}, + { "time-offset", "l", "dhcp", 2, 1}, + { "routers", "IA", "dhcp", 3, 1}, + { "time-servers", "IA", "dhcp", 4, 1}, + { "ien116-name-servers", "IA", "dhcp", 5, 2}, + /// ien116-name-servers -> name-servers + { "domain-name-servers", "IA", "dhcp", 6, 1}, + { "log-servers", "IA", "dhcp", 7, 1}, + { "cookie-servers", "IA", "dhcp", 8, 1}, + { "lpr-servers", "IA", "dhcp", 9, 1}, + { "impress-servers", "IA", "dhcp", 10, 1}, + { "resource-location-servers", "IA", "dhcp", 11, 1}, + { "host-name", "t", "dhcp", 12, 1}, + { "boot-size", "S", "dhcp", 13, 1}, + { "merit-dump", "t", "dhcp", 14, 1}, + { "domain-name", "t", "dhcp", 15, 1}, + { "swap-server", "I", "dhcp", 16, 1}, + { "root-path", "t", "dhcp", 17, 1}, + { "extensions-path", "t", "dhcp", 18, 1}, + { "ip-forwarding", "f", "dhcp", 19, 1}, + { "non-local-source-routing", "f", "dhcp", 20, 1}, + { "policy-filter", "IIA", "dhcp", 21, 1}, + { "max-dgram-reassembly", "S", "dhcp", 22, 1}, + { "default-ip-ttl", "B", "dhcp", 23, 1}, + { "path-mtu-aging-timeout", "L", "dhcp", 24, 1}, + { "path-mtu-plateau-table", "SA", "dhcp", 25, 1}, + { "interface-mtu", "S", "dhcp", 26, 1}, + { "all-subnets-local", "f", "dhcp", 27, 1}, + { "broadcast-address", "I", "dhcp", 28, 1}, + { "perform-mask-discovery", "f", "dhcp", 29, 1}, + { "mask-supplier", "f", "dhcp", 30, 1}, + { "router-discovery", "f", "dhcp", 31, 1}, + { "router-solicitation-address", "I", "dhcp", 32, 1}, + { "static-routes", "IIA", "dhcp", 33, 1}, + { "trailer-encapsulation", "f", "dhcp", 34, 1}, + { "arp-cache-timeout", "L", "dhcp", 35, 1}, + { "ieee802-3-encapsulation", "f", "dhcp", 36, 1}, + { "default-tcp-ttl", "B", "dhcp", 37, 1}, + { "tcp-keepalive-interval", "L", "dhcp", 38, 1}, + { "tcp-keepalive-garbage", "f", "dhcp", 39, 1}, + { "nis-domain", "t", "dhcp", 40, 1}, + { "nis-servers", "IA", "dhcp", 41, 1}, + { "ntp-servers", "IA", "dhcp", 42, 1}, + { "vendor-encapsulated-options", "E.", "dhcp", 43, 1}, + { "netbios-name-servers", "IA", "dhcp", 44, 1}, + { "netbios-dd-server", "IA", "dhcp", 45, 1}, + { "netbios-node-type", "B", "dhcp", 46, 1}, + { "netbios-scope", "t", "dhcp", 47, 1}, + { "font-servers", "IA", "dhcp", 48, 1}, + { "x-display-manager", "IA", "dhcp", 49, 1}, + { "dhcp-requested-address", "I", "dhcp", 50, 1}, + { "dhcp-lease-time", "L", "dhcp", 51, 1}, + { "dhcp-option-overload", "B", "dhcp", 52, 1}, + { "dhcp-message-type", "B", "dhcp", 53, 1}, + { "dhcp-server-identifier", "I", "dhcp", 54, 1}, + { "dhcp-parameter-request-list", "BA", "dhcp", 55, 1}, + { "dhcp-message", "t", "dhcp", 56, 1}, + { "dhcp-max-message-size", "S", "dhcp", 57, 1}, + { "dhcp-renewal-time", "L", "dhcp", 58, 1}, + { "dhcp-rebinding-time", "L", "dhcp", 59, 1}, + { "vendor-class-identifier", "X", "dhcp", 60, 1}, + { "dhcp-client-identifier", "X", "dhcp", 61, 1}, + { "nwip-domain", "t", "dhcp", 62, 2}, + /// nwip-domain nwip-domain-name + { "nwip-suboptions", "Enwip.", "dhcp", 63, 1}, + { "nisplus-domain", "t", "dhcp", 64, 2}, + /// nisplus-domain nisplus-domain-name + { "nisplus-servers", "IA", "dhcp", 65, 1}, + { "tftp-server-name", "t", "dhcp", 66, 1}, + { "bootfile-name", "t", "dhcp", 67, 2}, + /// bootfile-name boot-file-name + { "mobile-ip-home-agent", "IA", "dhcp", 68, 1}, + { "smtp-server", "IA", "dhcp", 69, 1}, + { "pop-server", "IA", "dhcp", 70, 1}, + { "nntp-server", "IA", "dhcp", 71, 1}, + { "www-server", "IA", "dhcp", 72, 1}, + { "finger-server", "IA", "dhcp", 73, 1}, + { "irc-server", "IA", "dhcp", 74, 1}, + { "streettalk-server", "IA", "dhcp", 75, 1}, + { "streettalk-directory-assistance-server", "IA", + "dhcp", 76, 1}, + { "user-class", "t", "dhcp", 77, 1}, + { "slp-directory-agent", "fIa", "dhcp", 78, 0}, + /// not supported by Kea + { "slp-service-scope", "fto", "dhcp", 79, 9}, + /// not supported by Kea + /* 80 is the zero-length rapid-commit (RFC 4039) */ + { "fqdn", "Efqdn.", "dhcp", 81, 1}, + { "relay-agent-information", "Eagent.", "dhcp", 82, 2}, + /// relay-agent-information dhcp-agent-options + /* 83 is iSNS (RFC 4174) */ + /* 84 is unassigned */ + { "nds-servers", "IA", "dhcp", 85, 0}, + /// not supported by Kea + { "nds-tree-name", "t", "dhcp", 86, 0}, + /// not supported by Kea + { "nds-context", "t", "dhcp", 87, 0}, + /// not supported by Kea + { "bcms-controller-names", "D", "dhcp", 88, 0}, + /// not supported by Kea + { "bcms-controller-address", "Ia", "dhcp", 89, 0}, + /// not supported by Kea + /* 90 is the authentication option (RFC 3118) */ + /// supported by Kea + { "client-last-transaction-time", "L", "dhcp", 91, 1}, + { "associated-ip", "Ia", "dhcp", 92, 1}, + /// 93 supported by Kea + /// 94 supported by Kea + /// 97 supported by Kea + { "uap-servers", "t", "dhcp", 98, 0}, + /// not supported by Kea + { "geoconf-civic", "X", "dhcp", 99, 0}, + /// not supported by Kea + { "pcode", "t", "dhcp", 100, 0}, + /// not supported by Kea + { "tcode", "t", "dhcp", 101, 0}, + /// not supported by Kea + { "netinfo-server-address", "Ia", "dhcp", 112, 0}, + /// not supported by Kea + { "netinfo-server-tag", "t", "dhcp", 113, 0}, + /// not supported by Kea + { "default-url", "t", "dhcp", 114, 0}, + /// not supported by Kea + { "auto-config", "B", "dhcp", 116, 0}, + /// not supported by Kea + { "name-service-search", "Sa", "dhcp", 117, 0}, + /// not supported by Kea + { "subnet-selection", "I", "dhcp", 118, 1}, + { "domain-search", "Dc", "dhcp", 119, 1}, + /// Kea uses different format + { "vivco", "Evendor-class.", "dhcp", 124, 2}, + /// vivco vivco-suboptions + { "vivso", "Evendor.", "dhcp", 125, 2}, + /// vivso vivso-suboptions + {"pana-agent", "Ia", "dhcp", 136, 0}, + /// not supported by Kea + {"v4-lost", "d", "dhcp", 137, 0}, + /// not supported by Kea + {"capwap-ac-v4", "Ia", "dhcp", 138, 0}, + /// not supported by Kea + { "sip-ua-cs-domains", "Dc", "dhcp", 141, 0}, + /// not supported by Kea + { "ipv4-address-andsf", "IA", "dhcp", 142, 0}, + /// not supported by Kea + { "rdnss-selection", "BIID", "dhcp", 146, 0}, + /// not supported by Kea + { "v4-portparams", "BBS", "dhcp", 159, 0}, + /// not supported by Kea + { "v4-captive-portal", "t", "dhcp", 160, 0}, + /// not supported by Kea + { "option-6rd", "BB6Ia", "dhcp", 212, 0}, + /// not supported by Kea + {"v4-access-domain", "d", "dhcp", 213, 0}, + /// not supported by Kea + +/// DHCPv6 + + { "client-id", "X", "dhcp6", 1, 2}, + /// client-id clientid + { "server-id", "X", "dhcp6", 2, 2}, + /// server-id serverid + { "ia-na", "X", "dhcp6", 3, 1}, + { "ia-ta", "X", "dhcp6", 4, 1}, + { "ia-addr", "X", "dhcp6", 5, 2}, + /// ia-addr iaaddr + { "oro", "SA", "dhcp6", 6, 1}, + { "preference", "B", "dhcp6", 7, 1}, + { "elapsed-time", "S", "dhcp6", 8, 1}, + { "relay-msg", "X", "dhcp6", 9, 1}, + /* 10 is auth */ + /// 10 supported by Kea + { "unicast", "6", "dhcp6", 12, 1}, + { "status-code", "Nstatus-codes.to", "dhcp6", 13, 1}, + { "rapid-commit", "Z", "dhcp6", 14, 1}, + /* 15 is user-class */ + /// 15 supported by Kea + /* 16 is vendor-class */ + /// 16 supported by Kea + { "vendor-opts", "Evsio.", "dhcp6", 17, 1}, + { "interface-id", "X", "dhcp6", 18, 1}, + { "reconf-msg", "Ndhcpv6-messages.", "dhcp6", 19, 1}, + { "reconf-accept", "Z", "dhcp6", 20, 1}, + { "sip-servers-names", "D", "dhcp6", 21, 2}, + /// sip-servers-names sip-server-dns + { "sip-servers-addresses", "6A", "dhcp6", 22, 2}, + /// sip-servers-addresses sip-server-addr + { "name-servers", "6A", "dhcp6", 23, 2}, + /// name-servers dns-servers + { "domain-search", "D", "dhcp6", 24, 1}, + { "ia-pd", "X", "dhcp6", 25, 1}, + { "ia-prefix", "X", "dhcp6", 26, 2}, + /// ia-prefix iaprefix + { "nis-servers", "6A", "dhcp6", 27, 1}, + { "nisp-servers", "6A", "dhcp6", 28, 1}, + { "nis-domain-name", "D", "dhcp6", 29, 1}, + { "nisp-domain-name", "D", "dhcp6", 30, 1}, + { "sntp-servers", "6A", "dhcp6", 31, 1}, + { "info-refresh-time", "T", "dhcp6", 32, 2}, + /// info-refresh-time information-refresh-time + { "bcms-server-d", "D", "dhcp6", 33, 2}, + /// bcms-server-d bcms-server-dns + { "bcms-server-a", "6A", "dhcp6", 34, 2}, + /// bcms-server-a bcms-server-addr + /* Note that 35 is not assigned. */ + { "geoconf-civic", "X", "dhcp6", 36, 1}, + { "remote-id", "X", "dhcp6", 37, 1}, + { "subscriber-id", "X", "dhcp6", 38, 1}, + { "fqdn", "Efqdn6-if-you-see-me-its-a-bug-bug-bug.", + "dhcp6", 39, 2}, + /// fqdn client-fqdn + { "pana-agent", "6A", "dhcp6", 40, 1}, + { "new-posix-timezone", "t", "dhcp6", 41, 1}, + { "new-tzdb-timezone", "t", "dhcp6", 42, 1}, + { "ero", "SA", "dhcp6", 43, 1}, + { "lq-query", "X", "dhcp6", 44, 1}, + { "client-data", "X", "dhcp6", 45, 1}, + { "clt-time", "L", "dhcp6", 46, 1}, + { "lq-relay-data", "6X", "dhcp6", 47, 1}, + { "lq-client-link", "6A", "dhcp6", 48, 1}, + { "v6-lost", "d", "dhcp6", 51, 0}, + /// not supported by Kea + { "capwap-ac-v6", "6a", "dhcp6", 52, 0}, + /// not supported by Kea + { "relay-id", "X", "dhcp6", 53, 0}, + /// not supported by Kea + { "v6-access-domain", "d", "dhcp6", 57, 0}, + /// not supported by Kea + { "sip-ua-cs-list", "D", "dhcp6", 58, 0}, + /// not supported by Kea + { "bootfile-url", "t", "dhcp6", 59, 1}, + { "bootfile-param", "X", "dhcp6", 60, 1}, + { "client-arch-type", "SA", "dhcp6", 61, 1}, + { "nii", "BBB", "dhcp6", 62, 1}, + { "aftr-name", "d", "dhcp6", 64, 1}, + { "erp-local-domain-name", "d", "dhcp6", 65, 1}, + /// 66 supported by Kea + /// 67 supported by Kea + { "rdnss-selection", "6BD", "dhcp6", 74, 0}, + /// not supported by Kea + { "client-linklayer-addr", "X", "dhcp6", 79, 1}, + { "link-address", "6", "dhcp6", 80, 0}, + /// not supported by Kea + { "solmax-rt", "L", "dhcp6", 82, 0}, + /// not supported by Kea + { "inf-max-rt", "L", "dhcp6", 83, 0}, + /// not supported by Kea + { "dhcpv4-msg", "X", "dhcp6", 87, 2}, + /// dhcpv4-msg dhcpv4-message + { "dhcp4-o-dhcp6-server", "6A", "dhcp6", 88, 2}, + /// dhcp4-o-dhcp6-server dhcp4o6-server-addr + { "v6-captive-portal", "t", "dhcp6", 103, 0}, + /// not supported by Kea + { "ipv6-address-andsf", "6A", "dhcp6", 143, 0}, + /// not supported by Kea + +/// SERVER + + { "default-lease-time", "T", "_server_", 1, 0}, + { "max-lease-time", "T", "_server_", 2, 0}, + { "min-lease-time", "T", "_server_", 3, 0}, + { "dynamic-bootp-lease-cutoff", "T", "_server_", 4, 0}, + { "dynamic-bootp-lease-length", "L", "_server_", 5, 0}, + { "boot-unknown-clients", "f", "_server_", 6, 0}, + { "dynamic-bootp", "f", "_server_", 7, 0}, + { "allow-bootp", "f", "_server_", 8, 0}, + { "allow-booting", "f", "_server_", 9, 0}, + { "one-lease-per-client", "f", "_server_", 10, 0}, + { "get-lease-hostnames", "f", "_server_", 11, 0}, + { "use-host-decl-names", "f", "_server_", 12, 0}, + { "use-lease-addr-for-default-route", "f", + "_server_", 13, 0}, + { "min-secs", "B", "_server_", 14, 0}, + { "filename", "t", "_server_", 15, 0}, + { "server-name", "t", "_server_", 16, 0}, + { "next-server", "I", "_server_", 17, 0}, + { "authoritative", "f", "_server_", 18, 0}, + { "vendor-option-space", "U", "_server_", 19, 0}, + { "always-reply-rfc1048", "f", "_server_", 20, 0}, + { "site-option-space", "X", "_server_", 21, 0}, + { "always-broadcast", "f", "_server_", 22, 0}, + { "ddns-domainname", "t", "_server_", 23, 0}, + { "ddns-hostname", "t", "_server_", 24, 0}, + { "ddns-rev-domainname", "t", "_server_", 25, 0}, + { "lease-file-name", "t", "_server_", 26, 0}, + { "pid-file-name", "t", "_server_", 27, 0}, + { "duplicates", "f", "_server_", 28, 0}, + { "declines", "f", "_server_", 29, 0}, + { "ddns-updates", "f", "_server_", 30, 0}, + { "omapi-port", "S", "_server_", 31, 0}, + { "local-port", "S", "_server_", 32, 0}, + { "limited-broadcast-address", "I", "_server_", 33, 0}, + { "remote-port", "S", "_server_", 34, 0}, + { "local-address", "I", "_server_", 35, 0}, + { "omapi-key", "d", "_server_", 36, 0}, + { "stash-agent-options", "f", "_server_", 37, 0}, + { "ddns-ttl", "T", "_server_", 38, 0}, + { "ddns-update-style", "Nddns-styles.", "_server_", 39, 0}, + { "client-updates", "f", "_server_", 40, 0}, + { "update-optimization", "f", "_server_", 41, 0}, + { "ping-check", "f", "_server_", 42, 0}, + { "update-static-leases", "f", "_server_", 43, 0}, + { "log-facility", "Nsyslog-facilities.", + "_server_", 44, 0}, + { "do-forward-updates", "f", "_server_", 45, 0}, + { "ping-timeout", "T", "_server_", 46, 0}, + { "infinite-is-reserved", "f", "_server_", 47, 0}, + { "update-conflict-detection", "f", "_server_", 48, 0}, + { "leasequery", "f", "_server_", 49, 0}, + { "adaptive-lease-time-threshold", "B", "_server_", 50, 0}, + { "do-reverse-updates", "f", "_server_", 51, 0}, + { "fqdn-reply", "f", "_server_", 52, 0}, + { "preferred-lifetime", "T", "_server_", 53, 0}, + { "dhcpv6-lease-file-name", "t", "_server_", 54, 0}, + { "dhcpv6-pid-file-name", "t", "_server_", 55, 0}, + { "limit-addrs-per-ia", "L", "_server_", 56, 0}, + { "limit-prefs-per-ia", "L", "_server_", 57, 0}, + { "dhcp-cache-threshold", "B", "_server_", 78, 0}, + { "dont-use-fsync", "f", "_server_", 79, 0}, + { "ddns-local-address4", "I", "_server_", 80, 0}, + { "ddns-local-address6", "6", "_server_", 81, 0}, + { "ignore-client-uids", "f", "_server_", 82, 0}, + { "log-threshold-low", "B", "_server_", 83, 0}, + { "log-threshold-high", "B", "_server_", 84, 0}, + { "echo-client-id", "f", "_server_", 85, 0}, + { "server-id-check", "f", "_server_", 86, 0}, + { "prefix-length-mode", "Nprefix_length_modes.", + "_server_", 87, 0}, + { "dhcpv6-set-tee-times", "f", "_server_", 88, 0}, + { "abandon-lease-time", "T", "_server_", 89, 0}, + +/// END maker + + { NULL, NULL, NULL, 0, 0 } +}; + +const char * +option_map_space(const char *space) +{ + if (strcmp(space, "dhcp") == 0) + return "dhcp4"; + else if (strcmp(space, "dhcp6") == 0) + return space; + else if (strcmp(space, "vendor") == 0) + return "vendor-encapsulated-options-space"; + else if(strcmp(space, "agent") == 0) + return "dhcp-agent-options-space"; + else if(strcmp(space, "vsio") == 0) + return "vendor-opts-space"; + else + return NULL; +} + +struct option * +option_lookup_name(const char *space, const char *name) +{ + struct option *option; + + for (option = options; option->name != NULL; option++) { + if (strcmp(space, option->space) != 0) + continue; + if (strcmp(name, option->name) == 0) + return option; + } + return NULL; +} + +struct option * +option_lookup_code(const char *space, unsigned code) +{ + struct option *option; + + for (option = options; option->name != NULL; option++) { + if (strcmp(space, option->space) != 0) + continue; + if (code == option->code) + return option; + } + return NULL; +} + +void +option_map_name(struct option *option) +{ + assert(option != NULL); + assert(option->status == must_renamed); + + if (strcmp("dhcp4", option->space) == 0) + switch (option->code) { + case 5: + option->name = "name-servers"; + break; + case 62: + option->name = "nwip-domain-name"; + break; + case 64: + option->name = "nisplus-domain-name"; + break; + case 67: + option->name = "boot-file-name"; + break; + case 82: + option->name = "dhcp-agent-options"; + break; + case 124: + option->name = "vivco-suboptions"; + break; + case 125: + option->name = "vivso-suboptions"; + break; + default: + break; + } + if (strcmp("dhcp6", option->space) == 0) + switch (option->code) { + case 1: + option->name = "clientid"; + break; + case 2: + option->name = "serverid"; + break; + case 5: + option->name = "iaaddr"; + break; + case 21: + option->name = "sip-server-dns"; + break; + case 22: + option->name = "sip-server-addr"; + break; + case 23: + option->name = "dns-servers"; + break; + case 26: + option->name = "iaprefix"; + break; + case 32: + option->name = "information-refresh-time"; + break; + case 33: + option->name = "bcms-server-dns"; + break; + case 34: + option->name = "bcms-server-addr "; + break; + case 39: + option->name = "client-fqdn"; + break; + case 87: + option->name = "dhcpv4-message"; + break; + case 88: + option->name = "dhcp4o6-server-addr"; + break; + default: + break; + } + assert(0); +} diff --git a/keama/parse.c b/keama/parse.c index 7976be69..55d07672 100644 --- a/keama/parse.c +++ b/keama/parse.c @@ -26,6 +26,7 @@ #include <sys/types.h> #include <arpa/inet.h> #include <ctype.h> +#include <netdb.h> #include <stdlib.h> #include <string.h> @@ -54,8 +55,6 @@ static enum expression_context op_context(enum expr_op); static int op_precedence(enum expr_op, enum expr_op); static enum expression_context expression_context(struct element *); -static isc_boolean_t is_empty_option(struct element *); - /* Skip to the semicolon ending the current statement. If we encounter braces, the matching closing brace terminates the statement. */ @@ -198,14 +197,13 @@ parse_host_name(struct parse *cfile) */ struct string * -parse_ip_addr_or_hostname(struct parse *cfile, isc_boolean_t *ipaddr) +parse_ip_addr_or_hostname(struct parse *cfile, isc_boolean_t check_multi) { const char *val; enum dhcp_token token; unsigned char addr[4]; unsigned len = sizeof(addr); - - *ipaddr = ISC_FALSE; + isc_boolean_t ipaddr = ISC_FALSE; token = peek_token(&val, NULL, cfile); if (token == NUMBER) { @@ -220,17 +218,43 @@ parse_ip_addr_or_hostname(struct parse *cfile, isc_boolean_t *ipaddr) skip_token(NULL, NULL, cfile); if (next_token(NULL, NULL, cfile) == DOT && next_token(NULL, NULL, cfile) == NUMBER) - *ipaddr = ISC_TRUE; + ipaddr = ISC_TRUE; restore_parse_state(cfile); - if (*ipaddr) + if (ipaddr) return parse_numeric_aggregate(cfile, addr, &len, DOT, 10, 8); } - if (is_identifier(token) || token == NUMBER) - return parse_host_name(cfile); - return NULL; + if (is_identifier(token) || token == NUMBER) { + struct string *name; + struct hostent *h; + + name = parse_host_name(cfile); + if (name == NULL) + return NULL; + + /* from do_host_lookup */ + h = gethostbyname(name->content); + if ((h == NULL) || (h->h_addr_list[0] == NULL)) + parse_error(cfile, "%s: host unknown.", name->content); + if (check_multi && h->h_addr_list[1]) { + struct comment *comment; + char msg[128]; + + snprintf(msg, sizeof(msg), + "/// %s resolves into multiple addresses", + name->content); + comment = createComment(msg); + TAILQ_INSERT_TAIL(&cfile->comments, comment, next); + } + return makeString(4, h->h_addr_list[0]); + } + + if (token != RBRACE && token != LBRACE) + token = next_token(&val, NULL, cfile); + parse_error(cfile, "%s (%d): expecting IP address or hostname", + val, token); } /* @@ -401,6 +425,7 @@ parse_hardware_param(struct parse *cfile) else appendString(r, buf); hw = createString(r); + TAILQ_CONCAT(&hw->comments, &cfile->comments, next); if (!ether || (hlen != 6)) { hw->skip = ISC_TRUE; cfile->issue_counter++; @@ -605,15 +630,16 @@ convert_num(struct parse *cfile, unsigned char *buf, const char *str, IDENTIFIER . IDENTIFIER */ -struct element * -parse_option_name(struct parse *cfile) +struct option * +parse_option_name(struct parse *cfile, + isc_boolean_t allocate, + isc_boolean_t *known) { const char *val; enum dhcp_token token; - struct string *uname; - struct string *name; - struct element *option; - isc_boolean_t know_universe = ISC_TRUE; + const char *uname; + const char *space; + struct option *option = NULL; unsigned code; token = next_token(&val, NULL, cfile); @@ -621,7 +647,9 @@ parse_option_name(struct parse *cfile) parse_error(cfile, "expecting identifier after option keyword."); - uname = makeString(-1, val); + uname = strdup(val); + if (!uname) + parse_error(cfile, "no memory for uname information."); token = peek_token(&val, NULL, cfile); if (token == DOT) { /* Go ahead and take the DOT token... */ @@ -632,48 +660,88 @@ parse_option_name(struct parse *cfile) if (!is_identifier(token)) parse_error(cfile, "expecting identifier after '.'"); - name = makeString(-1, val); /* map universe to Kea space */ - if (strcmp(uname->content, "dhcp") == 0) { - uname = makeString(-1, "dhcp4"); - } else if (strcmp(uname->content, "vendor") == 0) { - uname = makeString(-1, - "vendor-encapsulated-options-space"); - } else if (strcmp(uname->content, "agent") == 0) { - uname = makeString(-1, "dhcp-agent-options-space"); - } else if (strcmp(uname->content, "dhcp6") == 0) { - /* same name */ - } else if (strcmp(uname->content, "vsio") == 0) { - uname = makeString(-1, "vendor-opts-space"); - } else - know_universe = ISC_FALSE; + space = option_map_space(uname); + + /* unknown things can't happen in warning free configs */ + if (!space) { + cfile->issue_counter++; + allocate = ISC_TRUE; + } } else { /* Use the default hash table, which contains all the standard dhcp option names. */ - name = uname; - uname = makeString(-1, "dhcp4"); - val = name->content; + val = uname; + space = "dhcp4"; } - option = createMap(); - mapSet(option, createString(uname), "space"); + if (space) + option = option_lookup_name(space, val); - /* If the option name is of the form unknown-[decimal], use - * the trailing decimal value to find the option definition. - * If there is no definition, construct one. This is to - * support legacy use of unknown options in config files or - * lease databases. - */ - if (strncasecmp(val, "unknown-", 8) == 0) { + if (option) { + if (known) + *known = ISC_TRUE; + if (option->status == must_renamed) + option_map_name(option); + return option; + } else if (strncasecmp(val, "unknown-", 8) == 0) { code = atoi(val + 8); - mapSet(option, createInt(code), "code"); - } else { - mapSet(option, createString(name), "name"); - } - if (!know_universe) { - option->skip = ISC_TRUE; - cfile->issue_counter++; - } + + /* Option code 0 is always illegal for us, thanks + * to the option decoder. + */ + if (code == 0) + parse_error(cfile, "Option code 0 is illegal " + "in the %s space.", space); + if ((local_family == AF_INET) && (code == 255)) + parse_error(cfile, "Option code 255 is illegal " + "in the %s space.", space); + + /* It's odd to think of unknown option codes as + * being known, but this means we know what the + * parsed name is talking about. + */ + if (known) + *known = ISC_TRUE; + if (space) + option = option_lookup_code(space, code); + + /* If we did not find an option of that code, + * manufacture an unknown-xxx option definition. + */ + if (option == NULL) { + option = (struct option *)malloc(sizeof(*option)); + /* DHCP code does not check allocation failure? */ + memset(option, 0, sizeof(*option)); + option->name = strdup(val); + option->space = space ? space : uname; + option->code = code; + /* X == binary but we shan't use CSV format */ + option->format = "X"; + } else { + struct comment *comment; + char msg[256]; + + snprintf(msg, sizeof(msg), + "/// option %s.%s redefinition", + val, space); + comment = createComment(msg); + TAILQ_INSERT_TAIL(&cfile->comments, comment, next); + } + /* If we've been told to allocate, that means that this + * (might) be an option code definition, so we'll create + * an option structure and return it for the parent to + * decide. + */ + } else if (allocate) { + option = (struct option *)malloc(sizeof(*option)); + /* DHCP code does not check allocation failure? */ + memset(option, 0, sizeof(*option)); + option->name = strdup(val); + option->space = space ? space : uname; + } else + parse_error(cfile, "no option named %s in space %s", + val, space); return option; } @@ -727,7 +795,7 @@ parse_option_space_decl(struct parse *cfile) if ((local_family == AF_INET) && (tsize != 1)) { struct comment *comment; - comment = createComment("### only code width " + comment = createComment("/// only code width " "1 is supported"); TAILQ_INSERT_TAIL(&p->comments, comment, next); @@ -735,7 +803,7 @@ parse_option_space_decl(struct parse *cfile) (tsize != 2)) { struct comment *comment; - comment = createComment("### only code width " + comment = createComment("/// only code width " "2 is supported"); TAILQ_INSERT_TAIL(&p->comments, comment, next); @@ -758,7 +826,7 @@ parse_option_space_decl(struct parse *cfile) if ((local_family == AF_INET) && (lsize != 1)) { struct comment *comment; - comment = createComment("### only length " + comment = createComment("/// only length " "width 1 is " "supported"); TAILQ_INSERT_TAIL(&p->comments, @@ -767,7 +835,7 @@ parse_option_space_decl(struct parse *cfile) (lsize != 2)) { struct comment *comment; - comment = createComment("### only length " + comment = createComment("/// only length " "width 2 is " "supported"); TAILQ_INSERT_TAIL(&p->comments, @@ -829,10 +897,11 @@ parse_option_space_decl(struct parse *cfile) ENCAPSULATE identifier */ void -parse_option_code_definition(struct parse *cfile, struct element *option) +parse_option_code_definition(struct parse *cfile, struct option *option) { const char *val; enum dhcp_token token; + struct element *def; unsigned arrayp = 0; int recordp = 0; isc_boolean_t no_more_in_record = ISC_FALSE; @@ -845,11 +914,27 @@ parse_option_code_definition(struct parse *cfile, struct element *option) struct string *saved; struct element *optdef; + /* Put the option in the definition */ + def = createMap(); + mapSet(def, createString(makeString(-1, option->space)), "space"); + mapSet(def, createString(makeString(-1, option->name)), "name"); + TAILQ_CONCAT(&def->comments, &cfile->comments, next); + if (option->status != kea_unknown) { + struct comment *comment; + + comment = createComment("/// Kea does not allow redefinition " + "of options"); + TAILQ_INSERT_TAIL(&def->comments, comment, next); + def->skip = ISC_TRUE; + cfile->issue_counter++; + } + /* Parse the option code. */ token = next_token(&val, NULL, cfile); if (token != NUMBER) parse_error(cfile, "expecting option code number."); - mapSet(option, createInt(atoi(val)), "code"); + TAILQ_CONCAT(&def->comments, &cfile->comments, next); + mapSet(def, createInt(atoi(val)), "code"); token = next_token(&val, NULL, cfile); if (token != EQUAL) @@ -890,10 +975,10 @@ parse_option_code_definition(struct parse *cfile, struct element *option) if (recordp) { struct comment *comment; - comment = createComment("### unsupported array " + comment = createComment("/// unsupported array " "inside a record"); - TAILQ_INSERT_TAIL(&option->comments, comment, next); - option->skip = ISC_TRUE; + TAILQ_INSERT_TAIL(&def->comments, comment, next); + def->skip = ISC_TRUE; not_supported = ISC_TRUE; cfile->issue_counter++; } @@ -908,10 +993,10 @@ parse_option_code_definition(struct parse *cfile, struct element *option) if (token == LBRACE) { struct comment *comment; - comment = createComment("### unsupported record " + comment = createComment("/// unsupported record " "inside an array"); - TAILQ_INSERT_TAIL(&option->comments, comment, next); - option->skip = ISC_TRUE; + TAILQ_INSERT_TAIL(&def->comments, comment, next); + def->skip = ISC_TRUE; not_supported = ISC_TRUE; cfile->issue_counter++; } @@ -969,10 +1054,10 @@ parse_option_code_definition(struct parse *cfile, struct element *option) struct comment *comment; skip_token(&val, NULL, cfile); - comment = createComment("### unsupported " + comment = createComment("/// unsupported " "compressed fqdn list"); - TAILQ_INSERT_TAIL(&option->comments, comment, next); - option->skip = ISC_TRUE; + TAILQ_INSERT_TAIL(&def->comments, comment, next); + def->skip = ISC_TRUE; not_supported = ISC_TRUE; cfile->issue_counter++; type = "compressed fqdn"; @@ -1044,23 +1129,23 @@ parse_option_code_definition(struct parse *cfile, struct element *option) parse_error(cfile, "Arrays of encapsulations don't make sense."); if (arrayp) - mapSet(option, createBool(arrayp), "array"); + mapSet(def, createBool(arrayp), "array"); if (recordp) { - mapSet(option, createString(datatype), "record-types"); - mapSet(option, createString(makeString(-1, "record")), "type"); + mapSet(def, createString(datatype), "record-types"); + mapSet(def, createString(makeString(-1, "record")), "type"); } else - mapSet(option, createString(datatype), "type"); + mapSet(def, createString(datatype), "type"); if (not_supported) - mapSet(option, createString(saved), "definition"); + mapSet(def, createString(saved), "definition"); if (has_encapsulation) - mapSet(option, createString(encapsulated), "encapsulate"); + mapSet(def, createString(encapsulated), "encapsulate"); optdef = mapGet(cfile->stack[1], "option-def"); if (optdef == NULL) { optdef = createList(); mapSet(cfile->stack[1], optdef, "option-def"); } - listPush(optdef, option); + listPush(optdef, def); } /* @@ -1246,6 +1331,7 @@ parse_executable_statements(struct element *statements, struct parse *cfile, isc_boolean_t *lose, enum expression_context case_context) { + /* Kea todo: check reduction to scalar */ while (parse_executable_statement(statements, cfile, lose, case_context)) /* continue */ @@ -1262,10 +1348,11 @@ parse_executable_statement(struct element *result, enum dhcp_token token; const char *val; struct element *st; - struct element *option; + struct option *option; struct element *var; struct element *pri; struct element *expr; + isc_boolean_t known; int flag; int i; struct element *zone; @@ -1323,30 +1410,24 @@ parse_executable_statement(struct element *result, case SEND: skip_token(&val, NULL, cfile); - option = parse_option_name(cfile); + known = ISC_FALSE; + option = parse_option_name(cfile, ISC_FALSE, &known); if (option == NULL) { *lose = ISC_TRUE; return ISC_FALSE; } - if (!option->skip) { - option->skip = ISC_TRUE; - cfile->issue_counter++; - } - mapSet(result, option, "send"); - return ISC_TRUE; + return parse_option_statement(result, cfile, option, + send_option_statement); case SUPERSEDE: case OPTION: skip_token(&val, NULL, cfile); - option = parse_option_name(cfile); + known = ISC_FALSE; + option = parse_option_name(cfile, ISC_FALSE, &known); if (option == NULL) { *lose = ISC_TRUE; return ISC_FALSE; } - if ((token == SUPERSEDE) && !option->skip) { - option->skip = ISC_TRUE; - cfile->issue_counter++; - } return parse_option_statement(result, cfile, option, supersede_option_statement); @@ -1360,11 +1441,8 @@ parse_executable_statement(struct element *result, flag = 2; pad: skip_token(&val, NULL, cfile); - option = parse_allow_deny(cfile, flag); - st = mapGet(option, "server-option"); - if (st == NULL) - return ISC_FALSE; - mapSet(result, st, "server-option"); + st = parse_allow_deny(cfile, flag); + mapSet(result, st, "server-control"); break; case DEFAULT: @@ -1372,7 +1450,8 @@ parse_executable_statement(struct element *result, token = peek_token(&val, NULL, cfile); if (token == COLON) goto switch_default; - option = parse_option_name(cfile); + known = ISC_FALSE; + option = parse_option_name(cfile, ISC_FALSE, &known); if (option == NULL) { *lose = ISC_TRUE; return ISC_FALSE; @@ -1381,7 +1460,8 @@ parse_executable_statement(struct element *result, default_option_statement); case PREPEND: skip_token(&val, NULL, cfile); - option = parse_option_name(cfile); + known = ISC_FALSE; + option = parse_option_name(cfile, ISC_FALSE, &known); if (option == NULL) { *lose = ISC_TRUE; return ISC_FALSE; @@ -1390,7 +1470,8 @@ parse_executable_statement(struct element *result, prepend_option_statement); case APPEND: skip_token(&val, NULL, cfile); - option = parse_option_name(cfile); + known = ISC_FALSE; + option = parse_option_name(cfile, ISC_FALSE, &known); if (option == NULL) { *lose = ISC_TRUE; return ISC_FALSE; @@ -1668,9 +1749,15 @@ parse_executable_statement(struct element *result, default: if (is_identifier(token)) { skip_token(&val, NULL, cfile); - option = createMap(); - return parse_option_statement(result, cfile, option, - supersede_option_statement); + /* the config universe is the server one */ + option = option_lookup_name("_server_", val); + if (option) { + result->skip = ISC_TRUE; + cfile->issue_counter++; + return parse_option_statement + (result, cfile, option, + supersede_option_statement); + } } if (token == NUMBER_OR_NAME || token == NAME) { @@ -1745,9 +1832,9 @@ parse_zone(struct element *zone, struct parse *cfile) skip_token(&val, NULL, cfile); do { struct string *value; - isc_boolean_t ia; - value = parse_ip_addr_or_hostname(cfile, &ia); + value = parse_ip_addr_or_hostname(cfile, + ISC_FALSE); if (value == NULL) parse_error(cfile, "expecting IP addr or hostname."); @@ -2312,6 +2399,8 @@ parse_non_binary(struct element *expr, struct element *chain; struct string *data; struct comment *comment; + struct option *option; + isc_boolean_t known; unsigned len; token = peek_token(&val, NULL, cfile); @@ -2364,17 +2453,23 @@ parse_non_binary(struct element *expr, case EXISTS: skip_token(&val, NULL, cfile); - /* Pass reference directly to expression structure. */ - nexp = parse_option_name(cfile); - if (nexp == NULL) { + known = ISC_FALSE; + option = parse_option_name(cfile, ISC_FALSE, &known); + if (option == NULL) { *lose = ISC_TRUE; return ISC_FALSE;; } - if (!nexp->skip) { - nexp->skip = ISC_TRUE; - cfile->issue_counter++; - } + nexp = createMap(); + mapSet(nexp, + createString(makeString(-1, option->space)), + "space"); + mapSet(nexp, + createString(makeString(-1, option->name)), + "name"); + nexp->skip = ISC_TRUE; + cfile->issue_counter++; mapSet(expr, nexp, "exists"); + /* Kea todo: we have it in classification */ break; case STATIC: @@ -2667,18 +2762,22 @@ parse_non_binary(struct element *expr, case OPTION: case CONFIG_OPTION: - cfile->issue_counter++; skip_token(&val, NULL, cfile); - /* Pass reference directly to expression structure. */ - nexp = parse_option_name(cfile); - if (nexp == NULL) { + known = ISC_FALSE; + option = parse_option_name(cfile, ISC_FALSE, &known); + if (option == NULL) { *lose = ISC_TRUE; return ISC_FALSE; } - if (!nexp->skip) { - nexp->skip = ISC_TRUE; - cfile->issue_counter++; - } + nexp = createMap(); + mapSet(nexp, + createString(makeString(-1, option->space)), + "space"); + mapSet(nexp, + createString(makeString(-1, option->name)), + "name"); + nexp->skip = ISC_TRUE; + cfile->issue_counter++; mapSet(expr, nexp, token == OPTION ? "option" : "config-option"); break; @@ -2897,7 +2996,7 @@ parse_non_binary(struct element *expr, #define FORMERR 1 #endif resetInt(expr, FORMERR); - comment = createComment("# constant FORMERR(1)"); + comment = createComment("/// constant FORMERR(1)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -2907,7 +3006,7 @@ parse_non_binary(struct element *expr, #define ISC_R_SUCCESS 0 #endif resetInt(expr, ISC_R_SUCCESS); - comment = createComment("# constant ISC_R_SUCCESS(0)"); + comment = createComment("/// constant ISC_R_SUCCESS(0)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -2917,7 +3016,7 @@ parse_non_binary(struct element *expr, #define DHCP_R_NOTAUTH ((6 << 16) + 21) #endif resetInt(expr, DHCP_R_NOTAUTH); - comment = createComment("# constant DHCP_R_NOTAUTH(393237)"); + comment = createComment("/// constant DHCP_R_NOTAUTH(393237)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -2927,7 +3026,7 @@ parse_non_binary(struct element *expr, #define ISC_R_NOTIMPLEMENTED 27 #endif resetInt(expr, ISC_R_NOTIMPLEMENTED); - comment = createComment("# constant ISC_R_NOTIMPLEMENTED(27)"); + comment = createComment("/// constant ISC_R_NOTIMPLEMENTED(27)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -2937,7 +3036,7 @@ parse_non_binary(struct element *expr, #define DHCP_R_NOTZONE ((6 << 16) + 22) #endif resetInt(expr, DHCP_R_NOTZONE); - comment = createComment("# constant DHCP_R_NOTZONE(393238)"); + comment = createComment("/// constant DHCP_R_NOTZONE(393238)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -2947,7 +3046,7 @@ parse_non_binary(struct element *expr, #define DHCP_R_NXDOMAIN ((6 << 16) + 15) #endif resetInt(expr, DHCP_R_NXDOMAIN); - comment = createComment("# constant DHCP_R_NXDOMAIN(393231)"); + comment = createComment("/// constant DHCP_R_NXDOMAIN(393231)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -2957,7 +3056,7 @@ parse_non_binary(struct element *expr, #define DHCP_R_NXRRSET ((6 << 16) + 20) #endif resetInt(expr, DHCP_R_NXRRSET); - comment = createComment("# constant DHCP_R_NXRRSET(393236)"); + comment = createComment("/// constant DHCP_R_NXRRSET(393236)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -2967,7 +3066,7 @@ parse_non_binary(struct element *expr, #define DHCP_R_REFUSED ((6 << 16) + 17) #endif resetInt(expr, DHCP_R_REFUSED); - comment = createComment("# constant DHCP_R_REFUSED(393233)"); + comment = createComment("/// constant DHCP_R_REFUSED(393233)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -2977,7 +3076,7 @@ parse_non_binary(struct element *expr, #define DHCP_R_SERVFAIL ((6 << 16) + 14) #endif resetInt(expr, DHCP_R_SERVFAIL); - comment = createComment("# constant DHCP_R_SERVFAIL(393230)"); + comment = createComment("/// constant DHCP_R_SERVFAIL(393230)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -2987,7 +3086,7 @@ parse_non_binary(struct element *expr, #define DHCP_R_YXDOMAIN ((6 << 16) + 18) #endif resetInt(expr, DHCP_R_YXDOMAIN); - comment = createComment("# constant DHCP_R_YXDOMAIN(393234)"); + comment = createComment("/// constant DHCP_R_YXDOMAIN(393234)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -2997,7 +3096,7 @@ parse_non_binary(struct element *expr, #define DHCP_R_YXRRSET ((6 << 16) + 19) #endif resetInt(expr, DHCP_R_YXRRSET); - comment = createComment("# constant DHCP_R_YXRRSET(393235)"); + comment = createComment("/// constant DHCP_R_YXRRSET(393235)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -3007,7 +3106,7 @@ parse_non_binary(struct element *expr, #define S_INIT 2 #endif resetInt(expr, S_INIT); - comment = createComment("# constant S_INIT(2)"); + comment = createComment("/// constant S_INIT(2)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -3017,7 +3116,7 @@ parse_non_binary(struct element *expr, #define S_REBOOTING 1 #endif resetInt(expr, S_REBOOTING); - comment = createComment("# constant S_REBOOTING(1)"); + comment = createComment("/// constant S_REBOOTING(1)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -3027,7 +3126,7 @@ parse_non_binary(struct element *expr, #define S_SELECTING 3 #endif resetInt(expr, S_SELECTING); - comment = createComment("# constant S_SELECTING(3)"); + comment = createComment("/// constant S_SELECTING(3)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -3037,7 +3136,7 @@ parse_non_binary(struct element *expr, #define S_REQUESTING 4 #endif resetInt(expr, S_REQUESTING); - comment = createComment("# constant S_REQUESTING(4)"); + comment = createComment("/// constant S_REQUESTING(4)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -3047,7 +3146,7 @@ parse_non_binary(struct element *expr, #define S_BOUND 5 #endif resetInt(expr, S_BOUND); - comment = createComment("# constant S_BOUND(5)"); + comment = createComment("/// constant S_BOUND(5)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -3057,7 +3156,7 @@ parse_non_binary(struct element *expr, #define S_RENEWING 6 #endif resetInt(expr, S_RENEWING); - comment = createComment("# constant S_RENEWING(6)"); + comment = createComment("/// constant S_RENEWING(6)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -3067,7 +3166,7 @@ parse_non_binary(struct element *expr, #define S_REBINDING 7 #endif resetInt(expr, S_REBINDING); - comment = createComment("# constant S_REBINDING(7)"); + comment = createComment("/// constant S_REBINDING(7)"); TAILQ_INSERT_TAIL(&expr->comments, comment, next); break; @@ -3488,7 +3587,9 @@ new_rhs: } isc_boolean_t -parse_option_data(struct element *expr, struct parse *cfile) +parse_option_data(struct element *expr, + struct parse *cfile, + struct option *option) { const char *val; enum dhcp_token token; @@ -3539,13 +3640,14 @@ parse_option_data(struct element *expr, struct parse *cfile) if (canon_bool) { struct comment *comment; - comment = createComment("## canonized booleans to true|false"); + comment = createComment("/// canonized booleans to " + " lowercase true or false"); TAILQ_INSERT_TAIL(&comments, comment, next); } if (has_ignore) { struct comment *comment; - comment = createComment("## 'ignore' pseudo-boolean is used"); + comment = createComment("/// 'ignore' pseudo-boolean is used"); TAILQ_INSERT_TAIL(&comments, comment, next); } return ISC_TRUE; @@ -3560,7 +3662,8 @@ parse_option_data(struct element *expr, struct parse *cfile) isc_boolean_t parse_option_statement(struct element *result, struct parse *cfile, - struct element *option, enum statement_op op) + + struct option *option, enum statement_op op) { const char *val; enum dhcp_token token; @@ -3568,9 +3671,10 @@ parse_option_statement(struct element *result, struct parse *cfile, isc_boolean_t lose; expr = createMap(); + TAILQ_CONCAT(&expr->comments, &cfile->comments, next); token = peek_token(&val, NULL, cfile); /* We should keep a list of defined empty options */ - if ((token == SEMI) && is_empty_option(option)) { + if ((token == SEMI) && (option && (option->format[0] != 'Z'))) { /* Eat the semicolon... */ /* * XXXSK: I'm not sure why we should ever get here, but we @@ -3594,7 +3698,7 @@ parse_option_statement(struct element *result, struct parse *cfile, return ISC_FALSE; } } else { - if (!parse_option_data(expr, cfile)) + if (!parse_option_data(expr, cfile, option)) return ISC_FALSE; } @@ -3958,46 +4062,3 @@ expression_context(struct element *expr) return context_boolean; return context_any; } - -/* Helpers */ - -static isc_boolean_t -is_empty_option(struct element *option) -{ - struct element *type; - struct element *code; - struct element *name; - - if (option == NULL) - return ISC_FALSE; - - type = mapGet(option, "type"); - code = mapGet(option, "code"); - name = mapGet(option, "name"); - - /* user defined with an available definition */ - if (type && (strcmp(stringValue(type)->content, "empty") == 0)) - return ISC_TRUE; - - /* It should be better to get the space... */ - if (local_family == AF_INET) { - /* not defined rapid commit at code 80 */ - if (code && (intValue(code) == 80)) - return ISC_TRUE; - } else { - /* Kea TODO: Are ISC DHCP option name case sensitive? */ - /* rapid-commit at code 14 */ - if ((name && - (strcasecmp(stringValue(name)->content, - "rapid-commit") == 0)) || - (code && (intValue(code) == 14))) - return ISC_TRUE; - /* reconf-accept at code 20 */ - if ((name && - (strcasecmp(stringValue(name)->content, - "reconf-accept") == 0)) || - (code && (intValue(code) == 20))) - return ISC_TRUE; - } - return ISC_FALSE; -} |