master
cpp 115 lines 3.83 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2
3 #include "precomp.h"
4 #include "DnsTunnelingChannel.h"
5
6 using wsl::core::networking::DnsTunnelingChannel;
7
8 DnsTunnelingChannel::DnsTunnelingChannel(wil::unique_socket&& socket, DnsTunnelingCallback&& reportDnsRequest) :
9 m_channel{std::move(socket), "DnsTunneling", {m_stopEvent.get()}}, m_reportDnsRequest(std::move(reportDnsRequest))
10 {
11 WSL_LOG("DnsTunnelingChannel::DnsTunnelingChannel [Windows]", TraceLoggingValue(m_channel.Socket(), "socket"));
12
13 // Start thread waiting for incoming messages from Linux side
14 m_receiveWorkerThread = std::thread([this]() { ReceiveLoop(); });
15 }
16
17 DnsTunnelingChannel::~DnsTunnelingChannel()
18 {
19 Stop();
20 }
21
22 void DnsTunnelingChannel::SendDnsMessage(const gsl::span<gsl::byte> dnsBuffer, const LX_GNS_DNS_CLIENT_IDENTIFIER& dnsClientIdentifier) noexcept
23 try
24 {
25 // Exit if channel was stopped
26 if (m_stopEvent.is_signaled())
27 {
28 return;
29 }
30
31 wsl::shared::MessageWriter<LX_GNS_DNS_TUNNELING_MESSAGE> message(LxGnsMessageDnsTunneling);
32 message->DnsClientIdentifier = dnsClientIdentifier;
33 message.WriteSpan(dnsBuffer);
34
35 m_channel.SendMessage<LX_GNS_DNS_TUNNELING_MESSAGE>(message.Span());
36 }
37 CATCH_LOG()
38
39 void DnsTunnelingChannel::ReceiveLoop() noexcept
40 {
41 std::vector<gsl::byte> receiveBuffer;
42
43 for (;;)
44 {
45 try
46 {
47 if (m_stopEvent.is_signaled())
48 {
49 return;
50 }
51
52 WSL_LOG_DEBUG("DnsTunnelingChannel::ReceiveLoop [Windows] - waiting for next message from Linux");
53
54 // Read next message. wsl::shared::socket::RecvMessage() first reads the message header, then uses it to determine the
55 // total size of the message and read the rest of the message, resizing the buffer if needed.
56 auto [message, span] = m_channel.ReceiveMessageOrClosed<MESSAGE_HEADER>();
57 if (message == nullptr)
58 {
59 WSL_LOG("DnsTunnelingChannel::ReceiveLoop [Windows] - failed to read message");
60 return;
61 }
62
63 // Get the message type from the message header
64 switch (message->MessageType)
65 {
66 case LxGnsMessageDnsTunneling:
67 {
68 // Cast message to a LX_GNS_DNS_TUNNELING_MESSAGE struct
69 auto* dnsMessage = gslhelpers::try_get_struct<LX_GNS_DNS_TUNNELING_MESSAGE>(span);
70 if (!dnsMessage)
71 {
72 WSL_LOG(
73 "DnsTunnelingChannel::ReceiveLoop [Windows] - failed to convert message to LX_GNS_DNS_TUNNELING_MESSAGE");
74 return;
75 }
76
77 // Extract DNS buffer from message
78 auto dnsBuffer = span.subspan(offsetof(LX_GNS_DNS_TUNNELING_MESSAGE, Buffer));
79
80 WSL_LOG_DEBUG(
81 "DnsTunnelingChannel::ReceiveLoop [Windows] - received DNS message",
82 TraceLoggingValue(dnsBuffer.size(), "DNS buffer size"),
83 TraceLoggingValue(dnsMessage->DnsClientIdentifier.Protocol == IPPROTO_UDP ? "UDP" : "TCP", "Protocol"),
84 TraceLoggingValue(dnsMessage->DnsClientIdentifier.DnsClientId, "DNS client id"));
85
86 // Invoke callback to notify about the new DNS request
87 m_reportDnsRequest(dnsBuffer, dnsMessage->DnsClientIdentifier);
88
89 break;
90 }
91
92 default:
93 {
94 THROW_HR_MSG(E_UNEXPECTED, "Unexpected LX_MESSAGE_TYPE : %i", message->MessageType);
95 }
96 }
97 }
98 CATCH_LOG()
99 }
100 }
101
102 void DnsTunnelingChannel::Stop() noexcept
103 try
104 {
105 WSL_LOG("DnsTunnelingChannel::Stop [Windows]");
106
107 m_stopEvent.SetEvent();
108
109 // Stop receive loop
110 if (m_receiveWorkerThread.joinable())
111 {
112 m_receiveWorkerThread.join();
113 }
114 }
115 CATCH_LOG()