Skip to content

Commit 8aadbb4

Browse files
benhillisBen Hillis
andauthored
DNS: Simplify dns logic and switch to using 'search' instead of 'domain' which is obsolete. (#14133)
* DNS: Simplify dns logic and switch to using 'search' instead of 'domain' which is obsolete. * add optional header for natnetworking * format * extend configuration test for virtioproxy networking mode --------- Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
1 parent b8e9351 commit 8aadbb4

File tree

13 files changed

+67
-131
lines changed

13 files changed

+67
-131
lines changed

src/linux/init/GnsEngine.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -315,21 +315,17 @@ void GnsEngine::ProcessDNSChange(Interface& interface, const wsl::shared::hns::D
315315
content << L"nameserver " << server << L"\n";
316316
}
317317

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

328327
GNS_LOG_INFO(
329-
"Setting DNS server domain to {}: {} on interfaceName {} ",
330-
payload.Domain.c_str(),
331-
content.str().c_str(),
332-
interface.Name().c_str());
328+
"Setting DNS search to {}: {} on interfaceName {} ", payload.Search.c_str(), content.str().c_str(), interface.Name().c_str());
333329

334330
std::wofstream resolvConf;
335331
resolvConf.exceptions(std::ofstream::badbit | std::ofstream::failbit);

src/windows/common/NatNetworking.cpp

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@ static wil::srwlock g_endpointsInUseLock;
2626
static std::vector<GUID> g_endpointsInUse;
2727

2828
NatNetworking::NatNetworking(
29-
HCS_SYSTEM system, wsl::windows::common::hcs::unique_hcn_network&& network, GnsChannel&& gnsChannel, Config& config, wil::unique_socket&& dnsHvsocket) :
30-
m_system(system), m_config(config), m_network(std::move(network)), m_gnsChannel(std::move(gnsChannel))
29+
HCS_SYSTEM system,
30+
wsl::windows::common::hcs::unique_hcn_network&& network,
31+
GnsChannel&& gnsChannel,
32+
Config& config,
33+
wil::unique_socket&& dnsHvsocket,
34+
LPCWSTR dnsOptions) :
35+
m_system(system), m_config(config), m_network(std::move(network)), m_dnsOptions(dnsOptions), m_gnsChannel(std::move(gnsChannel))
3136
{
3237
m_connectivityTelemetryEnabled = config.EnableTelemetry && !WslTraceLoggingShouldDisableTelemetry();
3338

@@ -48,7 +53,7 @@ NatNetworking::NatNetworking(
4853
// prioritized means:
4954
// - can only set 3 DNS servers (Linux limitation)
5055
// - 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
51-
m_mirrorDnsInfo.emplace();
56+
m_useMirrorDnsSettings = true;
5257
}
5358
}
5459

@@ -337,7 +342,7 @@ void NatNetworking::Initialize()
337342
UpdateDns(endpointProperties.GatewayAddress.c_str());
338343

