master
h 94 lines 3.84 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2
3 #pragma once
4 #include <optional>
5 #include <map>
6 #include <utility>
7
8 #include <ComputeNetwork.h>
9 #include <LxssDynamicFunction.h>
10
11 #include "hcs.hpp"
12
13 #include <wil/resource.h>
14
15 namespace wsl::core::networking {
16 class GuestNetworkService
17 {
18 public:
19 GuestNetworkService() noexcept;
20
21 ~GuestNetworkService() noexcept
22 {
23 Stop();
24 }
25
26 GuestNetworkService(const GuestNetworkService& other) = delete;
27 GuestNetworkService(GuestNetworkService&& other) = delete;
28 GuestNetworkService& operator=(const GuestNetworkService& other) = delete;
29 GuestNetworkService& operator=(GuestNetworkService&& other) = delete;
30
31 void CreateGuestNetworkService(
32 const bool firewallEnabled,
33 const std::set<USHORT>& IgnoredPorts,
34 const GUID& VmId,
35 const UUID& ServerUuid,
36 HCN_NOTIFICATION_CALLBACK Callback,
37 void* CallbackContext);
38
39 void SetGuestNetworkServiceState(_In_ wsl::shared::hns::GuestNetworkServiceState State) const;
40
41 std::pair<uint16_t, uint16_t> AllocateEphemeralPortRange();
42
43 int OnPortAllocationRequest(const SOCKADDR_INET& Address, _In_ int Protocol, _In_ bool Allocate) noexcept;
44
45 void Stop() noexcept;
46
47 private:
48 struct HcnPortReservation
49 {
50 // The consumer of the port reservations requests reservations at a {SOCKADDR_INET, Protocol} granularity.
51 // The HCN port reservation API allows reservations at a {PortNumber, Protocol} granularity.
52 // Using a reference count to coalesce consumer requests to their appropriate HCN requests.
53 HANDLE Handle;
54 ULONG ReferenceCount;
55 };
56
57 // Returns true if the port allocation should be always allowed, without asking HNS.
58 static bool IsPortAllocationLoopbackException(const SOCKADDR_INET& Address) noexcept;
59
60 static bool IsPortAllocationMulticast(const SOCKADDR_INET& Address, _In_ int Protocol) noexcept;
61
62 bool IsPortInHostEphemeralRange(uint16_t PortNumber, int Protocol) const noexcept;
63
64 _Requires_lock_held_(m_dataLock)
65 bool IsPortInGuestEphemeralRange(uint16_t PortNumber) const noexcept;
66
67 uint16_t ComputeHostEphemeralPortCap(int Protocol) const noexcept;
68
69 _Requires_lock_held_(m_dataLock)
70 uint16_t ComputeHostEphemeralOverlap(int Protocol) const noexcept;
71
72 static std::pair<uint16_t, uint16_t> QueryHostEphemeralPortRange(LPCWSTR WmiClassName) noexcept;
73
74 static std::optional<LxssDynamicFunction<decltype(HcnReserveGuestNetworkServicePortRange)>> m_allocatePortRange;
75 static std::optional<LxssDynamicFunction<decltype(HcnReserveGuestNetworkServicePort)>> m_allocatePort;
76 static std::optional<LxssDynamicFunction<decltype(HcnReleaseGuestNetworkServicePortReservationHandle)>> m_releasePort;
77
78 wsl::windows::common::hcs::unique_hcn_guest_network_service m_service;
79 wsl::windows::common::hcs::unique_hcn_guest_network_service_callback m_guestNetworkServiceCallback;
80 GUID m_id{};
81 wil::srwlock m_dataLock;
82 _Guarded_by_(m_dataLock) std::set<uint16_t> m_ignoredPorts;
83 _Guarded_by_(m_dataLock) std::map<std::pair<HCN_PORT_PROTOCOL, USHORT>, HcnPortReservation> m_reservedPorts;
84 _Guarded_by_(m_dataLock) HCN_PORT_RANGE_RESERVATION m_reservedPortRange {};
85
86 // Host ephemeral port ranges can change. They are queried once at startup, if a change occurs, the service will need to be
87 // restarted. Note: The host ephemeral range will be the same for both IPv4 and IPv6, but can be different for TCP and UDP.
88 std::pair<uint16_t, uint16_t> m_hostTcpEphemeralPortRange{};
89 std::pair<uint16_t, uint16_t> m_hostUdpEphemeralPortRange{};
90
91 _Guarded_by_(m_dataLock) uint16_t m_hostTcpEphemeralPortsInUse {};
92 _Guarded_by_(m_dataLock) uint16_t m_hostUdpEphemeralPortsInUse {};
93 };
94 } // namespace wsl::core::networking