@samitouri / QOSAMI-WSL / commits / a057ee63

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 {