1 /*
2 * Copyright (c) 2018, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements mDNS publisher based on mDNSResponder.
32 */
33
34 #define OTBR_LOG_TAG "MDNS"
35
36 #include "mdns/mdns_mdnssd.hpp"
37
38 #include <algorithm>
39
40 #include <arpa/inet.h>
41 #include <assert.h>
42 #include <errno.h>
43 #include <inttypes.h>
44 #include <netinet/in.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48
49 #include "common/code_utils.hpp"
50 #include "common/dns_utils.hpp"
51 #include "common/logging.hpp"
52 #include "common/time.hpp"
53
54 namespace otbr {
55
56 namespace Mdns {
57
58 static const char kDomain[] = "local.";
59
DNSErrorToOtbrError(DNSServiceErrorType aError)60 static otbrError DNSErrorToOtbrError(DNSServiceErrorType aError)
61 {
62 otbrError error;
63
64 switch (aError)
65 {
66 case kDNSServiceErr_NoError:
67 error = OTBR_ERROR_NONE;
68 break;
69
70 case kDNSServiceErr_NoSuchKey:
71 case kDNSServiceErr_NoSuchName:
72 case kDNSServiceErr_NoSuchRecord:
73 error = OTBR_ERROR_NOT_FOUND;
74 break;
75
76 case kDNSServiceErr_Invalid:
77 case kDNSServiceErr_BadParam:
78 case kDNSServiceErr_BadFlags:
79 case kDNSServiceErr_BadInterfaceIndex:
80 error = OTBR_ERROR_INVALID_ARGS;
81 break;
82
83 case kDNSServiceErr_NameConflict:
84 error = OTBR_ERROR_DUPLICATED;
85 break;
86
87 case kDNSServiceErr_Unsupported:
88 error = OTBR_ERROR_NOT_IMPLEMENTED;
89 break;
90
91 case kDNSServiceErr_ServiceNotRunning:
92 error = OTBR_ERROR_INVALID_STATE;
93 break;
94
95 default:
96 error = OTBR_ERROR_MDNS;
97 break;
98 }
99
100 return error;
101 }
102
DNSErrorToString(DNSServiceErrorType aError)103 static const char *DNSErrorToString(DNSServiceErrorType aError)
104 {
105 switch (aError)
106 {
107 case kDNSServiceErr_NoError:
108 return "OK";
109
110 case kDNSServiceErr_Unknown:
111 // 0xFFFE FFFF
112 return "Unknown";
113
114 case kDNSServiceErr_NoSuchName:
115 return "No Such Name";
116
117 case kDNSServiceErr_NoMemory:
118 return "No Memory";
119
120 case kDNSServiceErr_BadParam:
121 return "Bad Param";
122
123 case kDNSServiceErr_BadReference:
124 return "Bad Reference";
125
126 case kDNSServiceErr_BadState:
127 return "Bad State";
128
129 case kDNSServiceErr_BadFlags:
130 return "Bad Flags";
131
132 case kDNSServiceErr_Unsupported:
133 return "Unsupported";
134
135 case kDNSServiceErr_NotInitialized:
136 return "Not Initialized";
137
138 case kDNSServiceErr_AlreadyRegistered:
139 return "Already Registered";
140
141 case kDNSServiceErr_NameConflict:
142 return "Name Conflict";
143
144 case kDNSServiceErr_Invalid:
145 return "Invalid";
146
147 case kDNSServiceErr_Firewall:
148 return "Firewall";
149
150 case kDNSServiceErr_Incompatible:
151 // client library incompatible with daemon
152 return "Incompatible";
153
154 case kDNSServiceErr_BadInterfaceIndex:
155 return "Bad Interface Index";
156
157 case kDNSServiceErr_Refused:
158 return "Refused";
159
160 case kDNSServiceErr_NoSuchRecord:
161 return "No Such Record";
162
163 case kDNSServiceErr_NoAuth:
164 return "No Auth";
165
166 case kDNSServiceErr_NoSuchKey:
167 return "No Such Key";
168
169 case kDNSServiceErr_NATTraversal:
170 return "NAT Traversal";
171
172 case kDNSServiceErr_DoubleNAT:
173 return "Double NAT";
174
175 case kDNSServiceErr_BadTime:
176 // Codes up to here existed in Tiger
177 return "Bad Time";
178
179 case kDNSServiceErr_BadSig:
180 return "Bad Sig";
181
182 case kDNSServiceErr_BadKey:
183 return "Bad Key";
184
185 case kDNSServiceErr_Transient:
186 return "Transient";
187
188 case kDNSServiceErr_ServiceNotRunning:
189 // Background daemon not running
190 return "Service Not Running";
191
192 case kDNSServiceErr_NATPortMappingUnsupported:
193 // NAT doesn't support NAT-PMP or UPnP
194 return "NAT Port Mapping Unsupported";
195
196 case kDNSServiceErr_NATPortMappingDisabled:
197 // NAT supports NAT-PMP or UPnP but it's disabled by the administrator
198 return "NAT Port Mapping Disabled";
199
200 case kDNSServiceErr_NoRouter:
201 // No router currently configured (probably no network connectivity)
202 return "No Router";
203
204 case kDNSServiceErr_PollingMode:
205 return "Polling Mode";
206
207 case kDNSServiceErr_Timeout:
208 return "Timeout";
209
210 default:
211 assert(false);
212 return nullptr;
213 }
214 }
215
PublisherMDnsSd(StateCallback aCallback)216 PublisherMDnsSd::PublisherMDnsSd(StateCallback aCallback)
217 : mHostsRef(nullptr)
218 , mState(State::kIdle)
219 , mStateCallback(std::move(aCallback))
220 {
221 }
222
~PublisherMDnsSd(void)223 PublisherMDnsSd::~PublisherMDnsSd(void)
224 {
225 Stop(kNormalStop);
226 }
227
Start(void)228 otbrError PublisherMDnsSd::Start(void)
229 {
230 mState = State::kReady;
231 mStateCallback(State::kReady);
232 return OTBR_ERROR_NONE;
233 }
234
IsStarted(void) const235 bool PublisherMDnsSd::IsStarted(void) const
236 {
237 return mState == State::kReady;
238 }
239
Stop(StopMode aStopMode)240 void PublisherMDnsSd::Stop(StopMode aStopMode)
241 {
242 VerifyOrExit(mState == State::kReady);
243
244 // If we get a `kDNSServiceErr_ServiceNotRunning` and need to
245 // restart the `Publisher`, we should immediately de-allocate
246 // all `ServiceRef`. Otherwise, we first clear the `Registrations`
247 // list so that `DnssdHostRegisteration` destructor gets the chance
248 // to update registered records if needed.
249
250 switch (aStopMode)
251 {
252 case kNormalStop:
253 break;
254
255 case kStopOnServiceNotRunningError:
256 DeallocateHostsRef();
257 break;
258 }
259
260 mServiceRegistrations.clear();
261 mHostRegistrations.clear();
262 mKeyRegistrations.clear();
263 DeallocateHostsRef();
264
265 mSubscribedServices.clear();
266 mSubscribedHosts.clear();
267
268 mState = State::kIdle;
269
270 exit:
271 return;
272 }
273
CreateSharedHostsRef(void)274 DNSServiceErrorType PublisherMDnsSd::CreateSharedHostsRef(void)
275 {
276 DNSServiceErrorType dnsError = kDNSServiceErr_NoError;
277
278 VerifyOrExit(mHostsRef == nullptr);
279
280 dnsError = DNSServiceCreateConnection(&mHostsRef);
281 otbrLogDebug("Created new shared DNSServiceRef: %p", mHostsRef);
282
283 exit:
284 return dnsError;
285 }
286
DeallocateHostsRef(void)287 void PublisherMDnsSd::DeallocateHostsRef(void)
288 {
289 VerifyOrExit(mHostsRef != nullptr);
290
291 HandleServiceRefDeallocating(mHostsRef);
292 DNSServiceRefDeallocate(mHostsRef);
293 otbrLogDebug("Deallocated DNSServiceRef for hosts: %p", mHostsRef);
294 mHostsRef = nullptr;
295
296 exit:
297 return;
298 }
299
Update(MainloopContext & aMainloop)300 void PublisherMDnsSd::Update(MainloopContext &aMainloop)
301 {
302 for (auto &kv : mServiceRegistrations)
303 {
304 auto &serviceReg = static_cast<DnssdServiceRegistration &>(*kv.second);
305
306 serviceReg.Update(aMainloop);
307 }
308
309 if (mHostsRef != nullptr)
310 {
311 int fd = DNSServiceRefSockFD(mHostsRef);
312
313 assert(fd != -1);
314
315 aMainloop.AddFdToReadSet(fd);
316 }
317
318 for (const auto &service : mSubscribedServices)
319 {
320 service->UpdateAll(aMainloop);
321 }
322
323 for (const auto &host : mSubscribedHosts)
324 {
325 host->Update(aMainloop);
326 }
327 }
328
Process(const MainloopContext & aMainloop)329 void PublisherMDnsSd::Process(const MainloopContext &aMainloop)
330 {
331 mServiceRefsToProcess.clear();
332
333 for (auto &kv : mServiceRegistrations)
334 {
335 auto &serviceReg = static_cast<DnssdServiceRegistration &>(*kv.second);
336
337 serviceReg.Process(aMainloop, mServiceRefsToProcess);
338 }
339
340 if (mHostsRef != nullptr)
341 {
342 int fd = DNSServiceRefSockFD(mHostsRef);
343
344 if (FD_ISSET(fd, &aMainloop.mReadFdSet))
345 {
346 mServiceRefsToProcess.push_back(mHostsRef);
347 }
348 }
349
350 for (const auto &service : mSubscribedServices)
351 {
352 service->ProcessAll(aMainloop, mServiceRefsToProcess);
353 }
354
355 for (const auto &host : mSubscribedHosts)
356 {
357 host->Process(aMainloop, mServiceRefsToProcess);
358 }
359
360 for (DNSServiceRef serviceRef : mServiceRefsToProcess)
361 {
362 DNSServiceErrorType error;
363
364 // As we go through the list of `mServiceRefsToProcess` the call
365 // to `DNSServiceProcessResult()` can itself invoke callbacks
366 // into `PublisherMDnsSd` and OT, which in turn, may change the
367 // state of `Publisher` and potentially trigger a previously
368 // valid `ServiceRef` in the list to be deallocated. We use
369 // `HandleServiceRefDeallocating()` which is called whenever a
370 // `ServiceRef` is being deallocated and from this we update
371 // the entry in `mServiceRefsToProcess` list to `nullptr` so to
372 // avoid calling `DNSServiceProcessResult()` on an already
373 // freed `ServiceRef`.
374
375 if (serviceRef == nullptr)
376 {
377 continue;
378 }
379
380 error = DNSServiceProcessResult(serviceRef);
381
382 if (error != kDNSServiceErr_NoError)
383 {
384 otbrLogLevel logLevel = (error == kDNSServiceErr_BadReference) ? OTBR_LOG_INFO : OTBR_LOG_WARNING;
385 otbrLog(logLevel, OTBR_LOG_TAG, "DNSServiceProcessResult failed: %s (serviceRef = %p)",
386 DNSErrorToString(error), serviceRef);
387 }
388 if (error == kDNSServiceErr_ServiceNotRunning)
389 {
390 otbrLogWarning("Need to reconnect to mdnsd");
391 Stop(kStopOnServiceNotRunningError);
392 Start();
393 ExitNow();
394 }
395 }
396 exit:
397 return;
398 }
399
HandleServiceRefDeallocating(const DNSServiceRef & aServiceRef)400 void PublisherMDnsSd::HandleServiceRefDeallocating(const DNSServiceRef &aServiceRef)
401 {
402 for (DNSServiceRef &entry : mServiceRefsToProcess)
403 {
404 if (entry == aServiceRef)
405 {
406 entry = nullptr;
407 }
408 }
409 }
410
Update(MainloopContext & aMainloop) const411 void PublisherMDnsSd::DnssdServiceRegistration::Update(MainloopContext &aMainloop) const
412 {
413 int fd;
414
415 VerifyOrExit(mServiceRef != nullptr);
416
417 fd = DNSServiceRefSockFD(mServiceRef);
418 VerifyOrExit(fd != -1);
419
420 aMainloop.AddFdToReadSet(fd);
421
422 exit:
423 return;
424 }
425
Process(const MainloopContext & aMainloop,std::vector<DNSServiceRef> & aReadyServices) const426 void PublisherMDnsSd::DnssdServiceRegistration::Process(const MainloopContext &aMainloop,
427 std::vector<DNSServiceRef> &aReadyServices) const
428 {
429 int fd;
430
431 VerifyOrExit(mServiceRef != nullptr);
432
433 fd = DNSServiceRefSockFD(mServiceRef);
434 VerifyOrExit(fd != -1);
435
436 VerifyOrExit(FD_ISSET(fd, &aMainloop.mReadFdSet));
437 aReadyServices.push_back(mServiceRef);
438
439 exit:
440 return;
441 }
442
Register(void)443 otbrError PublisherMDnsSd::DnssdServiceRegistration::Register(void)
444 {
445 std::string fullHostName;
446 std::string regType = MakeRegType(mType, mSubTypeList);
447 const char *hostNameCString = nullptr;
448 const char *serviceNameCString = nullptr;
449 DnssdKeyRegistration *keyReg;
450 DNSServiceErrorType dnsError;
451
452 if (!mHostName.empty())
453 {
454 fullHostName = MakeFullHostName(mHostName);
455 hostNameCString = fullHostName.c_str();
456 }
457
458 if (!mName.empty())
459 {
460 serviceNameCString = mName.c_str();
461 }
462
463 keyReg = static_cast<DnssdKeyRegistration *>(GetPublisher().FindKeyRegistration(mName, mType));
464
465 if (keyReg != nullptr)
466 {
467 keyReg->Unregister();
468 }
469
470 otbrLogInfo("Registering service %s.%s", mName.c_str(), regType.c_str());
471
472 dnsError = DNSServiceRegister(&mServiceRef, kDNSServiceFlagsNoAutoRename, kDNSServiceInterfaceIndexAny,
473 serviceNameCString, regType.c_str(),
474 /* domain */ nullptr, hostNameCString, htons(mPort), mTxtData.size(), mTxtData.data(),
475 HandleRegisterResult, this);
476
477 if (dnsError != kDNSServiceErr_NoError)
478 {
479 HandleRegisterResult(/* aFlags */ 0, dnsError);
480 }
481
482 if (keyReg != nullptr)
483 {
484 keyReg->Register();
485 }
486
487 return GetPublisher().DnsErrorToOtbrError(dnsError);
488 }
489
Unregister(void)490 void PublisherMDnsSd::DnssdServiceRegistration::Unregister(void)
491 {
492 DnssdKeyRegistration *keyReg = mRelatedKeyReg;
493
494 VerifyOrExit(mServiceRef != nullptr);
495
496 // If we have a related key registration associated with this
497 // service registration, we first unregister it and after we
498 // deallocated the `mServiceRef` try to register it again
499 // (which will add it as an individual record not tied to a
500 // service registration). Note that the `keyReg->Unregister()`
501 // will clear the `mRelatedKeyReg` field, so we need to keep
502 // a local copy to it in `keyReg`.
503
504 if (keyReg != nullptr)
505 {
506 keyReg->Unregister();
507 }
508
509 GetPublisher().HandleServiceRefDeallocating(mServiceRef);
510 DNSServiceRefDeallocate(mServiceRef);
511 mServiceRef = nullptr;
512
513 if (keyReg != nullptr)
514 {
515 keyReg->Register();
516 }
517
518 exit:
519 return;
520 }
521
HandleRegisterResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,DNSServiceErrorType aError,const char * aName,const char * aType,const char * aDomain,void * aContext)522 void PublisherMDnsSd::DnssdServiceRegistration::HandleRegisterResult(DNSServiceRef aServiceRef,
523 DNSServiceFlags aFlags,
524 DNSServiceErrorType aError,
525 const char *aName,
526 const char *aType,
527 const char *aDomain,
528 void *aContext)
529 {
530 OTBR_UNUSED_VARIABLE(aServiceRef);
531 OTBR_UNUSED_VARIABLE(aName);
532 OTBR_UNUSED_VARIABLE(aType);
533 OTBR_UNUSED_VARIABLE(aDomain);
534
535 static_cast<DnssdServiceRegistration *>(aContext)->HandleRegisterResult(aFlags, aError);
536 }
537
HandleRegisterResult(DNSServiceFlags aFlags,DNSServiceErrorType aError)538 void PublisherMDnsSd::DnssdServiceRegistration::HandleRegisterResult(DNSServiceFlags aFlags, DNSServiceErrorType aError)
539 {
540 if (mRelatedKeyReg != nullptr)
541 {
542 mRelatedKeyReg->HandleRegisterResult(aError);
543 }
544
545 if ((aError == kDNSServiceErr_NoError) && (aFlags & kDNSServiceFlagsAdd))
546 {
547 otbrLogInfo("Successfully registered service %s.%s", mName.c_str(), mType.c_str());
548 Complete(OTBR_ERROR_NONE);
549 }
550 else
551 {
552 otbrLogErr("Failed to register service %s.%s: %s", mName.c_str(), mType.c_str(), DNSErrorToString(aError));
553 GetPublisher().RemoveServiceRegistration(mName, mType, DNSErrorToOtbrError(aError));
554 }
555 }
556
Register(void)557 otbrError PublisherMDnsSd::DnssdHostRegistration::Register(void)
558 {
559 DNSServiceErrorType dnsError = kDNSServiceErr_NoError;
560
561 otbrLogInfo("Registering new host %s", mName.c_str());
562
563 for (const Ip6Address &address : mAddresses)
564 {
565 DNSRecordRef recordRef = nullptr;
566
567 dnsError = GetPublisher().CreateSharedHostsRef();
568 VerifyOrExit(dnsError == kDNSServiceErr_NoError);
569
570 dnsError = DNSServiceRegisterRecord(GetPublisher().mHostsRef, &recordRef, kDNSServiceFlagsShared,
571 kDNSServiceInterfaceIndexAny, MakeFullHostName(mName).c_str(),
572 kDNSServiceType_AAAA, kDNSServiceClass_IN, sizeof(address.m8), address.m8,
573 /* ttl */ 0, HandleRegisterResult, this);
574 VerifyOrExit(dnsError == kDNSServiceErr_NoError);
575
576 mAddrRecordRefs.push_back(recordRef);
577 mAddrRegistered.push_back(false);
578 }
579
580 exit:
581 if ((dnsError != kDNSServiceErr_NoError) || mAddresses.empty())
582 {
583 HandleRegisterResult(/* aRecordRef */ nullptr, dnsError);
584 }
585
586 return GetPublisher().DnsErrorToOtbrError(dnsError);
587 }
588
Unregister(void)589 void PublisherMDnsSd::DnssdHostRegistration::Unregister(void)
590 {
591 DNSServiceErrorType dnsError;
592
593 VerifyOrExit(GetPublisher().mHostsRef != nullptr);
594
595 for (size_t index = 0; index < mAddrRecordRefs.size(); index++)
596 {
597 const Ip6Address &address = mAddresses[index];
598
599 if (mAddrRegistered[index])
600 {
601 // The Bonjour mDNSResponder somehow doesn't send goodbye message for the AAAA record when it is
602 // removed by `DNSServiceRemoveRecord`. Per RFC 6762, a goodbye message of a record sets its TTL
603 // to zero but the receiver should record the TTL of 1 and flushes the cache 1 second later. Here
604 // we remove the AAAA record after updating its TTL to 1 second. This has the same effect as
605 // sending a goodbye message.
606 // TODO: resolve the goodbye issue with Bonjour mDNSResponder.
607 dnsError = DNSServiceUpdateRecord(GetPublisher().mHostsRef, mAddrRecordRefs[index], kDNSServiceFlagsUnique,
608 sizeof(address.m8), address.m8, /* ttl */ 1);
609 otbrLogResult(DNSErrorToOtbrError(dnsError), "Send goodbye message for host %s address %s: %s",
610 MakeFullHostName(mName).c_str(), address.ToString().c_str(), DNSErrorToString(dnsError));
611 }
612
613 dnsError = DNSServiceRemoveRecord(GetPublisher().mHostsRef, mAddrRecordRefs[index], /* flags */ 0);
614
615 otbrLogResult(DNSErrorToOtbrError(dnsError), "Remove record for host %s address %s: %s",
616 MakeFullHostName(mName).c_str(), address.ToString().c_str(), DNSErrorToString(dnsError));
617 }
618
619 exit:
620 mAddrRegistered.clear();
621 mAddrRecordRefs.clear();
622 }
623
HandleRegisterResult(DNSServiceRef aServiceRef,DNSRecordRef aRecordRef,DNSServiceFlags aFlags,DNSServiceErrorType aError,void * aContext)624 void PublisherMDnsSd::DnssdHostRegistration::HandleRegisterResult(DNSServiceRef aServiceRef,
625 DNSRecordRef aRecordRef,
626 DNSServiceFlags aFlags,
627 DNSServiceErrorType aError,
628 void *aContext)
629 {
630 OTBR_UNUSED_VARIABLE(aServiceRef);
631 OTBR_UNUSED_VARIABLE(aFlags);
632
633 static_cast<DnssdHostRegistration *>(aContext)->HandleRegisterResult(aRecordRef, aError);
634 }
635
HandleRegisterResult(DNSRecordRef aRecordRef,DNSServiceErrorType aError)636 void PublisherMDnsSd::DnssdHostRegistration::HandleRegisterResult(DNSRecordRef aRecordRef, DNSServiceErrorType aError)
637 {
638 if (aError != kDNSServiceErr_NoError)
639 {
640 otbrLogErr("Failed to register host %s: %s", mName.c_str(), DNSErrorToString(aError));
641 GetPublisher().RemoveHostRegistration(mName, DNSErrorToOtbrError(aError));
642 }
643 else
644 {
645 bool shouldComplete = !IsCompleted();
646
647 for (size_t index = 0; index < mAddrRecordRefs.size(); index++)
648 {
649 if ((mAddrRecordRefs[index] == aRecordRef) && !mAddrRegistered[index])
650 {
651 mAddrRegistered[index] = true;
652 otbrLogInfo("Successfully registered host %s address %s", mName.c_str(),
653 mAddresses[index].ToString().c_str());
654 }
655
656 if (!mAddrRegistered[index])
657 {
658 shouldComplete = false;
659 }
660 }
661
662 if (shouldComplete)
663 {
664 otbrLogInfo("Successfully registered all host %s addresses", mName.c_str());
665 Complete(OTBR_ERROR_NONE);
666 }
667 }
668 }
669
Register(void)670 otbrError PublisherMDnsSd::DnssdKeyRegistration::Register(void)
671 {
672 DNSServiceErrorType dnsError = kDNSServiceErr_NoError;
673 DnssdServiceRegistration *serviceReg;
674
675 otbrLogInfo("Registering new key %s", mName.c_str());
676
677 serviceReg = static_cast<DnssdServiceRegistration *>(GetPublisher().FindServiceRegistration(mName));
678
679 if ((serviceReg != nullptr) && (serviceReg->mServiceRef != nullptr))
680 {
681 otbrLogInfo("Key %s is being registered as a record of an existing service registration", mName.c_str());
682
683 dnsError = DNSServiceAddRecord(serviceReg->mServiceRef, &mRecordRef, kDNSServiceFlagsUnique,
684 kDNSServiceType_KEY, mKeyData.size(), mKeyData.data(), /* ttl */ 0);
685
686 VerifyOrExit(dnsError == kDNSServiceErr_NoError);
687
688 mRelatedServiceReg = serviceReg;
689 serviceReg->mRelatedKeyReg = this;
690
691 if (mRelatedServiceReg->IsCompleted())
692 {
693 HandleRegisterResult(kDNSServiceErr_NoError);
694 }
695
696 // If related service registration is not yet finished,
697 // we wait for service registration completion to signal
698 // key record registration as well.
699 }
700 else
701 {
702 otbrLogInfo("Key %s is being registered individually", mName.c_str());
703
704 dnsError = GetPublisher().CreateSharedHostsRef();
705 VerifyOrExit(dnsError == kDNSServiceErr_NoError);
706
707 dnsError = DNSServiceRegisterRecord(GetPublisher().mHostsRef, &mRecordRef, kDNSServiceFlagsUnique,
708 kDNSServiceInterfaceIndexAny, MakeFullKeyName(mName).c_str(),
709 kDNSServiceType_KEY, kDNSServiceClass_IN, mKeyData.size(), mKeyData.data(),
710 /* ttl */ 0, HandleRegisterResult, this);
711 VerifyOrExit(dnsError == kDNSServiceErr_NoError);
712 }
713
714 exit:
715 if (dnsError != kDNSServiceErr_NoError)
716 {
717 HandleRegisterResult(dnsError);
718 }
719
720 return GetPublisher().DnsErrorToOtbrError(dnsError);
721 }
722
Unregister(void)723 void PublisherMDnsSd::DnssdKeyRegistration::Unregister(void)
724 {
725 DNSServiceErrorType dnsError;
726 DNSServiceRef serviceRef;
727
728 VerifyOrExit(mRecordRef != nullptr);
729
730 if (mRelatedServiceReg != nullptr)
731 {
732 serviceRef = mRelatedServiceReg->mServiceRef;
733
734 mRelatedServiceReg->mRelatedKeyReg = nullptr;
735 mRelatedServiceReg = nullptr;
736
737 otbrLogInfo("Unregistering key %s (was registered as a record of a service)", mName.c_str());
738 }
739 else
740 {
741 serviceRef = GetPublisher().mHostsRef;
742
743 otbrLogInfo("Unregistering key %s (was registered individually)", mName.c_str());
744 }
745
746 VerifyOrExit(serviceRef != nullptr);
747
748 dnsError = DNSServiceRemoveRecord(serviceRef, mRecordRef, /* flags */ 0);
749
750 otbrLogInfo("Unregistered key %s: error:%s", mName.c_str(), DNSErrorToString(dnsError));
751
752 exit:
753 return;
754 }
755
HandleRegisterResult(DNSServiceRef aServiceRef,DNSRecordRef aRecordRef,DNSServiceFlags aFlags,DNSServiceErrorType aError,void * aContext)756 void PublisherMDnsSd::DnssdKeyRegistration::HandleRegisterResult(DNSServiceRef aServiceRef,
757 DNSRecordRef aRecordRef,
758 DNSServiceFlags aFlags,
759 DNSServiceErrorType aError,
760 void *aContext)
761 {
762 OTBR_UNUSED_VARIABLE(aServiceRef);
763 OTBR_UNUSED_VARIABLE(aRecordRef);
764 OTBR_UNUSED_VARIABLE(aFlags);
765
766 static_cast<DnssdKeyRegistration *>(aContext)->HandleRegisterResult(aError);
767 }
768
HandleRegisterResult(DNSServiceErrorType aError)769 void PublisherMDnsSd::DnssdKeyRegistration::HandleRegisterResult(DNSServiceErrorType aError)
770 {
771 if (aError != kDNSServiceErr_NoError)
772 {
773 otbrLogErr("Failed to register key %s: %s", mName.c_str(), DNSErrorToString(aError));
774 GetPublisher().RemoveKeyRegistration(mName, DNSErrorToOtbrError(aError));
775 }
776 else
777 {
778 otbrLogInfo("Successfully registered key %s", mName.c_str());
779 Complete(OTBR_ERROR_NONE);
780 }
781 }
782
PublishServiceImpl(const std::string & aHostName,const std::string & aName,const std::string & aType,const SubTypeList & aSubTypeList,uint16_t aPort,const TxtData & aTxtData,ResultCallback && aCallback)783 otbrError PublisherMDnsSd::PublishServiceImpl(const std::string &aHostName,
784 const std::string &aName,
785 const std::string &aType,
786 const SubTypeList &aSubTypeList,
787 uint16_t aPort,
788 const TxtData &aTxtData,
789 ResultCallback &&aCallback)
790 {
791 otbrError error = OTBR_ERROR_NONE;
792 SubTypeList sortedSubTypeList = SortSubTypeList(aSubTypeList);
793 std::string regType = MakeRegType(aType, sortedSubTypeList);
794 DnssdServiceRegistration *serviceReg;
795
796 if (mState != State::kReady)
797 {
798 error = OTBR_ERROR_INVALID_STATE;
799 std::move(aCallback)(error);
800 ExitNow();
801 }
802
803 aCallback = HandleDuplicateServiceRegistration(aHostName, aName, aType, sortedSubTypeList, aPort, aTxtData,
804 std::move(aCallback));
805 VerifyOrExit(!aCallback.IsNull());
806
807 serviceReg = new DnssdServiceRegistration(aHostName, aName, aType, sortedSubTypeList, aPort, aTxtData,
808 std::move(aCallback), this);
809 AddServiceRegistration(std::unique_ptr<DnssdServiceRegistration>(serviceReg));
810
811 error = serviceReg->Register();
812
813 exit:
814 return error;
815 }
816
UnpublishService(const std::string & aName,const std::string & aType,ResultCallback && aCallback)817 void PublisherMDnsSd::UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback)
818 {
819 otbrError error = OTBR_ERROR_NONE;
820
821 VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
822 RemoveServiceRegistration(aName, aType, OTBR_ERROR_ABORTED);
823
824 exit:
825 std::move(aCallback)(error);
826 }
827
PublishHostImpl(const std::string & aName,const AddressList & aAddresses,ResultCallback && aCallback)828 otbrError PublisherMDnsSd::PublishHostImpl(const std::string &aName,
829 const AddressList &aAddresses,
830 ResultCallback &&aCallback)
831 {
832 otbrError error = OTBR_ERROR_NONE;
833 DnssdHostRegistration *hostReg;
834
835 if (mState != State::kReady)
836 {
837 error = OTBR_ERROR_INVALID_STATE;
838 std::move(aCallback)(error);
839 ExitNow();
840 }
841
842 aCallback = HandleDuplicateHostRegistration(aName, aAddresses, std::move(aCallback));
843 VerifyOrExit(!aCallback.IsNull());
844
845 hostReg = new DnssdHostRegistration(aName, aAddresses, std::move(aCallback), this);
846 AddHostRegistration(std::unique_ptr<DnssdHostRegistration>(hostReg));
847
848 error = hostReg->Register();
849
850 exit:
851 return error;
852 }
853
UnpublishHost(const std::string & aName,ResultCallback && aCallback)854 void PublisherMDnsSd::UnpublishHost(const std::string &aName, ResultCallback &&aCallback)
855 {
856 otbrError error = OTBR_ERROR_NONE;
857
858 VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
859 RemoveHostRegistration(aName, OTBR_ERROR_ABORTED);
860
861 exit:
862 // We may failed to unregister the host from underlying mDNS publishers, but
863 // it usually means that the mDNS publisher is already not functioning. So it's
864 // okay to return success directly since the service is not advertised anyway.
865 std::move(aCallback)(error);
866 }
867
PublishKeyImpl(const std::string & aName,const KeyData & aKeyData,ResultCallback && aCallback)868 otbrError PublisherMDnsSd::PublishKeyImpl(const std::string &aName, const KeyData &aKeyData, ResultCallback &&aCallback)
869 {
870 otbrError error = OTBR_ERROR_NONE;
871 DnssdKeyRegistration *keyReg;
872
873 if (mState != State::kReady)
874 {
875 error = OTBR_ERROR_INVALID_STATE;
876 std::move(aCallback)(error);
877 ExitNow();
878 }
879
880 aCallback = HandleDuplicateKeyRegistration(aName, aKeyData, std::move(aCallback));
881 VerifyOrExit(!aCallback.IsNull());
882
883 keyReg = new DnssdKeyRegistration(aName, aKeyData, std::move(aCallback), this);
884 AddKeyRegistration(std::unique_ptr<DnssdKeyRegistration>(keyReg));
885
886 error = keyReg->Register();
887
888 exit:
889 return error;
890 }
891
UnpublishKey(const std::string & aName,ResultCallback && aCallback)892 void PublisherMDnsSd::UnpublishKey(const std::string &aName, ResultCallback &&aCallback)
893 {
894 otbrError error = OTBR_ERROR_NONE;
895
896 VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
897 RemoveKeyRegistration(aName, OTBR_ERROR_ABORTED);
898
899 exit:
900 std::move(aCallback)(error);
901 }
902
903 // See `regtype` parameter of the DNSServiceRegister() function for more information.
MakeRegType(const std::string & aType,SubTypeList aSubTypeList)904 std::string PublisherMDnsSd::MakeRegType(const std::string &aType, SubTypeList aSubTypeList)
905 {
906 std::string regType = aType;
907
908 std::sort(aSubTypeList.begin(), aSubTypeList.end());
909
910 for (const auto &subType : aSubTypeList)
911 {
912 regType += "," + subType;
913 }
914
915 return regType;
916 }
917
SubscribeService(const std::string & aType,const std::string & aInstanceName)918 void PublisherMDnsSd::SubscribeService(const std::string &aType, const std::string &aInstanceName)
919 {
920 VerifyOrExit(mState == Publisher::State::kReady);
921 mSubscribedServices.push_back(MakeUnique<ServiceSubscription>(*this, aType, aInstanceName));
922
923 otbrLogInfo("Subscribe service %s.%s (total %zu)", aInstanceName.c_str(), aType.c_str(),
924 mSubscribedServices.size());
925
926 if (aInstanceName.empty())
927 {
928 mSubscribedServices.back()->Browse();
929 }
930 else
931 {
932 mSubscribedServices.back()->Resolve(kDNSServiceInterfaceIndexAny, aInstanceName, aType, kDomain);
933 }
934
935 exit:
936 return;
937 }
938
UnsubscribeService(const std::string & aType,const std::string & aInstanceName)939 void PublisherMDnsSd::UnsubscribeService(const std::string &aType, const std::string &aInstanceName)
940 {
941 ServiceSubscriptionList::iterator it;
942
943 VerifyOrExit(mState == Publisher::State::kReady);
944 it = std::find_if(mSubscribedServices.begin(), mSubscribedServices.end(),
945 [&aType, &aInstanceName](const std::unique_ptr<ServiceSubscription> &aService) {
946 return aService->mType == aType && aService->mInstanceName == aInstanceName;
947 });
948 VerifyOrExit(it != mSubscribedServices.end());
949
950 mSubscribedServices.erase(it);
951
952 otbrLogInfo("Unsubscribe service %s.%s (left %zu)", aInstanceName.c_str(), aType.c_str(),
953 mSubscribedServices.size());
954
955 exit:
956 return;
957 }
958
OnServiceResolveFailedImpl(const std::string & aType,const std::string & aInstanceName,int32_t aErrorCode)959 void PublisherMDnsSd::OnServiceResolveFailedImpl(const std::string &aType,
960 const std::string &aInstanceName,
961 int32_t aErrorCode)
962 {
963 otbrLogWarning("Resolve service %s.%s failed: code=%" PRId32, aInstanceName.c_str(), aType.c_str(), aErrorCode);
964 }
965
OnHostResolveFailedImpl(const std::string & aHostName,int32_t aErrorCode)966 void PublisherMDnsSd::OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode)
967 {
968 otbrLogWarning("Resolve host %s failed: code=%" PRId32, aHostName.c_str(), aErrorCode);
969 }
970
DnsErrorToOtbrError(int32_t aErrorCode)971 otbrError PublisherMDnsSd::DnsErrorToOtbrError(int32_t aErrorCode)
972 {
973 return otbr::Mdns::DNSErrorToOtbrError(aErrorCode);
974 }
975
SubscribeHost(const std::string & aHostName)976 void PublisherMDnsSd::SubscribeHost(const std::string &aHostName)
977 {
978 VerifyOrExit(mState == State::kReady);
979 mSubscribedHosts.push_back(MakeUnique<HostSubscription>(*this, aHostName));
980
981 otbrLogInfo("Subscribe host %s (total %zu)", aHostName.c_str(), mSubscribedHosts.size());
982
983 mSubscribedHosts.back()->Resolve();
984
985 exit:
986 return;
987 }
988
UnsubscribeHost(const std::string & aHostName)989 void PublisherMDnsSd::UnsubscribeHost(const std::string &aHostName)
990 {
991 HostSubscriptionList ::iterator it;
992
993 VerifyOrExit(mState == Publisher::State::kReady);
994 it = std::find_if(
995 mSubscribedHosts.begin(), mSubscribedHosts.end(),
996 [&aHostName](const std::unique_ptr<HostSubscription> &aHost) { return aHost->mHostName == aHostName; });
997
998 VerifyOrExit(it != mSubscribedHosts.end());
999
1000 mSubscribedHosts.erase(it);
1001
1002 otbrLogInfo("Unsubscribe host %s (remaining %d)", aHostName.c_str(), mSubscribedHosts.size());
1003
1004 exit:
1005 return;
1006 }
1007
Create(StateCallback aCallback)1008 Publisher *Publisher::Create(StateCallback aCallback)
1009 {
1010 return new PublisherMDnsSd(aCallback);
1011 }
1012
Destroy(Publisher * aPublisher)1013 void Publisher::Destroy(Publisher *aPublisher)
1014 {
1015 delete static_cast<PublisherMDnsSd *>(aPublisher);
1016 }
1017
Release(void)1018 void PublisherMDnsSd::ServiceRef::Release(void)
1019 {
1020 DeallocateServiceRef();
1021 }
1022
DeallocateServiceRef(void)1023 void PublisherMDnsSd::ServiceRef::DeallocateServiceRef(void)
1024 {
1025 if (mServiceRef != nullptr)
1026 {
1027 mPublisher.HandleServiceRefDeallocating(mServiceRef);
1028 DNSServiceRefDeallocate(mServiceRef);
1029 mServiceRef = nullptr;
1030 }
1031 }
1032
Update(MainloopContext & aMainloop) const1033 void PublisherMDnsSd::ServiceRef::Update(MainloopContext &aMainloop) const
1034 {
1035 int fd;
1036
1037 VerifyOrExit(mServiceRef != nullptr);
1038
1039 fd = DNSServiceRefSockFD(mServiceRef);
1040 assert(fd != -1);
1041 aMainloop.AddFdToReadSet(fd);
1042 exit:
1043 return;
1044 }
1045
Process(const MainloopContext & aMainloop,std::vector<DNSServiceRef> & aReadyServices) const1046 void PublisherMDnsSd::ServiceRef::Process(const MainloopContext &aMainloop,
1047 std::vector<DNSServiceRef> &aReadyServices) const
1048 {
1049 int fd;
1050
1051 VerifyOrExit(mServiceRef != nullptr);
1052
1053 fd = DNSServiceRefSockFD(mServiceRef);
1054 assert(fd != -1);
1055 if (FD_ISSET(fd, &aMainloop.mReadFdSet))
1056 {
1057 aReadyServices.push_back(mServiceRef);
1058 }
1059 exit:
1060 return;
1061 }
1062
Browse(void)1063 void PublisherMDnsSd::ServiceSubscription::Browse(void)
1064 {
1065 assert(mServiceRef == nullptr);
1066
1067 otbrLogInfo("DNSServiceBrowse %s", mType.c_str());
1068 DNSServiceBrowse(&mServiceRef, /* flags */ 0, kDNSServiceInterfaceIndexAny, mType.c_str(),
1069 /* domain */ nullptr, HandleBrowseResult, this);
1070 }
1071
HandleBrowseResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aInstanceName,const char * aType,const char * aDomain,void * aContext)1072 void PublisherMDnsSd::ServiceSubscription::HandleBrowseResult(DNSServiceRef aServiceRef,
1073 DNSServiceFlags aFlags,
1074 uint32_t aInterfaceIndex,
1075 DNSServiceErrorType aErrorCode,
1076 const char *aInstanceName,
1077 const char *aType,
1078 const char *aDomain,
1079 void *aContext)
1080 {
1081 static_cast<ServiceSubscription *>(aContext)->HandleBrowseResult(aServiceRef, aFlags, aInterfaceIndex, aErrorCode,
1082 aInstanceName, aType, aDomain);
1083 }
1084
HandleBrowseResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aInstanceName,const char * aType,const char * aDomain)1085 void PublisherMDnsSd::ServiceSubscription::HandleBrowseResult(DNSServiceRef aServiceRef,
1086 DNSServiceFlags aFlags,
1087 uint32_t aInterfaceIndex,
1088 DNSServiceErrorType aErrorCode,
1089 const char *aInstanceName,
1090 const char *aType,
1091 const char *aDomain)
1092 {
1093 OTBR_UNUSED_VARIABLE(aServiceRef);
1094 OTBR_UNUSED_VARIABLE(aDomain);
1095
1096 otbrLogInfo("DNSServiceBrowse reply: %s %s.%s inf %" PRIu32 ", flags=%" PRIu32 ", error=%" PRId32,
1097 aFlags & kDNSServiceFlagsAdd ? "add" : "remove", aInstanceName, aType, aInterfaceIndex, aFlags,
1098 aErrorCode);
1099
1100 VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
1101
1102 if (aFlags & kDNSServiceFlagsAdd)
1103 {
1104 Resolve(aInterfaceIndex, aInstanceName, aType, aDomain);
1105 }
1106 else
1107 {
1108 mPublisher.OnServiceRemoved(aInterfaceIndex, mType, aInstanceName);
1109 }
1110
1111 exit:
1112 if (aErrorCode != kDNSServiceErr_NoError)
1113 {
1114 mPublisher.OnServiceResolveFailed(mType, mInstanceName, aErrorCode);
1115 Release();
1116 }
1117 }
1118
Resolve(uint32_t aInterfaceIndex,const std::string & aInstanceName,const std::string & aType,const std::string & aDomain)1119 void PublisherMDnsSd::ServiceSubscription::Resolve(uint32_t aInterfaceIndex,
1120 const std::string &aInstanceName,
1121 const std::string &aType,
1122 const std::string &aDomain)
1123 {
1124 mResolvingInstances.push_back(
1125 MakeUnique<ServiceInstanceResolution>(*this, aInstanceName, aType, aDomain, aInterfaceIndex));
1126 mResolvingInstances.back()->Resolve();
1127 }
1128
UpdateAll(MainloopContext & aMainloop) const1129 void PublisherMDnsSd::ServiceSubscription::UpdateAll(MainloopContext &aMainloop) const
1130 {
1131 Update(aMainloop);
1132
1133 for (const auto &instance : mResolvingInstances)
1134 {
1135 instance->Update(aMainloop);
1136 }
1137 }
1138
ProcessAll(const MainloopContext & aMainloop,std::vector<DNSServiceRef> & aReadyServices) const1139 void PublisherMDnsSd::ServiceSubscription::ProcessAll(const MainloopContext &aMainloop,
1140 std::vector<DNSServiceRef> &aReadyServices) const
1141 {
1142 Process(aMainloop, aReadyServices);
1143
1144 for (const auto &instance : mResolvingInstances)
1145 {
1146 instance->Process(aMainloop, aReadyServices);
1147 }
1148 }
1149
Resolve(void)1150 void PublisherMDnsSd::ServiceInstanceResolution::Resolve(void)
1151 {
1152 assert(mServiceRef == nullptr);
1153
1154 mSubscription->mPublisher.mServiceInstanceResolutionBeginTime[std::make_pair(mInstanceName, mType)] = Clock::now();
1155
1156 otbrLogInfo("DNSServiceResolve %s %s inf %u", mInstanceName.c_str(), mType.c_str(), mNetifIndex);
1157 DNSServiceResolve(&mServiceRef, /* flags */ kDNSServiceFlagsTimeout, mNetifIndex, mInstanceName.c_str(),
1158 mType.c_str(), mDomain.c_str(), HandleResolveResult, this);
1159 }
1160
HandleResolveResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aFullName,const char * aHostTarget,uint16_t aPort,uint16_t aTxtLen,const unsigned char * aTxtRecord,void * aContext)1161 void PublisherMDnsSd::ServiceInstanceResolution::HandleResolveResult(DNSServiceRef aServiceRef,
1162 DNSServiceFlags aFlags,
1163 uint32_t aInterfaceIndex,
1164 DNSServiceErrorType aErrorCode,
1165 const char *aFullName,
1166 const char *aHostTarget,
1167 uint16_t aPort,
1168 uint16_t aTxtLen,
1169 const unsigned char *aTxtRecord,
1170 void *aContext)
1171 {
1172 static_cast<ServiceInstanceResolution *>(aContext)->HandleResolveResult(
1173 aServiceRef, aFlags, aInterfaceIndex, aErrorCode, aFullName, aHostTarget, aPort, aTxtLen, aTxtRecord);
1174 }
1175
HandleResolveResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aFullName,const char * aHostTarget,uint16_t aPort,uint16_t aTxtLen,const unsigned char * aTxtRecord)1176 void PublisherMDnsSd::ServiceInstanceResolution::HandleResolveResult(DNSServiceRef aServiceRef,
1177 DNSServiceFlags aFlags,
1178 uint32_t aInterfaceIndex,
1179 DNSServiceErrorType aErrorCode,
1180 const char *aFullName,
1181 const char *aHostTarget,
1182 uint16_t aPort,
1183 uint16_t aTxtLen,
1184 const unsigned char *aTxtRecord)
1185 {
1186 OTBR_UNUSED_VARIABLE(aServiceRef);
1187
1188 std::string instanceName, type, domain;
1189 otbrError error = OTBR_ERROR_NONE;
1190
1191 otbrLogInfo("DNSServiceResolve reply: %s host %s:%d, TXT=%dB inf %u, flags=%u", aFullName, aHostTarget, aPort,
1192 aTxtLen, aInterfaceIndex, aFlags);
1193
1194 VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
1195
1196 SuccessOrExit(error = SplitFullServiceInstanceName(aFullName, instanceName, type, domain));
1197
1198 mInstanceInfo.mNetifIndex = aInterfaceIndex;
1199 mInstanceInfo.mName = instanceName;
1200 mInstanceInfo.mHostName = aHostTarget;
1201 mInstanceInfo.mPort = ntohs(aPort);
1202 mInstanceInfo.mTxtData.assign(aTxtRecord, aTxtRecord + aTxtLen);
1203 // priority and weight are not given in the reply
1204 mInstanceInfo.mPriority = 0;
1205 mInstanceInfo.mWeight = 0;
1206
1207 DeallocateServiceRef();
1208 error = GetAddrInfo(aInterfaceIndex);
1209
1210 exit:
1211 if (error != OTBR_ERROR_NONE)
1212 {
1213 otbrLogWarning("Failed to resolve service instance %s", aFullName);
1214 }
1215
1216 if (aErrorCode != kDNSServiceErr_NoError || error != OTBR_ERROR_NONE)
1217 {
1218 mSubscription->mPublisher.OnServiceResolveFailed(mSubscription->mType, mInstanceName, aErrorCode);
1219 FinishResolution();
1220 }
1221 }
1222
GetAddrInfo(uint32_t aInterfaceIndex)1223 otbrError PublisherMDnsSd::ServiceInstanceResolution::GetAddrInfo(uint32_t aInterfaceIndex)
1224 {
1225 DNSServiceErrorType dnsError;
1226
1227 assert(mServiceRef == nullptr);
1228
1229 otbrLogInfo("DNSServiceGetAddrInfo %s inf %d", mInstanceInfo.mHostName.c_str(), aInterfaceIndex);
1230
1231 dnsError = DNSServiceGetAddrInfo(&mServiceRef, /* flags */ 0, aInterfaceIndex,
1232 kDNSServiceProtocol_IPv6 | kDNSServiceProtocol_IPv4,
1233 mInstanceInfo.mHostName.c_str(), HandleGetAddrInfoResult, this);
1234
1235 if (dnsError != kDNSServiceErr_NoError)
1236 {
1237 otbrLogWarning("DNSServiceGetAddrInfo failed: %s", DNSErrorToString(dnsError));
1238 }
1239
1240 return dnsError == kDNSServiceErr_NoError ? OTBR_ERROR_NONE : OTBR_ERROR_MDNS;
1241 }
1242
HandleGetAddrInfoResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aHostName,const struct sockaddr * aAddress,uint32_t aTtl,void * aContext)1243 void PublisherMDnsSd::ServiceInstanceResolution::HandleGetAddrInfoResult(DNSServiceRef aServiceRef,
1244 DNSServiceFlags aFlags,
1245 uint32_t aInterfaceIndex,
1246 DNSServiceErrorType aErrorCode,
1247 const char *aHostName,
1248 const struct sockaddr *aAddress,
1249 uint32_t aTtl,
1250 void *aContext)
1251 {
1252 static_cast<ServiceInstanceResolution *>(aContext)->HandleGetAddrInfoResult(aServiceRef, aFlags, aInterfaceIndex,
1253 aErrorCode, aHostName, aAddress, aTtl);
1254 }
1255
HandleGetAddrInfoResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aHostName,const struct sockaddr * aAddress,uint32_t aTtl)1256 void PublisherMDnsSd::ServiceInstanceResolution::HandleGetAddrInfoResult(DNSServiceRef aServiceRef,
1257 DNSServiceFlags aFlags,
1258 uint32_t aInterfaceIndex,
1259 DNSServiceErrorType aErrorCode,
1260 const char *aHostName,
1261 const struct sockaddr *aAddress,
1262 uint32_t aTtl)
1263 {
1264 OTBR_UNUSED_VARIABLE(aServiceRef);
1265 OTBR_UNUSED_VARIABLE(aInterfaceIndex);
1266
1267 Ip6Address address;
1268 bool isAdd = (aFlags & kDNSServiceFlagsAdd) != 0;
1269
1270 otbrLog(aErrorCode == kDNSServiceErr_NoError ? OTBR_LOG_INFO : OTBR_LOG_WARNING, OTBR_LOG_TAG,
1271 "DNSServiceGetAddrInfo reply: flags=%" PRIu32 ", host=%s, sa_family=%u, error=%" PRId32, aFlags, aHostName,
1272 static_cast<unsigned int>(aAddress->sa_family), aErrorCode);
1273
1274 VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
1275 VerifyOrExit(aAddress->sa_family == AF_INET6);
1276
1277 address.CopyFrom(*reinterpret_cast<const struct sockaddr_in6 *>(aAddress));
1278 VerifyOrExit(!address.IsUnspecified() && !address.IsLinkLocal() && !address.IsMulticast() && !address.IsLoopback(),
1279 otbrLogDebug("DNSServiceGetAddrInfo ignores address %s", address.ToString().c_str()));
1280
1281 otbrLogInfo("DNSServiceGetAddrInfo reply: %s address=%s, ttl=%" PRIu32, isAdd ? "add" : "remove",
1282 address.ToString().c_str(), aTtl);
1283
1284 if (isAdd)
1285 {
1286 mInstanceInfo.AddAddress(address);
1287 }
1288 else
1289 {
1290 mInstanceInfo.RemoveAddress(address);
1291 }
1292 mInstanceInfo.mTtl = aTtl;
1293
1294 exit:
1295 if (!mInstanceInfo.mAddresses.empty() || aErrorCode != kDNSServiceErr_NoError)
1296 {
1297 FinishResolution();
1298 }
1299 }
1300
FinishResolution(void)1301 void PublisherMDnsSd::ServiceInstanceResolution::FinishResolution(void)
1302 {
1303 ServiceSubscription *subscription = mSubscription;
1304 std::string serviceName = mSubscription->mType;
1305 DiscoveredInstanceInfo instanceInfo = mInstanceInfo;
1306
1307 // NOTE: The `ServiceSubscription` object may be freed in `OnServiceResolved`.
1308 subscription->mPublisher.OnServiceResolved(serviceName, instanceInfo);
1309 }
1310
Resolve(void)1311 void PublisherMDnsSd::HostSubscription::Resolve(void)
1312 {
1313 std::string fullHostName = MakeFullHostName(mHostName);
1314
1315 assert(mServiceRef == nullptr);
1316
1317 mPublisher.mHostResolutionBeginTime[mHostName] = Clock::now();
1318
1319 otbrLogInfo("DNSServiceGetAddrInfo %s inf %d", fullHostName.c_str(), kDNSServiceInterfaceIndexAny);
1320
1321 DNSServiceGetAddrInfo(&mServiceRef, /* flags */ 0, kDNSServiceInterfaceIndexAny,
1322 kDNSServiceProtocol_IPv6 | kDNSServiceProtocol_IPv4, fullHostName.c_str(),
1323 HandleResolveResult, this);
1324 }
1325
HandleResolveResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aHostName,const struct sockaddr * aAddress,uint32_t aTtl,void * aContext)1326 void PublisherMDnsSd::HostSubscription::HandleResolveResult(DNSServiceRef aServiceRef,
1327 DNSServiceFlags aFlags,
1328 uint32_t aInterfaceIndex,
1329 DNSServiceErrorType aErrorCode,
1330 const char *aHostName,
1331 const struct sockaddr *aAddress,
1332 uint32_t aTtl,
1333 void *aContext)
1334 {
1335 static_cast<HostSubscription *>(aContext)->HandleResolveResult(aServiceRef, aFlags, aInterfaceIndex, aErrorCode,
1336 aHostName, aAddress, aTtl);
1337 }
1338
HandleResolveResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aHostName,const struct sockaddr * aAddress,uint32_t aTtl)1339 void PublisherMDnsSd::HostSubscription::HandleResolveResult(DNSServiceRef aServiceRef,
1340 DNSServiceFlags aFlags,
1341 uint32_t aInterfaceIndex,
1342 DNSServiceErrorType aErrorCode,
1343 const char *aHostName,
1344 const struct sockaddr *aAddress,
1345 uint32_t aTtl)
1346 {
1347 OTBR_UNUSED_VARIABLE(aServiceRef);
1348
1349 Ip6Address address;
1350 bool isAdd = (aFlags & kDNSServiceFlagsAdd) != 0;
1351
1352 otbrLog(aErrorCode == kDNSServiceErr_NoError ? OTBR_LOG_INFO : OTBR_LOG_WARNING, OTBR_LOG_TAG,
1353 "DNSServiceGetAddrInfo reply: flags=%" PRIu32 ", host=%s, sa_family=%u, error=%" PRId32, aFlags, aHostName,
1354 static_cast<unsigned int>(aAddress->sa_family), aErrorCode);
1355
1356 VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
1357 VerifyOrExit(aAddress->sa_family == AF_INET6);
1358
1359 address.CopyFrom(*reinterpret_cast<const struct sockaddr_in6 *>(aAddress));
1360 VerifyOrExit(!address.IsLinkLocal(),
1361 otbrLogDebug("DNSServiceGetAddrInfo ignore link-local address %s", address.ToString().c_str()));
1362
1363 otbrLogInfo("DNSServiceGetAddrInfo reply: %s address=%s, ttl=%" PRIu32, isAdd ? "add" : "remove",
1364 address.ToString().c_str(), aTtl);
1365
1366 if (isAdd)
1367 {
1368 mHostInfo.AddAddress(address);
1369 }
1370 else
1371 {
1372 mHostInfo.RemoveAddress(address);
1373 }
1374 mHostInfo.mHostName = aHostName;
1375 mHostInfo.mNetifIndex = aInterfaceIndex;
1376 mHostInfo.mTtl = aTtl;
1377
1378 // NOTE: This `HostSubscription` object may be freed in `OnHostResolved`.
1379 mPublisher.OnHostResolved(mHostName, mHostInfo);
1380
1381 exit:
1382 if (aErrorCode != kDNSServiceErr_NoError)
1383 {
1384 mPublisher.OnHostResolveFailed(aHostName, aErrorCode);
1385 }
1386 }
1387
1388 } // namespace Mdns
1389
1390 } // namespace otbr
1391