339344
// if using the shared access DNS proxy, ensure that the shared access service is allowed inbound UDP access.
340-
if (!m_mirrorDnsInfo && !m_dnsTunnelingResolver)
345+
if (!m_useMirrorDnsSettings && !m_dnsTunnelingResolver)
341346
{
342347
// N.B. This rule works around a host OS issue that prevents the DNS proxy from working on older versions of Windows.
343348
ConfigureSharedAccessFirewallRule();
@@ -433,35 +438,22 @@ _Requires_lock_held_(m_lock)
433438
void NatNetworking::UpdateDns(std::optional<PCWSTR> gatewayAddress) noexcept
434439
try
435440
{
436-
if (!m_dnsTunnelingResolver && !m_mirrorDnsInfo && !gatewayAddress)
441+
if (!m_dnsTunnelingResolver && !m_useMirrorDnsSettings && !gatewayAddress)
437442
{
438443
return;
439444
}
440445

441446
networking::DnsInfo latestDnsSettings{};
442447

443-
// true if the "domain" entry of /etc/resolv.conf should be configured
444-
// Note: the "domain" entry allows a single DNS suffix to be configured
445-
bool configureLinuxDomain = false;
446-
447448
// NAT mode with DNS tunneling
448449
if (m_dnsTunnelingResolver)
449450
{
450451
latestDnsSettings = HostDnsInfo::GetDnsTunnelingSettings(m_dnsTunnelingIpAddress);
451452
}
452453
// NAT mode without Shared Access DNS proxy
453-
else if (m_mirrorDnsInfo)
454+
else if (m_useMirrorDnsSettings)
454455
{
455-
m_mirrorDnsInfo->UpdateNetworkInformation();
456-
const auto settings = m_mirrorDnsInfo->GetDnsSettings(DnsSettingsFlags::IncludeVpn);
457-
458-
latestDnsSettings.Servers = std::move(settings.Servers);
459-
460-
if (!settings.Domains.empty())
461-
{
462-
latestDnsSettings.Domains.emplace_back(std::move(settings.Domains.front()));
463-
configureLinuxDomain = true;
464-
}
456+
latestDnsSettings = HostDnsInfo::GetDnsSettings(DnsSettingsFlags::IncludeVpn);
465457
}
466458
// NAT mode with Shared Access DNS proxy
467459
else if (gatewayAddress)
@@ -472,11 +464,10 @@ try
472464

473465
if (latestDnsSettings != m_trackedDnsSettings)
474466
{
475-
auto dnsNotification = BuildDnsNotification(latestDnsSettings, configureLinuxDomain);
467+
auto dnsNotification = BuildDnsNotification(latestDnsSettings, m_dnsOptions);
476468

477469
WSL_LOG(
478470
"NatNetworking::UpdateDns",
479-
TraceLoggingValue(dnsNotification.Domain.c_str(), "domain"),
480471
TraceLoggingValue(dnsNotification.Options.c_str(), "options"),
481472
TraceLoggingValue(dnsNotification.Search.c_str(), "search"),
482473
TraceLoggingValue(dnsNotification.ServerList.c_str(), "serverList"));

src/windows/common/NatNetworking.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@ namespace wsl::core {
1818
class NatNetworking final : public INetworkingEngine
1919
{
2020
public:
21-
NatNetworking(HCS_SYSTEM system, wsl::windows::common::hcs::unique_hcn_network&& network, GnsChannel&& gnsChannel, Config& config, wil::unique_socket&& dnsHvsocket);
21+
NatNetworking(
22+
HCS_SYSTEM system,
23+
wsl::windows::common::hcs::unique_hcn_network&& network,
24+
GnsChannel&& gnsChannel,
25+
Config& config,
26+
wil::unique_socket&& dnsHvsocket,
27+
LPCWSTR dnsOptions = LX_INIT_RESOLVCONF_FULL_HEADER);
2228
~NatNetworking() override;
2329

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

78+
// If true, DNS settings are retrieved from host adapters (mirrored mode)
79+
// rather than using the shared access DNS proxy
80+
bool m_useMirrorDnsSettings = false;
81+
82+
// Options/header for /etc/resolv.conf
83+
LPCWSTR m_dnsOptions = nullptr;
84+
7285
GnsChannel m_gnsChannel;
7386
std::shared_ptr<networking::NetworkSettings> m_networkSettings;
7487
networking::EphemeralHcnEndpoint m_endpoint;
7588
ULONG m_networkMtu = 0;
7689

77-
std::optional<networking::HostDnsInfo> m_mirrorDnsInfo;
7890
networking::unique_notify_handle m_networkNotifyHandle{};
7991
};
8092

src/windows/common/VirtioNetworking.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ using wsl::core::VirtioNetworking;
1414
static constexpr auto c_loopbackDeviceName = TEXT(LX_INIT_LOOPBACK_DEVICE_NAME);
1515

1616
VirtioNetworking::VirtioNetworking(
17-
GnsChannel&& gnsChannel, bool enableLocalhostRelay, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken) :
17+
GnsChannel&& gnsChannel, bool enableLocalhostRelay, LPCWSTR dnsOptions, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken) :
1818
m_guestDeviceManager(std::move(guestDeviceManager)),
1919
m_userToken(std::move(userToken)),
2020
m_gnsChannel(std::move(gnsChannel)),
21-
m_enableLocalhostRelay(enableLocalhostRelay)
21+
m_enableLocalhostRelay(enableLocalhostRelay),
22+
m_dnsOptions(dnsOptions)
2223
{
2324
}
2425

@@ -66,7 +67,7 @@ void VirtioNetworking::Initialize()
6667
}
6768

6869
// Get initial DNS settings for device options.
69-
auto initialDns = m_dnsUpdateHelper.GetCurrentDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
70+
auto initialDns = networking::HostDnsInfo::GetDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
7071
if (!initialDns.Servers.empty())
7172
{
7273
if (device_options.tellp() > 0)
@@ -260,7 +261,7 @@ try
260261
UpdateMtu();
261262

262263
// Check for DNS changes and send update if needed.
263-
auto currentDns = m_dnsUpdateHelper.GetCurrentDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
264+
auto currentDns = networking::HostDnsInfo::GetDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
264265
if (currentDns != m_trackedDnsSettings)
265266
{
266267
m_trackedDnsSettings = currentDns;
@@ -274,7 +275,7 @@ void VirtioNetworking::SendDnsUpdate(const networking::DnsInfo& dnsSettings)
274275
hns::ModifyGuestEndpointSettingRequest<hns::DNS> notification{};
275276
notification.RequestType = hns::ModifyRequestType::Update;
276277
notification.ResourceType = hns::GuestEndpointResourceType::DNS;
277-
notification.Settings = networking::BuildDnsNotification(dnsSettings);
278+
notification.Settings = networking::BuildDnsNotification(dnsSettings, m_dnsOptions);
278279
m_gnsChannel.SendHnsNotification(ToJsonW(notification).c_str(), m_adapterId);
279280
}
280281

src/windows/common/VirtioNetworking.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace wsl::core {
1313
class VirtioNetworking : public INetworkingEngine
1414
{
1515
public:
16-
VirtioNetworking(GnsChannel&& gnsChannel, bool enableLocalhostRelay, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken);
16+
VirtioNetworking(GnsChannel&& gnsChannel, bool enableLocalhostRelay, LPCWSTR dnsOptions, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken);
1717
~VirtioNetworking();
1818

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

5556
std::optional<ULONGLONG> m_interfaceLuid;
5657
ULONG m_networkMtu = 0;
57-
networking::DnsUpdateHelper m_dnsUpdateHelper;
5858
networking::DnsInfo m_trackedDnsSettings;
5959

6060
// Note: this field must be destroyed first to stop the callbacks before any other field is destroyed.

src/windows/common/WslCoreHostDnsInfo.cpp

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,6 @@ wsl::core::networking::DnsInfo wsl::core::networking::HostDnsInfo::GetDnsTunneli
105105
return dnsInfo;
106106
}
107107

108-
std::vector<wsl::core::networking::IpAdapterAddress> wsl::core::networking::HostDnsInfo::GetAdapterAddresses()
109-
{
110-
std::lock_guard<std::mutex> lock(m_lock);
111-
return m_addresses;
112-
}
113-
114108
std::vector<std::string> wsl::core::networking::HostDnsInfo::GetDnsServerStrings(
115109
_In_ const PIP_ADAPTER_DNS_SERVER_ADDRESS& FirstDnsServer, _In_ USHORT IpFamilyFilter, _In_ USHORT MaxValues)
116110
{
@@ -233,7 +227,7 @@ std::vector<std::string> wsl::core::networking::HostDnsInfo::GetInterfaceDnsSuff
233227

234228
wsl::core::networking::DnsInfo wsl::core::networking::HostDnsInfo::GetDnsSettings(_In_ DnsSettingsFlags Flags)
235229
{
236-
std::vector<IpAdapterAddress> Addresses = GetAdapterAddresses();
230+
std::vector<IpAdapterAddress> Addresses = AdapterAddresses::GetCurrent();
237231

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

329-
void wsl::core::networking::HostDnsInfo::UpdateNetworkInformation()
330-
{
331-
std::lock_guard<std::mutex> lock(m_lock);
332-
m_addresses = AdapterAddresses::GetCurrent();
333-
}
334-
335323
std::string wsl::core::networking::GenerateResolvConf(_In_ const DnsInfo& Info)
336324
{
337325
std::string contents{};
@@ -345,7 +333,10 @@ std::string wsl::core::networking::GenerateResolvConf(_In_ const DnsInfo& Info)
345333
contents += c_asciiNewLine;
346334
}
347335

348-
// Add domain information if it is available.
336+
// Add DNS suffix information using 'search' directive.
337+
// Per resolv.conf(5): "The domain directive is an obsolete name for the search directive
338+
// that handles one search list entry only."
339+
// See: https://man7.org/linux/man-pages/man5/resolv.conf.5.html
349340
if (!Info.Domains.empty())
350341
{
351342
contents += "search ";
@@ -497,28 +488,21 @@ wsl::core::networking::DnsSuffixRegistryWatcher::DnsSuffixRegistryWatcher(Regist
497488
m_registryWatchers.swap(localRegistryWatchers);
498489
}
499490

500-
wsl::shared::hns::DNS wsl::core::networking::BuildDnsNotification(const DnsInfo& settings, bool useLinuxDomainEntry)
491+
wsl::shared::hns::DNS wsl::core::networking::BuildDnsNotification(const DnsInfo& settings, PCWSTR options)
501492
{
502493
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())
494+
if (options)
507495
{
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, ','));
496+
dnsNotification.Options = options;
515497
}
516498

517-
return dnsNotification;
518-
}
499+
dnsNotification.ServerList = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(settings.Servers, ','));
519500

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

src/windows/common/WslCoreHostDnsInfo.h

Lines changed: 5 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright (C) Microsoft Corporation. All rights reserved.
22

33
#pragma once
4-
#include <mutex>
54
#include <string>
65
#include <vector>
76

@@ -42,9 +41,9 @@ std::string GenerateResolvConf(_In_ const DnsInfo& Info);
4241
/// Builds an hns::DNS notification from DnsInfo settings.
4342
/// </summary>
4443
/// <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);
44+
/// <param name="options">The resolv.conf header options (defaults to LX_INIT_RESOLVCONF_FULL_HEADER)</param>
45+
/// <returns>The hns::DNS notification ready to send via GNS channel</returns>
46+
wsl::shared::hns::DNS BuildDnsNotification(const DnsInfo& settings, PCWSTR options = LX_INIT_RESOLVCONF_FULL_HEADER);
4847

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

@@ -53,27 +52,15 @@ DWORD GetBestInterface();
5352
class HostDnsInfo
5453
{
5554
public:
56-
DnsInfo GetDnsSettings(_In_ DnsSettingsFlags Flags);
57-
58-
void UpdateNetworkInformation();
55+
static DnsInfo GetDnsSettings(_In_ DnsSettingsFlags Flags);
5956

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

62-
const std::vector<IpAdapterAddress>& CurrentAddresses() const
63-
{
64-
return m_addresses;
65-
}
66-
6759
private:
68-
/// <summary>
69-
/// Internal function to retrieve the latest copy of interface information.
70-
/// </summary>
71-
std::vector<IpAdapterAddress> GetAdapterAddresses();
72-
7360
/// <summary>
7461
/// Internal function to retrieve interface DNS servers.
7562
/// </summary>
76-
std::vector<std::string> GetInterfaceDnsServers(const std::vector<IpAdapterAddress>& AdapterAddresses, _In_ DnsSettingsFlags Flags);
63+
static std::vector<std::string> GetInterfaceDnsServers(const std::vector<IpAdapterAddress>& AdapterAddresses, _In_ DnsSettingsFlags Flags);
7764

7865
/// <summary>
7966
/// Internal function to retrieve all Windows DNS suffixes.
@@ -84,30 +71,6 @@ class HostDnsInfo
8471
/// Internal function to convert DNS server addresses into strings.
8572
/// </summary>
8673
static std::vector<std::string> GetDnsServerStrings(_In_ const PIP_ADAPTER_DNS_SERVER_ADDRESS& DnsServer, _In_ USHORT IpFamilyFilter, _In_ USHORT MaxValues);
87-
88-
/// <summary>
89-
/// Stores latest copy of interface information.
90-
/// </summary>
91-
std::mutex m_lock;
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;
11174
};
11275

11376
using RegistryChangeCallback = std::function<void()>;

0 commit comments

Comments
 (0)