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