WSL/src/windows/common/WslCoreConfig.cpp
Josh Soref abce91d14b
Spelling (#12954)
* link: Collect WSL logs (recommended method)

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: Advanced Authoring Tests in C++

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: CMake Documentation and Community

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: Collect WSL logs for networking issues

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: Collect WSL logs (recommended method)

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: ; otherwise,

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: a

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: access

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: accessible

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: across

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: actively

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: adapters

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: address

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: addresses

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: and

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: appropriate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: argument

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: associated

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: attach

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: available

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: beginning

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: between

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: binaries

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: bound

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: buffer

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: buffers

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: cannot

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: canonical

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: capabilities

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: case-insensitive

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: case-sensitive

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: certified

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: command

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: committer

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: communication

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: complains

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: configuration

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: consumed

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: continue

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: converted

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: currently

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: customers

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: daemon

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: deferred

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: definitions

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: delimiter

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: delivered

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: dellink

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: derived

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: descriptor

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: destined

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: destruct

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: destructible

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: destructor

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: detach

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: differentiate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: directories

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: disassociate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: disposition

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: distribution

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: distro

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: duping

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: emitted

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: empty

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: environment

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: every time

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: exclusive

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: expected

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: expire

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: explicitly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: fall back

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: false

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: fastfail

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: filesystem

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: first

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: followed

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: for

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: functionality

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: functionally

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: github

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: greater

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: guarantee

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: guaranteed

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: handles

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: hangup

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: hierarchy

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: hogwarts

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: hydrated

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: icrnl

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: implementation

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: implementing

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: initialize

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: instance

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: instantiate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: instantiations

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: intentionally

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: interpret

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: interpreter

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: irreversibly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: iteration

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: iterator

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: its

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: kernel

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: kmsg

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: knowledge

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: maximum

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: mirrored

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: msftconnecttest

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: multi

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: multiple

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: mutable

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: namespace

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: nonexistent

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: notifications

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: occurred

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: occurring

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: otherwise,

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: outstanding

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: overridden

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: partition

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: pass through

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: passthrough

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: performs

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: periodically

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: positional

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: precedence

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: preexisting

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: preferring

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: prepopulate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: previous

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: privileges

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: process

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: processes

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: programmatically

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: protection

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: provided

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: reasonable

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: receive

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: received

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: red hat

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: reentrant

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: registered

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: regularly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: relay

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: release

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: representing

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: requests

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: response

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: resurrect

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: retention

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: returned

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: security

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: semaphore

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: separate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: separator

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: service

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: set up

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: setup

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: severely

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: should

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: signal

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: similarly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: simple

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: simplified

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: single

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: specified

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: splitting

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: standard

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: stress

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: succeed

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: success

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: successfully

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: supplementary

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: synced

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: system

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: take

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: than

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: that opening

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: the

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: threadpool

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: to

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: true

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: truncate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: tunneling

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: unexpected

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: uninitialize

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: unique

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: unprivileged

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: unregistered

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: untrusted

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: upgrade

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: utility

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: validating

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: variant

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: variation

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: variations

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: verify

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: visible

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: whether

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: winget

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: worker

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: written

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: wslservice

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* format source

---------

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
Co-authored-by: Ben Hillis <benhillis@gmail.com>
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
2025-07-23 15:19:00 -07:00

524 lines
22 KiB
C++

/*++
Copyright (c) Microsoft. All rights reserved.
Module Name:
WslCoreConfig.cpp
Abstract:
This file contains the WSL Core VM configuration helper class definition.
--*/
#include "precomp.h"
#include "WslCoreConfig.h"
#include "Localization.h"
#include "WslCoreFirewallSupport.h"
#include "WslCoreNetworkingSupport.h"
constexpr auto c_natGatewayAddress = L"NatGatewayIpAddress";
constexpr auto c_natNetwork = L"NatNetwork";
constexpr auto c_natIpAddress = L"NatIpAddress";
wsl::core::Config::Config(_In_opt_ LPCWSTR Path, _In_opt_ HANDLE UserToken)
{
ParseConfigFile(Path, UserToken);
Initialize(UserToken);
}
void wsl::core::Config::ParseConfigFile(_In_opt_ LPCWSTR ConfigFilePath, _In_opt_ HANDLE UserToken)
{
windows::common::ExecutionContext context(windows::common::ParseConfig);
auto parseIgnoredPorts = [&](const char* name, const char* value, const wchar_t* fileName, unsigned long fileLine) {
const auto ignoredPortsVector = wsl::shared::string::Split(std::string{value}, ',');
for (const auto& portString : ignoredPortsVector)
{
int number = 0;
if (FAILED(wil::ResultFromException([&]() { number = std::stoi(portString); })) || (number <= 0 || number > USHRT_MAX))
{
EMIT_USER_WARNING(shared::Localization::MessageConfigInvalidInteger(value, name, fileName, fileLine));
}
else
{
IgnoredPorts.insert(static_cast<uint16_t>(number));
}
}
};
auto parseDnsTunnelingIp = [&](const char* name, const char* value, const wchar_t* fileName, unsigned long fileLine) {
// If the IP is invalid, DNS tunneling is disabled.
in_addr address{};
if (inet_pton(AF_INET, value, &address) != 1)
{
EMIT_USER_WARNING(shared::Localization::MessageConfigInvalidIp(value, name, fileName, fileLine));
EnableDnsTunneling = false;
}
else
{
DnsTunnelingIpAddress = address.S_un.S_addr;
}
};
ConfigKeyPresence earlyBootLoggingPresent{};
ConfigKeyPresence macAddressPresent{};
bool enableFirewall = true;
std::wstring userKernelModules;
std::vector<ConfigKey> keys{
ConfigKey(ConfigSetting::Kernel, KernelPath),
ConfigKey(ConfigSetting::KernelCommandLine, KernelCommandLine),
ConfigKey(ConfigSetting::KernelModules, KernelModulesPath),
ConfigKey(ConfigSetting::Memory, MemoryString(MemorySizeBytes)),
ConfigKey(ConfigSetting::Processors, ProcessorCount),
ConfigKey(ConfigSetting::DebugConsole, EnableDebugConsole),
ConfigKey(ConfigSetting::EarlyBootLogging, EnableEarlyBootLogging, &earlyBootLoggingPresent),
ConfigKey(ConfigSetting::Swap, MemoryString(SwapSizeBytes)),
ConfigKey(ConfigSetting::SwapFile, SwapFilePath),
ConfigKey(ConfigSetting::LocalhostForwarding, EnableLocalhostRelay, &LocalhostRelayConfigPresence),
ConfigKey(ConfigSetting::NestedVirtualization, EnableNestedVirtualization),
ConfigKey(ConfigSetting::Virtio9p, EnableVirtio9p),
ConfigKey(ConfigSetting::Virtiofs, EnableVirtioFs),
ConfigKey(ConfigSetting::KernelDebugPort, KernelDebugPort),
ConfigKey(ConfigSetting::GpuSupport, EnableGpuSupport),
ConfigKey(ConfigSetting::GuiApplications, EnableGuiApps),
ConfigKey(ConfigSetting::SystemDistro, SystemDistroPath),
ConfigKey(ConfigSetting::Telemetry, EnableTelemetry),
ConfigKey(ConfigSetting::VmIdleTimeout, VmIdleTimeout),
ConfigKey(ConfigSetting::DebugConsoleLogFile, DebugConsoleLogFile),
ConfigKey(ConfigSetting::KernelBootTimeout, KernelBootTimeout),
ConfigKey(ConfigSetting::DistributionStartTimeout, DistributionStartTimeout),
ConfigKey(ConfigSetting::Virtio, EnableVirtio),
ConfigKey(ConfigSetting::HostFileSystemAccess, EnableHostFileSystemAccess),
ConfigKey(ConfigSetting::MountDeviceTimeout, MountDeviceTimeout),
ConfigKey(ConfigSetting::HardwarePerformanceCounters, EnableHardwarePerformanceCounters),
ConfigKey(ConfigSetting::VmSwitch, VmSwitch),
ConfigKey(ConfigSetting::MacAddress, MacAddress, &macAddressPresent),
ConfigKey(ConfigSetting::Dhcp, EnableDhcp),
ConfigKey(ConfigSetting::DhcpTimeout, DhcpTimeout),
ConfigKey(ConfigSetting::Ipv6, EnableIpv6),
ConfigKey(ConfigSetting::DnsProxy, EnableDnsProxy),
ConfigKey(ConfigSetting::SafeMode, EnableSafeMode),
ConfigKey(ConfigSetting::DefaultVhdSize, MemoryString(VhdSizeBytes)),
ConfigKey(ConfigSetting::CrashDumpFolder, CrashDumpFolder),
ConfigKey(ConfigSetting::MaxCrashDumpCount, MaxCrashDumpCount),
ConfigKey(ConfigSetting::DistributionInstallPath, DefaultDistributionLocation),
ConfigKey(ConfigSetting::InstanceIdleTimeout, InstanceIdleTimeout),
ConfigKey(ConfigSetting::LoadDefaultKernelModules, LoadDefaultKernelModules, &loadKernelModulesPresence),
ConfigKey(ConfigSetting::LoadKernelModules, userKernelModules, &loadKernelModulesPresence),
// Features that were previously experimental (the old header is maintained for compatability).
ConfigKey({ConfigSetting::NetworkingMode, ConfigSetting::Experimental::NetworkingMode}, wsl::core::NetworkingModes, NetworkingMode, &NetworkingModePresence),
ConfigKey({ConfigSetting::DnsTunneling, ConfigSetting::Experimental::DnsTunneling}, EnableDnsTunneling, &DnsTunnelingConfigPresence),
ConfigKey({ConfigSetting::Firewall, ConfigSetting::Experimental::Firewall}, enableFirewall, &FirewallConfigPresence),
ConfigKey({ConfigSetting::AutoProxy, ConfigSetting::Experimental::AutoProxy}, EnableAutoProxy),
// Experimental features.
ConfigKey(ConfigSetting::Experimental::AutoMemoryReclaim, wsl::core::MemoryReclaimModes, MemoryReclaim),
ConfigKey(ConfigSetting::Experimental::SparseVhd, EnableSparseVhd),
ConfigKey(ConfigSetting::Experimental::BestEffortDnsParsing, BestEffortDnsParsing),
ConfigKey(ConfigSetting::Experimental::DnsTunnelingIpAddress, std::move(parseDnsTunnelingIp)),
ConfigKey(ConfigSetting::Experimental::InitialAutoProxyTimeout, InitialAutoProxyTimeout),
ConfigKey(ConfigSetting::Experimental::IgnoredPorts, std::move(parseIgnoredPorts)),
ConfigKey(ConfigSetting::Experimental::HostAddressLoopback, EnableHostAddressLoopback),
ConfigKey(ConfigSetting::Experimental::SetVersionDebug, SetVersionDebug)};
wil::unique_file ConfigFile;
if (ConfigFilePath != nullptr)
{
ConfigFile.reset(_wfopen(ConfigFilePath, L"rt,ccs=UTF-8"));
if (!ConfigFile)
{
const auto error = _doserrno;
LOG_WIN32_MSG(error, "opening config file failed");
if (error != ERROR_FILE_NOT_FOUND)
{
EMIT_USER_WARNING(wsl::shared::Localization::MessageFailedToOpenConfigFile(
ConfigFilePath, wsl::windows::common::wslutil::GetErrorString(HRESULT_FROM_WIN32(error))));
}
}
}
// Parse the configuration keys.
WI_VERIFY(::ParseConfigFile(keys, ConfigFile.get(), (CFG_SKIP_INVALID_LINES | CFG_SKIP_UNKNOWN_VALUES), ConfigFilePath) == 0);
// Hyper-V firewall must always be configured for Mirrored Mode.
// For NAT mode, we use the experimental config to determine if Hyper-V firewall should be enabled
if ((NetworkingMode::Mirrored == NetworkingMode) || enableFirewall)
{
FirewallConfig.Enable();
}
if (EnableDnsTunneling && !DnsTunnelingIpAddress.has_value())
{
in_addr address{};
WI_VERIFY(inet_pton(AF_INET, LX_INIT_DNS_TUNNELING_IP_ADDRESS, &address) == 1);
DnsTunnelingIpAddress = address.S_un.S_addr;
}
if (macAddressPresent == ConfigKeyPresence::Absent && NetworkingMode == NetworkingMode::Bridged)
{
// Generate a random mac address if unspecified, so that the VM retains the same if restarted
const std::independent_bits_engine<std::default_random_engine, 16, unsigned short> random;
// independent_bits_engine doesn't support unsigned char on MSVC
auto* macAddressShort = reinterpret_cast<unsigned short*>(MacAddress.data());
std::generate(macAddressShort, macAddressShort + 3, random);
// Clear the multicast bit
MacAddress[0] &= ~1;
// Set the locally generated bit.
MacAddress[0] |= 2;
}
// Enable early boot logging if the debug console is enabled, unless explicitly disabled
if (EnableDebugConsole || !DebugConsoleLogFile.empty())
{
if (earlyBootLoggingPresent == ConfigKeyPresence::Absent)
{
EnableEarlyBootLogging = true;
}
}
if (CrashDumpFolder.empty() && MaxCrashDumpCount >= 0)
{
CrashDumpFolder = wsl::windows::common::filesystem::GetTempFolderPath(UserToken) / "wsl-crashes";
}
if (DefaultDistributionLocation.empty())
{
DefaultDistributionLocation = wsl::windows::common::filesystem::GetLocalAppDataPath(UserToken) / "wsl";
}
if (!LoadDefaultKernelModules)
{
KernelModulesList.clear();
}
for (auto& e : wsl::shared::string::Split(userKernelModules, L','))
{
KernelModulesList.emplace_back(std::move(e));
}
}
void wsl::core::Config::SaveNetworkingSettings(_In_opt_ HANDLE UserToken) const
try
{
if (NetworkingMode != NetworkingMode::Nat)
{
return;
}
const auto machineKey = wsl::windows::common::registry::OpenLxssMachineKey(KEY_SET_VALUE);
wsl::windows::common::registry::WriteString(machineKey.get(), nullptr, c_natGatewayAddress, NatGateway.c_str());
wsl::windows::common::registry::WriteString(machineKey.get(), nullptr, c_natNetwork, NatNetwork.c_str());
auto runAsUser = wil::impersonate_token(UserToken);
const auto userKey = wsl::windows::common::registry::OpenLxssUserKey();
wsl::windows::common::registry::WriteString(userKey.get(), nullptr, c_natIpAddress, NatIpAddress.c_str());
}
CATCH_LOG();
unsigned long wsl::core::Config::WriteConfigFile(_In_ LPCWSTR ConfigFilePath, _In_ ConfigKey KeyToWrite, _In_ bool RemoveKey)
{
windows::common::ExecutionContext context(windows::common::ParseConfig);
if (!ConfigFilePath)
{
return ERROR_INVALID_PARAMETER;
}
// Open file for reading & writing. This assumes the file exists.
wil::unique_file ConfigFile(_wfopen(ConfigFilePath, L"r+t,ccs=UTF-8"));
const auto win32Error = _doserrno;
if (!ConfigFile && win32Error != ERROR_FILE_NOT_FOUND)
{
return win32Error;
}
// Since we aren't parsing in the config file, we don't need to pass in the known keys.
std::vector<ConfigKey> keys{};
std::wstring configFileOutput{};
auto result = ::ParseConfigFile(
keys, ConfigFile.get(), (CFG_SKIP_INVALID_LINES | CFG_SKIP_UNKNOWN_VALUES), ConfigFilePath, configFileOutput, KeyToWrite, RemoveKey);
if (result != 0)
{
return ERROR_READ_FAULT;
}
// If the config file didn't exist/wasn't opened, open it for writing.
if (!ConfigFile)
{
ConfigFile.reset(_wfopen(ConfigFilePath, L"wt,ccs=UTF-8"));
if (!ConfigFile)
{
return _doserrno;
}
}
// Move file pointer to beginning of file, write out the new config file, and truncate the file.
rewind(ConfigFile.get());
result = fputws(configFileOutput.c_str(), ConfigFile.get());
if (result == WEOF)
{
return ERROR_WRITE_FAULT;
}
const auto fileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(ConfigFile.get())));
if (SetEndOfFile(fileHandle) != TRUE)
{
return GetLastError();
}
return ERROR_SUCCESS;
}
#define VALIDATE_CONFIG_OPTION(_dependency, _setting, _value) \
{ \
LOG_HR_IF(E_INVALIDARG, _dependency && (_setting != _value)); \
_setting = _value; \
}
void wsl::core::Config::Initialize(_In_opt_ HANDLE UserToken)
{
// Determine the maximum number of processors that can be added to the VM.
// If the user did not supply a processor count, use the maximum.
const auto MaximumProcessorCount = wsl::windows::common::wslutil::GetLogicalProcessorCount();
if (ProcessorCount <= 0)
{
ProcessorCount = MaximumProcessorCount;
}
else if (ProcessorCount > MaximumProcessorCount)
{
EMIT_USER_WARNING(wsl::shared::Localization::MessageTooManyProcessors(ProcessorCount, MaximumProcessorCount));
ProcessorCount = MaximumProcessorCount;
}
// Determine how much memory to add to the VM. If the user did not specify a value,
// use 50% of host memory. Otherwise, ensure the value falls within 256MB and the total system memory.
MEMORYSTATUSEX memInfo{sizeof(MEMORYSTATUSEX)};
THROW_IF_WIN32_BOOL_FALSE(GlobalMemoryStatusEx(&memInfo));
MaximumMemorySizeBytes = memInfo.ullTotalPhys;
if (MemorySizeBytes == 0)
{
MemorySizeBytes = (MaximumMemorySizeBytes / 2);
}
else
{
MemorySizeBytes = std::max<UINT64>(MemorySizeBytes, (256 * _1MB));
MemorySizeBytes = std::min<UINT64>(MemorySizeBytes, MaximumMemorySizeBytes);
}
// Use the user-defined swap size if one was specified; otherwise, set to 25%
// the memory size rounded up to the nearest GB.
//
// N.B. This heuristic is modeled after Red Hat and Ubuntu's recommended swap size.
if (SwapSizeBytes == UINT64_MAX)
{
SwapSizeBytes = ((MemorySizeBytes / 4 + _1GB - 1) & ~(_1GB - 1));
}
// Apply machine-wide policies to the configuration.
auto key = wsl::windows::policies::OpenPoliciesKey();
auto applyOverride = [&key](LPCWSTR ValueName, LPCWSTR SettingName, auto& value) {
if (value != std::remove_reference_t<decltype(value)>{} && !wsl::windows::policies::IsFeatureAllowed(key.get(), ValueName))
{
value = std::remove_reference_t<decltype(value)>{};
EMIT_USER_WARNING(wsl::shared::Localization::MessageSettingOverriddenByPolicy(SettingName));
}
};
applyOverride(wsl::windows::policies::c_allowCustomKernelUserSetting, L"wsl2.kernel", KernelPath);
applyOverride(wsl::windows::policies::c_allowCustomKernelUserSetting, L"wsl2.kernelModules", KernelModulesPath);
applyOverride(wsl::windows::policies::c_allowCustomSystemDistroUserSetting, L"wsl2.systemDistro", SystemDistroPath);
applyOverride(wsl::windows::policies::c_allowCustomKernelCommandLineUserSetting, L"wsl2.kernelCommandLine", KernelCommandLine);
applyOverride(wsl::windows::policies::c_allowKernelDebuggingUserSetting, L"wsl2.kernelDebugPort", KernelDebugPort);
applyOverride(wsl::windows::policies::c_allowNestedVirtualizationUserSetting, L"wsl2.nestedVirtualization", EnableNestedVirtualization);
if (!wsl::windows::policies::IsFeatureAllowed(key.get(), wsl::windows::policies::c_allowDebugShellUserSetting))
{
// N.B. The warning for debug shell is handled in wsl.exe.
EnableDebugShell = false;
}
// Read the policy key for default networking mode.
auto defaultNetworkingMode = wsl::core::NetworkingMode::Nat;
const auto setting = wsl::windows::policies::GetPolicyValue(key.get(), wsl::windows::policies::c_defaultNetworkingMode);
if (setting.has_value())
{
switch (setting.value())
{
case wsl::core::NetworkingMode::None:
case wsl::core::NetworkingMode::Nat:
case wsl::core::NetworkingMode::Mirrored:
case wsl::core::NetworkingMode::VirtioProxy:
defaultNetworkingMode = static_cast<wsl::core::NetworkingMode>(setting.value());
break;
case wsl::core::NetworkingMode::Bridged: // Bridged requires additional configuration.
default:
LOG_HR_MSG(E_UNEXPECTED, "Invalid default networking mode: %d", setting.value());
break;
}
}
// Determine if the user is allowed to override the networking mode.
//
// N.B. User can always disable networking entirely.
if (NetworkingModePresence == ConfigKeyPresence::Present)
{
if ((!wsl::windows::policies::IsFeatureAllowed(key.get(), wsl::windows::policies::c_allowCustomNetworkingModeUserSetting)) &&
(NetworkingMode != wsl::core::NetworkingMode::None) && (NetworkingMode != defaultNetworkingMode))
{
NetworkingMode = defaultNetworkingMode;
EMIT_USER_WARNING(wsl::shared::Localization::MessageSettingOverriddenByPolicy(L"wsl2.networkingMode"));
}
}
else
{
NetworkingMode = defaultNetworkingMode;
}
// Mirrored mode has Hyper-V Firewall always on - we ignore the local setting regardless in this case.
if (NetworkingMode != wsl::core::NetworkingMode::Mirrored)
{
if (!FirewallConfig.Enabled() &&
!wsl::windows::policies::IsFeatureAllowed(key.get(), wsl::windows::policies::c_allowCustomFirewallUserSetting))
{
FirewallConfig.Enable();
EMIT_USER_WARNING(wsl::shared::Localization::MessageSettingOverriddenByPolicy(L"wsl2.firewall"));
}
}
// Load NAT configuration from the registry.
if (NetworkingMode == wsl::core::NetworkingMode::Nat)
try
{
const auto machineKey = wsl::windows::common::registry::OpenLxssMachineKey();
NatGateway = wsl::windows::common::registry::ReadString(machineKey.get(), nullptr, c_natGatewayAddress, L"");
NatNetwork = wsl::windows::common::registry::ReadString(machineKey.get(), nullptr, c_natNetwork, L"");
auto runAsUser = wil::impersonate_token(UserToken);
const auto userKey = wsl::windows::common::registry::OpenLxssUserKey();
NatIpAddress = wsl::windows::common::registry::ReadString(userKey.get(), nullptr, c_natIpAddress, L"");
}
CATCH_LOG()
// Due to an issue with Global Secure Access Client, do not use DNS tunneling if the service is present.
if (EnableDnsTunneling)
try
{
// Open a handle to the service control manager and check if the inbox service is registered.
const wil::unique_schandle manager{OpenSCManager(nullptr, nullptr, SC_MANAGER_ENUMERATE_SERVICE)};
THROW_LAST_ERROR_IF(!manager);
// Check if the service is running.
const wil::unique_schandle service{OpenServiceW(manager.get(), L"GlobalSecureAccessTunnelingService", SERVICE_QUERY_STATUS)};
if (service)
{
SERVICE_STATUS status;
THROW_IF_WIN32_BOOL_FALSE(QueryServiceStatus(service.get(), &status));
if (status.dwCurrentState != SERVICE_STOPPED)
{
if (DnsTunnelingConfigPresence == ConfigKeyPresence::Present)
{
EMIT_USER_WARNING(wsl::shared::Localization::MessageDnsTunnelingDisabled());
}
EnableDnsTunneling = false;
}
}
}
CATCH_LOG()
// Ensure that settings are consistent (disable features that require other features that are not present).
if (EnableSafeMode)
{
EMIT_USER_WARNING(wsl::shared::Localization::MessageSafeModeEnabled());
VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableHostFileSystemAccess, false);
VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableNestedVirtualization, false);
VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableHardwarePerformanceCounters, false);
VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableGpuSupport, false);
VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableVirtio, false);
VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableGuiApps, false);
VALIDATE_CONFIG_OPTION(EnableSafeMode, SwapSizeBytes, 0);
VALIDATE_CONFIG_OPTION(EnableSafeMode, KernelPath, std::filesystem::path{});
VALIDATE_CONFIG_OPTION(EnableSafeMode, KernelModulesPath, std::filesystem::path{});
VALIDATE_CONFIG_OPTION(EnableSafeMode, NetworkingMode, NetworkingMode::None);
VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableDnsTunneling, false);
VALIDATE_CONFIG_OPTION(EnableSafeMode, EnableAutoProxy, false);
}
if (!EnableVirtio)
{
VALIDATE_CONFIG_OPTION(!EnableVirtio, EnableVirtio9p, false);
VALIDATE_CONFIG_OPTION(!EnableVirtio, EnableVirtioFs, false);
}
if (EnableVirtio9p)
{
EMIT_USER_WARNING(wsl::shared::Localization::MessageConfigVirtio9pDisabled());
EnableVirtio9p = false;
}
if (NetworkingMode != NetworkingMode::Nat && NetworkingMode != NetworkingMode::Mirrored)
{
VALIDATE_CONFIG_OPTION((NetworkingMode != NetworkingMode::Nat && NetworkingMode != NetworkingMode::Mirrored), EnableDnsTunneling, false);
}
if (!EnableDnsTunneling)
{
VALIDATE_CONFIG_OPTION(!EnableDnsTunneling, BestEffortDnsParsing, false);
VALIDATE_CONFIG_OPTION(!EnableDnsTunneling, DnsTunnelingIpAddress, std::optional<uint32_t>{});
}
if (NetworkingMode != NetworkingMode::Mirrored)
{
VALIDATE_CONFIG_OPTION((NetworkingMode != NetworkingMode::Mirrored), IgnoredPorts, std::set<uint16_t>{});
VALIDATE_CONFIG_OPTION((NetworkingMode != NetworkingMode::Mirrored), EnableHostAddressLoopback, false);
}
}
GUID wsl::core::Config::NatNetworkId() const noexcept
{
// Identifier for the WSL virtual network: {b95d0c5e-57d4-412b-b571-18a81a16e005}
static constexpr GUID c_networkId = {0xb95d0c5e, 0x57d4, 0x412b, {0xb5, 0x71, 0x18, 0xa8, 0x1a, 0x16, 0xe0, 0x05}};
// Identifier for the WSL virtual network with Hyper-v firewall enabled: {790e58b4-7939-4434-9358-89ae7ddbe87e}
static constexpr GUID c_networkWithFirewallId = {0x790e58b4, 0x7939, 0x4434, {0x93, 0x58, 0x89, 0xae, 0x7d, 0xdb, 0xe8, 0x7e}};
return FirewallConfig.Enabled() ? c_networkWithFirewallId : c_networkId;
}
LPCWSTR wsl::core::Config::NatNetworkName() const noexcept
{
static constexpr auto c_networkName = L"WSL";
static constexpr auto c_networkWithFirewallName = L"WSL (Hyper-V firewall)";
return FirewallConfig.Enabled() ? c_networkWithFirewallName : c_networkName;
}
void wsl::core::FirewallConfiguration::Enable() noexcept
{
VmCreatorId = wsl::core::networking::c_wslFirewallVmCreatorId;
DefaultLoopbackPolicy = FirewallAction::Allow;
Rules = wsl::core::networking::MakeDefaultFirewallRuleConfiguration(networking::c_wslFirewallVmCreatorId);
}
void wsl::core::FirewallConfiguration::reset() noexcept
{
VmCreatorId.reset();
Rules.clear();
DefaultLoopbackPolicy = FirewallAction::Invalid;
}
bool wsl::core::FirewallConfiguration::Enabled() const noexcept
{
return VmCreatorId.has_value();
}