summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-04-12 17:16:11 +0200
committerThomas Haller <thaller@redhat.com>2022-04-20 12:07:04 +0200
commit9ff1f666809ad5b773eec826cd07735562e720bf (patch)
treeae12f4e6841bf4cfb7c0f038b11fe27ee027492c
parent202d9c36c38eca098bca07483fc0d043e33110fd (diff)
downloadNetworkManager-9ff1f666809ad5b773eec826cd07735562e720bf.tar.gz
glib-aux: add nm_hostname_is_valid() helper from systemd
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.c76
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.h4
-rw-r--r--src/libnm-glib-aux/tests/test-shared-general.c50
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();
}