]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: connection - Add connection_is_valid_dns_name()
authorAki Tuomi <aki.tuomi@open-xchange.com>
Mon, 17 Apr 2023 05:12:39 +0000 (08:12 +0300)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 20 Nov 2023 12:21:55 +0000 (14:21 +0200)
Checks that given name is valid DNS servername, including
characters _ and RFC5891 section 4.2.1 specified ones.

src/lib/connection.c
src/lib/connection.h
src/lib/test-connection.c

index 1897b6e300a720564fafdf291153936e9d7c5fae..41307e2c13564b747dcb7592bea79d375928b85a 100644 (file)
@@ -1011,3 +1011,21 @@ void connection_list_deinit(struct connection_list **_list)
        }
        i_free(list);
 }
+
+bool connection_is_valid_dns_name(const char *name)
+{
+       const char *p = name;
+       if (*name == '\0')
+               return FALSE;
+       if (strstr(name, "..") != NULL)
+               return FALSE;
+       for (; *p != '\0'; p++) {
+               if ((*p < '0' || *p > '9') &&
+                   (*p < 'A' || *p > 'Z') &&
+                   (*p < 'a' || *p > 'z') &&
+                   *p != '.' && *p != '-' &&
+                   *p != '_' && *p != ':')
+                       return FALSE;
+       }
+       return p - name < 256; /* maximum length is 255 by RFC 952 */
+}
index 8318dbf83c4ebe09c84cf8a518f7b2af6cb5bdf5..7a0bc104823dfe54c460a94e94d56cd06ba8ed8f 100644 (file)
@@ -275,4 +275,10 @@ int connection_input_line_default(struct connection *conn, const char *line);
 void connection_set_handlers(struct connection *conn, const struct connection_vfuncs *vfuncs);
 void connection_set_default_handlers(struct connection *conn);
 
+/* Checks if the given name is a valid DNS servername as per RFC1123 section 1.2,
+   RFC8591 section 4.2.1 and for practicality, the '_' character.
+   IP address like values are also accepted.
+*/
+bool connection_is_valid_dns_name(const char *name);
+
 #endif
index feb1f9ceeaca84e70c94d6c00fd8bf5ad2151d8c..b30dc6b40e8a21611e1d110c5b66b555a70e2ac3 100644 (file)
@@ -725,6 +725,60 @@ static void test_connection_no_version(void)
 
 /* END NO VERSION TEST */
 
+static void test_connection_is_valid_dns_name(void)
+{
+       test_begin("connection is valid DNS name");
+
+       struct test_case {
+               const char *input;
+               bool valid;
+       } test_cases[] = {
+               { "", FALSE }, /* empty string is not valid */
+               { "valid.hostname", TRUE },
+               { "xn--land-poa.island", TRUE },
+               { "dns_server.name", TRUE },
+               { "127.0.0.1", TRUE },
+               { "fe80::1", TRUE },
+               { "hello world domain", FALSE }, /* spaces are not valid */
+               { "hello\tworld\tdomain", FALSE }, /* tabs are not valid */
+               { "hello,world,domain", FALSE }, /* commas are not valid */
+               { "hello..world..domain", FALSE }, /* double-dot is not valid */
+               { "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+                 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+                 "xxxxxxx.yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
+                 "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
+                 "yyyyyyyyyyyyyyy", TRUE }, /* 255 bytes long */
+               { "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+                 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+                 "xxxxxxxx.yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
+                 "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
+                 "yyyyyyyyyyyyyyyy", FALSE }, /* 256 bytes long */
+       };
+
+       /* first, ensure everything not allowed is rejected as first byte. */
+       for (int c = 0; c <= UCHAR_MAX; c++) T_BEGIN {
+               bool valid = TRUE;
+               /* is it valid? */
+               if ((c < '0' || c > '9') &&
+                   (c < 'A' || c > 'Z') &&
+                   (c < 'a' || c > 'z') &&
+                   c != '.' && c != '-' &&
+                   c != '_' && c != ':')
+                       valid = FALSE;
+
+               const char *name = t_strdup_printf("%c", (unsigned char)c);
+               test_assert(connection_is_valid_dns_name(name) == valid);
+       } T_END;
+
+       /* then test special cases */
+       for (size_t i = 0; i < N_ELEMENTS(test_cases); i++) {
+               const struct test_case *tc = &test_cases[i];
+               test_assert_idx(connection_is_valid_dns_name(tc->input) == tc->valid, i);
+       }
+
+       test_end();
+}
+
 void test_connection(void)
 {
        test_connection_simple();
@@ -741,4 +795,5 @@ void test_connection(void)
        test_connection_handshake_failed_input();
        test_connection_input_error_reason();
        test_connection_no_version();
+       test_connection_is_valid_dns_name();
 }