master
cpp 540 lines 23.3 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 WslCoreConfig.cpp
8
9 Abstract:
10
11 This file contains the WSL Core VM configuration helper class definition.
12
13 --*/
14
15 #include "precomp.h"
16 #include "WslCoreConfig.h"
17 #include "helpers.hpp"
18 #include "Localization.h"
19 #include "WslCoreFirewallSupport.h"
20 #include "WslCoreNetworkingSupport.h"
21
22 constexpr auto c_natGatewayAddress = L"NatGatewayIpAddress";
23 constexpr auto c_natNetwork = L"NatNetwork";
24 constexpr auto c_natIpAddress = L"NatIpAddress";
25
26 wsl::core::Config::Config(_In_opt_ LPCWSTR Path, _In_opt_ HANDLE UserToken)
27 {
28 ParseConfigFile(Path, UserToken);
29 Initialize(UserToken);
30 }
31
32 void wsl::core::Config::ParseConfigFile(_In_opt_ LPCWSTR ConfigFilePath, _In_opt_ HANDLE UserToken)
33 {
34 windows::common::ExecutionContext context(windows::common::ParseConfig);
35
36 auto parseIgnoredPorts = [&](const char* name, const char* value, const wchar_t* fileName, unsigned long fileLine) {
37 const auto ignoredPortsVector = wsl::shared::string::Split(std::string{value}, ',');
38 for (const auto& portString : ignoredPortsVector)
39 {
40 int number = 0;
41 if (FAILED(wil::ResultFromException([&]() { number = std::stoi(portString); })) || (number <= 0 || number > USHRT_MAX))
42 {
43 EMIT_USER_WARNING(shared::Localization::MessageConfigInvalidInteger(value, name, fileName, fileLine));
44 }
45 else
46 {
47 IgnoredPorts.insert(static_cast<uint16_t>(number));
48 }
49 }
50 };
51
52 auto parseDnsTunnelingIp = [&](const char* name, const char* value, const wchar_t* fileName, unsigned long fileLine) {
53 // If the IP is invalid, DNS tunneling is disabled.
54 in_addr address{};
55
56 if (inet_pton(AF_INET, value, &address) != 1)
57 {
58 EMIT_USER_WARNING(shared::Localization::MessageConfigInvalidIp(value, name, fileName, fileLine));
59 EnableDnsTunneling = false;
60 }
61 else
62 {
63 DnsTunnelingIpAddress = address.S_un.S_addr;
64 }
65 };
66
67 ConfigKeyPresence earlyBootLoggingPresent{};
68 ConfigKeyPresence macAddressPresent{};
69 bool enableFirewall = true;
70 std::wstring userKernelModules;
71
72 std::vector<ConfigKey> keys{
73 ConfigKey(ConfigSetting::Kernel, KernelPath),
74 ConfigKey(ConfigSetting::KernelCommandLine, KernelCommandLine),
75 ConfigKey(ConfigSetting::KernelModules, KernelModulesPath),
76 ConfigKey(ConfigSetting::Memory, MemoryString(MemorySizeBytes)),
77 ConfigKey(ConfigSetting::Processors, ProcessorCount),
78 ConfigKey(ConfigSetting::DebugConsole, EnableDebugConsole),
79 ConfigKey(ConfigSetting::EarlyBootLogging, EnableEarlyBootLogging, &earlyBootLoggingPresent),
80 ConfigKey(ConfigSetting::Swap, MemoryString(SwapSizeBytes)),
81 ConfigKey(ConfigSetting::SwapFile, SwapFilePath),
82 ConfigKey(ConfigSetting::LocalhostForwarding, EnableLocalhostRelay, &LocalhostRelayConfigPresence),
83 ConfigKey(ConfigSetting::NestedVirtualization, EnableNestedVirtualization),
84 ConfigKey(ConfigSetting::Virtio9p, EnableVirtio9p),
85 ConfigKey(ConfigSetting::Virtiofs, EnableVirtioFs),
86 ConfigKey(ConfigSetting::KernelDebugPort, KernelDebugPort),
87 ConfigKey(ConfigSetting::GpuSupport, EnableGpuSupport),
88 ConfigKey(ConfigSetting::GuiApplications, EnableGuiApps),
89 ConfigKey(ConfigSetting::SystemDistro, SystemDistroPath),
90 ConfigKey(ConfigSetting::Telemetry, EnableTelemetry),
91 ConfigKey(ConfigSetting::VmIdleTimeout, VmIdleTimeout),
92 ConfigKey(ConfigSetting::DebugConsoleLogFile, DebugConsoleLogFile),
93 ConfigKey(ConfigSetting::KernelBootTimeout, KernelBootTimeout),
94 ConfigKey(ConfigSetting::DistributionStartTimeout, DistributionStartTimeout),
95 ConfigKey(ConfigSetting::Virtio, EnableVirtio),
96 ConfigKey(ConfigSetting::HostFileSystemAccess, EnableHostFileSystemAccess),
97 ConfigKey(ConfigSetting::MountDeviceTimeout, MountDeviceTimeout),
98 ConfigKey(ConfigSetting::HardwarePerformanceCounters, EnableHardwarePerformanceCounters),
99 ConfigKey(ConfigSetting::VmSwitch, VmSwitch),
100 ConfigKey(ConfigSetting::MacAddress, MacAddress, &macAddressPresent),
101 ConfigKey(ConfigSetting::Dhcp, EnableDhcp),
102 ConfigKey(ConfigSetting::DhcpTimeout, DhcpTimeout),
103 ConfigKey(ConfigSetting::Ipv6, EnableIpv6),
104 ConfigKey(ConfigSetting::DnsProxy, EnableDnsProxy),
105 ConfigKey(ConfigSetting::SafeMode, EnableSafeMode),
106 ConfigKey(ConfigSetting::DefaultVhdSize, MemoryString(VhdSizeBytes)),
107 ConfigKey(ConfigSetting::CrashDumpFolder, CrashDumpFolder),
108 ConfigKey(ConfigSetting::MaxCrashDumpCount, MaxCrashDumpCount),
109 ConfigKey(ConfigSetting::DistributionInstallPath, DefaultDistributionLocation),
110 ConfigKey(ConfigSetting::InstanceIdleTimeout, InstanceIdleTimeout),
111 ConfigKey(ConfigSetting::LoadDefaultKernelModules, LoadDefaultKernelModules, &LoadKernelModulesPresence),
112 ConfigKey(ConfigSetting::LoadKernelModules, userKernelModules, &LoadKernelModulesPresence),
113 ConfigKey(ConfigSetting::IsolateDistroCgroup, IsolateDistroCgroup),
114
115 // Features that were previously experimental (the old header is maintained for compatibility).
116 ConfigKey({ConfigSetting::NetworkingMode, ConfigSetting::Experimental::NetworkingMode}, wsl::core::NetworkingModes, NetworkingMode, &NetworkingModePresence),
117 ConfigKey({ConfigSetting::DnsTunneling, ConfigSetting::Experimental::DnsTunneling}, EnableDnsTunneling, &DnsTunnelingConfigPresence),
118 ConfigKey({ConfigSetting::Firewall, ConfigSetting::Experimental::Firewall}, enableFirewall, &FirewallConfigPresence),
119 ConfigKey({ConfigSetting::AutoProxy, ConfigSetting::Experimental::AutoProxy}, EnableAutoProxy),
120
121 // Experimental features.
122 ConfigKey(ConfigSetting::Experimental::AutoMemoryReclaim, wsl::core::MemoryReclaimModes, MemoryReclaim),
123 ConfigKey(ConfigSetting::Experimental::SparseVhd, EnableSparseVhd),
124 ConfigKey(ConfigSetting::Experimental::BestEffortDnsParsing, BestEffortDnsParsing),
125 ConfigKey(ConfigSetting::Experimental::DnsTunnelingIpAddress, std::move(parseDnsTunnelingIp)),
126 ConfigKey(ConfigSetting::Experimental::InitialAutoProxyTimeout, InitialAutoProxyTimeout),
127 ConfigKey(ConfigSetting::Experimental::IgnoredPorts, std::move(parseIgnoredPorts)),
128 ConfigKey(ConfigSetting::Experimental::HostAddressLoopback, EnableHostAddressLoopback),
129 ConfigKey(ConfigSetting::Experimental::SetVersionDebug, SetVersionDebug),
130 ConfigKey(ConfigSetting::Experimental::Swiotlb, MemoryString(SwiotlbSizeBytes)),
131 ConfigKey(ConfigSetting::Experimental::VirtioFsAggregateShares, EnableVirtioFsAggregateShares)};
132
133 wil::unique_file ConfigFile;
134 if (ConfigFilePath != nullptr)
135 {
136 ConfigFile.reset(_wfopen(ConfigFilePath, L"rt,ccs=UTF-8"));
137 if (!ConfigFile)
138 {
139 const auto error = _doserrno;
140 LOG_WIN32_MSG(error, "opening config file failed");
141 if (error != ERROR_FILE_NOT_FOUND)
142 {
143 EMIT_USER_WARNING(wsl::shared::Localization::MessageFailedToOpenConfigFile(
144 ConfigFilePath, wsl::windows::common::wslutil::GetErrorString(HRESULT_FROM_WIN32(error))));
145 }
146 }
147 }
148
149 // Parse the configuration keys.
150 WI_VERIFY(::ParseConfigFile(keys, ConfigFile.get(), (CFG_SKIP_INVALID_LINES | CFG_SKIP_UNKNOWN_VALUES), ConfigFilePath) == 0);
151
152 // Hyper-V firewall must always be configured for Mirrored Mode.
153 // For NAT mode, we use the experimental config to determine if Hyper-V firewall should be enabled
154 if ((NetworkingMode::Mirrored == NetworkingMode) || enableFirewall)
155 {
156 FirewallConfig.Enable();
157 }
158
159 if (EnableDnsTunneling && !DnsTunnelingIpAddress.has_value())
160 {
161 in_addr address{};
162 WI_VERIFY(inet_pton(AF_INET, LX_INIT_DNS_TUNNELING_IP_ADDRESS, &address) == 1);
163
164 DnsTunnelingIpAddress = address.S_un.S_addr;
165 }
166
167 if (macAddressPresent == ConfigKeyPresence::Absent && NetworkingMode == NetworkingMode::Bridged)
168 {
169 // Generate a random mac address if unspecified, so that the VM retains the same if restarted
170 const std::independent_bits_engine<std::default_random_engine, 16, unsigned short> random;
171
172 // independent_bits_engine doesn't support unsigned char on MSVC
173 auto* macAddressShort = reinterpret_cast<unsigned short*>(MacAddress.data());
174 std::generate(macAddressShort, macAddressShort + 3, random);
175
176 // Clear the multicast bit
177 MacAddress[0] &= ~1;
178 // Set the locally generated bit.
179 MacAddress[0] |= 2;
180 }
181
182 // Enable early boot logging if the debug console is enabled, unless explicitly disabled
183 if (EnableDebugConsole || !DebugConsoleLogFile.empty())
184 {
185 if (earlyBootLoggingPresent == ConfigKeyPresence::Absent)
186 {
187 EnableEarlyBootLogging = true;
188 }
189 }
190
191 if (CrashDumpFolder.empty() && MaxCrashDumpCount >= 0)
192 {
193 CrashDumpFolder = wsl::windows::common::filesystem::GetTempFolderPath(UserToken) / "wsl-crashes";
194 }
195
196 if (DefaultDistributionLocation.empty())
197 {
198 DefaultDistributionLocation = wsl::windows::common::filesystem::GetLocalAppDataPath(UserToken) / "wsl";
199 }
200
201 auto kernelModules =
202 LoadDefaultKernelModules ? std::vector<std::wstring>{L"tun", L"ip_tables", L"br_netfilter"} : std::vector<std::wstring>{};
203
204 if (!userKernelModules.empty())
205 {
206 for (const auto& e : wsl::shared::string::Split(userKernelModules, L','))
207 {
208 kernelModules.emplace_back(std::move(e));
209 }
210 }
211
212 KernelModulesList = wsl::shared::string::Join(kernelModules, L',');
213 }
214
215 void wsl::core::Config::SaveNetworkingSettings(_In_opt_ HANDLE UserToken) const
216 try
217 {
218 if (NetworkingMode != NetworkingMode::Nat)
219 {
220 return;
221 }
222
223 const auto machineKey = wsl::windows::common::registry::OpenLxssMachineKey(KEY_SET_VALUE);
224 wsl::windows::common::registry::WriteString(machineKey.get(), nullptr, c_natGatewayAddress, NatGateway.c_str());
225 wsl::windows::common::registry::WriteString(machineKey.get(), nullptr, c_natNetwork, NatNetwork.c_str());
226
227 auto runAsUser = wil::impersonate_token(UserToken);
228 const auto userKey = wsl::windows::common::registry::OpenLxssUserKey();
229 wsl::windows::common::registry::WriteString(userKey.get(), nullptr, c_natIpAddress, NatIpAddress.c_str());
230 }
231 CATCH_LOG();
232
233 unsigned long wsl::core::Config::WriteConfigFile(_In_ LPCWSTR ConfigFilePath, _In_ ConfigKey KeyToWrite, _In_ bool RemoveKey)
234 {
235 windows::common::ExecutionContext context(windows::common::ParseConfig);
236
237 if (!ConfigFilePath)
238 {
239 return ERROR_INVALID_PARAMETER;
240 }
241
242 // Open file for reading & writing. This assumes the file exists.
243 wil::unique_file ConfigFile(_wfopen(ConfigFilePath, L"r+t,ccs=UTF-8"));
244 const auto win32Error = _doserrno;
245 if (!ConfigFile && win32Error != ERROR_FILE_NOT_FOUND)
246 {
247 return win32Error;
248 }
249
250 // Since we aren't parsing in the config file, we don't need to pass in the known keys.
251 std::vector<ConfigKey> keys{};
252 std::wstring configFileOutput{};
253 auto result = ::ParseConfigFile(
254 keys, ConfigFile.get(), (CFG_SKIP_INVALID_LINES | CFG_SKIP_UNKNOWN_VALUES), ConfigFilePath, configFileOutput, KeyToWrite, RemoveKey);
255 if (result != 0)
256 {
257 return ERROR_READ_FAULT;
258 }
259
260 // If the config file didn't exist/wasn't opened, open it for writing.
261 if (!ConfigFile)
262 {
263 ConfigFile.reset(_wfopen(ConfigFilePath, L"wt,ccs=UTF-8"));
264 if (!ConfigFile)
265 {
266 return _doserrno;
267 }
268 }
269
270 // Move file pointer to beginning of file, write out the new config file, and truncate the file.
271 rewind(ConfigFile.get());
272 result = fputws(configFileOutput.c_str(), ConfigFile.get());
273 if (result == WEOF)
274 {
275 return ERROR_WRITE_FAULT;
276 }
277
278 const auto fileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(ConfigFile.get())));
279 if (SetEndOfFile(fileHandle) != TRUE)
280 {
281 return GetLastError();
282 }
283
284 return ERROR_SUCCESS;
285 }
286
287 #define VALIDATE_CONFIG_OPTION(_dependency, _setting, _value) \
288 { \
289 LOG_HR_IF(E_INVALIDARG, _dependency && (_setting != _value)); \
290 _setting = _value; \
291 }
292
293 void wsl::core::Config::Initialize(_In_opt_ HANDLE UserToken)
294 {
295 // Determine the maximum number of processors that can be added to the VM.
296 // If the user did not supply a processor count, use the maximum.
297 MaximumProcessorCount = wsl::windows::common::wslutil::GetLogicalProcessorCount();
298 if (ProcessorCount <= 0)
299 {
300 ProcessorCount = MaximumProcessorCount;
301 }
302 else if (ProcessorCount > MaximumProcessorCount)
303 {
304 EMIT_USER_WARNING(wsl::shared::Localization::MessageTooManyProcessors(ProcessorCount, MaximumProcessorCount));
305 ProcessorCount = MaximumProcessorCount;
306 }
307
308 // Determine how much memory to add to the VM. If the user did not specify a value,
309 // use 50% of host memory. Otherwise, ensure the value falls within 256MB and the total system memory.
310 MEMORYSTATUSEX memInfo{sizeof(MEMORYSTATUSEX)};
311 THROW_IF_WIN32_BOOL_FALSE(GlobalMemoryStatusEx(&memInfo));
312
313 MaximumMemorySizeBytes = memInfo.ullTotalPhys;
314 if (MemorySizeBytes == 0)
315 {
316 MemorySizeBytes = (MaximumMemorySizeBytes / 2);
317 }
318 else
319 {
320 MemorySizeBytes = std::max<UINT64>(MemorySizeBytes, (256 * _1MB));
321 MemorySizeBytes = std::min<UINT64>(MemorySizeBytes, MaximumMemorySizeBytes);
322 }
323
324 // Use the user-defined swap size if one was specified; otherwise, set to 25%
325 // the memory size rounded up to the nearest GB.
326 //
327 // N.B. This heuristic is modeled after Red Hat and Ubuntu's recommended swap size.
328 if (SwapSizeBytes == UINT64_MAX)
329 {
330 SwapSizeBytes = ((MemorySizeBytes / 4 + _1GB - 1) & ~(_1GB - 1));
331 }
332
333 // Apply machine-wide policies to the configuration.
334 auto key = wsl::windows::policies::OpenPoliciesKey();
335 auto applyOverride = [&key](LPCWSTR ValueName, LPCWSTR SettingName, auto& value) {
336 if (value != std::remove_reference_t<decltype(value)>{} && !wsl::windows::policies::IsFeatureAllowed(key.get(), ValueName))
337 {
338 value = std::remove_reference_t<decltype(value)>{};
339 EMIT_USER_WARNING(wsl::shared::Localization::MessageSettingOverriddenByPolicy(SettingName));
340 }
341 };
342
343 applyOverride(wsl::windows::policies::c_allowCustomKernelUserSetting, L"wsl2.kernel", KernelPath);
344 applyOverride(wsl::windows::policies::c_allowCustomKernelUserSetting, L"wsl2.kernelModules", KernelModulesPath);
345 applyOverride(wsl::windows::policies::c_allowCustomSystemDistroUserSetting, L"wsl2.systemDistro", SystemDistroPath);
346 applyOverride(wsl::windows::policies::c_allowCustomKernelCommandLineUserSetting, L"wsl2.kernelCommandLine", KernelCommandLine);
347 applyOverride(wsl::windows::policies::c_allowKernelDebuggingUserSetting, L"wsl2.kernelDebugPort", KernelDebugPort);
348 applyOverride(wsl::windows::policies::c_allowNestedVirtualizationUserSetting, L"wsl2.nestedVirtualization", EnableNestedVirtualization);
349
350 if (!wsl::windows::policies::IsFeatureAllowed(key.get(), wsl::windows::policies::c_allowDebugShellUserSetting))
351 {
352 // N.B. The warning for debug shell is handled in wsl.exe.
353 EnableDebugShell = false;
354 }
355
356 // Read the policy key for default networking mode.
357 auto defaultNetworkingMode = wsl::core::NetworkingMode::Nat;
358 const auto setting = wsl::windows::policies::GetPolicyValue(key.get(), wsl::windows::policies::c_defaultNetworkingMode);
359 if (setting.has_value())
360 {
361 switch (setting.value())
362 {
363 case wsl::core::NetworkingMode::None:
364 case wsl::core::NetworkingMode::Nat:
365 case wsl::core::NetworkingMode::Mirrored:
366 case wsl::core::NetworkingMode::Consomme:
367 defaultNetworkingMode = static_cast<wsl::core::NetworkingMode>(setting.value());
368 break;
369
370 case wsl::core::NetworkingMode::Bridged: // Bridged requires additional configuration.
371 default:
372 LOG_HR_MSG(E_UNEXPECTED, "Invalid default networking mode: %d", setting.value());
373 break;
374 }
375 }
376
377 // Determine if the user is allowed to override the networking mode.
378 //
379 // N.B. User can always disable networking entirely.
380 if (NetworkingModePresence == ConfigKeyPresence::Present)
381 {
382 if ((!wsl::windows::policies::IsFeatureAllowed(key.get(), wsl::windows::policies::c_allowCustomNetworkingModeUserSetting)) &&
383 (NetworkingMode != wsl::core::NetworkingMode::None) && (NetworkingMode != defaultNetworkingMode))
384 {
385 NetworkingMode = defaultNetworkingMode;
386 EMIT_USER_WARNING(wsl::shared::Localization::MessageSettingOverriddenByPolicy(L"wsl2.networkingMode"));
387 }
388 }
389 else
390 {
391 NetworkingMode = defaultNetworkingMode;
392 }
393
394 // Mirrored mode has Hyper-V Firewall always on - we ignore the local setting regardless in this case.
395 if (NetworkingMode != wsl::core::NetworkingMode::Mirrored)
396 {
397 if (!FirewallConfig.Enabled() &&
398 !wsl::windows::policies::IsFeatureAllowed(key.get(), wsl::windows::policies::c_allowCustomFirewallUserSetting))
399 {
400 FirewallConfig.Enable();
401 EMIT_USER_WARNING(wsl::shared::Localization::MessageSettingOverriddenByPolicy(L"wsl2.firewall"));
402 }
403 }
404
405 // Due to an issue with Global Secure Access Client, do not use DNS tunneling if the service is present.
406 if (EnableDnsTunneling)
407 {
408 try
409 {
410 if (wsl::windows::common::helpers::IsServiceRunning(L"GlobalSecureAccessTunnelingService"))
411 {
412 if (DnsTunnelingConfigPresence == ConfigKeyPresence::Present)
413 {
414 EMIT_USER_WARNING(wsl::shared::Localization::MessageDnsTunnelingDisabled());
415 }
416
417 EnableDnsTunneling = false;
418 }
419 }
420 CATCH_LOG()
421 }
422
423 // Ensure that settings are consistent (disable features that require other features that are not present).
424 if (EnableSafeMode)
425 {
426 EMIT_USER_WARNING(wsl::shared::Localization::MessageSafeModeEnabled());
427 VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableHostFileSystemAccess, false);
428 VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableNestedVirtualization, false);
429 VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableHardwarePerformanceCounters, false);
430 VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableGpuSupport, false);
431 VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableVirtio, false);
432 VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableGuiApps, false);
433 VALIDATE_CONFIG_OPTION(EnableSafeMode, SwapSizeBytes, 0);
434 VALIDATE_CONFIG_OPTION(EnableSafeMode, KernelPath, std::filesystem::path{});
435 VALIDATE_CONFIG_OPTION(EnableSafeMode, KernelModulesPath, std::filesystem::path{});
436 VALIDATE_CONFIG_OPTION(EnableSafeMode, NetworkingMode, NetworkingMode::None);
437 VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableDnsTunneling, false);
438 VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableAutoProxy, false);
439 }
440
441 if (!EnableVirtio)
442 {
443 VALIDATE_CONFIG_OPTION(!EnableVirtio, EnableVirtio9p, false);
444 VALIDATE_CONFIG_OPTION(!EnableVirtio, EnableVirtioFs, false);
445 VALIDATE_CONFIG_OPTION(!EnableVirtio, SwiotlbSizeBytes, 0);
446
447 if (NetworkingMode == NetworkingMode::Consomme)
448 {
449 NetworkingMode = (defaultNetworkingMode == NetworkingMode::Consomme) ? NetworkingMode::None : NetworkingMode::Nat;
450 EMIT_USER_WARNING(wsl::shared::Localization::MessageConsommeRequiresVirtio(ToString(NetworkingMode)));
451 }
452 }
453
454 if (EnableVirtio9p)
455 {
456 EMIT_USER_WARNING(wsl::shared::Localization::MessageConfigVirtio9pDisabled());
457 EnableVirtio9p = false;
458 }
459
460 // Compute a default swiotlb config only when a virtio device that requires bounce buffers is present.
461 // N.B. Must run after policy overrides so networking/fs modes reflect final values.
462 if (SwiotlbSizeBytes == 0 && (EnableVirtioFs || EnableVirtio9p || (NetworkingMode == NetworkingMode::Consomme)))
463 {
464 SwiotlbSizeBytes = wsl::windows::common::helpers::ComputeDefaultSwiotlbConfig(MemorySizeBytes);
465 }
466
467 if (NetworkingMode != NetworkingMode::Nat && NetworkingMode != NetworkingMode::Mirrored && NetworkingMode != NetworkingMode::Consomme)
468 {
469 VALIDATE_CONFIG_OPTION(
470 (NetworkingMode != NetworkingMode::Nat && NetworkingMode != NetworkingMode::Mirrored && NetworkingMode != NetworkingMode::Consomme),
471 EnableDnsTunneling,
472 false);
473 }
474
475 if (!EnableDnsTunneling)
476 {
477 VALIDATE_CONFIG_OPTION(!EnableDnsTunneling, BestEffortDnsParsing, false);
478 VALIDATE_CONFIG_OPTION(!EnableDnsTunneling, DnsTunnelingIpAddress, std::optional<uint32_t>{});
479 }
480
481 if (NetworkingMode != NetworkingMode::Mirrored)
482 {
483 VALIDATE_CONFIG_OPTION((NetworkingMode != NetworkingMode::Mirrored), IgnoredPorts, std::set<uint16_t>{});
484 VALIDATE_CONFIG_OPTION((NetworkingMode != NetworkingMode::Mirrored), EnableHostAddressLoopback, false);
485 }
486
487 // Load NAT configuration from the registry.
488 // N.B. This must be done after all networking mode adjustments (e.g. Consomme -> NAT fallback).
489 if (NetworkingMode == wsl::core::NetworkingMode::Nat)
490 {
491 try
492 {
493 const auto machineKey = wsl::windows::common::registry::OpenLxssMachineKey();
494 NatGateway = wsl::windows::common::registry::ReadString(machineKey.get(), nullptr, c_natGatewayAddress, L"");
495 NatNetwork = wsl::windows::common::registry::ReadString(machineKey.get(), nullptr, c_natNetwork, L"");
496
497 auto runAsUser = wil::impersonate_token(UserToken);
498 const auto userKey = wsl::windows::common::registry::OpenLxssUserKey();
499 NatIpAddress = wsl::windows::common::registry::ReadString(userKey.get(), nullptr, c_natIpAddress, L"");
500 }
501 CATCH_LOG()
502 }
503 }
504
505 GUID wsl::core::Config::NatNetworkId() const noexcept
506 {
507 // Identifier for the WSL virtual network: {b95d0c5e-57d4-412b-b571-18a81a16e005}
508 static constexpr GUID c_networkId = {0xb95d0c5e, 0x57d4, 0x412b, {0xb5, 0x71, 0x18, 0xa8, 0x1a, 0x16, 0xe0, 0x05}};
509
510 // Identifier for the WSL virtual network with Hyper-v firewall enabled: {790e58b4-7939-4434-9358-89ae7ddbe87e}
511 static constexpr GUID c_networkWithFirewallId = {0x790e58b4, 0x7939, 0x4434, {0x93, 0x58, 0x89, 0xae, 0x7d, 0xdb, 0xe8, 0x7e}};
512
513 return FirewallConfig.Enabled() ? c_networkWithFirewallId : c_networkId;
514 }
515
516 LPCWSTR wsl::core::Config::NatNetworkName() const noexcept
517 {
518 static constexpr auto c_networkName = L"WSL";
519 static constexpr auto c_networkWithFirewallName = L"WSL (Hyper-V firewall)";
520 return FirewallConfig.Enabled() ? c_networkWithFirewallName : c_networkName;
521 }
522
523 void wsl::core::FirewallConfiguration::Enable() noexcept
524 {
525 VmCreatorId = wsl::core::networking::c_wslFirewallVmCreatorId;
526 DefaultLoopbackPolicy = FirewallAction::Allow;
527 Rules = wsl::core::networking::MakeDefaultFirewallRuleConfiguration(networking::c_wslFirewallVmCreatorId);
528 }
529
530 void wsl::core::FirewallConfiguration::reset() noexcept
531 {
532 VmCreatorId.reset();
533 Rules.clear();
534 DefaultLoopbackPolicy = FirewallAction::Invalid;
535 }
536
537 bool wsl::core::FirewallConfiguration::Enabled() const noexcept
538 {
539 return VmCreatorId.has_value();
540 }