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