1 /*
2 * Copyright (c) 2020, 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 includes implementation for SRP server.
32 */
33
34 #include "srp_server.hpp"
35
36 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
37
38 #include "common/as_core_type.hpp"
39 #include "common/const_cast.hpp"
40 #include "common/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/log.hpp"
43 #include "common/new.hpp"
44 #include "common/num_utils.hpp"
45 #include "common/random.hpp"
46 #include "net/dns_types.hpp"
47 #include "thread/thread_netif.hpp"
48
49 namespace ot {
50 namespace Srp {
51
52 RegisterLogModule("SrpServer");
53
54 static const char kDefaultDomain[] = "default.service.arpa.";
55 static const char kServiceSubTypeLabel[] = "._sub.";
56
ErrorToDnsResponseCode(Error aError)57 static Dns::UpdateHeader::Response ErrorToDnsResponseCode(Error aError)
58 {
59 Dns::UpdateHeader::Response responseCode;
60
61 switch (aError)
62 {
63 case kErrorNone:
64 responseCode = Dns::UpdateHeader::kResponseSuccess;
65 break;
66 case kErrorNoBufs:
67 responseCode = Dns::UpdateHeader::kResponseServerFailure;
68 break;
69 case kErrorParse:
70 responseCode = Dns::UpdateHeader::kResponseFormatError;
71 break;
72 case kErrorDuplicated:
73 responseCode = Dns::UpdateHeader::kResponseNameExists;
74 break;
75 default:
76 responseCode = Dns::UpdateHeader::kResponseRefused;
77 break;
78 }
79
80 return responseCode;
81 }
82
83 //---------------------------------------------------------------------------------------------------------------------
84 // Server
85
Server(Instance & aInstance)86 Server::Server(Instance &aInstance)
87 : InstanceLocator(aInstance)
88 , mSocket(aInstance)
89 , mLeaseTimer(aInstance)
90 , mOutstandingUpdatesTimer(aInstance)
91 , mServiceUpdateId(Random::NonCrypto::GetUint32())
92 , mPort(kUdpPortMin)
93 , mState(kStateDisabled)
94 , mAddressMode(kDefaultAddressMode)
95 , mAnycastSequenceNumber(0)
96 , mHasRegisteredAnyService(false)
97 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
98 , mAutoEnable(false)
99 #endif
100 {
101 IgnoreError(SetDomain(kDefaultDomain));
102 }
103
SetAddressMode(AddressMode aMode)104 Error Server::SetAddressMode(AddressMode aMode)
105 {
106 Error error = kErrorNone;
107
108 VerifyOrExit(mState == kStateDisabled, error = kErrorInvalidState);
109 VerifyOrExit(mAddressMode != aMode);
110 LogInfo("Address Mode: %s -> %s", AddressModeToString(mAddressMode), AddressModeToString(aMode));
111 mAddressMode = aMode;
112
113 exit:
114 return error;
115 }
116
SetAnycastModeSequenceNumber(uint8_t aSequenceNumber)117 Error Server::SetAnycastModeSequenceNumber(uint8_t aSequenceNumber)
118 {
119 Error error = kErrorNone;
120
121 VerifyOrExit(mState == kStateDisabled, error = kErrorInvalidState);
122 mAnycastSequenceNumber = aSequenceNumber;
123
124 LogInfo("Set Anycast Address Mode Seq Number to %d", aSequenceNumber);
125
126 exit:
127 return error;
128 }
129
SetEnabled(bool aEnabled)130 void Server::SetEnabled(bool aEnabled)
131 {
132 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
133 mAutoEnable = false;
134 #endif
135
136 if (aEnabled)
137 {
138 Enable();
139 }
140 else
141 {
142 Disable();
143 }
144 }
145
Enable(void)146 void Server::Enable(void)
147 {
148 VerifyOrExit(mState == kStateDisabled);
149 mState = kStateStopped;
150
151 // Request publishing of "DNS/SRP Address Service" entry in the
152 // Thread Network Data based of `mAddressMode`. Then wait for
153 // callback `HandleNetDataPublisherEntryChange()` from the
154 // `Publisher` to start the SRP server.
155
156 switch (mAddressMode)
157 {
158 case kAddressModeUnicast:
159 SelectPort();
160 Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(mPort);
161 break;
162
163 case kAddressModeAnycast:
164 mPort = kAnycastAddressModePort;
165 Get<NetworkData::Publisher>().PublishDnsSrpServiceAnycast(mAnycastSequenceNumber);
166 break;
167 }
168
169 exit:
170 return;
171 }
172
Disable(void)173 void Server::Disable(void)
174 {
175 VerifyOrExit(mState != kStateDisabled);
176 Get<NetworkData::Publisher>().UnpublishDnsSrpService();
177 Stop();
178 mState = kStateDisabled;
179
180 exit:
181 return;
182 }
183
184 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
SetAutoEnableMode(bool aEnabled)185 void Server::SetAutoEnableMode(bool aEnabled)
186 {
187 VerifyOrExit(mAutoEnable != aEnabled);
188 mAutoEnable = aEnabled;
189
190 Get<BorderRouter::RoutingManager>().HandleSrpServerAutoEnableMode();
191
192 exit:
193 return;
194 }
195 #endif
196
TtlConfig(void)197 Server::TtlConfig::TtlConfig(void)
198 {
199 mMinTtl = kDefaultMinTtl;
200 mMaxTtl = kDefaultMaxTtl;
201 }
202
SetTtlConfig(const TtlConfig & aTtlConfig)203 Error Server::SetTtlConfig(const TtlConfig &aTtlConfig)
204 {
205 Error error = kErrorNone;
206
207 VerifyOrExit(aTtlConfig.IsValid(), error = kErrorInvalidArgs);
208 mTtlConfig = aTtlConfig;
209
210 exit:
211 return error;
212 }
213
GrantTtl(uint32_t aLease,uint32_t aTtl) const214 uint32_t Server::TtlConfig::GrantTtl(uint32_t aLease, uint32_t aTtl) const
215 {
216 OT_ASSERT(mMinTtl <= mMaxTtl);
217
218 return Clamp(Min(aTtl, aLease), mMinTtl, mMaxTtl);
219 }
220
LeaseConfig(void)221 Server::LeaseConfig::LeaseConfig(void)
222 {
223 mMinLease = kDefaultMinLease;
224 mMaxLease = kDefaultMaxLease;
225 mMinKeyLease = kDefaultMinKeyLease;
226 mMaxKeyLease = kDefaultMaxKeyLease;
227 }
228
IsValid(void) const229 bool Server::LeaseConfig::IsValid(void) const
230 {
231 bool valid = false;
232
233 // TODO: Support longer LEASE.
234 // We use milliseconds timer for LEASE & KEY-LEASE, this is to avoid overflow.
235 VerifyOrExit(mMaxKeyLease <= Time::MsecToSec(TimerMilli::kMaxDelay));
236 VerifyOrExit(mMinLease <= mMaxLease);
237 VerifyOrExit(mMinKeyLease <= mMaxKeyLease);
238 VerifyOrExit(mMinLease <= mMinKeyLease);
239 VerifyOrExit(mMaxLease <= mMaxKeyLease);
240
241 valid = true;
242
243 exit:
244 return valid;
245 }
246
GrantLease(uint32_t aLease) const247 uint32_t Server::LeaseConfig::GrantLease(uint32_t aLease) const
248 {
249 OT_ASSERT(mMinLease <= mMaxLease);
250
251 return (aLease == 0) ? 0 : Clamp(aLease, mMinLease, mMaxLease);
252 }
253
GrantKeyLease(uint32_t aKeyLease) const254 uint32_t Server::LeaseConfig::GrantKeyLease(uint32_t aKeyLease) const
255 {
256 OT_ASSERT(mMinKeyLease <= mMaxKeyLease);
257
258 return (aKeyLease == 0) ? 0 : Clamp(aKeyLease, mMinKeyLease, mMaxKeyLease);
259 }
260
SetLeaseConfig(const LeaseConfig & aLeaseConfig)261 Error Server::SetLeaseConfig(const LeaseConfig &aLeaseConfig)
262 {
263 Error error = kErrorNone;
264
265 VerifyOrExit(aLeaseConfig.IsValid(), error = kErrorInvalidArgs);
266 mLeaseConfig = aLeaseConfig;
267
268 exit:
269 return error;
270 }
271
SetDomain(const char * aDomain)272 Error Server::SetDomain(const char *aDomain)
273 {
274 Error error = kErrorNone;
275 uint16_t length;
276
277 VerifyOrExit(mState == kStateDisabled, error = kErrorInvalidState);
278
279 length = StringLength(aDomain, Dns::Name::kMaxNameSize);
280 VerifyOrExit((length > 0) && (length < Dns::Name::kMaxNameSize), error = kErrorInvalidArgs);
281
282 if (aDomain[length - 1] == '.')
283 {
284 error = mDomain.Set(aDomain);
285 }
286 else
287 {
288 // Need to append dot at the end
289
290 char buf[Dns::Name::kMaxNameSize];
291
292 VerifyOrExit(length < Dns::Name::kMaxNameSize - 1, error = kErrorInvalidArgs);
293
294 memcpy(buf, aDomain, length);
295 buf[length] = '.';
296 buf[length + 1] = '\0';
297
298 error = mDomain.Set(buf);
299 }
300
301 exit:
302 return error;
303 }
304
GetNextHost(const Server::Host * aHost)305 const Server::Host *Server::GetNextHost(const Server::Host *aHost)
306 {
307 return (aHost == nullptr) ? mHosts.GetHead() : aHost->GetNext();
308 }
309
310 // This method adds a SRP service host and takes ownership of it.
311 // The caller MUST make sure that there is no existing host with the same hostname.
AddHost(Host & aHost)312 void Server::AddHost(Host &aHost)
313 {
314 LogInfo("Add new host %s", aHost.GetFullName());
315
316 OT_ASSERT(mHosts.FindMatching(aHost.GetFullName()) == nullptr);
317 IgnoreError(mHosts.Add(aHost));
318 }
RemoveHost(Host * aHost,RetainName aRetainName,NotifyMode aNotifyServiceHandler)319 void Server::RemoveHost(Host *aHost, RetainName aRetainName, NotifyMode aNotifyServiceHandler)
320 {
321 VerifyOrExit(aHost != nullptr);
322
323 aHost->mLease = 0;
324 aHost->ClearResources();
325
326 if (aRetainName)
327 {
328 LogInfo("Remove host %s (but retain its name)", aHost->GetFullName());
329 }
330 else
331 {
332 aHost->mKeyLease = 0;
333 IgnoreError(mHosts.Remove(*aHost));
334 LogInfo("Fully remove host %s", aHost->GetFullName());
335 }
336
337 if (aNotifyServiceHandler && mServiceUpdateHandler.IsSet())
338 {
339 uint32_t updateId = AllocateId();
340
341 LogInfo("SRP update handler is notified (updatedId = %lu)", ToUlong(updateId));
342 mServiceUpdateHandler.Invoke(updateId, aHost, static_cast<uint32_t>(kDefaultEventsHandlerTimeout));
343 // We don't wait for the reply from the service update handler,
344 // but always remove the host (and its services) regardless of
345 // host/service update result. Because removing a host should fail
346 // only when there is system failure of the platform mDNS implementation
347 // and in which case the host is not expected to be still registered.
348 }
349
350 if (!aRetainName)
351 {
352 aHost->Free();
353 }
354
355 exit:
356 return;
357 }
358
HasNameConflictsWith(Host & aHost) const359 bool Server::HasNameConflictsWith(Host &aHost) const
360 {
361 bool hasConflicts = false;
362 const Host *existingHost = mHosts.FindMatching(aHost.GetFullName());
363
364 if (existingHost != nullptr && aHost.GetKeyRecord()->GetKey() != existingHost->GetKeyRecord()->GetKey())
365 {
366 LogWarn("Name conflict: host name %s has already been allocated", aHost.GetFullName());
367 ExitNow(hasConflicts = true);
368 }
369
370 for (const Service &service : aHost.mServices)
371 {
372 // Check on all hosts for a matching service with the same
373 // instance name and if found, verify that it has the same
374 // key.
375
376 for (const Host &host : mHosts)
377 {
378 if (host.HasServiceInstance(service.GetInstanceName()) &&
379 aHost.GetKeyRecord()->GetKey() != host.GetKeyRecord()->GetKey())
380 {
381 LogWarn("Name conflict: service name %s has already been allocated", service.GetInstanceName());
382 ExitNow(hasConflicts = true);
383 }
384 }
385 }
386
387 exit:
388 return hasConflicts;
389 }
390
HandleServiceUpdateResult(ServiceUpdateId aId,Error aError)391 void Server::HandleServiceUpdateResult(ServiceUpdateId aId, Error aError)
392 {
393 UpdateMetadata *update = mOutstandingUpdates.FindMatching(aId);
394
395 if (update != nullptr)
396 {
397 HandleServiceUpdateResult(update, aError);
398 }
399 else
400 {
401 LogInfo("Delayed SRP host update result, the SRP update has been committed (updateId = %lu)", ToUlong(aId));
402 }
403 }
404
HandleServiceUpdateResult(UpdateMetadata * aUpdate,Error aError)405 void Server::HandleServiceUpdateResult(UpdateMetadata *aUpdate, Error aError)
406 {
407 LogInfo("Handler result of SRP update (id = %lu) is received: %s", ToUlong(aUpdate->GetId()),
408 ErrorToString(aError));
409
410 IgnoreError(mOutstandingUpdates.Remove(*aUpdate));
411 CommitSrpUpdate(aError, *aUpdate);
412 aUpdate->Free();
413
414 if (mOutstandingUpdates.IsEmpty())
415 {
416 mOutstandingUpdatesTimer.Stop();
417 }
418 else
419 {
420 mOutstandingUpdatesTimer.FireAt(mOutstandingUpdates.GetTail()->GetExpireTime());
421 }
422 }
423
CommitSrpUpdate(Error aError,Host & aHost,const MessageMetadata & aMessageMetadata)424 void Server::CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &aMessageMetadata)
425 {
426 CommitSrpUpdate(aError, aHost, aMessageMetadata.mDnsHeader, aMessageMetadata.mMessageInfo,
427 aMessageMetadata.mTtlConfig, aMessageMetadata.mLeaseConfig);
428 }
429
CommitSrpUpdate(Error aError,UpdateMetadata & aUpdateMetadata)430 void Server::CommitSrpUpdate(Error aError, UpdateMetadata &aUpdateMetadata)
431 {
432 CommitSrpUpdate(aError, aUpdateMetadata.GetHost(), aUpdateMetadata.GetDnsHeader(),
433 aUpdateMetadata.IsDirectRxFromClient() ? &aUpdateMetadata.GetMessageInfo() : nullptr,
434 aUpdateMetadata.GetTtlConfig(), aUpdateMetadata.GetLeaseConfig());
435 }
436
CommitSrpUpdate(Error aError,Host & aHost,const Dns::UpdateHeader & aDnsHeader,const Ip6::MessageInfo * aMessageInfo,const TtlConfig & aTtlConfig,const LeaseConfig & aLeaseConfig)437 void Server::CommitSrpUpdate(Error aError,
438 Host &aHost,
439 const Dns::UpdateHeader &aDnsHeader,
440 const Ip6::MessageInfo *aMessageInfo,
441 const TtlConfig &aTtlConfig,
442 const LeaseConfig &aLeaseConfig)
443 {
444 Host *existingHost;
445 uint32_t grantedTtl;
446 uint32_t hostLease = 0;
447 uint32_t hostKeyLease = 0;
448 uint32_t grantedLease = 0;
449 uint32_t grantedKeyLease = 0;
450 bool shouldFreeHost = true;
451
452 SuccessOrExit(aError);
453
454 hostLease = aHost.GetLease();
455 hostKeyLease = aHost.GetKeyLease();
456 grantedLease = aLeaseConfig.GrantLease(hostLease);
457 grantedKeyLease = aHost.ShouldUseShortLeaseOption() ? grantedLease : aLeaseConfig.GrantKeyLease(hostKeyLease);
458 grantedTtl = aTtlConfig.GrantTtl(grantedLease, aHost.GetTtl());
459
460 aHost.SetLease(grantedLease);
461 aHost.SetKeyLease(grantedKeyLease);
462 aHost.SetTtl(grantedTtl);
463
464 for (Service &service : aHost.mServices)
465 {
466 service.mDescription->mLease = grantedLease;
467 service.mDescription->mKeyLease = grantedKeyLease;
468 service.mDescription->mTtl = grantedTtl;
469 }
470
471 existingHost = mHosts.FindMatching(aHost.GetFullName());
472
473 if (aHost.GetLease() == 0)
474 {
475 if (aHost.GetKeyLease() == 0)
476 {
477 LogInfo("Remove key of host %s", aHost.GetFullName());
478 RemoveHost(existingHost, kDeleteName, kDoNotNotifyServiceHandler);
479 }
480 else if (existingHost != nullptr)
481 {
482 existingHost->SetKeyLease(aHost.GetKeyLease());
483 RemoveHost(existingHost, kRetainName, kDoNotNotifyServiceHandler);
484
485 for (Service &service : existingHost->mServices)
486 {
487 existingHost->RemoveService(&service, kRetainName, kDoNotNotifyServiceHandler);
488 }
489 }
490 }
491 else if (existingHost != nullptr)
492 {
493 SuccessOrExit(aError = existingHost->MergeServicesAndResourcesFrom(aHost));
494 }
495 else
496 {
497 AddHost(aHost);
498 shouldFreeHost = false;
499
500 for (Service &service : aHost.GetServices())
501 {
502 service.mIsCommitted = true;
503 service.Log(Service::kAddNew);
504 }
505
506 #if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
507 if (!mHasRegisteredAnyService && (mAddressMode == kAddressModeUnicast))
508 {
509 Settings::SrpServerInfo info;
510
511 mHasRegisteredAnyService = true;
512 info.SetPort(GetSocket().mSockName.mPort);
513 IgnoreError(Get<Settings>().Save(info));
514 }
515 #endif
516 }
517
518 // Re-schedule the lease timer.
519 HandleLeaseTimer();
520
521 exit:
522 if (aMessageInfo != nullptr)
523 {
524 if (aError == kErrorNone && !(grantedLease == hostLease && grantedKeyLease == hostKeyLease))
525 {
526 SendResponse(aDnsHeader, grantedLease, grantedKeyLease, aHost.ShouldUseShortLeaseOption(), *aMessageInfo);
527 }
528 else
529 {
530 SendResponse(aDnsHeader, ErrorToDnsResponseCode(aError), *aMessageInfo);
531 }
532 }
533
534 if (shouldFreeHost)
535 {
536 aHost.Free();
537 }
538 }
539
SelectPort(void)540 void Server::SelectPort(void)
541 {
542 mPort = kUdpPortMin;
543
544 #if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
545 {
546 Settings::SrpServerInfo info;
547
548 if (Get<Settings>().Read(info) == kErrorNone)
549 {
550 mPort = info.GetPort() + 1;
551 if (mPort < kUdpPortMin || mPort > kUdpPortMax)
552 {
553 mPort = kUdpPortMin;
554 }
555 }
556 }
557 #endif
558
559 LogInfo("Selected port %u", mPort);
560 }
561
Start(void)562 void Server::Start(void)
563 {
564 VerifyOrExit(mState == kStateStopped);
565
566 mState = kStateRunning;
567 PrepareSocket();
568 LogInfo("Start listening on port %u", mPort);
569
570 exit:
571 return;
572 }
573
PrepareSocket(void)574 void Server::PrepareSocket(void)
575 {
576 Error error = kErrorNone;
577
578 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
579 Ip6::Udp::Socket &dnsSocket = Get<Dns::ServiceDiscovery::Server>().mSocket;
580
581 if (dnsSocket.GetSockName().GetPort() == mPort)
582 {
583 // If the DNS-SD socket matches our port number, we use the
584 // same socket so we close our own socket (in case it was
585 // open). `GetSocket()` will now return the DNS-SD socket.
586
587 IgnoreError(mSocket.Close());
588 ExitNow();
589 }
590 #endif
591
592 VerifyOrExit(!mSocket.IsOpen());
593 SuccessOrExit(error = mSocket.Open(HandleUdpReceive, this));
594 error = mSocket.Bind(mPort, Ip6::kNetifThread);
595
596 exit:
597 if (error != kErrorNone)
598 {
599 LogCrit("Failed to prepare socket: %s", ErrorToString(error));
600 Stop();
601 }
602 }
603
GetSocket(void)604 Ip6::Udp::Socket &Server::GetSocket(void)
605 {
606 Ip6::Udp::Socket *socket = &mSocket;
607
608 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
609 Ip6::Udp::Socket &dnsSocket = Get<Dns::ServiceDiscovery::Server>().mSocket;
610
611 if (dnsSocket.GetSockName().GetPort() == mPort)
612 {
613 socket = &dnsSocket;
614 }
615 #endif
616
617 return *socket;
618 }
619
620 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
621
HandleDnssdServerStateChange(void)622 void Server::HandleDnssdServerStateChange(void)
623 {
624 // This is called from` Dns::ServiceDiscovery::Server` to notify
625 // that it has started or stopped. We check whether we need to
626 // share the socket.
627
628 if (mState == kStateRunning)
629 {
630 PrepareSocket();
631 }
632 }
633
HandleDnssdServerUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)634 Error Server::HandleDnssdServerUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
635 {
636 // This is called from` Dns::ServiceDiscovery::Server` when a UDP
637 // message is received on its socket. We check whether we are
638 // sharing socket and if so we process the received message. We
639 // return `kErrorNone` to indicate that message was successfully
640 // processed by `Srp::Server`, otherwise `kErrorDrop` is returned.
641
642 Error error = kErrorDrop;
643
644 VerifyOrExit((mState == kStateRunning) && !mSocket.IsOpen());
645
646 error = ProcessMessage(aMessage, aMessageInfo);
647
648 exit:
649 return error;
650 }
651
652 #endif // OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
653
Stop(void)654 void Server::Stop(void)
655 {
656 VerifyOrExit(mState == kStateRunning);
657
658 mState = kStateStopped;
659
660 while (!mHosts.IsEmpty())
661 {
662 RemoveHost(mHosts.GetHead(), kDeleteName, kNotifyServiceHandler);
663 }
664
665 // TODO: We should cancel any outstanding service updates, but current
666 // OTBR mDNS publisher cannot properly handle it.
667 while (!mOutstandingUpdates.IsEmpty())
668 {
669 mOutstandingUpdates.Pop()->Free();
670 }
671
672 mLeaseTimer.Stop();
673 mOutstandingUpdatesTimer.Stop();
674
675 LogInfo("Stop listening on %u", mPort);
676 IgnoreError(mSocket.Close());
677 mHasRegisteredAnyService = false;
678
679 exit:
680 return;
681 }
682
HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent)683 void Server::HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent)
684 {
685 switch (aEvent)
686 {
687 case NetworkData::Publisher::kEventEntryAdded:
688 Start();
689 break;
690
691 case NetworkData::Publisher::kEventEntryRemoved:
692 Stop();
693 break;
694 }
695 }
696
FindOutstandingUpdate(const MessageMetadata & aMessageMetadata) const697 const Server::UpdateMetadata *Server::FindOutstandingUpdate(const MessageMetadata &aMessageMetadata) const
698 {
699 const UpdateMetadata *ret = nullptr;
700
701 VerifyOrExit(aMessageMetadata.IsDirectRxFromClient());
702
703 for (const UpdateMetadata &update : mOutstandingUpdates)
704 {
705 if (aMessageMetadata.mDnsHeader.GetMessageId() == update.GetDnsHeader().GetMessageId() &&
706 aMessageMetadata.mMessageInfo->GetPeerAddr() == update.GetMessageInfo().GetPeerAddr() &&
707 aMessageMetadata.mMessageInfo->GetPeerPort() == update.GetMessageInfo().GetPeerPort())
708 {
709 ExitNow(ret = &update);
710 }
711 }
712
713 exit:
714 return ret;
715 }
716
ProcessDnsUpdate(Message & aMessage,MessageMetadata & aMetadata)717 void Server::ProcessDnsUpdate(Message &aMessage, MessageMetadata &aMetadata)
718 {
719 Error error = kErrorNone;
720 Host *host = nullptr;
721
722 LogInfo("Received DNS update from %s", aMetadata.IsDirectRxFromClient()
723 ? aMetadata.mMessageInfo->GetPeerAddr().ToString().AsCString()
724 : "an SRPL Partner");
725
726 SuccessOrExit(error = ProcessZoneSection(aMessage, aMetadata));
727
728 if (FindOutstandingUpdate(aMetadata) != nullptr)
729 {
730 LogInfo("Drop duplicated SRP update request: MessageId=%u", aMetadata.mDnsHeader.GetMessageId());
731
732 // Silently drop duplicate requests.
733 // This could rarely happen, because the outstanding SRP update timer should
734 // be shorter than the SRP update retransmission timer.
735 ExitNow(error = kErrorNone);
736 }
737
738 // Per 2.3.2 of SRP draft 6, no prerequisites should be included in a SRP update.
739 VerifyOrExit(aMetadata.mDnsHeader.GetPrerequisiteRecordCount() == 0, error = kErrorFailed);
740
741 host = Host::Allocate(GetInstance(), aMetadata.mRxTime);
742 VerifyOrExit(host != nullptr, error = kErrorNoBufs);
743 SuccessOrExit(error = ProcessUpdateSection(*host, aMessage, aMetadata));
744
745 // Parse lease time and validate signature.
746 SuccessOrExit(error = ProcessAdditionalSection(host, aMessage, aMetadata));
747
748 SuccessOrExit(error = ValidateServiceSubTypes(*host, aMetadata));
749
750 HandleUpdate(*host, aMetadata);
751
752 exit:
753 if (error != kErrorNone)
754 {
755 if (host != nullptr)
756 {
757 host->Free();
758 }
759
760 if (aMetadata.IsDirectRxFromClient())
761 {
762 SendResponse(aMetadata.mDnsHeader, ErrorToDnsResponseCode(error), *aMetadata.mMessageInfo);
763 }
764 }
765 }
766
ProcessZoneSection(const Message & aMessage,MessageMetadata & aMetadata) const767 Error Server::ProcessZoneSection(const Message &aMessage, MessageMetadata &aMetadata) const
768 {
769 Error error = kErrorNone;
770 char name[Dns::Name::kMaxNameSize];
771 uint16_t offset = aMetadata.mOffset;
772
773 VerifyOrExit(aMetadata.mDnsHeader.GetZoneRecordCount() == 1, error = kErrorParse);
774
775 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name)));
776 // TODO: return `Dns::kResponseNotAuth` for not authorized zone names.
777 VerifyOrExit(StringMatch(name, GetDomain(), kStringCaseInsensitiveMatch), error = kErrorSecurity);
778 SuccessOrExit(error = aMessage.Read(offset, aMetadata.mDnsZone));
779 offset += sizeof(Dns::Zone);
780
781 VerifyOrExit(aMetadata.mDnsZone.GetType() == Dns::ResourceRecord::kTypeSoa, error = kErrorParse);
782 aMetadata.mOffset = offset;
783
784 exit:
785 if (error != kErrorNone)
786 {
787 LogWarn("Failed to process DNS Zone section: %s", ErrorToString(error));
788 }
789
790 return error;
791 }
792
ProcessUpdateSection(Host & aHost,const Message & aMessage,MessageMetadata & aMetadata) const793 Error Server::ProcessUpdateSection(Host &aHost, const Message &aMessage, MessageMetadata &aMetadata) const
794 {
795 Error error = kErrorNone;
796
797 // Process Service Discovery, Host and Service Description Instructions with
798 // 3 times iterations over all DNS update RRs. The order of those processes matters.
799
800 // 0. Enumerate over all Service Discovery Instructions before processing any other records.
801 // So that we will know whether a name is a hostname or service instance name when processing
802 // a "Delete All RRsets from a name" record.
803 SuccessOrExit(error = ProcessServiceDiscoveryInstructions(aHost, aMessage, aMetadata));
804
805 // 1. Enumerate over all RRs to build the Host Description Instruction.
806 SuccessOrExit(error = ProcessHostDescriptionInstruction(aHost, aMessage, aMetadata));
807
808 // 2. Enumerate over all RRs to build the Service Description Instructions.
809 SuccessOrExit(error = ProcessServiceDescriptionInstructions(aHost, aMessage, aMetadata));
810
811 // 3. Verify that there are no name conflicts.
812 VerifyOrExit(!HasNameConflictsWith(aHost), error = kErrorDuplicated);
813
814 exit:
815 if (error != kErrorNone)
816 {
817 LogWarn("Failed to process DNS Update section: %s", ErrorToString(error));
818 }
819
820 return error;
821 }
822
ProcessHostDescriptionInstruction(Host & aHost,const Message & aMessage,const MessageMetadata & aMetadata) const823 Error Server::ProcessHostDescriptionInstruction(Host &aHost,
824 const Message &aMessage,
825 const MessageMetadata &aMetadata) const
826 {
827 Error error = kErrorNone;
828 uint16_t offset = aMetadata.mOffset;
829
830 OT_ASSERT(aHost.GetFullName() == nullptr);
831
832 for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
833 {
834 char name[Dns::Name::kMaxNameSize];
835 Dns::ResourceRecord record;
836
837 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name)));
838
839 SuccessOrExit(error = aMessage.Read(offset, record));
840
841 if (record.GetClass() == Dns::ResourceRecord::kClassAny)
842 {
843 // Delete All RRsets from a name.
844 VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed);
845
846 // A "Delete All RRsets from a name" RR can only apply to a Service or Host Description.
847
848 if (!aHost.HasServiceInstance(name))
849 {
850 // If host name is already set to a different name, `SetFullName()`
851 // will return `kErrorFailed`.
852 SuccessOrExit(error = aHost.SetFullName(name));
853 aHost.ClearResources();
854 }
855 }
856 else if (record.GetType() == Dns::ResourceRecord::kTypeAaaa)
857 {
858 Dns::AaaaRecord aaaaRecord;
859
860 VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
861
862 SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
863
864 SuccessOrExit(error = aHost.SetFullName(name));
865
866 SuccessOrExit(error = aMessage.Read(offset, aaaaRecord));
867 VerifyOrExit(aaaaRecord.IsValid(), error = kErrorParse);
868
869 // Tolerate kErrorDrop for AAAA Resources.
870 VerifyOrExit(aHost.AddIp6Address(aaaaRecord.GetAddress()) != kErrorNoBufs, error = kErrorNoBufs);
871 }
872 else if (record.GetType() == Dns::ResourceRecord::kTypeKey)
873 {
874 // We currently support only ECDSA P-256.
875 Dns::Ecdsa256KeyRecord keyRecord;
876
877 VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
878
879 SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
880
881 SuccessOrExit(error = aMessage.Read(offset, keyRecord));
882 VerifyOrExit(keyRecord.IsValid(), error = kErrorParse);
883
884 VerifyOrExit(aHost.GetKeyRecord() == nullptr || *aHost.GetKeyRecord() == keyRecord, error = kErrorSecurity);
885 aHost.SetKeyRecord(keyRecord);
886 }
887
888 offset += record.GetSize();
889 }
890
891 // Verify that we have a complete Host Description Instruction.
892
893 VerifyOrExit(aHost.GetFullName() != nullptr, error = kErrorFailed);
894 VerifyOrExit(aHost.GetKeyRecord() != nullptr, error = kErrorFailed);
895
896 // We check the number of host addresses after processing of the
897 // Lease Option in the Addition Section and determining whether
898 // the host is being removed or registered.
899
900 exit:
901 if (error != kErrorNone)
902 {
903 LogWarn("Failed to process Host Description instructions: %s", ErrorToString(error));
904 }
905
906 return error;
907 }
908
ProcessServiceDiscoveryInstructions(Host & aHost,const Message & aMessage,const MessageMetadata & aMetadata) const909 Error Server::ProcessServiceDiscoveryInstructions(Host &aHost,
910 const Message &aMessage,
911 const MessageMetadata &aMetadata) const
912 {
913 Error error = kErrorNone;
914 uint16_t offset = aMetadata.mOffset;
915
916 for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
917 {
918 char serviceName[Dns::Name::kMaxNameSize];
919 char instanceName[Dns::Name::kMaxNameSize];
920 Dns::PtrRecord ptrRecord;
921 const char *subServiceName;
922 Service *service;
923 bool isSubType;
924
925 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, serviceName, sizeof(serviceName)));
926 VerifyOrExit(Dns::Name::IsSubDomainOf(serviceName, GetDomain()), error = kErrorSecurity);
927
928 error = Dns::ResourceRecord::ReadRecord(aMessage, offset, ptrRecord);
929
930 if (error == kErrorNotFound)
931 {
932 // `ReadRecord()` updates `aOffset` to skip over a
933 // non-matching record.
934 error = kErrorNone;
935 continue;
936 }
937
938 SuccessOrExit(error);
939
940 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, instanceName, sizeof(instanceName)));
941
942 VerifyOrExit(ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone ||
943 ptrRecord.GetClass() == aMetadata.mDnsZone.GetClass(),
944 error = kErrorFailed);
945
946 // Check if the `serviceName` is a subtype with the name
947 // format: "<sub-label>._sub.<service-labels>.<domain>."
948
949 subServiceName = StringFind(serviceName, kServiceSubTypeLabel, kStringCaseInsensitiveMatch);
950 isSubType = (subServiceName != nullptr);
951
952 if (isSubType)
953 {
954 // Skip over the "._sub." label to get to the base
955 // service name.
956 subServiceName += sizeof(kServiceSubTypeLabel) - 1;
957 }
958
959 // Verify that instance name and service name are related.
960 VerifyOrExit(Dns::Name::IsSubDomainOf(instanceName, isSubType ? subServiceName : serviceName),
961 error = kErrorFailed);
962
963 // Ensure the same service does not exist already.
964 VerifyOrExit(aHost.FindService(serviceName, instanceName) == nullptr, error = kErrorFailed);
965
966 service = aHost.AddNewService(serviceName, instanceName, isSubType, aMetadata.mRxTime);
967 VerifyOrExit(service != nullptr, error = kErrorNoBufs);
968
969 // This RR is a "Delete an RR from an RRset" update when the CLASS is NONE.
970 service->mIsDeleted = (ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone);
971
972 if (!service->mIsDeleted)
973 {
974 SuccessOrExit(error = aHost.ProcessTtl(ptrRecord.GetTtl()));
975 }
976 }
977
978 exit:
979 if (error != kErrorNone)
980 {
981 LogWarn("Failed to process Service Discovery instructions: %s", ErrorToString(error));
982 }
983
984 return error;
985 }
986
ProcessServiceDescriptionInstructions(Host & aHost,const Message & aMessage,MessageMetadata & aMetadata) const987 Error Server::ProcessServiceDescriptionInstructions(Host &aHost,
988 const Message &aMessage,
989 MessageMetadata &aMetadata) const
990 {
991 Error error = kErrorNone;
992 uint16_t offset = aMetadata.mOffset;
993
994 for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
995 {
996 RetainPtr<Service::Description> desc;
997 char name[Dns::Name::kMaxNameSize];
998 Dns::ResourceRecord record;
999
1000 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name)));
1001 SuccessOrExit(error = aMessage.Read(offset, record));
1002
1003 if (record.GetClass() == Dns::ResourceRecord::kClassAny)
1004 {
1005 // Delete All RRsets from a name.
1006 VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed);
1007
1008 desc = aHost.FindServiceDescription(name);
1009
1010 if (desc != nullptr)
1011 {
1012 desc->ClearResources();
1013 desc->mUpdateTime = aMetadata.mRxTime;
1014 }
1015
1016 offset += record.GetSize();
1017 continue;
1018 }
1019
1020 if (record.GetType() == Dns::ResourceRecord::kTypeSrv)
1021 {
1022 Dns::SrvRecord srvRecord;
1023 char hostName[Dns::Name::kMaxNameSize];
1024 uint16_t hostNameLength = sizeof(hostName);
1025
1026 VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
1027
1028 SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
1029
1030 SuccessOrExit(error = aMessage.Read(offset, srvRecord));
1031 offset += sizeof(srvRecord);
1032
1033 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, hostName, hostNameLength));
1034 VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = kErrorSecurity);
1035 VerifyOrExit(aHost.Matches(hostName), error = kErrorFailed);
1036
1037 desc = aHost.FindServiceDescription(name);
1038 VerifyOrExit(desc != nullptr, error = kErrorFailed);
1039
1040 // Make sure that this is the first SRV RR for this service description
1041 VerifyOrExit(desc->mPort == 0, error = kErrorFailed);
1042 desc->mTtl = srvRecord.GetTtl();
1043 desc->mPriority = srvRecord.GetPriority();
1044 desc->mWeight = srvRecord.GetWeight();
1045 desc->mPort = srvRecord.GetPort();
1046 desc->mUpdateTime = aMetadata.mRxTime;
1047 }
1048 else if (record.GetType() == Dns::ResourceRecord::kTypeTxt)
1049 {
1050 VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
1051
1052 SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
1053
1054 desc = aHost.FindServiceDescription(name);
1055 VerifyOrExit(desc != nullptr, error = kErrorFailed);
1056
1057 offset += sizeof(record);
1058 SuccessOrExit(error = desc->SetTxtDataFromMessage(aMessage, offset, record.GetLength()));
1059 offset += record.GetLength();
1060 }
1061 else
1062 {
1063 offset += record.GetSize();
1064 }
1065 }
1066
1067 // Verify that all service descriptions on `aHost` are updated. Note
1068 // that `mUpdateTime` on a new `Service::Description` is set to
1069 // `GetNow().GetDistantPast()`.
1070
1071 for (Service &service : aHost.mServices)
1072 {
1073 VerifyOrExit(service.mDescription->mUpdateTime == aMetadata.mRxTime, error = kErrorFailed);
1074
1075 // Check that either both `mPort` and `mTxtData` are set
1076 // (i.e., we saw both SRV and TXT record) or both are default
1077 // (cleared) value (i.e., we saw neither of them).
1078
1079 VerifyOrExit((service.mDescription->mPort == 0) == service.mDescription->mTxtData.IsNull(),
1080 error = kErrorFailed);
1081 }
1082
1083 aMetadata.mOffset = offset;
1084
1085 exit:
1086 if (error != kErrorNone)
1087 {
1088 LogWarn("Failed to process Service Description instructions: %s", ErrorToString(error));
1089 }
1090
1091 return error;
1092 }
1093
IsValidDeleteAllRecord(const Dns::ResourceRecord & aRecord)1094 bool Server::IsValidDeleteAllRecord(const Dns::ResourceRecord &aRecord)
1095 {
1096 return aRecord.GetClass() == Dns::ResourceRecord::kClassAny && aRecord.GetType() == Dns::ResourceRecord::kTypeAny &&
1097 aRecord.GetTtl() == 0 && aRecord.GetLength() == 0;
1098 }
1099
ProcessAdditionalSection(Host * aHost,const Message & aMessage,MessageMetadata & aMetadata) const1100 Error Server::ProcessAdditionalSection(Host *aHost, const Message &aMessage, MessageMetadata &aMetadata) const
1101 {
1102 Error error = kErrorNone;
1103 Dns::OptRecord optRecord;
1104 Dns::LeaseOption leaseOption;
1105 Dns::SigRecord sigRecord;
1106 char name[2]; // The root domain name (".") is expected.
1107 uint16_t offset = aMetadata.mOffset;
1108 uint16_t sigOffset;
1109 uint16_t sigRdataOffset;
1110 char signerName[Dns::Name::kMaxNameSize];
1111 uint16_t signatureLength;
1112
1113 VerifyOrExit(aMetadata.mDnsHeader.GetAdditionalRecordCount() == 2, error = kErrorFailed);
1114
1115 // EDNS(0) Update Lease Option.
1116
1117 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name)));
1118 SuccessOrExit(error = aMessage.Read(offset, optRecord));
1119
1120 SuccessOrExit(error = leaseOption.ReadFrom(aMessage, offset + sizeof(optRecord), optRecord.GetLength()));
1121
1122 offset += optRecord.GetSize();
1123
1124 aHost->SetLease(leaseOption.GetLeaseInterval());
1125 aHost->SetKeyLease(leaseOption.GetKeyLeaseInterval());
1126
1127 // If the client included the short variant of Lease Option,
1128 // server must also use the short variant in its response.
1129 aHost->SetUseShortLeaseOption(leaseOption.IsShortVariant());
1130
1131 if (aHost->GetLease() > 0)
1132 {
1133 uint8_t hostAddressesNum;
1134
1135 aHost->GetAddresses(hostAddressesNum);
1136
1137 // There MUST be at least one valid address if we have nonzero lease.
1138 VerifyOrExit(hostAddressesNum > 0, error = kErrorFailed);
1139 }
1140
1141 // SIG(0).
1142
1143 sigOffset = offset;
1144 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name)));
1145 SuccessOrExit(error = aMessage.Read(offset, sigRecord));
1146 VerifyOrExit(sigRecord.IsValid(), error = kErrorParse);
1147
1148 sigRdataOffset = offset + sizeof(Dns::ResourceRecord);
1149 offset += sizeof(sigRecord);
1150
1151 // TODO: Verify that the signature doesn't expire. This is not
1152 // implemented because the end device may not be able to get
1153 // the synchronized date/time.
1154
1155 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, signerName, sizeof(signerName)));
1156
1157 signatureLength = sigRecord.GetLength() - (offset - sigRdataOffset);
1158 offset += signatureLength;
1159
1160 // Verify the signature. Currently supports only ECDSA.
1161
1162 VerifyOrExit(sigRecord.GetAlgorithm() == Dns::KeyRecord::kAlgorithmEcdsaP256Sha256, error = kErrorFailed);
1163 VerifyOrExit(sigRecord.GetTypeCovered() == 0, error = kErrorFailed);
1164 VerifyOrExit(signatureLength == Crypto::Ecdsa::P256::Signature::kSize, error = kErrorParse);
1165
1166 SuccessOrExit(error = VerifySignature(*aHost->GetKeyRecord(), aMessage, aMetadata.mDnsHeader, sigOffset,
1167 sigRdataOffset, sigRecord.GetLength(), signerName));
1168
1169 aMetadata.mOffset = offset;
1170
1171 exit:
1172 if (error != kErrorNone)
1173 {
1174 LogWarn("Failed to process DNS Additional section: %s", ErrorToString(error));
1175 }
1176
1177 return error;
1178 }
1179
VerifySignature(const Dns::Ecdsa256KeyRecord & aKeyRecord,const Message & aMessage,Dns::UpdateHeader aDnsHeader,uint16_t aSigOffset,uint16_t aSigRdataOffset,uint16_t aSigRdataLength,const char * aSignerName) const1180 Error Server::VerifySignature(const Dns::Ecdsa256KeyRecord &aKeyRecord,
1181 const Message &aMessage,
1182 Dns::UpdateHeader aDnsHeader,
1183 uint16_t aSigOffset,
1184 uint16_t aSigRdataOffset,
1185 uint16_t aSigRdataLength,
1186 const char *aSignerName) const
1187 {
1188 Error error;
1189 uint16_t offset = aMessage.GetOffset();
1190 uint16_t signatureOffset;
1191 Crypto::Sha256 sha256;
1192 Crypto::Sha256::Hash hash;
1193 Crypto::Ecdsa::P256::Signature signature;
1194 Message *signerNameMessage = nullptr;
1195
1196 VerifyOrExit(aSigRdataLength >= Crypto::Ecdsa::P256::Signature::kSize, error = kErrorInvalidArgs);
1197
1198 sha256.Start();
1199
1200 // SIG RDATA less signature.
1201 sha256.Update(aMessage, aSigRdataOffset, sizeof(Dns::SigRecord) - sizeof(Dns::ResourceRecord));
1202
1203 // The uncompressed (canonical) form of the signer name should be used for signature
1204 // verification. See https://tools.ietf.org/html/rfc2931#section-3.1 for details.
1205 signerNameMessage = Get<Ip6::Udp>().NewMessage();
1206 VerifyOrExit(signerNameMessage != nullptr, error = kErrorNoBufs);
1207 SuccessOrExit(error = Dns::Name::AppendName(aSignerName, *signerNameMessage));
1208 sha256.Update(*signerNameMessage, signerNameMessage->GetOffset(), signerNameMessage->GetLength());
1209
1210 // We need the DNS header before appending the SIG RR.
1211 aDnsHeader.SetAdditionalRecordCount(aDnsHeader.GetAdditionalRecordCount() - 1);
1212 sha256.Update(aDnsHeader);
1213 sha256.Update(aMessage, offset + sizeof(aDnsHeader), aSigOffset - offset - sizeof(aDnsHeader));
1214
1215 sha256.Finish(hash);
1216
1217 signatureOffset = aSigRdataOffset + aSigRdataLength - Crypto::Ecdsa::P256::Signature::kSize;
1218 SuccessOrExit(error = aMessage.Read(signatureOffset, signature));
1219
1220 error = aKeyRecord.GetKey().Verify(hash, signature);
1221
1222 exit:
1223 if (error != kErrorNone)
1224 {
1225 LogWarn("Failed to verify message signature: %s", ErrorToString(error));
1226 }
1227
1228 FreeMessage(signerNameMessage);
1229 return error;
1230 }
1231
ValidateServiceSubTypes(Host & aHost,const MessageMetadata & aMetadata)1232 Error Server::ValidateServiceSubTypes(Host &aHost, const MessageMetadata &aMetadata)
1233 {
1234 Error error = kErrorNone;
1235 Host *existingHost;
1236
1237 // Verify that there is a matching base type service for all
1238 // sub-type services in `aHost` (which is from the received
1239 // and parsed SRP Update message).
1240
1241 for (const Service &service : aHost.GetServices())
1242 {
1243 if (service.IsSubType() && (aHost.FindBaseService(service.GetInstanceName()) == nullptr))
1244 {
1245 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
1246 char subLabel[Dns::Name::kMaxLabelSize];
1247
1248 IgnoreError(service.GetServiceSubTypeLabel(subLabel, sizeof(subLabel)));
1249 LogWarn("Message contains instance %s with subtype %s without base type", service.GetInstanceName(),
1250 subLabel);
1251 #endif
1252
1253 ExitNow(error = kErrorParse);
1254 }
1255 }
1256
1257 // SRP server must treat the update instructions for a service type
1258 // and all its sub-types as atomic, i.e., when a service and its
1259 // sub-types are being updated, whatever information appears in the
1260 // SRP Update is the entirety of information about that service and
1261 // its sub-types. Any previously registered sub-type that does not
1262 // appear in a new SRP Update, must be removed.
1263 //
1264 // We go though the list of registered services for the same host
1265 // and if the base service is included in the new SRP Update
1266 // message, we add any previously registered service sub-type that
1267 // does not appear in new Update message as "deleted".
1268
1269 existingHost = mHosts.FindMatching(aHost.GetFullName());
1270 VerifyOrExit(existingHost != nullptr);
1271
1272 for (const Service &baseService : existingHost->GetServices())
1273 {
1274 if (baseService.IsSubType() || (aHost.FindBaseService(baseService.GetInstanceName()) == nullptr))
1275 {
1276 continue;
1277 }
1278
1279 for (const Service &subService : existingHost->GetServices())
1280 {
1281 if (!subService.IsSubType() || !subService.MatchesInstanceName(baseService.GetInstanceName()))
1282 {
1283 continue;
1284 }
1285
1286 SuccessOrExit(error = aHost.AddCopyOfServiceAsDeletedIfNotPresent(subService, aMetadata.mRxTime));
1287 }
1288 }
1289
1290 exit:
1291 return error;
1292 }
1293
HandleUpdate(Host & aHost,const MessageMetadata & aMetadata)1294 void Server::HandleUpdate(Host &aHost, const MessageMetadata &aMetadata)
1295 {
1296 Error error = kErrorNone;
1297 Host *existingHost;
1298
1299 // Check whether the SRP update wants to remove `aHost`.
1300
1301 VerifyOrExit(aHost.GetLease() == 0);
1302
1303 aHost.ClearResources();
1304
1305 existingHost = mHosts.FindMatching(aHost.GetFullName());
1306 VerifyOrExit(existingHost != nullptr);
1307
1308 // The client may not include all services it has registered before
1309 // when removing a host. We copy and append any missing services to
1310 // `aHost` from the `existingHost` and mark them as deleted.
1311
1312 for (Service &service : existingHost->mServices)
1313 {
1314 if (service.mIsDeleted)
1315 {
1316 continue;
1317 }
1318
1319 SuccessOrExit(error = aHost.AddCopyOfServiceAsDeletedIfNotPresent(service, aMetadata.mRxTime));
1320 }
1321
1322 exit:
1323 InformUpdateHandlerOrCommit(error, aHost, aMetadata);
1324 }
1325
InformUpdateHandlerOrCommit(Error aError,Host & aHost,const MessageMetadata & aMetadata)1326 void Server::InformUpdateHandlerOrCommit(Error aError, Host &aHost, const MessageMetadata &aMetadata)
1327 {
1328 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1329 if (aError == kErrorNone)
1330 {
1331 uint8_t numAddrs;
1332 const Ip6::Address *addrs;
1333
1334 LogInfo("Processed DNS update info");
1335 LogInfo(" Host:%s", aHost.GetFullName());
1336 LogInfo(" Lease:%lu, key-lease:%lu, ttl:%lu", ToUlong(aHost.GetLease()), ToUlong(aHost.GetKeyLease()),
1337 ToUlong(aHost.GetTtl()));
1338
1339 addrs = aHost.GetAddresses(numAddrs);
1340
1341 if (numAddrs == 0)
1342 {
1343 LogInfo(" No host address");
1344 }
1345 else
1346 {
1347 LogInfo(" %d host address(es):", numAddrs);
1348
1349 for (; numAddrs > 0; addrs++, numAddrs--)
1350 {
1351 LogInfo(" %s", addrs->ToString().AsCString());
1352 }
1353 }
1354
1355 for (const Service &service : aHost.GetServices())
1356 {
1357 char subLabel[Dns::Name::kMaxLabelSize];
1358
1359 IgnoreError(service.GetServiceSubTypeLabel(subLabel, sizeof(subLabel)));
1360
1361 LogInfo(" %s service '%s'%s%s", service.IsDeleted() ? "Deleting" : "Adding", service.GetInstanceName(),
1362 service.IsSubType() ? " subtype:" : "", subLabel);
1363 }
1364 }
1365 else
1366 {
1367 LogInfo("Error %s processing received DNS update", ErrorToString(aError));
1368 }
1369 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1370
1371 if ((aError == kErrorNone) && mServiceUpdateHandler.IsSet())
1372 {
1373 UpdateMetadata *update = UpdateMetadata::Allocate(GetInstance(), aHost, aMetadata);
1374
1375 if (update != nullptr)
1376 {
1377 mOutstandingUpdates.Push(*update);
1378 mOutstandingUpdatesTimer.FireAtIfEarlier(update->GetExpireTime());
1379
1380 LogInfo("SRP update handler is notified (updatedId = %lu)", ToUlong(update->GetId()));
1381 mServiceUpdateHandler.Invoke(update->GetId(), &aHost, static_cast<uint32_t>(kDefaultEventsHandlerTimeout));
1382 ExitNow();
1383 }
1384
1385 aError = kErrorNoBufs;
1386 }
1387
1388 CommitSrpUpdate(aError, aHost, aMetadata);
1389
1390 exit:
1391 return;
1392 }
1393
SendResponse(const Dns::UpdateHeader & aHeader,Dns::UpdateHeader::Response aResponseCode,const Ip6::MessageInfo & aMessageInfo)1394 void Server::SendResponse(const Dns::UpdateHeader &aHeader,
1395 Dns::UpdateHeader::Response aResponseCode,
1396 const Ip6::MessageInfo &aMessageInfo)
1397 {
1398 Error error;
1399 Message *response = nullptr;
1400 Dns::UpdateHeader header;
1401
1402 response = GetSocket().NewMessage();
1403 VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1404
1405 header.SetMessageId(aHeader.GetMessageId());
1406 header.SetType(Dns::UpdateHeader::kTypeResponse);
1407 header.SetQueryType(aHeader.GetQueryType());
1408 header.SetResponseCode(aResponseCode);
1409 SuccessOrExit(error = response->Append(header));
1410
1411 SuccessOrExit(error = GetSocket().SendTo(*response, aMessageInfo));
1412
1413 if (aResponseCode != Dns::UpdateHeader::kResponseSuccess)
1414 {
1415 LogWarn("Send fail response: %d", aResponseCode);
1416 }
1417 else
1418 {
1419 LogInfo("Send success response");
1420 }
1421
1422 UpdateResponseCounters(aResponseCode);
1423
1424 exit:
1425 if (error != kErrorNone)
1426 {
1427 LogWarn("Failed to send response: %s", ErrorToString(error));
1428 FreeMessage(response);
1429 }
1430 }
1431
SendResponse(const Dns::UpdateHeader & aHeader,uint32_t aLease,uint32_t aKeyLease,bool mUseShortLeaseOption,const Ip6::MessageInfo & aMessageInfo)1432 void Server::SendResponse(const Dns::UpdateHeader &aHeader,
1433 uint32_t aLease,
1434 uint32_t aKeyLease,
1435 bool mUseShortLeaseOption,
1436 const Ip6::MessageInfo &aMessageInfo)
1437 {
1438 Error error;
1439 Message *response = nullptr;
1440 Dns::UpdateHeader header;
1441 Dns::OptRecord optRecord;
1442 Dns::LeaseOption leaseOption;
1443 uint16_t optionSize;
1444
1445 response = GetSocket().NewMessage();
1446 VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1447
1448 header.SetMessageId(aHeader.GetMessageId());
1449 header.SetType(Dns::UpdateHeader::kTypeResponse);
1450 header.SetQueryType(aHeader.GetQueryType());
1451 header.SetResponseCode(Dns::UpdateHeader::kResponseSuccess);
1452 header.SetAdditionalRecordCount(1);
1453 SuccessOrExit(error = response->Append(header));
1454
1455 // Append the root domain (".").
1456 SuccessOrExit(error = Dns::Name::AppendTerminator(*response));
1457
1458 optRecord.Init();
1459 optRecord.SetUdpPayloadSize(kUdpPayloadSize);
1460 optRecord.SetDnsSecurityFlag();
1461
1462 if (mUseShortLeaseOption)
1463 {
1464 leaseOption.InitAsShortVariant(aLease);
1465 }
1466 else
1467 {
1468 leaseOption.InitAsLongVariant(aLease, aKeyLease);
1469 }
1470
1471 optionSize = static_cast<uint16_t>(leaseOption.GetSize());
1472 optRecord.SetLength(optionSize);
1473
1474 SuccessOrExit(error = response->Append(optRecord));
1475 SuccessOrExit(error = response->AppendBytes(&leaseOption, optionSize));
1476
1477 SuccessOrExit(error = GetSocket().SendTo(*response, aMessageInfo));
1478
1479 LogInfo("Send success response with granted lease: %lu and key lease: %lu", ToUlong(aLease), ToUlong(aKeyLease));
1480
1481 UpdateResponseCounters(Dns::UpdateHeader::kResponseSuccess);
1482
1483 exit:
1484 if (error != kErrorNone)
1485 {
1486 LogWarn("Failed to send response: %s", ErrorToString(error));
1487 FreeMessage(response);
1488 }
1489 }
1490
HandleUdpReceive(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)1491 void Server::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
1492 {
1493 static_cast<Server *>(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo));
1494 }
1495
HandleUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1496 void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1497 {
1498 Error error = ProcessMessage(aMessage, aMessageInfo);
1499
1500 if (error != kErrorNone)
1501 {
1502 LogInfo("Failed to handle DNS message: %s", ErrorToString(error));
1503 }
1504 }
1505
ProcessMessage(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1506 Error Server::ProcessMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1507 {
1508 return ProcessMessage(aMessage, TimerMilli::GetNow(), mTtlConfig, mLeaseConfig, &aMessageInfo);
1509 }
1510
ProcessMessage(Message & aMessage,TimeMilli aRxTime,const TtlConfig & aTtlConfig,const LeaseConfig & aLeaseConfig,const Ip6::MessageInfo * aMessageInfo)1511 Error Server::ProcessMessage(Message &aMessage,
1512 TimeMilli aRxTime,
1513 const TtlConfig &aTtlConfig,
1514 const LeaseConfig &aLeaseConfig,
1515 const Ip6::MessageInfo *aMessageInfo)
1516 {
1517 Error error;
1518 MessageMetadata metadata;
1519
1520 metadata.mOffset = aMessage.GetOffset();
1521 metadata.mRxTime = aRxTime;
1522 metadata.mTtlConfig = aTtlConfig;
1523 metadata.mLeaseConfig = aLeaseConfig;
1524 metadata.mMessageInfo = aMessageInfo;
1525
1526 SuccessOrExit(error = aMessage.Read(metadata.mOffset, metadata.mDnsHeader));
1527 metadata.mOffset += sizeof(Dns::UpdateHeader);
1528
1529 VerifyOrExit(metadata.mDnsHeader.GetType() == Dns::UpdateHeader::Type::kTypeQuery, error = kErrorDrop);
1530 VerifyOrExit(metadata.mDnsHeader.GetQueryType() == Dns::UpdateHeader::kQueryTypeUpdate, error = kErrorDrop);
1531
1532 ProcessDnsUpdate(aMessage, metadata);
1533
1534 exit:
1535 return error;
1536 }
1537
HandleLeaseTimer(void)1538 void Server::HandleLeaseTimer(void)
1539 {
1540 TimeMilli now = TimerMilli::GetNow();
1541 TimeMilli earliestExpireTime = now.GetDistantFuture();
1542 Host *nextHost;
1543
1544 for (Host *host = mHosts.GetHead(); host != nullptr; host = nextHost)
1545 {
1546 nextHost = host->GetNext();
1547
1548 if (host->GetKeyExpireTime() <= now)
1549 {
1550 LogInfo("KEY LEASE of host %s expired", host->GetFullName());
1551
1552 // Removes the whole host and all services if the KEY RR expired.
1553 RemoveHost(host, kDeleteName, kNotifyServiceHandler);
1554 }
1555 else if (host->IsDeleted())
1556 {
1557 // The host has been deleted, but the hostname & service instance names retain.
1558
1559 Service *next;
1560
1561 earliestExpireTime = Min(earliestExpireTime, host->GetKeyExpireTime());
1562
1563 // Check if any service instance name expired.
1564 for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1565 {
1566 next = service->GetNext();
1567
1568 OT_ASSERT(service->mIsDeleted);
1569
1570 if (service->GetKeyExpireTime() <= now)
1571 {
1572 service->Log(Service::kKeyLeaseExpired);
1573 host->RemoveService(service, kDeleteName, kNotifyServiceHandler);
1574 }
1575 else
1576 {
1577 earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1578 }
1579 }
1580 }
1581 else if (host->GetExpireTime() <= now)
1582 {
1583 LogInfo("LEASE of host %s expired", host->GetFullName());
1584
1585 // If the host expired, delete all resources of this host and its services.
1586 for (Service &service : host->mServices)
1587 {
1588 // Don't need to notify the service handler as `RemoveHost` at below will do.
1589 host->RemoveService(&service, kRetainName, kDoNotNotifyServiceHandler);
1590 }
1591
1592 RemoveHost(host, kRetainName, kNotifyServiceHandler);
1593
1594 earliestExpireTime = Min(earliestExpireTime, host->GetKeyExpireTime());
1595 }
1596 else
1597 {
1598 // The host doesn't expire, check if any service expired or is explicitly removed.
1599
1600 Service *next;
1601
1602 OT_ASSERT(!host->IsDeleted());
1603
1604 earliestExpireTime = Min(earliestExpireTime, host->GetExpireTime());
1605
1606 for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1607 {
1608 next = service->GetNext();
1609
1610 if (service->GetKeyExpireTime() <= now)
1611 {
1612 service->Log(Service::kKeyLeaseExpired);
1613 host->RemoveService(service, kDeleteName, kNotifyServiceHandler);
1614 }
1615 else if (service->mIsDeleted)
1616 {
1617 // The service has been deleted but the name retains.
1618 earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1619 }
1620 else if (service->GetExpireTime() <= now)
1621 {
1622 service->Log(Service::kLeaseExpired);
1623
1624 // The service is expired, delete it.
1625 host->RemoveService(service, kRetainName, kNotifyServiceHandler);
1626 earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1627 }
1628 else
1629 {
1630 earliestExpireTime = Min(earliestExpireTime, service->GetExpireTime());
1631 }
1632 }
1633 }
1634 }
1635
1636 if (earliestExpireTime != now.GetDistantFuture())
1637 {
1638 OT_ASSERT(earliestExpireTime >= now);
1639 if (!mLeaseTimer.IsRunning() || earliestExpireTime <= mLeaseTimer.GetFireTime())
1640 {
1641 LogInfo("Lease timer is scheduled for %lu seconds", ToUlong(Time::MsecToSec(earliestExpireTime - now)));
1642 mLeaseTimer.StartAt(earliestExpireTime, 0);
1643 }
1644 }
1645 else
1646 {
1647 LogInfo("Lease timer is stopped");
1648 mLeaseTimer.Stop();
1649 }
1650 }
1651
HandleOutstandingUpdatesTimer(void)1652 void Server::HandleOutstandingUpdatesTimer(void)
1653 {
1654 while (!mOutstandingUpdates.IsEmpty() && mOutstandingUpdates.GetTail()->GetExpireTime() <= TimerMilli::GetNow())
1655 {
1656 LogInfo("Outstanding service update timeout (updateId = %lu)", ToUlong(mOutstandingUpdates.GetTail()->GetId()));
1657 HandleServiceUpdateResult(mOutstandingUpdates.GetTail(), kErrorResponseTimeout);
1658 }
1659 }
1660
AddressModeToString(AddressMode aMode)1661 const char *Server::AddressModeToString(AddressMode aMode)
1662 {
1663 static const char *const kAddressModeStrings[] = {
1664 "unicast", // (0) kAddressModeUnicast
1665 "anycast", // (1) kAddressModeAnycast
1666 };
1667
1668 static_assert(kAddressModeUnicast == 0, "kAddressModeUnicast value is incorrect");
1669 static_assert(kAddressModeAnycast == 1, "kAddressModeAnycast value is incorrect");
1670
1671 return kAddressModeStrings[aMode];
1672 }
1673
UpdateResponseCounters(Dns::UpdateHeader::Response aResponseCode)1674 void Server::UpdateResponseCounters(Dns::UpdateHeader::Response aResponseCode)
1675 {
1676 switch (aResponseCode)
1677 {
1678 case Dns::UpdateHeader::kResponseSuccess:
1679 ++mResponseCounters.mSuccess;
1680 break;
1681 case Dns::UpdateHeader::kResponseServerFailure:
1682 ++mResponseCounters.mServerFailure;
1683 break;
1684 case Dns::UpdateHeader::kResponseFormatError:
1685 ++mResponseCounters.mFormatError;
1686 break;
1687 case Dns::UpdateHeader::kResponseNameExists:
1688 ++mResponseCounters.mNameExists;
1689 break;
1690 case Dns::UpdateHeader::kResponseRefused:
1691 ++mResponseCounters.mRefused;
1692 break;
1693 default:
1694 ++mResponseCounters.mOther;
1695 break;
1696 }
1697 }
1698
1699 //---------------------------------------------------------------------------------------------------------------------
1700 // Server::Service
1701
Init(const char * aServiceName,Description & aDescription,bool aIsSubType,TimeMilli aUpdateTime)1702 Error Server::Service::Init(const char *aServiceName, Description &aDescription, bool aIsSubType, TimeMilli aUpdateTime)
1703 {
1704 mDescription.Reset(&aDescription);
1705 mNext = nullptr;
1706 mUpdateTime = aUpdateTime;
1707 mIsDeleted = false;
1708 mIsSubType = aIsSubType;
1709 mIsCommitted = false;
1710
1711 return mServiceName.Set(aServiceName);
1712 }
1713
GetServiceSubTypeLabel(char * aLabel,uint8_t aMaxSize) const1714 Error Server::Service::GetServiceSubTypeLabel(char *aLabel, uint8_t aMaxSize) const
1715 {
1716 Error error = kErrorNone;
1717 const char *serviceName = GetServiceName();
1718 const char *subServiceName;
1719 uint8_t labelLength;
1720
1721 memset(aLabel, 0, aMaxSize);
1722
1723 VerifyOrExit(IsSubType(), error = kErrorInvalidArgs);
1724
1725 subServiceName = StringFind(serviceName, kServiceSubTypeLabel, kStringCaseInsensitiveMatch);
1726 OT_ASSERT(subServiceName != nullptr);
1727
1728 if (subServiceName - serviceName < aMaxSize)
1729 {
1730 labelLength = static_cast<uint8_t>(subServiceName - serviceName);
1731 }
1732 else
1733 {
1734 labelLength = aMaxSize - 1;
1735 error = kErrorNoBufs;
1736 }
1737
1738 memcpy(aLabel, serviceName, labelLength);
1739
1740 exit:
1741 return error;
1742 }
1743
GetExpireTime(void) const1744 TimeMilli Server::Service::GetExpireTime(void) const
1745 {
1746 OT_ASSERT(!mIsDeleted);
1747 OT_ASSERT(!GetHost().IsDeleted());
1748
1749 return mUpdateTime + Time::SecToMsec(mDescription->mLease);
1750 }
1751
GetKeyExpireTime(void) const1752 TimeMilli Server::Service::GetKeyExpireTime(void) const
1753 {
1754 return mUpdateTime + Time::SecToMsec(mDescription->mKeyLease);
1755 }
1756
GetLeaseInfo(LeaseInfo & aLeaseInfo) const1757 void Server::Service::GetLeaseInfo(LeaseInfo &aLeaseInfo) const
1758 {
1759 TimeMilli now = TimerMilli::GetNow();
1760 TimeMilli keyExpireTime = GetKeyExpireTime();
1761
1762 aLeaseInfo.mLease = Time::SecToMsec(GetLease());
1763 aLeaseInfo.mKeyLease = Time::SecToMsec(GetKeyLease());
1764 aLeaseInfo.mRemainingKeyLease = (now <= keyExpireTime) ? (keyExpireTime - now) : 0;
1765
1766 if (!mIsDeleted)
1767 {
1768 TimeMilli expireTime = GetExpireTime();
1769
1770 aLeaseInfo.mRemainingLease = (now <= expireTime) ? (expireTime - now) : 0;
1771 }
1772 else
1773 {
1774 aLeaseInfo.mRemainingLease = 0;
1775 }
1776 }
1777
MatchesInstanceName(const char * aInstanceName) const1778 bool Server::Service::MatchesInstanceName(const char *aInstanceName) const
1779 {
1780 return StringMatch(mDescription->mInstanceName.AsCString(), aInstanceName, kStringCaseInsensitiveMatch);
1781 }
1782
MatchesServiceName(const char * aServiceName) const1783 bool Server::Service::MatchesServiceName(const char *aServiceName) const
1784 {
1785 return StringMatch(mServiceName.AsCString(), aServiceName, kStringCaseInsensitiveMatch);
1786 }
1787
MatchesFlags(Flags aFlags) const1788 bool Server::Service::MatchesFlags(Flags aFlags) const
1789 {
1790 bool matches = false;
1791
1792 if (IsSubType())
1793 {
1794 VerifyOrExit(aFlags & kFlagSubType);
1795 }
1796 else
1797 {
1798 VerifyOrExit(aFlags & kFlagBaseType);
1799 }
1800
1801 if (IsDeleted())
1802 {
1803 VerifyOrExit(aFlags & kFlagDeleted);
1804 }
1805 else
1806 {
1807 VerifyOrExit(aFlags & kFlagActive);
1808 }
1809
1810 matches = true;
1811
1812 exit:
1813 return matches;
1814 }
1815
1816 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
Log(Action aAction) const1817 void Server::Service::Log(Action aAction) const
1818 {
1819 static const char *const kActionStrings[] = {
1820 "Add new", // (0) kAddNew
1821 "Update existing", // (1) kUpdateExisting
1822 "Remove but retain name of", // (2) kRemoveButRetainName
1823 "Fully remove", // (3) kFullyRemove
1824 "LEASE expired for", // (4) kLeaseExpired
1825 "KEY LEASE expired for", // (5) kKeyLeaseExpired
1826 };
1827
1828 char subLabel[Dns::Name::kMaxLabelSize];
1829
1830 static_assert(0 == kAddNew, "kAddNew value is incorrect");
1831 static_assert(1 == kUpdateExisting, "kUpdateExisting value is incorrect");
1832 static_assert(2 == kRemoveButRetainName, "kRemoveButRetainName value is incorrect");
1833 static_assert(3 == kFullyRemove, "kFullyRemove value is incorrect");
1834 static_assert(4 == kLeaseExpired, "kLeaseExpired value is incorrect");
1835 static_assert(5 == kKeyLeaseExpired, "kKeyLeaseExpired value is incorrect");
1836
1837 // We only log if the `Service` is marked as committed. This
1838 // ensures that temporary `Service` entries associated with a
1839 // newly received SRP update message are not logged (e.g., when
1840 // associated `Host` is being freed).
1841
1842 if (mIsCommitted)
1843 {
1844 IgnoreError(GetServiceSubTypeLabel(subLabel, sizeof(subLabel)));
1845
1846 LogInfo("%s service '%s'%s%s", kActionStrings[aAction], GetInstanceName(), IsSubType() ? " subtype:" : "",
1847 subLabel);
1848 }
1849 }
1850 #else
Log(Action) const1851 void Server::Service::Log(Action) const {}
1852 #endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1853
1854 //---------------------------------------------------------------------------------------------------------------------
1855 // Server::Service::Description
1856
Init(const char * aInstanceName,Host & aHost)1857 Error Server::Service::Description::Init(const char *aInstanceName, Host &aHost)
1858 {
1859 mNext = nullptr;
1860 mHost = &aHost;
1861 mPriority = 0;
1862 mWeight = 0;
1863 mTtl = 0;
1864 mPort = 0;
1865 mLease = 0;
1866 mKeyLease = 0;
1867 mUpdateTime = TimerMilli::GetNow().GetDistantPast();
1868 mTxtData.Free();
1869
1870 return mInstanceName.Set(aInstanceName);
1871 }
1872
Matches(const char * aInstanceName) const1873 bool Server::Service::Description::Matches(const char *aInstanceName) const
1874 {
1875 return StringMatch(mInstanceName.AsCString(), aInstanceName, kStringCaseInsensitiveMatch);
1876 }
1877
ClearResources(void)1878 void Server::Service::Description::ClearResources(void)
1879 {
1880 mPort = 0;
1881 mTxtData.Free();
1882 }
1883
TakeResourcesFrom(Description & aDescription)1884 void Server::Service::Description::TakeResourcesFrom(Description &aDescription)
1885 {
1886 mTxtData.SetFrom(static_cast<Heap::Data &&>(aDescription.mTxtData));
1887
1888 mPriority = aDescription.mPriority;
1889 mWeight = aDescription.mWeight;
1890 mPort = aDescription.mPort;
1891
1892 mTtl = aDescription.mTtl;
1893 mLease = aDescription.mLease;
1894 mKeyLease = aDescription.mKeyLease;
1895 mUpdateTime = TimerMilli::GetNow();
1896 }
1897
SetTxtDataFromMessage(const Message & aMessage,uint16_t aOffset,uint16_t aLength)1898 Error Server::Service::Description::SetTxtDataFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
1899 {
1900 Error error;
1901
1902 SuccessOrExit(error = mTxtData.SetFrom(aMessage, aOffset, aLength));
1903 VerifyOrExit(Dns::TxtRecord::VerifyTxtData(mTxtData.GetBytes(), mTxtData.GetLength(), /* aAllowEmpty */ false),
1904 error = kErrorParse);
1905
1906 exit:
1907 if (error != kErrorNone)
1908 {
1909 mTxtData.Free();
1910 }
1911
1912 return error;
1913 }
1914
1915 //---------------------------------------------------------------------------------------------------------------------
1916 // Server::Host
1917
Host(Instance & aInstance,TimeMilli aUpdateTime)1918 Server::Host::Host(Instance &aInstance, TimeMilli aUpdateTime)
1919 : InstanceLocator(aInstance)
1920 , mNext(nullptr)
1921 , mTtl(0)
1922 , mLease(0)
1923 , mKeyLease(0)
1924 , mUpdateTime(aUpdateTime)
1925 {
1926 mKeyRecord.Clear();
1927 }
1928
~Host(void)1929 Server::Host::~Host(void) { FreeAllServices(); }
1930
SetFullName(const char * aFullName)1931 Error Server::Host::SetFullName(const char *aFullName)
1932 {
1933 // `mFullName` becomes immutable after it is set, so if it is
1934 // already set, we only accept a `aFullName` that matches the
1935 // current name.
1936
1937 Error error;
1938
1939 if (mFullName.IsNull())
1940 {
1941 error = mFullName.Set(aFullName);
1942 }
1943 else
1944 {
1945 error = Matches(aFullName) ? kErrorNone : kErrorFailed;
1946 }
1947
1948 return error;
1949 }
1950
Matches(const char * aFullName) const1951 bool Server::Host::Matches(const char *aFullName) const
1952 {
1953 return StringMatch(mFullName.AsCString(), aFullName, kStringCaseInsensitiveMatch);
1954 }
1955
SetKeyRecord(Dns::Ecdsa256KeyRecord & aKeyRecord)1956 void Server::Host::SetKeyRecord(Dns::Ecdsa256KeyRecord &aKeyRecord)
1957 {
1958 OT_ASSERT(aKeyRecord.IsValid());
1959
1960 mKeyRecord = aKeyRecord;
1961 }
1962
GetExpireTime(void) const1963 TimeMilli Server::Host::GetExpireTime(void) const
1964 {
1965 OT_ASSERT(!IsDeleted());
1966
1967 return mUpdateTime + Time::SecToMsec(mLease);
1968 }
1969
GetKeyExpireTime(void) const1970 TimeMilli Server::Host::GetKeyExpireTime(void) const { return mUpdateTime + Time::SecToMsec(mKeyLease); }
1971
GetLeaseInfo(LeaseInfo & aLeaseInfo) const1972 void Server::Host::GetLeaseInfo(LeaseInfo &aLeaseInfo) const
1973 {
1974 TimeMilli now = TimerMilli::GetNow();
1975 TimeMilli keyExpireTime = GetKeyExpireTime();
1976
1977 aLeaseInfo.mLease = Time::SecToMsec(GetLease());
1978 aLeaseInfo.mKeyLease = Time::SecToMsec(GetKeyLease());
1979 aLeaseInfo.mRemainingKeyLease = (now <= keyExpireTime) ? (keyExpireTime - now) : 0;
1980
1981 if (!IsDeleted())
1982 {
1983 TimeMilli expireTime = GetExpireTime();
1984
1985 aLeaseInfo.mRemainingLease = (now <= expireTime) ? (expireTime - now) : 0;
1986 }
1987 else
1988 {
1989 aLeaseInfo.mRemainingLease = 0;
1990 }
1991 }
1992
ProcessTtl(uint32_t aTtl)1993 Error Server::Host::ProcessTtl(uint32_t aTtl)
1994 {
1995 // This method processes the TTL value received in a resource record.
1996 //
1997 // If no TTL value is stored, this method wil set the stored value to @p aTtl and return `kErrorNone`.
1998 // If a TTL value is stored and @p aTtl equals the stored value, this method returns `kErrorNone`.
1999 // Otherwise, this method returns `kErrorRejected`.
2000
2001 Error error = kErrorRejected;
2002
2003 VerifyOrExit(aTtl && (mTtl == 0 || mTtl == aTtl));
2004
2005 mTtl = aTtl;
2006
2007 error = kErrorNone;
2008
2009 exit:
2010 return error;
2011 }
2012
FindNextService(const Service * aPrevService,Service::Flags aFlags,const char * aServiceName,const char * aInstanceName) const2013 const Server::Service *Server::Host::FindNextService(const Service *aPrevService,
2014 Service::Flags aFlags,
2015 const char *aServiceName,
2016 const char *aInstanceName) const
2017 {
2018 const Service *service = (aPrevService == nullptr) ? GetServices().GetHead() : aPrevService->GetNext();
2019
2020 for (; service != nullptr; service = service->GetNext())
2021 {
2022 if (!service->MatchesFlags(aFlags))
2023 {
2024 continue;
2025 }
2026
2027 if ((aServiceName != nullptr) && !service->MatchesServiceName(aServiceName))
2028 {
2029 continue;
2030 }
2031
2032 if ((aInstanceName != nullptr) && !service->MatchesInstanceName(aInstanceName))
2033 {
2034 continue;
2035 }
2036
2037 break;
2038 }
2039
2040 return service;
2041 }
2042
AddNewService(const char * aServiceName,const char * aInstanceName,bool aIsSubType,TimeMilli aUpdateTime)2043 Server::Service *Server::Host::AddNewService(const char *aServiceName,
2044 const char *aInstanceName,
2045 bool aIsSubType,
2046 TimeMilli aUpdateTime)
2047 {
2048 Service *service = nullptr;
2049 RetainPtr<Service::Description> desc(FindServiceDescription(aInstanceName));
2050
2051 if (desc == nullptr)
2052 {
2053 desc.Reset(Service::Description::AllocateAndInit(aInstanceName, *this));
2054 VerifyOrExit(desc != nullptr);
2055 }
2056
2057 service = Service::AllocateAndInit(aServiceName, *desc, aIsSubType, aUpdateTime);
2058 VerifyOrExit(service != nullptr);
2059
2060 mServices.Push(*service);
2061
2062 exit:
2063 return service;
2064 }
2065
RemoveService(Service * aService,RetainName aRetainName,NotifyMode aNotifyServiceHandler)2066 void Server::Host::RemoveService(Service *aService, RetainName aRetainName, NotifyMode aNotifyServiceHandler)
2067 {
2068 Server &server = Get<Server>();
2069
2070 VerifyOrExit(aService != nullptr);
2071
2072 aService->mIsDeleted = true;
2073
2074 aService->Log(aRetainName ? Service::kRemoveButRetainName : Service::kFullyRemove);
2075
2076 if (aNotifyServiceHandler && server.mServiceUpdateHandler.IsSet())
2077 {
2078 uint32_t updateId = server.AllocateId();
2079
2080 LogInfo("SRP update handler is notified (updatedId = %lu)", ToUlong(updateId));
2081 server.mServiceUpdateHandler.Invoke(updateId, this, static_cast<uint32_t>(kDefaultEventsHandlerTimeout));
2082 // We don't wait for the reply from the service update handler,
2083 // but always remove the service regardless of service update result.
2084 // Because removing a service should fail only when there is system
2085 // failure of the platform mDNS implementation and in which case the
2086 // service is not expected to be still registered.
2087 }
2088
2089 if (!aRetainName)
2090 {
2091 IgnoreError(mServices.Remove(*aService));
2092 aService->Free();
2093 }
2094
2095 exit:
2096 return;
2097 }
2098
AddCopyOfServiceAsDeletedIfNotPresent(const Service & aService,TimeMilli aUpdateTime)2099 Error Server::Host::AddCopyOfServiceAsDeletedIfNotPresent(const Service &aService, TimeMilli aUpdateTime)
2100 {
2101 Error error = kErrorNone;
2102 Service *newService;
2103
2104 VerifyOrExit(FindService(aService.GetServiceName(), aService.GetInstanceName()) == nullptr);
2105
2106 newService =
2107 AddNewService(aService.GetServiceName(), aService.GetInstanceName(), aService.IsSubType(), aUpdateTime);
2108
2109 VerifyOrExit(newService != nullptr, error = kErrorNoBufs);
2110
2111 newService->mDescription->mUpdateTime = aUpdateTime;
2112 newService->mIsDeleted = true;
2113
2114 exit:
2115 return error;
2116 }
2117
FreeAllServices(void)2118 void Server::Host::FreeAllServices(void)
2119 {
2120 while (!mServices.IsEmpty())
2121 {
2122 RemoveService(mServices.GetHead(), kDeleteName, kDoNotNotifyServiceHandler);
2123 }
2124 }
2125
ClearResources(void)2126 void Server::Host::ClearResources(void) { mAddresses.Free(); }
2127
MergeServicesAndResourcesFrom(Host & aHost)2128 Error Server::Host::MergeServicesAndResourcesFrom(Host &aHost)
2129 {
2130 // This method merges services, service descriptions, and other
2131 // resources from another `aHost` into current host. It can
2132 // possibly take ownership of some items from `aHost`.
2133
2134 Error error = kErrorNone;
2135
2136 LogInfo("Update host %s", GetFullName());
2137
2138 mAddresses.TakeFrom(static_cast<Heap::Array<Ip6::Address> &&>(aHost.mAddresses));
2139 mKeyRecord = aHost.mKeyRecord;
2140 mTtl = aHost.mTtl;
2141 mLease = aHost.mLease;
2142 mKeyLease = aHost.mKeyLease;
2143 mUpdateTime = TimerMilli::GetNow();
2144
2145 for (Service &service : aHost.mServices)
2146 {
2147 Service *existingService = FindService(service.GetServiceName(), service.GetInstanceName());
2148 Service *newService;
2149
2150 if (service.mIsDeleted)
2151 {
2152 // `RemoveService()` does nothing if `existingService` is `nullptr`.
2153 RemoveService(existingService, kRetainName, kDoNotNotifyServiceHandler);
2154 continue;
2155 }
2156
2157 // Add/Merge `service` into the existing service or a allocate a new one
2158
2159 newService = (existingService != nullptr) ? existingService
2160 : AddNewService(service.GetServiceName(), service.GetInstanceName(),
2161 service.IsSubType(), service.GetUpdateTime());
2162
2163 VerifyOrExit(newService != nullptr, error = kErrorNoBufs);
2164
2165 newService->mIsDeleted = false;
2166 newService->mIsCommitted = true;
2167 newService->mUpdateTime = TimerMilli::GetNow();
2168
2169 if (!service.mIsSubType)
2170 {
2171 // (1) Service description is shared across a base type and all its subtypes.
2172 // (2) `TakeResourcesFrom()` releases resources pinned to its argument.
2173 // Therefore, make sure the function is called only for the base type.
2174 newService->mDescription->TakeResourcesFrom(*service.mDescription);
2175 }
2176
2177 newService->Log((existingService != nullptr) ? Service::kUpdateExisting : Service::kAddNew);
2178 }
2179
2180 exit:
2181 return error;
2182 }
2183
HasServiceInstance(const char * aInstanceName) const2184 bool Server::Host::HasServiceInstance(const char *aInstanceName) const
2185 {
2186 return (FindServiceDescription(aInstanceName) != nullptr);
2187 }
2188
FindServiceDescription(const char * aInstanceName) const2189 const RetainPtr<Server::Service::Description> Server::Host::FindServiceDescription(const char *aInstanceName) const
2190 {
2191 const Service::Description *desc = nullptr;
2192
2193 for (const Service &service : mServices)
2194 {
2195 if (service.mDescription->Matches(aInstanceName))
2196 {
2197 desc = service.mDescription.Get();
2198 break;
2199 }
2200 }
2201
2202 return RetainPtr<Service::Description>(AsNonConst(desc));
2203 }
2204
FindServiceDescription(const char * aInstanceName)2205 RetainPtr<Server::Service::Description> Server::Host::FindServiceDescription(const char *aInstanceName)
2206 {
2207 return AsNonConst(AsConst(this)->FindServiceDescription(aInstanceName));
2208 }
2209
FindService(const char * aServiceName,const char * aInstanceName) const2210 const Server::Service *Server::Host::FindService(const char *aServiceName, const char *aInstanceName) const
2211 {
2212 return FindNextService(/* aPrevService */ nullptr, kFlagsAnyService, aServiceName, aInstanceName);
2213 }
2214
FindService(const char * aServiceName,const char * aInstanceName)2215 Server::Service *Server::Host::FindService(const char *aServiceName, const char *aInstanceName)
2216 {
2217 return AsNonConst(AsConst(this)->FindService(aServiceName, aInstanceName));
2218 }
2219
FindBaseService(const char * aInstanceName) const2220 const Server::Service *Server::Host::FindBaseService(const char *aInstanceName) const
2221 {
2222 return FindNextService(/*a PrevService */ nullptr, kFlagsBaseTypeServiceOnly, /* aServiceName */ nullptr,
2223 aInstanceName);
2224 }
2225
FindBaseService(const char * aInstanceName)2226 Server::Service *Server::Host::FindBaseService(const char *aInstanceName)
2227 {
2228 return AsNonConst(AsConst(this)->FindBaseService(aInstanceName));
2229 }
2230
AddIp6Address(const Ip6::Address & aIp6Address)2231 Error Server::Host::AddIp6Address(const Ip6::Address &aIp6Address)
2232 {
2233 Error error = kErrorNone;
2234
2235 if (aIp6Address.IsMulticast() || aIp6Address.IsUnspecified() || aIp6Address.IsLoopback())
2236 {
2237 // We don't like those address because they cannot be used
2238 // for communication with exterior devices.
2239 ExitNow(error = kErrorDrop);
2240 }
2241
2242 // Drop duplicate addresses.
2243 VerifyOrExit(!mAddresses.Contains(aIp6Address), error = kErrorDrop);
2244
2245 error = mAddresses.PushBack(aIp6Address);
2246
2247 if (error == kErrorNoBufs)
2248 {
2249 LogWarn("Too many addresses for host %s", GetFullName());
2250 }
2251
2252 exit:
2253 return error;
2254 }
2255
2256 //---------------------------------------------------------------------------------------------------------------------
2257 // Server::UpdateMetadata
2258
UpdateMetadata(Instance & aInstance,Host & aHost,const MessageMetadata & aMessageMetadata)2259 Server::UpdateMetadata::UpdateMetadata(Instance &aInstance, Host &aHost, const MessageMetadata &aMessageMetadata)
2260 : InstanceLocator(aInstance)
2261 , mNext(nullptr)
2262 , mExpireTime(TimerMilli::GetNow() + kDefaultEventsHandlerTimeout)
2263 , mDnsHeader(aMessageMetadata.mDnsHeader)
2264 , mId(Get<Server>().AllocateId())
2265 , mTtlConfig(aMessageMetadata.mTtlConfig)
2266 , mLeaseConfig(aMessageMetadata.mLeaseConfig)
2267 , mHost(aHost)
2268 , mIsDirectRxFromClient(aMessageMetadata.IsDirectRxFromClient())
2269 {
2270 if (aMessageMetadata.mMessageInfo != nullptr)
2271 {
2272 mMessageInfo = *aMessageMetadata.mMessageInfo;
2273 }
2274 }
2275
2276 } // namespace Srp
2277 } // namespace ot
2278
2279 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
2280