Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include "Server.h"
19 :
20 : #include <errno.h>
21 : #include <utility>
22 :
23 : #include <lib/dnssd/minimal_mdns/core/DnsHeader.h>
24 : #include <platform/CHIPDeviceLayer.h>
25 :
26 : namespace mdns {
27 : namespace Minimal {
28 : namespace {
29 :
30 : class ShutdownOnError
31 : {
32 : public:
33 17 : ShutdownOnError(ServerBase * s) : mServer(s) {}
34 17 : ~ShutdownOnError()
35 : {
36 17 : if (mServer != nullptr)
37 : {
38 0 : mServer->Shutdown();
39 : }
40 17 : }
41 :
42 17 : CHIP_ERROR ReturnSuccess()
43 : {
44 17 : mServer = nullptr;
45 17 : return CHIP_NO_ERROR;
46 : }
47 :
48 : private:
49 : ServerBase * mServer;
50 : };
51 :
52 : /**
53 : * Extracts the Listening UDP Endpoint from an underlying ServerBase::EndpointInfo
54 : */
55 : class ListenSocketPickerDelegate : public ServerBase::BroadcastSendDelegate
56 : {
57 : public:
58 48 : chip::Inet::UDPEndPoint * Accept(ServerBase::EndpointInfo * info) override { return info->mListenUdp; }
59 : };
60 :
61 : #if CHIP_MINMDNS_USE_EPHEMERAL_UNICAST_PORT
62 :
63 : /**
64 : * Extracts the Querying UDP Endpoint from an underlying ServerBase::EndpointInfo
65 : */
66 : class QuerySocketPickerDelegate : public ServerBase::BroadcastSendDelegate
67 : {
68 : public:
69 0 : chip::Inet::UDPEndPoint * Accept(ServerBase::EndpointInfo * info) override { return info->mUnicastQueryUdp; }
70 : };
71 :
72 : #else
73 :
74 : using QuerySocketPickerDelegate = ListenSocketPickerDelegate;
75 :
76 : #endif
77 :
78 : /**
79 : * Validates that an endpoint belongs to a specific interface/ip address type before forwarding the
80 : * endpoint accept logic to another BroadcastSendDelegate.
81 : *
82 : * Usage like:
83 : *
84 : * SomeDelegate *child = ....;
85 : * InterfaceTypeFilterDelegate filter(interfaceId, IPAddressType::IPv6, child);
86 : *
87 : * UDPEndPoint *udp = filter.Accept(endpointInfo);
88 : */
89 : class InterfaceTypeFilterDelegate : public ServerBase::BroadcastSendDelegate
90 : {
91 : public:
92 78 : InterfaceTypeFilterDelegate(chip::Inet::InterfaceId interface, chip::Inet::IPAddressType type,
93 78 : ServerBase::BroadcastSendDelegate * child) :
94 78 : mInterface(interface),
95 78 : mAddressType(type), mChild(child)
96 78 : {}
97 :
98 96 : chip::Inet::UDPEndPoint * Accept(ServerBase::EndpointInfo * info) override
99 : {
100 96 : if ((info->mInterfaceId != mInterface) && (info->mInterfaceId != chip::Inet::InterfaceId::Null()))
101 : {
102 0 : return nullptr;
103 : }
104 :
105 96 : if ((mAddressType != chip::Inet::IPAddressType::kAny) && (info->mAddressType != mAddressType))
106 : {
107 48 : return nullptr;
108 : }
109 :
110 48 : return mChild->Accept(info);
111 : }
112 :
113 : private:
114 : chip::Inet::InterfaceId mInterface;
115 : chip::Inet::IPAddressType mAddressType;
116 : ServerBase::BroadcastSendDelegate * mChild = nullptr;
117 : };
118 :
119 : } // namespace
120 :
121 : namespace BroadcastIpAddresses {
122 :
123 : // Get standard mDNS Broadcast addresses
124 232 : chip::Inet::IPAddress Get(chip::Inet::IPAddressType addressType)
125 : {
126 : chip::Inet::IPAddress address;
127 : #if INET_CONFIG_ENABLE_IPV4
128 232 : if (addressType == chip::Inet::IPAddressType::kIPv4)
129 : {
130 116 : VerifyOrDie(chip::Inet::IPAddress::FromString("224.0.0.251", address));
131 : }
132 : else
133 : #endif
134 : {
135 116 : VerifyOrDie(chip::Inet::IPAddress::FromString("FF02::FB", address));
136 : }
137 232 : return address;
138 : }
139 :
140 : } // namespace BroadcastIpAddresses
141 :
142 : namespace {
143 :
144 : #if CHIP_ERROR_LOGGING
145 0 : const char * AddressTypeStr(chip::Inet::IPAddressType addressType)
146 : {
147 0 : switch (addressType)
148 : {
149 0 : case chip::Inet::IPAddressType::kIPv6:
150 0 : return "IPv6";
151 : #if INET_CONFIG_ENABLE_IPV4
152 0 : case chip::Inet::IPAddressType::kIPv4:
153 0 : return "IPv4";
154 : #endif // INET_CONFIG_ENABLE_IPV4
155 0 : default:
156 0 : return "UNKNOWN";
157 : }
158 : }
159 : #endif
160 :
161 : } // namespace
162 :
163 42 : ServerBase::~ServerBase()
164 : {
165 42 : Shutdown();
166 42 : }
167 :
168 47 : void ServerBase::Shutdown()
169 : {
170 47 : ShutdownEndpoints();
171 47 : mIsInitialized = false;
172 47 : }
173 :
174 97 : void ServerBase::ShutdownEndpoints()
175 : {
176 97 : mEndpoints.ReleaseAll();
177 97 : }
178 :
179 0 : void ServerBase::ShutdownEndpoint(EndpointInfo & aEndpoint)
180 : {
181 0 : mEndpoints.ReleaseObject(&aEndpoint);
182 0 : }
183 :
184 2 : bool ServerBase::IsListening() const
185 : {
186 2 : bool listening = false;
187 2 : mEndpoints.ForEachActiveObject([&](auto * endpoint) {
188 1 : if (endpoint->mListenUdp != nullptr)
189 : {
190 1 : listening = true;
191 1 : return chip::Loop::Break;
192 : }
193 0 : return chip::Loop::Continue;
194 : });
195 2 : return listening;
196 : }
197 :
198 17 : CHIP_ERROR ServerBase::Listen(chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager, ListenIterator * it,
199 : uint16_t port)
200 : {
201 17 : ShutdownEndpoints(); // ensure everything starts fresh
202 :
203 17 : chip::Inet::InterfaceId interfaceId = chip::Inet::InterfaceId::Null();
204 : chip::Inet::IPAddressType addressType;
205 :
206 17 : ShutdownOnError autoShutdown(this);
207 :
208 51 : while (it->Next(&interfaceId, &addressType))
209 : {
210 : chip::Inet::UDPEndPoint * listenUdp;
211 34 : ReturnErrorOnFailure(udpEndPointManager->NewEndPoint(&listenUdp));
212 34 : std::unique_ptr<chip::Inet::UDPEndPoint, EndpointInfo::EndPointDeletor> endPointHolder(listenUdp, {});
213 :
214 34 : ReturnErrorOnFailure(listenUdp->Bind(addressType, chip::Inet::IPAddress::Any, port, interfaceId));
215 :
216 34 : ReturnErrorOnFailure(listenUdp->Listen(OnUdpPacketReceived, nullptr /*OnReceiveError*/, this));
217 :
218 34 : CHIP_ERROR err = listenUdp->JoinMulticastGroup(interfaceId, BroadcastIpAddresses::Get(addressType));
219 :
220 34 : if (err != CHIP_NO_ERROR)
221 : {
222 : char interfaceName[chip::Inet::InterfaceId::kMaxIfNameLength];
223 0 : interfaceId.GetInterfaceName(interfaceName, sizeof(interfaceName));
224 :
225 : // Log only as non-fatal error. Failure to join will mean we reply to unicast queries only.
226 0 : ChipLogError(DeviceLayer, "MDNS failed to join multicast group on %s for address type %s: %" CHIP_ERROR_FORMAT,
227 : interfaceName, AddressTypeStr(addressType), err.Format());
228 :
229 0 : endPointHolder.reset();
230 : }
231 :
232 : #if CHIP_MINMDNS_USE_EPHEMERAL_UNICAST_PORT
233 : // Separate UDP endpoint for unicast queries, bound to 0 (i.e. pick random ephemeral port)
234 : // - helps in not having conflicts on port 5353, will receive unicast replies directly
235 : // - has a *DRAWBACK* of unicast queries being considered LEGACY by mdns since they do
236 : // not originate from 5353 and the answers will include a query section.
237 : chip::Inet::UDPEndPoint * unicastQueryUdp;
238 34 : ReturnErrorOnFailure(udpEndPointManager->NewEndPoint(&unicastQueryUdp));
239 34 : std::unique_ptr<chip::Inet::UDPEndPoint, EndpointInfo::EndPointDeletor> endPointHolderUnicast(unicastQueryUdp, {});
240 34 : ReturnErrorOnFailure(unicastQueryUdp->Bind(addressType, chip::Inet::IPAddress::Any, 0, interfaceId));
241 34 : ReturnErrorOnFailure(unicastQueryUdp->Listen(OnUdpPacketReceived, nullptr /*OnReceiveError*/, this));
242 : #endif
243 :
244 : #if CHIP_MINMDNS_USE_EPHEMERAL_UNICAST_PORT
245 34 : if (endPointHolder || endPointHolderUnicast)
246 : {
247 : // If allocation fails, the rref will not be consumed, so that the endpoint will also be freed correctly
248 34 : mEndpoints.CreateObject(interfaceId, addressType, std::move(endPointHolder), std::move(endPointHolderUnicast));
249 : }
250 : #else
251 : if (endPointHolder)
252 : {
253 : // If allocation fails, the rref will not be consumed, so that the endpoint will also be freed correctly
254 : mEndpoints.CreateObject(interfaceId, addressType, std::move(endPointHolder));
255 : }
256 : #endif
257 :
258 : // If at least one IPv6 interface is used by the mDNS server, notify the application that DNS-SD is ready.
259 34 : if (!mIsInitialized && addressType == chip::Inet::IPAddressType::kIPv6)
260 : {
261 : #if !CHIP_DEVICE_LAYER_NONE
262 2 : chip::DeviceLayer::ChipDeviceEvent event{};
263 2 : event.Type = chip::DeviceLayer::DeviceEventType::kDnssdInitialized;
264 2 : chip::DeviceLayer::PlatformMgr().PostEventOrDie(&event);
265 : #endif
266 2 : mIsInitialized = true;
267 : }
268 34 : }
269 :
270 17 : return autoShutdown.ReturnSuccess();
271 17 : }
272 :
273 0 : CHIP_ERROR ServerBase::DirectSend(chip::System::PacketBufferHandle && data, const chip::Inet::IPAddress & addr, uint16_t port,
274 : chip::Inet::InterfaceId interface)
275 : {
276 0 : CHIP_ERROR err = CHIP_ERROR_NOT_CONNECTED;
277 0 : mEndpoints.ForEachActiveObject([&](auto * info) {
278 0 : if (info->mListenUdp == nullptr)
279 : {
280 0 : return chip::Loop::Continue;
281 : }
282 :
283 0 : if (info->mAddressType != addr.Type())
284 : {
285 0 : return chip::Loop::Continue;
286 : }
287 :
288 0 : chip::Inet::InterfaceId boundIf = info->mListenUdp->GetBoundInterface();
289 :
290 0 : if ((boundIf.IsPresent()) && (boundIf != interface))
291 : {
292 0 : return chip::Loop::Continue;
293 : }
294 :
295 0 : err = info->mListenUdp->SendTo(addr, port, std::move(data));
296 0 : return chip::Loop::Break;
297 : });
298 :
299 0 : return err;
300 : }
301 :
302 0 : CHIP_ERROR ServerBase::BroadcastUnicastQuery(chip::System::PacketBufferHandle && data, uint16_t port)
303 : {
304 0 : QuerySocketPickerDelegate socketPicker;
305 0 : return BroadcastImpl(std::move(data), port, &socketPicker);
306 0 : }
307 :
308 0 : CHIP_ERROR ServerBase::BroadcastUnicastQuery(chip::System::PacketBufferHandle && data, uint16_t port,
309 : chip::Inet::InterfaceId interface, chip::Inet::IPAddressType addressType)
310 : {
311 0 : QuerySocketPickerDelegate socketPicker;
312 0 : InterfaceTypeFilterDelegate filter(interface, addressType, &socketPicker);
313 :
314 0 : return BroadcastImpl(std::move(data), port, &filter);
315 0 : }
316 :
317 78 : CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle && data, uint16_t port, chip::Inet::InterfaceId interface,
318 : chip::Inet::IPAddressType addressType)
319 : {
320 78 : ListenSocketPickerDelegate socketPicker;
321 78 : InterfaceTypeFilterDelegate filter(interface, addressType, &socketPicker);
322 :
323 78 : return BroadcastImpl(std::move(data), port, &filter);
324 78 : }
325 :
326 0 : CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle && data, uint16_t port)
327 : {
328 0 : ListenSocketPickerDelegate socketPicker;
329 0 : return BroadcastImpl(std::move(data), port, &socketPicker);
330 0 : }
331 :
332 78 : CHIP_ERROR ServerBase::BroadcastImpl(chip::System::PacketBufferHandle && data, uint16_t port, BroadcastSendDelegate * delegate)
333 : {
334 : // Broadcast requires sending data multiple times, each of which may error
335 : // out, yet broadcast only has a single error code.
336 : //
337 : // The general logic of error handling is:
338 : // - if no send done at all, return error
339 : // - if at least one broadcast succeeds, assume success overall
340 : // + some internal consistency validations for state error.
341 :
342 78 : unsigned successes = 0;
343 78 : unsigned failures = 0;
344 78 : CHIP_ERROR lastError = CHIP_ERROR_NO_ENDPOINT;
345 :
346 78 : if (chip::Loop::Break == mEndpoints.ForEachActiveObject([&](auto * info) {
347 96 : chip::Inet::UDPEndPoint * udp = delegate->Accept(info);
348 :
349 96 : if (udp == nullptr)
350 : {
351 48 : return chip::Loop::Continue;
352 : }
353 :
354 48 : CHIP_ERROR err = CHIP_NO_ERROR;
355 :
356 : /// The same packet needs to be sent over potentially multiple interfaces.
357 : /// LWIP does not like having a pbuf sent over serparate interfaces, hence we create a copy
358 : /// for sending via `CloneData`
359 : ///
360 : /// TODO: this wastes one copy of the data and that could be optimized away
361 48 : chip::System::PacketBufferHandle tempBuf = data.CloneData();
362 48 : if (tempBuf.IsNull())
363 : {
364 : // Not enough memory available to clone pbuf
365 0 : err = CHIP_ERROR_NO_MEMORY;
366 : }
367 48 : else if (info->mAddressType == chip::Inet::IPAddressType::kIPv6)
368 : {
369 24 : err = udp->SendTo(mIpv6BroadcastAddress, port, std::move(tempBuf), udp->GetBoundInterface());
370 : }
371 : #if INET_CONFIG_ENABLE_IPV4
372 24 : else if (info->mAddressType == chip::Inet::IPAddressType::kIPv4)
373 : {
374 24 : err = udp->SendTo(mIpv4BroadcastAddress, port, std::move(tempBuf), udp->GetBoundInterface());
375 : }
376 : #endif
377 : else
378 : {
379 : // This is a general error of internal consistency: every address has a known type. Fail completely otherwise.
380 0 : lastError = CHIP_ERROR_INCORRECT_STATE;
381 0 : return chip::Loop::Break;
382 : }
383 :
384 48 : if (err == CHIP_NO_ERROR)
385 : {
386 48 : successes++;
387 : }
388 : else
389 : {
390 0 : failures++;
391 0 : lastError = err;
392 : #if CHIP_DETAIL_LOGGING
393 : char ifaceName[chip::Inet::InterfaceId::kMaxIfNameLength];
394 0 : err = info->mInterfaceId.GetInterfaceName(ifaceName, sizeof(ifaceName));
395 0 : if (err != CHIP_NO_ERROR)
396 0 : strcpy(ifaceName, "???");
397 0 : ChipLogDetail(Discovery, "Warning: Attempt to mDNS broadcast failed on %s: %s", ifaceName, lastError.AsString());
398 : #endif
399 : }
400 48 : return chip::Loop::Continue;
401 48 : }))
402 : {
403 0 : return lastError;
404 : }
405 :
406 78 : if (failures != 0)
407 : {
408 : // if we had failures, log if the final status was success or failure, to make log reading
409 : // easier. Some mDNS failures may be expected (e.g. for interfaces unavailable)
410 0 : if (successes != 0)
411 : {
412 0 : ChipLogDetail(Discovery, "mDNS broadcast had only partial success: %u successes and %u failures.", successes, failures);
413 : }
414 : else
415 : {
416 0 : ChipLogProgress(Discovery, "mDNS broadcast full failed in %u separate send attempts.", failures);
417 : }
418 : }
419 :
420 78 : if (!successes)
421 : {
422 30 : return lastError;
423 : }
424 :
425 48 : return CHIP_NO_ERROR;
426 : }
427 :
428 32 : void ServerBase::OnUdpPacketReceived(chip::Inet::UDPEndPoint * endPoint, chip::System::PacketBufferHandle && buffer,
429 : const chip::Inet::IPPacketInfo * info)
430 : {
431 32 : ServerBase * srv = static_cast<ServerBase *>(endPoint->mAppState);
432 32 : if (!srv->mDelegate)
433 : {
434 0 : return;
435 : }
436 :
437 32 : mdns::Minimal::BytesRange data(buffer->Start(), buffer->Start() + buffer->DataLength());
438 32 : if (data.Size() < HeaderRef::kSizeBytes)
439 : {
440 0 : ChipLogError(Discovery, "Packet to small for mDNS data: %d bytes", static_cast<int>(data.Size()));
441 0 : return;
442 : }
443 :
444 32 : if (HeaderRef(const_cast<uint8_t *>(data.Start())).GetFlags().IsQuery())
445 : {
446 : // Only consider queries that are received on the same interface we are listening on.
447 : // Without this, queries show up on all addresses on all interfaces, resulting
448 : // in more replies than one would expect.
449 0 : if (endPoint->GetBoundInterface() == info->Interface)
450 : {
451 0 : srv->mDelegate->OnQuery(data, info);
452 : }
453 : }
454 : else
455 : {
456 32 : srv->mDelegate->OnResponse(data, info);
457 : }
458 : }
459 :
460 : } // namespace Minimal
461 : } // namespace mdns
|