

























Implement the OT_DHCP6_VENDOR option type to properly handle the DHCPv6 Vendor Class option (code 16) according to RFC 3315.
Previously, this option was marked as OT_INTERNAL, causing dnsmasq to fail immediately if configured by name. Bypassing this block by using the numerical option format (option6:16) caused the payload to be formatted with an unintended string-length prefix. This broke compliance because the RFC requires a fixed 4-byte Enterprise ID at the beginning of the option, followed by data blocks. This byte misalignment broke features like UEFI HTTP IPv6 Boot This patch removes the OT_INTERNAL restriction and moves the formatting logic to the parser phase, correctly assembling the wire-format layout (4-byte ID + 2-byte chunk length + string) so it can be injected directly into the network buffer. Signed-off-by: Luiz Angelo Daros de Luca <[email protected]> --- src/dhcp-common.c | 33 ++++++++++++++++++++++++++++++++- src/dnsmasq.h | 1 + src/option.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/dhcp-common.c b/src/dhcp-common.c index 6b8824a..fa92381 100644 --- a/src/dhcp-common.c +++ b/src/dhcp-common.c @@ -734,7 +734,7 @@ static const struct opttab_t opttab6[] = { { "status", 13, OT_INTERNAL }, { "rapid-commit", 14, OT_INTERNAL }, { "user-class", 15, OT_INTERNAL | OT_CSTRING }, - { "vendor-class", 16, OT_INTERNAL | OT_CSTRING }, + { "vendor-class", 16, OT_DHCP6_VENDOR }, { "vendor-opts", 17, OT_INTERNAL }, { "sip-server-domain", 21, OT_RFC1035_NAME }, { "sip-server", 22, OT_ADDR_LIST }, @@ -909,6 +909,37 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, buf[j++] = ','; } } + else if ((ot[o].size & OT_DHCP6_VENDOR)) + { + unsigned int enterprise; + unsigned char *p = &val[0]; + + if (opt_len >= 4) + { + GETLONG(enterprise, p); + snprintf(buf, buf_len, "%u", enterprise); + j = strlen(buf); + i = 4; + while (i + 2 <= opt_len) + { + int k, len; + p = &val[i]; + GETSHORT(len, p); + if (i + 2 + len > opt_len) + break; + if (j < buf_len - 1) + buf[j++] = ','; + for (k = 0; k < len && j < buf_len - 1; k++) + { + char c = *p++; + if (isprint((unsigned char)c)) + buf[j++] = c; + } + buf[j] = 0; + i += len + 2; + } + } + } #endif else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0) { diff --git a/src/dnsmasq.h b/src/dnsmasq.h index ebb8d15..88171f9 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -834,6 +834,7 @@ struct frec { #define OT_CSTRING 0x0800 #define OT_DEC 0x0400 #define OT_TIME 0x0200 +#define OT_DHCP6_VENDOR 0x0100 /* actions in the daemon->helper RPC */ #define ACTION_DEL 1 diff --git a/src/option.c b/src/option.c index 274732f..a11a341 100644 --- a/src/option.c +++ b/src/option.c @@ -1902,6 +1902,51 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags) comma = split(arg); } + new->val = newp; + new->len = p - newp; + } + else if (comma && (opt_len & OT_DHCP6_VENDOR)) + { + /* First arg is Enterprise ID (4 bytes) + subsequent are length fields (2 bytes each) + string */ + int i, commas = 1; + unsigned char *p, *newp; + + for (i = 0; comma[i]; i++) + if (comma[i] == ',') + commas++; + + newp = opt_malloc(strlen(comma)+(2*commas)+4); + p = newp; + arg = comma; + comma = split(arg); + + if (arg && *arg) + { + unsigned int enterprise = atoi(arg); + PUTLONG(enterprise, p); + } + else + goto_err(_("missing enterprise ID in dhcp-option")); + + arg = comma; + comma = split(arg); + + if (!arg || !*arg) + goto_err(_("missing vendor class in dhcp-option")); + + while (arg && *arg) + { + u16 len = strlen(arg); + unhide_metas(arg); + PUTSHORT(len, p); + memcpy(p, arg, len); + p += len; + + arg = comma; + comma = split(arg); + } + new->val = newp; new->len = p - newp; } -- 2.54.0 _______________________________________________ Dnsmasq-discuss mailing list [email protected] https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。