diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 5457e668dd2..201e33ed6e0 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -1691,6 +1691,16 @@
+
+ MUDURL=
+
+ When configured, the Manufacturer Usage Descriptions (MUD) URL will be sent to the DHCPV6 server.
+ Takes an URL of length up to 255 characters. A superficial verification that the string is a valid URL
+ will be performed. DHCPv6 clients are intended to have at most one MUD URL associated with them. See
+ RFC 8520.
+
+
+
ForceDHCPv6PDOtherInformation=
diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c
index 8664d8cdc0d..0473aba6159 100644
--- a/src/network/networkd-dhcp-common.c
+++ b/src/network/networkd-dhcp-common.c
@@ -8,6 +8,7 @@
#include "parse-util.h"
#include "string-table.h"
#include "strv.h"
+#include "web-util.h"
int config_parse_dhcp(
const char* unit,
@@ -265,6 +266,48 @@ int config_parse_dhcp6_pd_hint(
return 0;
}
+int config_parse_dhcp6_mud_url(
+ 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) {
+
+ _cleanup_free_ char *unescaped = NULL;
+ Network *network = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ network->dhcp6_mudurl = mfree(network->dhcp6_mudurl);
+ return 0;
+ }
+
+ r = cunescape(rvalue, 0, &unescaped);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Failed to parse MUD URL '%s', ignoring: %m", rvalue);
+
+ return 0;
+ }
+
+ return free_and_replace(network->dhcp6_mudurl, unescaped);
+}
+
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 1d6ddbb8cc0..ca86016ef2a 100644
--- a/src/network/networkd-dhcp-common.h
+++ b/src/network/networkd-dhcp-common.h
@@ -48,4 +48,5 @@ CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_sip);
CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
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);
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 7304270c60b..3580498e351 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -676,6 +676,12 @@ int dhcp6_configure(Link *link) {
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for rapid commit: %m");
}
+ if (link->network->dhcp6_mudurl) {
+ r = sd_dhcp6_client_set_request_mud_url(client, link->network->dhcp6_mudurl);
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MUD URL: %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 fd996327a55..d98b32b7568 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -189,6 +189,7 @@ DHCPv4.RouteMTUBytes, config_parse_mtu,
DHCPv6.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp6_use_dns)
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.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 e7ead446c76..46a5a5320a0 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -644,6 +644,7 @@ static Network *network_free(Network *network) {
set_free(network->dhcp_black_listed_ip);
set_free(network->dhcp_request_options);
free(network->mac);
+ free(network->dhcp6_mudurl);
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 f747ccaf101..3b48e4238dc 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -130,6 +130,7 @@ struct Network {
bool dhcp6_use_ntp;
bool dhcp6_without_ra;
uint8_t dhcp6_pd_length;
+ char *dhcp6_mudurl;
struct in6_addr dhcp6_pd_address;
/* DHCP Server Support */
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index 4418fc01495..76a4c42403c 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -110,6 +110,7 @@ RapidCommit=
ForceDHCPv6PDOtherInformation=
PrefixDelegationHint=
WithoutRA=
+MUDURL=
[Route]
Destination=
Protocol=