]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
networkd/dhcp: shorten overlong hostname (#7616)
authorLuca Bruno <luca.bruno@coreos.com>
Wed, 13 Dec 2017 17:00:46 +0000 (17:00 +0000)
committerLennart Poettering <lennart@poettering.net>
Wed, 13 Dec 2017 17:00:46 +0000 (18:00 +0100)
This commit updates networkd behavior to check if the hostname option
received via DHCP is too long for Linux limit, and in case shorten it.
An overlong hostname will be truncated to the first dot or to
`HOST_MAX_LEN`, whatever comes earlier.

src/basic/hostname-util.c
src/basic/hostname-util.h
src/network/networkd-dhcp4.c
src/network/test-network.c

index 12a579b38ac0432785d1148448c84e3978dd066c..b59e5425a5d381e401d2fbe3d1e716c9fc50f7ad 100644 (file)
@@ -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;
 
index 52fd6b0899b5f5581b8c9aa135c0d9f7296c63e0..d837d6f28c5dd061ff1cdce08f1c7e679caf8ddf 100644 (file)
@@ -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);
index ac1781d83ee432f7b95e718637185050696dc496..0b46deb00936577339f8a94922d46ea19518cf50 100644 (file)
@@ -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);
index a6b273a29063dc15953d87b18bc9f6e810c397a1..f3e8f508f3bb636c8f8600f21035962d05f2002f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <sys/param.h>
+
 #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);