master
h 141 lines 5.46 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2
3 #pragma once
4
5 #include "DnsTunnelingChannel.h"
6 #include "WslCoreMessageQueue.h"
7 #include "WslCoreNetworkingSupport.h"
8
9 namespace wsl::core::networking {
10
11 enum class DnsResolverFlags
12 {
13 None = 0x0,
14 BestEffortDnsParsing = 0x1
15 };
16 DEFINE_ENUM_FLAG_OPERATORS(DnsResolverFlags);
17
18 class DnsResolver
19 {
20 public:
21 DnsResolver(wil::unique_socket&& dnsHvsocket, DnsResolverFlags flags);
22 ~DnsResolver() noexcept;
23
24 DnsResolver(const DnsResolver&) = delete;
25 DnsResolver& operator=(const DnsResolver&) = delete;
26
27 DnsResolver(DnsResolver&&) = delete;
28 DnsResolver& operator=(DnsResolver&&) = delete;
29
30 void Stop() noexcept;
31
32 static HRESULT LoadDnsResolverMethods() noexcept;
33
34 private:
35 struct DnsQueryContext
36 {
37 // Struct containing protocol (TCP/UDP) and unique id of the Linux DNS client making the request.
38 LX_GNS_DNS_CLIENT_IDENTIFIER m_dnsClientIdentifier{};
39
40 // Handle used to cancel the request.
41 DNS_QUERY_RAW_CANCEL m_cancelHandle{};
42
43 // Unique query id.
44 uint32_t m_id{};
45
46 // Callback to the parent object to notify about the DNS query completion.
47 std::function<void(DnsQueryContext*, DNS_QUERY_RAW_RESULT*)> m_handleQueryCompletion;
48
49 DnsQueryContext(
50 uint32_t id,
51 const LX_GNS_DNS_CLIENT_IDENTIFIER& dnsClientIdentifier,
52 std::function<void(DnsQueryContext*, DNS_QUERY_RAW_RESULT*)>&& handleQueryCompletion) :
53 m_dnsClientIdentifier(dnsClientIdentifier), m_id(id), m_handleQueryCompletion(std::move(handleQueryCompletion))
54 {
55 }
56
57 ~DnsQueryContext() noexcept = default;
58
59 DnsQueryContext(const DnsQueryContext&) = delete;
60 DnsQueryContext& operator=(const DnsQueryContext&) = delete;
61 DnsQueryContext(DnsQueryContext&&) = delete;
62 DnsQueryContext& operator=(DnsQueryContext&&) = delete;
63 };
64
65 void GenerateTelemetry() noexcept;
66
67 // Process DNS request received from Linux.
68 //
69 // Arguments:
70 // dnsBuffer - buffer containing DNS request.
71 // dnsClientIdentifier - struct containing protocol (TCP/UDP) and unique id of the Linux DNS client making the request.
72 void ProcessDnsRequest(const gsl::span<gsl::byte> dnsBuffer, const LX_GNS_DNS_CLIENT_IDENTIFIER& dnsClientIdentifier) noexcept;
73
74 // Handle completion of DNS query.
75 //
76 // Arguments:
77 // dnsQueryContext - context structure for the DNS request.
78 // queryResults - structure containing result of the DNS request.
79 void HandleDnsQueryCompletion(_Inout_ DnsQueryContext* dnsQueryContext, _Inout_opt_ DNS_QUERY_RAW_RESULT* queryResults) noexcept;
80
81 void ResolveExternalInterfaceConstraintIndex() noexcept;
82
83 // Callback that will be invoked by the DNS API whenever a request finishes. The callback is invoked on success, error or when request is cancelled.
84 //
85 // Arguments:
86 // queryContext - pointer to context structure, will be a structure of type DnsQueryContext.
87 // queryResults - pointer to structure containing the result of the DNS request.
88 static VOID CALLBACK DnsQueryRawCallback(_In_ VOID* queryContext, _Inout_opt_ DNS_QUERY_RAW_RESULT* queryResults) noexcept;
89
90 static VOID CALLBACK InterfaceChangeCallback(_In_ PVOID context, PMIB_IPINTERFACE_ROW, MIB_NOTIFICATION_TYPE) noexcept;
91
92 std::recursive_mutex m_dnsLock;
93
94 // Flag used when shutting down the object.
95 _Guarded_by_(m_dnsLock) bool m_stopped = false;
96
97 // Hvsocket channel used to exchange DNS messages with Linux.
98 DnsTunnelingChannel m_dnsChannel;
99
100 // Queue used to send DNS responses to Linux.
101 WslCoreMessageQueue m_dnsResponseQueue;
102
103 // Unique id that is incremented for each request. In case the value reaches MAX_UINT and is reset to 0,
104 // it's assumed previous requests with id's 0, 1, ... finished in the meantime and the id can be reused.
105 _Guarded_by_(m_dnsLock) uint32_t m_currentRequestId = 0;
106
107 // Mapping request id to the request context structure.
108 _Guarded_by_(m_dnsLock) std::unordered_map<uint32_t, std::unique_ptr<DnsQueryContext>> m_dnsRequests {};
109
110 // Event that is set when all tracked DNS requests have completed.
111 wil::unique_event m_allRequestsFinished{wil::EventOptions::ManualReset};
112
113 // Used for handling of external interface constraint setting.
114 unique_notify_handle m_interfaceNotificationHandle{};
115
116 std::wstring m_externalInterfaceConstraintName;
117 _Guarded_by_(m_dnsLock) ULONG m_externalInterfaceConstraintIndex = 0;
118
119 const DnsResolverFlags m_flags{};
120
121 // Statistics used for telemetry.
122 std::atomic<uint32_t> m_totalUdpQueries{0};
123 std::atomic<uint32_t> m_successfulUdpQueries{0};
124 std::atomic<uint32_t> m_totalTcpQueries{0};
125 std::atomic<uint32_t> m_successfulTcpQueries{0};
126 std::atomic<uint32_t> m_queriesWithNullResult{0};
127 std::atomic<uint32_t> m_failedDnsQueryRawCalls{0};
128
129 _Guarded_by_(m_dnsLock) std::map<uint32_t, uint32_t> m_dnsApiFailures;
130
131 // Dynamic functions used for calling the DNS APIs.
132
133 // Function to start a raw DNS request.
134 static std::optional<LxssDynamicFunction<decltype(DnsQueryRaw)>> s_dnsQueryRaw;
135 // Function to cancel a raw DNS request.
136 static std::optional<LxssDynamicFunction<decltype(DnsCancelQueryRaw)>> s_dnsCancelQueryRaw;
137 // Function to free the structure containing the result of a raw DNS request.
138 static std::optional<LxssDynamicFunction<decltype(DnsQueryRawResultFree)>> s_dnsQueryRawResultFree;
139 };
140
141 } // namespace wsl::core::networking