diff --git a/README.md b/README.md index f6b1b18..a8c44e0 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ A Windows desktop application for managing DNS servers across your network adapt ## Features - **Network discovery** — Detects adapters (Wi‑Fi, Ethernet, VPN, virtual) +- **Adapter health badges** — Shows connected/disconnected and enabled/disabled state for each adapter - **DNS catalog** — 30+ providers (Google, Cloudflare, Quad9, OpenDNS, AdGuard, etc.) - **Custom DNS** — Add and manage your own servers - **Speed test** — Real DNS queries with latency, packet loss, and stability @@ -101,3 +102,10 @@ This builds the C++ DLL, copies it to `windows_gui`, and builds the WPF applicat 2. Download the latest **DNSChanger-Setup-x.x.x.exe**. 3. Run the installer (UAC may prompt). 4. Launch **DNS Changer** from the Start menu or desktop. Use **Run as administrator** when changing DNS. + + +## Latest changes (v2.1.0) + +- Improved network adapter handling so disconnected adapters stay visible. +- DNS apply/restore now protects users from applying changes to disabled adapters. +- Updated UI with richer adapter status details and a version badge in the header. diff --git a/cpp_core/src/dns_apply_windows.cpp b/cpp_core/src/dns_apply_windows.cpp index cac5fc8..73fd129 100644 --- a/cpp_core/src/dns_apply_windows.cpp +++ b/cpp_core/src/dns_apply_windows.cpp @@ -1,11 +1,54 @@ +#define WIN32_LEAN_AND_MEAN #include "../include/dns_apply_windows.h" #include "../include/logger.h" #include "../include/win_utils.h" +#include +#include #include -#include #include +#include #include #include +#include +#include + +namespace { +std::string NormalizeGuid(std::string guid) { + guid.erase(std::remove_if(guid.begin(), guid.end(), [](unsigned char ch) { + return std::isspace(ch); + }), guid.end()); + + if (!guid.empty() && guid.front() == '{' && guid.back() == '}') { + return guid; + } + + return "{" + guid + "}"; +} + +std::wstring FindAdapterFriendlyName(const std::string& interfaceGuid) { + ULONG bufferSize = 0; + GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &bufferSize); + if (bufferSize == 0) { + return L""; + } + + std::vector buffer(bufferSize); + PIP_ADAPTER_ADDRESSES adapters = reinterpret_cast(buffer.data()); + + if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, adapters, &bufferSize) != NO_ERROR) { + return L""; + } + + const std::string normalizedGuid = NormalizeGuid(interfaceGuid); + for (auto* adapter = adapters; adapter != nullptr; adapter = adapter->Next) { + if (adapter->AdapterName && normalizedGuid == adapter->AdapterName && adapter->FriendlyName) { + return adapter->FriendlyName; + } + } + + return L""; +} +} #pragma comment(lib, "iphlpapi.lib") #pragma comment(lib, "netapi32.lib") @@ -20,7 +63,8 @@ bool DnsManager::SetDns(const std::string& interfaceGuid, const std::string& dns // Try Windows SDK API first (Windows 10 1809+) GUID guid; - std::wstring guidWide = WinUtils::Utf8ToWide(interfaceGuid); + const std::string normalizedGuid = NormalizeGuid(interfaceGuid); + std::wstring guidWide = WinUtils::Utf8ToWide(normalizedGuid); HRESULT hr = CLSIDFromString(guidWide.c_str(), &guid); if (SUCCEEDED(hr)) { // Prepare DNS server addresses @@ -54,8 +98,11 @@ bool DnsManager::SetDns(const std::string& interfaceGuid, const std::string& dns } // Fallback to netsh if SDK API fails or not available + std::wstring adapterName = FindAdapterFriendlyName(interfaceGuid); + std::wstring adapterSelector = adapterName.empty() ? guidWide : adapterName; + std::wstringstream cmd; - cmd << L"interface ip set dns \"" << guidWide << L"\" static " << WinUtils::Utf8ToWide(dns1); + cmd << L"interface ipv4 set dnsservers name=\"" << adapterSelector << L"\" static " << WinUtils::Utf8ToWide(dns1) << L" primary"; STARTUPINFOW si = {0}; si.cb = sizeof(si); @@ -78,7 +125,7 @@ bool DnsManager::SetDns(const std::string& interfaceGuid, const std::string& dns // Set secondary DNS if provided if (!dns2.empty()) { std::wstringstream cmd2; - cmd2 << L"interface ip add dns \"" << guidWide << L"\" " << WinUtils::Utf8ToWide(dns2) << L" index=2"; + cmd2 << L"interface ipv4 add dnsservers name=\"" << adapterSelector << L"\" " << WinUtils::Utf8ToWide(dns2) << L" index=2"; std::wstring cmdLine2 = L"netsh.exe " + cmd2.str(); std::vector cmdLineBuf2(cmdLine2.begin(), cmdLine2.end()); cmdLineBuf2.push_back(L'\0'); @@ -113,7 +160,8 @@ bool DnsManager::RestoreDefaultDns(const std::string& interfaceGuid) { // Try Windows SDK API first GUID guid; - std::wstring guidWide = WinUtils::Utf8ToWide(interfaceGuid); + const std::string normalizedGuid = NormalizeGuid(interfaceGuid); + std::wstring guidWide = WinUtils::Utf8ToWide(normalizedGuid); HRESULT hr = CLSIDFromString(guidWide.c_str(), &guid); if (SUCCEEDED(hr)) { DNS_INTERFACE_SETTINGS settings = {0}; @@ -130,8 +178,11 @@ bool DnsManager::RestoreDefaultDns(const std::string& interfaceGuid) { } // Fallback to netsh + std::wstring adapterName = FindAdapterFriendlyName(interfaceGuid); + std::wstring adapterSelector = adapterName.empty() ? guidWide : adapterName; + std::wstringstream cmd; - cmd << L"interface ip set dns \"" << guidWide << L"\" dhcp"; + cmd << L"interface ipv4 set dnsservers name=\"" << adapterSelector << L"\" source=dhcp"; STARTUPINFOW si = {0}; si.cb = sizeof(si); diff --git a/cpp_core/src/network_windows.cpp b/cpp_core/src/network_windows.cpp index 53f48b7..21ae706 100644 --- a/cpp_core/src/network_windows.cpp +++ b/cpp_core/src/network_windows.cpp @@ -110,8 +110,8 @@ NetworkList NetworkDiscovery::DiscoverAdapters() { } } - // Only add enabled adapters - if (netAdapter.isEnabled) { + // Skip loopback adapters but keep disabled/disconnected adapters visible in UI. + if (adapter->IfType != IF_TYPE_SOFTWARE_LOOPBACK) { list.adapters.push_back(netAdapter); } diff --git a/windows_gui/DNSChanger.csproj b/windows_gui/DNSChanger.csproj index 1f207e0..d59af14 100644 --- a/windows_gui/DNSChanger.csproj +++ b/windows_gui/DNSChanger.csproj @@ -10,6 +10,9 @@ DNSChanger app.manifest true + 2.1.0 + 2.1.0.0 + 2.1.0.0 diff --git a/windows_gui/MainWindow.xaml b/windows_gui/MainWindow.xaml index efb72eb..ede7faf 100644 --- a/windows_gui/MainWindow.xaml +++ b/windows_gui/MainWindow.xaml @@ -40,11 +40,16 @@ BorderBrush="{StaticResource BorderBrush}" BorderThickness="0,0,0,1"> - + + + + + @@ -82,8 +88,14 @@ + + - + - - - - + + + + + + + + diff --git a/windows_gui/Models/NetworkModel.cs b/windows_gui/Models/NetworkModel.cs index a27367b..50df3ae 100644 --- a/windows_gui/Models/NetworkModel.cs +++ b/windows_gui/Models/NetworkModel.cs @@ -13,7 +13,9 @@ public class NetworkModel public string DnsSecondary { get; set; } = string.Empty; public bool IsEnabled { get; set; } public bool IsConnected { get; set; } - + public string StatusBadge => IsConnected ? "Connected" : "Disconnected"; + public string AdapterState => IsEnabled ? "Enabled" : "Disabled"; + public string DnsSummary => string.IsNullOrWhiteSpace(DnsSecondary) ? DnsPrimary : $"{DnsPrimary}, {DnsSecondary}"; } } diff --git a/windows_gui/ViewModels/MainViewModel.cs b/windows_gui/ViewModels/MainViewModel.cs index d28307f..a121421 100644 --- a/windows_gui/ViewModels/MainViewModel.cs +++ b/windows_gui/ViewModels/MainViewModel.cs @@ -210,11 +210,20 @@ private async Task RefreshNetworksAsync() { StatusMessage = "Refreshing networks..."; Networks = await _dnsService.GetNetworksAsync(); - if (Networks.Count > 0 && SelectedNetwork == null) + + if (Networks.Count > 0) + { + SelectedNetwork = Networks.FirstOrDefault(n => n.IsConnected) + ?? Networks.FirstOrDefault(n => n.IsEnabled) + ?? Networks[0]; + } + else { - SelectedNetwork = Networks[0]; + SelectedNetwork = null; } - StatusMessage = $"Found {Networks.Count} network(s)"; + + int connectedCount = Networks.Count(n => n.IsConnected); + StatusMessage = $"Found {Networks.Count} network(s), {connectedCount} connected"; } private async Task RefreshDnsServersAsync() @@ -349,6 +358,13 @@ public void ApplyDns() if (SelectedNetwork == null || SelectedDns == null) return; + if (!SelectedNetwork.IsEnabled) + { + UiService.ShowError($"{SelectedNetwork.Name} is disabled. Enable the adapter and try again."); + StatusMessage = "Selected adapter is disabled"; + return; + } + // Check admin rights before attempting if (!AdminService.IsRunningAsAdministrator()) { @@ -394,6 +410,13 @@ public void RestoreDefaultDns() if (SelectedNetwork == null) return; + if (!SelectedNetwork.IsEnabled) + { + UiService.ShowError($"{SelectedNetwork.Name} is disabled. Enable the adapter and try again."); + StatusMessage = "Selected adapter is disabled"; + return; + } + // Check admin rights before attempting if (!AdminService.IsRunningAsAdministrator()) {