diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 12a579b38a..b59e5425a5 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -221,6 +221,38 @@ int sethostname_idempotent(const char *s) { return 1; } +int shorten_overlong(const char *s, char **ret) { + char *h, *p; + + /* Shorten an overlong name to HOST_NAME_MAX or to the first dot, + * whatever comes earlier. */ + + assert(s); + + h = strdup(s); + if (!h) + return -ENOMEM; + + if (hostname_is_valid(h, false)) { + *ret = h; + return 0; + } + + p = strchr(h, '.'); + if (p) + *p = 0; + + strshorten(h, HOST_NAME_MAX); + + if (!hostname_is_valid(h, false)) { + free(h); + return -EDOM; + } + + *ret = h; + return 1; +} + int read_etc_hostname_stream(FILE *f, char **ret) { int r; diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h index 52fd6b0899..d837d6f28c 100644 --- a/src/basic/hostname-util.h +++ b/src/basic/hostname-util.h @@ -39,5 +39,7 @@ bool is_gateway_hostname(const char *hostname); int sethostname_idempotent(const char *s); +int shorten_overlong(const char *s, char **ret); + int read_etc_hostname_stream(FILE *f, char **ret); int read_etc_hostname(const char *path, char **ret); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index ac1781d83e..0b46deb009 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -462,12 +462,21 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { } if (link->network->dhcp_use_hostname) { - const char *hostname = NULL; + const char *dhcpname = NULL; + _cleanup_free_ char *hostname = NULL; if (link->network->dhcp_hostname) - hostname = link->network->dhcp_hostname; + dhcpname = link->network->dhcp_hostname; else - (void) sd_dhcp_lease_get_hostname(lease, &hostname); + (void) sd_dhcp_lease_get_hostname(lease, &dhcpname); + + if (dhcpname) { + r = shorten_overlong(dhcpname, &hostname); + if (r < 0) + log_link_warning_errno(link, r, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname); + if (r == 1) + log_link_notice(link, "Overlong DCHP hostname received, shortened from '%s' to '%s'", dhcpname, hostname); + } if (hostname) { r = manager_set_hostname(link->manager, hostname); diff --git a/src/network/test-network.c b/src/network/test-network.c index a6b273a290..f3e8f508f3 100644 --- a/src/network/test-network.c +++ b/src/network/test-network.c @@ -18,10 +18,14 @@ along with systemd; If not, see . ***/ +#include + #include "alloc-util.h" #include "dhcp-lease-internal.h" +#include "hostname-util.h" #include "network-internal.h" #include "networkd-manager.h" +#include "string-util.h" #include "udev-util.h" static void test_deserialize_in_addr(void) { @@ -186,6 +190,51 @@ static void test_address_equality(void) { assert_se(!address_equal(a1, a2)); } +static void test_dhcp_hostname_shorten_overlong(void) { + int r; + + { + /* simple hostname, no actions, no errors */ + _cleanup_free_ char *shortened = NULL; + r = shorten_overlong("name1", &shortened); + assert_se(r == 0); + assert_se(streq("name1", shortened)); + } + + { + /* simple fqdn, no actions, no errors */ + _cleanup_free_ char *shortened = NULL; + r = shorten_overlong("name1.example.com", &shortened); + assert_se(r == 0); + assert_se(streq("name1.example.com", shortened)); + } + + { + /* overlong fqdn, cut to first dot, no errors */ + _cleanup_free_ char *shortened = NULL; + r = shorten_overlong("name1.test-dhcp-this-one-here-is-a-very-very-long-domain.example.com", &shortened); + assert_se(r == 1); + assert_se(streq("name1", shortened)); + } + + { + /* overlong hostname, cut to HOST_MAX_LEN, no errors */ + _cleanup_free_ char *shortened = NULL; + r = shorten_overlong("test-dhcp-this-one-here-is-a-very-very-long-hostname-without-domainname", &shortened); + assert_se(r == 1); + assert_se(streq("test-dhcp-this-one-here-is-a-very-very-long-hostname-without-dom", shortened)); + } + + { + /* overlong fqdn, cut to first dot, empty result error */ + _cleanup_free_ char *shortened = NULL; + r = shorten_overlong(".test-dhcp-this-one-here-is-a-very-very-long-hostname.example.com", &shortened); + assert_se(r == -EDOM); + assert_se(shortened == NULL); + } + +} + int main(void) { _cleanup_manager_free_ Manager *manager = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL; @@ -196,6 +245,7 @@ int main(void) { test_deserialize_in_addr(); test_deserialize_dhcp_routes(); test_address_equality(); + test_dhcp_hostname_shorten_overlong(); assert_se(sd_event_default(&event) >= 0);