diff --git a/man/systemd.network.xml b/man/systemd.network.xml index d891873c7e..e6d005400b 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1652,7 +1652,8 @@ RequestOptions= - A whitespace-separated list of integers in the range 1–254. + When configured, allows to set arbitrary request options in the DHCPv4 request options list and will be + sent to the DHCPV4 server. A whitespace-separated list of integers in the range 1..254. Defaults to unset. @@ -1725,6 +1726,14 @@ + + RequestOptions= + + When configured, allows to set arbitrary request options in the DHCPv6 request options list and will + sent to the DHCPV6 server. A whitespace-separated list of integers in the range 1..254. Defaults to unset. + + + ForceDHCPv6PDOtherInformation= @@ -1746,7 +1755,7 @@ Takes an IPv6 address with prefix length as Address= in the "[Network]" section. Specifies the DHCPv6 client for the requesting router to include - a prefix-hint in the DHCPv6 solicitation. Prefix ranges 1-128. Defaults to unset. + a prefix-hint in the DHCPv6 solicitation. Prefix ranges 1..128. Defaults to unset. diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index e94de0cfe0..ae1c4493c7 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -519,6 +519,82 @@ int config_parse_dhcp_send_option( return 0; } +int config_parse_dhcp_request_options( + 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) { + + Network *network = data; + const char *p; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + if (ltype == AF_INET) + network->dhcp_request_options = set_free(network->dhcp_request_options); + else + network->dhcp6_request_options = set_free(network->dhcp6_request_options); + + return 0; + } + + for (p = rvalue;;) { + _cleanup_free_ char *n = NULL; + uint32_t i; + + r = extract_first_word(&p, &n, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse DHCP request option, ignoring assignment: %s", + rvalue); + return 0; + } + if (r == 0) + return 0; + + r = safe_atou32(n, &i); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "DHCP request option is invalid, ignoring assignment: %s", n); + continue; + } + + if (i < 1 || i >= 255) { + log_syntax(unit, LOG_ERR, filename, line, r, + "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n); + continue; + } + + if (ltype == AF_INET) + r = set_ensure_allocated(&network->dhcp_request_options, NULL); + else + r = set_ensure_allocated(&network->dhcp6_request_options, NULL); + if (r < 0) + return log_oom(); + + if (ltype == AF_INET) + r = set_put(network->dhcp_request_options, UINT32_TO_PTR(i)); + else + r = set_put(network->dhcp6_request_options, UINT32_TO_PTR(i)); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to store DHCP request option '%s', ignoring assignment: %m", n); + } + + return 0; +} + DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting"); diff --git a/src/network/networkd-dhcp-common.h b/src/network/networkd-dhcp-common.h index 0511413a51..efadcebe21 100644 --- a/src/network/networkd-dhcp-common.h +++ b/src/network/networkd-dhcp-common.h @@ -51,3 +51,4 @@ 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_send_option); +CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index ada14ecd18..7d52a3a6a1 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -1659,72 +1659,6 @@ int config_parse_dhcp_user_class( return 0; } -int config_parse_dhcp_request_options( - 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) { - - Network *network = data; - const char *p; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (isempty(rvalue)) { - network->dhcp_request_options = set_free(network->dhcp_request_options); - return 0; - } - - for (p = rvalue;;) { - _cleanup_free_ char *n = NULL; - uint32_t i; - - r = extract_first_word(&p, &n, NULL, 0); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Failed to parse DHCP request option, ignoring assignment: %s", - rvalue); - return 0; - } - if (r == 0) - return 0; - - r = safe_atou32(n, &i); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "DHCP request option is invalid, ignoring assignment: %s", n); - continue; - } - - if (i < 1 || i >= 255) { - log_syntax(unit, LOG_ERR, filename, line, r, - "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n); - continue; - } - - r = set_ensure_allocated(&network->dhcp_request_options, NULL); - if (r < 0) - return log_oom(); - - r = set_put(network->dhcp_request_options, UINT32_TO_PTR(i)); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, r, - "Failed to store DHCP request option '%s', ignoring assignment: %m", n); - } - - return 0; -} - int config_parse_dhcp_ip_service_type( const char *unit, const char *filename, diff --git a/src/network/networkd-dhcp4.h b/src/network/networkd-dhcp4.h index b0c30b598c..78e10d9299 100644 --- a/src/network/networkd-dhcp4.h +++ b/src/network/networkd-dhcp4.h @@ -26,6 +26,5 @@ CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_black_listed_ip_address); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class); -CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_ip_service_type); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_mud_url); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 78c99e95bb..05df41cd3a 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -621,6 +621,7 @@ static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) { int dhcp6_configure(Link *link) { _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; sd_dhcp6_option *send_option; + void *request_options; const DUID *duid; Iterator i; int r; @@ -692,6 +693,19 @@ int dhcp6_configure(Link *link) { return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MUD URL: %m"); } + SET_FOREACH(request_options, link->network->dhcp6_request_options, i) { + uint32_t option = PTR_TO_UINT32(request_options); + + r = sd_dhcp6_client_set_request_option(client, option); + if (r == -EEXIST) { + log_link_debug(link, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option); + continue; + } + + if (r < 0) + return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option); + } + 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 d709633df3..711bec7588 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -166,7 +166,7 @@ DHCPv4.UseHostname, config_parse_bool, DHCPv4.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains) DHCPv4.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_use_routes) DHCPv4.UseGateway, config_parse_tristate, 0, offsetof(Network, dhcp_use_gateway) -DHCPv4.RequestOptions, config_parse_dhcp_request_options, 0, 0 +DHCPv4.RequestOptions, config_parse_dhcp_request_options, AF_INET, 0 DHCPv4.Anonymize, config_parse_bool, 0, offsetof(Network, dhcp_anonymize) DHCPv4.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname) DHCPv4.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname) @@ -193,6 +193,7 @@ DHCPv6.UseDNS, config_parse_bool, DHCPv6.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp6_use_ntp) DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit) DHCPv6.MUDURL, config_parse_dhcp6_mud_url, 0, 0 +DHCPv6.RequestOptions, config_parse_dhcp_request_options, AF_INET6, 0 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 4ba46d28e3..a15f884ab0 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -650,6 +650,7 @@ static Network *network_free(Network *network) { free(network->dhcp_hostname); set_free(network->dhcp_black_listed_ip); set_free(network->dhcp_request_options); + set_free(network->dhcp6_request_options); free(network->mac); free(network->dhcp6_mudurl); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 092e58d42c..019bd7676b 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -134,6 +134,7 @@ struct Network { char *dhcp6_mudurl; struct in6_addr dhcp6_pd_address; OrderedHashmap *dhcp6_client_send_options; + Set *dhcp6_request_options; /* DHCP Server Support */ bool dhcp_server; diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 82399f7b1a..743ab903ea 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -114,6 +114,7 @@ PrefixDelegationHint= WithoutRA= MUDURL= SendOption= +RequestOptions= [Route] Destination= Protocol=