Implement DNS tunelling support for WSLA (#13651)

This commit is contained in:
Blue 2025-10-30 15:24:04 -07:00 committed by GitHub
parent cedbb94d36
commit 8b62d5a662
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 57 additions and 8 deletions

View File

@ -16,6 +16,7 @@ Abstract:
#include "hcs_schema.h"
#include "NatNetworking.h"
#include "WSLAUserSession.h"
#include "DnsResolver.h"
using namespace wsl::windows::common;
using helpers::WindowsBuildNumbers;
@ -324,21 +325,33 @@ void WSLAVirtualMachine::ConfigureNetworking()
else if (m_settings.NetworkingMode == WslNetworkingModeNAT)
{
// Launch GNS
// WSLA-TODO: Using fd=4 here seems to hang gns. There's probably a hardcoded file descriptor somewhere that's causing
// so using 1000 for now.
std::vector<WSLA_PROCESS_FD> fds(1);
fds[0].Fd = 1000;
fds[0].Type = WslFdType::WslFdTypeDefault;
WSLA_PROCESS_FD fd{};
fd.Fd = 3;
fd.Type = WslFdType::WslFdTypeDefault;
std::vector<const char*> cmd{"/gns", LX_INIT_GNS_SOCKET_ARG, "1000"};
// If DNS tunnelling is enabled, use an additional for its channel.
if (m_settings.EnableDnsTunneling)
{
fds.emplace_back(WSLA_PROCESS_FD{.Fd = 1001, .Type = WslFdType::WslFdTypeDefault});
cmd.emplace_back(LX_INIT_GNS_DNS_SOCKET_ARG);
cmd.emplace_back("1001");
cmd.emplace_back(LX_INIT_GNS_DNS_TUNNELING_IP);
cmd.emplace_back(LX_INIT_DNS_TUNNELING_IP_ADDRESS);
THROW_IF_FAILED(wsl::core::networking::DnsResolver::LoadDnsResolverMethods());
}
std::vector<const char*> cmd{"/gns", LX_INIT_GNS_SOCKET_ARG, "3"};
WSLA_CREATE_PROCESS_OPTIONS options{};
options.Executable = "/init";
options.CommandLine = cmd.data();
options.CommandLineCount = static_cast<ULONG>(cmd.size());
std::vector<HANDLE> socketHandles(2);
WSLA_CREATE_PROCESS_RESULT result{};
auto sockets = CreateLinuxProcessImpl(&options, 1, &fd, &result);
auto sockets = CreateLinuxProcessImpl(&options, static_cast<DWORD>(fds.size()), fds.data(), &result);
THROW_HR_IF(E_FAIL, result.Errno != 0);
@ -353,7 +366,11 @@ void WSLAVirtualMachine::ConfigureNetworking()
// TODO: DNS Tunneling support
m_networkEngine = std::make_unique<wsl::core::NatNetworking>(
m_computeSystem.get(), wsl::core::NatNetworking::CreateNetwork(config), std::move(sockets[0]), config, wil::unique_socket{});
m_computeSystem.get(),
wsl::core::NatNetworking::CreateNetwork(config),
std::move(sockets[0]),
config,
sockets.size() > 1 ? std::move(sockets[1]) : wil::unique_socket{});
m_networkEngine->Initialize();

View File

@ -99,6 +99,7 @@ struct _VIRTUAL_MACHINE_SETTINGS {
BOOL EnableDebugShell;
BOOL EnableEarlyBootDmesg;
BOOL EnableGPU;
BOOL EnableDnsTunnelling;
} VIRTUAL_MACHINE_SETTINGS;

View File

@ -520,6 +520,37 @@ class WSLATests
VERIFY_ARE_EQUAL(RunCommand(vm.get(), {"/bin/grep", "-iF", "nameserver", "/etc/resolv.conf"}), 0);
}
TEST_METHOD(NATNetworkingWithDnsTunneling)
{
WSL2_TEST_ONLY();
WslVirtualMachineSettings settings{};
settings.CPU.CpuCount = 4;
settings.DisplayName = L"WSLA";
settings.Memory.MemoryMb = 2048;
settings.Options.BootTimeoutMs = 30 * 1000;
settings.Networking.Mode = WslNetworkingModeNAT;
settings.Networking.DnsTunneling = true;
auto vm = CreateVm(&settings);
// Validate that eth0 has an ip address
VERIFY_ARE_EQUAL(
RunCommand(
vm.get(),
{"/bin/bash",
"-c",
"ip a show dev eth0 | grep -iF 'inet ' | grep -E '[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}'"}),
0);
// Verify that /etc/resolv.conf is correctly configured.
auto [pid, in, out, err] = LaunchCommand(vm.get(), {"/bin/grep", "-iF", "nameserver ", "/etc/resolv.conf"});
auto output = ReadToString((SOCKET)out.get());
VERIFY_ARE_EQUAL(output, std::format("nameserver {}\n", LX_INIT_DNS_TUNNELING_IP_ADDRESS));
}
TEST_METHOD(OpenFiles)
{
WSL2_TEST_ONLY();