diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 19b49702f3..6e5a2702ba 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1788,6 +1788,17 @@ currently NUL bytes are not allowed. + + + VendorClass= + + A DHCPv6 client can use VendorClass option to identify the vendor that + manufactured the hardware on which the client is running. The information + contained in the data area of this option is contained in one or more opaque + fields that identify details of the hardware configuration. Takes a + whitespace-separated list of strings. + + diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index ce9e6cae7e..f1b210c54c 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -381,7 +381,7 @@ int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mud assert_return(client, -EINVAL); assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); assert_return(mudurl, -EINVAL); - assert_return(strlen(mudurl) <= UINT8_MAX, -EINVAL); + assert_return(strlen(mudurl) <= 255, -EINVAL); assert_return(http_url_is_valid(mudurl), -EINVAL); return free_and_strdup(&client->mudurl, mudurl); diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index 9ab0187d2d..55191849d8 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -329,6 +329,59 @@ int config_parse_dhcp_user_class( return 0; } +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 (;;) { + _cleanup_free_ char *w = NULL; + + r = extract_first_word(&rvalue, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to split vendor classes option, ignoring: %s", rvalue); + break; + } + if (r == 0) + break; + + if (strlen(w) > UINT8_MAX) { + log_syntax(unit, LOG_ERR, 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; + } + + return 0; +} + int config_parse_dhcp6_mud_url( const char *unit, const char *filename, diff --git a/src/network/networkd-dhcp-common.h b/src/network/networkd-dhcp-common.h index bf8bc2bf67..d837f89c25 100644 --- a/src/network/networkd-dhcp-common.h +++ b/src/network/networkd-dhcp-common.h @@ -51,5 +51,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class); +CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_vendor_class); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_option); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index a33f22880b..29226b64bf 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -712,6 +712,12 @@ int dhcp6_configure(Link *link) { return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set user class: %m"); } + if (link->network->dhcp6_vendor_class) { + r = sd_dhcp6_client_set_request_vendor_class(client, link->network->dhcp6_vendor_class); + if (r < 0) + return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor class: %m"); + } + r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link); if (r < 0) return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set callback: %m"); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 798781cfe4..28bb705190 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -195,6 +195,7 @@ DHCPv6.RapidCommit, config_parse_bool, 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.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information) DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0 DHCPv6.WithoutRA, config_parse_bool, 0, offsetof(Network, dhcp6_without_ra) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 1c2100d89f..cd57df6d3d 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -654,6 +654,7 @@ static Network *network_free(Network *network) { free(network->mac); free(network->dhcp6_mudurl); strv_free(network->dhcp6_user_class); + strv_free(network->dhcp6_vendor_class); if (network->dhcp_acd) sd_ipv4acd_unref(network->dhcp_acd); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 8a6de4df01..82810bcce1 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -133,6 +133,7 @@ struct Network { uint8_t dhcp6_pd_length; char *dhcp6_mudurl; char **dhcp6_user_class; + char **dhcp6_vendor_class; struct in6_addr dhcp6_pd_address; OrderedHashmap *dhcp6_client_send_options; Set *dhcp6_request_options; diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 9ce0fc3f99..918fb3ac8a 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -116,6 +116,7 @@ MUDURL= SendOption= RequestOptions= UserClass= +VendorClass= [Route] Destination= Protocol=