From 4388c38468faa5794e54f29364ae8b20426f9180 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 9 Aug 2026 10:34:01 +0200 Subject: [PATCH] Fix bogus 256-byte DHCPv6 vendor-class option. lookup_dhcp_len() returns the flag word from the option table, so since 1af6ee64686dfc1428bd8c8eb3a29eb91cb9fdda an option carrying OT_DHCP6_VENDOR yields an opt_len of 0x0100. --dhcp-option=option6:vendor-class,343 has a purely decimal argument list and therefore takes the is_dec branch, which comes long before the new OT_DHCP6_VENDOR branch, and if (opt_len != 0) new->len = opt_len; sets new->len to 256. The value is then written by shifting an int by up to 2040 bits, which is undefined behavior, and a 256-byte vendor-class option ends up on the wire: $ dnsmasq --test --dhcp-option=option6:vendor-class,343 option.c:1715:23: runtime error: shift exponent 2040 is too large for 32-bit type 'int' dnsmasq: syntax check OK. The numeric spelling option6:16,343 takes the same path. Before 1af6ee6 both were rejected, as vendor-class was OT_INTERNAL back then. Keep the is_dec branch away from OT_DHCP6_VENDOR, so the dedicated parser runs and reports the missing vendor class instead. Signed-off-by: DL6ER --- src/option.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/option.c b/src/option.c index 2846ea5..15c794e 100644 --- a/src/option.c +++ b/src/option.c @@ -1688,7 +1688,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags) parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL); new->flags |= DHOPT_HEX; } - else if (is_dec) + else if (is_dec && !(opt_len & OT_DHCP6_VENDOR)) { int i, val = atoi(comma); /* assume numeric arg is 1 byte except for