summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvan Hunt <each@isc.org>2008-01-23 19:19:22 +0000
committerEvan Hunt <each@isc.org>2008-01-23 19:19:22 +0000
commit4cafb815437c88938502ad45393a2be70f448511 (patch)
treeda8ef6656190863aad1c9945a45d6fefb61264e9
parent771484ac0449ca6c0e3b4263c69f84dc1b5b00f2 (diff)
downloadisc-dhcp-4cafb815437c88938502ad45393a2be70f448511.tar.gz
Added explicit parser support for zero-length DHCP options, such as
rapid-commit, via format code 'Z' [rt17355]
-rw-r--r--RELNOTES3
-rw-r--r--common/conflex.c2
-rw-r--r--common/options.c2
-rw-r--r--common/parse.c47
-rw-r--r--common/tables.c5
-rw-r--r--includes/dhctoken.h3
6 files changed, 48 insertions, 14 deletions
diff --git a/RELNOTES b/RELNOTES
index 20547e66..432ed4e0 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -55,6 +55,9 @@ suggested fixes to <dhcp-users@isc.org>.
Changes since 4.0.0
+- Added explicit parser support for zero-length DHCP options, such as
+ rapid-commit, via format code 'Z'
+
- Exit with warning when DHCPv6-specific statements are used in the
config file but -6 is not specified.
diff --git a/common/conflex.c b/common/conflex.c
index 5ac39d8d..27568d28 100644
--- a/common/conflex.c
+++ b/common/conflex.c
@@ -1422,6 +1422,8 @@ intern(char *atom, enum dhcp_token dfv) {
return NS_YXRRSET;
break;
case 'z':
+ if (!strcasecmp (atom + 1, "erolen"))
+ return ZEROLEN;
if (!strcasecmp (atom + 1, "one"))
return ZONE;
break;
diff --git a/common/options.c b/common/options.c
index cb46b11f..dc8f86ab 100644
--- a/common/options.c
+++ b/common/options.c
@@ -2660,7 +2660,7 @@ append_option(struct data_string *dst, struct universe *universe,
{
struct data_string tmp;
- if (src->len == 0)
+ if (src->len == 0 && option->format[0] != 'Z')
return 0;
memset(&tmp, 0, sizeof(tmp));
diff --git a/common/parse.c b/common/parse.c
index f6bfa131..585a3578 100644
--- a/common/parse.c
+++ b/common/parse.c
@@ -1666,6 +1666,18 @@ int parse_option_code_definition (cfile, option)
has_encapsulation = 1;
break;
+ case ZEROLEN:
+ type = 'Z';
+ if (arrayp) {
+ parse_warn (cfile, "array incompatible with zerolen.");
+ skip_to_rbrace (cfile, recordp);
+ if (recordp)
+ skip_to_semi (cfile);
+ return 0;
+ }
+ no_more_in_record = 1;
+ break;
+
default:
parse_warn (cfile, "unknown data type %s", val);
skip_to_rbrace (cfile, recordp);
@@ -4902,7 +4914,7 @@ struct option *option;
fmt = option->format;
/* 'a' means always uniform */
- if ((fmt[0] != '\0') && (tolower((int)fmt[1]) == 'a'))
+ if ((fmt[0] != 'Z') && (tolower((int)fmt[1]) == 'a'))
uniform = 1;
do {
@@ -4913,8 +4925,9 @@ struct option *option;
tmp = *expr;
*expr = NULL;
+
if (!parse_option_token(expr, cfile, &fmt, tmp,
- uniform, lookups)) {
+ uniform, lookups)) {
if (fmt [1] != 'o') {
if (tmp)
expression_dereference (&tmp,
@@ -4924,12 +4937,10 @@ struct option *option;
*expr = tmp;
tmp = NULL;
}
- if (tmp)
+ if (tmp)
expression_dereference (&tmp, MDL);
- if (*fmt != '\0')
- fmt++;
-
+ fmt++;
} while (*fmt != '\0');
if ((*fmt == 'A') || (*fmt == 'a')) {
@@ -4975,7 +4986,7 @@ int parse_option_statement (result, cfile, lookups, option, op)
int lose;
token = peek_token (&val, (unsigned *)0, cfile);
- if ((token == SEMI) && (option->format[0] != '\0')) {
+ if ((token == SEMI) && (option->format[0] != 'Z')) {
/* Eat the semicolon... */
/*
* XXXSK: I'm not sure why we should ever get here, but we
@@ -5261,8 +5272,13 @@ int parse_option_token (rv, cfile, fmt, expr, uniform, lookups)
return 0;
break;
- case '\0': /* Zero-length option. */
- buf[0] = '\0';
+ case 'Z': /* Zero-length option. */
+ token = peek_token (&val, (unsigned *)0, cfile);
+ if (token != SEMI) {
+ parse_warn(cfile, "semicolon expected.");
+ skip_to_semi(cfile);
+ }
+ buf[0] = '\0';
if (!make_const_data(&t, /* expression */
buf, /* buffer */
0, /* length */
@@ -5273,7 +5289,7 @@ int parse_option_token (rv, cfile, fmt, expr, uniform, lookups)
break;
default:
- parse_warn (cfile, "Bad format %c in parse_option_token.",
+ parse_warn (cfile, "Bad format '%c' in parse_option_token.",
**fmt);
skip_to_semi (cfile);
return 0;
@@ -5511,6 +5527,17 @@ int parse_option_decl (oc, cfile)
dp = buf;
goto alloc;
+ case 'Z': /* Zero-length option */
+ token = next_token(&val, (unsigned *)0, cfile);
+ if (token != SEMI) {
+ parse_warn(cfile,
+ "semicolon expected.");
+ goto parse_exit;
+ }
+ len = 0;
+ buf[0] = '\0';
+ break;
+
default:
log_error ("parse_option_param: Bad format %c",
*fmt);
diff --git a/common/tables.c b/common/tables.c
index 9259332d..27972835 100644
--- a/common/tables.c
+++ b/common/tables.c
@@ -92,6 +92,7 @@ HASH_FUNCTIONS (option_code, const unsigned *, struct option,
d - Domain name (i.e., FOO or FOO.BAR).
D - Domain list (i.e., example.com eng.example.com)
c - When following a 'D' atom, enables compression pointers.
+ Z - Zero-length option
*/
struct universe dhcp_universe;
@@ -341,7 +342,7 @@ static struct option dhcpv6_options[] = {
#endif
{ "unicast", "6", &dhcpv6_universe, 12, 1 },
{ "status-code", "Nstatus-codes.to", &dhcpv6_universe, 13, 1 },
- { "rapid-commit", "", &dhcpv6_universe, 14, 1 },
+ { "rapid-commit", "Z", &dhcpv6_universe, 14, 1 },
#if 0
/* XXX: user-class contents are of the form "StA" where the
* integer describes the length of the text field. We don't have
@@ -354,7 +355,7 @@ static struct option dhcpv6_options[] = {
{ "vendor-opts", "Evsio.", &dhcpv6_universe, 17, 1 },
{ "interface-id", "X", &dhcpv6_universe, 18, 1 },
{ "reconf-msg", "Ndhcpv6-messages.", &dhcpv6_universe, 19, 1 },
- { "reconf-accept", "", &dhcpv6_universe, 20, 1 },
+ { "reconf-accept", "Z", &dhcpv6_universe, 20, 1 },
/* RFC3319 OPTIONS */
diff --git a/includes/dhctoken.h b/includes/dhctoken.h
index 568d4112..2a8fb3f1 100644
--- a/includes/dhctoken.h
+++ b/includes/dhctoken.h
@@ -348,7 +348,8 @@ enum dhcp_token {
RANGE6 = 651,
WHITESPACE = 652,
TOKEN_ALSO = 653,
- AFTER = 654
+ AFTER = 654,
+ ZEROLEN = 655
};
#define is_identifier(x) ((x) >= FIRST_TOKEN && \