udhcp: support string user options, closes 10946

function                                             old     new   delta
udhcp_str2optset                                     536     628     +92
packed_usage                                       32757   32760      +3
udhcpc_main                                         2708    2692     -16
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 95/-16)             Total: 79 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2018-04-13 13:18:34 +02:00
parent 46158dc833
commit 266f6f1973
4 changed files with 54 additions and 46 deletions

View File

@ -70,8 +70,9 @@ option domain local
option lease 864000 # default: 10 days option lease 864000 # default: 10 days
option msstaticroutes 10.0.0.0/8 10.127.0.1 # single static route option msstaticroutes 10.0.0.0/8 10.127.0.1 # single static route
option staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1 option staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1
# Arbitrary option in hex form: # Arbitrary option in hex or string form:
option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4"
option 14 "dumpfile"
# Currently supported options (for more info, see options.c): # Currently supported options (for more info, see options.c):
#opt lease NUM #opt lease NUM

View File

@ -378,23 +378,6 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg)
* Called to parse "udhcpc -x OPTNAME:OPTVAL" * Called to parse "udhcpc -x OPTNAME:OPTVAL"
* and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives. * and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives.
*/ */
/* helper for the helper */
static char *allocate_tempopt_if_needed(
const struct dhcp_optflag *optflag,
char *buffer,
int *length_p)
{
char *allocated = NULL;
if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_BIN) {
const char *end;
allocated = xstrdup(buffer); /* more than enough */
end = hex2bin(allocated, buffer, 255);
if (errno)
bb_error_msg_and_die("malformed hex string '%s'", buffer);
*length_p = end - allocated;
}
return allocated;
}
/* helper: add an option to the opt_list */ /* helper: add an option to the opt_list */
static NOINLINE void attach_option( static NOINLINE void attach_option(
struct option_set **opt_list, struct option_set **opt_list,
@ -403,9 +386,16 @@ static NOINLINE void attach_option(
int length) int length)
{ {
struct option_set *existing; struct option_set *existing;
char *allocated; char *allocated = NULL;
allocated = allocate_tempopt_if_needed(optflag, buffer, &length); if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_BIN) {
const char *end;
allocated = xstrdup(buffer); /* more than enough */
end = hex2bin(allocated, buffer, 255);
if (errno)
bb_error_msg_and_die("malformed hex string '%s'", buffer);
length = end - allocated;
}
#if ENABLE_FEATURE_UDHCP_RFC3397 #if ENABLE_FEATURE_UDHCP_RFC3397
if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) { if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
/* reuse buffer and length for RFC1035-formatted string */ /* reuse buffer and length for RFC1035-formatted string */
@ -463,12 +453,12 @@ static NOINLINE void attach_option(
int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dhcp_optflag *optflags, const char *option_strings) int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dhcp_optflag *optflags, const char *option_strings)
{ {
struct option_set **opt_list = arg; struct option_set **opt_list = arg;
char *opt, *val; char *opt;
char *str; char *str;
const struct dhcp_optflag *optflag; const struct dhcp_optflag *optflag;
struct dhcp_optflag bin_optflag; struct dhcp_optflag userdef_optflag;
unsigned optcode; unsigned optcode;
int retval, length; int retval;
/* IP_PAIR needs 8 bytes, STATIC_ROUTES needs 9 max */ /* IP_PAIR needs 8 bytes, STATIC_ROUTES needs 9 max */
char buffer[9] ALIGNED(4); char buffer[9] ALIGNED(4);
uint16_t *result_u16 = (uint16_t *) buffer; uint16_t *result_u16 = (uint16_t *) buffer;
@ -476,28 +466,40 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dh
/* Cheat, the only *const* str possible is "" */ /* Cheat, the only *const* str possible is "" */
str = (char *) const_str; str = (char *) const_str;
opt = strtok(str, " \t="); opt = strtok(str, " \t=:");
if (!opt) if (!opt)
return 0; return 0;
optcode = bb_strtou(opt, NULL, 0); optcode = bb_strtou(opt, NULL, 0);
if (!errno && optcode < 255) { if (!errno && optcode < 255) {
/* Raw (numeric) option code */ /* Raw (numeric) option code.
bin_optflag.flags = OPTION_BIN; * Initially assume binary (hex-str), but if "str" or 'str'
bin_optflag.code = optcode; * is seen later, switch to STRING.
optflag = &bin_optflag; */
userdef_optflag.flags = OPTION_BIN;
userdef_optflag.code = optcode;
optflag = &userdef_optflag;
} else { } else {
optflag = &optflags[udhcp_option_idx(opt, option_strings)]; optflag = &optflags[udhcp_option_idx(opt, option_strings)];
} }
/* Loop to handle OPTION_LIST case, else execute just once */
retval = 0; retval = 0;
do { do {
val = strtok(NULL, ", \t"); int length;
char *val;
if (optflag->flags == OPTION_BIN)
val = trim(strtok(NULL, "")); /* do not split "'q w e'" */
else
val = strtok(NULL, ", \t");
if (!val) if (!val)
break; break;
length = dhcp_option_lengths[optflag->flags & OPTION_TYPE_MASK]; length = dhcp_option_lengths[optflag->flags & OPTION_TYPE_MASK];
retval = 0; retval = 0;
opt = buffer; /* new meaning for variable opt */ opt = buffer; /* new meaning for variable opt */
switch (optflag->flags & OPTION_TYPE_MASK) { switch (optflag->flags & OPTION_TYPE_MASK) {
case OPTION_IP: case OPTION_IP:
retval = udhcp_str2nip(val, buffer); retval = udhcp_str2nip(val, buffer);
@ -510,6 +512,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dh
if (retval) if (retval)
retval = udhcp_str2nip(val, buffer + 4); retval = udhcp_str2nip(val, buffer + 4);
break; break;
case_OPTION_STRING:
case OPTION_STRING: case OPTION_STRING:
case OPTION_STRING_HOST: case OPTION_STRING_HOST:
#if ENABLE_FEATURE_UDHCP_RFC3397 #if ENABLE_FEATURE_UDHCP_RFC3397
@ -577,12 +580,26 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dh
} }
break; break;
} }
case OPTION_BIN: /* handled in attach_option() */ case OPTION_BIN:
/* Raw (numeric) option code. Is it a string? */
if (val[0] == '"' || val[0] == '\'') {
char delim = val[0];
char *end = last_char_is(val + 1, delim);
if (end) {
*end = '\0';
val++;
userdef_optflag.flags = OPTION_STRING;
goto case_OPTION_STRING;
}
}
/* No: hex-str option, handled in attach_option() */
opt = val; opt = val;
retval = 1; retval = 1;
break;
default: default:
break; break;
} }
if (retval) if (retval)
attach_option(opt_list, optflag, opt, length); attach_option(opt_list, optflag, opt, length);
} while (retval && (optflag->flags & OPTION_LIST)); } while (retval && (optflag->flags & OPTION_LIST));

