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=