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