cleanup: cleanup for virtio networking dns (#14111)

* cleanup: cleanup for virtio networking dns

* simplify

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
This commit is contained in:
Ben Hillis 2026-01-27 11:14:30 -08:00 committed by GitHub
parent 608ce7d8f2
commit a057ee63ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 86 additions and 85 deletions

View File

@ -438,9 +438,6 @@ try
return;
}
hns::ModifyGuestEndpointSettingRequest<hns::DNS> notification{};
notification.Settings.Options = LX_INIT_RESOLVCONF_FULL_HEADER;
networking::DnsInfo latestDnsSettings{};
// true if the "domain" entry of /etc/resolv.conf should be configured
@ -475,28 +472,19 @@ try
if (latestDnsSettings != m_trackedDnsSettings)
{
notification.Settings.ServerList = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(latestDnsSettings.Servers, ','));
if (configureLinuxDomain)
{
WI_ASSERT(!latestDnsSettings.Domains.empty());
notification.Settings.Domain = wsl::shared::string::MultiByteToWide(latestDnsSettings.Domains.front());
}
else
{
notification.Settings.Search = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(latestDnsSettings.Domains, ','));
}
auto dnsNotification = BuildDnsNotification(latestDnsSettings, configureLinuxDomain);
WSL_LOG(
"NatNetworking::UpdateDns",
TraceLoggingValue(notification.Settings.Domain.c_str(), "domain"),
TraceLoggingValue(notification.Settings.Options.c_str(), "options"),
TraceLoggingValue(notification.Settings.Search.c_str(), "search"),
TraceLoggingValue(notification.Settings.ServerList.c_str(), "serverList"));
TraceLoggingValue(dnsNotification.Domain.c_str(), "domain"),
TraceLoggingValue(dnsNotification.Options.c_str(), "options"),
TraceLoggingValue(dnsNotification.Search.c_str(), "search"),
TraceLoggingValue(dnsNotification.ServerList.c_str(), "serverList"));
hns::ModifyGuestEndpointSettingRequest<hns::DNS> notification{};
notification.RequestType = hns::ModifyRequestType::Update;
notification.ResourceType = hns::GuestEndpointResourceType::DNS;
notification.Settings = notification.Settings;
notification.Settings = std::move(dnsNotification);
m_gnsChannel.SendHnsNotification(ToJsonW(notification).c_str(), m_endpoint.Id);
m_trackedDnsSettings = std::move(latestDnsSettings);

View File

@ -65,14 +65,15 @@ void VirtioNetworking::Initialize()
device_options << L"gateway_ip=" << default_route;
}
auto dns_servers = m_networkSettings->DnsServersString();
if (!dns_servers.empty())
// Get initial DNS settings for device options.
auto initialDns = m_dnsUpdateHelper.GetCurrentDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
if (!initialDns.Servers.empty())
{
if (device_options.tellp() > 0)
{
device_options << L";";
}
device_options << L"nameservers=" << dns_servers;
device_options << L"nameservers=" << wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(initialDns.Servers, ','));
}
auto lock = m_lock.lock_exclusive();
@ -104,15 +105,9 @@ void VirtioNetworking::Initialize()
m_gnsChannel.SendHnsNotification(ToJsonW(request).c_str(), m_adapterId);
}
// Update DNS information.
if (!dns_servers.empty())
{
// TODO: DNS domain suffixes
hns::DNS dnsSettings{};
dnsSettings.Options = LX_INIT_RESOLVCONF_FULL_HEADER;
dnsSettings.ServerList = dns_servers;
UpdateDns(std::move(dnsSettings));
}
// Send the initial DNS configuration to GNS and track it.
m_trackedDnsSettings = initialDns;
SendDnsUpdate(initialDns);
if (m_enableLocalhostRelay)
{
@ -263,15 +258,23 @@ try
{
auto lock = m_lock.lock_exclusive();
UpdateMtu();
// Check for DNS changes and send update if needed.
auto currentDns = m_dnsUpdateHelper.GetCurrentDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
if (currentDns != m_trackedDnsSettings)
{
m_trackedDnsSettings = currentDns;
SendDnsUpdate(currentDns);
}
}
CATCH_LOG();
void VirtioNetworking::UpdateDns(hns::DNS&& dnsSettings)
void VirtioNetworking::SendDnsUpdate(const networking::DnsInfo& dnsSettings)
{
hns::ModifyGuestEndpointSettingRequest<hns::DNS> notification{};
notification.RequestType = hns::ModifyRequestType::Update;
notification.ResourceType = hns::GuestEndpointResourceType::DNS;
notification.Settings = std::move(dnsSettings);
notification.Settings = networking::BuildDnsNotification(dnsSettings);
m_gnsChannel.SendHnsNotification(ToJsonW(notification).c_str(), m_adapterId);
}

View File

@ -38,7 +38,7 @@ private:
int ModifyOpenPorts(_In_ PCWSTR tag, _In_ const SOCKADDR_INET& addr, _In_ int protocol, _In_ bool isOpen) const;
void RefreshGuestConnection(NL_NETWORK_CONNECTIVITY_HINT hint) noexcept;
void SetupLoopbackDevice();
void UpdateDns(wsl::shared::hns::DNS&& dnsSettings);
void SendDnsUpdate(const networking::DnsInfo& dnsSettings);
void UpdateMtu();
mutable wil::srwlock m_lock;
@ -54,7 +54,8 @@ private:
std::optional<ULONGLONG> m_interfaceLuid;
ULONG m_networkMtu = 0;
std::optional<wsl::core::networking::HostDnsInfo> m_dnsInfo;
networking::DnsUpdateHelper m_dnsUpdateHelper;
networking::DnsInfo m_trackedDnsSettings;
// Note: this field must be destroyed first to stop the callbacks before any other field is destroyed.
networking::unique_notify_handle m_networkNotifyHandle;

View File

@ -496,3 +496,29 @@ wsl::core::networking::DnsSuffixRegistryWatcher::DnsSuffixRegistryWatcher(Regist
m_registryWatchers.swap(localRegistryWatchers);
}
wsl::shared::hns::DNS wsl::core::networking::BuildDnsNotification(const DnsInfo& settings, bool useLinuxDomainEntry)
{
wsl::shared::hns::DNS dnsNotification{};
dnsNotification.Options = LX_INIT_RESOLVCONF_FULL_HEADER;
dnsNotification.ServerList = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(settings.Servers, ','));
if (useLinuxDomainEntry && !settings.Domains.empty())
{
// Use 'domain' entry for single DNS suffix (typically used when mirroring host DNS without tunneling)
dnsNotification.Domain = wsl::shared::string::MultiByteToWide(settings.Domains.front());
}
else
{
// Use 'search' entry for DNS suffix list
dnsNotification.Search = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(settings.Domains, ','));
}
return dnsNotification;
}
wsl::core::networking::DnsInfo wsl::core::networking::DnsUpdateHelper::GetCurrentDnsSettings(DnsSettingsFlags flags)
{
m_hostDnsInfo.UpdateNetworkInformation();
return m_hostDnsInfo.GetDnsSettings(flags);
}

