Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 5 additions & 9 deletions src/linux/init/GnsEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,21 +315,17 @@ void GnsEngine::ProcessDNSChange(Interface& interface, const wsl::shared::hns::D
content << L"nameserver " << server << L"\n";
}

if (!payload.Domain.empty())
{
content << L"domain " << payload.Domain << L"\n";
}

// Use 'search' for DNS suffixes.
// Per resolv.conf(5): "The domain directive is an obsolete name for the search directive
// that handles one search list entry only."
// See: https://man7.org/linux/man-pages/man5/resolv.conf.5.html
if (!payload.Search.empty())
{
content << L"search " << wsl::shared::string::Join(wsl::shared::string::Split(payload.Search, L','), L' ') << L"\n";
}

GNS_LOG_INFO(
"Setting DNS server domain to {}: {} on interfaceName {} ",
payload.Domain.c_str(),
content.str().c_str(),
interface.Name().c_str());
"Setting DNS search to {}: {} on interfaceName {} ", payload.Search.c_str(), content.str().c_str(), interface.Name().c_str());

std::wofstream resolvConf;
resolvConf.exceptions(std::ofstream::badbit | std::ofstream::failbit);
Expand Down
35 changes: 13 additions & 22 deletions src/windows/common/NatNetworking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@ static wil::srwlock g_endpointsInUseLock;
static std::vector<GUID> g_endpointsInUse;

NatNetworking::NatNetworking(
HCS_SYSTEM system, wsl::windows::common::hcs::unique_hcn_network&& network, GnsChannel&& gnsChannel, Config& config, wil::unique_socket&& dnsHvsocket) :
m_system(system), m_config(config), m_network(std::move(network)), m_gnsChannel(std::move(gnsChannel))
HCS_SYSTEM system,
wsl::windows::common::hcs::unique_hcn_network&& network,
GnsChannel&& gnsChannel,
Config& config,
wil::unique_socket&& dnsHvsocket,
LPCWSTR dnsOptions) :
m_system(system), m_config(config), m_network(std::move(network)), m_dnsOptions(dnsOptions), m_gnsChannel(std::move(gnsChannel))
{
m_connectivityTelemetryEnabled = config.EnableTelemetry && !WslTraceLoggingShouldDisableTelemetry();

Expand All @@ -48,7 +53,7 @@ NatNetworking::NatNetworking(
// prioritized means:
// - can only set 3 DNS servers (Linux limitation)
// - when there are multiple host connected interfaces, we need to use the DNS servers from the most-likely-to-be-used interface on the host
m_mirrorDnsInfo.emplace();
m_useMirrorDnsSettings = true;
}
}

Expand Down Expand Up @@ -337,7 +342,7 @@ void NatNetworking::Initialize()
UpdateDns(endpointProperties.GatewayAddress.c_str());

