udhcp: support string user options, closes 10946
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 13 Apr 2018 11:18:34 +0000 (13:18 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 13 Apr 2018 11:27:52 +0000 (13:27 +0200)
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>
examples/udhcp/udhcpd.conf
networking/udhcp/common.c
networking/udhcp/d6_dhcpc.c
networking/udhcp/dhcpc.c

index eca44c0ab41ed09df2d8d1aaf84be803c6b882be..90714bcdf06feb2e38018dc4217e15d111bf17f4 100644 (file)
@@ -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
index d3eea5def50e2c0b2e6a8a6de41cc68afda12ad6..fbf9c6878a3b2d80403b6323f4a96dedb3e61778 100644 (file)
@@ -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));
index 289df66ee630b220202b071b3ceb776f8c57d3ca..85d9da724a21b92f8d18adf4b8b502a6ea2a2c1b 100644 (file)
@@ -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,
index 90b07bf4b2952e2c2088af56df797c69215b32a3..bd9e8fdc2d4edd7fd04df3556348121ea9ea6e54 100644 (file)
@@ -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,