1 /*
2 * Copyright (c) 2020, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file includes implementation for SRP server.
32 */
33
34 #include "srp_server.hpp"
35
36 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
37
38 #include "common/as_core_type.hpp"
39 #include "common/const_cast.hpp"
40 #include "common/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/log.hpp"
43 #include "common/new.hpp"
44 #include "common/num_utils.hpp"
45 #include "common/random.hpp"
46 #include "common/string.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)
90 , mLeaseTimer(aInstance)
91 , mOutstandingUpdatesTimer(aInstance)
92 , mCompletedUpdateTask(aInstance)
93 , mServiceUpdateId(Random::NonCrypto::GetUint32())
94 , mPort(kUdpPortMin)
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 = AllocateId();
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
343 if (!aRetainName)
344 {
345 aHost->Free();
346 }
347
348 exit:
349 return;
350 }
351
HasNameConflictsWith(Host & aHost) const352 bool Server::HasNameConflictsWith(Host &aHost) const
353 {
354 bool hasConflicts = false;
355 const Host *existingHost = mHosts.FindMatching(aHost.GetFullName());
356
357 if ((existingHost != nullptr) && (aHost.mKey != existingHost->mKey))
358 {
359 LogWarn("Name conflict: host name %s has already been allocated", aHost.GetFullName());
360 ExitNow(hasConflicts = true);
361 }
362
363 for (const Service &service : aHost.mServices)
364 {
365 // Check on all hosts for a matching service with the same
366 // instance name and if found, verify that it has the same
367 // key.
368
369 for (const Host &host : mHosts)
370 {
371 if (host.HasService(service.GetInstanceName()) && (aHost.mKey != host.mKey))
372 {
373 LogWarn("Name conflict: service name %s has already been allocated", service.GetInstanceName());
374 ExitNow(hasConflicts = true);
375 }
376 }
377 }
378
379 exit:
380 return hasConflicts;
381 }
382
HandleServiceUpdateResult(ServiceUpdateId aId,Error aError)383 void Server::HandleServiceUpdateResult(ServiceUpdateId aId, Error aError)
384 {
385 UpdateMetadata *update = mOutstandingUpdates.RemoveMatching(aId);
386
387 if (update == nullptr)
388 {
389 LogInfo("Delayed SRP host update result, the SRP update has been committed (updateId = %lu)", ToUlong(aId));
390 ExitNow();
391 }
392
393 update->SetError(aError);
394
395 LogInfo("Handler result of SRP update (id = %lu) is received: %s", ToUlong(update->GetId()), ErrorToString(aError));
396
397 // We add new `update` at the tail of the `mCompletedUpdates` list
398 // so that updates are processed in the order we receive the
399 // `HandleServiceUpdateResult()` callbacks for them. The
400 // completed updates are processed from `mCompletedUpdateTask`
401 // and `ProcessCompletedUpdates()`.
402
403 mCompletedUpdates.PushAfterTail(*update);
404 mCompletedUpdateTask.Post();
405
406 if (mOutstandingUpdates.IsEmpty())
407 {
408 mOutstandingUpdatesTimer.Stop();
409 }
410 else
411 {
412 mOutstandingUpdatesTimer.FireAt(mOutstandingUpdates.GetTail()->GetExpireTime());
413 }
414
415 exit:
416 return;
417 }
418
ProcessCompletedUpdates(void)419 void Server::ProcessCompletedUpdates(void)
420 {
421 UpdateMetadata *update;
422
423 while ((update = mCompletedUpdates.Pop()) != nullptr)
424 {
425 CommitSrpUpdate(*update);
426 }
427 }
428
CommitSrpUpdate(Error aError,Host & aHost,const MessageMetadata & aMessageMetadata)429 void Server::CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &aMessageMetadata)
430 {
431 CommitSrpUpdate(aError, aHost, aMessageMetadata.mDnsHeader, aMessageMetadata.mMessageInfo,
432 aMessageMetadata.mTtlConfig, aMessageMetadata.mLeaseConfig);
433 }
434
CommitSrpUpdate(UpdateMetadata & aUpdateMetadata)435 void Server::CommitSrpUpdate(UpdateMetadata &aUpdateMetadata)
436 {
437 CommitSrpUpdate(aUpdateMetadata.GetError(), aUpdateMetadata.GetHost(), aUpdateMetadata.GetDnsHeader(),
438 aUpdateMetadata.IsDirectRxFromClient() ? &aUpdateMetadata.GetMessageInfo() : nullptr,
439 aUpdateMetadata.GetTtlConfig(), aUpdateMetadata.GetLeaseConfig());
440
441 aUpdateMetadata.Free();
442 }
443
CommitSrpUpdate(Error aError,Host & aHost,const Dns::UpdateHeader & aDnsHeader,const Ip6::MessageInfo * aMessageInfo,const TtlConfig & aTtlConfig,const LeaseConfig & aLeaseConfig)444 void Server::CommitSrpUpdate(Error aError,
445 Host &aHost,
446 const Dns::UpdateHeader &aDnsHeader,
447 const Ip6::MessageInfo *aMessageInfo,
448 const TtlConfig &aTtlConfig,
449 const LeaseConfig &aLeaseConfig)
450 {
451 Host *existingHost = nullptr;
452 uint32_t grantedTtl = 0;
453 uint32_t hostLease = 0;
454 uint32_t hostKeyLease = 0;
455 uint32_t grantedLease = 0;
456 uint32_t grantedKeyLease = 0;
457 bool useShortLease = aHost.ShouldUseShortLeaseOption();
458
459 if (aError != kErrorNone)
460 {
461 aHost.Free();
462 ExitNow();
463 }
464
465 hostLease = aHost.GetLease();
466 hostKeyLease = aHost.GetKeyLease();
467 grantedLease = aLeaseConfig.GrantLease(hostLease);
468 grantedKeyLease = useShortLease ? grantedLease : aLeaseConfig.GrantKeyLease(hostKeyLease);
469 grantedTtl = aTtlConfig.GrantTtl(grantedLease, aHost.GetTtl());
470
471 existingHost = mHosts.RemoveMatching(aHost.GetFullName());
472
473 LogInfo("Committing update for %s host %s", (existingHost != nullptr) ? "existing" : "new", aHost.GetFullName());
474 LogInfo(" Granted lease:%lu, key-lease:%lu, ttl:%lu", ToUlong(grantedLease), ToUlong(grantedKeyLease),
475 ToUlong(grantedTtl));
476
477 aHost.SetLease(grantedLease);
478 aHost.SetKeyLease(grantedKeyLease);
479 aHost.SetTtl(grantedTtl);
480
481 if (grantedKeyLease == 0)
482 {
483 VerifyOrExit(existingHost != nullptr);
484 LogInfo("Fully remove host %s", aHost.GetFullName());
485 aHost.Free();
486 ExitNow();
487 }
488
489 mHosts.Push(aHost);
490
491 for (Service &service : aHost.mServices)
492 {
493 service.mLease = grantedLease;
494 service.mKeyLease = grantedKeyLease;
495 service.mTtl = grantedTtl;
496 service.mIsCommitted = true;
497
498 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
499 {
500 Service::Action action = Service::kAddNew;
501
502 if (service.mIsDeleted)
503 {
504 action = Service::kRemoveButRetainName;
505 }
506 else if ((existingHost != nullptr) && existingHost->HasService(service.GetInstanceName()))
507 {
508 action = Service::kUpdateExisting;
509 }
510
511 service.Log(action);
512 }
513 #endif
514 }
515
516 if (existingHost != nullptr)
517 {
518 // Move any existing service that is not included in the new
519 // update into `aHost`.
520
521 Service *existingService;
522
523 while ((existingService = existingHost->mServices.Pop()) != nullptr)
524 {
525 if (!aHost.HasService(existingService->GetInstanceName()))
526 {
527 aHost.AddService(*existingService);
528 existingService->Log(Service::kKeepUnchanged);
529 }
530 else
531 {
532 existingService->Free();
533 }
534 }
535 }
536
537 #if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
538 if (!mHasRegisteredAnyService && (mAddressMode == kAddressModeUnicast))
539 {
540 Settings::SrpServerInfo info;
541
542 mHasRegisteredAnyService = true;
543 info.SetPort(GetSocket().mSockName.mPort);
544 IgnoreError(Get<Settings>().Save(info));
545 }
546 #endif
547
548 if (!aHost.IsDeleted())
549 {
550 mLeaseTimer.FireAtIfEarlier(Min(aHost.GetExpireTime(), aHost.GetKeyExpireTime()));
551 }
552
553 exit:
554 if (aMessageInfo != nullptr)
555 {
556 if (aError == kErrorNone && !(grantedLease == hostLease && grantedKeyLease == hostKeyLease))
557 {
558 SendResponse(aDnsHeader, grantedLease, grantedKeyLease, useShortLease, *aMessageInfo);
559 }
560 else
561 {
562 SendResponse(aDnsHeader, ErrorToDnsResponseCode(aError), *aMessageInfo);
563 }
564 }
565
566 if (existingHost != nullptr)
567 {
568 existingHost->Free();
569 }
570 }
571
SelectPort(void)572 void Server::SelectPort(void)
573 {
574 mPort = kUdpPortMin;
575
576 #if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
577 {
578 Settings::SrpServerInfo info;
579
580 if (Get<Settings>().Read(info) == kErrorNone)
581 {
582 mPort = info.GetPort() + 1;
583 if (mPort < kUdpPortMin || mPort > kUdpPortMax)
584 {
585 mPort = kUdpPortMin;
586 }
587 }
588 }
589 #endif
590
591 LogInfo("Selected port %u", mPort);
592 }
593
Start(void)594 void Server::Start(void)
595 {
596 VerifyOrExit(mState == kStateStopped);
597
598 mState = kStateRunning;
599 PrepareSocket();
600 LogInfo("Start listening on port %u", mPort);
601
602 exit:
603 return;
604 }
605
PrepareSocket(void)606 void Server::PrepareSocket(void)
607 {
608 Error error = kErrorNone;
609
610 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
611 Ip6::Udp::Socket &dnsSocket = Get<Dns::ServiceDiscovery::Server>().mSocket;
612
613 if (dnsSocket.GetSockName().GetPort() == mPort)
614 {
615 // If the DNS-SD socket matches our port number, we use the
616 // same socket so we close our own socket (in case it was
617 // open). `GetSocket()` will now return the DNS-SD socket.
618
619 IgnoreError(mSocket.Close());
620 ExitNow();
621 }
622 #endif
623
624 VerifyOrExit(!mSocket.IsOpen());
625 SuccessOrExit(error = mSocket.Open(HandleUdpReceive, this));
626 error = mSocket.Bind(mPort, Ip6::kNetifThread);
627
628 exit:
629 if (error != kErrorNone)
630 {
631 LogCrit("Failed to prepare socket: %s", ErrorToString(error));
632 Stop();
633 }
634 }
635
GetSocket(void)636 Ip6::Udp::Socket &Server::GetSocket(void)
637 {
638 Ip6::Udp::Socket *socket = &mSocket;
639
640 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
641 Ip6::Udp::Socket &dnsSocket = Get<Dns::ServiceDiscovery::Server>().mSocket;
642
643 if (dnsSocket.GetSockName().GetPort() == mPort)
644 {
645 socket = &dnsSocket;
646 }
647 #endif
648
649 return *socket;
650 }
651
652 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
653
HandleDnssdServerStateChange(void)654 void Server::HandleDnssdServerStateChange(void)
655 {
656 // This is called from` Dns::ServiceDiscovery::Server` to notify
657 // that it has started or stopped. We check whether we need to
658 // share the socket.
659
660 if (mState == kStateRunning)
661 {
662 PrepareSocket();
663 }
664 }
665
HandleDnssdServerUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)666 Error Server::HandleDnssdServerUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
667 {
668 // This is called from` Dns::ServiceDiscovery::Server` when a UDP
669 // message is received on its socket. We check whether we are
670 // sharing socket and if so we process the received message. We
671 // return `kErrorNone` to indicate that message was successfully
672 // processed by `Srp::Server`, otherwise `kErrorDrop` is returned.
673
674 Error error = kErrorDrop;
675
676 VerifyOrExit((mState == kStateRunning) && !mSocket.IsOpen());
677
678 error = ProcessMessage(aMessage, aMessageInfo);
679
680 exit:
681 return error;
682 }
683
684 #endif // OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
685
Stop(void)686 void Server::Stop(void)
687 {
688 VerifyOrExit(mState == kStateRunning);
689
690 mState = kStateStopped;
691
692 while (!mHosts.IsEmpty())
693 {
694 RemoveHost(mHosts.GetHead(), kDeleteName);
695 }
696
697 // TODO: We should cancel any outstanding service updates, but current
698 // OTBR mDNS publisher cannot properly handle it.
699 while (!mOutstandingUpdates.IsEmpty())
700 {
701 mOutstandingUpdates.Pop()->Free();
702 }
703
704 mLeaseTimer.Stop();
705 mOutstandingUpdatesTimer.Stop();
706
707 LogInfo("Stop listening on %u", mPort);
708 IgnoreError(mSocket.Close());
709 mHasRegisteredAnyService = false;
710
711 exit:
712 return;
713 }
714
HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent)715 void Server::HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent)
716 {
717 switch (aEvent)
718 {
719 case NetworkData::Publisher::kEventEntryAdded:
720 Start();
721 break;
722
723 case NetworkData::Publisher::kEventEntryRemoved:
724 Stop();
725 break;
726 }
727 }
728
FindOutstandingUpdate(const MessageMetadata & aMessageMetadata) const729 const Server::UpdateMetadata *Server::FindOutstandingUpdate(const MessageMetadata &aMessageMetadata) const
730 {
731 const UpdateMetadata *ret = nullptr;
732
733 VerifyOrExit(aMessageMetadata.IsDirectRxFromClient());
734
735 for (const UpdateMetadata &update : mOutstandingUpdates)
736 {
737 if (aMessageMetadata.mDnsHeader.GetMessageId() == update.GetDnsHeader().GetMessageId() &&
738 aMessageMetadata.mMessageInfo->GetPeerAddr() == update.GetMessageInfo().GetPeerAddr() &&
739 aMessageMetadata.mMessageInfo->GetPeerPort() == update.GetMessageInfo().GetPeerPort())
740 {
741 ExitNow(ret = &update);
742 }
743 }
744
745 exit:
746 return ret;
747 }
748
ProcessDnsUpdate(Message & aMessage,MessageMetadata & aMetadata)749 void Server::ProcessDnsUpdate(Message &aMessage, MessageMetadata &aMetadata)
750 {
751 Error error = kErrorNone;
752 Host *host = nullptr;
753
754 LogInfo("Received DNS update from %s", aMetadata.IsDirectRxFromClient()
755 ? aMetadata.mMessageInfo->GetPeerAddr().ToString().AsCString()
756 : "an SRPL Partner");
757
758 SuccessOrExit(error = ProcessZoneSection(aMessage, aMetadata));
759
760 if (FindOutstandingUpdate(aMetadata) != nullptr)
761 {
762 LogInfo("Drop duplicated SRP update request: MessageId=%u", aMetadata.mDnsHeader.GetMessageId());
763
764 // Silently drop duplicate requests.
765 // This could rarely happen, because the outstanding SRP update timer should
766 // be shorter than the SRP update retransmission timer.
767 ExitNow(error = kErrorNone);
768 }
769
770 // Per 2.3.2 of SRP draft 6, no prerequisites should be included in a SRP update.
771 VerifyOrExit(aMetadata.mDnsHeader.GetPrerequisiteRecordCount() == 0, error = kErrorFailed);
772
773 host = Host::Allocate(GetInstance(), aMetadata.mRxTime);
774 VerifyOrExit(host != nullptr, error = kErrorNoBufs);
775 SuccessOrExit(error = ProcessUpdateSection(*host, aMessage, aMetadata));
776
777 // Parse lease time and validate signature.
778 SuccessOrExit(error = ProcessAdditionalSection(host, aMessage, aMetadata));
779
780 HandleUpdate(*host, aMetadata);
781
782 exit:
783 if (error != kErrorNone)
784 {
785 if (host != nullptr)
786 {
787 host->Free();
788 }
789
790 if (aMetadata.IsDirectRxFromClient())
791 {
792 SendResponse(aMetadata.mDnsHeader, ErrorToDnsResponseCode(error), *aMetadata.mMessageInfo);
793 }
794 }
795 }
796
ProcessZoneSection(const Message & aMessage,MessageMetadata & aMetadata) const797 Error Server::ProcessZoneSection(const Message &aMessage, MessageMetadata &aMetadata) const
798 {
799 Error error = kErrorNone;
800 char name[Dns::Name::kMaxNameSize];
801 uint16_t offset = aMetadata.mOffset;
802
803 VerifyOrExit(aMetadata.mDnsHeader.GetZoneRecordCount() == 1, error = kErrorParse);
804
805 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name)));
806 // TODO: return `Dns::kResponseNotAuth` for not authorized zone names.
807 VerifyOrExit(StringMatch(name, GetDomain(), kStringCaseInsensitiveMatch), error = kErrorSecurity);
808 SuccessOrExit(error = aMessage.Read(offset, aMetadata.mDnsZone));
809 offset += sizeof(Dns::Zone);
810
811 VerifyOrExit(aMetadata.mDnsZone.GetType() == Dns::ResourceRecord::kTypeSoa, error = kErrorParse);
812 aMetadata.mOffset = offset;
813
814 exit:
815 if (error != kErrorNone)
816 {
817 LogWarn("Failed to process DNS Zone section: %s", ErrorToString(error));
818 }
819
820 return error;
821 }
822
ProcessUpdateSection(Host & aHost,const Message & aMessage,MessageMetadata & aMetadata) const823 Error Server::ProcessUpdateSection(Host &aHost, const Message &aMessage, MessageMetadata &aMetadata) const
824 {
825 Error error = kErrorNone;
826
827 // Process Service Discovery, Host and Service Description Instructions with
828 // 3 times iterations over all DNS update RRs. The order of those processes matters.
829
830 // 0. Enumerate over all Service Discovery Instructions before processing any other records.
831 // So that we will know whether a name is a hostname or service instance name when processing
832 // a "Delete All RRsets from a name" record.
833 SuccessOrExit(error = ProcessServiceDiscoveryInstructions(aHost, aMessage, aMetadata));
834
835 // 1. Enumerate over all RRs to build the Host Description Instruction.
836 SuccessOrExit(error = ProcessHostDescriptionInstruction(aHost, aMessage, aMetadata));
837
838 // 2. Enumerate over all RRs to build the Service Description Instructions.
839 SuccessOrExit(error = ProcessServiceDescriptionInstructions(aHost, aMessage, aMetadata));
840
841 // 3. Verify that there are no name conflicts.
842 VerifyOrExit(!HasNameConflictsWith(aHost), error = kErrorDuplicated);
843
844 exit:
845 if (error != kErrorNone)
846 {
847 LogWarn("Failed to process DNS Update section: %s", ErrorToString(error));
848 }
849
850 return error;
851 }
852
ProcessHostDescriptionInstruction(Host & aHost,const Message & aMessage,const MessageMetadata & aMetadata) const853 Error Server::ProcessHostDescriptionInstruction(Host &aHost,
854 const Message &aMessage,
855 const MessageMetadata &aMetadata) const
856 {
857 Error error = kErrorNone;
858 uint16_t offset = aMetadata.mOffset;
859
860 OT_ASSERT(aHost.GetFullName() == nullptr);
861
862 for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
863 {
864 char name[Dns::Name::kMaxNameSize];
865 Dns::ResourceRecord record;
866
867 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name)));
868
869 SuccessOrExit(error = aMessage.Read(offset, record));
870
871 if (record.GetClass() == Dns::ResourceRecord::kClassAny)
872 {
873 // Delete All RRsets from a name.
874 VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed);
875
876 // A "Delete All RRsets from a name" RR can only apply to a Service or Host Description.
877
878 if (!aHost.HasService(name))
879 {
880 // If host name is already set to a different name, `SetFullName()`
881 // will return `kErrorFailed`.
882 SuccessOrExit(error = aHost.SetFullName(name));
883 aHost.ClearResources();
884 }
885 }
886 else if (record.GetType() == Dns::ResourceRecord::kTypeAaaa)
887 {
888 Dns::AaaaRecord aaaaRecord;
889
890 VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
891
892 SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
893
894 SuccessOrExit(error = aHost.SetFullName(name));
895
896 SuccessOrExit(error = aMessage.Read(offset, aaaaRecord));
897 VerifyOrExit(aaaaRecord.IsValid(), error = kErrorParse);
898
899 // Tolerate kErrorDrop for AAAA Resources.
900 VerifyOrExit(aHost.AddIp6Address(aaaaRecord.GetAddress()) != kErrorNoBufs, error = kErrorNoBufs);
901 }
902 else if (record.GetType() == Dns::ResourceRecord::kTypeKey)
903 {
904 // We currently support only ECDSA P-256.
905 Dns::Ecdsa256KeyRecord keyRecord;
906
907 VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
908
909 SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
910
911 SuccessOrExit(error = aMessage.Read(offset, keyRecord));
912 VerifyOrExit(keyRecord.IsValid(), error = kErrorParse);
913
914 if (aHost.mParsedKey)
915 {
916 VerifyOrExit(aHost.mKey == keyRecord.GetKey(), error = kErrorSecurity);
917 }
918 else
919 {
920 aHost.mParsedKey = true;
921 aHost.mKey = keyRecord.GetKey();
922 }
923 }
924
925 offset += record.GetSize();
926 }
927
928 // Verify that we have a complete Host Description Instruction.
929
930 VerifyOrExit(aHost.GetFullName() != nullptr, error = kErrorFailed);
931 VerifyOrExit(aHost.mParsedKey, error = kErrorFailed);
932
933 // We check the number of host addresses after processing of the
934 // Lease Option in the Addition Section and determining whether
935 // the host is being removed or registered.
936
937 exit:
938 if (error != kErrorNone)
939 {
940 LogWarn("Failed to process Host Description instructions: %s", ErrorToString(error));
941 }
942
943 return error;
944 }
945
ProcessServiceDiscoveryInstructions(Host & aHost,const Message & aMessage,const MessageMetadata & aMetadata) const946 Error Server::ProcessServiceDiscoveryInstructions(Host &aHost,
947 const Message &aMessage,
948 const MessageMetadata &aMetadata) const
949 {
950 Error error = kErrorNone;
951 uint16_t offset = aMetadata.mOffset;
952
953 for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
954 {
955 char serviceName[Dns::Name::kMaxNameSize];
956 char instanceLabel[Dns::Name::kMaxLabelSize];
957 char instanceServiceName[Dns::Name::kMaxNameSize];
958 String<Dns::Name::kMaxNameSize> instanceName;
959 Dns::PtrRecord ptrRecord;
960 const char *subServiceName;
961 Service *service;
962 bool isSubType;
963 bool isDelete;
964
965 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, serviceName, sizeof(serviceName)));
966 VerifyOrExit(Dns::Name::IsSubDomainOf(serviceName, GetDomain()), error = kErrorSecurity);
967
968 error = Dns::ResourceRecord::ReadRecord(aMessage, offset, ptrRecord);
969
970 if (error == kErrorNotFound)
971 {
972 // `ReadRecord()` updates `aOffset` to skip over a
973 // non-matching record.
974 error = kErrorNone;
975 continue;
976 }
977
978 SuccessOrExit(error);
979
980 SuccessOrExit(error = ptrRecord.ReadPtrName(aMessage, offset, instanceLabel, sizeof(instanceLabel),
981 instanceServiceName, sizeof(instanceServiceName)));
982 instanceName.Append("%s.%s", instanceLabel, instanceServiceName);
983
984 // Class None indicates "Delete an RR from an RRset".
985 isDelete = (ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone);
986
987 VerifyOrExit(isDelete || ptrRecord.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorParse);
988
989 // Check if the `serviceName` is a sub-type with name
990 // format: "<sub-label>._sub.<service-labels>.<domain>."
991
992 subServiceName = StringFind(serviceName, kServiceSubTypeLabel, kStringCaseInsensitiveMatch);
993 isSubType = (subServiceName != nullptr);
994
995 if (isSubType)
996 {
997 // Skip over the "._sub." label to get to the base
998 // service name.
999 subServiceName += sizeof(kServiceSubTypeLabel) - 1;
1000 }
1001
1002 // Verify that instance name and service name are related.
1003 VerifyOrExit(Dns::Name::IsSubDomainOf(instanceName.AsCString(), isSubType ? subServiceName : serviceName),
1004 error = kErrorFailed);
1005
1006 // Find a matching existing service or allocate a new one.
1007
1008 service = aHost.FindService(instanceName.AsCString());
1009
1010 if (service == nullptr)
1011 {
1012 service = aHost.AddNewService(instanceName.AsCString(), instanceLabel, aMetadata.mRxTime);
1013 VerifyOrExit(service != nullptr, error = kErrorNoBufs);
1014 }
1015
1016 if (isSubType)
1017 {
1018 VerifyOrExit(!service->HasSubTypeServiceName(serviceName), error = kErrorFailed);
1019
1020 // Ignore a sub-type service delete.
1021
1022 if (!isDelete)
1023 {
1024 Heap::String *newSubTypeLabel = service->mSubTypes.PushBack();
1025
1026 VerifyOrExit(newSubTypeLabel != nullptr, error = kErrorNoBufs);
1027 SuccessOrExit(error = newSubTypeLabel->Set(serviceName));
1028 }
1029 }
1030 else
1031 {
1032 // Processed PTR record is the base service (not a
1033 // sub-type). `mServiceName` is only set when base
1034 // service is processed.
1035
1036 VerifyOrExit(service->mServiceName.IsNull(), error = kErrorFailed);
1037 SuccessOrExit(error = service->mServiceName.Set(serviceName));
1038 service->mIsDeleted = isDelete;
1039 }
1040
1041 if (!isDelete)
1042 {
1043 SuccessOrExit(error = aHost.ProcessTtl(ptrRecord.GetTtl()));
1044 }
1045 }
1046
1047 // Verify that for all services, a PTR record was processed for
1048 // the base service (`mServiceName` is set), and for a deleted
1049 // service, no PTR record was seen adding a sub-type.
1050
1051 for (const Service &service : aHost.mServices)
1052 {
1053 VerifyOrExit(!service.mServiceName.IsNull(), error = kErrorParse);
1054
1055 if (service.mIsDeleted)
1056 {
1057 VerifyOrExit(service.mSubTypes.GetLength() == 0, error = kErrorParse);
1058 }
1059 }
1060
1061 exit:
1062 if (error != kErrorNone)
1063 {
1064 LogWarn("Failed to process Service Discovery instructions: %s", ErrorToString(error));
1065 }
1066
1067 return error;
1068 }
1069
ProcessServiceDescriptionInstructions(Host & aHost,const Message & aMessage,MessageMetadata & aMetadata) const1070 Error Server::ProcessServiceDescriptionInstructions(Host &aHost,
1071 const Message &aMessage,
1072 MessageMetadata &aMetadata) const
1073 {
1074 Error error = kErrorNone;
1075 uint16_t offset = aMetadata.mOffset;
1076
1077 for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
1078 {
1079 char name[Dns::Name::kMaxNameSize];
1080 Dns::ResourceRecord record;
1081 Service *service;
1082
1083 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name)));
1084 SuccessOrExit(error = aMessage.Read(offset, record));
1085
1086 if (record.GetClass() == Dns::ResourceRecord::kClassAny)
1087 {
1088 // Delete All RRsets from a name.
1089 VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed);
1090
1091 service = aHost.FindService(name);
1092
1093 if (service != nullptr)
1094 {
1095 VerifyOrExit(!service->mParsedDeleteAllRrset);
1096 service->mParsedDeleteAllRrset = true;
1097 }
1098
1099 offset += record.GetSize();
1100 continue;
1101 }
1102
1103 if (record.GetType() == Dns::ResourceRecord::kTypeSrv)
1104 {
1105 Dns::SrvRecord srvRecord;
1106 char hostName[Dns::Name::kMaxNameSize];
1107 uint16_t hostNameLength = sizeof(hostName);
1108
1109 VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
1110
1111 SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
1112
1113 SuccessOrExit(error = aMessage.Read(offset, srvRecord));
1114 offset += sizeof(srvRecord);
1115
1116 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, hostName, hostNameLength));
1117 VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = kErrorSecurity);
1118 VerifyOrExit(aHost.Matches(hostName), error = kErrorFailed);
1119
1120 service = aHost.FindService(name);
1121 VerifyOrExit(service != nullptr, error = kErrorFailed);
1122
1123 VerifyOrExit(!service->mParsedSrv, error = kErrorParse);
1124 service->mParsedSrv = true;
1125
1126 service->mTtl = srvRecord.GetTtl();
1127 service->mPriority = srvRecord.GetPriority();
1128 service->mWeight = srvRecord.GetWeight();
1129 service->mPort = srvRecord.GetPort();
1130 }
1131 else if (record.GetType() == Dns::ResourceRecord::kTypeTxt)
1132 {
1133 VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
1134
1135 SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
1136
1137 service = aHost.FindService(name);
1138 VerifyOrExit(service != nullptr, error = kErrorFailed);
1139
1140 service->mParsedTxt = true;
1141
1142 offset += sizeof(record);
1143 SuccessOrExit(error = service->SetTxtDataFromMessage(aMessage, offset, record.GetLength()));
1144 offset += record.GetLength();
1145 }
1146 else
1147 {
1148 offset += record.GetSize();
1149 }
1150 }
1151
1152 for (const Service &service : aHost.mServices)
1153 {
1154 VerifyOrExit(service.mParsedDeleteAllRrset, error = kErrorFailed);
1155 VerifyOrExit(service.mParsedSrv == service.mParsedTxt, error = kErrorFailed);
1156
1157 if (!service.mIsDeleted)
1158 {
1159 VerifyOrExit(service.mParsedSrv, error = kErrorFailed);
1160 }
1161 }
1162
1163 aMetadata.mOffset = offset;
1164
1165 exit:
1166 if (error != kErrorNone)
1167 {
1168 LogWarn("Failed to process Service Description instructions: %s", ErrorToString(error));
1169 }
1170
1171 return error;
1172 }
1173
IsValidDeleteAllRecord(const Dns::ResourceRecord & aRecord)1174 bool Server::IsValidDeleteAllRecord(const Dns::ResourceRecord &aRecord)
1175 {
1176 return aRecord.GetClass() == Dns::ResourceRecord::kClassAny && aRecord.GetType() == Dns::ResourceRecord::kTypeAny &&
1177 aRecord.GetTtl() == 0 && aRecord.GetLength() == 0;
1178 }
1179
ProcessAdditionalSection(Host * aHost,const Message & aMessage,MessageMetadata & aMetadata) const1180 Error Server::ProcessAdditionalSection(Host *aHost, const Message &aMessage, MessageMetadata &aMetadata) const
1181 {
1182 Error error = kErrorNone;
1183 Dns::OptRecord optRecord;
1184 Dns::LeaseOption leaseOption;
1185 Dns::SigRecord sigRecord;
1186 char name[2]; // The root domain name (".") is expected.
1187 uint16_t offset = aMetadata.mOffset;
1188 uint16_t sigOffset;
1189 uint16_t sigRdataOffset;
1190 char signerName[Dns::Name::kMaxNameSize];
1191 uint16_t signatureLength;
1192
1193 VerifyOrExit(aMetadata.mDnsHeader.GetAdditionalRecordCount() == 2, error = kErrorFailed);
1194
1195 // EDNS(0) Update Lease Option.
1196
1197 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name)));
1198 SuccessOrExit(error = aMessage.Read(offset, optRecord));
1199
1200 SuccessOrExit(error = leaseOption.ReadFrom(aMessage, offset + sizeof(optRecord), optRecord.GetLength()));
1201
1202 offset += optRecord.GetSize();
1203
1204 aHost->SetLease(leaseOption.GetLeaseInterval());
1205 aHost->SetKeyLease(leaseOption.GetKeyLeaseInterval());
1206
1207 // If the client included the short variant of Lease Option,
1208 // server must also use the short variant in its response.
1209 aHost->SetUseShortLeaseOption(leaseOption.IsShortVariant());
1210
1211 if (aHost->GetLease() > 0)
1212 {
1213 uint8_t hostAddressesNum;
1214
1215 aHost->GetAddresses(hostAddressesNum);
1216
1217 // There MUST be at least one valid address if we have nonzero lease.
1218 VerifyOrExit(hostAddressesNum > 0, error = kErrorFailed);
1219 }
1220
1221 // SIG(0).
1222
1223 sigOffset = offset;
1224 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name)));
1225 SuccessOrExit(error = aMessage.Read(offset, sigRecord));
1226 VerifyOrExit(sigRecord.IsValid(), error = kErrorParse);
1227
1228 sigRdataOffset = offset + sizeof(Dns::ResourceRecord);
1229 offset += sizeof(sigRecord);
1230
1231 // TODO: Verify that the signature doesn't expire. This is not
1232 // implemented because the end device may not be able to get
1233 // the synchronized date/time.
1234
1235 SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, signerName, sizeof(signerName)));
1236
1237 signatureLength = sigRecord.GetLength() - (offset - sigRdataOffset);
1238 offset += signatureLength;
1239
1240 // Verify the signature. Currently supports only ECDSA.
1241
1242 VerifyOrExit(sigRecord.GetAlgorithm() == Dns::KeyRecord::kAlgorithmEcdsaP256Sha256, error = kErrorFailed);
1243 VerifyOrExit(sigRecord.GetTypeCovered() == 0, error = kErrorFailed);
1244 VerifyOrExit(signatureLength == Crypto::Ecdsa::P256::Signature::kSize, error = kErrorParse);
1245
1246 SuccessOrExit(error = VerifySignature(aHost->mKey, aMessage, aMetadata.mDnsHeader, sigOffset, sigRdataOffset,
1247 sigRecord.GetLength(), signerName));
1248
1249 aMetadata.mOffset = offset;
1250
1251 exit:
1252 if (error != kErrorNone)
1253 {
1254 LogWarn("Failed to process DNS Additional section: %s", ErrorToString(error));
1255 }
1256
1257 return error;
1258 }
1259
VerifySignature(const Host::Key & aKey,const Message & aMessage,Dns::UpdateHeader aDnsHeader,uint16_t aSigOffset,uint16_t aSigRdataOffset,uint16_t aSigRdataLength,const char * aSignerName) const1260 Error Server::VerifySignature(const Host::Key &aKey,
1261 const Message &aMessage,
1262 Dns::UpdateHeader aDnsHeader,
1263 uint16_t aSigOffset,
1264 uint16_t aSigRdataOffset,
1265 uint16_t aSigRdataLength,
1266 const char *aSignerName) const
1267 {
1268 Error error;
1269 uint16_t offset = aMessage.GetOffset();
1270 uint16_t signatureOffset;
1271 Crypto::Sha256 sha256;
1272 Crypto::Sha256::Hash hash;
1273 Crypto::Ecdsa::P256::Signature signature;
1274 Message *signerNameMessage = nullptr;
1275
1276 VerifyOrExit(aSigRdataLength >= Crypto::Ecdsa::P256::Signature::kSize, error = kErrorInvalidArgs);
1277
1278 sha256.Start();
1279
1280 // SIG RDATA less signature.
1281 sha256.Update(aMessage, aSigRdataOffset, sizeof(Dns::SigRecord) - sizeof(Dns::ResourceRecord));
1282
1283 // The uncompressed (canonical) form of the signer name should be used for signature
1284 // verification. See https://tools.ietf.org/html/rfc2931#section-3.1 for details.
1285 signerNameMessage = Get<Ip6::Udp>().NewMessage();
1286 VerifyOrExit(signerNameMessage != nullptr, error = kErrorNoBufs);
1287 SuccessOrExit(error = Dns::Name::AppendName(aSignerName, *signerNameMessage));
1288 sha256.Update(*signerNameMessage, signerNameMessage->GetOffset(), signerNameMessage->GetLength());
1289
1290 // We need the DNS header before appending the SIG RR.
1291 aDnsHeader.SetAdditionalRecordCount(aDnsHeader.GetAdditionalRecordCount() - 1);
1292 sha256.Update(aDnsHeader);
1293 sha256.Update(aMessage, offset + sizeof(aDnsHeader), aSigOffset - offset - sizeof(aDnsHeader));
1294
1295 sha256.Finish(hash);
1296
1297 signatureOffset = aSigRdataOffset + aSigRdataLength - Crypto::Ecdsa::P256::Signature::kSize;
1298 SuccessOrExit(error = aMessage.Read(signatureOffset, signature));
1299
1300 error = aKey.Verify(hash, signature);
1301
1302 exit:
1303 if (error != kErrorNone)
1304 {
1305 LogWarn("Failed to verify message signature: %s", ErrorToString(error));
1306 }
1307
1308 FreeMessage(signerNameMessage);
1309 return error;
1310 }
1311
HandleUpdate(Host & aHost,const MessageMetadata & aMetadata)1312 void Server::HandleUpdate(Host &aHost, const MessageMetadata &aMetadata)
1313 {
1314 Error error = kErrorNone;
1315 Host *existingHost;
1316
1317 // Check whether the SRP update wants to remove `aHost`.
1318
1319 VerifyOrExit(aHost.GetLease() == 0);
1320
1321 aHost.ClearResources();
1322
1323 existingHost = mHosts.FindMatching(aHost.GetFullName());
1324 VerifyOrExit(existingHost != nullptr);
1325
1326 // The client may not include all services it has registered before
1327 // when removing a host. We copy and append any missing services to
1328 // `aHost` from the `existingHost` and mark them as deleted.
1329
1330 for (const Service &existingService : existingHost->mServices)
1331 {
1332 Service *service;
1333
1334 if (existingService.mIsDeleted || aHost.HasService(existingService.GetInstanceName()))
1335 {
1336 continue;
1337 }
1338
1339 service = aHost.AddNewService(existingService.GetInstanceName(), existingService.GetInstanceLabel(),
1340 aMetadata.mRxTime);
1341 VerifyOrExit(service != nullptr, error = kErrorNoBufs);
1342
1343 SuccessOrExit(error = service->mServiceName.Set(existingService.GetServiceName()));
1344 service->mIsDeleted = true;
1345 }
1346
1347 exit:
1348 InformUpdateHandlerOrCommit(error, aHost, aMetadata);
1349 }
1350
InformUpdateHandlerOrCommit(Error aError,Host & aHost,const MessageMetadata & aMetadata)1351 void Server::InformUpdateHandlerOrCommit(Error aError, Host &aHost, const MessageMetadata &aMetadata)
1352 {
1353 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1354 if (aError == kErrorNone)
1355 {
1356 uint8_t numAddrs;
1357 const Ip6::Address *addrs;
1358
1359 LogInfo("Processed SRP update info");
1360 LogInfo(" Host:%s", aHost.GetFullName());
1361 LogInfo(" Lease:%lu, key-lease:%lu, ttl:%lu", ToUlong(aHost.GetLease()), ToUlong(aHost.GetKeyLease()),
1362 ToUlong(aHost.GetTtl()));
1363
1364 addrs = aHost.GetAddresses(numAddrs);
1365
1366 if (numAddrs == 0)
1367 {
1368 LogInfo(" No host address");
1369 }
1370 else
1371 {
1372 LogInfo(" %d host address(es):", numAddrs);
1373
1374 for (; numAddrs > 0; addrs++, numAddrs--)
1375 {
1376 LogInfo(" %s", addrs->ToString().AsCString());
1377 }
1378 }
1379
1380 for (const Service &service : aHost.mServices)
1381 {
1382 LogInfo(" %s service '%s'", service.IsDeleted() ? "Deleting" : "Adding", service.GetInstanceName());
1383
1384 for (const Heap::String &subType : service.mSubTypes)
1385 {
1386 char label[Dns::Name::kMaxLabelSize];
1387
1388 IgnoreError(Service::ParseSubTypeServiceName(subType.AsCString(), label, sizeof(label)));
1389 LogInfo(" sub-type: %s", label);
1390 }
1391 }
1392 }
1393 else
1394 {
1395 LogInfo("Error %s processing received SRP update", ErrorToString(aError));
1396 }
1397 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1398
1399 if ((aError == kErrorNone) && mServiceUpdateHandler.IsSet())
1400 {
1401 UpdateMetadata *update = UpdateMetadata::Allocate(GetInstance(), aHost, aMetadata);
1402
1403 if (update != nullptr)
1404 {
1405 mOutstandingUpdates.Push(*update);
1406 mOutstandingUpdatesTimer.FireAtIfEarlier(update->GetExpireTime());
1407
1408 LogInfo("SRP update handler is notified (updatedId = %lu)", ToUlong(update->GetId()));
1409 mServiceUpdateHandler.Invoke(update->GetId(), &aHost, static_cast<uint32_t>(kDefaultEventsHandlerTimeout));
1410 ExitNow();
1411 }
1412
1413 aError = kErrorNoBufs;
1414 }
1415
1416 CommitSrpUpdate(aError, aHost, aMetadata);
1417
1418 exit:
1419 return;
1420 }
1421
SendResponse(const Dns::UpdateHeader & aHeader,Dns::UpdateHeader::Response aResponseCode,const Ip6::MessageInfo & aMessageInfo)1422 void Server::SendResponse(const Dns::UpdateHeader &aHeader,
1423 Dns::UpdateHeader::Response aResponseCode,
1424 const Ip6::MessageInfo &aMessageInfo)
1425 {
1426 Error error;
1427 Message *response = nullptr;
1428 Dns::UpdateHeader header;
1429
1430 response = GetSocket().NewMessage();
1431 VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1432
1433 header.SetMessageId(aHeader.GetMessageId());
1434 header.SetType(Dns::UpdateHeader::kTypeResponse);
1435 header.SetQueryType(aHeader.GetQueryType());
1436 header.SetResponseCode(aResponseCode);
1437 SuccessOrExit(error = response->Append(header));
1438
1439 SuccessOrExit(error = GetSocket().SendTo(*response, aMessageInfo));
1440
1441 if (aResponseCode != Dns::UpdateHeader::kResponseSuccess)
1442 {
1443 LogWarn("Send fail response: %d", aResponseCode);
1444 }
1445 else
1446 {
1447 LogInfo("Send success response");
1448 }
1449
1450 UpdateResponseCounters(aResponseCode);
1451
1452 exit:
1453 if (error != kErrorNone)
1454 {
1455 LogWarn("Failed to send response: %s", ErrorToString(error));
1456 FreeMessage(response);
1457 }
1458 }
1459
SendResponse(const Dns::UpdateHeader & aHeader,uint32_t aLease,uint32_t aKeyLease,bool mUseShortLeaseOption,const Ip6::MessageInfo & aMessageInfo)1460 void Server::SendResponse(const Dns::UpdateHeader &aHeader,
1461 uint32_t aLease,
1462 uint32_t aKeyLease,
1463 bool mUseShortLeaseOption,
1464 const Ip6::MessageInfo &aMessageInfo)
1465 {
1466 Error error;
1467 Message *response = nullptr;
1468 Dns::UpdateHeader header;
1469 Dns::OptRecord optRecord;
1470 Dns::LeaseOption leaseOption;
1471 uint16_t optionSize;
1472
1473 response = GetSocket().NewMessage();
1474 VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1475
1476 header.SetMessageId(aHeader.GetMessageId());
1477 header.SetType(Dns::UpdateHeader::kTypeResponse);
1478 header.SetQueryType(aHeader.GetQueryType());
1479 header.SetResponseCode(Dns::UpdateHeader::kResponseSuccess);
1480 header.SetAdditionalRecordCount(1);
1481 SuccessOrExit(error = response->Append(header));
1482
1483 // Append the root domain (".").
1484 SuccessOrExit(error = Dns::Name::AppendTerminator(*response));
1485
1486 optRecord.Init();
1487 optRecord.SetUdpPayloadSize(kUdpPayloadSize);
1488 optRecord.SetDnsSecurityFlag();
1489
1490 if (mUseShortLeaseOption)
1491 {
1492 leaseOption.InitAsShortVariant(aLease);
1493 }
1494 else
1495 {
1496 leaseOption.InitAsLongVariant(aLease, aKeyLease);
1497 }
1498
1499 optionSize = static_cast<uint16_t>(leaseOption.GetSize());
1500 optRecord.SetLength(optionSize);
1501
1502 SuccessOrExit(error = response->Append(optRecord));
1503 SuccessOrExit(error = response->AppendBytes(&leaseOption, optionSize));
1504
1505 SuccessOrExit(error = GetSocket().SendTo(*response, aMessageInfo));
1506
1507 LogInfo("Send success response with granted lease: %lu and key lease: %lu", ToUlong(aLease), ToUlong(aKeyLease));
1508
1509 UpdateResponseCounters(Dns::UpdateHeader::kResponseSuccess);
1510
1511 exit:
1512 if (error != kErrorNone)
1513 {
1514 LogWarn("Failed to send response: %s", ErrorToString(error));
1515 FreeMessage(response);
1516 }
1517 }
1518
HandleUdpReceive(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)1519 void Server::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
1520 {
1521 static_cast<Server *>(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo));
1522 }
1523
HandleUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1524 void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1525 {
1526 Error error = ProcessMessage(aMessage, aMessageInfo);
1527
1528 if (error != kErrorNone)
1529 {
1530 LogInfo("Failed to handle DNS message: %s", ErrorToString(error));
1531 }
1532 }
1533
ProcessMessage(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1534 Error Server::ProcessMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1535 {
1536 return ProcessMessage(aMessage, TimerMilli::GetNow(), mTtlConfig, mLeaseConfig, &aMessageInfo);
1537 }
1538
ProcessMessage(Message & aMessage,TimeMilli aRxTime,const TtlConfig & aTtlConfig,const LeaseConfig & aLeaseConfig,const Ip6::MessageInfo * aMessageInfo)1539 Error Server::ProcessMessage(Message &aMessage,
1540 TimeMilli aRxTime,
1541 const TtlConfig &aTtlConfig,
1542 const LeaseConfig &aLeaseConfig,
1543 const Ip6::MessageInfo *aMessageInfo)
1544 {
1545 Error error;
1546 MessageMetadata metadata;
1547
1548 metadata.mOffset = aMessage.GetOffset();
1549 metadata.mRxTime = aRxTime;
1550 metadata.mTtlConfig = aTtlConfig;
1551 metadata.mLeaseConfig = aLeaseConfig;
1552 metadata.mMessageInfo = aMessageInfo;
1553
1554 SuccessOrExit(error = aMessage.Read(metadata.mOffset, metadata.mDnsHeader));
1555 metadata.mOffset += sizeof(Dns::UpdateHeader);
1556
1557 VerifyOrExit(metadata.mDnsHeader.GetType() == Dns::UpdateHeader::Type::kTypeQuery, error = kErrorDrop);
1558 VerifyOrExit(metadata.mDnsHeader.GetQueryType() == Dns::UpdateHeader::kQueryTypeUpdate, error = kErrorDrop);
1559
1560 ProcessDnsUpdate(aMessage, metadata);
1561
1562 exit:
1563 return error;
1564 }
1565
HandleLeaseTimer(void)1566 void Server::HandleLeaseTimer(void)
1567 {
1568 TimeMilli now = TimerMilli::GetNow();
1569 TimeMilli earliestExpireTime = now.GetDistantFuture();
1570 Host *nextHost;
1571
1572 for (Host *host = mHosts.GetHead(); host != nullptr; host = nextHost)
1573 {
1574 nextHost = host->GetNext();
1575
1576 if (host->GetKeyExpireTime() <= now)
1577 {
1578 LogInfo("KEY LEASE of host %s expired", host->GetFullName());
1579
1580 // Removes the whole host and all services if the KEY RR expired.
1581 RemoveHost(host, kDeleteName);
1582 }
1583 else if (host->IsDeleted())
1584 {
1585 // The host has been deleted, but the hostname & service instance names retain.
1586
1587 Service *next;
1588
1589 earliestExpireTime = Min(earliestExpireTime, host->GetKeyExpireTime());
1590
1591 // Check if any service instance name expired.
1592 for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1593 {
1594 next = service->GetNext();
1595
1596 OT_ASSERT(service->mIsDeleted);
1597
1598 if (service->GetKeyExpireTime() <= now)
1599 {
1600 service->Log(Service::kKeyLeaseExpired);
1601 host->RemoveService(service, kDeleteName, kNotifyServiceHandler);
1602 }
1603 else
1604 {
1605 earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1606 }
1607 }
1608 }
1609 else if (host->GetExpireTime() <= now)
1610 {
1611 LogInfo("LEASE of host %s expired", host->GetFullName());
1612
1613 // If the host expired, delete all resources of this host and its services.
1614 for (Service &service : host->mServices)
1615 {
1616 // Don't need to notify the service handler as `RemoveHost` at below will do.
1617 host->RemoveService(&service, kRetainName, kDoNotNotifyServiceHandler);
1618 }
1619
1620 RemoveHost(host, kRetainName);
1621
1622 earliestExpireTime = Min(earliestExpireTime, host->GetKeyExpireTime());
1623 }
1624 else
1625 {
1626 // The host doesn't expire, check if any service expired or is explicitly removed.
1627
1628 Service *next;
1629
1630 OT_ASSERT(!host->IsDeleted());
1631
1632 earliestExpireTime = Min(earliestExpireTime, host->GetExpireTime());
1633
1634 for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1635 {
1636 next = service->GetNext();
1637
1638 if (service->GetKeyExpireTime() <= now)
1639 {
1640 service->Log(Service::kKeyLeaseExpired);
1641 host->RemoveService(service, kDeleteName, kNotifyServiceHandler);
1642 }
1643 else if (service->mIsDeleted)
1644 {
1645 // The service has been deleted but the name retains.
1646 earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1647 }
1648 else if (service->GetExpireTime() <= now)
1649 {
1650 service->Log(Service::kLeaseExpired);
1651
1652 // The service is expired, delete it.
1653 host->RemoveService(service, kRetainName, kNotifyServiceHandler);
1654 earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1655 }
1656 else
1657 {
1658 earliestExpireTime = Min(earliestExpireTime, service->GetExpireTime());
1659 }
1660 }
1661 }
1662 }
1663
1664 if (earliestExpireTime != now.GetDistantFuture())
1665 {
1666 OT_ASSERT(earliestExpireTime >= now);
1667 if (!mLeaseTimer.IsRunning() || earliestExpireTime <= mLeaseTimer.GetFireTime())
1668 {
1669 LogInfo("Lease timer is scheduled for %lu seconds", ToUlong(Time::MsecToSec(earliestExpireTime - now)));
1670 mLeaseTimer.StartAt(earliestExpireTime, 0);
1671 }
1672 }
1673 else
1674 {
1675 LogInfo("Lease timer is stopped");
1676 mLeaseTimer.Stop();
1677 }
1678 }
1679
HandleOutstandingUpdatesTimer(void)1680 void Server::HandleOutstandingUpdatesTimer(void)
1681 {
1682 TimeMilli now = TimerMilli::GetNow();
1683 UpdateMetadata *update;
1684
1685 while ((update = mOutstandingUpdates.GetTail()) != nullptr)
1686 {
1687 if (update->GetExpireTime() > now)
1688 {
1689 mOutstandingUpdatesTimer.FireAtIfEarlier(update->GetExpireTime());
1690 break;
1691 }
1692
1693 LogInfo("Outstanding service update timeout (updateId = %lu)", ToUlong(update->GetId()));
1694
1695 IgnoreError(mOutstandingUpdates.Remove(*update));
1696 update->SetError(kErrorResponseTimeout);
1697 CommitSrpUpdate(*update);
1698 }
1699 }
1700
AddressModeToString(AddressMode aMode)1701 const char *Server::AddressModeToString(AddressMode aMode)
1702 {
1703 static const char *const kAddressModeStrings[] = {
1704 "unicast", // (0) kAddressModeUnicast
1705 "anycast", // (1) kAddressModeAnycast
1706 };
1707
1708 static_assert(kAddressModeUnicast == 0, "kAddressModeUnicast value is incorrect");
1709 static_assert(kAddressModeAnycast == 1, "kAddressModeAnycast value is incorrect");
1710
1711 return kAddressModeStrings[aMode];
1712 }
1713
UpdateResponseCounters(Dns::UpdateHeader::Response aResponseCode)1714 void Server::UpdateResponseCounters(Dns::UpdateHeader::Response aResponseCode)
1715 {
1716 switch (aResponseCode)
1717 {
1718 case Dns::UpdateHeader::kResponseSuccess:
1719 ++mResponseCounters.mSuccess;
1720 break;
1721 case Dns::UpdateHeader::kResponseServerFailure:
1722 ++mResponseCounters.mServerFailure;
1723 break;
1724 case Dns::UpdateHeader::kResponseFormatError:
1725 ++mResponseCounters.mFormatError;
1726 break;
1727 case Dns::UpdateHeader::kResponseNameExists:
1728 ++mResponseCounters.mNameExists;
1729 break;
1730 case Dns::UpdateHeader::kResponseRefused:
1731 ++mResponseCounters.mRefused;
1732 break;
1733 default:
1734 ++mResponseCounters.mOther;
1735 break;
1736 }
1737 }
1738
1739 //---------------------------------------------------------------------------------------------------------------------
1740 // Server::Service
1741
Init(const char * aInstanceName,const char * aInstanceLabel,Host & aHost,TimeMilli aUpdateTime)1742 Error Server::Service::Init(const char *aInstanceName, const char *aInstanceLabel, Host &aHost, TimeMilli aUpdateTime)
1743 {
1744 Error error;
1745
1746 mNext = nullptr;
1747 mHost = &aHost;
1748 mPriority = 0;
1749 mWeight = 0;
1750 mTtl = 0;
1751 mPort = 0;
1752 mLease = 0;
1753 mKeyLease = 0;
1754 mUpdateTime = aUpdateTime;
1755 mIsDeleted = false;
1756 mIsCommitted = false;
1757
1758 mParsedDeleteAllRrset = false;
1759 mParsedSrv = false;
1760 mParsedTxt = false;
1761
1762 SuccessOrExit(error = mInstanceLabel.Set(aInstanceLabel));
1763 error = mInstanceName.Set(aInstanceName);
1764
1765 exit:
1766 return error;
1767 }
1768
GetSubTypeServiceNameAt(uint16_t aIndex) const1769 const char *Server::Service::GetSubTypeServiceNameAt(uint16_t aIndex) const
1770 {
1771 const Heap::String *subType = mSubTypes.At(aIndex);
1772
1773 return (subType == nullptr) ? nullptr : subType->AsCString();
1774 }
1775
ParseSubTypeServiceName(const char * aSubTypeServiceName,char * aLabel,uint8_t aLabelSize)1776 Error Server::Service::ParseSubTypeServiceName(const char *aSubTypeServiceName, char *aLabel, uint8_t aLabelSize)
1777 {
1778 Error error = kErrorNone;
1779 const char *subPos;
1780 uint8_t labelLength;
1781
1782 aLabel[0] = kNullChar;
1783
1784 subPos = StringFind(aSubTypeServiceName, kServiceSubTypeLabel, kStringCaseInsensitiveMatch);
1785 VerifyOrExit(subPos != nullptr, error = kErrorInvalidArgs);
1786
1787 if (subPos - aSubTypeServiceName < aLabelSize)
1788 {
1789 labelLength = static_cast<uint8_t>(subPos - aSubTypeServiceName);
1790 }
1791 else
1792 {
1793 labelLength = aLabelSize - 1;
1794 error = kErrorNoBufs;
1795 }
1796
1797 memcpy(aLabel, aSubTypeServiceName, labelLength);
1798 aLabel[labelLength] = kNullChar;
1799
1800 exit:
1801 return error;
1802 }
1803
GetExpireTime(void) const1804 TimeMilli Server::Service::GetExpireTime(void) const
1805 {
1806 OT_ASSERT(!mIsDeleted);
1807 OT_ASSERT(!GetHost().IsDeleted());
1808
1809 return mUpdateTime + Time::SecToMsec(mLease);
1810 }
1811
GetKeyExpireTime(void) const1812 TimeMilli Server::Service::GetKeyExpireTime(void) const { return mUpdateTime + Time::SecToMsec(mKeyLease); }
1813
GetLeaseInfo(LeaseInfo & aLeaseInfo) const1814 void Server::Service::GetLeaseInfo(LeaseInfo &aLeaseInfo) const
1815 {
1816 TimeMilli now = TimerMilli::GetNow();
1817 TimeMilli keyExpireTime = GetKeyExpireTime();
1818
1819 aLeaseInfo.mLease = Time::SecToMsec(GetLease());
1820 aLeaseInfo.mKeyLease = Time::SecToMsec(GetKeyLease());
1821 aLeaseInfo.mRemainingKeyLease = (now <= keyExpireTime) ? (keyExpireTime - now) : 0;
1822
1823 if (!mIsDeleted)
1824 {
1825 TimeMilli expireTime = GetExpireTime();
1826
1827 aLeaseInfo.mRemainingLease = (now <= expireTime) ? (expireTime - now) : 0;
1828 }
1829 else
1830 {
1831 aLeaseInfo.mRemainingLease = 0;
1832 }
1833 }
1834
MatchesInstanceName(const char * aInstanceName) const1835 bool Server::Service::MatchesInstanceName(const char *aInstanceName) const { return Matches(aInstanceName); }
1836
MatchesServiceName(const char * aServiceName) const1837 bool Server::Service::MatchesServiceName(const char *aServiceName) const
1838 {
1839 return StringMatch(mServiceName.AsCString(), aServiceName, kStringCaseInsensitiveMatch);
1840 }
1841
Matches(const char * aInstanceName) const1842 bool Server::Service::Matches(const char *aInstanceName) const
1843 {
1844 return StringMatch(mInstanceName.AsCString(), aInstanceName, kStringCaseInsensitiveMatch);
1845 }
1846
HasSubTypeServiceName(const char * aSubTypeServiceName) const1847 bool Server::Service::HasSubTypeServiceName(const char *aSubTypeServiceName) const
1848 {
1849 bool has = false;
1850
1851 for (const Heap::String &subType : mSubTypes)
1852 {
1853 if (StringMatch(subType.AsCString(), aSubTypeServiceName, kStringCaseInsensitiveMatch))
1854 {
1855 has = true;
1856 break;
1857 }
1858 }
1859
1860 return has;
1861 }
1862
1863 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
Log(Action aAction) const1864 void Server::Service::Log(Action aAction) const
1865 {
1866 static const char *const kActionStrings[] = {
1867 "Add new", // (0) kAddNew
1868 "Update existing", // (1) kUpdateExisting
1869 "Keep unchanged", // (2) kKeepUnchanged
1870 "Remove but retain name of", // (3) kRemoveButRetainName
1871 "Fully remove", // (4) kFullyRemove
1872 "LEASE expired for", // (5) kLeaseExpired
1873 "KEY LEASE expired for", // (6) kKeyLeaseExpired
1874 };
1875
1876 static_assert(0 == kAddNew, "kAddNew value is incorrect");
1877 static_assert(1 == kUpdateExisting, "kUpdateExisting value is incorrect");
1878 static_assert(2 == kKeepUnchanged, "kKeepUnchanged value is incorrect");
1879 static_assert(3 == kRemoveButRetainName, "kRemoveButRetainName value is incorrect");
1880 static_assert(4 == kFullyRemove, "kFullyRemove value is incorrect");
1881 static_assert(5 == kLeaseExpired, "kLeaseExpired value is incorrect");
1882 static_assert(6 == kKeyLeaseExpired, "kKeyLeaseExpired value is incorrect");
1883
1884 // We only log if the `Service` is marked as committed. This
1885 // ensures that temporary `Service` entries associated with a
1886 // newly received SRP update message are not logged (e.g., when
1887 // associated `Host` is being freed).
1888
1889 if (mIsCommitted)
1890 {
1891 LogInfo("%s service '%s'", kActionStrings[aAction], GetInstanceName());
1892
1893 for (const Heap::String &subType : mSubTypes)
1894 {
1895 char label[Dns::Name::kMaxLabelSize];
1896
1897 IgnoreError(ParseSubTypeServiceName(subType.AsCString(), label, sizeof(label)));
1898 LogInfo(" sub-type: %s", subType.AsCString());
1899 }
1900 }
1901 }
1902 #else
Log(Action) const1903 void Server::Service::Log(Action) const {}
1904 #endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1905
SetTxtDataFromMessage(const Message & aMessage,uint16_t aOffset,uint16_t aLength)1906 Error Server::Service::SetTxtDataFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
1907 {
1908 Error error;
1909
1910 SuccessOrExit(error = mTxtData.SetFrom(aMessage, aOffset, aLength));
1911 VerifyOrExit(Dns::TxtRecord::VerifyTxtData(mTxtData.GetBytes(), mTxtData.GetLength(), /* aAllowEmpty */ false),
1912 error = kErrorParse);
1913
1914 exit:
1915 if (error != kErrorNone)
1916 {
1917 mTxtData.Free();
1918 }
1919
1920 return error;
1921 }
1922
1923 //---------------------------------------------------------------------------------------------------------------------
1924 // Server::Host
1925
Host(Instance & aInstance,TimeMilli aUpdateTime)1926 Server::Host::Host(Instance &aInstance, TimeMilli aUpdateTime)
1927 : InstanceLocator(aInstance)
1928 , mNext(nullptr)
1929 , mTtl(0)
1930 , mLease(0)
1931 , mKeyLease(0)
1932 , mUpdateTime(aUpdateTime)
1933 , mParsedKey(false)
1934 , mUseShortLeaseOption(false)
1935 {
1936 }
1937
~Host(void)1938 Server::Host::~Host(void) { FreeAllServices(); }
1939
SetFullName(const char * aFullName)1940 Error Server::Host::SetFullName(const char *aFullName)
1941 {
1942 // `mFullName` becomes immutable after it is set, so if it is
1943 // already set, we only accept a `aFullName` that matches the
1944 // current name.
1945
1946 Error error;
1947
1948 if (mFullName.IsNull())
1949 {
1950 error = mFullName.Set(aFullName);
1951 }
1952 else
1953 {
1954 error = Matches(aFullName) ? kErrorNone : kErrorFailed;
1955 }
1956
1957 return error;
1958 }
1959
Matches(const char * aFullName) const1960 bool Server::Host::Matches(const char *aFullName) const
1961 {
1962 return StringMatch(mFullName.AsCString(), aFullName, kStringCaseInsensitiveMatch);
1963 }
1964
GetExpireTime(void) const1965 TimeMilli Server::Host::GetExpireTime(void) const
1966 {
1967 OT_ASSERT(!IsDeleted());
1968
1969 return mUpdateTime + Time::SecToMsec(mLease);
1970 }
1971
GetKeyExpireTime(void) const1972 TimeMilli Server::Host::GetKeyExpireTime(void) const { return mUpdateTime + Time::SecToMsec(mKeyLease); }
1973
GetLeaseInfo(LeaseInfo & aLeaseInfo) const1974 void Server::Host::GetLeaseInfo(LeaseInfo &aLeaseInfo) const
1975 {
1976 TimeMilli now = TimerMilli::GetNow();
1977 TimeMilli keyExpireTime = GetKeyExpireTime();
1978
1979 aLeaseInfo.mLease = Time::SecToMsec(GetLease());
1980 aLeaseInfo.mKeyLease = Time::SecToMsec(GetKeyLease());
1981 aLeaseInfo.mRemainingKeyLease = (now <= keyExpireTime) ? (keyExpireTime - now) : 0;
1982
1983 if (!IsDeleted())
1984 {
1985 TimeMilli expireTime = GetExpireTime();
1986
1987 aLeaseInfo.mRemainingLease = (now <= expireTime) ? (expireTime - now) : 0;
1988 }
1989 else
1990 {
1991 aLeaseInfo.mRemainingLease = 0;
1992 }
1993 }
1994
ProcessTtl(uint32_t aTtl)1995 Error Server::Host::ProcessTtl(uint32_t aTtl)
1996 {
1997 // This method processes the TTL value received in a resource record.
1998 //
1999 // If no TTL value is stored, this method will set the stored value to @p aTtl and return `kErrorNone`.
2000 // If a TTL value is stored and @p aTtl equals the stored value, this method returns `kErrorNone`.
2001 // Otherwise, this method returns `kErrorRejected`.
2002
2003 Error error = kErrorRejected;
2004
2005 VerifyOrExit(aTtl && (mTtl == 0 || mTtl == aTtl));
2006
2007 mTtl = aTtl;
2008
2009 error = kErrorNone;
2010
2011 exit:
2012 return error;
2013 }
2014
GetNextService(const Service * aPrevService) const2015 const Server::Service *Server::Host::GetNextService(const Service *aPrevService) const
2016 {
2017 return (aPrevService == nullptr) ? mServices.GetHead() : aPrevService->GetNext();
2018 }
2019
AddNewService(const char * aInstanceName,const char * aInstanceLabel,TimeMilli aUpdateTime)2020 Server::Service *Server::Host::AddNewService(const char *aInstanceName,
2021 const char *aInstanceLabel,
2022 TimeMilli aUpdateTime)
2023 {
2024 Service *service = Service::AllocateAndInit(aInstanceName, aInstanceLabel, *this, aUpdateTime);
2025
2026 VerifyOrExit(service != nullptr);
2027 AddService(*service);
2028
2029 exit:
2030 return service;
2031 }
2032
AddService(Service & aService)2033 void Server::Host::AddService(Service &aService)
2034 {
2035 aService.mHost = this;
2036 mServices.Push(aService);
2037 }
2038
RemoveService(Service * aService,RetainName aRetainName,NotifyMode aNotifyServiceHandler)2039 void Server::Host::RemoveService(Service *aService, RetainName aRetainName, NotifyMode aNotifyServiceHandler)
2040 {
2041 Server &server = Get<Server>();
2042
2043 VerifyOrExit(aService != nullptr);
2044
2045 aService->mIsDeleted = true;
2046
2047 aService->Log(aRetainName ? Service::kRemoveButRetainName : Service::kFullyRemove);
2048
2049 if (aNotifyServiceHandler && server.mServiceUpdateHandler.IsSet())
2050 {
2051 uint32_t updateId = server.AllocateId();
2052
2053 LogInfo("SRP update handler is notified (updatedId = %lu)", ToUlong(updateId));
2054 server.mServiceUpdateHandler.Invoke(updateId, this, static_cast<uint32_t>(kDefaultEventsHandlerTimeout));
2055 // We don't wait for the reply from the service update handler,
2056 // but always remove the service regardless of service update result.
2057 // Because removing a service should fail only when there is system
2058 // failure of the platform mDNS implementation and in which case the
2059 // service is not expected to be still registered.
2060 }
2061
2062 if (!aRetainName)
2063 {
2064 IgnoreError(mServices.Remove(*aService));
2065 aService->Free();
2066 }
2067
2068 exit:
2069 return;
2070 }
2071
FreeAllServices(void)2072 void Server::Host::FreeAllServices(void)
2073 {
2074 while (!mServices.IsEmpty())
2075 {
2076 RemoveService(mServices.GetHead(), kDeleteName, kDoNotNotifyServiceHandler);
2077 }
2078 }
2079
ClearResources(void)2080 void Server::Host::ClearResources(void) { mAddresses.Free(); }
2081
FindService(const char * aInstanceName)2082 Server::Service *Server::Host::FindService(const char *aInstanceName) { return mServices.FindMatching(aInstanceName); }
2083
FindService(const char * aInstanceName) const2084 const Server::Service *Server::Host::FindService(const char *aInstanceName) const
2085 {
2086 return mServices.FindMatching(aInstanceName);
2087 }
2088
HasService(const char * aInstanceName) const2089 bool Server::Host::HasService(const char *aInstanceName) const { return mServices.ContainsMatching(aInstanceName); }
2090
AddIp6Address(const Ip6::Address & aIp6Address)2091 Error Server::Host::AddIp6Address(const Ip6::Address &aIp6Address)
2092 {
2093 Error error = kErrorNone;
2094
2095 if (aIp6Address.IsMulticast() || aIp6Address.IsUnspecified() || aIp6Address.IsLoopback())
2096 {
2097 // We don't like those address because they cannot be used
2098 // for communication with exterior devices.
2099 ExitNow(error = kErrorDrop);
2100 }
2101
2102 // Drop duplicate addresses.
2103 VerifyOrExit(!mAddresses.Contains(aIp6Address), error = kErrorDrop);
2104
2105 error = mAddresses.PushBack(aIp6Address);
2106
2107 if (error == kErrorNoBufs)
2108 {
2109 LogWarn("Too many addresses for host %s", GetFullName());
2110 }
2111
2112 exit:
2113 return error;
2114 }
2115
2116 //---------------------------------------------------------------------------------------------------------------------
2117 // Server::UpdateMetadata
2118
UpdateMetadata(Instance & aInstance,Host & aHost,const MessageMetadata & aMessageMetadata)2119 Server::UpdateMetadata::UpdateMetadata(Instance &aInstance, Host &aHost, const MessageMetadata &aMessageMetadata)
2120 : InstanceLocator(aInstance)
2121 , mNext(nullptr)
2122 , mExpireTime(TimerMilli::GetNow() + kDefaultEventsHandlerTimeout)
2123 , mDnsHeader(aMessageMetadata.mDnsHeader)
2124 , mId(Get<Server>().AllocateId())
2125 , mTtlConfig(aMessageMetadata.mTtlConfig)
2126 , mLeaseConfig(aMessageMetadata.mLeaseConfig)
2127 , mHost(aHost)
2128 , mError(kErrorNone)
2129 , mIsDirectRxFromClient(aMessageMetadata.IsDirectRxFromClient())
2130 {
2131 if (aMessageMetadata.mMessageInfo != nullptr)
2132 {
2133 mMessageInfo = *aMessageMetadata.mMessageInfo;
2134 }
2135 }
2136
2137 } // namespace Srp
2138 } // namespace ot
2139
2140 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
2141