diff options
author | Thomas Haller <thaller@redhat.com> | 2022-04-12 17:16:11 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2022-04-20 12:07:04 +0200 |
commit | 9ff1f666809ad5b773eec826cd07735562e720bf (patch) | |
tree | ae12f4e6841bf4cfb7c0f038b11fe27ee027492c | |
parent | 202d9c36c38eca098bca07483fc0d043e33110fd (diff) | |
download | NetworkManager-9ff1f666809ad5b773eec826cd07735562e720bf.tar.gz |
glib-aux: add nm_hostname_is_valid() helper from systemd
-rw-r--r-- | src/libnm-glib-aux/nm-shared-utils.c | 76 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-shared-utils.h | 4 | ||||
-rw-r--r-- | src/libnm-glib-aux/tests/test-shared-general.c | 50 |
3 files changed, 130 insertions, 0 deletions
diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c index 9446cce80c..0756bad45b 100644 --- a/src/libnm-glib-aux/nm-shared-utils.c +++ b/src/libnm-glib-aux/nm-shared-utils.c @@ -7175,3 +7175,79 @@ nm_path_simplify(char *path) *f = '\0'; return path; } + +/*****************************************************************************/ + +static gboolean +valid_ldh_char(char c) +{ + /* "LDH" → "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */ + + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-'; +} + +/** + * nm_hostname_is_valid: + * @s: the hostname to check. + * @trailing_dot: Accept trailing dot on multi-label names. + * + * Return: %TRUE if valid. + */ +gboolean +nm_hostname_is_valid(const char *s, gboolean trailing_dot) +{ + unsigned n_dots = 0; + const char *p; + gboolean dot; + gboolean hyphen; + + /* Copied from systemd's hostname_is_valid() + * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/hostname-util.c#L85 */ + + /* Check if s looks like a valid hostname or FQDN. This does not do full DNS validation, but only + * checks if the name is composed of allowed characters and the length is not above the maximum + * allowed by Linux (c.f. dns_name_is_valid()). A trailing dot is allowed if + * VALID_HOSTNAME_TRAILING_DOT flag is set and at least two components are present in the name. Note + * that due to the restricted charset and length this call is substantially more conservative than + * dns_name_is_valid(). Doesn't accept empty hostnames, hostnames with leading dots, and hostnames + * with multiple dots in a sequence. Doesn't allow hyphens at the beginning or end of label. */ + + if (nm_str_is_empty(s)) + return FALSE; + + for (p = s, dot = hyphen = TRUE; *p; p++) + if (*p == '.') { + if (dot || hyphen) + return FALSE; + + dot = TRUE; + hyphen = FALSE; + n_dots++; + + } else if (*p == '-') { + if (dot) + return FALSE; + + dot = FALSE; + hyphen = TRUE; + + } else { + if (!valid_ldh_char(*p)) + return FALSE; + + dot = FALSE; + hyphen = FALSE; + } + + if (dot && (n_dots < 2 || !trailing_dot)) + return FALSE; + if (hyphen) + return FALSE; + + /* Note that HOST_NAME_MAX is 64 on Linux, but DNS allows domain names up to + * 255 characters */ + if (p - s > HOST_NAME_MAX) + return FALSE; + + return TRUE; +} diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h index 34936e0a36..14b6302662 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -3346,4 +3346,8 @@ nm_path_startswith(const char *path, const char *prefix) return nm_path_startswith_full(path, prefix, TRUE); } +/*****************************************************************************/ + +gboolean nm_hostname_is_valid(const char *s, gboolean trailing_dot); + #endif /* __NM_SHARED_UTILS_H__ */ diff --git a/src/libnm-glib-aux/tests/test-shared-general.c b/src/libnm-glib-aux/tests/test-shared-general.c index c3fa2559ed..0d588f17b7 100644 --- a/src/libnm-glib-aux/tests/test-shared-general.c +++ b/src/libnm-glib-aux/tests/test-shared-general.c @@ -2101,6 +2101,55 @@ test_path_simplify(void) /*****************************************************************************/ +static void +test_hostname_is_valid(void) +{ + g_assert(nm_hostname_is_valid("foobar", FALSE)); + g_assert(nm_hostname_is_valid("foobar.com", FALSE)); + g_assert(!nm_hostname_is_valid("foobar.com.", FALSE)); + g_assert(nm_hostname_is_valid("fooBAR", FALSE)); + g_assert(nm_hostname_is_valid("fooBAR.com", FALSE)); + g_assert(!nm_hostname_is_valid("fooBAR.", FALSE)); + g_assert(!nm_hostname_is_valid("fooBAR.com.", FALSE)); + g_assert(!nm_hostname_is_valid("fööbar", FALSE)); + g_assert(!nm_hostname_is_valid("", FALSE)); + g_assert(!nm_hostname_is_valid(".", FALSE)); + g_assert(!nm_hostname_is_valid("..", FALSE)); + g_assert(!nm_hostname_is_valid("foobar.", FALSE)); + g_assert(!nm_hostname_is_valid(".foobar", FALSE)); + g_assert(!nm_hostname_is_valid("foo..bar", FALSE)); + g_assert(!nm_hostname_is_valid("foo.bar..", FALSE)); + g_assert( + !nm_hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + FALSE)); + g_assert(!nm_hostname_is_valid( + "au-xph5-rvgrdsb5hcxc-47et3a5vvkrc-server-wyoz4elpdpe3.openstack.local", + FALSE)); + + g_assert(nm_hostname_is_valid("foobar", TRUE)); + g_assert(nm_hostname_is_valid("foobar.com", TRUE)); + g_assert(nm_hostname_is_valid("foobar.com.", TRUE)); + g_assert(nm_hostname_is_valid("fooBAR", TRUE)); + g_assert(nm_hostname_is_valid("fooBAR.com", TRUE)); + g_assert(!nm_hostname_is_valid("fooBAR.", TRUE)); + g_assert(nm_hostname_is_valid("fooBAR.com.", TRUE)); + g_assert(!nm_hostname_is_valid("fööbar", TRUE)); + g_assert(!nm_hostname_is_valid("", TRUE)); + g_assert(!nm_hostname_is_valid(".", TRUE)); + g_assert(!nm_hostname_is_valid("..", TRUE)); + g_assert(!nm_hostname_is_valid("foobar.", TRUE)); + g_assert(!nm_hostname_is_valid(".foobar", TRUE)); + g_assert(!nm_hostname_is_valid("foo..bar", TRUE)); + g_assert(!nm_hostname_is_valid("foo.bar..", TRUE)); + g_assert( + !nm_hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + TRUE)); +} + +/*****************************************************************************/ + NMTST_DEFINE(); int @@ -2144,6 +2193,7 @@ main(int argc, char **argv) g_test_add_func("/general/test_path_find_first_component", test_path_find_first_component); g_test_add_func("/general/test_path_startswith", test_path_startswith); g_test_add_func("/general/test_path_simplify", test_path_simplify); + g_test_add_func("/general/test_hostname_is_valid", test_hostname_is_valid); return g_test_run(); } |