Skip to content

Commit 7daa758

Browse files
author
Ben Hillis
committed
wslc: implement dns tunneling for virtio proxy networking mode
This change implements dnstunneling for the virtio proxy networking mode. For now, this implementation uses the same socket-based approach, but in the fututure this will be moved over to the built-in dns support that is part of the wsldevicehost dll.
1 parent e46cf9a commit 7daa758

13 files changed

Lines changed: 205 additions & 34 deletions

File tree

src/windows/common/VirtioNetworking.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,29 @@ static constexpr auto c_eth0DeviceName = L"eth0";
1515
static constexpr auto c_loopbackDeviceName = TEXT(LX_INIT_LOOPBACK_DEVICE_NAME);
1616

1717
VirtioNetworking::VirtioNetworking(
18-
GnsChannel&& gnsChannel, VirtioNetworkingFlags flags, LPCWSTR dnsOptions, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken) :
18+
GnsChannel&& gnsChannel,
19+
VirtioNetworkingFlags flags,
20+
LPCWSTR dnsOptions,
21+
std::shared_ptr<GuestDeviceManager> guestDeviceManager,
22+
wil::shared_handle userToken,
23+
wil::unique_socket&& dnsHvsocket) :
1924
m_guestDeviceManager(std::move(guestDeviceManager)),
2025
m_userToken(std::move(userToken)),
2126
m_gnsChannel(std::move(gnsChannel)),
2227
m_flags(flags),
2328
m_dnsOptions(dnsOptions)
2429
{
30+
THROW_HR_IF_MSG(
31+
E_INVALIDARG,
32+
((!!dnsHvsocket != WI_IsFlagSet(m_flags, VirtioNetworkingFlags::DnsTunnelingSocket)) ||
33+
(WI_IsFlagSet(m_flags, VirtioNetworkingFlags::DnsTunnelingSocket) && WI_IsFlagSet(m_flags, VirtioNetworkingFlags::DnsTunneling))),
34+
"Incompatible DNS settings");
35+
36+
if (dnsHvsocket)
37+
{
38+
networking::DnsResolverFlags resolverFlags{};
39+
m_dnsTunnelingResolver.emplace(std::move(dnsHvsocket), resolverFlags);
40+
}
2541
}
2642

2743
VirtioNetworking::~VirtioNetworking()
@@ -196,6 +212,10 @@ try
196212
{
197213
currentDns = networking::HostDnsInfo::GetDnsTunnelingSettings(default_route);
198214
}
215+
else if (WI_IsFlagSet(m_flags, VirtioNetworkingFlags::DnsTunnelingSocket))
216+
{
217+
currentDns = networking::HostDnsInfo::GetDnsTunnelingSettings(TEXT(LX_INIT_DNS_TUNNELING_IP_ADDRESS));
218+
}
199219
else
200220
{
201221
wsl::core::networking::DnsSettingsFlags dnsFlags = networking::DnsSettingsFlags::IncludeVpn;

src/windows/common/VirtioNetworking.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "INetworkingEngine.h"
66
#include "GnsChannel.h"
7+
#include "DnsResolver.h"
78
#include "WslCoreHostDnsInfo.h"
89
#include "GnsPortTrackerChannel.h"
910
#include "GuestDeviceManager.h"
@@ -16,13 +17,21 @@ enum class VirtioNetworkingFlags
1617
LocalhostRelay = 0x1,
1718
DnsTunneling = 0x2,
1819
Ipv6 = 0x4,
20+
DnsTunnelingSocket = 0x8,
1921
};
2022
DEFINE_ENUM_FLAG_OPERATORS(VirtioNetworkingFlags);
2123

