cleanup: cleanup for virtio networking dns (#14111)
* cleanup: cleanup for virtio networking dns * simplify --------- Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Ben Hillis committed
Jan 27, 2026 at 11:14 UTC
a057ee63ab0a4251fe258fa7228d58637bd7ffed
8 files changed
+86
-85
src/windows/common/NatNetworking.cpp
+7
-19
@@ -438,9 +438,6 @@ try
438
return;
439
}
440
441
- hns::ModifyGuestEndpointSettingRequest<hns::DNS> notification{};
442
- notification.Settings.Options = LX_INIT_RESOLVCONF_FULL_HEADER;
443
-
441
networking::DnsInfo latestDnsSettings{};
442
443
// true if the "domain" entry of /etc/resolv.conf should be configured
@@ -475,28 +472,19 @@ try
472
473
if (latestDnsSettings != m_trackedDnsSettings)
474
{
478
- notification.Settings.ServerList = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(latestDnsSettings.Servers, ','));
479
-
480
- if (configureLinuxDomain)
481
- {
482
- WI_ASSERT(!latestDnsSettings.Domains.empty());
483
- notification.Settings.Domain = wsl::shared::string::MultiByteToWide(latestDnsSettings.Domains.front());
484
- }
485
- else
486
- {
487
- notification.Settings.Search = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(latestDnsSettings.Domains, ','));
488
- }
475
+ auto dnsNotification = BuildDnsNotification(latestDnsSettings, configureLinuxDomain);
476
477
WSL_LOG(
478
"NatNetworking::UpdateDns",
492
- TraceLoggingValue(notification.Settings.Domain.c_str(), "domain"),
493
- TraceLoggingValue(notification.Settings.Options.c_str(), "options"),
494
- TraceLoggingValue(notification.Settings.Search.c_str(), "search"),
495
- TraceLoggingValue(notification.Settings.ServerList.c_str(), "serverList"));
479
+ TraceLoggingValue(dnsNotification.Domain.c_str(), "domain"),
480
+ TraceLoggingValue(dnsNotification.Options.c_str(), "options"),
481
+ TraceLoggingValue(dnsNotification.Search.c_str(), "search"),
482
+ TraceLoggingValue(dnsNotification.ServerList.c_str(), "serverList"));
483
484
+ hns::ModifyGuestEndpointSettingRequest<hns::DNS> notification{};
485
notification.RequestType = hns::ModifyRequestType::Update;
486
notification.ResourceType = hns::GuestEndpointResourceType::DNS;
499
- notification.Settings = notification.Settings;
487
+ notification.Settings = std::move(dnsNotification);
488
m_gnsChannel.SendHnsNotification(ToJsonW(notification).c_str(), m_endpoint.Id);
489
490
m_trackedDnsSettings = std::move(latestDnsSettings);
src/windows/common/VirtioNetworking.cpp
+17
-14
@@ -65,14 +65,15 @@ void VirtioNetworking::Initialize()
65
device_options << L"gateway_ip=" << default_route;
66
}
67
68
- auto dns_servers = m_networkSettings->DnsServersString();
69
- if (!dns_servers.empty())
68
+ // Get initial DNS settings for device options.
69
+ auto initialDns = m_dnsUpdateHelper.GetCurrentDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
70
+ if (!initialDns.Servers.empty())
71
{
72
if (device_options.tellp() > 0)
73
{
74
device_options << L";";
75
}
75
- device_options << L"nameservers=" << dns_servers;
76
+ device_options << L"nameservers=" << wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(initialDns.Servers, ','));
77
}
78
79
auto lock = m_lock.lock_exclusive();
@@ -104,15 +105,9 @@ void VirtioNetworking::Initialize()
105
m_gnsChannel.SendHnsNotification(ToJsonW(request).c_str(), m_adapterId);
106
}
107
107
- // Update DNS information.
108
- if (!dns_servers.empty())
109
- {
110
- // TODO: DNS domain suffixes
111
- hns::DNS dnsSettings{};
112
- dnsSettings.Options = LX_INIT_RESOLVCONF_FULL_HEADER;
113
- dnsSettings.ServerList = dns_servers;
114
- UpdateDns(std::move(dnsSettings));
115
- }
108
+ // Send the initial DNS configuration to GNS and track it.
109
+ m_trackedDnsSettings = initialDns;
110
+ SendDnsUpdate(initialDns);
111
112
if (m_enableLocalhostRelay)
113
{
@@ -263,15 +258,23 @@ try
258
{
259
auto lock = m_lock.lock_exclusive();
260
UpdateMtu();
261
+
262
+ // Check for DNS changes and send update if needed.
263
+ auto currentDns = m_dnsUpdateHelper.GetCurrentDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
264
+ if (currentDns != m_trackedDnsSettings)
265
+ {
266
+ m_trackedDnsSettings = currentDns;
267
+ SendDnsUpdate(currentDns);
268
+ }
269
}
270
CATCH_LOG();
271
269
-void VirtioNetworking::UpdateDns(hns::DNS&& dnsSettings)
272
+void VirtioNetworking::SendDnsUpdate(const networking::DnsInfo& dnsSettings)
273
{
274
hns::ModifyGuestEndpointSettingRequest<hns::DNS> notification{};
275
notification.RequestType = hns::ModifyRequestType::Update;
276
notification.ResourceType = hns::GuestEndpointResourceType::DNS;
274
- notification.Settings = std::move(dnsSettings);
277
+ notification.Settings = networking::BuildDnsNotification(dnsSettings);
278
m_gnsChannel.SendHnsNotification(ToJsonW(notification).c_str(), m_adapterId);
279
}
280
src/windows/common/VirtioNetworking.h
+3
-2
@@ -38,7 +38,7 @@ private:
38
int ModifyOpenPorts(_In_ PCWSTR tag, _In_ const SOCKADDR_INET& addr, _In_ int protocol, _In_ bool isOpen) const;
39
void RefreshGuestConnection(NL_NETWORK_CONNECTIVITY_HINT hint) noexcept;
40
void SetupLoopbackDevice();
41
- void UpdateDns(wsl::shared::hns::DNS&& dnsSettings);
41
+ void SendDnsUpdate(const networking::DnsInfo& dnsSettings);
42
void UpdateMtu();
43
44
mutable wil::srwlock m_lock;
@@ -54,7 +54,8 @@ private:
54
55
std::optional<ULONGLONG> m_interfaceLuid;
56
ULONG m_networkMtu = 0;
57
- std::optional<wsl::core::networking::HostDnsInfo> m_dnsInfo;
57
+ networking::DnsUpdateHelper m_dnsUpdateHelper;
58
+ networking::DnsInfo m_trackedDnsSettings;
59
60
// Note: this field must be destroyed first to stop the callbacks before any other field is destroyed.
61
networking::unique_notify_handle m_networkNotifyHandle;
src/windows/common/WslCoreHostDnsInfo.cpp
+26
@@ -496,3 +496,29 @@ wsl::core::networking::DnsSuffixRegistryWatcher::DnsSuffixRegistryWatcher(Regist
496
497
m_registryWatchers.swap(localRegistryWatchers);
498
}
499
+
500
+wsl::shared::hns::DNS wsl::core::networking::BuildDnsNotification(const DnsInfo& settings, bool useLinuxDomainEntry)
501
+{
502
+ wsl::shared::hns::DNS dnsNotification{};
503
+ dnsNotification.Options = LX_INIT_RESOLVCONF_FULL_HEADER;
504
+ dnsNotification.ServerList = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(settings.Servers, ','));
505
+
506
+ if (useLinuxDomainEntry && !settings.Domains.empty())
507
+ {
508
+ // Use 'domain' entry for single DNS suffix (typically used when mirroring host DNS without tunneling)
509
+ dnsNotification.Domain = wsl::shared::string::MultiByteToWide(settings.Domains.front());
510
+ }
511
+ else
512
+ {
513
+ // Use 'search' entry for DNS suffix list
514
+ dnsNotification.Search = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(settings.Domains, ','));
515
+ }
516
+
517
+ return dnsNotification;
518
+}
519
+
520
+wsl::core::networking::DnsInfo wsl::core::networking::DnsUpdateHelper::GetCurrentDnsSettings(DnsSettingsFlags flags)
521
+{
522
+ m_hostDnsInfo.UpdateNetworkInformation();
523
+ return m_hostDnsInfo.GetDnsSettings(flags);
524
+}
src/windows/common/WslCoreHostDnsInfo.h
+26
@@ -38,6 +38,14 @@ inline bool operator!=(const DnsInfo& lhs, const DnsInfo& rhs) noexcept
38
39
std::string GenerateResolvConf(_In_ const DnsInfo& Info);
40
41
+/// <summary>
42
+/// Builds an hns::DNS notification from DnsInfo settings.
43
+/// </summary>
44
+/// <param name="settings">The DNS settings to convert</param>
45
+/// <param name="useLinuxDomainEntry">If true, uses 'domain' entry for single suffix; otherwise uses 'search' for all
46
+/// suffixes</param> <returns>The hns::DNS notification ready to send via GNS channel</returns>
47
+wsl::shared::hns::DNS BuildDnsNotification(const DnsInfo& settings, bool useLinuxDomainEntry = false);
48
+
49
std::vector<std::string> GetAllDnsSuffixes(const std::vector<IpAdapterAddress>& AdapterAddresses);
50
51
DWORD GetBestInterface();
@@ -84,6 +92,24 @@ private:
92
_Guarded_by_(m_lock) std::vector<IpAdapterAddress> m_addresses;
93
};
94
95
+/// <summary>
96
+/// Helper class that fetches current DNS settings from the host.
97
+/// Callers are responsible for tracking changes if needed.
98
+/// </summary>
99
+class DnsUpdateHelper
100
+{
101
+public:
102
+ /// <summary>
103
+ /// Fetches current DNS settings from the host.
104
+ /// </summary>
105
+ /// <param name="flags">Flags controlling which DNS settings to include</param>
106
+ /// <returns>Current DNS settings</returns>
107
+ DnsInfo GetCurrentDnsSettings(DnsSettingsFlags flags);
108
+
109
+private:
110
+ HostDnsInfo m_hostDnsInfo;
111
+};
112
+
113
using RegistryChangeCallback = std::function<void()>;
114
115
/// <summary>
src/windows/common/WslCoreNetworkEndpointSettings.cpp
+4
-18
@@ -26,17 +26,13 @@ std::shared_ptr<wsl::core::networking::NetworkSettings> wsl::core::networking::G
26
address,
27
route,
28
properties.MacAddress,
29
- L"unuseddevicename",
29
properties.InterfaceConstraint.InterfaceIndex,
31
- properties.InterfaceConstraint.InterfaceMediaType,
32
- properties.DNSServerList);
30
+ properties.InterfaceConstraint.InterfaceMediaType);
31
}
32
33
std::shared_ptr<wsl::core::networking::NetworkSettings> wsl::core::networking::GetHostEndpointSettings()
34
{
37
- HostDnsInfo dnsInfo;
38
- dnsInfo.UpdateNetworkInformation();
39
- auto addresses = dnsInfo.CurrentAddresses();
35
+ auto addresses = AdapterAddresses::GetCurrent();
36
auto bestIndex = GetBestInterface();
37
auto bestInterfacePtr =
38
std::find_if(addresses.cbegin(), addresses.cend(), [&](const auto& address) { return address->IfIndex == bestIndex; });
@@ -95,16 +91,6 @@ std::shared_ptr<wsl::core::networking::NetworkSettings> wsl::core::networking::G
91
route.NextHopString = windows::common::string::SockAddrInetToWstring(route.NextHop);
92
}
93
98
- std::wstring dnsServerList;
99
- for (const auto& serverAddress : dnsInfo.GetDnsSettings(DnsSettingsFlags::IncludeVpn).Servers)
100
- {
101
- if (!dnsServerList.empty())
102
- {
103
- dnsServerList += L",";
104
- }
105
- dnsServerList += wsl::shared::string::MultiByteToWide(serverAddress);
106
- }
107
-
108
- return std::shared_ptr<NetworkSettings>(new NetworkSettings(
109
- bestInterface->NetworkGuid, address, route, macAddress, {}, bestInterface->IfIndex, bestInterface->IfType, dnsServerList));
94
+ return std::make_shared<NetworkSettings>(
95
+ bestInterface->NetworkGuid, address, route, macAddress, bestInterface->IfIndex, bestInterface->IfType);
96
}
src/windows/common/WslCoreNetworkEndpointSettings.h
+1
-19
@@ -258,33 +258,21 @@ struct NetworkSettings
258
{
259
NetworkSettings() = default;
260
261
- NetworkSettings(
262
- const GUID& interfaceGuid,
263
- EndpointIpAddress preferredIpAddress,
264
- EndpointRoute gateway,
265
- std::wstring macAddress,
266
- std::wstring deviceName,
267
- uint32_t interfaceIndex,
268
- uint32_t mediaType,
269
- const std::wstring& dnsServerList) :
261
+ NetworkSettings(const GUID& interfaceGuid, EndpointIpAddress preferredIpAddress, EndpointRoute gateway, std::wstring macAddress, uint32_t interfaceIndex, uint32_t mediaType) :
262
InterfaceGuid(interfaceGuid),
263
PreferredIpAddress(std::move(preferredIpAddress)),
264
MacAddress(std::move(macAddress)),
273
- DeviceName(std::move(deviceName)),
265
InterfaceIndex(interfaceIndex),
266
InterfaceType(mediaType)
267
{
268
Routes.emplace(std::move(gateway));
278
- DnsServers = wsl::shared::string::Split(dnsServerList, L',');
269
}
270
271
GUID InterfaceGuid{};
272
EndpointIpAddress PreferredIpAddress{};
273
std::set<EndpointIpAddress> IpAddresses{}; // Does not include PreferredIpAddress.
274
std::set<EndpointRoute> Routes{};
285
- std::vector<std::wstring> DnsServers{};
275
std::wstring MacAddress;
287
- std::wstring DeviceName;
276
IF_INDEX InterfaceIndex = 0;
277
IFTYPE InterfaceType = 0;
278
ULONG IPv4InterfaceMtu = 0;
@@ -344,11 +332,6 @@ struct NetworkSettings
332
});
333
}
334
347
- std::wstring DnsServersString() const
348
- {
349
- return wsl::shared::string::Join(DnsServers, L',');
350
- }
351
-
335
// will return ULONG_MAX if there's no configured MTU
336
ULONG GetEffectiveMtu() const noexcept
337
{
@@ -386,7 +369,6 @@ std::shared_ptr<NetworkSettings> GetHostEndpointSettings();
369
TraceLoggingValue((settings)->PreferredIpAddress.PrefixLength, "preferredIpAddressPrefixLength"), \
370
TraceLoggingValue((settings)->IpAddressesString().c_str(), "ipAddresses"), \
371
TraceLoggingValue((settings)->RoutesString().c_str(), "routes"), \
389
- TraceLoggingValue((settings)->DnsServersString().c_str(), "dnsServerList"), \
372
TraceLoggingValue((settings)->MacAddress.c_str(), "macAddress"), \
373
TraceLoggingValue((settings)->IPv4InterfaceMtu, "IPv4InterfaceMtu"), \
374
TraceLoggingValue((settings)->IPv6InterfaceMtu, "IPv6InterfaceMtu"), \
src/windows/service/exe/WslMirroredNetworking.cpp
+2
-13
@@ -18,6 +18,7 @@ Abstract:
18
#include "Stringify.h"
19
#include "WslCoreNetworkingSupport.h"
20
#include "WslCoreNetworkEndpointSettings.h"
21
+#include "WslCoreHostDnsInfo.h"
22
#include "hcs.hpp"
23
#include "hns_schema.h"
24
@@ -895,17 +896,6 @@ try
896
}
897
CATCH_RETURN()
898
898
-static hns::DNS ConvertDnsInfoToHnsSettingsMsg(const wsl::core::networking::DnsInfo& dnsInfo)
899
-{
900
- hns::DNS dnsSettings{};
901
- dnsSettings.Options = LX_INIT_RESOLVCONF_FULL_HEADER;
902
-
903
- dnsSettings.ServerList = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(dnsInfo.Servers, ','));
904
- dnsSettings.Search = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(dnsInfo.Domains, ','));
905
-
906
- return dnsSettings;
907
-}
908
-
899
_Requires_lock_held_(m_networkLock)
900
_Check_return_ HRESULT wsl::core::networking::WslMirroredNetworkManager::SendDnsRequestToGns(
901
const NetworkEndpoint& endpoint, const DnsInfo& dnsInfo, hns::ModifyRequestType requestType) noexcept
@@ -915,7 +905,7 @@ try
905
modifyRequest.ResourceType = hns::GuestEndpointResourceType::DNS;
906
modifyRequest.RequestType = requestType;
907
modifyRequest.targetDeviceName = wsl::shared::string::GuidToString<wchar_t>(endpoint.InterfaceGuid);
918
- modifyRequest.Settings = ConvertDnsInfoToHnsSettingsMsg(dnsInfo);
908
+ modifyRequest.Settings = BuildDnsNotification(dnsInfo);
909
910
WSL_LOG(
911
"WslMirroredNetworkManager::SendDnsRequestToGns",
@@ -1982,7 +1972,6 @@ void wsl::core::networking::WslMirroredNetworkManager::AddEndpointImpl(EndpointT
1972
THROW_IF_FAILED(hr);
1973
1974
endpointTrackingObject.m_networkEndpoint.Network->MacAddress = endpointTrackingObject.m_hnsEndpoint.MacAddress;
1985
- endpointTrackingObject.m_networkEndpoint.Network->DeviceName = endpointTrackingObject.m_hnsEndpoint.PortFriendlyName;
1975
1976
if (IsInterfaceIndexOfGelnic(endpointTrackingObject.m_networkEndpoint.Network->InterfaceIndex))
1977
{