@samitouri / QOSAMI-WSL / commits / c5fb4aa6

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