2224
class VirtioNetworking : public INetworkingEngine
2325
{
2426
public:
25-
VirtioNetworking(GnsChannel&& gnsChannel, VirtioNetworkingFlags flags, LPCWSTR dnsOptions, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken);
27+
VirtioNetworking(
28+
GnsChannel&& gnsChannel,
29+
VirtioNetworkingFlags flags,
30+
LPCWSTR dnsOptions,
31+
std::shared_ptr<GuestDeviceManager> guestDeviceManager,
32+
wil::shared_handle userToken,
33+
wil::unique_socket&& dnsHvsocket = {});
34+
2635
~VirtioNetworking();
2736

2837
// Note: This class cannot be moved because m_networkNotifyHandle captures a 'this' pointer.
@@ -61,6 +70,7 @@ class VirtioNetworking : public INetworkingEngine
6170
std::shared_ptr<networking::NetworkSettings> m_networkSettings;
6271
VirtioNetworkingFlags m_flags = VirtioNetworkingFlags::None;
6372
LPCWSTR m_dnsOptions = nullptr;
73+
std::optional<networking::DnsResolver> m_dnsTunnelingResolver;
6474
std::optional<GUID> m_localhostAdapterId;
6575
std::optional<GUID> m_adapterId;
6676

src/windows/common/WslCoreConfig.cpp

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -419,26 +419,14 @@ void wsl::core::Config::Initialize(_In_opt_ HANDLE UserToken)
419419
{
420420
try
421421
{
422-
// Open a handle to the service control manager and check if the inbox service is registered.
423-
const wil::unique_schandle manager{OpenSCManager(nullptr, nullptr, SC_MANAGER_ENUMERATE_SERVICE)};
424-
THROW_LAST_ERROR_IF(!manager);
425-
426-
// Check if the service is running.
427-
const wil::unique_schandle service{OpenServiceW(manager.get(), L"GlobalSecureAccessTunnelingService", SERVICE_QUERY_STATUS)};
428-
if (service)
422+
if (wsl::windows::common::helpers::IsServiceRunning(L"GlobalSecureAccessTunnelingService"))
429423
{
430-
SERVICE_STATUS status;
431-
THROW_IF_WIN32_BOOL_FALSE(QueryServiceStatus(service.get(), &status));
432-
433-
if (status.dwCurrentState != SERVICE_STOPPED)
424+
if (DnsTunnelingConfigPresence == ConfigKeyPresence::Present)
434425
{
435-
if (DnsTunnelingConfigPresence == ConfigKeyPresence::Present)
436-
{
437-
EMIT_USER_WARNING(wsl::shared::Localization::MessageDnsTunnelingDisabled());
438-
}
439-
440-
EnableDnsTunneling = false;
426+
EMIT_USER_WARNING(wsl::shared::Localization::MessageDnsTunnelingDisabled());
441427
}
428+
429+
EnableDnsTunneling = false;
442430
}
443431
}
444432
CATCH_LOG()
@@ -474,9 +462,12 @@ void wsl::core::Config::Initialize(_In_opt_ HANDLE UserToken)
474462
EnableVirtio9p = false;
475463
}
476464

477-
if (NetworkingMode != NetworkingMode::Nat && NetworkingMode != NetworkingMode::Mirrored)
465+
if (NetworkingMode != NetworkingMode::Nat && NetworkingMode != NetworkingMode::Mirrored && NetworkingMode != NetworkingMode::VirtioProxy)
478466
{
479-
VALIDATE_CONFIG_OPTION((NetworkingMode != NetworkingMode::Nat && NetworkingMode != NetworkingMode::Mirrored), EnableDnsTunneling, false);
467+
VALIDATE_CONFIG_OPTION(
468+
(NetworkingMode != NetworkingMode::Nat && NetworkingMode != NetworkingMode::Mirrored && NetworkingMode != NetworkingMode::VirtioProxy),
469+
EnableDnsTunneling,
470+
false);
480471
}
481472

482473
if (!EnableDnsTunneling)

src/windows/common/helpers.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,22 @@ bool wsl::windows::common::helpers::IsServicePresent(_In_ LPCWSTR ServiceName)
475475
return !!service;
476476
}
477477

