master
cpp 755 lines 34.1 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2
3 #include "MirroredNetworking.h"
4 #include "Stringify.h"
5 #include "WslCoreFirewallSupport.h"
6 #include "WslCoreNetworkingSupport.h"
7 #include "WslMirroredNetworking.h"
8 #include "WslCoreVm.h"
9
10 using wsl::core::MirroredNetworking;
11 using wsl::core::networking::NetworkEndpoint;
12 using namespace wsl::shared;
13
14 MirroredNetworking::MirroredNetworking(HCS_SYSTEM system, GnsChannel&& gnsChannel, const Config& config, GUID runtimeId, wil::unique_socket&& dnsHvsocket) :
15 m_system(system), m_runtimeId(runtimeId), m_config(config), m_gnsChannel(std::move(gnsChannel))
16 {
17 // ensure the MTA apartment stays alive for the lifetime of this object in this process for our callback
18 THROW_IF_FAILED(CoIncrementMTAUsage(&m_mtaCookie));
19
20 // Create the DNS resolver used for DNS tunneling
21 if (dnsHvsocket)
22 {
23 networking::DnsResolverFlags resolverFlags{};
24 WI_SetFlagIf(resolverFlags, networking::DnsResolverFlags::BestEffortDnsParsing, m_config.BestEffortDnsParsing);
25
26 m_dnsTunnelingResolver.emplace(std::move(dnsHvsocket), resolverFlags);
27 }
28 }
29
30 MirroredNetworking::~MirroredNetworking()
31 {
32 // Unblock GNSChannel if any calls are pended to unblock all the threadpools
33 // will also unblock m_networkManager, if that's waiting for calls through the GNS channel into Linux
34 m_gnsChannel.Stop();
35
36 // Stop DNS suffix change notifications before stopping m_networkManager and m_networkingQueue, as they can call into those objects.
37 m_dnsSuffixRegistryWatcher.reset();
38
39 // Gns must unregister all callbacks first (which could call into m_networkManager)
40 // Then we must shutdown the entire m_networkManager
41 // Accessing m_gnsRpcServer here is safe because it's only written to in the
42 // constructor, which is protected by m_instanceLock in LxssUserSessionImpl
43 if (m_gnsRpcServer)
44 {
45 // Unregister for GNS notifications
46 m_guestNetworkService.Stop();
47
48 if (m_networkManager)
49 {
50 m_networkManager->Stop();
51 }
52 }
53
54 // stop the TCPIP network change notifications - then stop all queued network work
55 m_addressNotificationHandle.reset();
56 m_routeNotificationHandle.reset();
57 m_interfaceNotificationHandle.reset();
58 m_networkNotificationHandle.reset();
59
60 m_gnsPortTrackerChannel.reset();
61 m_networkingQueue.cancel();
62 m_gnsMessageQueue.cancel();
63 }
64
65 // static
66 bool MirroredNetworking::IsHyperVFirewallSupported(const wsl::core::Config& vmConfig) noexcept
67 {
68 PCSTR executionStep = "";
69 try
70 {
71 const auto hyperVFirewallSupport = wsl::core::networking::GetHyperVFirewallSupportVersion(vmConfig.FirewallConfig);
72
73 if (hyperVFirewallSupport == wsl::core::networking::HyperVFirewallSupport::None)
74 {
75 WSL_LOG("IsHyperVFirewallSupported returning false: No Hyper-V Firewall API present");
76 return false;
77 }
78
79 if (hyperVFirewallSupport == wsl::core::networking::HyperVFirewallSupport::Version1)
80 {
81 // not allowing Hyper-V Firewall support with WSL with just the Version1 Hyper-V Firewall API
82 WSL_LOG("IsHyperVFirewallSupported returning false: WSL requires Hyper-V Firewall version2 but version1 is present");
83 return false;
84 }
85
86 executionStep = "HcnEnumerateNetworks";
87 // Check to see if the network is already created without Hyper-V Firewall.
88 // HNS only supports one networking configuration per boot cycle, so if it was configured with the
89 // Mirrored flag but without the Hyper-V Firewall flag, then we MUST NOT attempt to enable Hyper-V Firewall.
90 for (const auto& id : wsl::core::networking::EnumerateNetworks())
91 {
92 executionStep = "HcnOpenNetwork";
93 auto network = wsl::core::networking::OpenNetwork(id);
94
95 executionStep = "HcnQueryNetworkProperties";
96 auto [networkProperties, propertiesString] = wsl::core::networking::QueryNetworkProperties(network.get());
97 if (WI_IsFlagSet(static_cast<uint32_t>(networkProperties.Flags), WI_EnumValue(wsl::shared::hns::NetworkFlags::EnableFlowSteering)) &&
98 !WI_IsFlagSet(static_cast<uint32_t>(networkProperties.Flags), WI_EnumValue(wsl::shared::hns::NetworkFlags::EnableFirewall)))
99 {
100 WSL_LOG(
101 "IsHyperVFirewallSupported returning false: HNS Mirrored-network already created without Hyper-V Firewall "
102 "support, cannot enable Hyper-V Firewall");
103 return false;
104 }
105 }
106
107 return true;
108 }
109 catch (...)
110 {
111 const auto hr = wil::ResultFromCaughtException();
112 WSL_LOG(
113 "IsHyperVFirewallSupportedFailed",
114 TraceLoggingHResult(hr, "result"),
115 TraceLoggingValue(executionStep, "executionStep"),
116 TraceLoggingValue("Mirrored", "networkingMode"));
117
118 return false;
119 }
120 }
121
122 // static
123 bool MirroredNetworking::IsExternalInterfaceConstrained(const HCN_NETWORK network) noexcept
124 {
125 try
126 {
127 // Read interface constraint
128 const auto lxssKey = windows::common::registry::OpenLxssMachineKey(KEY_READ);
129 const auto interfaceConstraint =
130 windows::common::registry::ReadString(lxssKey.get(), nullptr, networking::c_interfaceConstraintKey, L"");
131
132 if (!interfaceConstraint.empty())
133 {
134 // The user has configured an ExternalInterfaceConstraint
135
136 // Use GetAdapterAddresses to obtain the InterfaceGuid of the interface corresponding to the constraint
137 constexpr auto GET_ADAPTER_ADDRESSES_BUFFER_SIZE_INITIAL = (15 * 1024);
138 constexpr auto GAA_FLAGS = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_DNS_SERVER;
139
140 ULONG result = ERROR_SUCCESS;
141 ULONG bufferSize = GET_ADAPTER_ADDRESSES_BUFFER_SIZE_INITIAL;
142 std::vector<std::byte> buffer;
143 PIP_ADAPTER_ADDRESSES adapter;
144
145 do
146 {
147 buffer.resize(bufferSize);
148 adapter = gslhelpers::get_struct<IP_ADAPTER_ADDRESSES>(gsl::make_span(buffer));
149 result = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAGS, nullptr, adapter, &bufferSize);
150 } while (result == ERROR_BUFFER_OVERFLOW);
151
152 THROW_LAST_ERROR_IF_MSG(result != ERROR_SUCCESS, "GetAdaptersAddresses");
153
154 // Find the external interface constraint adapter (i.e. the adapter which has its friendly name matching the regkey value)
155 bool interfaceConstraintPresent = false;
156 while (adapter != nullptr)
157 {
158 if (wsl::shared::string::IsEqual(interfaceConstraint, adapter->FriendlyName, true))
159 {
160 interfaceConstraintPresent = true;
161 break;
162 }
163 adapter = adapter->Next;
164 }
165
166 if (interfaceConstraintPresent)
167 {
168 // Retrieve the interfaceGuid corresponding to this endpoint by querying the HNS network
169 GUID endpointInterfaceGuid{};
170 wil::unique_cotaskmem_string error;
171 wil::unique_cotaskmem_string networkPropertiesString;
172 wsl::shared::hns::HNSNetwork networkProperties;
173 try
174 {
175 std::tie(networkProperties, networkPropertiesString) = wsl::core::networking::QueryNetworkProperties(network);
176 }
177 catch (...)
178 {
179 WSL_LOG(
180 "IsExternalInterfaceConstrainedFailed",
181 TraceLoggingHResult(wil::ResultFromCaughtException(), "result"),
182 TraceLoggingValue("HcnQueryNetworkProperties", "executionStep"),
183 TraceLoggingValue("Mirrored", "networkingMode"));
184
185 return false;
186 }
187
188 // Successfully read the interfaceGuid for this endpoint
189 endpointInterfaceGuid = networkProperties.InterfaceConstraint.InterfaceGuid;
190
191 // Obtain ExternalInterfaceConstraint's interfaceGuid to compare against the endpoint's interfaceGuid
192 GUID externalInterfaceConstraintGuid{};
193 THROW_IF_WIN32_ERROR(ConvertInterfaceLuidToGuid(&(adapter->Luid), &externalInterfaceConstraintGuid));
194
195 if (externalInterfaceConstraintGuid == endpointInterfaceGuid)
196 {
197 // This interface matches the one we are looking for.
198 // There is an external interface constraint configured, the constrained
199 // interface is present, and the interface in question is the ExternalInterfaceConstraint.
200 // This interface is allowed to operate normally and must not be constrained.
201 WSL_LOG(
202 "IsExternalInterfaceConstrainedInterface",
203 TraceLoggingValue(endpointInterfaceGuid, "InterfaceGuid"),
204 TraceLoggingValue(
205 "ExternalInterfaceConstraint is configured and this interface is the "
206 "ExternalInterfaceConstraint. This interface must NOT be constrained",
207 "state"));
208 return false;
209 }
210
211 // There is an external interface constraint configured and the constrained
212 // interface is present, but this is not the ExternalInterfaceConstraint.
213 // Thus, this interface must be constrained.
214 WSL_LOG(
215 "IsExternalInterfaceConstrainedInterface",
216 TraceLoggingValue(endpointInterfaceGuid, "InterfaceGuid"),
217 TraceLoggingValue(
218 "ExternalInterfaceConstraint is configured and the ExternalInterfaceConstraint is "
219 "found. This interface must be constrained.",
220 "state"));
221 return true;
222 }
223 // There is an ExternalInterfaceConstraint configured, but it is not present/up.
224 // Thus, this interface must be constrained.
225 WSL_LOG(
226 "IsExternalInterfaceConstrainedInterface",
227 TraceLoggingValue(
228 "ExternalInterfaceConstraint is configured and the ExternalInterfaceConstraint is NOT "
229 "found. All interfaces must be constrained.",
230 "state"));
231 return true;
232 }
233
234 // There is no ExternalInterfaceConstraint configured.
235 // This, this interface must NOT be constrained.
236 WSL_LOG(
237 "IsExternalInterfaceConstrainedInterface",
238 TraceLoggingValue("ExternalInterfaceConstraint is not configured. All interfaces must NOT be constrained.", "state"));
239 return false;
240 }
241 CATCH_LOG()
242
243 // If we reached here, we hit caught an unexpected error. Default to non-constrained
244 return false;
245 }
246
247 void MirroredNetworking::Initialize()
248 {
249 // Configure IPV6 before anything else happens (IPV6 configuration needs to be done early).
250 m_networkingQueue.submit([this] {
251 return wil::ResultFromException([&]() { m_gnsChannel.SendNetworkDeviceMessage(LxGnsMessageSetupIpv6, L"{}"); });
252 });
253
254 m_gnsRpcServer = GnsRpcServer::GetOrCreate();
255 m_guestNetworkService.CreateGuestNetworkService(
256 m_config.FirewallConfig.Enabled(), m_config.IgnoredPorts, m_runtimeId, m_gnsRpcServer->GetServerUuid(), s_GuestNetworkServiceCallback, this);
257 m_ephemeralPortRange = m_guestNetworkService.AllocateEphemeralPortRange();
258
259 networking::ConfigureHyperVFirewall(m_config.FirewallConfig, wsl::windows::common::wslutil::c_vmOwner);
260
261 // must keep all m_networkManager interactions (including) creation queued
262 // also must queue GNS callbacks to keep them serialized
263 // the queue also prevents losing change notifications while we are still processing add notifications
264 // calling submit_with_results to get a WslThreadPoolWaitableResult so we can conditionally wait for this workitem to complete to determine if it succeeded
265 const auto workItemTracker = m_networkingQueue.submit_with_results<HRESULT>([this] {
266 try
267 {
268 auto addNetworkEndpointCallback = [this](const GUID& networkId) {
269 m_networkingQueue.submit([this, networkId] { this->AddNetworkEndpoint(networkId); });
270 };
271
272 // Create and start the network manager.
273 //
274 // N.B. Mirrored networks may not yet exist and the NetworkManager c'tor will cause HCS to create them asynchronously.
275 // This is done by the query submitted to HcnEnumerateNetworks.
276 // Once the networks are created, the network change callback will be invoked and endpoints will be hot-added.
277 // implement wsl::core::networking::GnsMessageCallbackWithCallbackResult so WSL can serialize messages to Linux
278 auto networkManagerGnsMessageCallbackWithCallbackResult = [this](
279 LX_MESSAGE_TYPE messageType,
280 const std::wstring& notificationString,
281 networking::GnsCallbackFlags callbackFlags,
282 _Out_opt_ int* returnedResult) -> HRESULT {
283 // NetworkManagerGnsMessageCallback queues the actual work to the m_gnsMessageQueue
284 return NetworkManagerGnsMessageCallback(messageType, notificationString, callbackFlags, returnedResult);
285 };
286
287 m_networkManager = std::make_unique<wsl::core::networking::WslMirroredNetworkManager>(
288 m_system, m_config, std::move(networkManagerGnsMessageCallbackWithCallbackResult), std::move(addNetworkEndpointCallback), m_ephemeralPortRange);
289
290 // Register notifications for DNS suffix changes
291 m_dnsSuffixRegistryWatcher.emplace(
292 [this] { m_networkingQueue.submit([this] { m_networkManager->OnDnsSuffixChange(); }); });
293
294 // Send the requisite notifications for the required network devices
295 m_networkManager->SendCreateNotificationsForInitialEndpoints();
296
297 // HNS now has all host interfaces that will be mirrored mapped into NetworkIds
298 std::vector<GUID> networkIds;
299 THROW_IF_FAILED(m_networkManager->EnumerateNetworks(networkIds));
300
301 // Create an endpoint on each mirrored network.
302 for (auto& networkId : networkIds)
303 {
304 AddNetworkEndpoint(networkId);
305 }
306
307 // At this point all endpoints are configured, mark the GuestNetworkService as 'Synchronized'
308 m_guestNetworkService.SetGuestNetworkServiceState(hns::GuestNetworkServiceState::Synchronized);
309 }
310 catch (...)
311 {
312 const auto hr = wil::ResultFromCaughtException();
313 WSL_LOG(
314 "FailedToStartNetworkManager",
315 TraceLoggingValue(m_runtimeId, "vmId"),
316 TraceLoggingValue(hr, "error"),
317 TraceLoggingValue(ToString(m_config.NetworkingMode), "networkConfiguration"));
318
319 return hr;
320 }
321 return S_OK;
322 });
323
324 // Wait for initial mirroring to give users a consistent experience.
325 // the wait should not timeout - we are waiting infinite
326 const auto waitResult = workItemTracker->wait(INFINITE);
327 WI_ASSERT(ERROR_SUCCESS == waitResult);
328 // now we can read the HRESULT returned from the work item
329 const auto hr = workItemTracker->read_result();
330 if (SUCCEEDED(hr))
331 {
332 // We must wait for the goal state to be reached outside of the queue, since operations
333 // required to reach the goal state require processing in the queue.
334 const auto goalStateHr = m_networkManager->WaitForMirroredGoalState();
335 if (FAILED(goalStateHr))
336 {
337 WSL_LOG(
338 "WaitForMirroredGoalStateFailed",
339 TraceLoggingHResult(goalStateHr, "hr"),
340 TraceLoggingValue(m_config.EnableDnsTunneling, "DnsTunnelingEnabled"),
341 TraceLoggingValue(m_config.FirewallConfig.Enabled(), "HyperVFirewallEnabled"),
342 TraceLoggingValue(m_config.EnableAutoProxy, "AutoProxyFeatureEnabled"));
343 }
344 }
345
346 THROW_IF_FAILED(hr);
347 // else we don't need to wait on the result
348 // it can safely go out of scope and we can exit (it's a shared_ptr)
349 }
350
351 void MirroredNetworking::FillInitialConfiguration(LX_MINI_INIT_NETWORKING_CONFIGURATION& message)
352 {
353 message.NetworkingMode = LxMiniInitNetworkingModeMirrored;
354
355 std::tie(message.EphemeralPortRangeStart, message.EphemeralPortRangeEnd) = m_ephemeralPortRange;
356 message.PortTrackerType = LxMiniInitPortTrackerTypeMirrored;
357 message.EnableDhcpClient = false;
358 message.DisableIpv6 = false;
359 }
360
361 void MirroredNetworking::StartPortTracker(wil::unique_socket&& socket)
362 {
363 WI_ASSERT(!m_gnsPortTrackerChannel.has_value());
364
365 m_gnsPortTrackerChannel.emplace(
366 std::move(socket),
367 [&](const SOCKADDR_INET& Address, int Protocol, bool Allocate) {
368 return m_guestNetworkService.OnPortAllocationRequest(Address, Protocol, Allocate);
369 },
370 [&](_In_ const std::string& InterfaceName, _In_ bool Up) {
371 m_networkingQueue.submit([=, this] {
372 if (m_networkManager)
373 {
374 m_networkManager->TunAdapterStateChanged(InterfaceName, Up);
375 }
376 });
377 });
378 }
379
380 void MirroredNetworking::TraceLoggingRundown() noexcept
381 {
382 m_networkingQueue.submit([this] {
383 if (m_networkManager)
384 {
385 m_networkManager->TraceLoggingRundown();
386 }
387 });
388 }
389
390 // must be called from m_networkingQueue - m_networkManager must be called only from that queue
391 void MirroredNetworking::AddNetworkEndpoint(const GUID& NetworkId) noexcept
392 {
393 PCSTR executionStep = "";
394 try
395 {
396 WI_ASSERT(m_networkingQueue.isRunningInQueue());
397 WI_ASSERT(m_networkManager);
398
399 if (m_networkManager->DoesEndpointExist(NetworkId))
400 {
401 WSL_LOG(
402 "MirroredNetworking::AddNetworkEndpoint - NetworkId already exists", TraceLoggingValue(NetworkId, "networkId"));
403 return;
404 }
405
406 executionStep = "HcnOpenNetwork";
407 auto network = wsl::core::networking::OpenNetwork(NetworkId);
408 WSL_LOG("MirroredNetworking::AddNetworkEndpoint [HcnOpenNetwork]", TraceLoggingValue(NetworkId, "networkId"));
409
410 // Query the network properties for diagnostic purposes only.
411 wsl::shared::hns::HNSNetwork properties;
412 wil::unique_cotaskmem_string networkProperties;
413 executionStep = "HcnQueryNetworkProperties";
414 std::tie(properties, networkProperties) = wsl::core::networking::QueryNetworkProperties(network.get());
415 WSL_LOG(
416 "MirroredNetworking::AddNetworkEndpoint [HcnQueryNetworkProperties]",
417 TraceLoggingValue(NetworkId, "networkId"),
418 TraceLoggingValue(networkProperties.get(), "networkProperties"));
419
420 // Create a network endpoint.
421 // first see if we have cached a prior endpoint-id that matches this network-id
422 GUID endpointId{};
423 const auto existingEndpointValue = m_networkIdMappings.find(NetworkId);
424 if (existingEndpointValue != m_networkIdMappings.end())
425 {
426 endpointId = existingEndpointValue->second;
427 WSL_LOG(
428 "MirroredNetworking::AddNetworkEndpoint [using existing endpoint id]",
429 TraceLoggingValue(NetworkId, "networkId"),
430 TraceLoggingValue(endpointId, "endpointId"));
431 }
432 else
433 {
434 executionStep = "CoCreateGuid";
435 THROW_IF_FAILED(CoCreateGuid(&endpointId));
436 }
437
438 std::wstring endpointSettings;
439 NetworkEndpoint endpointInfo{};
440 endpointInfo.NetworkId = NetworkId;
441 endpointInfo.EndpointId = endpointId;
442
443 if (m_config.FirewallConfig.Enabled())
444 {
445 // Create HNS firewall policy object for the endpoint
446 hns::HostComputeEndpoint hnsEndpoint{};
447 hns::EndpointPolicy<hns::PortnameEndpointPolicySetting> endpointPortNamePolicy{};
448 hns::EndpointPolicy<hns::FirewallPolicySetting> endpointFirewallPolicy{};
449
450 // Assemble the endpoint
451 hnsEndpoint.HostComputeNetwork = NetworkId;
452 hnsEndpoint.SchemaVersion.Major = 2;
453 hnsEndpoint.SchemaVersion.Minor = 16;
454
455 // Port name policy
456 endpointPortNamePolicy.Type = hns::EndpointPolicyType::PortName;
457 hnsEndpoint.Policies.emplace_back(std::move(endpointPortNamePolicy));
458
459 // Firewall policy
460 hns::FirewallPolicySetting firewallPolicyObject{};
461 firewallPolicyObject.VmCreatorId = m_config.FirewallConfig.VmCreatorId.value();
462
463 // Set firewall policy flags
464 // Currently, only the ConstrainedInterface flag is supported, which is set based on the user configuring an ExternalInterfaceConstraint.
465 firewallPolicyObject.PolicyFlags = IsExternalInterfaceConstrained(network.get()) ? hns::FirewallPolicyFlags::ConstrainedInterface
466 : hns::FirewallPolicyFlags::None;
467
468 endpointFirewallPolicy.Settings = std::move(firewallPolicyObject);
469 endpointFirewallPolicy.Type = hns::EndpointPolicyType::Firewall;
470 hnsEndpoint.Policies.emplace_back(std::move(endpointFirewallPolicy));
471 endpointSettings = ToJsonW(hnsEndpoint);
472 }
473 else
474 {
475 // If Hyper-V Firewall is not supported for this scenario, only configure the basic HNS endpoint object
476 wsl::shared::hns::HNSEndpoint settings{};
477 settings.VirtualNetwork = NetworkId;
478 endpointSettings = ToJsonW(settings);
479 }
480
481 // Create the endpoint
482 executionStep = "HcnCreateEndpoint";
483 wil::unique_cotaskmem_string error;
484 auto result = HcnCreateEndpoint(network.get(), endpointInfo.EndpointId, endpointSettings.c_str(), &endpointInfo.Endpoint, &error);
485
486 WSL_LOG(
487 "MirroredNetworking::AddNetworkEndpoint [HcnCreateEndpoint]",
488 TraceLoggingValue(NetworkId, "HNSEndpoint::NetworkId"),
489 TraceLoggingValue(result, "result"),
490 TraceLoggingValue(error.is_valid() ? error.get() : L"", "errorString"));
491 THROW_IF_FAILED_MSG(result, "HcnCreateEndpoint %ls", error.get());
492
493 wil::unique_cotaskmem_string propertiesString;
494 executionStep = "HcnQueryEndpointProperties";
495 result = HcnQueryEndpointProperties(endpointInfo.Endpoint.get(), nullptr, &propertiesString, &error);
496 WSL_LOG(
497 "MirroredNetworking::AddNetworkEndpoint [HcnQueryEndpointProperties]",
498 TraceLoggingValue(endpointInfo.EndpointId, "endpointId"),
499 TraceLoggingValue(result, "result"),
500 TraceLoggingValue(error.is_valid() ? error.get() : L"", "errorString"),
501 TraceLoggingValue(propertiesString.is_valid() ? propertiesString.get() : L"", "propertiesString"));
502 THROW_IF_FAILED_MSG(result, "HcnQueryEndpointProperties %ls", error.get());
503
504 executionStep = "ParsingHcnQueryEndpointProperties";
505 auto endpointProperties = FromJson<hns::HNSEndpoint>(propertiesString.get());
506
507 endpointInfo.Network = m_networkManager->GetEndpointSettings(endpointProperties);
508 endpointInfo.InterfaceGuid = endpointProperties.InterfaceConstraint.InterfaceGuid;
509
510 WSL_LOG(
511 "MirroredNetworking::AddNetworkEndpoint",
512 TraceLoggingValue(endpointInfo.EndpointId, "endpointId"),
513 TraceLoggingValue(endpointInfo.InterfaceGuid, "endpointInterfaceGuid"),
514 TraceLoggingValue(endpointInfo.InterfaceLuid.Value, "endpointInterfaceLuid"),
515 TraceLoggingValue(endpointProperties.IPAddress.c_str(), "endpointIpAddress"),
516 TraceLoggingValue(endpointProperties.PortFriendlyName.c_str(), "endpointPortFriendlyName"),
517 TraceLoggingValue(endpointProperties.Name.c_str(), "endpointName"),
518 TraceLoggingValue(endpointProperties.VirtualNetwork, "endpointVirtualNetwork"),
519 TraceLoggingValue(endpointProperties.VirtualNetworkName.c_str(), "endpointVirtualNetworkName"));
520
521 m_networkManager->AddEndpoint(std::move(endpointInfo), std::move(endpointProperties));
522
523 if (!m_networkNotificationHandle)
524 {
525 // Register for network connectivity change notifications to update the MTU.
526 LOG_IF_WIN32_ERROR(NotifyNetworkConnectivityHintChange(
527 [](PVOID context, NL_NETWORK_CONNECTIVITY_HINT hint) {
528 WSL_LOG(
529 "MirroredNetworking::NotifyNetworkConnectivityHintChange fired",
530 TraceLoggingValue(static_cast<uint32_t>(hint.ConnectivityLevel), "connectivityLevel"),
531 TraceLoggingValue(static_cast<uint32_t>(hint.ConnectivityCost), "connectivityCost"));
532
533 auto* thisPtr = static_cast<MirroredNetworking*>(context);
534 thisPtr->m_networkingQueue.submit([thisPtr] {
535 if (thisPtr->m_networkManager)
536 {
537 thisPtr->m_networkManager->OnNetworkConnectivityHintChange();
538 }
539 });
540 },
541 this,
542 TRUE,
543 &m_networkNotificationHandle));
544 }
545 if (!m_interfaceNotificationHandle)
546 {
547 LOG_IF_WIN32_ERROR(NotifyIpInterfaceChange(
548 AF_UNSPEC,
549 [](PVOID context, PMIB_IPINTERFACE_ROW row, MIB_NOTIFICATION_TYPE) {
550 WSL_LOG(
551 "MirroredNetworking::NotifyIpInterfaceChange fired",
552 TraceLoggingValue(row->Family, "family"),
553 TraceLoggingValue(row->InterfaceIndex, "ifIndex"));
554
555 auto* thisPtr = static_cast<MirroredNetworking*>(context);
556 thisPtr->m_networkingQueue.submit([thisPtr] {
557 if (thisPtr->m_networkManager)
558 {
559 thisPtr->m_networkManager->OnNetworkConnectivityHintChange();
560 }
561 });
562 },
563 this,
564 FALSE,
565 &m_interfaceNotificationHandle));
566 }
567 if (!m_routeNotificationHandle)
568 {
569 LOG_IF_WIN32_ERROR(NotifyRouteChange2(
570 AF_UNSPEC,
571 [](PVOID context, PMIB_IPFORWARD_ROW2 row, MIB_NOTIFICATION_TYPE) {
572 WSL_LOG("MirroredNetworking::NotifyRouteChange2 fired", TraceLoggingValue(row->InterfaceIndex, "ifIndex"));
573
574 auto* thisPtr = static_cast<MirroredNetworking*>(context);
575 thisPtr->m_networkingQueue.submit([thisPtr] {
576 if (thisPtr->m_networkManager)
577 {
578 thisPtr->m_networkManager->OnNetworkConnectivityHintChange();
579 }
580 });
581 },
582 this,
583 FALSE,
584 &m_routeNotificationHandle));
585 }
586 if (!m_addressNotificationHandle)
587 {
588 LOG_IF_WIN32_ERROR(NotifyUnicastIpAddressChange(
589 AF_UNSPEC,
590 [](PVOID context, PMIB_UNICASTIPADDRESS_ROW row, MIB_NOTIFICATION_TYPE) {
591 WSL_LOG(
592 "MirroredNetworking::NotifyUnicastIpAddressChange fired",
593 TraceLoggingValue(row->InterfaceIndex, "ifIndex"));
594
595 auto* thisPtr = static_cast<MirroredNetworking*>(context);
596 thisPtr->m_networkingQueue.submit([thisPtr] {
597 if (thisPtr->m_networkManager)
598 {
599 thisPtr->m_networkManager->OnNetworkConnectivityHintChange();
600 }
601 });
602 },
603 this,
604 FALSE,
605 &m_addressNotificationHandle));
606 }
607
608 // we've successfully added a new endpoint - track that Id
609 if (existingEndpointValue == m_networkIdMappings.end())
610 {
611 WSL_LOG(
612 "MirroredNetworking::AddNetworkEndpoint [tracking new endpoint]",
613 TraceLoggingValue(NetworkId, "networkId"),
614 TraceLoggingValue(endpointId, "endpointId"));
615 m_networkIdMappings[NetworkId] = endpointId;
616 }
617 }
618 catch (...)
619 {
620 WSL_LOG(
621 "AddNetworkEndpointFailure",
622 TraceLoggingHResult(wil::ResultFromCaughtException(), "result"),
623 TraceLoggingValue(executionStep, "executionStep"),
624 TraceLoggingValue("Mirrored", "networkingMode"),
625 TraceLoggingValue(m_config.EnableDnsTunneling, "DnsTunnelingEnabled"),
626 TraceLoggingValue(m_config.FirewallConfig.Enabled(), "HyperVFirewallEnabled"),
627 TraceLoggingValue(m_config.EnableAutoProxy, "AutoProxyFeatureEnabled") // the feature is enabled, but we don't know if proxy settings are actually configured
628 );
629 }
630 }
631
632 // must be called from m_networkingQueue so all GNS interactions are correctly serialized
633 // OnNetworkEndpointChange is called from GNS
634 HRESULT MirroredNetworking::OnNetworkEndpointChange(const GUID& EndpointId, _In_ LPCWSTR Settings) const noexcept
635 try
636 {
637 WI_ASSERT(m_networkingQueue.isRunningInQueue());
638
639 const auto notification = FromJson<hns::ModifyGuestEndpointSettingRequest<void>>(Settings);
640
641 // not sending Neighbor updates into the container
642 if (notification.ResourceType == hns::GuestEndpointResourceType::Neighbor)
643 {
644 return E_NOTIMPL;
645 }
646
647 // a network property changed on some interface that HNS is tracking
648 // we're using this notification as a trigger to rediscover the preferred interface
649 WSL_LOG(
650 "MirroredNetworking::OnNetworkEndpointChange [GNS server notification]",
651 TraceLoggingValue(wsl::shared::string::GuidToString<wchar_t>(EndpointId).c_str(), "Endpoint"),
652 TraceLoggingValue(Settings, "Payload"));
653 m_networkManager->OnNetworkEndpointChange();
654
655 return S_OK;
656 }
657 CATCH_RETURN()
658
659 HRESULT MirroredNetworking::NetworkManagerGnsMessageCallback(
660 LX_MESSAGE_TYPE messageType, std::wstring notificationString, networking::GnsCallbackFlags callbackFlags, _Out_opt_ int* returnedValueFromGns) noexcept
661 try
662 {
663 // only pass the OUT returnedValueFromGns int* if the callback flags are set to wait
664 if (returnedValueFromGns)
665 {
666 *returnedValueFromGns = ERROR_FATAL_APP_EXIT;
667 WI_ASSERT(WI_IsFlagSet(callbackFlags, wsl::core::networking::GnsCallbackFlags::Wait));
668 }
669
670 auto sendGnsMessage = [this, messageType, capturedNotificationString = std::move(notificationString), callbackFlags, returnedValueFromGns]() mutable {
671 try
672 {
673 auto retryCount = 0ul;
674 auto sendMessage = [&]() {
675 const auto hr = wil::ResultFromException([&] {
676 if (returnedValueFromGns && WI_IsFlagSet(callbackFlags, wsl::core::networking::GnsCallbackFlags::Wait))
677 {
678 *returnedValueFromGns =
679 m_gnsChannel.SendNetworkDeviceMessageReturnResult(messageType, capturedNotificationString.c_str());
680 }
681 else
682 {
683 m_gnsChannel.SendNetworkDeviceMessage(messageType, capturedNotificationString.c_str());
684 }
685 });
686 const bool hasLinuxResult = returnedValueFromGns != nullptr;
687 const int linuxResultCode = hasLinuxResult ? *returnedValueFromGns : 0;
688 WSL_LOG(
689 "MirroredNetworking::NetworkManagerGnsMessageCallback",
690 TraceLoggingValue(ToString(messageType), "messageType"),
691 TraceLoggingValue(capturedNotificationString.c_str(), "notificationString"),
692 TraceLoggingValue(hr, "hr"),
693 TraceLoggingValue(hasLinuxResult, "hasLinuxResult"),
694 TraceLoggingValue(linuxResultCode, "linuxResultCode"),
695 TraceLoggingValue(retryCount, "retryCount"));
696
697 ++retryCount;
698 return networking::GetGnsCallbackResult(messageType, hr, linuxResultCode);
699 };
700
701 return wsl::shared::retry::RetryWithTimeout<HRESULT>(sendMessage, std::chrono::milliseconds(100), std::chrono::seconds(3));
702 }
703 CATCH_RETURN()
704 };
705
706 if (WI_IsFlagSet(callbackFlags, wsl::core::networking::GnsCallbackFlags::Wait))
707 {
708 return m_gnsMessageQueue.submit_and_wait(std::move(sendGnsMessage));
709 }
710
711 m_gnsMessageQueue.submit(std::move(sendGnsMessage));
712 return S_OK;
713 }
714 CATCH_RETURN()
715
716 void MirroredNetworking::GuestNetworkServiceCallback(DWORD NotificationType, HRESULT NotificationStatus, _In_opt_ PCWSTR NotificationData) noexcept
717 try
718 {
719 WSL_LOG(
720 "MirroredNetworking::GuestNetworkServiceCallback",
721 TraceLoggingValue(wsl::windows::common::stringify::HcnNotificationsToString(NotificationType), "NotificationType"),
722 TraceLoggingValue(NotificationStatus, "NotificationStatus"),
723 TraceLoggingValue(NotificationData, "NotificationData"));
724
725 WI_ASSERT(SUCCEEDED(NotificationStatus));
726
727 hns::NotificationBase data{};
728 if (ARGUMENT_PRESENT(NotificationData))
729 {
730 data = FromJson<hns::NotificationBase>(NotificationData);
731 }
732
733 switch (NotificationType)
734 {
735 case HcnNotificationServiceDisconnect:
736 break;
737
738 case HcnNotificationGuestNetworkServiceStateChanged:
739 break;
740
741 case HcnNotificationGuestNetworkServiceInterfaceStateChanged:
742 break;
743
744 default:
745 WI_ASSERT(false);
746 }
747
748 return;
749 }
750 CATCH_LOG()
751
752 void CALLBACK MirroredNetworking::s_GuestNetworkServiceCallback(DWORD NotificationType, _In_ void* Context, HRESULT NotificationStatus, _In_opt_ PCWSTR NotificationData)
753 {
754 static_cast<MirroredNetworking*>(Context)->GuestNetworkServiceCallback(NotificationType, NotificationStatus, NotificationData);
755 }