Merge remote-tracking branch 'origin/master' into HEAD

This commit is contained in:
Ben Hillis 2026-02-02 16:20:06 -08:00
commit ff4b5d5102
35 changed files with 6261 additions and 6125 deletions

View File

@ -166,8 +166,8 @@
"FriendlyName": "Arch Linux",
"Default": true,
"Amd64Url": {
"Url": "https://fastly.mirror.pkgbuild.com/wsl/2026.01.01.156076/archlinux-2026.01.01.156076.wsl",
"Sha256": "e3820c60df62edc22df29c9c16d2205512d95c1b086232a9b7bc3960542036d4"
"Url": "https://fastly.mirror.pkgbuild.com/wsl/2026.02.01.158360/archlinux-2026.02.01.158360.wsl",
"Sha256": "e3287ab9f0458240fc6a966849dbc69188bdc7ef376dc27d441aef6f13dd45e5"
}
}
],

View File

@ -292,10 +292,12 @@ a wsl.exe --install &lt;Distro&gt;.</value>
<value>Starší verze distribuce nepodporuje WSL 2.</value>
</data>
<data name="MessageEnableVirtualization" xml:space="preserve">
<value>WsL2 se v aktuální konfiguraci vašeho počítače nepodporuje.
Povolte volitelnou součást „Platforma virtuálního počítače“ a ujistěte se, že je v systému BIOS povolená virtualizace.
Povolte platformu virtuálních počítačů spuštěním příkazu: wsl.exe --install --no-distribution
Informace najdete na https://aka.ms/enablevirtualization</value>
<value>WSL2 nelze spustit, protože na tomto počítači není povolena virtualizace.
Ujistěte se, že je povolena volitelná součást „Virtual Machine Platform“ a že je virtualizace zapnutá v nastavení firmwaru vašeho počítače.
Povolte „Virtual Machine Platform“ spuštěním: wsl.exe --install --no-distribution
Další informace najdete na https://aka.ms/enablevirtualization</value>
<comment>{Locked="--install "}{Locked="--no-distribution
"}Command line arguments, file names and string inserts should not be translated</comment>
</data>

File diff suppressed because it is too large Load Diff

View File

@ -298,10 +298,12 @@ und "wsl.exe --install &lt;Distro&gt;".</value>
<value>WSL 2 wird von der Legacy Distribution nicht unterstütztt.</value>
</data>
<data name="MessageEnableVirtualization" xml:space="preserve">
<value>WSL2 wird von Ihrer aktuellen Computerkonfiguration nicht unterstützt.
Aktivieren Sie die optionale Komponente "Plattform für virtuelle Computer", und stellen Sie sicher, dass die Virtualisierung im BIOS aktiviert ist.
Aktivieren Sie "Plattform für virtuelle Computer", indem Sie ": wsl.exe --install --no-distribution
" ausführen. Weitere Informationen finden Sie unter https://aka.ms/enablevirtualization</value>
<value>WSL2 kann nicht gestartet werden, da die Virtualisierung auf diesem Computer nicht aktiviert ist.
Stellen Sie sicher, dass die optionale Komponente „VM-Plattform“ aktiviert ist und die Virtualisierung in den Firmwareeinstellungen Ihres Computers eingeschaltet ist.
Aktivieren Sie „VM-Plattform“, indem Sie folgenden Befehl ausführen: wsl.exe --install --no-distribution
Weitere Informationen finden Sie unter https://aka.ms/enablevirtualization</value>
<comment>{Locked="--install "}{Locked="--no-distribution
"}Command line arguments, file names and string inserts should not be translated</comment>
</data>

File diff suppressed because it is too large Load Diff

View File

@ -292,10 +292,12 @@ A 'wsl.exe --list --online' parancs használatával listázhatja az elérhető d
<value>Az örökölt disztribúció nem támogatja a WSL 2-t.</value>
</data>
<data name="MessageEnableVirtualization" xml:space="preserve">
<value>A jelenlegi számítógép-konfiguráció nem támogatja a WSL2-t.
Engedélyezze a „Virtuálisgép-platform” választható összetevőt, és győződjön meg arról, hogy a virtualizálás engedélyezve van a BIOS-ban.
<value>A WSL2 nem indítható el, mert a virtualizáció nincs engedélyezve ezen a gépen.
Győződjön meg arról, hogy a „Virtuálisgép-platform” választható összetevő engedélyezve van, és a virtualizáció be van kapcsolva a számítógép firmware-beállításaiban.
A „Virtuálisgép-platform” engedélyezéséhez futtassa a következőt: wsl.exe --install --no-distribution
További információért látogasson el a https://aka.ms/enablevirtualization oldalra</value>
További információért látogasson el ide: https://aka.ms/enablevirtualization</value>
<comment>{Locked="--install "}{Locked="--no-distribution
"}Command line arguments, file names and string inserts should not be translated</comment>
</data>

File diff suppressed because it is too large Load Diff

View File

@ -292,9 +292,11 @@ e "wsl.exe --install &lt;Distro&gt;" para instalar.</value>
<value>A distribuição legada não suporta o WSL 2.</value>
</data>
<data name="MessageEnableVirtualization" xml:space="preserve">
<value>O WSL2 não é suportado com a configuração atual do computador.
Ative o componente opcional "Plataforma de Máquinas Virtuais" e certifique-se de que a virtualização está ativada no BIOS.
Ative a "Plataforma de Máquinas Virtuais" executando: wsl.exe --install --no-distribution
<value>O WSL2 não consegue iniciar porque a virtualização não está ativada nesta máquina.
Certifique-se de que o componente opcional "Plataforma de Máquina Virtual" está ativado e a virtualização está ligada nas definições de firmware do seu computador.
Ative a "Plataforma de Máquina Virtual" ao executar: wsl.exe --install --no-distribution
Para obter informações, visite https://aka.ms/enablevirtualization</value>
<comment>{Locked="--install "}{Locked="--no-distribution
"}Command line arguments, file names and string inserts should not be translated</comment>

View File

@ -169,7 +169,7 @@ Diski ayırmak için '{} {}' wsl.exe çalıştırın.</value>
<value>Sağlanan yükleme konumu zaten kullanılıyor.</value>
</data>
<data name="MessageDistroNameAlreadyExists" xml:space="preserve">
<value>Sağlanan ada sahip bir dağıtım zaten mevcut. Farklı bir isim seçmek için --name seçeneğini kullanın.</value>
<value>Sağlanan ada sahip bir dağıtım zaten mevcut. Farklı bir ad seçmek için --name komutunu kullanın.</value>
<comment>{Locked="--name "}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageDistroNotFound" xml:space="preserve">
@ -1123,7 +1123,7 @@ wsl.exe --manage &lt;DistributionName&gt; --set-sparse true --allow-unsafe</valu
<value>/etc/fstab with mount -a işlenemedi.</value>
</data>
<data name="MessageReadOnlyDistro" xml:space="preserve">
<value>ağıtım diski bağlanırken bir hata oluştu, yedek plan olarak salt okunur şekilde bağlandı.
<value>Dıtım diski bağlanırken bir hata oluştu, yedek plan olarak salt okunur şekilde bağlandı.
Kurtarma yönergelerine bakın: https://aka.ms/wsldiskmountrecovery</value>
</data>
<data name="MessageFailedToTranslate" xml:space="preserve">
@ -1364,7 +1364,7 @@ Kurtarma yönergelerine bakın: https://aka.ms/wsldiskmountrecovery</value>
<value>Yoksayılan bağlantı noktaları</value>
</data>
<data name="Settings_IgnoredPorts.Description" xml:space="preserve">
<value>Yalnızca wsl2.networkingMode olarak ayarlandığında uygulanabilir. Linux uygulamalarının otomatik olarak iletilen veya Windows'ta değerlendirilen bağlantı noktalarına bağlanacak bağlantı noktalarını belirtir. Virgülle ayrılmış bir listede biçimlendirilmelidir, örneğin: 3000.9000.9090.</value>
<value>Yalnızca wsl2.networkingMode olarak ayarlandığında uygulanabilir. Linux uygulamalarının otomatik olarak iletilen veya Windows'da değerlendirilen bağlantı noktalarına bağlanacak bağlantı noktalarını belirtir. Virgülle ayrılmış bir listede biçimlendirilmelidir, örneğin: 3000.9000.9090.</value>
<comment>{Locked="wsl2.networkingMode"}.wslconfig property key names should not be translated</comment>
</data>
<data name="Settings_IgnoredPortsResetButton.Content" xml:space="preserve">

View File

@ -315,21 +315,17 @@ void GnsEngine::ProcessDNSChange(Interface& interface, const wsl::shared::hns::D
content << L"nameserver " << server << L"\n";
}
if (!payload.Domain.empty())
{
content << L"domain " << payload.Domain << L"\n";
}
// Use 'search' for DNS suffixes.
// Per resolv.conf(5): "The domain directive is an obsolete name for the search directive
// that handles one search list entry only."
// See: https://man7.org/linux/man-pages/man5/resolv.conf.5.html
if (!payload.Search.empty())
{
content << L"search " << wsl::shared::string::Join(wsl::shared::string::Split(payload.Search, L','), L' ') << L"\n";
}
GNS_LOG_INFO(
"Setting DNS server domain to {}: {} on interfaceName {} ",
payload.Domain.c_str(),
content.str().c_str(),
interface.Name().c_str());
"Setting DNS search to {}: {} on interfaceName {} ", payload.Search.c_str(), content.str().c_str(), interface.Name().c_str());
THROW_LAST_ERROR_IF(UtilMkdirPath("/etc", 0755) < 0);
std::wofstream resolvConf;

View File

@ -1729,10 +1729,6 @@ Return Value:
if (strcmp(MountEnum.Current().FileSystemType, PLAN9_FS_TYPE) == 0)
{
MountSource = UtilParsePlan9MountSource(MountEnum.Current().SuperOptions);
if (MountSource.empty())
{
continue;
}
}
else if (strcmp(MountEnum.Current().FileSystemType, DRVFS_FS_TYPE) == 0)
{
@ -1741,13 +1737,18 @@ Return Value:
}
else if (strcmp(MountEnum.Current().FileSystemType, VIRTIO_FS_TYPE) == 0)
{
MountSource = UtilParseVirtiofsMountSource(MountEnum.Current().Source);
MountSource = QueryVirtiofsMountSource(MountEnum.Current().Source);
}
else
{
continue;
}
if (MountSource.empty())
{
continue;
}
auto letter = ConfigGetDriveLetter(MountSource);
if (letter.has_value())
{
@ -2445,17 +2446,10 @@ try
NewMountOptions += ',';
}
MountPlan9Filesystem(NewSource, MountEntry.MountPoint, NewMountOptions.c_str(), Message->Admin, Config);
MountPlan9Share(NewSource, MountEntry.MountPoint, NewMountOptions.c_str(), Message->Admin, Config);
}
else if (strcmp(MountEntry.FileSystemType, VIRTIO_FS_TYPE) == 0)
{
std::string_view Source = MountEntry.Source;
std::string_view OldTag = Message->Admin ? LX_INIT_DRVFS_VIRTIO_TAG : LX_INIT_DRVFS_ADMIN_VIRTIO_TAG;
if (!wsl::shared::string::StartsWith(Source, OldTag))
{
continue;
}
RemountVirtioFs(MountEntry.Source, MountEntry.MountPoint, MountEntry.MountOptions, Message->Admin);
}
else

View File

@ -298,70 +298,12 @@ try
{
return MountFilesystem(DRVFS_FS_TYPE, Source, Target, Options, ExitCode);
}
// Use virtiofs if the source of the mount is the root of a drive; otherwise, use 9p.
if (WSL_USE_VIRTIO_FS(Config))
else if (WSL_USE_VIRTIO_FS(Config))
{
if (wsl::shared::string::IsDriveRoot(Source))
{
return MountVirtioFs(Source, Target, Options, Admin, Config, ExitCode);
}
LOG_WARNING("virtiofs is only supported for mounting full drives, using 9p to mount {}", Source);
return MountVirtioFs(Source, Target, Options, Admin, Config, ExitCode);
}
//
// Check if the path is a UNC path.
//
const char* Plan9Source;
std::string UncSource;
if ((strlen(Source) >= PLAN9_UNC_PREFIX_LENGTH) && ((Source[0] == '/') || (Source[0] == '\\')) &&
((Source[1] == '/') || (Source[1] == '\\')))
{
UncSource = PLAN9_UNC_TRANSLATED_PREFIX;
UncSource += &Source[PLAN9_UNC_PREFIX_LENGTH];
Plan9Source = UncSource.c_str();
}
else
{
Plan9Source = Source;
}
//
// Check whether to use the elevated or regular 9p server.
//
bool Elevated = Admin.has_value() ? Admin.value() : IsDrvfsElevated();
//
// Initialize mount options.
//
auto Plan9Options = std::format("{};path={}", PLAN9_ANAME_DRVFS, Plan9Source);
//
// N.B. The cache option is added to the start of this so if the user
// specifies one explicitly, it will override the default.
//
std::string MountOptions = "cache=mmap,";
auto ParsedOptions = ConvertDrvfsMountOptionsToPlan9(Options ? Options : "", Config);
Plan9Options += ParsedOptions.first;
MountOptions += ParsedOptions.second;
//
// Append the 9p mount options to the end of the other mount options and perform the mount operation.
//
MountOptions += Plan9Options;
if (MountPlan9Filesystem(Source, Target, MountOptions.c_str(), Elevated, Config, ExitCode) < 0)
{
return -1;
}
return 0;
return MountPlan9(Source, Target, Options, Admin, Config, ExitCode);
}
CATCH_RETURN_ERRNO()
@ -407,7 +349,7 @@ Return Value:
return ExitCode;
}
int MountPlan9Filesystem(const char* Source, const char* Target, const char* Options, bool Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode)
int MountPlan9Share(const char* Source, const char* Target, const char* Options, bool Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode)
/*++
@ -425,6 +367,8 @@ Arguments:
Admin - Supplies a boolean specifying if the admin share should be used.
Config - Supplies the distribution configuration.
ExitCode - Supplies an optional pointer that receives the exit code.
Return Value:
@ -452,10 +396,95 @@ Return Value:
MountOptions =
std::format("msize={},trans=fd,rfdno={},wfdno={},{}", LX_INIT_UTILITY_VM_PLAN9_BUFFER_SIZE, Fd.get(), Fd.get(), Options);
return MountFilesystem(PLAN9_FS_TYPE, Source, Target, MountOptions.c_str(), ExitCode);
}
}
int MountPlan9(const char* Source, const char* Target, const char* Options, std::optional<bool> Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode)
/*++
Routine Description:
This routine will perform a DrvFs mount using Plan9.
Arguments:
Source - Supplies the mount source.
Target - Supplies the mount target.
Options - Supplies the mount options.
Admin - Supplies an optional boolean to specify if the admin or non-admin share should be used.
Config - Supplies the distribution configuration.
ExitCode - Supplies an optional pointer that receives the exit code.
Return Value:
0 on success, -1 on failure.
--*/
try
{
//
// Check if the path is a UNC path.
//
const char* Plan9Source;
std::string UncSource;
if ((strlen(Source) >= PLAN9_UNC_PREFIX_LENGTH) && ((Source[0] == '/') || (Source[0] == '\\')) &&
((Source[1] == '/') || (Source[1] == '\\')))
{
UncSource = PLAN9_UNC_TRANSLATED_PREFIX;
UncSource += &Source[PLAN9_UNC_PREFIX_LENGTH];
Plan9Source = UncSource.c_str();
}
else
{
Plan9Source = Source;
}
//
// Check whether to use the elevated or regular 9p server.
//
bool Elevated = Admin.has_value() ? Admin.value() : IsDrvfsElevated();
//
// Initialize mount options.
//
auto Plan9Options = std::format("{};path={}", PLAN9_ANAME_DRVFS, Plan9Source);
//
// N.B. The cache option is added to the start of this so if the user
// specifies one explicitly, it will override the default.
//
std::string MountOptions = "cache=mmap,";
auto ParsedOptions = ConvertDrvfsMountOptionsToPlan9(Options ? Options : "", Config);
Plan9Options += ParsedOptions.first;
MountOptions += ParsedOptions.second;
//
// Append the 9p mount options to the end of the other mount options and perform the mount operation.
//
MountOptions += Plan9Options;
if (MountPlan9Share(Source, Target, MountOptions.c_str(), Elevated, Config, ExitCode) < 0)
{
return -1;
}
return 0;
}
CATCH_RETURN_ERRNO()
int MountVirtioFs(const char* Source, const char* Target, const char* Options, std::optional<bool> Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode)
/*++
@ -486,8 +515,6 @@ Return Value:
try
{
assert(wsl::shared::string::IsDriveRoot(Source));
//
// Check whether to use the elevated or non-elevated virtiofs server.
//
@ -516,7 +543,7 @@ try
AddShare.WriteString(AddShare->OptionsOffset, Plan9Options);
//
// Connect to the wsl service to add the virtiofs share.
// Connect to the wsl service to add the virtiofs share. If adding the share fails, fallback to mounting using Plan9.
//
wsl::shared::SocketChannel Channel{UtilConnectVsock(LX_INIT_UTILITY_VM_VIRTIOFS_PORT, true), "VirtoFs"};
@ -527,11 +554,10 @@ try
gsl::span<gsl::byte> ResponseSpan;
const auto& Response = Channel.Transaction<LX_INIT_ADD_VIRTIOFS_SHARE_MESSAGE>(AddShare.Span(), &ResponseSpan);
if (Response.Result != 0)
{
LOG_ERROR("Add virtiofs share for {} failed {}", Source, Response.Result);
return -1;
LOG_WARNING("Add virtiofs share for {} failed {}, falling back to Plan9", Source, Response.Result);
return MountPlan9(Source, Target, Options, Admin, Config, ExitCode);
}
//
@ -596,3 +622,52 @@ try
return MountWithRetry(Tag, Target, VIRTIO_FS_TYPE, Options);
}
CATCH_RETURN_ERRNO()
std::string QueryVirtiofsMountSource(const char* Tag)
/*++
Routine Description:
This routine takes a virtiofs tag and determines the Windows path it refers to.
Arguments:
Tag - Supplies the virtiofs tag to query.
Return Value:
The mount source, an empty string on failure.
--*/
try
{
wsl::shared::MessageWriter<LX_INIT_QUERY_VIRTIOFS_SHARE_MESSAGE> QueryShare(LxInitMessageQueryVirtioFsDevice);
QueryShare.WriteString(QueryShare->TagOffset, Tag);
//
// Connect to the host and send the query request.
//
wsl::shared::SocketChannel Channel{UtilConnectVsock(LX_INIT_UTILITY_VM_VIRTIOFS_PORT, true), "QueryVirtioFs"};
if (Channel.Socket() < 0)
{
return {};
}
gsl::span<gsl::byte> ResponseSpan;
const auto& Response = Channel.Transaction<LX_INIT_QUERY_VIRTIOFS_SHARE_MESSAGE>(QueryShare.Span(), &ResponseSpan);
if (Response.Result != 0)
{
LOG_ERROR("Query virtiofs share for {} failed {}", Tag, Response.Result);
return {};
}
return wsl::shared::string::FromSpan(ResponseSpan, Response.TagOffset);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return {};
}

