diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 2ead483519..bb6c35f9ba 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1430,6 +1430,18 @@ sent even if this is set to true. + + + MUDURL= + + When configured, the Manufacturer Usage Descriptions (MUD) URL will be sent to the + DHCPv4 server. Takes an URL of length up to 255 characters. A superficial verification that + the string is a valid URL will be performed. DHCPv4 clients are intended to have at most one + MUD URL associated with them. See + RFC 8520. + + + UseHostname= diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 83fb25264a..48e5c15fd0 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -5,6 +5,7 @@ #include #include +#include "escape.h" #include "alloc-util.h" #include "dhcp-client-internal.h" #include "hostname-util.h" @@ -17,6 +18,7 @@ #include "string-table.h" #include "string-util.h" #include "sysctl-util.h" +#include "web-util.h" static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all); static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all); @@ -1456,6 +1458,13 @@ int dhcp4_configure(Link *link) { return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set vendor class identifier: %m"); } + if (link->network->dhcp_mudurl) { + r = sd_dhcp_client_set_mud_url(link->dhcp_client, + link->network->dhcp_mudurl); + if (r < 0) + return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set MUD URL: %m"); + } + if (link->network->dhcp_user_class) { r = sd_dhcp_client_set_user_class(link->dhcp_client, (const char **) link->network->dhcp_user_class); if (r < 0) @@ -1744,6 +1753,48 @@ int config_parse_dhcp_ip_service_type( return 0; } +int config_parse_dhcp_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->dhcp_mudurl = mfree(network->dhcp_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_strdup_warn(&network->dhcp_mudurl, unescaped); +} + static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = { [DHCP_CLIENT_ID_MAC] = "mac", [DHCP_CLIENT_ID_DUID] = "duid", diff --git a/src/network/networkd-dhcp4.h b/src/network/networkd-dhcp4.h index 95fa5ee4b5..b0c30b598c 100644 --- a/src/network/networkd-dhcp4.h +++ b/src/network/networkd-dhcp4.h @@ -28,3 +28,4 @@ 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-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 04d411c4ad..18ba23bfc8 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -170,6 +170,7 @@ DHCPv4.SendHostname, config_parse_bool, DHCPv4.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname) DHCPv4.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) DHCPv4.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) +DHCPv4.MUDURL, config_parse_dhcp_mud_url, 0, 0 DHCPv4.MaxAttempts, config_parse_dhcp_max_attempts, 0, 0 DHCPv4.UserClass, config_parse_dhcp_user_class, 0, offsetof(Network, dhcp_user_class) DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index a71fac6790..6afe29d53b 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -640,6 +640,7 @@ static Network *network_free(Network *network) { free(network->description); free(network->dhcp_vendor_class_identifier); + free(network->dhcp_mudurl); strv_free(network->dhcp_user_class); free(network->dhcp_hostname); set_free(network->dhcp_black_listed_ip); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index fe28789784..66ee01d7f3 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -91,6 +91,7 @@ struct Network { AddressFamily dhcp; DHCPClientIdentifier dhcp_client_identifier; char *dhcp_vendor_class_identifier; + char *dhcp_mudurl; char **dhcp_user_class; char *dhcp_hostname; uint64_t dhcp_max_attempts; diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index e1af206941..01b1b50ff6 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -102,6 +102,7 @@ IPServiceType= SendOption= SendVendorOption= SendDecline= +MUDURL= RouteMTUBytes= [DHCPv6] UseNTP=