From 549dbf49853d448fc804a51bc99612560ed23e34 Mon Sep 17 00:00:00 2001 From: Yurii Date: Mon, 19 Oct 2026 05:22:31 +0300 Subject: [PATCH] fix: reject invalid hostnames safely --- lib/NetworkUtils/NetworkMgr.h | 63 ++++++++++++++++++++++------------- src/utils.h | 12 ++++--- 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/lib/NetworkUtils/NetworkMgr.h b/lib/NetworkUtils/NetworkMgr.h index ae94712..aeea4f3 100644 --- a/lib/NetworkUtils/NetworkMgr.h +++ b/lib/NetworkUtils/NetworkMgr.h @@ -381,6 +381,46 @@ namespace NetworkUtils { return constrain(map(rssi, -100, -50, 0, 100), 0, 100); } + static bool isHostnameValid(const char* value) { + if (value == nullptr) { + return false; + } + + size_t len = strlen(value); + if (len == 0 || len > 24 || value[0] == '-' || value[len - 1] == '-') { + return false; + } + + for (size_t i = 0; i < len; i++) { + const char symbol = value[i]; + + // Lowercase ASCII letters. + if (symbol >= 'a' && symbol <= 'z') { + continue; + } + + // Uppercase ASCII letters. + if (symbol >= 'A' && symbol <= 'Z') { + continue; + } + + // Decimal digits. + if (symbol >= '0' && symbol <= '9') { + continue; + } + + // Hyphens are allowed inside the hostname. + if (symbol == '-') { + continue; + } + + // All other characters are invalid. + return false; + } + + return true; + } + protected: const unsigned int reconnectInterval = 15000; const unsigned int failedConnectTimeout = 185000; @@ -449,28 +489,5 @@ namespace NetworkUtils { } #endif - /** - * @brief check RFC compliance - * - * @param value - * @return true - * @return false - */ - static bool isHostnameValid(const char* value) { - size_t len = strlen(value); - if (len > 24) { - return false; - } else if (value[len - 1] == '-') { - return false; - } - - for (size_t i = 0; i < len; i++) { - if (!isalnum(value[i]) && value[i] != '-') { - return false; - } - } - - return true; - } }; } diff --git a/src/utils.h b/src/utils.h index 499670b..b3e626a 100644 --- a/src/utils.h +++ b/src/utils.h @@ -296,12 +296,14 @@ bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) { bool changed = false; // hostname - if (!src[FPSTR(S_HOSTNAME)].isNull()) { - String value = src[FPSTR(S_HOSTNAME)].as(); + if (src[FPSTR(S_HOSTNAME)].is()) { + const JsonString value = src[FPSTR(S_HOSTNAME)].as(); - if (value.length() < sizeof(dst.hostname) && !value.equals(dst.hostname)) { - strcpy(dst.hostname, value.c_str()); - changed = true; + if (value.size() < sizeof(dst.hostname) && NetworkUtils::NetworkMgr::isHostnameValid(value.c_str())) { + if (strcmp(value.c_str(), dst.hostname) != 0) { + strcpy(dst.hostname, value.c_str()); + changed = true; + } } }