dhcpv4: don't hardcode options array length
authorDavid Härdeman <[email protected]>
Tue, 7 Oct 2025 08:09:38 +0000 (10:09 +0200)
committerÁlvaro Fernández Rojas <[email protected]>
Tue, 21 Oct 2025 17:05:51 +0000 (19:05 +0200)
Instead of copying around the same data on the stack, keep two arrays with
mandatory and requested options, then loop over both of them.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
src/dhcpv4.c

index 509f9e78890027ab6bf3c73e4bf82d4a0545fd78..aa72bdcb89bd6f46c48fb739a90a4ba1582c6588 100644 (file)
@@ -780,8 +780,6 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len,
                .code = DHCPV4_OPT_DNR,
        };
        uint8_t reply_end = DHCPV4_OPT_END;
-       uint8_t *reply_opts;
-       size_t reply_opts_len = 0;
 
        struct iovec iov[IOV_TOTAL] = {
                [IOV_HEADER]            = { &reply, sizeof(reply) },
@@ -812,6 +810,22 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len,
                [IOV_PADDING]           = { NULL, 0 },
        };
 
+       /* Options which *might* be included in the reply unrequested */
+       uint8_t std_opts[] = {
+               DHCPV4_OPT_NETMASK,
+               DHCPV4_OPT_ROUTER,
+               DHCPV4_OPT_DNSSERVER,
+               DHCPV4_OPT_HOSTNAME,
+               DHCPV4_OPT_MTU,
+               DHCPV4_OPT_BROADCAST,
+               DHCPV4_OPT_LEASETIME,
+               DHCPV4_OPT_RENEW,
+               DHCPV4_OPT_REBIND,
+               DHCPV4_OPT_AUTHENTICATION,
+               DHCPV4_OPT_SEARCH_DOMAIN,
+               DHCPV4_OPT_FORCERENEW_NONCE_CAPABLE,
+       };
+
        /* Misc */
        struct sockaddr_in dest_addr;
        bool incl_fr_opt = false;
@@ -957,25 +971,11 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len,
                return;
        }
 
-       reply_opts = alloca(req_opts_len + 32);
-       reply_opts[reply_opts_len++] = DHCPV4_OPT_NETMASK;
-       reply_opts[reply_opts_len++] = DHCPV4_OPT_ROUTER;
-       reply_opts[reply_opts_len++] = DHCPV4_OPT_DNSSERVER;
-       reply_opts[reply_opts_len++] = DHCPV4_OPT_HOSTNAME;
-       reply_opts[reply_opts_len++] = DHCPV4_OPT_MTU;
-       reply_opts[reply_opts_len++] = DHCPV4_OPT_BROADCAST;
-       reply_opts[reply_opts_len++] = DHCPV4_OPT_LEASETIME;
-       reply_opts[reply_opts_len++] = DHCPV4_OPT_RENEW;
-       reply_opts[reply_opts_len++] = DHCPV4_OPT_REBIND;
-       reply_opts[reply_opts_len++] = DHCPV4_OPT_AUTHENTICATION;
-       reply_opts[reply_opts_len++] = DHCPV4_OPT_SEARCH_DOMAIN;
-       reply_opts[reply_opts_len++] = DHCPV4_OPT_FORCERENEW_NONCE_CAPABLE;
-       memcpy(&reply_opts[reply_opts_len], req_opts, req_opts_len);
-       reply_opts_len += req_opts_len;
-
        /* Note: each option might get called more than once */
-       for (size_t i = 0; i < reply_opts_len; i++) {
-               switch (reply_opts[i]) {
+       for (size_t i = 0; i < sizeof(std_opts) + req_opts_len; i++) {
+               uint8_t opt = i < sizeof(std_opts) ? std_opts[i] : req_opts[i - sizeof(std_opts)];
+
+               switch (opt) {
                case DHCPV4_OPT_NETMASK:
                        if (!a)
                                break;