From 266f6f19732f9b35487a87a346e58c1c3a0af43d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 13 Apr 2018 13:18:34 +0200 Subject: 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 --- examples/udhcp/udhcpd.conf | 3 +- networking/udhcp/common.c | 71 ++++++++++++++++++++++++++++----------------- networking/udhcp/d6_dhcpc.c | 11 ++----- networking/udhcp/dhcpc.c | 11 ++----- 4 files changed, 52 insertions(+), 44 deletions(-) diff --git a/examples/udhcp/udhcpd.conf b/examples/udhcp/udhcpd.conf index eca44c0ab..90714bcdf 100644 --- a/examples/udhcp/udhcpd.conf +++ b/examples/udhcp/udhcpd.conf @@ -70,8 +70,9 @@ option domain local option lease 864000 # default: 10 days 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 -# 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 14 "dumpfile" # Currently supported options (for more info, see options.c): #opt lease NUM diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index d3eea5def..fbf9c6878 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -378,34 +378,24 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg) * Called to parse "udhcpc -x OPTNAME:OPTVAL" * and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives. */ -/* helper for the helper */ -static char *allocate_tempopt_if_needed( +/* helper: add an option to the opt_list */ +static NOINLINE void attach_option( + struct option_set **opt_list, const struct dhcp_optflag *optflag, char *buffer, - int *length_p) + int length) { + struct option_set *existing; 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; + length = end - allocated; } - return allocated; -} -/* helper: add an option to the opt_list */ -static NOINLINE void attach_option( - struct option_set **opt_list, - const struct dhcp_optflag *optflag, - char *buffer, - int length) -{ - struct option_set *existing; - char *allocated; - - allocated = allocate_tempopt_if_needed(optflag, buffer, &length); #if ENABLE_FEATURE_UDHCP_RFC3397 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_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) { struct option_set **opt_list = arg; - char *opt, *val; + char *opt; char *str; const struct dhcp_optflag *optflag; - struct dhcp_optflag bin_optflag; + struct dhcp_optflag userdef_optflag; unsigned optcode; - int retval, length; + int retval; /* IP_PAIR needs 8 bytes, STATIC_ROUTES needs 9 max */ char buffer[9] ALIGNED(4); 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 "" */ str = (char *) const_str; - opt = strtok(str, " \t="); + opt = strtok(str, " \t=:"); if (!opt) return 0; optcode = bb_strtou(opt, NULL, 0); if (!errno && optcode < 255) { - /* Raw (numeric) option code */ - bin_optflag.flags = OPTION_BIN; - bin_optflag.code = optcode; - optflag = &bin_optflag; + /* Raw (numeric) option code. + * Initially assume binary (hex-str), but if "str" or 'str' + * is seen later, switch to STRING. + */ + userdef_optflag.flags = OPTION_BIN; + userdef_optflag.code = optcode; + optflag = &userdef_optflag; } else { optflag = &optflags[udhcp_option_idx(opt, option_strings)]; } + /* Loop to handle OPTION_LIST case, else execute just once */ retval = 0; 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) break; + length = dhcp_option_lengths[optflag->flags & OPTION_TYPE_MASK]; retval = 0; opt = buffer; /* new meaning for variable opt */ + switch (optflag->flags & OPTION_TYPE_MASK) { case OPTION_IP: 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) retval = udhcp_str2nip(val, buffer + 4); break; +case_OPTION_STRING: case OPTION_STRING: case OPTION_STRING_HOST: #if ENABLE_FEATURE_UDHCP_RFC3397 @@ -577,12 +580,26 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dh } 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; retval = 1; + break; default: break; } + if (retval) attach_option(opt_list, optflag, opt, length); } while (retval && (optflag->flags & OPTION_LIST)); diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 289df66ee..85d9da724 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c @@ -1063,6 +1063,7 @@ static void client_background(void) //usage: "\n -x hostname:bbox - option 12" //usage: "\n -x lease:3600 - option 51 (lease time)" //usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" +//usage: "\n -x 14:'\"dumpfile\"' - option 14 (shell-quoted)" //usage: IF_UDHCP_VERBOSE( //usage: "\n -v Verbose" //usage: ) @@ -1155,15 +1156,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) } } while (list_x) { - char *optstr = 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: */ + char *optstr = xstrdup(llist_pop(&list_x)); udhcp_str2optset(optstr, &client_config.options, d6_optflags, d6_option_strings); - if (colon) - *colon = ':'; /* restore it for NOMMU reexec */ + free(optstr); } if (d6_read_interface(client_config.interface, diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 90b07bf4b..bd9e8fdc2 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -1224,6 +1224,7 @@ static void client_background(void) //usage: "\n -x hostname:bbox - option 12" //usage: "\n -x lease:3600 - option 51 (lease time)" //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 -V VENDOR Vendor identifier (default 'udhcp VERSION')" //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) { - char *optstr = 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: */ + char *optstr = xstrdup(llist_pop(&list_x)); udhcp_str2optset(optstr, &client_config.options, dhcp_optflags, dhcp_option_strings); - if (colon) - *colon = ':'; /* restore it for NOMMU reexec */ + free(optstr); } if (udhcp_read_interface(client_config.interface, -- cgit v1.2.3