mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-10-09 16:52:43 +07:00
dhcp6: implement vendor class support
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 <luizluca@gmail.com>
This commit is contained in:
+5
-3
@@ -1372,11 +1372,13 @@ described in RFC 3442.
|
||||
IPv6 options are specified using the \fBoption6:\fP
|
||||
keyword, followed by the option number or option name. The IPv6 option
|
||||
name space is disjoint from the IPv4 option name space. IPv6 addresses
|
||||
in options must be bracketed with square brackets, eg.
|
||||
\fB --dhcp-option=option6:ntp-server,[1234::56]\fP.
|
||||
in options must be bracketed with square brackets, eg. \fB --dhcp-option=option6:ntp-server,[1234::56]\fP.
|
||||
For IPv6, [::] means "the global address of
|
||||
the machine running dnsmasq", whilst [fd00::] is replaced with the
|
||||
ULA, if it exists, and [fe80::] with the link-local address.
|
||||
ULA, if it exists, and [fe80::] with the link-local address. The vendorclass option
|
||||
is special for DHCPv6, since it requires an enterprise number which must appear as a decimal number
|
||||
before the class(es). eg. \fB --dhcp-option=option6:vendor-class,343,HTTPClient\fP
|
||||
|
||||
|
||||
Be careful: data-type suitability for the option number sent is not checked.
|
||||
It is quite possible to persuade dnsmasq to generate illegal DHCP packets with
|
||||
|
||||
+32
-1
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user