• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2021, 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 implements the DNS-SD server.
32  */
33 
34 #include "dnssd_server.hpp"
35 
36 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
37 
38 #include <openthread/platform/dns.h>
39 
40 #include "common/array.hpp"
41 #include "common/as_core_type.hpp"
42 #include "common/code_utils.hpp"
43 #include "common/debug.hpp"
44 #include "common/locator_getters.hpp"
45 #include "common/log.hpp"
46 #include "common/string.hpp"
47 #include "instance/instance.hpp"
48 #include "net/srp_server.hpp"
49 #include "net/udp6.hpp"
50 
51 namespace ot {
52 namespace Dns {
53 namespace ServiceDiscovery {
54 
55 RegisterLogModule("DnssdServer");
56 
57 const char Server::kDefaultDomainName[] = "default.service.arpa.";
58 const char Server::kSubLabel[]          = "_sub";
59 
60 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
61 const char *Server::kBlockedDomains[] = {"ipv4only.arpa."};
62 #endif
63 
Server(Instance & aInstance)64 Server::Server(Instance &aInstance)
65     : InstanceLocator(aInstance)
66     , mSocket(aInstance)
67 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
68     , mEnableUpstreamQuery(false)
69 #endif
70     , mTimer(aInstance)
71     , mTestMode(kTestModeDisabled)
72 {
73     mCounters.Clear();
74 }
75 
Start(void)76 Error Server::Start(void)
77 {
78     Error error = kErrorNone;
79 
80     VerifyOrExit(!IsRunning());
81 
82     SuccessOrExit(error = mSocket.Open(&Server::HandleUdpReceive, this));
83     SuccessOrExit(error = mSocket.Bind(kPort, kBindUnspecifiedNetif ? Ip6::kNetifUnspecified : Ip6::kNetifThread));
84 
85 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
86     Get<Srp::Server>().HandleDnssdServerStateChange();
87 #endif
88 
89     LogInfo("Started");
90 
91 exit:
92     if (error != kErrorNone)
93     {
94         IgnoreError(mSocket.Close());
95     }
96 
97     return error;
98 }
99 
Stop(void)100 void Server::Stop(void)
101 {
102     for (ProxyQuery &query : mProxyQueries)
103     {
104         Finalize(query, Header::kResponseServerFailure);
105     }
106 
107 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
108     for (UpstreamQueryTransaction &txn : mUpstreamQueryTransactions)
109     {
110         if (txn.IsValid())
111         {
112             ResetUpstreamQueryTransaction(txn, kErrorFailed);
113         }
114     }
115 #endif
116 
117     mTimer.Stop();
118 
119     IgnoreError(mSocket.Close());
120     LogInfo("Stopped");
121 
122 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
123     Get<Srp::Server>().HandleDnssdServerStateChange();
124 #endif
125 }
126 
HandleUdpReceive(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)127 void Server::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
128 {
129     static_cast<Server *>(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo));
130 }
131 
HandleUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)132 void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
133 {
134     Request request;
135 
136 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
137     // We first let the `Srp::Server` process the received message.
138     // It returns `kErrorNone` to indicate that it successfully
139     // processed the message.
140 
141     VerifyOrExit(Get<Srp::Server>().HandleDnssdServerUdpReceive(aMessage, aMessageInfo) != kErrorNone);
142 #endif
143 
144     request.mMessage     = &aMessage;
145     request.mMessageInfo = &aMessageInfo;
146     SuccessOrExit(aMessage.Read(aMessage.GetOffset(), request.mHeader));
147 
148     VerifyOrExit(request.mHeader.GetType() == Header::kTypeQuery);
149 
150     LogInfo("Received query from %s", aMessageInfo.GetPeerAddr().ToString().AsCString());
151 
152     ProcessQuery(request);
153 
154 exit:
155     return;
156 }
157 
ProcessQuery(Request & aRequest)158 void Server::ProcessQuery(Request &aRequest)
159 {
160     ResponseCode rcode = Header::kResponseSuccess;
161     Response     response(GetInstance());
162 
163 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
164     if (mEnableUpstreamQuery && ShouldForwardToUpstream(aRequest))
165     {
166         Error error = ResolveByUpstream(aRequest);
167 
168         if (error == kErrorNone)
169         {
170             ExitNow();
171         }
172 
173         LogWarnOnError(error, "forwarding to upstream");
174 
175         rcode = Header::kResponseServerFailure;
176 
177         // Continue to allocate and prepare the response message
178         // to send the `kResponseServerFailure` response code.
179     }
180 #endif
181 
182     SuccessOrExit(response.AllocateAndInitFrom(aRequest));
183 
184 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
185     // Forwarding the query to the upstream may have already set the
186     // response error code.
187     SuccessOrExit(rcode);
188 #endif
189 
190     SuccessOrExit(rcode = aRequest.ParseQuestions(mTestMode));
191     SuccessOrExit(rcode = response.AddQuestionsFrom(aRequest));
192 
193 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
194     response.Log();
195 #endif
196 
197 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
198     switch (response.ResolveBySrp())
199     {
200     case kErrorNone:
201         mCounters.mResolvedBySrp++;
202         ExitNow();
203 
204     case kErrorNotFound:
205         rcode = Header::kResponseNameError;
206         break;
207 
208     default:
209         rcode = Header::kResponseServerFailure;
210         ExitNow();
211     }
212 #endif
213 
214     ResolveByProxy(response, *aRequest.mMessageInfo);
215 
216 exit:
217     if (rcode != Header::kResponseSuccess)
218     {
219         response.SetResponseCode(rcode);
220     }
221 
222     response.Send(*aRequest.mMessageInfo);
223 }
224 
Response(Instance & aInstance)225 Server::Response::Response(Instance &aInstance)
226     : InstanceLocator(aInstance)
227 {
228     // `mHeader` constructors already clears it
229 
230     mOffsets.Clear();
231 }
232 
AllocateAndInitFrom(const Request & aRequest)233 Error Server::Response::AllocateAndInitFrom(const Request &aRequest)
234 {
235     Error error = kErrorNone;
236 
237     mMessage.Reset(Get<Server>().mSocket.NewMessage());
238     VerifyOrExit(!mMessage.IsNull(), error = kErrorNoBufs);
239 
240     mHeader.SetType(Header::kTypeResponse);
241     mHeader.SetMessageId(aRequest.mHeader.GetMessageId());
242     mHeader.SetQueryType(aRequest.mHeader.GetQueryType());
243 
244     if (aRequest.mHeader.IsRecursionDesiredFlagSet())
245     {
246         mHeader.SetRecursionDesiredFlag();
247     }
248 
249     // Append the empty header to reserve room for it in the message.
250     // Header will be updated in the message before sending it.
251     error = mMessage->Append(mHeader);
252 
253 exit:
254     if (error != kErrorNone)
255     {
256         mMessage.Free();
257     }
258 
259     return error;
260 }
261 
Send(const Ip6::MessageInfo & aMessageInfo)262 void Server::Response::Send(const Ip6::MessageInfo &aMessageInfo)
263 {
264     ResponseCode rcode = mHeader.GetResponseCode();
265 
266     VerifyOrExit(!mMessage.IsNull());
267 
268     if (rcode == Header::kResponseServerFailure)
269     {
270         mHeader.SetQuestionCount(0);
271         mHeader.SetAnswerCount(0);
272         mHeader.SetAdditionalRecordCount(0);
273         IgnoreError(mMessage->SetLength(sizeof(Header)));
274     }
275 
276     mMessage->Write(0, mHeader);
277 
278     SuccessOrExit(Get<Server>().mSocket.SendTo(*mMessage, aMessageInfo));
279 
280     // When `SendTo()` returns success it takes over ownership of
281     // the given message, so we release ownership of `mMessage`.
282 
283     mMessage.Release();
284 
285     LogInfo("Send response, rcode:%u", rcode);
286 
287     Get<Server>().UpdateResponseCounters(rcode);
288 
289 exit:
290     return;
291 }
292 
ParseQuestions(uint8_t aTestMode)293 Server::ResponseCode Server::Request::ParseQuestions(uint8_t aTestMode)
294 {
295     // Parse header and questions from a `Request` query message and
296     // determine the `QueryType`.
297 
298     ResponseCode rcode         = Header::kResponseFormatError;
299     uint16_t     offset        = sizeof(Header);
300     uint16_t     questionCount = mHeader.GetQuestionCount();
301     Question     question;
302 
303     VerifyOrExit(mHeader.GetQueryType() == Header::kQueryTypeStandard, rcode = Header::kResponseNotImplemented);
304     VerifyOrExit(!mHeader.IsTruncationFlagSet());
305 
306     VerifyOrExit(questionCount > 0);
307 
308     SuccessOrExit(Name::ParseName(*mMessage, offset));
309     SuccessOrExit(mMessage->Read(offset, question));
310     offset += sizeof(question);
311 
312     switch (question.GetType())
313     {
314     case ResourceRecord::kTypePtr:
315         mType = kPtrQuery;
316         break;
317     case ResourceRecord::kTypeSrv:
318         mType = kSrvQuery;
319         break;
320     case ResourceRecord::kTypeTxt:
321         mType = kTxtQuery;
322         break;
323     case ResourceRecord::kTypeAaaa:
324         mType = kAaaaQuery;
325         break;
326     default:
327         ExitNow(rcode = Header::kResponseNotImplemented);
328     }
329 
330     if (questionCount > 1)
331     {
332         VerifyOrExit(!(aTestMode & kTestModeSingleQuestionOnly));
333 
334         VerifyOrExit(questionCount == 2);
335 
336         SuccessOrExit(Name::CompareName(*mMessage, offset, *mMessage, sizeof(Header)));
337         SuccessOrExit(mMessage->Read(offset, question));
338 
339         switch (question.GetType())
340         {
341         case ResourceRecord::kTypeSrv:
342             VerifyOrExit(mType == kTxtQuery);
343             break;
344 
345         case ResourceRecord::kTypeTxt:
346             VerifyOrExit(mType == kSrvQuery);
347             break;
348 
349         default:
350             ExitNow();
351         }
352 
353         mType = kSrvTxtQuery;
354     }
355 
356     rcode = Header::kResponseSuccess;
357 
358 exit:
359     return rcode;
360 }
361 
AddQuestionsFrom(const Request & aRequest)362 Server::ResponseCode Server::Response::AddQuestionsFrom(const Request &aRequest)
363 {
364     ResponseCode rcode = Header::kResponseServerFailure;
365     uint16_t     offset;
366 
367     mType = aRequest.mType;
368 
369     // Read the name from `aRequest.mMessage` and append it as is to
370     // the response message. This ensures all name formats, including
371     // service instance names with dot characters in the instance
372     // label, are appended correctly.
373 
374     SuccessOrExit(Name(*aRequest.mMessage, sizeof(Header)).AppendTo(*mMessage));
375 
376     // Check the name to include the correct domain name and determine
377     // the domain name offset (for DNS name compression).
378 
379     VerifyOrExit(ParseQueryName() == kErrorNone, rcode = Header::kResponseNameError);
380 
381     mHeader.SetQuestionCount(aRequest.mHeader.GetQuestionCount());
382 
383     offset = sizeof(Header);
384 
385     for (uint16_t questionCount = 0; questionCount < mHeader.GetQuestionCount(); questionCount++)
386     {
387         Question question;
388 
389         // The names and questions in `aRequest` are validated already
390         // from `ParseQuestions()`, so we can `IgnoreError()`  here.
391 
392         IgnoreError(Name::ParseName(*aRequest.mMessage, offset));
393         IgnoreError(aRequest.mMessage->Read(offset, question));
394         offset += sizeof(question);
395 
396         if (questionCount != 0)
397         {
398             SuccessOrExit(AppendQueryName());
399         }
400 
401         SuccessOrExit(mMessage->Append(question));
402     }
403 
404     rcode = Header::kResponseSuccess;
405 
406 exit:
407     return rcode;
408 }
409 
ParseQueryName(void)410 Error Server::Response::ParseQueryName(void)
411 {
412     // Parses and validates the query name and updates
413     // the name compression offsets.
414 
415     Error        error = kErrorNone;
416     Name::Buffer name;
417     uint16_t     offset;
418 
419     offset = sizeof(Header);
420     SuccessOrExit(error = Name::ReadName(*mMessage, offset, name));
421 
422     switch (mType)
423     {
424     case kPtrQuery:
425         // `mOffsets.mServiceName` may be updated as we read labels and if we
426         // determine that the query name is a sub-type service.
427         mOffsets.mServiceName = sizeof(Header);
428         break;
429 
430     case kSrvQuery:
431     case kTxtQuery:
432     case kSrvTxtQuery:
433         mOffsets.mInstanceName = sizeof(Header);
434         break;
435 
436     case kAaaaQuery:
437         mOffsets.mHostName = sizeof(Header);
438         break;
439     }
440 
441     // Read the query name labels one by one to check if the name is
442     // service sub-type and also check that it is sub-domain of the
443     // default domain name and determine its offset
444 
445     offset = sizeof(Header);
446 
447     while (true)
448     {
449         Name::LabelBuffer label;
450         uint8_t           labelLength = sizeof(label);
451         uint16_t          comapreOffset;
452 
453         SuccessOrExit(error = Name::ReadLabel(*mMessage, offset, label, labelLength));
454 
455         if ((mType == kPtrQuery) && StringMatch(label, kSubLabel, kStringCaseInsensitiveMatch))
456         {
457             mOffsets.mServiceName = offset;
458         }
459 
460         comapreOffset = offset;
461 
462         if (Name::CompareName(*mMessage, comapreOffset, kDefaultDomainName) == kErrorNone)
463         {
464             mOffsets.mDomainName = offset;
465             ExitNow();
466         }
467     }
468 
469     error = kErrorParse;
470 
471 exit:
472     return error;
473 }
474 
ReadQueryName(Name::Buffer & aName) const475 void Server::Response::ReadQueryName(Name::Buffer &aName) const { Server::ReadQueryName(*mMessage, aName); }
476 
QueryNameMatches(const char * aName) const477 bool Server::Response::QueryNameMatches(const char *aName) const { return Server::QueryNameMatches(*mMessage, aName); }
478 
AppendQueryName(void)479 Error Server::Response::AppendQueryName(void) { return Name::AppendPointerLabel(sizeof(Header), *mMessage); }
480 
AppendPtrRecord(const char * aInstanceLabel,uint32_t aTtl)481 Error Server::Response::AppendPtrRecord(const char *aInstanceLabel, uint32_t aTtl)
482 {
483     Error     error;
484     uint16_t  recordOffset;
485     PtrRecord ptrRecord;
486 
487     ptrRecord.Init();
488     ptrRecord.SetTtl(aTtl);
489 
490     SuccessOrExit(error = AppendQueryName());
491 
492     recordOffset = mMessage->GetLength();
493     SuccessOrExit(error = mMessage->Append(ptrRecord));
494 
495     mOffsets.mInstanceName = mMessage->GetLength();
496     SuccessOrExit(error = Name::AppendLabel(aInstanceLabel, *mMessage));
497     SuccessOrExit(error = Name::AppendPointerLabel(mOffsets.mServiceName, *mMessage));
498 
499     UpdateRecordLength(ptrRecord, recordOffset);
500 
501     IncResourceRecordCount();
502 
503 exit:
504     return error;
505 }
506 
507 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
AppendSrvRecord(const Srp::Server::Service & aService)508 Error Server::Response::AppendSrvRecord(const Srp::Server::Service &aService)
509 {
510     uint32_t ttl = TimeMilli::MsecToSec(aService.GetExpireTime() - TimerMilli::GetNow());
511 
512     return AppendSrvRecord(aService.GetHost().GetFullName(), ttl, aService.GetPriority(), aService.GetWeight(),
513                            aService.GetPort());
514 }
515 #endif
516 
AppendSrvRecord(const ServiceInstanceInfo & aInstanceInfo)517 Error Server::Response::AppendSrvRecord(const ServiceInstanceInfo &aInstanceInfo)
518 {
519     return AppendSrvRecord(aInstanceInfo.mHostName, aInstanceInfo.mTtl, aInstanceInfo.mPriority, aInstanceInfo.mWeight,
520                            aInstanceInfo.mPort);
521 }
522 
AppendSrvRecord(const char * aHostName,uint32_t aTtl,uint16_t aPriority,uint16_t aWeight,uint16_t aPort)523 Error Server::Response::AppendSrvRecord(const char *aHostName,
524                                         uint32_t    aTtl,
525                                         uint16_t    aPriority,
526                                         uint16_t    aWeight,
527                                         uint16_t    aPort)
528 {
529     Error        error = kErrorNone;
530     SrvRecord    srvRecord;
531     uint16_t     recordOffset;
532     Name::Buffer hostLabels;
533 
534     SuccessOrExit(error = Name::ExtractLabels(aHostName, kDefaultDomainName, hostLabels));
535 
536     srvRecord.Init();
537     srvRecord.SetTtl(aTtl);
538     srvRecord.SetPriority(aPriority);
539     srvRecord.SetWeight(aWeight);
540     srvRecord.SetPort(aPort);
541 
542     SuccessOrExit(error = Name::AppendPointerLabel(mOffsets.mInstanceName, *mMessage));
543 
544     recordOffset = mMessage->GetLength();
545     SuccessOrExit(error = mMessage->Append(srvRecord));
546 
547     mOffsets.mHostName = mMessage->GetLength();
548     SuccessOrExit(error = Name::AppendMultipleLabels(hostLabels, *mMessage));
549     SuccessOrExit(error = Name::AppendPointerLabel(mOffsets.mDomainName, *mMessage));
550 
551     UpdateRecordLength(srvRecord, recordOffset);
552 
553     IncResourceRecordCount();
554 
555 exit:
556     return error;
557 }
558 
559 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
AppendHostAddresses(const Srp::Server::Host & aHost)560 Error Server::Response::AppendHostAddresses(const Srp::Server::Host &aHost)
561 {
562     const Ip6::Address *addrs;
563     uint8_t             addrsLength;
564     uint32_t            ttl;
565 
566     addrs = aHost.GetAddresses(addrsLength);
567     ttl   = TimeMilli::MsecToSec(aHost.GetExpireTime() - TimerMilli::GetNow());
568 
569     return AppendHostAddresses(addrs, addrsLength, ttl);
570 }
571 #endif
572 
AppendHostAddresses(const HostInfo & aHostInfo)573 Error Server::Response::AppendHostAddresses(const HostInfo &aHostInfo)
574 {
575     return AppendHostAddresses(AsCoreTypePtr(aHostInfo.mAddresses), aHostInfo.mAddressNum, aHostInfo.mTtl);
576 }
577 
AppendHostAddresses(const ServiceInstanceInfo & aInstanceInfo)578 Error Server::Response::AppendHostAddresses(const ServiceInstanceInfo &aInstanceInfo)
579 {
580     return AppendHostAddresses(AsCoreTypePtr(aInstanceInfo.mAddresses), aInstanceInfo.mAddressNum, aInstanceInfo.mTtl);
581 }
582 
AppendHostAddresses(const Ip6::Address * aAddrs,uint16_t aAddrsLength,uint32_t aTtl)583 Error Server::Response::AppendHostAddresses(const Ip6::Address *aAddrs, uint16_t aAddrsLength, uint32_t aTtl)
584 {
585     Error error = kErrorNone;
586 
587     for (uint16_t index = 0; index < aAddrsLength; index++)
588     {
589         AaaaRecord aaaaRecord;
590 
591         aaaaRecord.Init();
592         aaaaRecord.SetTtl(aTtl);
593         aaaaRecord.SetAddress(aAddrs[index]);
594 
595         SuccessOrExit(error = Name::AppendPointerLabel(mOffsets.mHostName, *mMessage));
596         SuccessOrExit(error = mMessage->Append(aaaaRecord));
597 
598         IncResourceRecordCount();
599     }
600 
601 exit:
602     return error;
603 }
604 
605 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
AppendTxtRecord(const Srp::Server::Service & aService)606 Error Server::Response::AppendTxtRecord(const Srp::Server::Service &aService)
607 {
608     return AppendTxtRecord(aService.GetTxtData(), aService.GetTxtDataLength(),
609                            TimeMilli::MsecToSec(aService.GetExpireTime() - TimerMilli::GetNow()));
610 }
611 #endif
612 
AppendTxtRecord(const ServiceInstanceInfo & aInstanceInfo)613 Error Server::Response::AppendTxtRecord(const ServiceInstanceInfo &aInstanceInfo)
614 {
615     return AppendTxtRecord(aInstanceInfo.mTxtData, aInstanceInfo.mTxtLength, aInstanceInfo.mTtl);
616 }
617 
AppendTxtRecord(const void * aTxtData,uint16_t aTxtLength,uint32_t aTtl)618 Error Server::Response::AppendTxtRecord(const void *aTxtData, uint16_t aTxtLength, uint32_t aTtl)
619 {
620     Error     error = kErrorNone;
621     TxtRecord txtRecord;
622     uint8_t   emptyTxt = 0;
623 
624     if (aTxtLength == 0)
625     {
626         aTxtData   = &emptyTxt;
627         aTxtLength = sizeof(emptyTxt);
628     }
629 
630     txtRecord.Init();
631     txtRecord.SetTtl(aTtl);
632     txtRecord.SetLength(aTxtLength);
633 
634     SuccessOrExit(error = Name::AppendPointerLabel(mOffsets.mInstanceName, *mMessage));
635     SuccessOrExit(error = mMessage->Append(txtRecord));
636     SuccessOrExit(error = mMessage->AppendBytes(aTxtData, aTxtLength));
637 
638     IncResourceRecordCount();
639 
640 exit:
641     return error;
642 }
643 
UpdateRecordLength(ResourceRecord & aRecord,uint16_t aOffset)644 void Server::Response::UpdateRecordLength(ResourceRecord &aRecord, uint16_t aOffset)
645 {
646     // Calculates RR DATA length and updates and re-writes it in the
647     // response message. This should be called immediately
648     // after all the fields in the record are written in the message.
649     // `aOffset` gives the offset in the message to the start of the
650     // record.
651 
652     aRecord.SetLength(mMessage->GetLength() - aOffset - sizeof(Dns::ResourceRecord));
653     mMessage->Write(aOffset, aRecord);
654 }
655 
IncResourceRecordCount(void)656 void Server::Response::IncResourceRecordCount(void)
657 {
658     switch (mSection)
659     {
660     case kAnswerSection:
661         mHeader.SetAnswerCount(mHeader.GetAnswerCount() + 1);
662         break;
663     case kAdditionalDataSection:
664         mHeader.SetAdditionalRecordCount(mHeader.GetAdditionalRecordCount() + 1);
665         break;
666     }
667 }
668 
GetNameLength(const char * aName)669 uint8_t Server::GetNameLength(const char *aName)
670 {
671     return static_cast<uint8_t>(StringLength(aName, Name::kMaxNameLength));
672 }
673 
674 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
Log(void) const675 void Server::Response::Log(void) const
676 {
677     Name::Buffer name;
678 
679     ReadQueryName(name);
680     LogInfo("%s query for '%s'", QueryTypeToString(mType), name);
681 }
682 
QueryTypeToString(QueryType aType)683 const char *Server::Response::QueryTypeToString(QueryType aType)
684 {
685     static const char *const kTypeNames[] = {
686         "PTR",       // (0) kPtrQuery
687         "SRV",       // (1) kSrvQuery
688         "TXT",       // (2) kTxtQuery
689         "SRV & TXT", // (3) kSrvTxtQuery
690         "AAAA",      // (4) kAaaaQuery
691     };
692 
693     static_assert(0 == kPtrQuery, "kPtrQuery value is incorrect");
694     static_assert(1 == kSrvQuery, "kSrvQuery value is incorrect");
695     static_assert(2 == kTxtQuery, "kTxtQuery value is incorrect");
696     static_assert(3 == kSrvTxtQuery, "kSrvTxtQuery value is incorrect");
697     static_assert(4 == kAaaaQuery, "kAaaaQuery value is incorrect");
698 
699     return kTypeNames[aType];
700 }
701 #endif
702 
703 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
704 
ResolveBySrp(void)705 Error Server::Response::ResolveBySrp(void)
706 {
707     static const Section kSections[] = {kAnswerSection, kAdditionalDataSection};
708 
709     Error                       error          = kErrorNotFound;
710     const Srp::Server::Service *matchedService = nullptr;
711     bool                        found          = false;
712     Section                     srvSection;
713     Section                     txtSection;
714 
715     mSection = kAnswerSection;
716 
717     for (const Srp::Server::Host &host : Get<Srp::Server>().GetHosts())
718     {
719         if (host.IsDeleted())
720         {
721             continue;
722         }
723 
724         if (mType == kAaaaQuery)
725         {
726             if (QueryNameMatches(host.GetFullName()))
727             {
728                 error = AppendHostAddresses(host);
729                 ExitNow();
730             }
731 
732             continue;
733         }
734 
735         // `mType` is PTR or SRV/TXT query
736 
737         for (const Srp::Server::Service &service : host.GetServices())
738         {
739             if (service.IsDeleted())
740             {
741                 continue;
742             }
743 
744             if (mType == kPtrQuery)
745             {
746                 if (QueryNameMatchesService(service))
747                 {
748                     uint32_t ttl = TimeMilli::MsecToSec(service.GetExpireTime() - TimerMilli::GetNow());
749 
750                     SuccessOrExit(error = AppendPtrRecord(service.GetInstanceLabel(), ttl));
751                     matchedService = &service;
752                 }
753             }
754             else if (QueryNameMatches(service.GetInstanceName()))
755             {
756                 matchedService = &service;
757                 found          = true;
758                 break;
759             }
760         }
761 
762         if (found)
763         {
764             break;
765         }
766     }
767 
768     VerifyOrExit(matchedService != nullptr);
769 
770     if (mType == kPtrQuery)
771     {
772         // Skip adding additional records, when answering a
773         // PTR query with more than one answer. This is the
774         // recommended behavior to keep the size of the
775         // response small.
776 
777         VerifyOrExit(mHeader.GetAnswerCount() == 1);
778     }
779 
780     srvSection = ((mType == kSrvQuery) || (mType == kSrvTxtQuery)) ? kAnswerSection : kAdditionalDataSection;
781     txtSection = ((mType == kTxtQuery) || (mType == kSrvTxtQuery)) ? kAnswerSection : kAdditionalDataSection;
782 
783     for (Section section : kSections)
784     {
785         mSection = section;
786 
787         if (mSection == kAdditionalDataSection)
788         {
789             VerifyOrExit(!(Get<Server>().mTestMode & kTestModeEmptyAdditionalSection));
790         }
791 
792         if (srvSection == mSection)
793         {
794             SuccessOrExit(error = AppendSrvRecord(*matchedService));
795         }
796 
797         if (txtSection == mSection)
798         {
799             SuccessOrExit(error = AppendTxtRecord(*matchedService));
800         }
801     }
802 
803     SuccessOrExit(error = AppendHostAddresses(matchedService->GetHost()));
804 
805 exit:
806     return error;
807 }
808 
QueryNameMatchesService(const Srp::Server::Service & aService) const809 bool Server::Response::QueryNameMatchesService(const Srp::Server::Service &aService) const
810 {
811     // Check if the query name matches the base service name or any
812     // sub-type service names associated with `aService`.
813 
814     bool matches = QueryNameMatches(aService.GetServiceName());
815 
816     VerifyOrExit(!matches);
817 
818     for (uint16_t index = 0; index < aService.GetNumberOfSubTypes(); index++)
819     {
820         matches = QueryNameMatches(aService.GetSubTypeServiceNameAt(index));
821         VerifyOrExit(!matches);
822     }
823 
824 exit:
825     return matches;
826 }
827 
828 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
829 
830 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
ShouldForwardToUpstream(const Request & aRequest)831 bool Server::ShouldForwardToUpstream(const Request &aRequest)
832 {
833     bool         shouldForward = false;
834     uint16_t     readOffset;
835     Name::Buffer name;
836 
837     VerifyOrExit(aRequest.mHeader.IsRecursionDesiredFlagSet());
838     readOffset = sizeof(Header);
839 
840     for (uint16_t i = 0; i < aRequest.mHeader.GetQuestionCount(); i++)
841     {
842         SuccessOrExit(Name::ReadName(*aRequest.mMessage, readOffset, name));
843         readOffset += sizeof(Question);
844 
845         VerifyOrExit(!Name::IsSubDomainOf(name, kDefaultDomainName));
846 
847         for (const char *blockedDomain : kBlockedDomains)
848         {
849             VerifyOrExit(!Name::IsSameDomain(name, blockedDomain));
850         }
851     }
852 
853     shouldForward = true;
854 
855 exit:
856     return shouldForward;
857 }
858 
OnUpstreamQueryDone(UpstreamQueryTransaction & aQueryTransaction,Message * aResponseMessage)859 void Server::OnUpstreamQueryDone(UpstreamQueryTransaction &aQueryTransaction, Message *aResponseMessage)
860 {
861     Error error = kErrorNone;
862 
863     VerifyOrExit(aQueryTransaction.IsValid(), error = kErrorInvalidArgs);
864 
865     if (aResponseMessage != nullptr)
866     {
867         error = mSocket.SendTo(*aResponseMessage, aQueryTransaction.GetMessageInfo());
868     }
869     else
870     {
871         error = kErrorResponseTimeout;
872     }
873 
874     ResetUpstreamQueryTransaction(aQueryTransaction, error);
875 
876 exit:
877     FreeMessageOnError(aResponseMessage, error);
878 }
879 
AllocateUpstreamQueryTransaction(const Ip6::MessageInfo & aMessageInfo)880 Server::UpstreamQueryTransaction *Server::AllocateUpstreamQueryTransaction(const Ip6::MessageInfo &aMessageInfo)
881 {
882     UpstreamQueryTransaction *newTxn = nullptr;
883 
884     for (UpstreamQueryTransaction &txn : mUpstreamQueryTransactions)
885     {
886         if (!txn.IsValid())
887         {
888             newTxn = &txn;
889             break;
890         }
891     }
892 
893     VerifyOrExit(newTxn != nullptr, mCounters.mUpstreamDnsCounters.mFailures++);
894 
895     newTxn->Init(aMessageInfo);
896     LogInfo("Upstream query transaction %d initialized.", static_cast<int>(newTxn - mUpstreamQueryTransactions));
897     mTimer.FireAtIfEarlier(newTxn->GetExpireTime());
898 
899 exit:
900     return newTxn;
901 }
902 
ResolveByUpstream(const Request & aRequest)903 Error Server::ResolveByUpstream(const Request &aRequest)
904 {
905     Error                     error = kErrorNone;
906     UpstreamQueryTransaction *txn;
907 
908     txn = AllocateUpstreamQueryTransaction(*aRequest.mMessageInfo);
909     VerifyOrExit(txn != nullptr, error = kErrorNoBufs);
910 
911     otPlatDnsStartUpstreamQuery(&GetInstance(), txn, aRequest.mMessage);
912     mCounters.mUpstreamDnsCounters.mQueries++;
913 
914 exit:
915     return error;
916 }
917 #endif // OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
918 
ResolveByProxy(Response & aResponse,const Ip6::MessageInfo & aMessageInfo)919 void Server::ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessageInfo)
920 {
921     ProxyQuery    *query;
922     ProxyQueryInfo info;
923     Name::Buffer   name;
924 
925     VerifyOrExit(mQuerySubscribe.IsSet());
926 
927     // We try to convert `aResponse.mMessage` to a `ProxyQuery` by
928     // appending `ProxyQueryInfo` to it.
929 
930     info.mType        = aResponse.mType;
931     info.mMessageInfo = aMessageInfo;
932     info.mExpireTime  = TimerMilli::GetNow() + kQueryTimeout;
933     info.mOffsets     = aResponse.mOffsets;
934 
935     if (aResponse.mMessage->Append(info) != kErrorNone)
936     {
937         aResponse.SetResponseCode(Header::kResponseServerFailure);
938         ExitNow();
939     }
940 
941     // Take over the ownership of `aResponse.mMessage` and add it as a
942     // `ProxyQuery` in `mProxyQueries` list.
943 
944     query = aResponse.mMessage.Release();
945 
946     query->Write(0, aResponse.mHeader);
947     mProxyQueries.Enqueue(*query);
948 
949     mTimer.FireAtIfEarlier(info.mExpireTime);
950 
951     ReadQueryName(*query, name);
952     mQuerySubscribe.Invoke(name);
953 
954 exit:
955     return;
956 }
957 
ReadQueryName(const Message & aQuery,Name::Buffer & aName)958 void Server::ReadQueryName(const Message &aQuery, Name::Buffer &aName)
959 {
960     uint16_t offset = sizeof(Header);
961 
962     IgnoreError(Name::ReadName(aQuery, offset, aName));
963 }
964 
QueryNameMatches(const Message & aQuery,const char * aName)965 bool Server::QueryNameMatches(const Message &aQuery, const char *aName)
966 {
967     uint16_t offset = sizeof(Header);
968 
969     return (Name::CompareName(aQuery, offset, aName) == kErrorNone);
970 }
971 
ReadFrom(const ProxyQuery & aQuery)972 void Server::ProxyQueryInfo::ReadFrom(const ProxyQuery &aQuery)
973 {
974     SuccessOrAssert(aQuery.Read(aQuery.GetLength() - sizeof(ProxyQueryInfo), *this));
975 }
976 
RemoveFrom(ProxyQuery & aQuery) const977 void Server::ProxyQueryInfo::RemoveFrom(ProxyQuery &aQuery) const
978 {
979     SuccessOrAssert(aQuery.SetLength(aQuery.GetLength() - sizeof(ProxyQueryInfo)));
980 }
981 
UpdateIn(ProxyQuery & aQuery) const982 void Server::ProxyQueryInfo::UpdateIn(ProxyQuery &aQuery) const
983 {
984     aQuery.Write(aQuery.GetLength() - sizeof(ProxyQueryInfo), *this);
985 }
986 
ExtractServiceInstanceLabel(const char * aInstanceName,Name::LabelBuffer & aLabel)987 Error Server::Response::ExtractServiceInstanceLabel(const char *aInstanceName, Name::LabelBuffer &aLabel)
988 {
989     uint16_t     offset;
990     Name::Buffer serviceName;
991 
992     offset = mOffsets.mServiceName;
993     IgnoreError(Name::ReadName(*mMessage, offset, serviceName));
994 
995     return Name::ExtractLabels(aInstanceName, serviceName, aLabel);
996 }
997 
RemoveQueryAndPrepareResponse(ProxyQuery & aQuery,const ProxyQueryInfo & aInfo,Response & aResponse)998 void Server::RemoveQueryAndPrepareResponse(ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Response &aResponse)
999 {
1000     Name::Buffer name;
1001 
1002     mProxyQueries.Dequeue(aQuery);
1003     aInfo.RemoveFrom(aQuery);
1004 
1005     ReadQueryName(aQuery, name);
1006     mQueryUnsubscribe.InvokeIfSet(name);
1007 
1008     aResponse.InitFrom(aQuery, aInfo);
1009 }
1010 
InitFrom(ProxyQuery & aQuery,const ProxyQueryInfo & aInfo)1011 void Server::Response::InitFrom(ProxyQuery &aQuery, const ProxyQueryInfo &aInfo)
1012 {
1013     mMessage.Reset(&aQuery);
1014     IgnoreError(mMessage->Read(0, mHeader));
1015     mType    = aInfo.mType;
1016     mOffsets = aInfo.mOffsets;
1017 }
1018 
Answer(const ServiceInstanceInfo & aInstanceInfo,const Ip6::MessageInfo & aMessageInfo)1019 void Server::Response::Answer(const ServiceInstanceInfo &aInstanceInfo, const Ip6::MessageInfo &aMessageInfo)
1020 {
1021     static const Section kSections[] = {kAnswerSection, kAdditionalDataSection};
1022 
1023     Error   error      = kErrorNone;
1024     Section srvSection = ((mType == kSrvQuery) || (mType == kSrvTxtQuery)) ? kAnswerSection : kAdditionalDataSection;
1025     Section txtSection = ((mType == kTxtQuery) || (mType == kSrvTxtQuery)) ? kAnswerSection : kAdditionalDataSection;
1026 
1027     if (mType == kPtrQuery)
1028     {
1029         Name::LabelBuffer instanceLabel;
1030 
1031         SuccessOrExit(error = ExtractServiceInstanceLabel(aInstanceInfo.mFullName, instanceLabel));
1032         mSection = kAnswerSection;
1033         SuccessOrExit(error = AppendPtrRecord(instanceLabel, aInstanceInfo.mTtl));
1034     }
1035 
1036     for (Section section : kSections)
1037     {
1038         mSection = section;
1039 
1040         if (mSection == kAdditionalDataSection)
1041         {
1042             VerifyOrExit(!(Get<Server>().mTestMode & kTestModeEmptyAdditionalSection));
1043         }
1044 
1045         if (srvSection == mSection)
1046         {
1047             SuccessOrExit(error = AppendSrvRecord(aInstanceInfo));
1048         }
1049 
1050         if (txtSection == mSection)
1051         {
1052             SuccessOrExit(error = AppendTxtRecord(aInstanceInfo));
1053         }
1054     }
1055 
1056     error = AppendHostAddresses(aInstanceInfo);
1057 
1058 exit:
1059     if (error != kErrorNone)
1060     {
1061         SetResponseCode(Header::kResponseServerFailure);
1062     }
1063 
1064     Send(aMessageInfo);
1065 }
1066 
Answer(const HostInfo & aHostInfo,const Ip6::MessageInfo & aMessageInfo)1067 void Server::Response::Answer(const HostInfo &aHostInfo, const Ip6::MessageInfo &aMessageInfo)
1068 {
1069     mSection = kAnswerSection;
1070 
1071     if (AppendHostAddresses(aHostInfo) != kErrorNone)
1072     {
1073         SetResponseCode(Header::kResponseServerFailure);
1074     }
1075 
1076     Send(aMessageInfo);
1077 }
1078 
SetQueryCallbacks(SubscribeCallback aSubscribe,UnsubscribeCallback aUnsubscribe,void * aContext)1079 void Server::SetQueryCallbacks(SubscribeCallback aSubscribe, UnsubscribeCallback aUnsubscribe, void *aContext)
1080 {
1081     OT_ASSERT((aSubscribe == nullptr) == (aUnsubscribe == nullptr));
1082 
1083     mQuerySubscribe.Set(aSubscribe, aContext);
1084     mQueryUnsubscribe.Set(aUnsubscribe, aContext);
1085 }
1086 
HandleDiscoveredServiceInstance(const char * aServiceFullName,const ServiceInstanceInfo & aInstanceInfo)1087 void Server::HandleDiscoveredServiceInstance(const char *aServiceFullName, const ServiceInstanceInfo &aInstanceInfo)
1088 {
1089     OT_ASSERT(StringEndsWith(aServiceFullName, Name::kLabelSeparatorChar));
1090     OT_ASSERT(StringEndsWith(aInstanceInfo.mFullName, Name::kLabelSeparatorChar));
1091     OT_ASSERT(StringEndsWith(aInstanceInfo.mHostName, Name::kLabelSeparatorChar));
1092 
1093     // It is safe to remove entries from `mProxyQueries` as we iterate
1094     // over it since it is a `MessageQueue`.
1095 
1096     for (ProxyQuery &query : mProxyQueries)
1097     {
1098         bool           canAnswer = false;
1099         ProxyQueryInfo info;
1100 
1101         info.ReadFrom(query);
1102 
1103         switch (info.mType)
1104         {
1105         case kPtrQuery:
1106             canAnswer = QueryNameMatches(query, aServiceFullName);
1107             break;
1108 
1109         case kSrvQuery:
1110         case kTxtQuery:
1111         case kSrvTxtQuery:
1112             canAnswer = QueryNameMatches(query, aInstanceInfo.mFullName);
1113             break;
1114 
1115         case kAaaaQuery:
1116             break;
1117         }
1118 
1119         if (canAnswer)
1120         {
1121             Response response(GetInstance());
1122 
1123             RemoveQueryAndPrepareResponse(query, info, response);
1124             response.Answer(aInstanceInfo, info.mMessageInfo);
1125         }
1126     }
1127 }
1128 
HandleDiscoveredHost(const char * aHostFullName,const HostInfo & aHostInfo)1129 void Server::HandleDiscoveredHost(const char *aHostFullName, const HostInfo &aHostInfo)
1130 {
1131     OT_ASSERT(StringEndsWith(aHostFullName, Name::kLabelSeparatorChar));
1132 
1133     for (ProxyQuery &query : mProxyQueries)
1134     {
1135         ProxyQueryInfo info;
1136 
1137         info.ReadFrom(query);
1138 
1139         if ((info.mType == kAaaaQuery) && QueryNameMatches(query, aHostFullName))
1140         {
1141             Response response(GetInstance());
1142 
1143             RemoveQueryAndPrepareResponse(query, info, response);
1144             response.Answer(aHostInfo, info.mMessageInfo);
1145         }
1146     }
1147 }
1148 
GetNextQuery(const otDnssdQuery * aQuery) const1149 const otDnssdQuery *Server::GetNextQuery(const otDnssdQuery *aQuery) const
1150 {
1151     const ProxyQuery *query = static_cast<const ProxyQuery *>(aQuery);
1152 
1153     return (query == nullptr) ? mProxyQueries.GetHead() : query->GetNext();
1154 }
1155 
GetQueryTypeAndName(const otDnssdQuery * aQuery,Dns::Name::Buffer & aName)1156 Server::DnsQueryType Server::GetQueryTypeAndName(const otDnssdQuery *aQuery, Dns::Name::Buffer &aName)
1157 {
1158     const ProxyQuery *query = static_cast<const ProxyQuery *>(aQuery);
1159     ProxyQueryInfo    info;
1160     DnsQueryType      type;
1161 
1162     ReadQueryName(*query, aName);
1163     info.ReadFrom(*query);
1164 
1165     type = kDnsQueryBrowse;
1166 
1167     switch (info.mType)
1168     {
1169     case kPtrQuery:
1170         break;
1171 
1172     case kSrvQuery:
1173     case kTxtQuery:
1174     case kSrvTxtQuery:
1175         type = kDnsQueryResolve;
1176         break;
1177 
1178     case kAaaaQuery:
1179         type = kDnsQueryResolveHost;
1180         break;
1181     }
1182 
1183     return type;
1184 }
1185 
HandleTimer(void)1186 void Server::HandleTimer(void)
1187 {
1188     TimeMilli now        = TimerMilli::GetNow();
1189     TimeMilli nextExpire = now.GetDistantFuture();
1190 
1191     for (ProxyQuery &query : mProxyQueries)
1192     {
1193         ProxyQueryInfo info;
1194 
1195         info.ReadFrom(query);
1196 
1197         if (info.mExpireTime <= now)
1198         {
1199             Finalize(query, Header::kResponseSuccess);
1200         }
1201         else
1202         {
1203             nextExpire = Min(nextExpire, info.mExpireTime);
1204         }
1205     }
1206 
1207 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
1208     for (UpstreamQueryTransaction &query : mUpstreamQueryTransactions)
1209     {
1210         if (!query.IsValid())
1211         {
1212             continue;
1213         }
1214 
1215         if (query.GetExpireTime() <= now)
1216         {
1217             otPlatDnsCancelUpstreamQuery(&GetInstance(), &query);
1218         }
1219         else
1220         {
1221             nextExpire = Min(nextExpire, query.GetExpireTime());
1222         }
1223     }
1224 #endif
1225 
1226     if (nextExpire != now.GetDistantFuture())
1227     {
1228         mTimer.FireAtIfEarlier(nextExpire);
1229     }
1230 }
1231 
Finalize(ProxyQuery & aQuery,ResponseCode aResponseCode)1232 void Server::Finalize(ProxyQuery &aQuery, ResponseCode aResponseCode)
1233 {
1234     Response       response(GetInstance());
1235     ProxyQueryInfo info;
1236 
1237     info.ReadFrom(aQuery);
1238     RemoveQueryAndPrepareResponse(aQuery, info, response);
1239 
1240     response.SetResponseCode(aResponseCode);
1241     response.Send(info.mMessageInfo);
1242 }
1243 
UpdateResponseCounters(ResponseCode aResponseCode)1244 void Server::UpdateResponseCounters(ResponseCode aResponseCode)
1245 {
1246     switch (aResponseCode)
1247     {
1248     case UpdateHeader::kResponseSuccess:
1249         ++mCounters.mSuccessResponse;
1250         break;
1251     case UpdateHeader::kResponseServerFailure:
1252         ++mCounters.mServerFailureResponse;
1253         break;
1254     case UpdateHeader::kResponseFormatError:
1255         ++mCounters.mFormatErrorResponse;
1256         break;
1257     case UpdateHeader::kResponseNameError:
1258         ++mCounters.mNameErrorResponse;
1259         break;
1260     case UpdateHeader::kResponseNotImplemented:
1261         ++mCounters.mNotImplementedResponse;
1262         break;
1263     default:
1264         ++mCounters.mOtherResponse;
1265         break;
1266     }
1267 }
1268 
1269 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
Init(const Ip6::MessageInfo & aMessageInfo)1270 void Server::UpstreamQueryTransaction::Init(const Ip6::MessageInfo &aMessageInfo)
1271 {
1272     mMessageInfo = aMessageInfo;
1273     mValid       = true;
1274     mExpireTime  = TimerMilli::GetNow() + kQueryTimeout;
1275 }
1276 
ResetUpstreamQueryTransaction(UpstreamQueryTransaction & aTxn,Error aError)1277 void Server::ResetUpstreamQueryTransaction(UpstreamQueryTransaction &aTxn, Error aError)
1278 {
1279     int index = static_cast<int>(&aTxn - mUpstreamQueryTransactions);
1280 
1281     // Avoid the warnings when info / warn logging is disabled.
1282     OT_UNUSED_VARIABLE(index);
1283     if (aError == kErrorNone)
1284     {
1285         mCounters.mUpstreamDnsCounters.mResponses++;
1286         LogInfo("Upstream query transaction %d completed.", index);
1287     }
1288     else
1289     {
1290         mCounters.mUpstreamDnsCounters.mFailures++;
1291         LogWarn("Upstream query transaction %d closed: %s.", index, ErrorToString(aError));
1292     }
1293     aTxn.Reset();
1294 }
1295 #endif
1296 
1297 } // namespace ServiceDiscovery
1298 } // namespace Dns
1299 } // namespace ot
1300 
1301 #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE && OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_MOCK_PLAT_APIS_ENABLE
otPlatDnsStartUpstreamQuery(otInstance * aInstance,otPlatDnsUpstreamQuery * aTxn,const otMessage * aQuery)1302 void otPlatDnsStartUpstreamQuery(otInstance *aInstance, otPlatDnsUpstreamQuery *aTxn, const otMessage *aQuery)
1303 {
1304     OT_UNUSED_VARIABLE(aInstance);
1305     OT_UNUSED_VARIABLE(aTxn);
1306     OT_UNUSED_VARIABLE(aQuery);
1307 }
1308 
otPlatDnsCancelUpstreamQuery(otInstance * aInstance,otPlatDnsUpstreamQuery * aTxn)1309 void otPlatDnsCancelUpstreamQuery(otInstance *aInstance, otPlatDnsUpstreamQuery *aTxn)
1310 {
1311     otPlatDnsUpstreamQueryDone(aInstance, aTxn, nullptr);
1312 }
1313 #endif
1314 
1315 #endif // OPENTHREAD_CONFIG_DNS_SERVER_ENABLE
1316