View File

@ -38,6 +38,14 @@ inline bool operator!=(const DnsInfo& lhs, const DnsInfo& rhs) noexcept
std::string GenerateResolvConf(_In_ const DnsInfo& Info);
/// <summary>
/// Builds an hns::DNS notification from DnsInfo settings.
/// </summary>
/// <param name="settings">The DNS settings to convert</param>
/// <param name="useLinuxDomainEntry">If true, uses 'domain' entry for single suffix; otherwise uses 'search' for all
/// suffixes</param> <returns>The hns::DNS notification ready to send via GNS channel</returns>
wsl::shared::hns::DNS BuildDnsNotification(const DnsInfo& settings, bool useLinuxDomainEntry = false);
std::vector<std::string> GetAllDnsSuffixes(const std::vector<IpAdapterAddress>& AdapterAddresses);
DWORD GetBestInterface();
@ -84,6 +92,24 @@ private:
_Guarded_by_(m_lock) std::vector<IpAdapterAddress> m_addresses;
};
/// <summary>
/// Helper class that fetches current DNS settings from the host.
/// Callers are responsible for tracking changes if needed.
/// </summary>
class DnsUpdateHelper
{
public:
/// <summary>
/// Fetches current DNS settings from the host.
/// </summary>
/// <param name="flags">Flags controlling which DNS settings to include</param>
/// <returns>Current DNS settings</returns>
DnsInfo GetCurrentDnsSettings(DnsSettingsFlags flags);
private:
HostDnsInfo m_hostDnsInfo;
};
using RegistryChangeCallback = std::function<void()>;
/// <summary>

View File

@ -26,17 +26,13 @@ std::shared_ptr<wsl::core::networking::NetworkSettings> wsl::core::networking::G
address,
route,
properties.MacAddress,
L"unuseddevicename",
properties.InterfaceConstraint.InterfaceIndex,
properties.InterfaceConstraint.InterfaceMediaType,
properties.DNSServerList);
properties.InterfaceConstraint.InterfaceMediaType);
}
std::shared_ptr<wsl::core::networking::NetworkSettings> wsl::core::networking::GetHostEndpointSettings()
{
HostDnsInfo dnsInfo;
dnsInfo.UpdateNetworkInformation();
auto addresses = dnsInfo.CurrentAddresses();
auto addresses = AdapterAddresses::GetCurrent();
auto bestIndex = GetBestInterface();
auto bestInterfacePtr =
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
route.NextHopString = windows::common::string::SockAddrInetToWstring(route.NextHop);
}
std::wstring dnsServerList;
for (const auto& serverAddress : dnsInfo.GetDnsSettings(DnsSettingsFlags::IncludeVpn).Servers)
{
if (!dnsServerList.empty())
{
dnsServerList += L",";
}
dnsServerList += wsl::shared::string::MultiByteToWide(serverAddress);
}
return std::shared_ptr<NetworkSettings>(new NetworkSettings(
bestInterface->NetworkGuid, address, route, macAddress, {}, bestInterface->IfIndex, bestInterface->IfType, dnsServerList));
return std::make_shared<NetworkSettings>(
bestInterface->NetworkGuid, address, route, macAddress, bestInterface->IfIndex, bestInterface->IfType);
}

