From ed0d1b2e99942a7082e87eb5fcb0f615f0349564 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Sun, 17 May 2020 17:14:47 +0200 Subject: [PATCH] network: DHCPv6 - Add support to send vendor class information Frame 1: 177 bytes on wire (1416 bits), 177 bytes captured (1416 bits) on interface veth-peer, id 0 Ethernet II, Src: 1e:04:f8:b8:2f:d4 (1e:04:f8:b8:2f:d4), Dst: IPv6mcast_01:00:02 (33:33:00:01:00:02) Internet Protocol Version 6, Src: fe80::1c04:f8ff:feb8:2fd4, Dst: ff02::1:2 User Datagram Protocol, Src Port: 546, Dst Port: 547 DHCPv6 Message type: Solicit (1) Transaction ID: 0x5ca46b Rapid Commit Identity Association for Non-temporary Address Fully Qualified Domain Name Vendor Class Option: Vendor Class (16) Length: 23 Value: 0000ab11000048656c6c6f3a686f773a6172653a796f75 Enterprise ID: Tom Gundersen (systemd) (43793) vendor-class-data: Hello:how:are:you Identity Association for Prefix Delegation Option Request Client Identifier Elapsed time --- man/systemd.network.xml | 11 ++++ src/libsystemd-network/sd-dhcp6-client.c | 2 +- src/network/networkd-dhcp-common.c | 53 +++++++++++++++++++ src/network/networkd-dhcp-common.h | 1 + src/network/networkd-dhcp6.c | 6 +++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.c | 1 + src/network/networkd-network.h | 1 + .../fuzz-network-parser/directives.network | 1 + 9 files changed, 76 insertions(+), 1 deletion(-) 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=