summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancis Dupont <fdupont@isc.org>2017-04-11 03:37:20 +0200
committerFrancis Dupont <fdupont@isc.org>2018-11-29 16:42:12 +0100
commitf7270ab1fd2b2933eaf179403a349170746c977c (patch)
tree40dddc0c2a9ffc5900b220fdef1c128f471f7138
parent839fd6e7faf7890626ea9f7ad168af987044213b (diff)
downloadisc-dhcp-f7270ab1fd2b2933eaf179403a349170746c977c.tar.gz
Began 2nd pass
-rw-r--r--keama/Makefile.am2
-rw-r--r--keama/Makefile.in10
-rw-r--r--keama/confparse.c265
-rw-r--r--keama/dhctoken.h388
-rw-r--r--keama/json.c10
-rw-r--r--keama/keama.c4
-rw-r--r--keama/keama.h37
-rw-r--r--keama/options.c491
-rw-r--r--keama/parse.c423
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;
-}