Accept DHCPv6 vendorclasses with any enterprise number in --dhcp-vendorclass

if not enterprise number is specified. Also accept and match on
enterprise number only.
This commit is contained in:
Simon Kelley
2026-03-17 12:12:59 +00:00
parent 53313014b5
commit b4a0663654
3 changed files with 52 additions and 35 deletions

View File

@@ -1515,7 +1515,7 @@ The normal default DNS server (the same address as the DHCP server)
will not be appropriate when there is no route bewteen the
two, so this will have to be explicitly configured.
.TP
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,][<vendor-class>]
Map from a vendor-class string to a tag. Most DHCP clients provide a
"vendor class" which represents, in some sense, the type of host. This option
maps vendor classes to tags, so that DHCP options may be selectively delivered
@@ -1529,9 +1529,11 @@ allow fuzzy matching. The set: prefix is optional but allowed for
consistency.
Note that in IPv6 only, vendorclasses are namespaced with an
IANA-allocated enterprise number. This is given with enterprise:
IANA-allocated enterprise number. This may be given with an enterprise:
keyword and specifies that only vendorclasses matching the specified
number should be searched.
number should be searched. Similarly, an enterprise number may be given
with no vendor-class string. This always matches vendorclasses with
the given enterprise number.
.TP
.B \-j, --dhcp-userclass=set:<tag>,<user-class>
Map from a user-class string to a tag (with substring

View File

@@ -4580,39 +4580,41 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
only allowed for agent-options. */
arg = comma;
if ((comma = split(arg)))
if (option == 'U' && strstr(arg, "enterprise:") == arg)
{
if (option != 'U' || strstr(arg, "enterprise:") != arg)
comma = split(arg);
new->enterprise = atoi(arg+11);
arg = comma;
}
if (arg)
{
for (dig = 0, colon = 0, p = (unsigned char *)arg; *p; p++)
if (isxdigit(*p))
dig = 1;
else if (*p == ':')
colon = 1;
else
break;
unhide_metas(arg);
if (option == 'U' || option == 'j' || *p || !dig || !colon)
{
free(new->netid.net);
ret_err_free(gen_err, new);
new->len = strlen(arg);
new->data = opt_malloc(new->len);
memcpy(new->data, arg, new->len);
}
else
new->enterprise = atoi(arg+11);
{
new->len = parse_hex(comma, (unsigned char *)arg, strlen(arg), NULL, NULL);
new->data = opt_malloc(new->len);
memcpy(new->data, arg, new->len);
}
}
else
comma = arg;
for (dig = 0, colon = 0, p = (unsigned char *)comma; *p; p++)
if (isxdigit(*p))
dig = 1;
else if (*p == ':')
colon = 1;
else
break;
unhide_metas(comma);
if (option == 'U' || option == 'j' || *p || !dig || !colon)
else if (option != 'U' || new->enterprise == 0)
{
new->len = strlen(comma);
new->data = opt_malloc(new->len);
memcpy(new->data, comma, new->len);
}
else
{
new->len = parse_hex(comma, (unsigned char *)comma, strlen(comma), NULL, NULL);
new->data = opt_malloc(new->len);
memcpy(new->data, comma, new->len);
free(new->netid.net);
ret_err_free(gen_err, new);
}
switch (option)
@@ -4635,7 +4637,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
new->next = daemon->dhcp_vendors;
daemon->dhcp_vendors = new;
break;
}

View File

@@ -392,13 +392,26 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
if (opt6_len(opt) < 4)
continue;
if (vendor->enterprise != opt6_uint(opt, 0, 4))
if (vendor->enterprise != 0 && vendor->enterprise != opt6_uint(opt, 0, 4))
continue;
/* matching enterprise, no string match. */
if (vendor->enterprise != 0 && vendor->len == 0)
{
vendor->netid.next = state->tags;
state->tags = &vendor->netid;
break;
}
offset = 4;
/* If we're going to search the strings below, there must be at least one empty string to search
I think a vendor_class option with just the enterprise number is valid. */
if (opt6_len(opt) < 6)
continue;
}
/* Note that format if user/vendor classes is different to DHCP options - no option types. */
/* Note that format if user/vendor classes is different to DHCP options - no option types. */
for (enc_opt = opt6_ptr(opt, offset); enc_opt; enc_opt = opt6_user_vendor_next(enc_opt, enc_end))
for (i = 0; i <= (opt6_user_vendor_len(enc_opt) - vendor->len); i++)
if (memcmp(vendor->data, opt6_user_vendor_ptr(enc_opt, i), vendor->len) == 0)