View File

@ -23,9 +23,12 @@ int MountDrvfs(const char* Source, const char* Target, const char* Options, std:
int MountDrvfsEntry(int Argc, char* Argv[]);
int MountPlan9Filesystem(
const char* Source, const char* Target, const char* Options, bool Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode = nullptr);
int MountPlan9Share(const char* Source, const char* Target, const char* Options, bool Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode = nullptr);
int MountPlan9(const char* Source, const char* Target, const char* Options, std::optional<bool> Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode);
int MountVirtioFs(const char* Source, const char* Target, const char* Options, std::optional<bool> Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode = nullptr);
int RemountVirtioFs(const char* Tag, const char* Target, const char* Options, bool Admin);
std::string QueryVirtiofsMountSource(const char* Tag);

View File

@ -904,11 +904,12 @@ try
}
else if (strcmp(MountEnum.Current().FileSystemType, VIRTIO_FS_TYPE) == 0)
{
MountSource = UtilParseVirtiofsMountSource(MountEnum.Current().Source);
MountSource = QueryVirtiofsMountSource(MountEnum.Current().Source);
if (MountSource.empty())
{
continue;
}
MountEnum.Current().Source = MountSource.data();
}
else if (strcmp(MountEnum.Current().FileSystemType, DRVFS_FS_TYPE) == 0)
@ -2047,41 +2048,6 @@ Return Value:
return {};
}
std::string UtilParseVirtiofsMountSource(std::string_view Source)
/*++
Routine Description:
This routine parses the mount source to determine the actual source of a
a VirtioFs mount.
Arguments:
Source - Supplies the source string.
Return Value:
The mount source, or NULL if the source is not valid.
--*/
{
std::string MountSource{};
if (wsl::shared::string::StartsWith(Source, LX_INIT_DRVFS_ADMIN_VIRTIO_TAG) && (Source.size() >= sizeof(LX_INIT_DRVFS_ADMIN_VIRTIO_TAG)))
{
MountSource = Source[sizeof(LX_INIT_DRVFS_ADMIN_VIRTIO_TAG) - 1];
MountSource += ":";
}
else if (wsl::shared::string::StartsWith(Source, LX_INIT_DRVFS_VIRTIO_TAG) && (Source.size() >= sizeof(LX_INIT_DRVFS_VIRTIO_TAG)))
{
MountSource = Source[sizeof(LX_INIT_DRVFS_VIRTIO_TAG) - 1];
MountSource += ":";
}
return MountSource;
}
std::vector<char> UtilParseWslEnv(char* NtEnvironment)
/*++

View File

@ -259,8 +259,6 @@ int UtilParseCgroupsLine(char* Line, char** SubsystemName, bool* Enabled);
std::string UtilParsePlan9MountSource(std::string_view MountOptions);
std::string UtilParseVirtiofsMountSource(std::string_view MountOptions);
std::vector<char> UtilParseWslEnv(char* NtEnvironment);
int UtilProcessChildExitCode(int Status, const char* Name, int ExpectedStatus = 0, bool PrintError = true);

View File

@ -319,6 +319,7 @@ typedef enum _LX_MESSAGE_TYPE
LxInitMessageAddVirtioFsDevice,
LxInitMessageAddVirtioFsDeviceResponse,
LxInitMessageRemountVirtioFsDevice,
LxInitMessageQueryVirtioFsDevice,
LxInitMessageStartDistroInit,
LxInitMessageCreateLoginSession,
LxInitMessageStopPlan9Server,
@ -1169,6 +1170,17 @@ typedef struct _LX_INIT_REMOUNT_VIRTIOFS_SHARE_MESSAGE
PRETTY_PRINT(FIELD(Header), FIELD(Admin), STRING_FIELD(TagOffset));
} LX_INIT_REMOUNT_VIRTIOFS_SHARE_MESSAGE, *PLX_INIT_REMOUNT_VIRTIOFS_SHARE_MESSAGE;
typedef struct _LX_INIT_QUERY_VIRTIOFS_SHARE_MESSAGE
{
static inline auto Type = LxInitMessageQueryVirtioFsDevice;
using TResponse = LX_INIT_ADD_VIRTIOFS_SHARE_RESPONSE_MESSAGE;
MESSAGE_HEADER Header;
unsigned int TagOffset;
char Buffer[];
PRETTY_PRINT(FIELD(Header), STRING_FIELD(TagOffset));
} LX_INIT_QUERY_VIRTIOFS_SHARE_MESSAGE, *PLX_INIT_QUERY_VIRTIOFS_SHARE_MESSAGE;
//
// The messages that can be sent to mini_init.
//

View File

@ -52,26 +52,6 @@ inline unsigned int CopyToSpan(const std::string_view String, const gsl::span<gs
return PreviousOffset;
}
inline bool IsDriveRoot(const std::string_view Path)
{
bool IsRoot = true;
if (Path.length() == 3)
{
IsRoot &= Path[2] == '\\';
}
if (Path.length() == 2 || Path.length() == 3)
{
IsRoot &= isalpha(Path[0]) && Path[1] == ':';
}
else
{
IsRoot = false;
}
return IsRoot;
}
template <class T>
inline bool EndsWith(const std::basic_string<T>& String, const std::basic_string_view<T> Suffix)
{

View File

@ -26,8 +26,13 @@ static wil::srwlock g_endpointsInUseLock;
static std::vector<GUID> g_endpointsInUse;
NatNetworking::NatNetworking(
HCS_SYSTEM system, wsl::windows::common::hcs::unique_hcn_network&& network, GnsChannel&& gnsChannel, Config& config, wil::unique_socket&& dnsHvsocket) :
m_system(system), m_config(config), m_network(std::move(network)), m_gnsChannel(std::move(gnsChannel))
HCS_SYSTEM system,
wsl::windows::common::hcs::unique_hcn_network&& network,
GnsChannel&& gnsChannel,
Config& config,
wil::unique_socket&& dnsHvsocket,
LPCWSTR dnsOptions) :
m_system(system), m_config(config), m_network(std::move(network)), m_dnsOptions(dnsOptions), m_gnsChannel(std::move(gnsChannel))
{
m_connectivityTelemetryEnabled = config.EnableTelemetry && !WslTraceLoggingShouldDisableTelemetry();
@ -48,7 +53,7 @@ NatNetworking::NatNetworking(
// prioritized means:
// - can only set 3 DNS servers (Linux limitation)
// - when there are multiple host connected interfaces, we need to use the DNS servers from the most-likely-to-be-used interface on the host
m_mirrorDnsInfo.emplace();
m_useMirrorDnsSettings = true;
}
}
@ -337,7 +342,7 @@ void NatNetworking::Initialize()
UpdateDns(endpointProperties.GatewayAddress.c_str());
// if using the shared access DNS proxy, ensure that the shared access service is allowed inbound UDP access.
if (!m_mirrorDnsInfo && !m_dnsTunnelingResolver)
if (!m_useMirrorDnsSettings && !m_dnsTunnelingResolver)
{
// N.B. This rule works around a host OS issue that prevents the DNS proxy from working on older versions of Windows.
ConfigureSharedAccessFirewallRule();
@ -433,35 +438,22 @@ _Requires_lock_held_(m_lock)
void NatNetworking::UpdateDns(std::optional<PCWSTR> gatewayAddress) noexcept
try
{
if (!m_dnsTunnelingResolver && !m_mirrorDnsInfo && !gatewayAddress)
if (!m_dnsTunnelingResolver && !m_useMirrorDnsSettings && !gatewayAddress)
{
return;
}
networking::DnsInfo latestDnsSettings{};
// true if the "domain" entry of /etc/resolv.conf should be configured
// Note: the "domain" entry allows a single DNS suffix to be configured
bool configureLinuxDomain = false;
// NAT mode with DNS tunneling
if (m_dnsTunnelingResolver)
{
latestDnsSettings = HostDnsInfo::GetDnsTunnelingSettings(m_dnsTunnelingIpAddress);
}
// NAT mode without Shared Access DNS proxy
else if (m_mirrorDnsInfo)
else if (m_useMirrorDnsSettings)
{
m_mirrorDnsInfo->UpdateNetworkInformation();
const auto settings = m_mirrorDnsInfo->GetDnsSettings(DnsSettingsFlags::IncludeVpn);
latestDnsSettings.Servers = std::move(settings.Servers);
if (!settings.Domains.empty())
{
latestDnsSettings.Domains.emplace_back(std::move(settings.Domains.front()));
configureLinuxDomain = true;
}
latestDnsSettings = HostDnsInfo::GetDnsSettings(DnsSettingsFlags::IncludeVpn);
}
// NAT mode with Shared Access DNS proxy
else if (gatewayAddress)
@ -472,11 +464,10 @@ try
if (latestDnsSettings != m_trackedDnsSettings)
{
auto dnsNotification = BuildDnsNotification(latestDnsSettings, configureLinuxDomain);
auto dnsNotification = BuildDnsNotification(latestDnsSettings, m_dnsOptions);
WSL_LOG(
"NatNetworking::UpdateDns",
TraceLoggingValue(dnsNotification.Domain.c_str(), "domain"),
TraceLoggingValue(dnsNotification.Options.c_str(), "options"),
TraceLoggingValue(dnsNotification.Search.c_str(), "search"),
TraceLoggingValue(dnsNotification.ServerList.c_str(), "serverList"));

View File

@ -18,7 +18,13 @@ namespace wsl::core {
class NatNetworking final : public INetworkingEngine
{
public:
NatNetworking(HCS_SYSTEM system, wsl::windows::common::hcs::unique_hcn_network&& network, GnsChannel&& gnsChannel, Config& config, wil::unique_socket&& dnsHvsocket);
NatNetworking(
HCS_SYSTEM system,
wsl::windows::common::hcs::unique_hcn_network&& network,
GnsChannel&& gnsChannel,
Config& config,
wil::unique_socket&& dnsHvsocket,
LPCWSTR dnsOptions = LX_INIT_RESOLVCONF_FULL_HEADER);
~NatNetworking() override;
// Note: This class cannot be moved because m_networkNotifyHandle captures a 'this' pointer.
@ -69,12 +75,18 @@ private:
// The latest DNS settings configured in Linux
_Guarded_by_(m_lock) networking::DnsInfo m_trackedDnsSettings {};
// If true, DNS settings are retrieved from host adapters (mirrored mode)
// rather than using the shared access DNS proxy
bool m_useMirrorDnsSettings = false;
// Options/header for /etc/resolv.conf
LPCWSTR m_dnsOptions = nullptr;
GnsChannel m_gnsChannel;
std::shared_ptr<networking::NetworkSettings> m_networkSettings;
networking::EphemeralHcnEndpoint m_endpoint;
ULONG m_networkMtu = 0;
std::optional<networking::HostDnsInfo> m_mirrorDnsInfo;
networking::unique_notify_handle m_networkNotifyHandle{};
};

View File

@ -14,11 +14,12 @@ using wsl::core::VirtioNetworking;
static constexpr auto c_loopbackDeviceName = TEXT(LX_INIT_LOOPBACK_DEVICE_NAME);
VirtioNetworking::VirtioNetworking(
GnsChannel&& gnsChannel, bool enableLocalhostRelay, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken) :
GnsChannel&& gnsChannel, bool enableLocalhostRelay, LPCWSTR dnsOptions, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken) :
m_guestDeviceManager(std::move(guestDeviceManager)),
m_userToken(std::move(userToken)),
m_gnsChannel(std::move(gnsChannel)),
m_enableLocalhostRelay(enableLocalhostRelay)
m_enableLocalhostRelay(enableLocalhostRelay),
m_dnsOptions(dnsOptions)
{
}
@ -66,7 +67,7 @@ void VirtioNetworking::Initialize()
}
// Get initial DNS settings for device options.
auto initialDns = m_dnsUpdateHelper.GetCurrentDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
auto initialDns = networking::HostDnsInfo::GetDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
if (!initialDns.Servers.empty())
{
if (device_options.tellp() > 0)
@ -260,7 +261,7 @@ try
UpdateMtu();
// Check for DNS changes and send update if needed.
auto currentDns = m_dnsUpdateHelper.GetCurrentDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
auto currentDns = networking::HostDnsInfo::GetDnsSettings(networking::DnsSettingsFlags::IncludeVpn);
if (currentDns != m_trackedDnsSettings)
{
m_trackedDnsSettings = currentDns;
@ -274,7 +275,7 @@ void VirtioNetworking::SendDnsUpdate(const networking::DnsInfo& dnsSettings)
hns::ModifyGuestEndpointSettingRequest<hns::DNS> notification{};
notification.RequestType = hns::ModifyRequestType::Update;
notification.ResourceType = hns::GuestEndpointResourceType::DNS;
notification.Settings = networking::BuildDnsNotification(dnsSettings);
notification.Settings = networking::BuildDnsNotification(dnsSettings, m_dnsOptions);
m_gnsChannel.SendHnsNotification(ToJsonW(notification).c_str(), m_adapterId);
}

View File

@ -13,7 +13,7 @@ namespace wsl::core {
class VirtioNetworking : public INetworkingEngine
{
public:
VirtioNetworking(GnsChannel&& gnsChannel, bool enableLocalhostRelay, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken);
VirtioNetworking(GnsChannel&& gnsChannel, bool enableLocalhostRelay, LPCWSTR dnsOptions, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken);
~VirtioNetworking();
// Note: This class cannot be moved because m_networkNotifyHandle captures a 'this' pointer.
@ -49,12 +49,12 @@ private:
std::optional<GnsPortTrackerChannel> m_gnsPortTrackerChannel;
std::shared_ptr<networking::NetworkSettings> m_networkSettings;
bool m_enableLocalhostRelay;
LPCWSTR m_dnsOptions = nullptr;
GUID m_localhostAdapterId;
GUID m_adapterId;
std::optional<ULONGLONG> m_interfaceLuid;
ULONG m_networkMtu = 0;
networking::DnsUpdateHelper m_dnsUpdateHelper;
networking::DnsInfo m_trackedDnsSettings;
// Note: this field must be destroyed first to stop the callbacks before any other field is destroyed.

View File

@ -105,12 +105,6 @@ wsl::core::networking::DnsInfo wsl::core::networking::HostDnsInfo::GetDnsTunneli
return dnsInfo;
}
std::vector<wsl::core::networking::IpAdapterAddress> wsl::core::networking::HostDnsInfo::GetAdapterAddresses()
{
std::lock_guard<std::mutex> lock(m_lock);
return m_addresses;
}
std::vector<std::string> wsl::core::networking::HostDnsInfo::GetDnsServerStrings(
_In_ const PIP_ADAPTER_DNS_SERVER_ADDRESS& FirstDnsServer, _In_ USHORT IpFamilyFilter, _In_ USHORT MaxValues)
{
@ -233,7 +227,7 @@ std::vector<std::string> wsl::core::networking::HostDnsInfo::GetInterfaceDnsSuff
wsl::core::networking::DnsInfo wsl::core::networking::HostDnsInfo::GetDnsSettings(_In_ DnsSettingsFlags Flags)
{
std::vector<IpAdapterAddress> Addresses = GetAdapterAddresses();
std::vector<IpAdapterAddress> Addresses = AdapterAddresses::GetCurrent();
auto RemoveFilter = [&](const IpAdapterAddress& Address) {
// Ignore interfaces that are not currently "up".
@ -326,12 +320,6 @@ wsl::core::networking::DnsInfo wsl::core::networking::HostDnsInfo::GetDnsSetting
return DnsSettings;
}
void wsl::core::networking::HostDnsInfo::UpdateNetworkInformation()
{
std::lock_guard<std::mutex> lock(m_lock);
m_addresses = AdapterAddresses::GetCurrent();
}
std::string wsl::core::networking::GenerateResolvConf(_In_ const DnsInfo& Info)
{
std::string contents{};
@ -345,7 +333,10 @@ std::string wsl::core::networking::GenerateResolvConf(_In_ const DnsInfo& Info)
contents += c_asciiNewLine;
}
// Add domain information if it is available.
// Add DNS suffix information using 'search' directive.
// Per resolv.conf(5): "The domain directive is an obsolete name for the search directive
// that handles one search list entry only."
// See: https://man7.org/linux/man-pages/man5/resolv.conf.5.html
if (!Info.Domains.empty())
{
contents += "search ";
@ -497,28 +488,21 @@ wsl::core::networking::DnsSuffixRegistryWatcher::DnsSuffixRegistryWatcher(Regist
m_registryWatchers.swap(localRegistryWatchers);
}
wsl::shared::hns::DNS wsl::core::networking::BuildDnsNotification(const DnsInfo& settings, bool useLinuxDomainEntry)
wsl::shared::hns::DNS wsl::core::networking::BuildDnsNotification(const DnsInfo& settings, PCWSTR options)
{
wsl::shared::hns::DNS dnsNotification{};
dnsNotification.Options = LX_INIT_RESOLVCONF_FULL_HEADER;
if (options)
{
dnsNotification.Options = options;
}
dnsNotification.ServerList = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(settings.Servers, ','));
if (useLinuxDomainEntry && !settings.Domains.empty())
{
// Use 'domain' entry for single DNS suffix (typically used when mirroring host DNS without tunneling)
dnsNotification.Domain = wsl::shared::string::MultiByteToWide(settings.Domains.front());
}
else
{
// Use 'search' entry for DNS suffix list
dnsNotification.Search = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(settings.Domains, ','));
}
// Use 'search' entry for DNS suffix list.
// Per resolv.conf(5): "The domain directive is an obsolete name for the search directive
// that handles one search list entry only."
// See: https://man7.org/linux/man-pages/man5/resolv.conf.5.html
dnsNotification.Search = wsl::shared::string::MultiByteToWide(wsl::shared::string::Join(settings.Domains, ','));
return dnsNotification;
}
wsl::core::networking::DnsInfo wsl::core::networking::DnsUpdateHelper::GetCurrentDnsSettings(DnsSettingsFlags flags)
{
m_hostDnsInfo.UpdateNetworkInformation();
return m_hostDnsInfo.GetDnsSettings(flags);
}

View File

@ -1,7 +1,6 @@
// Copyright (C) Microsoft Corporation. All rights reserved.
#pragma once
#include <mutex>
#include <string>
#include <vector>
@ -42,9 +41,9 @@ std::string GenerateResolvConf(_In_ const DnsInfo& Info);
/// Builds an hns::DNS notification from DnsInfo settings.
/// </summary>
/// <param name="settings">The DNS settings to convert</param>
/// <param name="useLinuxDomainEntry">If true, uses 'domain' entry for single suffix; otherwise uses 'search' for all
/// suffixes</param> <returns>The hns::DNS notification ready to send via GNS channel</returns>
wsl::shared::hns::DNS BuildDnsNotification(const DnsInfo& settings, bool useLinuxDomainEntry = false);
/// <param name="options">The resolv.conf header options (defaults to LX_INIT_RESOLVCONF_FULL_HEADER)</param>
/// <returns>The hns::DNS notification ready to send via GNS channel</returns>
wsl::shared::hns::DNS BuildDnsNotification(const DnsInfo& settings, PCWSTR options = LX_INIT_RESOLVCONF_FULL_HEADER);
std::vector<std::string> GetAllDnsSuffixes(const std::vector<IpAdapterAddress>& AdapterAddresses);
@ -53,27 +52,15 @@ DWORD GetBestInterface();
class HostDnsInfo
{
public:
DnsInfo GetDnsSettings(_In_ DnsSettingsFlags Flags);
void UpdateNetworkInformation();
static DnsInfo GetDnsSettings(_In_ DnsSettingsFlags Flags);
static DnsInfo GetDnsTunnelingSettings(const std::wstring& dnsTunnelingNameserver);
const std::vector<IpAdapterAddress>& CurrentAddresses() const
{
return m_addresses;
}
private:
/// <summary>
/// Internal function to retrieve the latest copy of interface information.
/// </summary>
std::vector<IpAdapterAddress> GetAdapterAddresses();
/// <summary>
/// Internal function to retrieve interface DNS servers.
/// </summary>
std::vector<std::string> GetInterfaceDnsServers(const std::vector<IpAdapterAddress>& AdapterAddresses, _In_ DnsSettingsFlags Flags);
static std::vector<std::string> GetInterfaceDnsServers(const std::vector<IpAdapterAddress>& AdapterAddresses, _In_ DnsSettingsFlags Flags);
/// <summary>
/// Internal function to retrieve all Windows DNS suffixes.
@ -84,30 +71,6 @@ private:
/// Internal function to convert DNS server addresses into strings.
/// </summary>
static std::vector<std::string> GetDnsServerStrings(_In_ const PIP_ADAPTER_DNS_SERVER_ADDRESS& DnsServer, _In_ USHORT IpFamilyFilter, _In_ USHORT MaxValues);
/// <summary>
/// Stores latest copy of interface information.
/// </summary>
std::mutex m_lock;
_Guarded_by_(m_lock) std::vector<IpAdapterAddress> m_addresses;
};
/// <summary>
/// Helper class that fetches current DNS settings from the host.
/// Callers are responsible for tracking changes if needed.
/// </summary>
class DnsUpdateHelper
{
public:
/// <summary>
/// Fetches current DNS settings from the host.
/// </summary>
/// <param name="flags">Flags controlling which DNS settings to include</param>
/// <returns>Current DNS settings</returns>
DnsInfo GetCurrentDnsSettings(DnsSettingsFlags flags);
private:
HostDnsInfo m_hostDnsInfo;
};
using RegistryChangeCallback = std::function<void()>;

View File

@ -784,9 +784,6 @@ try
// Impersonate the service.
auto runAsSelf = wil::run_as_self();
// Update the instance's DNS information.
m_dnsInfo.UpdateNetworkInformation();
// Update the resolv.conf file if it has changed.
_UpdateNetworkConfigurationFiles(false);
return;
@ -799,7 +796,7 @@ void LxssInstance::_UpdateNetworkConfigurationFiles(_In_ bool UpdateAlways)
wsl::core::networking::DnsSettingsFlags flags = wsl::core::networking::DnsSettingsFlags::IncludeIpv6Servers;
WI_SetFlagIf(flags, wsl::core::networking::DnsSettingsFlags::IncludeVpn, m_enableVpnDetection);
const auto dnsSettings = m_dnsInfo.GetDnsSettings(flags);
const auto dnsSettings = wsl::core::networking::HostDnsInfo::GetDnsSettings(flags);
std::string fileContents = GenerateResolvConf(dnsSettings);
std::lock_guard<std::mutex> lock(m_resolvConfLock);
if (!UpdateAlways && (fileContents == m_lastResolvConfContents))

View File

@ -224,11 +224,6 @@ private:
/// </summary>
LxssIpTables m_ipTables;
/// <summary>
/// Class for querying host dns information.
/// </summary>
wsl::core::networking::HostDnsInfo m_dnsInfo;
/// <summary>
/// Settings for updating /etc/resolv.conf.
/// </summary>

View File

@ -570,7 +570,7 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
else if (m_vmConfig.NetworkingMode == NetworkingMode::VirtioProxy)
{
m_networkingEngine = std::make_unique<wsl::core::VirtioNetworking>(
std::move(gnsChannel), m_vmConfig.EnableLocalhostRelay, m_guestDeviceManager, m_userToken);
std::move(gnsChannel), m_vmConfig.EnableLocalhostRelay, LX_INIT_RESOLVCONF_FULL_HEADER, m_guestDeviceManager, m_userToken);
}
else if (m_vmConfig.NetworkingMode == NetworkingMode::Bridged)
{
@ -845,9 +845,6 @@ void WslCoreVm::AddDrvFsShare(_In_ bool Admin, _In_ HANDLE UserToken)
{
// Add virtiofs devices associating indices with paths from the fixed drive bitmap. These devices support
// multiple mounts in the guest, so this only needs to be done once.
// EX: drvfsC1 => C:\
// drvfsD2 => D:\
// drvfsaC3 => C:\ (elevated)
auto fixedDrives = wsl::windows::common::filesystem::EnumerateFixedDrives(UserToken).first;
while (fixedDrives != 0)
{
@ -2084,7 +2081,7 @@ void WslCoreVm::WaitForPmemDeviceInVm(_In_ ULONG PmemId)
_Requires_lock_held_(m_guestDeviceLock)
std::wstring WslCoreVm::AddVirtioFsShare(_In_ bool Admin, _In_ PCWSTR Path, _In_ PCWSTR Options, _In_opt_ HANDLE UserToken)
{
WI_ASSERT(m_vmConfig.EnableVirtioFs && wsl::shared::string::IsDriveRoot(wsl::shared::string::WideToMultiByte(Path)));
WI_ASSERT(m_vmConfig.EnableVirtioFs);
if (!ARGUMENT_PRESENT(UserToken))
{
@ -2095,22 +2092,27 @@ std::wstring WslCoreVm::AddVirtioFsShare(_In_ bool Admin, _In_ PCWSTR Path, _In_
WI_ASSERT(Admin == wsl::windows::common::security::IsTokenElevated(UserToken));
// Ensure that the path has a trailing path separator.
std::wstring sharePath{Path};
if (sharePath.back() != L'\\')
std::wstring sharePath(Path);
if (!sharePath.ends_with(L'\\') && !sharePath.ends_with(L'/'))
{
sharePath += L'\\';
sharePath.push_back(L'\\');
}
sharePath = std::filesystem::weakly_canonical(sharePath).wstring();
// Check if a matching share already exists.
bool created = false;
std::wstring tag;
VirtioFsShare key(sharePath.c_str(), Options, Admin);
if (!m_virtioFsShares.contains(key))
{
// Generate a new tag for the share.
tag = Admin ? TEXT(LX_INIT_DRVFS_ADMIN_VIRTIO_TAG) : TEXT(LX_INIT_DRVFS_VIRTIO_TAG);
tag += sharePath[0];
tag += std::to_wstring(m_virtioFsShares.size());
// Generate a new unique tag for the share.
//
// N.B. The tag can be maximum 36 characters long so a GUID without braces fits perfectly.
GUID tagGuid{};
THROW_IF_FAILED(CoCreateGuid(&tagGuid));
tag = wsl::shared::string::GuidToString<wchar_t>(tagGuid, wsl::shared::string::None);
WI_ASSERT(!FindVirtioFsShare(tag.c_str(), Admin));
(void)m_guestDeviceManager->AddGuestDevice(
@ -2546,8 +2548,6 @@ try
THROW_HR_IF(E_UNEXPECTED, !addShare);
const auto path = wsl::shared::string::FromSpan(span, addShare->PathOffset);
THROW_HR_IF_MSG(E_INVALIDARG, !wsl::shared::string::IsDriveRoot(path), "%hs is not the root of a drive", path);
const auto pathWide = wsl::shared::string::MultiByteToWide(path);
const auto options = wsl::shared::string::FromSpan(span, addShare->OptionsOffset);
const auto optionsWide = wsl::shared::string::MultiByteToWide(options);
@ -2567,19 +2567,6 @@ try
THROW_HR_IF(E_UNEXPECTED, !remountShare);
const std::string tag = wsl::shared::string::FromSpan(span, remountShare->TagOffset);
if (tag.find(LX_INIT_DRVFS_ADMIN_VIRTIO_TAG, 0) == 0)
{
THROW_HR_IF(E_UNEXPECTED, remountShare->Admin);
}
else if (tag.find(LX_INIT_DRVFS_VIRTIO_TAG, 0) == 0)
{
THROW_HR_IF(E_UNEXPECTED, !remountShare->Admin);
}
else
{
THROW_HR_MSG(E_UNEXPECTED, "Unexpected tag %hs", tag.data());
}
const auto tagWide = wsl::shared::string::MultiByteToWide(tag);
auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
const auto foundShare = FindVirtioFsShare(tagWide.c_str(), !remountShare->Admin);
@ -2590,6 +2577,24 @@ try
respondWithTag(newTag, result);
}
else if (message->MessageType == LxInitMessageQueryVirtioFsDevice)
{
std::wstring newTag;
const auto result = wil::ResultFromException([this, span, &newTag]() {
const auto* query = gslhelpers::try_get_struct<LX_INIT_QUERY_VIRTIOFS_SHARE_MESSAGE>(span);
THROW_HR_IF(E_UNEXPECTED, !query);
const std::string tag = wsl::shared::string::FromSpan(span, query->TagOffset);
const auto tagWide = wsl::shared::string::MultiByteToWide(tag);
auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
const auto foundShare = FindVirtioFsShare(tagWide.c_str());
THROW_HR_IF_MSG(E_UNEXPECTED, !foundShare.has_value(), "Unknown tag %ls", tagWide.c_str());
newTag = foundShare->Path;
});
respondWithTag(newTag, result);
}
else
{
THROW_HR_MSG(E_UNEXPECTED, "Unexpected MessageType %d", message->MessageType);

View File

@ -434,8 +434,7 @@ void wsl::core::networking::WslMirroredNetworkManager::ProcessDNSChange()
}
else
{
m_hostDnsInfo.UpdateNetworkInformation();
m_dnsInfo = m_hostDnsInfo.GetDnsSettings(
m_dnsInfo = wsl::core::networking::HostDnsInfo::GetDnsSettings(
wsl::core::networking::DnsSettingsFlags::IncludeVpn | wsl::core::networking::DnsSettingsFlags::IncludeIpv6Servers |
wsl::core::networking::DnsSettingsFlags::IncludeAllSuffixes);
}

View File

@ -224,9 +224,6 @@ private:
_Guarded_by_(m_networkLock) DnsInfo m_trackedDnsInfo;
// The current DNS info on the host
_Guarded_by_(m_networkLock) DnsInfo m_dnsInfo;
// m_hostDnsInfo is an optimization used to avoid allocating a large buffer every time we call
// GetAdaptersAddresses when querying host DNS info
_Guarded_by_(m_networkLock) HostDnsInfo m_hostDnsInfo;
std::wstring m_dnsTunnelingIpAddress;

View File

@ -561,11 +561,13 @@ void WSLAVirtualMachine::ConfigureNetworking()
wsl::core::NatNetworking::CreateNetwork(config),
std::move(gnsChannel),
config,
dnsChannelFd != -1 ? wil::unique_socket{(SOCKET)process->GetStdHandle(dnsChannelFd).release()} : wil::unique_socket{});
dnsChannelFd != -1 ? wil::unique_socket{(SOCKET)process->GetStdHandle(dnsChannelFd).release()} : wil::unique_socket{},
nullptr);
}
else
{
m_networkEngine = std::make_unique<wsl::core::VirtioNetworking>(std::move(gnsChannel), false, m_guestDeviceManager, m_userToken);
m_networkEngine =
std::make_unique<wsl::core::VirtioNetworking>(std::move(gnsChannel), false, nullptr, m_guestDeviceManager, m_userToken);
}
m_networkEngine->Initialize();

View File

@ -294,7 +294,7 @@ Return Value:
snprintf(
Plan9Options,
sizeof(Plan9Options),
"aname=drvfs;path=%s%s;symlinkroot=/mnt/,cache=5,access=client,msize=65536,trans=fd,rfd=4,wfd=4",
"aname=drvfs;path=%s%s;symlinkroot=/mnt/,cache=5,access=client,msize=65536,trans=fd,rfd=*,wfd=*",
Plan9Source,
Temp);
}

View File

@ -28,6 +28,7 @@ Abstract:
#define PATH_MAX (4096)
void MountEscapeString(const char* Source, char* Dest, size_t Length);
int MountCheckFsOptionsPattern(const char* Pattern, const char* Actual);
int MountCheckIsMount(
const char* Path,
@ -127,7 +128,14 @@ Return Value:
LxtCheckStringEqual(ExpectedMountOptions, mnt_fs_get_vfs_options(FileSystem));
if (ExpectedFsOptions != NULL)
{
LxtCheckStringEqual(ExpectedFsOptions, mnt_fs_get_fs_options(FileSystem));
if (strchr(ExpectedFsOptions, '*') != NULL)
{
LxtCheckResult(MountCheckFsOptionsPattern(ExpectedFsOptions, mnt_fs_get_fs_options(FileSystem)));
}
else
{
LxtCheckStringEqual(ExpectedFsOptions, mnt_fs_get_fs_options(FileSystem));
}
}
LxtCheckEqual(Stat.st_dev, mnt_fs_get_devno(FileSystem), "%lu");
@ -235,6 +243,109 @@ ErrorExit:
return Result;
}
int MountCheckFsOptionsPattern(const char* Pattern, const char* Actual)
/*++
Description:
This routine checks if mount options match a pattern with wildcards.
The '*' wildcard matches any sequence of characters.
Arguments:
Pattern - Supplies the expected pattern (e.g., "rfd=*,wfd=*").
Actual - Supplies the actual mount options string.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
const char* ActualPtr;
const char* MatchPosition;
const char* PatternPtr;
int Result;
const char* StarPosition;
PatternPtr = Pattern;
ActualPtr = Actual;
StarPosition = NULL;
MatchPosition = NULL;
Result = LXT_RESULT_FAILURE;
while (*ActualPtr != '\0')
{
if (*PatternPtr == '*')
{
//
// Remember position of * and where we are in actual string.
//
StarPosition = PatternPtr++;
MatchPosition = ActualPtr;
}
else if (*PatternPtr == *ActualPtr)
{
//
// Characters match, advance both.
//
PatternPtr++;
ActualPtr++;
}
else if (StarPosition != NULL)
{
//
// Mismatch but we have a *, backtrack and try matching one more character.
//
PatternPtr = StarPosition + 1;
ActualPtr = ++MatchPosition;
}
else
{
//
// Mismatch and no * to backtrack to.
//
goto ErrorExit;
}
}
//
// Consume any trailing *'s in pattern.
//
while (*PatternPtr == '*')
{
PatternPtr++;
}
//
// Both should be at end of string.
//
if (*PatternPtr != '\0')
{
goto ErrorExit;
}
Result = LXT_RESULT_SUCCESS;
ErrorExit:
if (!LXT_SUCCESS(Result))
{
LxtLogError("Mount options mismatch: expected '%s', got '%s'", Pattern, Actual);
}
return Result;
}
void MountEscapeString(const char* Source, char* Dest, size_t Length)
/*++

View File

@ -1706,11 +1706,7 @@ Return Value:
if (LxsstuVmMode())
{
std::wstring Command = L"/bin/cp /data/test/log/";
Command += LogFileToken;
Command += L" $(wslpath '";
Command += LinuxLogPath;
Command += L"')";
std::wstring Command = std::format(L"/bin/cp /data/test/log/{} $(wslpath '{}')", LogFileToken, LinuxLogPath);
VERIFY_NO_THROW(LxsstuRunTest(Command.c_str()));
}

View File

@ -226,12 +226,6 @@ public:
{
SKIP_TEST_ARM64();
if (Mode == DrvFsMode::VirtioFs)
{
LogSkipped("VirtioFS currently only supports mounting full drives");
return;
}
constexpr auto MountPoint = "C:\\lxss_fat";
constexpr auto VhdPath = "C:\\lxss_fat.vhdx";
auto Cleanup = wil::scope_exit([MountPoint, VhdPath] { DeleteVolume(MountPoint, VhdPath); });
@ -352,12 +346,6 @@ public:
SKIP_TEST_ARM64();
WSL_TEST_VERSION_REQUIRED(wsl::windows::common::helpers::WindowsBuildNumbers::Germanium);
if (Mode == DrvFsMode::VirtioFs)
{
LogSkipped("VirtioFS currently only supports mounting full drives");
return;
}
constexpr auto MountPoint = "C:\\lxss_refs";
constexpr auto VhdPath = "C:\\lxss_refs.vhdx";
auto Cleanup = wil::scope_exit([MountPoint, VhdPath] { DeleteVolume(MountPoint, VhdPath); });
@ -367,6 +355,68 @@ public:
LxsstuRunTest((L"bash -c '" + SkipUnstableTestEnvVar + L" /data/test/wsl_unit_tests drvfs -m 6'").c_str(), L"drvfs6"));
}
void WslPath(DrvFsMode Mode)
{
VERIFY_NO_THROW(LxsstuRunTest(L"/data/test/wsl_unit_tests wslpath", L"wslpath"));
auto testWslPath = [](const std::wstring& testDir) {
auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() { std::filesystem::remove_all(testDir); });
std::filesystem::create_directory(testDir);
auto [out, err] = LxsstuLaunchWslAndCaptureOutput(std::format(L"wslpath -aw '{}'", testDir));
VERIFY_ARE_EQUAL((std::filesystem::canonical(std::filesystem::current_path()) / testDir).wstring() + L"\n", out);
std::tie(out, err) = LxsstuLaunchWslAndCaptureOutput(std::format(L"wslpath -wa '{}'", testDir));
VERIFY_ARE_EQUAL((std::filesystem::canonical(std::filesystem::current_path()) / testDir).wstring() + L"\n", out);
std::tie(out, err) = LxsstuLaunchWslAndCaptureOutput(std::format(L"wslpath '{}'", testDir));
VERIFY_ARE_EQUAL(std::format(L"{}\n", testDir), out);
std::tie(out, err) = LxsstuLaunchWslAndCaptureOutput(std::format(L"wslpath -a '{}'", testDir));
VERIFY_IS_TRUE(out.find(L"/mnt/") == 0);
};
testWslPath(L"wslpath-test-dir");
testWslPath(L"wslpath-测试目录-テスト");
}
void DrvFsMountUnicodePath(DrvFsMode Mode)
{
WSL2_TEST_ONLY();
// Create a Windows directory with unicode characters
constexpr auto unicodeDir = L"C:\\drvfs-测试-テスト";
auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() { std::filesystem::remove_all(unicodeDir); });
std::filesystem::create_directory(unicodeDir);
// Create a test file inside the directory
const auto testFilePath = std::filesystem::path(unicodeDir) / L"test-file.txt";
{
std::ofstream testFile(testFilePath);
testFile << "hello from unicode path";
}
// Mount the unicode directory using mount -t drvfs
constexpr auto mountPoint = L"/tmp/unicode-mount-test";
auto unmountCleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
LxsstuLaunchWsl(std::format(L"-u root umount '{}'", mountPoint).c_str());
LxsstuLaunchWsl(std::format(L"-u root rmdir '{}'", mountPoint).c_str());
});
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-u root mkdir -p '{}'", mountPoint).c_str()), 0);
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-u root mount -t drvfs '{}' '{}'", unicodeDir, mountPoint).c_str()), 0);
// Verify we can read the test file through the mount
auto [out, err] = LxsstuLaunchWslAndCaptureOutput(std::format(L"cat '{}/test-file.txt'", mountPoint));
VERIFY_ARE_EQUAL(L"hello from unicode path", out);
// Verify we can list the directory
std::tie(out, err) = LxsstuLaunchWslAndCaptureOutput(std::format(L"ls '{}'", mountPoint));
VERIFY_IS_TRUE(out.find(L"test-file.txt") != std::wstring::npos);
}
// DrvFsTests Private Methods
private:
static VOID CreateDrvFsTestFiles(bool Metadata)
@ -935,7 +985,11 @@ private:
const auto lines = LxssSplitString(output.Stdout, L"\n");
VERIFY_ARE_EQUAL(lines.size(), 1);
VERIFY_IS_TRUE(output.Stdout.find(expectedType) == 0);
if (!expectedType.empty())
{
VERIFY_IS_TRUE(output.Stdout.find(expectedType) == 0);
}
};
std::wstring elevatedType;
@ -951,8 +1005,7 @@ private:
nonElevatedType = L"drvfs";
break;
case DrvFsMode::VirtioFs:
elevatedType = L"drvfsaC";
nonElevatedType = L"drvfsC";
// VirtioFs uses GUIDs as the tag so the value is not predictable.
break;
default:
@ -1149,6 +1202,12 @@ class WSL1 : public DrvFsTests
WSL1_TEST_ONLY();
DrvFsTests::XattrDrvFs(DrvFsMode::WSL1);
}
TEST_METHOD(WslPath)
{
WSL1_TEST_ONLY();
DrvFsTests::WslPath(DrvFsMode::WSL1);
}
};
#define WSL2_DRVFS_TEST_CLASS(_mode) \
@ -1266,6 +1325,18 @@ class WSL1 : public DrvFsTests
WSL2_TEST_ONLY(); \
DrvFsTests::DrvFsReFs(DrvFsMode::##_mode##); \
} \
\
TEST_METHOD(WslPath) \
{ \
WSL2_TEST_ONLY(); \
DrvFsTests::WslPath(DrvFsMode::##_mode##); \
} \
\
TEST_METHOD(DrvFsMountUnicodePath) \
{ \
WSL2_TEST_ONLY(); \
DrvFsTests::DrvFsMountUnicodePath(DrvFsMode::##_mode##); \
} \
}
WSL2_DRVFS_TEST_CLASS(Plan9);

View File

@ -1037,7 +1037,6 @@ class NetworkTests
wsl::shared::hns::DNS dns;
dns.ServerList = L"1.1.1.1,1.1.1.2";
dns.Domain = L"microsoft.com";
dns.Search = L"foo.microsoft.com,bar.microsoft.com";
dns.Options = LX_INIT_RESOLVCONF_FULL_HEADER;
RunGns(dns, ModifyRequestType::Update, GuestEndpointResourceType::DNS);
@ -1047,7 +1046,6 @@ class NetworkTests
const std::wstring expected = std::wstring(LX_INIT_RESOLVCONF_FULL_HEADER) +
L"nameserver 1.1.1.1\n"
L"nameserver 1.1.1.2\n"
L"domain microsoft.com\n"
L"search foo.microsoft.com bar.microsoft.com\n";
VERIFY_ARE_EQUAL(expected, out.c_str());
}
@ -4612,6 +4610,9 @@ class VirtioProxyTests
const std::wregex pattern(L"(.|\\n)*nameserver [0-9. ]+(.|\\n)*");
VERIFY_IS_TRUE(std::regex_match(out, pattern));
// Verify that /etc/resolv.conf contains a 'search' line with DNS suffixes
VERIFY_IS_TRUE(out.find(L"search ") != std::wstring::npos);
}
TEST_METHOD(GuestPortIsReleased)

View File

@ -878,11 +878,6 @@ class UnitTests
}
}
TEST_METHOD(WslPath)
{
VERIFY_NO_THROW(LxsstuRunTest(L"/data/test/wsl_unit_tests wslpath", L"wslpath"));
}
TEST_METHOD(FsTab)
{
//
@ -5958,25 +5953,6 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n",
VERIFY_IS_TRUE(a);
VERIFY_ARE_EQUAL(pos, L"-");
}
{
constexpr auto testDir = "wslpath-test-dir";
auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, []() { std::filesystem::remove_all(testDir); });
std::filesystem::create_directory(testDir);
auto [out, err] = LxsstuLaunchWslAndCaptureOutput(std::format(L"wslpath -aw {}", testDir));
VERIFY_ARE_EQUAL((std::filesystem::canonical(std::filesystem::current_path()) / testDir).wstring() + L"\n", out);
std::tie(out, err) = LxsstuLaunchWslAndCaptureOutput(std::format(L"wslpath -wa {}", testDir));
VERIFY_ARE_EQUAL((std::filesystem::canonical(std::filesystem::current_path()) / testDir).wstring() + L"\n", out);
std::tie(out, err) = LxsstuLaunchWslAndCaptureOutput(std::format(L"wslpath {}", testDir));
VERIFY_ARE_EQUAL(std::format(L"{}\n", testDir), out);
std::tie(out, err) = LxsstuLaunchWslAndCaptureOutput(std::format(L"wslpath -a {}", testDir));
VERIFY_IS_TRUE(out.find(L"/mnt/") == 0);
}
}
TEST_METHOD(CaseSensitivity)