// if using the shared access DNS proxy, ensure that the shared access service is allowed inbound UDP access.
if (!m_mirrorDnsInfo && !m_dnsTunnelingResolver)
if (!m_useMirrorDnsSettings && !m_dnsTunnelingResolver)
{
// N.B. This rule works around a host OS issue that prevents the DNS proxy from working on older versions of Windows.
ConfigureSharedAccessFirewallRule();
Expand Down Expand Up @@ -433,35 +438,22 @@ _Requires_lock_held_(m_lock)
void NatNetworking::UpdateDns(std::optional<PCWSTR> gatewayAddress) noexcept
try
{
if (!m_dnsTunnelingResolver && !m_mirrorDnsInfo && !gatewayAddress)
if (!m_dnsTunnelingResolver && !m_useMirrorDnsSettings && !gatewayAddress)
{
return;
}

networking::DnsInfo latestDnsSettings{};

// true if the "domain" entry of /etc/resolv.conf should be configured
// Note: the "domain" entry allows a single DNS suffix to be configured
bool configureLinuxDomain = false;

// NAT mode with DNS tunneling
if (m_dnsTunnelingResolver)
{
latestDnsSettings = HostDnsInfo::GetDnsTunnelingSettings(m_dnsTunnelingIpAddress);
}
// NAT mode without Shared Access DNS proxy
else if (m_mirrorDnsInfo)
else if (m_useMirrorDnsSettings)
{
m_mirrorDnsInfo->UpdateNetworkInformation();
const auto settings = m_mirrorDnsInfo->GetDnsSettings(DnsSettingsFlags::IncludeVpn);

latestDnsSettings.Servers = std::move(settings.Servers);

if (!settings.Domains.empty())
{
latestDnsSettings.Domains.emplace_back(std::move(settings.Domains.front()));
configureLinuxDomain = true;
}
latestDnsSettings = HostDnsInfo::GetDnsSettings(DnsSettingsFlags::IncludeVpn);
}
// NAT mode with Shared Access DNS proxy
else if (gatewayAddress)
Expand All @@ -472,11 +464,10 @@ try

if (latestDnsSettings != m_trackedDnsSettings)
{
auto dnsNotification = BuildDnsNotification(latestDnsSettings, configureLinuxDomain);
auto dnsNotification = BuildDnsNotification(latestDnsSettings, m_dnsOptions);

WSL_LOG(
"NatNetworking::UpdateDns",
TraceLoggingValue(dnsNotification.Domain.c_str(), "domain"),
TraceLoggingValue(dnsNotification.Options.c_str(), "options"),
TraceLoggingValue(dnsNotification.Search.c_str(), "search"),
TraceLoggingValue(dnsNotification.ServerList.c_str(), "serverList"));
Expand Down
16 changes: 14 additions & 2 deletions src/windows/common/NatNetworking.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ namespace wsl::core {
class NatNetworking final : public INetworkingEngine
{
public:
NatNetworking(HCS_SYSTEM system, wsl::windows::common::hcs::unique_hcn_network&& network, GnsChannel&& gnsChannel, Config& config, wil::unique_socket&& dnsHvsocket);
NatNetworking(
HCS_SYSTEM system,
wsl::windows::common::hcs::unique_hcn_network&& network,
GnsChannel&& gnsChannel,
Config& config,
wil::unique_socket&& dnsHvsocket,
LPCWSTR dnsOptions = LX_INIT_RESOLVCONF_FULL_HEADER);
~NatNetworking() override;

// Note: This class cannot be moved because m_networkNotifyHandle captures a 'this' pointer.
Expand Down Expand Up @@ -69,12 +75,18 @@ class NatNetworking final : public INetworkingEngine
// The latest DNS settings configured in Linux
_Guarded_by_(m_lock) networking::DnsInfo m_trackedDnsSettings {};

// If true, DNS settings are retrieved from host adapters (mirrored mode)
// rather than using the shared access DNS proxy
bool m_useMirrorDnsSettings = false;

// Options/header for /etc/resolv.conf
LPCWSTR m_dnsOptions = nullptr;

GnsChannel m_gnsChannel;
std::shared_ptr<networking::NetworkSettings> m_networkSettings;
networking::EphemeralHcnEndpoint m_endpoint;
ULONG m_networkMtu = 0;

std::optional<networking::HostDnsInfo> m_mirrorDnsInfo;
networking::unique_notify_handle m_networkNotifyHandle{};
};

Expand Down
11 changes: 6 additions & 5 deletions src/windows/common/VirtioNetworking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ using wsl::core::VirtioNetworking;
static constexpr auto c_loopbackDeviceName = TEXT(LX_INIT_LOOPBACK_DEVICE_NAME);

VirtioNetworking::VirtioNetworking(
GnsChannel&& gnsChannel, bool enableLocalhostRelay, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken) :
GnsChannel&& gnsChannel, bool enableLocalhostRelay, LPCWSTR dnsOptions, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken) :
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OneBlue - I'm open to other options, but basically I just don't want the WSL header in /etc/resolv.conf when we are running WSLA.

m_guestDeviceManager(std::move(guestDeviceManager)),
m_userToken(std::move(userToken)),
m_gnsChannel(std::move(gnsChannel)),
m_enableLocalhostRelay(enableLocalhostRelay)
m_enableLocalhostRelay(enableLocalhostRelay),
m_dnsOptions(dnsOptions)
{
}

Expand Down Expand Up @@ -66,7 +67,7 @@ void VirtioNetworking::Initialize()
}

// Get initial DNS settings for device options.
auto initialDns = m_dnsUpdateHelper.GetCurrentDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
auto initialDns = networking::HostDnsInfo::GetDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
if (!initialDns.Servers.empty())
{
if (device_options.tellp() > 0)
Expand Down Expand Up @@ -260,7 +261,7 @@ try
UpdateMtu();

// Check for DNS changes and send update if needed.
auto currentDns = m_dnsUpdateHelper.GetCurrentDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
auto currentDns = networking::HostDnsInfo::GetDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
if (currentDns != m_trackedDnsSettings)
{
m_trackedDnsSettings = currentDns;
Expand All @@ -274,7 +275,7 @@ void VirtioNetworking::SendDnsUpdate(const networking::DnsInfo& dnsSettings)
hns::ModifyGuestEndpointSettingRequest<hns::DNS> notification{};
notification.RequestType = hns::ModifyRequestType::Update;
notification.ResourceType = hns::GuestEndpointResourceType::DNS;
notification.Settings = networking::BuildDnsNotification(dnsSettings);
notification.Settings = networking::BuildDnsNotification(dnsSettings, m_dnsOptions);
m_gnsChannel.SendHnsNotification(ToJsonW(notification).c_str(), m_adapterId);
}

Expand Down
4 changes: 2 additions & 2 deletions src/windows/common/VirtioNetworking.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace wsl::core {
class VirtioNetworking : public INetworkingEngine
{
public:
VirtioNetworking(GnsChannel&& gnsChannel, bool enableLocalhostRelay, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken);
VirtioNetworking(GnsChannel&& gnsChannel, bool enableLocalhostRelay, LPCWSTR dnsOptions, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken);
~VirtioNetworking();

// Note: This class cannot be moved because m_networkNotifyHandle captures a 'this' pointer.
Expand Down Expand Up @@ -49,12 +49,12 @@ class VirtioNetworking : public INetworkingEngine
std::optional<GnsPortTrackerChannel> m_gnsPortTrackerChannel;
std::shared_ptr<networking::NetworkSettings> m_networkSettings;
bool m_enableLocalhostRelay;
LPCWSTR m_dnsOptions = nullptr;
GUID m_localhostAdapterId;
GUID m_adapterId;

std::optional<ULONGLONG> m_interfaceLuid;
ULONG m_networkMtu = 0;
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.
Expand Down
48 changes: 16 additions & 32 deletions src/windows/common/WslCoreHostDnsInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,6 @@ wsl::core::networking::DnsInfo wsl::core::networking::HostDnsInfo::GetDnsTunneli
return dnsInfo;
}

std::vector<wsl::core::networking::IpAdapterAddress> wsl::core::networking::HostDnsInfo::GetAdapterAddresses()
{
std::lock_guard<std::mutex> lock(m_lock);
return m_addresses;
}

std::vector<std::string> wsl::core::networking::HostDnsInfo::GetDnsServerStrings(
_In_ const PIP_ADAPTER_DNS_SERVER_ADDRESS& FirstDnsServer, _In_ USHORT IpFamilyFilter, _In_ USHORT MaxValues)
{
Expand Down Expand Up @@ -233,7 +227,7 @@ std::vector<std::string> wsl::core::networking::HostDnsInfo::GetInterfaceDnsSuff

wsl::core::networking::DnsInfo wsl::core::networking::HostDnsInfo::GetDnsSettings(_In_ DnsSettingsFlags Flags)
{
std::vector<IpAdapterAddress> Addresses = GetAdapterAddresses();
std::vector<IpAdapterAddress> Addresses = AdapterAddresses::GetCurrent();

auto RemoveFilter = [&](const IpAdapterAddress& Address) {
// Ignore interfaces that are not currently "up".
Expand Down Expand Up @@ -326,12 +320,6 @@ wsl::core::networking::DnsInfo wsl::core::networking::HostDnsInfo::GetDnsSetting
return DnsSettings;
}

void wsl::core::networking::HostDnsInfo::UpdateNetworkInformation()
{
std::lock_guard<std::mutex> lock(m_lock);
m_addresses = AdapterAddresses::GetCurrent();
}

std::string wsl::core::networking::GenerateResolvConf(_In_ const DnsInfo& Info)
{
std::string contents{};
Expand All @@ -345,7 +333,10 @@ std::string wsl::core::networking::GenerateResolvConf(_In_ const DnsInfo& Info)
contents += c_asciiNewLine;
}

// Add domain information if it is available.
// Add DNS suffix information using 'search' directive.
// Per resolv.conf(5): "The domain directive is an obsolete name for the search directive
// that handles one search list entry only."
// See: https://man7.org/linux/man-pages/man5/resolv.conf.5.html
if (!Info.Domains.empty())
{
contents += "search ";
Expand Down Expand Up @@ -497,28 +488,21 @@ 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 wsl::core::networking::BuildDnsNotification(const DnsInfo& settings, PCWSTR options)
{
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())
if (options)
{
// 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, ','));
dnsNotification.Options = options;
}

return dnsNotification;
}
dnsNotification.ServerList = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(settings.Servers, ','));

wsl::core::networking::DnsInfo wsl::core::networking::DnsUpdateHelper::GetCurrentDnsSettings(DnsSettingsFlags flags)
{
m_hostDnsInfo.UpdateNetworkInformation();
return m_hostDnsInfo.GetDnsSettings(flags);
// Use 'search' entry for DNS suffix list.
// Per resolv.conf(5): "The domain directive is an obsolete name for the search directive
// that handles one search list entry only."
// See: https://man7.org/linux/man-pages/man5/resolv.conf.5.html
dnsNotification.Search = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(settings.Domains, ','));

return dnsNotification;
}
47 changes: 5 additions & 42 deletions src/windows/common/WslCoreHostDnsInfo.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (C) Microsoft Corporation. All rights reserved.

#pragma once
#include <mutex>
#include <string>
#include <vector>

Expand Down Expand Up @@ -42,9 +41,9 @@ std::string GenerateResolvConf(_In_ const DnsInfo& Info);
/// 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);
/// <param name="options">The resolv.conf header options (defaults to LX_INIT_RESOLVCONF_FULL_HEADER)</param>
/// <returns>The hns::DNS notification ready to send via GNS channel</returns>
wsl::shared::hns::DNS BuildDnsNotification(const DnsInfo& settings, PCWSTR options = LX_INIT_RESOLVCONF_FULL_HEADER);

std::vector<std::string> GetAllDnsSuffixes(const std::vector<IpAdapterAddress>& AdapterAddresses);

Expand All @@ -53,27 +52,15 @@ DWORD GetBestInterface();
class HostDnsInfo
{
public:
DnsInfo GetDnsSettings(_In_ DnsSettingsFlags Flags);

void UpdateNetworkInformation();
static DnsInfo GetDnsSettings(_In_ DnsSettingsFlags Flags);

static DnsInfo GetDnsTunnelingSettings(const std::wstring& dnsTunnelingNameserver);

const std::vector<IpAdapterAddress>& CurrentAddresses() const
{
return m_addresses;
}

private:
/// <summary>
/// Internal function to retrieve the latest copy of interface information.
/// </summary>
std::vector<IpAdapterAddress> GetAdapterAddresses();

/// <summary>
/// Internal function to retrieve interface DNS servers.
/// </summary>
std::vector<std::string> GetInterfaceDnsServers(const std::vector<IpAdapterAddress>& AdapterAddresses, _In_ DnsSettingsFlags Flags);
static std::vector<std::string> GetInterfaceDnsServers(const std::vector<IpAdapterAddress>& AdapterAddresses, _In_ DnsSettingsFlags Flags);

/// <summary>
/// Internal function to retrieve all Windows DNS suffixes.
Expand All @@ -84,30 +71,6 @@ class HostDnsInfo
/// Internal function to convert DNS server addresses into strings.
/// </summary>
static std::vector<std::string> GetDnsServerStrings(_In_ const PIP_ADAPTER_DNS_SERVER_ADDRESS& DnsServer, _In_ USHORT IpFamilyFilter, _In_ USHORT MaxValues);

/// <summary>
/// Stores latest copy of interface information.
/// </summary>
std::mutex m_lock;
_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()>;
Expand Down
Loading