View File

@ -1063,6 +1063,7 @@ static void client_background(void)
//usage: "\n -x hostname:bbox - option 12" //usage: "\n -x hostname:bbox - option 12"
//usage: "\n -x lease:3600 - option 51 (lease time)" //usage: "\n -x lease:3600 - option 51 (lease time)"
//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" //usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
//usage: "\n -x 14:'\"dumpfile\"' - option 14 (shell-quoted)"
//usage: IF_UDHCP_VERBOSE( //usage: IF_UDHCP_VERBOSE(
//usage: "\n -v Verbose" //usage: "\n -v Verbose"
//usage: ) //usage: )
@ -1155,15 +1156,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
} }
} }
while (list_x) { while (list_x) {
char *optstr = llist_pop(&list_x); char *optstr = xstrdup(llist_pop(&list_x));
char *colon = strchr(optstr, ':');
if (colon)
*colon = ' ';
/* now it looks similar to udhcpd's config file line:
* "optname optval", using the common routine: */
udhcp_str2optset(optstr, &client_config.options, d6_optflags, d6_option_strings); udhcp_str2optset(optstr, &client_config.options, d6_optflags, d6_option_strings);
if (colon) free(optstr);
*colon = ':'; /* restore it for NOMMU reexec */
} }
if (d6_read_interface(client_config.interface, if (d6_read_interface(client_config.interface,

View File

@ -1224,6 +1224,7 @@ static void client_background(void)
//usage: "\n -x hostname:bbox - option 12" //usage: "\n -x hostname:bbox - option 12"
//usage: "\n -x lease:3600 - option 51 (lease time)" //usage: "\n -x lease:3600 - option 51 (lease time)"
//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" //usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
//usage: "\n -x 14:'\"dumpfile\"' - option 14 (shell-quoted)"
//usage: "\n -F NAME Ask server to update DNS mapping for NAME" //usage: "\n -F NAME Ask server to update DNS mapping for NAME"
//usage: "\n -V VENDOR Vendor identifier (default 'udhcp VERSION')" //usage: "\n -V VENDOR Vendor identifier (default 'udhcp VERSION')"
//usage: "\n -C Don't send MAC as client identifier" //usage: "\n -C Don't send MAC as client identifier"
@ -1335,15 +1336,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
} }
} }
while (list_x) { while (list_x) {
char *optstr = llist_pop(&list_x); char *optstr = xstrdup(llist_pop(&list_x));
char *colon = strchr(optstr, ':');
if (colon)
*colon = ' ';
/* now it looks similar to udhcpd's config file line:
* "optname optval", using the common routine: */
udhcp_str2optset(optstr, &client_config.options, dhcp_optflags, dhcp_option_strings); udhcp_str2optset(optstr, &client_config.options, dhcp_optflags, dhcp_option_strings);
if (colon) free(optstr);
*colon = ':'; /* restore it for NOMMU reexec */
} }
if (udhcp_read_interface(client_config.interface, if (udhcp_read_interface(client_config.interface,