Enable DNS tunneling for VirtioProxy networking mode (#14461)
- Allow VirtioProxy to keep EnableDnsTunneling=true in config, but clear socket-specific options (BestEffortDnsParsing, DnsTunnelingIpAddress) - Suppress dedicated DNS tunneling hvsocket for VirtioProxy; tunneling is handled through the VirtioNetworking device host instead - Set DnsTunneling flag on VirtioNetworkingFlags so the device host knows to tunnel DNS - Expand SWIOTLB kernel cmdline to cover VirtioFs and VirtioProxy - Bump DeviceHost package to 1.1.39-0 - Add VirtioProxy DNS test coverage for tunneling on/off - Skip GuestPortIsReleasedV6 on Windows 10 Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Ben Hillis committed
Mar 18, 2026 at 15:31 UTC
c5fb4aa6394f16cdb7d002f44fde789a1618fb7e
3 files changed
+96
-53
src/windows/common/WslCoreConfig.cpp
+9
-5
@@ -474,15 +474,19 @@ void wsl::core::Config::Initialize(_In_opt_ HANDLE UserToken)
474
EnableVirtio9p = false;
475
}
476
477
- if (NetworkingMode != NetworkingMode::Nat && NetworkingMode != NetworkingMode::Mirrored)
477
+ if (NetworkingMode != NetworkingMode::Nat && NetworkingMode != NetworkingMode::Mirrored && NetworkingMode != NetworkingMode::VirtioProxy)
478
{
479
- VALIDATE_CONFIG_OPTION((NetworkingMode != NetworkingMode::Nat && NetworkingMode != NetworkingMode::Mirrored), EnableDnsTunneling, false);
479
+ VALIDATE_CONFIG_OPTION(
480
+ (NetworkingMode != NetworkingMode::Nat && NetworkingMode != NetworkingMode::Mirrored && NetworkingMode != NetworkingMode::VirtioProxy),
481
+ EnableDnsTunneling,
482
+ false);
483
}
484
482
- if (!EnableDnsTunneling)
485
+ if (!EnableDnsTunneling || NetworkingMode == NetworkingMode::VirtioProxy)
486
{
484
- VALIDATE_CONFIG_OPTION(!EnableDnsTunneling, BestEffortDnsParsing, false);
485
- VALIDATE_CONFIG_OPTION(!EnableDnsTunneling, DnsTunnelingIpAddress, std::optional<uint32_t>{});
487
+ VALIDATE_CONFIG_OPTION(!EnableDnsTunneling || NetworkingMode == NetworkingMode::VirtioProxy, BestEffortDnsParsing, false);
488
+ VALIDATE_CONFIG_OPTION(
489
+ !EnableDnsTunneling || NetworkingMode == NetworkingMode::VirtioProxy, DnsTunnelingIpAddress, std::optional<uint32_t>{});
490
}
491
492
if (NetworkingMode != NetworkingMode::Mirrored)
src/windows/service/exe/WslCoreVm.cpp
+5
-4
@@ -520,7 +520,7 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
520
message->MemoryReclaimMode = static_cast<LX_MINI_INIT_MEMORY_RECLAIM_MODE>(m_vmConfig.MemoryReclaim);
521
message->EnableDebugShell = m_vmConfig.EnableDebugShell;
522
message->EnableSafeMode = m_vmConfig.EnableSafeMode;
523
- message->EnableDnsTunneling = m_vmConfig.EnableDnsTunneling;
523
+ message->EnableDnsTunneling = m_vmConfig.EnableDnsTunneling && m_vmConfig.NetworkingMode != NetworkingMode::VirtioProxy;
524
message->DefaultKernel = m_defaultKernel;
525
message->KernelModulesDeviceId = m_kernelModulesDeviceId;
526
message.WriteString(message->HostnameOffset, wsl::windows::common::filesystem::GetLinuxHostName());
@@ -537,7 +537,7 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
537
538
// Create hvsocket connection for DNS tunneling if enabled.
539
wil::unique_socket dnsTunnelingSocket;
540
- if (m_vmConfig.EnableDnsTunneling)
540
+ if (message->EnableDnsTunneling)
541
{
542
dnsTunnelingSocket = AcceptConnection(m_vmConfig.KernelBootTimeout);
543
}
@@ -578,6 +578,7 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
578
{
579
wsl::core::VirtioNetworkingFlags flags = wsl::core::VirtioNetworkingFlags::Ipv6;
580
WI_SetFlagIf(flags, wsl::core::VirtioNetworkingFlags::LocalhostRelay, m_vmConfig.EnableLocalhostRelay);
581
+ WI_SetFlagIf(flags, wsl::core::VirtioNetworkingFlags::DnsTunneling, m_vmConfig.EnableDnsTunneling);
582
m_networkingEngine = std::make_unique<wsl::core::VirtioNetworking>(
583
std::move(gnsChannel), flags, LX_INIT_RESOLVCONF_FULL_HEADER, m_guestDeviceManager, m_userToken);
584
}
@@ -1555,8 +1556,8 @@ std::wstring WslCoreVm::GenerateConfigJson()
1556
// Enable timesync workaround to sync on resume from sleep in modern standby.
1557
kernelCmdLine += L" hv_utils.timesync_implicit=1";
1558
1558
- // If using virtio-9p, enable SWIOTLB as a perf optimization (will cause VM to consume 64MB more memory).
1559
- if (m_vmConfig.EnableVirtio9p)
1559
+ // If using virtio features, enable SWIOTLB as a perf optimization (will cause VM to consume 64MB more memory).
1560
+ if (m_vmConfig.EnableVirtio9p || m_vmConfig.EnableVirtioFs || m_vmConfig.NetworkingMode == NetworkingMode::VirtioProxy)
1561
{
1562
kernelCmdLine += L" swiotlb=force";
1563
}
test/windows/NetworkTests.cpp
+82
-44
@@ -809,6 +809,19 @@ class NetworkTests
809
VerifyDigDnsResolution(L"dig +short +time=5 SOA bing.com");
810
}
811
812
+ static void VerifyDnsResolutionDigV6()
813
+ {
814
+ if (!HostHasInternetConnectivity(AF_INET6))
815
+ {
816
+ LogSkipped("Host does not have IPv6 internet connectivity. Skipping...");
817
+ return;
818
+ }
819
+
820
+ // Test AAAA record resolution (IPv6) with both UDP and TCP
821
+ VerifyDigDnsResolution(L"dig +short +time=5 AAAA bing.com");
822
+ VerifyDigDnsResolution(L"dig +tcp +short +time=5 AAAA bing.com");
823
+ }
824
+
825
static void VerifyDnsQueries()
826
{
827
// query for A/IPv4 records
@@ -4868,33 +4881,6 @@ class VirtioProxyTests
4881
auto tcpPort = NetworkTests::BindGuestPort(L"TCP4-LISTEN:2345", true);
4882
}
4883
4871
- TEST_METHOD(DnsResolutionBasic)
4872
- {
4873
- VIRTIOPROXY_TEST_ONLY();
4874
-
4875
- m_config->Update(LxssGenerateTestConfig({.networkingMode = wsl::core::NetworkingMode::VirtioProxy}));
4876
-
4877
- NetworkTests::VerifyDnsResolutionBasic();
4878
- }
4879
-
4880
- TEST_METHOD(DnsResolutionDig)
4881
- {
4882
- VIRTIOPROXY_TEST_ONLY();
4883
-
4884
- m_config->Update(LxssGenerateTestConfig({.networkingMode = wsl::core::NetworkingMode::VirtioProxy}));
4885
-
4886
- NetworkTests::VerifyDnsResolutionDig();
4887
- }
4888
-
4889
- TEST_METHOD(DnsResolutionRecordTypes)
4890
- {
4891
- VIRTIOPROXY_TEST_ONLY();
4892
-
4893
- m_config->Update(LxssGenerateTestConfig({.networkingMode = wsl::core::NetworkingMode::VirtioProxy}));
4894
-
4895
- NetworkTests::VerifyDnsResolutionRecordTypes();
4896
- }
4897
-
4884
TEST_METHOD(PortZeroBindIsTracked)
4885
{
4886
VIRTIOPROXY_TEST_ONLY();
@@ -4988,26 +4974,10 @@ class VirtioProxyTests
4974
}
4975
}
4976
4991
- TEST_METHOD(DnsResolutionDigV6)
4992
- {
4993
- VIRTIOPROXY_TEST_ONLY();
4994
-
4995
- m_config->Update(LxssGenerateTestConfig({.networkingMode = wsl::core::NetworkingMode::VirtioProxy}));
4996
-
4997
- if (!NetworkTests::HostHasInternetConnectivity(AF_INET6))
4998
- {
4999
- LogSkipped("Host does not have IPv6 internet connectivity. Skipping...");
5000
- return;
5001
- }
5002
-
5003
- // Test AAAA record resolution (IPv6) with both UDP and TCP
5004
- NetworkTests::VerifyDigDnsResolution(L"dig +short +time=5 AAAA bing.com");
5005
- NetworkTests::VerifyDigDnsResolution(L"dig +tcp +short +time=5 AAAA bing.com");
5006
- }
5007
-
4977
TEST_METHOD(GuestPortIsReleasedV6)
4978
{
4979
VIRTIOPROXY_TEST_ONLY();
4980
+ WINDOWS_11_TEST_ONLY();
4981
4982
m_config->Update(LxssGenerateTestConfig({.networkingMode = wsl::core::NetworkingMode::VirtioProxy}));
4983
@@ -5057,5 +5027,73 @@ class VirtioProxyTests
5027
const std::wregex v6Pattern(L"(.|\\n)*nameserver [0-9a-fA-F:]+\\n(.|\\n)*");
5028
VERIFY_IS_TRUE(std::regex_match(out, v6Pattern));
5029
}
5030
+
5031
+ TEST_METHOD(DnsResolutionBasicDnsTunneling)
5032
+ {
5033
+ VIRTIOPROXY_TEST_ONLY();
5034
+ DNS_TUNNELING_TEST_ONLY();
5035
+
5036
+ m_config->Update(LxssGenerateTestConfig({.networkingMode = wsl::core::NetworkingMode::VirtioProxy, .dnsTunneling = true}));
5037
+ NetworkTests::VerifyDnsResolutionBasic();
5038
+ }
5039
+
5040
+ TEST_METHOD(DnsResolutionDigDnsTunneling)
5041
+ {
5042
+ VIRTIOPROXY_TEST_ONLY();
5043
+ DNS_TUNNELING_TEST_ONLY();
5044
+
5045
+ m_config->Update(LxssGenerateTestConfig({.networkingMode = wsl::core::NetworkingMode::VirtioProxy, .dnsTunneling = true}));
5046
+ NetworkTests::VerifyDnsResolutionDig();
5047
+ }
5048
+
5049
+ TEST_METHOD(DnsResolutionRecordTypesDnsTunneling)
5050
+ {
5051
+ VIRTIOPROXY_TEST_ONLY();
5052
+ DNS_TUNNELING_TEST_ONLY();
5053
+
5054
+ m_config->Update(LxssGenerateTestConfig({.networkingMode = wsl::core::NetworkingMode::VirtioProxy, .dnsTunneling = true}));
5055
+ NetworkTests::VerifyDnsResolutionRecordTypes();
5056
+ }
5057
+
5058
+ TEST_METHOD(DnsResolutionDigV6DnsTunneling)
5059
+ {
5060
+ VIRTIOPROXY_TEST_ONLY();
5061
+ DNS_TUNNELING_TEST_ONLY();
5062
+
5063
+ m_config->Update(LxssGenerateTestConfig({.networkingMode = wsl::core::NetworkingMode::VirtioProxy, .dnsTunneling = true}));
5064
+ NetworkTests::VerifyDnsResolutionDigV6();
5065
+ }
5066
+
5067
+ TEST_METHOD(DnsResolutionBasic)
5068
+ {
5069
+ VIRTIOPROXY_TEST_ONLY();
5070
+
5071
+ m_config->Update(LxssGenerateTestConfig({.networkingMode = wsl::core::NetworkingMode::VirtioProxy, .dnsTunneling = false}));
5072
+ NetworkTests::VerifyDnsResolutionBasic();
5073
+ }
5074
+
5075
+ TEST_METHOD(DnsResolutionDig)
5076
+ {
5077
+ VIRTIOPROXY_TEST_ONLY();
5078
+
5079
+ m_config->Update(LxssGenerateTestConfig({.networkingMode = wsl::core::NetworkingMode::VirtioProxy, .dnsTunneling = false}));
5080
+ NetworkTests::VerifyDnsResolutionDig();
5081
+ }
5082
+
5083
+ TEST_METHOD(DnsResolutionRecordTypes)
5084
+ {
5085
+ VIRTIOPROXY_TEST_ONLY();
5086
+
5087
+ m_config->Update(LxssGenerateTestConfig({.networkingMode = wsl::core::NetworkingMode::VirtioProxy, .dnsTunneling = false}));
5088
+ NetworkTests::VerifyDnsResolutionRecordTypes();
5089
+ }
5090
+
5091
+ TEST_METHOD(DnsResolutionDigV6)
5092
+ {
5093
+ VIRTIOPROXY_TEST_ONLY();
5094
+
5095
+ m_config->Update(LxssGenerateTestConfig({.networkingMode = wsl::core::NetworkingMode::VirtioProxy, .dnsTunneling = false}));
5096
+ NetworkTests::VerifyDnsResolutionDigV6();
5097
+ }
5098
};
5099
} // namespace NetworkTests