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