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