From e4336c0a5df42f4c88ed31c4bad743b93b69718f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 12 Jan 2021 21:47:23 +0900 Subject: [PATCH 1/7] dhcp: length of each user class field must be positive This also fixes an memory leak when sd_dhcp_client_set_user_class() is called multiple times. --- src/libsystemd-network/dhcp-option.c | 10 ++++++---- src/libsystemd-network/sd-dhcp-client.c | 24 ++++++++++++++---------- src/network/networkd-dhcp4.c | 2 +- src/systemd/sd-dhcp-client.h | 2 +- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c index 70753c68d8..7e3fe4348b 100644 --- a/src/libsystemd-network/dhcp-option.c +++ b/src/libsystemd-network/dhcp-option.c @@ -38,11 +38,14 @@ static int option_append(uint8_t options[], size_t size, size_t *offset, size_t total = 0; char **s; + if (strv_isempty((char **) optval)) + return -EINVAL; + STRV_FOREACH(s, (char **) optval) { size_t len = strlen(*s); - if (len > 255) - return -ENAMETOOLONG; + if (len > 255 || len == 0) + return -EINVAL; total += 1 + len; } @@ -51,14 +54,13 @@ static int option_append(uint8_t options[], size_t size, size_t *offset, return -ENOBUFS; options[*offset] = code; - options[*offset + 1] = total; + options[*offset + 1] = total; *offset += 2; STRV_FOREACH(s, (char **) optval) { size_t len = strlen(*s); options[*offset] = len; - memcpy(&options[*offset + 1], *s, len); *offset += 1 + len; } diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 7604aafd6f..5cf3637d68 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -573,22 +573,26 @@ int sd_dhcp_client_set_mud_url( int sd_dhcp_client_set_user_class( sd_dhcp_client *client, - const char* const* user_class) { + char * const *user_class) { - _cleanup_strv_free_ char **s = NULL; - char **p; + char * const *p; + char **s = NULL; - STRV_FOREACH(p, (char **) user_class) - if (strlen(*p) > 255) - return -ENAMETOOLONG; + assert_return(client, -EINVAL); + assert_return(!strv_isempty(user_class), -EINVAL); - s = strv_copy((char **) user_class); + STRV_FOREACH(p, user_class) { + size_t n = strlen(*p); + + if (n > 255 || n == 0) + return -EINVAL; + } + + s = strv_copy(user_class); if (!s) return -ENOMEM; - client->user_class = TAKE_PTR(s); - - return 0; + return strv_free_and_replace(client->user_class, s); } int sd_dhcp_client_set_client_port( diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 080dcedab5..d5c1c507bf 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -1417,7 +1417,7 @@ int dhcp4_configure(Link *link) { } if (link->network->dhcp_user_class) { - r = sd_dhcp_client_set_user_class(link->dhcp_client, (const char **) link->network->dhcp_user_class); + r = sd_dhcp_client_set_user_class(link->dhcp_client, link->network->dhcp_user_class); if (r < 0) return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m"); } diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index c35328a9a6..822286919e 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -181,7 +181,7 @@ int sd_dhcp_client_set_mud_url( const char *mudurl); int sd_dhcp_client_set_user_class( sd_dhcp_client *client, - const char* const *user_class); + char * const *user_class); int sd_dhcp_client_get_lease( sd_dhcp_client *client, sd_dhcp_lease **ret); From b79951fa328f60577082a5710852e1d020d60b65 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 12 Jan 2021 21:55:15 +0900 Subject: [PATCH 2/7] network: refuse zero length dhcp user class --- src/network/networkd-dhcp-common.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index 4dd98a2c61..4826d15e80 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -533,6 +533,7 @@ int config_parse_dhcp_user_class( for (const char *p = rvalue;;) { _cleanup_free_ char *w = NULL; + size_t len; r = extract_first_word(&p, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); if (r == -ENOMEM) @@ -545,25 +546,24 @@ int config_parse_dhcp_user_class( if (r == 0) return 0; + len = strlen(w); if (ltype == AF_INET) { - if (strlen(w) > UINT8_MAX) { + if (len > UINT8_MAX || len == 0) { log_syntax(unit, LOG_WARNING, filename, line, 0, "%s length is not in the range 1-255, ignoring.", w); continue; } } else { - if (strlen(w) > UINT16_MAX) { + if (len > UINT16_MAX || len == 0) { log_syntax(unit, LOG_WARNING, filename, line, 0, "%s length is not in the range 1-65535, ignoring.", w); continue; } } - r = strv_push(l, w); + r = strv_consume(l, TAKE_PTR(w)); if (r < 0) return log_oom(); - - w = NULL; } } From 5a99444e4fe80c2ed416ca402b437e780a9de4b8 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 12 Jan 2021 22:03:43 +0900 Subject: [PATCH 3/7] dhcp6: refuse zero length dhcp user class This also fixes a memory leak when sd_dhcp6_client_set_request_user_class() is called multiple times. --- src/libsystemd-network/dhcp6-internal.h | 2 +- src/libsystemd-network/dhcp6-option.c | 13 ++++++++----- src/libsystemd-network/sd-dhcp6-client.c | 20 ++++++++++---------- src/systemd/sd-dhcp6-client.h | 2 +- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index 24d8a314a4..d02186a4b2 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -99,7 +99,7 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia); int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix); int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn); -int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class); +int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class); int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **user_class); int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedHashmap *vendor_options); int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index e2bf4f7e36..8151e66bca 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -200,19 +200,22 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) { return r; } -int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class) { +int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class) { _cleanup_free_ uint8_t *p = NULL; size_t total = 0, offset = 0; - char **s; + char * const *s; - assert_return(buf && *buf && buflen && user_class, -EINVAL); + assert(buf); + assert(*buf); + assert(buflen); + assert(!strv_isempty(user_class)); STRV_FOREACH(s, user_class) { size_t len = strlen(*s); uint8_t *q; - if (len > 0xffff) - return -ENAMETOOLONG; + if (len > 0xffff || len == 0) + return -EINVAL; q = realloc(p, total + len + 2); if (!q) return -ENOMEM; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index e068e0dc91..105d09f334 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -464,26 +464,26 @@ int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mud return free_and_strdup(&client->mudurl, mudurl); } -int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char **user_class) { - _cleanup_strv_free_ char **s = NULL; - char **p; +int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char * const *user_class) { + char * const *p; + char **s; assert_return(client, -EINVAL); assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); + assert_return(!strv_isempty(user_class), -EINVAL); - assert_return(user_class, -EINVAL); + STRV_FOREACH(p, user_class) { + size_t len = strlen(*p); - STRV_FOREACH(p, user_class) - if (strlen(*p) > UINT16_MAX) - return -ENAMETOOLONG; + if (len > UINT16_MAX || len == 0) + return -EINVAL; + } s = strv_copy(user_class); if (!s) return -ENOMEM; - client->user_class = TAKE_PTR(s); - - return 0; + return strv_free_and_replace(client->user_class, s); } int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char **vendor_class) { diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 75ee27d68b..492e281f8b 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -133,7 +133,7 @@ int sd_dhcp6_client_set_request_mud_url( const char *mudurl); int sd_dhcp6_client_set_request_user_class( sd_dhcp6_client *client, - char** user_class); + char * const *user_class); int sd_dhcp6_client_set_request_vendor_class( sd_dhcp6_client *client, char** vendor_class); From 8b6ea477a75b104ef17392552ea36a5955303f74 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 12 Jan 2021 22:23:53 +0900 Subject: [PATCH 4/7] dhcp: do not assign value twice --- src/libsystemd-network/sd-dhcp-client.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 5cf3637d68..ad0eeda5a2 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -274,7 +274,6 @@ int sd_dhcp_client_set_request_address( } int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) { - assert_return(client, -EINVAL); assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); assert_return(ifindex > 0, -EINVAL); @@ -348,13 +347,14 @@ int sd_dhcp_client_get_client_id( assert_return(data, -EINVAL); assert_return(data_len, -EINVAL); - *type = 0; - *data = NULL; - *data_len = 0; if (client->client_id_len) { *type = client->client_id.type; *data = client->client_id.raw.data; *data_len = client->client_id_len - sizeof(client->client_id.type); + } else { + *type = 0; + *data = NULL; + *data_len = 0; } return 0; From 361eb4125d2d7679c71fba157d70d75221970715 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 12 Jan 2021 22:28:36 +0900 Subject: [PATCH 5/7] dhcp6: add an assert() --- src/libsystemd-network/sd-dhcp6-client.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 105d09f334..687661cd5e 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -157,7 +157,6 @@ int sd_dhcp6_client_set_callback( } int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) { - assert_return(client, -EINVAL); assert_return(ifindex > 0, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); @@ -351,6 +350,7 @@ int sd_dhcp6_client_duid_as_string( assert_return(client, -EINVAL); assert_return(client->duid_len > 0, -ENODATA); + assert_return(duid, -EINVAL); v = dhcp6_duid_type_to_string(be16toh(client->duid.type)); if (v) { @@ -454,7 +454,6 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) } int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mudurl) { - assert_return(client, -EINVAL); assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); assert_return(mudurl, -EINVAL); From 019951ec97a98775063271e5f36096ac3ba0b510 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 12 Jan 2021 22:38:29 +0900 Subject: [PATCH 6/7] dhcp6: refuse zero length vendor class Also, fixes the maximum length of the vendor class to UINT16_MAX. Moreover, a memory leak in sd_dhcp6_client_set_request_vendor_class(). --- src/libsystemd-network/dhcp6-internal.h | 2 +- src/libsystemd-network/dhcp6-option.c | 9 ++++++--- src/libsystemd-network/sd-dhcp6-client.c | 21 +++++++++++---------- src/systemd/sd-dhcp6-client.h | 2 +- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index d02186a4b2..9a32b007fc 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -100,7 +100,7 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia); int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix); int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn); int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class); -int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **user_class); +int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const *user_class); int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedHashmap *vendor_options); int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen, uint8_t **optvalue); diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 8151e66bca..9f47c1bbe4 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -232,16 +232,16 @@ int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const * return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_USER_CLASS, total, p); } -int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **vendor_class) { +int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const *vendor_class) { _cleanup_free_ uint8_t *p = NULL; uint32_t enterprise_identifier; size_t total, offset; - char **s; + char * const *s; assert(buf); assert(*buf); assert(buflen); - assert(vendor_class); + assert(!strv_isempty(vendor_class)); enterprise_identifier = htobe32(SYSTEMD_PEN); @@ -256,6 +256,9 @@ int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **vendo size_t len = strlen(*s); uint8_t *q; + if (len > UINT16_MAX || len == 0) + return -EINVAL; + q = realloc(p, total + len + 2); if (!q) return -ENOMEM; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 687661cd5e..788f2e1d42 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -485,25 +485,26 @@ int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char * const return strv_free_and_replace(client->user_class, s); } -int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char **vendor_class) { - _cleanup_strv_free_ char **s = NULL; - char **p; +int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char * const *vendor_class) { + char * const *p; + char **s; assert_return(client, -EINVAL); assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); - assert_return(vendor_class, -EINVAL); + assert_return(!strv_isempty(vendor_class), -EINVAL); - STRV_FOREACH(p, vendor_class) - if (strlen(*p) > UINT8_MAX) - return -ENAMETOOLONG; + STRV_FOREACH(p, vendor_class) { + size_t len = strlen(*p); + + if (len > UINT16_MAX || len == 0) + return -EINVAL; + } s = strv_copy(vendor_class); if (!s) return -ENOMEM; - client->vendor_class = TAKE_PTR(s); - - return 0; + return strv_free_and_replace(client->vendor_class, s); } int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) { diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 492e281f8b..84e3170130 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -136,7 +136,7 @@ int sd_dhcp6_client_set_request_user_class( char * const *user_class); int sd_dhcp6_client_set_request_vendor_class( sd_dhcp6_client *client, - char** vendor_class); + char * const *vendor_class); int sd_dhcp6_client_set_prefix_delegation_hint( sd_dhcp6_client *client, uint8_t prefixlen, From 6fda02e1507333104b14a82f0cd80907bcc28d26 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 12 Jan 2021 22:48:47 +0900 Subject: [PATCH 7/7] network: merge config_parse_dhcp_user_class() and _vendor_class() --- src/network/networkd-dhcp-common.c | 54 +----------------------- src/network/networkd-dhcp-common.h | 3 +- src/network/networkd-network-gperf.gperf | 8 ++-- 3 files changed, 7 insertions(+), 58 deletions(-) diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index 4826d15e80..0d1dc2e8ed 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -507,7 +507,7 @@ int config_parse_iaid(const char *unit, return 0; } -int config_parse_dhcp_user_class( +int config_parse_dhcp_user_or_vendor_class( const char *unit, const char *filename, unsigned line, @@ -525,6 +525,7 @@ int config_parse_dhcp_user_class( assert(l); assert(lvalue); assert(rvalue); + assert(IN_SET(ltype, AF_INET, AF_INET6)); if (isempty(rvalue)) { *l = strv_free(*l); @@ -567,57 +568,6 @@ int config_parse_dhcp_user_class( } } -int config_parse_dhcp_vendor_class( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - char ***l = data; - int r; - - assert(l); - assert(lvalue); - assert(rvalue); - - if (isempty(rvalue)) { - *l = strv_free(*l); - return 0; - } - - for (const char *p = rvalue;;) { - _cleanup_free_ char *w = NULL; - - r = extract_first_word(&p, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to split vendor classes option, ignoring: %s", rvalue); - return 0; - } - if (r == 0) - return 0; - - if (strlen(w) > UINT8_MAX) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "%s length is not in the range 1-255, ignoring.", w); - continue; - } - - r = strv_push(l, w); - if (r < 0) - return log_oom(); - - w = NULL; - } -} - int config_parse_dhcp_send_option( const char *unit, const char *filename, diff --git a/src/network/networkd-dhcp-common.h b/src/network/networkd-dhcp-common.h index 78c149ebcc..aa100d0de4 100644 --- a/src/network/networkd-dhcp-common.h +++ b/src/network/networkd-dhcp-common.h @@ -66,7 +66,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_domains); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_ntp); CONFIG_PARSER_PROTOTYPE(config_parse_iaid); CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table); -CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class); -CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_vendor_class); +CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_or_vendor_class); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_option); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index afa97a6da4..00ba043b23 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -204,7 +204,7 @@ DHCPv4.RequestBroadcast, config_parse_bool, DHCPv4.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) DHCPv4.MUDURL, config_parse_dhcp_mud_url, 0, 0 DHCPv4.MaxAttempts, config_parse_dhcp_max_attempts, 0, 0 -DHCPv4.UserClass, config_parse_dhcp_user_class, AF_INET, offsetof(Network, dhcp_user_class) +DHCPv4.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET, offsetof(Network, dhcp_user_class) DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid) DHCPv4.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid) DHCPv4.RouteMetric, config_parse_dhcp_route_metric, 0, 0 @@ -227,8 +227,8 @@ DHCPv6.UseNTP, config_parse_dhcp_use_ntp, DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, dhcp6_rapid_commit) DHCPv6.MUDURL, config_parse_dhcp6_mud_url, 0, 0 DHCPv6.RequestOptions, config_parse_dhcp_request_options, AF_INET6, 0 -DHCPv6.UserClass, config_parse_dhcp_user_class, AF_INET6, offsetof(Network, dhcp6_user_class) -DHCPv6.VendorClass, config_parse_dhcp_vendor_class, 0, offsetof(Network, dhcp6_vendor_class) +DHCPv6.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_user_class) +DHCPv6.VendorClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_vendor_class) DHCPv6.SendVendorOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_vendor_options) DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information) DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0 @@ -467,7 +467,7 @@ DHCP.Hostname, config_parse_hostname, DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) DHCP.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical) DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) -DHCP.UserClass, config_parse_dhcp_user_class, AF_INET, offsetof(Network, dhcp_user_class) +DHCP.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET, offsetof(Network, dhcp_user_class) DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid) DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid) DHCP.RouteMetric, config_parse_dhcp_route_metric, 0, 0