478+
bool wsl::windows::common::helpers::IsServiceRunning(_In_ LPCWSTR ServiceName)
479+
{
480+
const wil::unique_schandle manager{OpenSCManager(nullptr, nullptr, SC_MANAGER_ENUMERATE_SERVICE)};
481+
THROW_LAST_ERROR_IF(!manager);
482+
483+
const wil::unique_schandle service{OpenServiceW(manager.get(), ServiceName, SERVICE_QUERY_STATUS)};
484+
if (!service)
485+
{
486+
return false;
487+
}
488+
489+
SERVICE_STATUS status;
490+
THROW_IF_WIN32_BOOL_FALSE(QueryServiceStatus(service.get(), &status));
491+
return status.dwCurrentState != SERVICE_STOPPED;
492+
}
493+
478494
bool wsl::windows::common::helpers::IsVirtioSerialConsoleSupported()
479495
{
480496
// See if the Windows version has the required platform change.

src/windows/common/helpers.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ bool IsPackageInstalled(_In_ LPCWSTR PackageFamilyName);
153153

154154
bool IsServicePresent(_In_ LPCWSTR ServiceName);
155155

156+
bool IsServiceRunning(_In_ LPCWSTR ServiceName);
157+
156158
bool IsVirtioSerialConsoleSupported();
157159

158160
bool IsVmemmSuffixSupported();

src/windows/service/exe/HcsVirtualMachine.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ HcsVirtualMachine::HcsVirtualMachine(_In_ const WSLCSessionSettings* Settings)
4343

4444
THROW_IF_FAILED(CoCreateGuid(&m_vmId));
4545
m_vmIdString = wsl::shared::string::GuidToString<wchar_t>(m_vmId, wsl::shared::string::GuidToStringFlags::Uppercase);
46-
m_featureFlags = static_cast<WSLCFeatureFlags>(Settings->FeatureFlags);
46+
m_featureFlags = Settings->FeatureFlags;
4747
m_networkingMode = Settings->NetworkingMode;
4848
m_bootTimeoutMs = Settings->BootTimeoutMs;
4949

@@ -369,8 +369,6 @@ try
369369
if (FeatureEnabled(WslcFeatureFlagsDnsTunneling))
370370
{
371371
THROW_HR_IF(E_INVALIDARG, DnsSocket == nullptr);
372-
THROW_HR_IF_MSG(
373-
E_NOTIMPL, m_networkingMode == WSLCNetworkingModeVirtioProxy, "DNS tunneling not supported for VirtioProxy");
374372

375373
THROW_IF_FAILED(wsl::core::networking::DnsResolver::LoadDnsResolverMethods());
376374
dnsSocketHandle.reset(reinterpret_cast<SOCKET>(wslutil::DuplicateHandle(*DnsSocket)));
@@ -383,34 +381,39 @@ try
383381
if (m_networkingMode == WSLCNetworkingModeNAT)
384382
{
385383
// TODO: refactor this to avoid using wsl config
386-
wsl::core::Config config(nullptr);
387-
if (!wsl::core::NatNetworking::IsHyperVFirewallSupported(config))
384+
m_natConfig.emplace(nullptr);
385+
if (!wsl::core::NatNetworking::IsHyperVFirewallSupported(*m_natConfig))
388386
{
389-
config.FirewallConfig.reset();
387+
m_natConfig->FirewallConfig.reset();
390388
}
391389

392390
// Enable DNS tunneling if a DNS socket was provided
393391
if (FeatureEnabled(WslcFeatureFlagsDnsTunneling))
394392
{
395-
config.EnableDnsTunneling = true;
393+
m_natConfig->EnableDnsTunneling = true;
396394
in_addr address{};
397395
WI_VERIFY(inet_pton(AF_INET, LX_INIT_DNS_TUNNELING_IP_ADDRESS, &address) == 1);
398-
config.DnsTunnelingIpAddress = address.S_un.S_addr;
396+
m_natConfig->DnsTunnelingIpAddress = address.S_un.S_addr;
399397
}
400398

401399
m_networkEngine = std::make_unique<wsl::core::NatNetworking>(
402400
m_computeSystem.get(),
403-
wsl::core::NatNetworking::CreateNetwork(config),
401+
wsl::core::NatNetworking::CreateNetwork(*m_natConfig),
404402
wsl::core::GnsChannel(std::move(gnsSocketHandle)),
405-
config,
403+
*m_natConfig,
406404
std::move(dnsSocketHandle),
407405
nullptr);
408406
}
409407
else if (m_networkingMode == WSLCNetworkingModeVirtioProxy)
410408
{
411409
wsl::core::VirtioNetworkingFlags flags = wsl::core::VirtioNetworkingFlags::Ipv6;
410+
if (FeatureEnabled(WslcFeatureFlagsDnsTunneling))
411+
{
412+
WI_SetFlag(flags, wsl::core::VirtioNetworkingFlags::DnsTunnelingSocket);
413+
}
414+
412415
m_networkEngine = std::make_unique<wsl::core::VirtioNetworking>(
413-
wsl::core::GnsChannel(std::move(gnsSocketHandle)), flags, nullptr, m_guestDeviceManager, m_userToken);
416+
wsl::core::GnsChannel(std::move(gnsSocketHandle)), flags, nullptr, m_guestDeviceManager, m_userToken, std::move(dnsSocketHandle));
414417
}
415418
else
416419
{

src/windows/service/exe/HcsVirtualMachine.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Module Name:
2020
#include "GuestDeviceManager.h"
2121
#include "Dmesg.h"
2222
#include "INetworkingEngine.h"
23+
#include "WslCoreConfig.h"
2324
#include <filesystem>
2425
#include <map>
2526

@@ -79,6 +80,7 @@ class HcsVirtualMachine
7980
wil::unique_socket m_listenSocket;
8081
std::shared_ptr<DmesgCollector> m_dmesgCollector;
8182
std::shared_ptr<GuestDeviceManager> m_guestDeviceManager;
83+
std::optional<wsl::core::Config> m_natConfig;
8284
std::unique_ptr<wsl::core::INetworkingEngine> m_networkEngine;
8385

8486
wil::unique_event m_vmExitEvent{wil::EventOptions::ManualReset};

src/windows/service/exe/WslCoreVm.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -571,8 +571,9 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
571571
{
572572
wsl::core::VirtioNetworkingFlags flags = wsl::core::VirtioNetworkingFlags::Ipv6;
573573
WI_SetFlagIf(flags, wsl::core::VirtioNetworkingFlags::LocalhostRelay, m_vmConfig.EnableLocalhostRelay);
574+
WI_SetFlagIf(flags, wsl::core::VirtioNetworkingFlags::DnsTunnelingSocket, m_vmConfig.EnableDnsTunneling);
574575
m_networkingEngine = std::make_unique<wsl::core::VirtioNetworking>(
575-
std::move(gnsChannel), flags, LX_INIT_RESOLVCONF_FULL_HEADER, m_guestDeviceManager, m_userToken);
576+
std::move(gnsChannel), flags, LX_INIT_RESOLVCONF_FULL_HEADER, m_guestDeviceManager, m_userToken, std::move(dnsTunnelingSocket));
576577
}
577578
else if (m_vmConfig.NetworkingMode == NetworkingMode::Bridged)
578579
{
@@ -1890,7 +1891,9 @@ bool WslCoreVm::InitializeDrvFsLockHeld(_In_ HANDLE UserToken)
18901891

18911892
bool WslCoreVm::IsDnsTunnelingSupported() const
18921893
{
1893-
WI_ASSERT(m_vmConfig.NetworkingMode == NetworkingMode::Nat || m_vmConfig.NetworkingMode == NetworkingMode::Mirrored);
1894+
WI_ASSERT(
1895+
m_vmConfig.NetworkingMode == NetworkingMode::Nat || m_vmConfig.NetworkingMode == NetworkingMode::Mirrored ||
1896+
m_vmConfig.NetworkingMode == NetworkingMode::VirtioProxy);
18941897

18951898
return SUCCEEDED_LOG(wsl::core::networking::DnsResolver::LoadDnsResolverMethods());
18961899
}

src/windows/wslc/services/SessionModel.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ SessionOptions::SessionOptions()
4242
{
4343
WI_SetFlag(m_sessionSettings.FeatureFlags, WslcFeatureFlagsVirtioFs);
4444
}
45+
46+
if (settings::User().Get<settings::Setting::SessionDnsTunneling>())
47+
{
48+
WI_SetFlag(m_sessionSettings.FeatureFlags, WslcFeatureFlagsDnsTunneling);
49+
}
4550
}
4651

4752
bool SessionOptions::IsElevated()

src/windows/wslc/settings/UserSettings.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ namespace details {
114114
return std::nullopt;
115115
}
116116

117+
WSLC_VALIDATE_SETTING(SessionDnsTunneling)
118+
{
119+
return value;
120+
}
121+
117122
#undef WSLC_VALIDATE_SETTING
118123

119124
} // namespace details

0 commit comments

Comments
 (0)