From: Aki Tuomi Date: Mon, 17 Apr 2023 05:12:39 +0000 (+0300) Subject: lib: connection - Add connection_is_valid_dns_name() X-Git-Tag: 2.4.0~2142 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=26da32a340ff4c92dafb3e764d355fefa6f2af03;p=thirdparty%2Fdovecot%2Fcore.git lib: connection - Add connection_is_valid_dns_name() Checks that given name is valid DNS servername, including characters _ and RFC5891 section 4.2.1 specified ones. --- diff --git a/src/lib/connection.c b/src/lib/connection.c index 1897b6e300..41307e2c13 100644 --- a/src/lib/connection.c +++ b/src/lib/connection.c @@ -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 */ +} diff --git a/src/lib/connection.h b/src/lib/connection.h index 8318dbf83c..7a0bc10482 100644 --- a/src/lib/connection.h +++ b/src/lib/connection.h @@ -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 diff --git a/src/lib/test-connection.c b/src/lib/test-connection.c index feb1f9ceea..b30dc6b40e 100644 --- a/src/lib/test-connection.c +++ b/src/lib/test-connection.c @@ -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(); }