View File

@ -258,33 +258,21 @@ struct NetworkSettings
{
NetworkSettings() = default;
NetworkSettings(
const GUID& interfaceGuid,
EndpointIpAddress preferredIpAddress,
EndpointRoute gateway,
std::wstring macAddress,
std::wstring deviceName,
uint32_t interfaceIndex,
uint32_t mediaType,
const std::wstring& dnsServerList) :
NetworkSettings(const GUID& interfaceGuid, EndpointIpAddress preferredIpAddress, EndpointRoute gateway, std::wstring macAddress, uint32_t interfaceIndex, uint32_t mediaType) :
InterfaceGuid(interfaceGuid),
PreferredIpAddress(std::move(preferredIpAddress)),
MacAddress(std::move(macAddress)),
DeviceName(std::move(deviceName)),
InterfaceIndex(interfaceIndex),
InterfaceType(mediaType)
{
Routes.emplace(std::move(gateway));
DnsServers = wsl::shared::string::Split(dnsServerList, L',');
}
GUID InterfaceGuid{};
EndpointIpAddress PreferredIpAddress{};
std::set<EndpointIpAddress> IpAddresses{}; // Does not include PreferredIpAddress.
std::set<EndpointRoute> Routes{};
std::vector<std::wstring> DnsServers{};
std::wstring MacAddress;
std::wstring DeviceName;
IF_INDEX InterfaceIndex = 0;
IFTYPE InterfaceType = 0;
ULONG IPv4InterfaceMtu = 0;
@ -344,11 +332,6 @@ struct NetworkSettings
});
}
std::wstring DnsServersString() const
{
return wsl::shared::string::Join(DnsServers, L',');
}
// will return ULONG_MAX if there's no configured MTU
ULONG GetEffectiveMtu() const noexcept
{
@ -386,7 +369,6 @@ std::shared_ptr<NetworkSettings> GetHostEndpointSettings();
TraceLoggingValue((settings)->PreferredIpAddress.PrefixLength, "preferredIpAddressPrefixLength"), \
TraceLoggingValue((settings)->IpAddressesString().c_str(), "ipAddresses"), \
TraceLoggingValue((settings)->RoutesString().c_str(), "routes"), \
TraceLoggingValue((settings)->DnsServersString().c_str(), "dnsServerList"), \
TraceLoggingValue((settings)->MacAddress.c_str(), "macAddress"), \
TraceLoggingValue((settings)->IPv4InterfaceMtu, "IPv4InterfaceMtu"), \
TraceLoggingValue((settings)->IPv6InterfaceMtu, "IPv6InterfaceMtu"), \

View File

@ -18,6 +18,7 @@ Abstract:
#include "Stringify.h"
#include "WslCoreNetworkingSupport.h"
#include "WslCoreNetworkEndpointSettings.h"
#include "WslCoreHostDnsInfo.h"
#include "hcs.hpp"
#include "hns_schema.h"
@ -895,17 +896,6 @@ try
}
CATCH_RETURN()
static hns::DNS ConvertDnsInfoToHnsSettingsMsg(const wsl::core::networking::DnsInfo& dnsInfo)
{
hns::DNS dnsSettings{};
dnsSettings.Options = LX_INIT_RESOLVCONF_FULL_HEADER;
dnsSettings.ServerList = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(dnsInfo.Servers, ','));
dnsSettings.Search = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(dnsInfo.Domains, ','));
return dnsSettings;
}
_Requires_lock_held_(m_networkLock)
_Check_return_ HRESULT wsl::core::networking::WslMirroredNetworkManager::SendDnsRequestToGns(
const NetworkEndpoint& endpoint, const DnsInfo& dnsInfo, hns::ModifyRequestType requestType) noexcept
@ -915,7 +905,7 @@ try
modifyRequest.ResourceType = hns::GuestEndpointResourceType::DNS;
modifyRequest.RequestType = requestType;
modifyRequest.targetDeviceName = wsl::shared::string::GuidToString<wchar_t>(endpoint.InterfaceGuid);
modifyRequest.Settings = ConvertDnsInfoToHnsSettingsMsg(dnsInfo);
modifyRequest.Settings = BuildDnsNotification(dnsInfo);
WSL_LOG(
"WslMirroredNetworkManager::SendDnsRequestToGns",
@ -1982,7 +1972,6 @@ void wsl::core::networking::WslMirroredNetworkManager::AddEndpointImpl(EndpointT
THROW_IF_FAILED(hr);
endpointTrackingObject.m_networkEndpoint.Network->MacAddress = endpointTrackingObject.m_hnsEndpoint.MacAddress;
endpointTrackingObject.m_networkEndpoint.Network->DeviceName = endpointTrackingObject.m_hnsEndpoint.PortFriendlyName;
if (IsInterfaceIndexOfGelnic(endpointTrackingObject.m_networkEndpoint.Network->InterfaceIndex))
{