From ca5036ca5bf80e54da6a0f9cbb5ca3eb5ce1007b Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 24 Aug 2024 19:38:44 -0500 Subject: [PATCH] fix(mdns): don't hardcode mDNS instance name --- src/network.cpp | 28 ++++++++++++++++++++++++++++ src/network.h | 7 +++++++ src/platform/linux/publish.cpp | 3 ++- src/platform/macos/publish.cpp | 3 ++- src/platform/windows/publish.cpp | 3 +-- tests/unit/test_network.cpp | 23 +++++++++++++++++++++++ 6 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 tests/unit/test_network.cpp diff --git a/src/network.cpp b/src/network.cpp index b7b18de88b0..b8628d214fe 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -206,4 +206,32 @@ namespace net { return mapped_port; } + + /** + * @brief Returns a string for use as the instance name for mDNS. + * @return Hostname-based instance name or "Sunshine" if hostname is invalid. + */ + std::string + mdns_instance_name() { + std::string hostname = boost::asio::ip::host_name(); + + // Truncate to 63 characters per RFC 6763 section 7.2. + if (hostname.size() > 63) { + hostname.resize(63); + } + + for (auto i = 0; i < hostname.size(); i++) { + // Replace any spaces with dashes + if (hostname[i] == ' ') { + hostname[i] = '-'; + } + else if (!std::isalnum(hostname[i]) && hostname[i] != '-') { + // Stop at the first invalid character + hostname.resize(i); + break; + } + } + + return !hostname.empty() ? hostname : "Sunshine"; + } } // namespace net diff --git a/src/network.h b/src/network.h index ffc0b2d2ff4..875d33665dc 100644 --- a/src/network.h +++ b/src/network.h @@ -105,4 +105,11 @@ namespace net { */ int encryption_mode_for_address(boost::asio::ip::address address); + + /** + * @brief Returns a string for use as the instance name for mDNS. + * @return Hostname-based instance name or "Sunshine" if hostname is invalid. + */ + std::string + mdns_instance_name(); } // namespace net diff --git a/src/platform/linux/publish.cpp b/src/platform/linux/publish.cpp index 29641411e50..7368d36029c 100644 --- a/src/platform/linux/publish.cpp +++ b/src/platform/linux/publish.cpp @@ -426,7 +426,8 @@ namespace platf::publish { return nullptr; } - name.reset(avahi::strdup(SERVICE_NAME)); + auto instance_name = net::mdns_instance_name(); + name.reset(avahi::strdup(instance_name.c_str())); client.reset( avahi::client_new(avahi::simple_poll_get(poll.get()), avahi::ClientFlags(0), client_callback, nullptr, &avhi_error)); diff --git a/src/platform/macos/publish.cpp b/src/platform/macos/publish.cpp index ec4f1f452dd..b8c977c0673 100644 --- a/src/platform/macos/publish.cpp +++ b/src/platform/macos/publish.cpp @@ -105,7 +105,8 @@ namespace platf::publish { &serviceRef, 0, // flags 0, // interfaceIndex - SERVICE_NAME, SERVICE_TYPE, + nullptr, // name + SERVICE_TYPE, nullptr, // domain nullptr, // host htons(net::map_port(nvhttp::PORT_HTTP)), diff --git a/src/platform/windows/publish.cpp b/src/platform/windows/publish.cpp index fe3352e2309..c6901c8a09b 100644 --- a/src/platform/windows/publish.cpp +++ b/src/platform/windows/publish.cpp @@ -37,7 +37,6 @@ constexpr auto DNS_QUERY_RESULTS_VERSION1 = 0x1; #define SERVICE_DOMAIN "local" -constexpr auto SERVICE_INSTANCE_NAME = SV(SERVICE_NAME "." SERVICE_TYPE "." SERVICE_DOMAIN); constexpr auto SERVICE_TYPE_DOMAIN = SV(SERVICE_TYPE "." SERVICE_DOMAIN); #ifndef __MINGW32__ @@ -107,8 +106,8 @@ namespace platf::publish { service(bool enable, PDNS_SERVICE_INSTANCE &existing_instance) { auto alarm = safe::make_alarm(); - std::wstring name { SERVICE_INSTANCE_NAME.data(), SERVICE_INSTANCE_NAME.size() }; std::wstring domain { SERVICE_TYPE_DOMAIN.data(), SERVICE_TYPE_DOMAIN.size() }; + std::wstring name = from_utf8(net::mdns_instance_name() + '.') + domain; auto host = from_utf8(boost::asio::ip::host_name() + ".local"); diff --git a/tests/unit/test_network.cpp b/tests/unit/test_network.cpp new file mode 100644 index 00000000000..13436dd3ce3 --- /dev/null +++ b/tests/unit/test_network.cpp @@ -0,0 +1,23 @@ +/** + * @file tests/unit/test_network.cpp + * @brief Test src/network.* + */ +#include + +#include "../tests_common.h" + +TEST(MdnsInstanceNameTests, ValidLength) { + auto name = net::mdns_instance_name(); + + // The instance name must be 63 characters or less + EXPECT_LT(name.size(), 64); +} + +TEST(MdnsInstanceNameTests, ValidCharacters) { + auto name = net::mdns_instance_name(); + + // The string must not contain invalid hostname characters + for (const char& c : name) { + EXPECT_TRUE(std::isalnum(c) || c == '-'); + } +}