mirror of
https://github.com/espressif/openthread.git
synced 2026-10-02 22:07:36 +00:00
This commit renames several methods in `Ip6::Address`, `Ip6::InterfaceIdentifier`, `Ip6::Prefix`, and `Ip4::Address` that fully initialize the object from `Set...()` to `Init...()`. This creates a clear semantic distinction in the API: - `Init...()`: Fully (re-)initializing the object. - `Set...()`: Modifies a specific property or a sub-component of the object (e.g., `SetPrefix()`, `SetLocator()`, `SetSubnetId()`). Some examples of renames include: - `SetFromExtAddress()` -> `InitFromExtAddress()` - `SetToLocator()` -> `InitAsLocator()` - `SetToLinkLocalAddress()` -> `InitAsLinkLocalAddress()` - `SetToRoutingLocator()` -> `InitAsRoutingLocator()` - `SetToAnycastLocator()` -> `InitAsAnycastLocator()` - `SetToIp4Mapped()` -> `InitAsIp4Mapped()` All calls to these methods across the codebase have been updated to reflect the new names.
525 lines
20 KiB
C++
525 lines
20 KiB
C++
/*
|
|
* Copyright (c) 2026, The OpenThread Authors.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the copyright holder nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "nexus_core.hpp"
|
|
#include "nexus_node.hpp"
|
|
|
|
namespace ot {
|
|
namespace Nexus {
|
|
|
|
namespace {
|
|
|
|
static constexpr uint32_t kFormNetworkTime = 10 * 1000;
|
|
static constexpr uint32_t kJoinNetworkTime = 20 * 1000;
|
|
static constexpr uint32_t kStabilizationTime = 10 * 1000;
|
|
|
|
static constexpr char kGuaPrefix[] = "2005:1234:abcd:100::/64";
|
|
static constexpr char kEth1Addr[] = "2005:1234:abcd:100::E1";
|
|
static constexpr char kBr1AilAddr[] = "2005:1234:abcd:100::B1";
|
|
|
|
static constexpr char kThreadGroup1[] = "threadgroup1.org";
|
|
static constexpr char kThreadGroup2[] = "threadgroup2.org";
|
|
|
|
static constexpr char kThreadGroup1Aaaa[] = "2002:1234::E1:1";
|
|
static constexpr char kThreadGroup1A[] = "192.168.217.1";
|
|
static constexpr char kThreadGroup2A[] = "192.168.217.2";
|
|
|
|
static constexpr uint16_t kTypePrivateUse = 65285; // 0xFF05
|
|
static constexpr uint32_t kPrivateData = 0x12345678;
|
|
|
|
static Node *sEth1Node = nullptr;
|
|
|
|
bool HandleUdpHook(Instance &aInstance, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
|
{
|
|
Node &node = AsNode(&aInstance);
|
|
Dns::Header dnsHeader;
|
|
char name[Dns::Name::kMaxNameSize];
|
|
uint16_t readPos;
|
|
uint16_t qType;
|
|
uint16_t qClass;
|
|
Message *response;
|
|
bool handled = false;
|
|
|
|
VerifyOrExit(&node == sEth1Node);
|
|
VerifyOrExit(aMessageInfo.GetSockPort() == UpstreamDns::kDnsPort);
|
|
|
|
SuccessOrExit(aMessage.Read(aMessage.GetOffset(), dnsHeader));
|
|
VerifyOrExit(dnsHeader.GetType() == Dns::Header::kTypeQuery);
|
|
VerifyOrExit(dnsHeader.GetQuestionCount() == 1);
|
|
|
|
readPos = aMessage.GetOffset() + sizeof(dnsHeader);
|
|
SuccessOrExit(Dns::Name::ReadName(aMessage, readPos, name));
|
|
SuccessOrExit(aMessage.Read(readPos, qType));
|
|
qType = BigEndian::HostSwap16(qType);
|
|
readPos += sizeof(uint16_t);
|
|
SuccessOrExit(aMessage.Read(readPos, qClass));
|
|
qClass = BigEndian::HostSwap16(qClass);
|
|
readPos += sizeof(uint16_t);
|
|
|
|
Log("Eth_1 received DNS query for '%s' (type %u)", name, qType);
|
|
|
|
response = node.Get<MessagePool>().Allocate(Message::kTypeIp6);
|
|
VerifyOrExit(response != nullptr);
|
|
|
|
dnsHeader.SetType(Dns::Header::kTypeResponse);
|
|
dnsHeader.SetAnswerCount(0);
|
|
dnsHeader.SetRecursionDesiredFlag();
|
|
dnsHeader.SetRecursionAvailableFlag();
|
|
|
|
if (Dns::Name::IsSameDomain(name, kThreadGroup1))
|
|
{
|
|
if (qType == Dns::ResourceRecord::kTypeAaaa)
|
|
{
|
|
Ip6::Address address;
|
|
Dns::ResourceRecord rr;
|
|
|
|
SuccessOrQuit(address.FromString(kThreadGroup1Aaaa));
|
|
dnsHeader.SetAnswerCount(1);
|
|
SuccessOrQuit(response->Append(dnsHeader));
|
|
SuccessOrQuit(Dns::Name::AppendName(name, *response));
|
|
SuccessOrQuit(response->Append(BigEndian::HostSwap16(qType)));
|
|
SuccessOrQuit(response->Append(BigEndian::HostSwap16(qClass)));
|
|
SuccessOrQuit(Dns::Name::AppendName(name, *response));
|
|
rr.Init(Dns::ResourceRecord::kTypeAaaa);
|
|
rr.SetTtl(1800);
|
|
rr.SetLength(sizeof(Ip6::Address));
|
|
SuccessOrQuit(response->Append(rr));
|
|
SuccessOrQuit(response->Append(address));
|
|
Log("Eth_1 sending AAAA response for %s: %s", name, kThreadGroup1Aaaa);
|
|
}
|
|
else if (qType == Dns::ResourceRecord::kTypeA)
|
|
{
|
|
Ip4::Address address;
|
|
Dns::ResourceRecord rr;
|
|
|
|
SuccessOrQuit(address.FromString(kThreadGroup1A));
|
|
dnsHeader.SetAnswerCount(1);
|
|
SuccessOrQuit(response->Append(dnsHeader));
|
|
SuccessOrQuit(Dns::Name::AppendName(name, *response));
|
|
SuccessOrQuit(response->Append(BigEndian::HostSwap16(qType)));
|
|
SuccessOrQuit(response->Append(BigEndian::HostSwap16(qClass)));
|
|
SuccessOrQuit(Dns::Name::AppendName(name, *response));
|
|
rr.Init(Dns::ResourceRecord::kTypeA);
|
|
rr.SetTtl(1800);
|
|
rr.SetLength(sizeof(Ip4::Address));
|
|
SuccessOrQuit(response->Append(rr));
|
|
SuccessOrQuit(response->Append(address));
|
|
Log("Eth_1 sending A response for %s: %s", name, kThreadGroup1A);
|
|
}
|
|
}
|
|
else if (Dns::Name::IsSameDomain(name, kThreadGroup2))
|
|
{
|
|
if (qType == Dns::ResourceRecord::kTypeA)
|
|
{
|
|
Ip4::Address address;
|
|
Dns::ResourceRecord rr;
|
|
|
|
SuccessOrQuit(address.FromString(kThreadGroup2A));
|
|
dnsHeader.SetAnswerCount(1);
|
|
SuccessOrQuit(response->Append(dnsHeader));
|
|
SuccessOrQuit(Dns::Name::AppendName(name, *response));
|
|
SuccessOrQuit(response->Append(BigEndian::HostSwap16(qType)));
|
|
SuccessOrQuit(response->Append(BigEndian::HostSwap16(qClass)));
|
|
SuccessOrQuit(Dns::Name::AppendName(name, *response));
|
|
rr.Init(Dns::ResourceRecord::kTypeA);
|
|
rr.SetTtl(1800);
|
|
rr.SetLength(sizeof(Ip4::Address));
|
|
SuccessOrQuit(response->Append(rr));
|
|
SuccessOrQuit(response->Append(address));
|
|
Log("Eth_1 sending A response for %s: %s", name, kThreadGroup2A);
|
|
}
|
|
else if (qType == kTypePrivateUse)
|
|
{
|
|
Dns::ResourceRecord rr;
|
|
uint32_t data = BigEndian::HostSwap32(kPrivateData);
|
|
|
|
dnsHeader.SetAnswerCount(1);
|
|
SuccessOrQuit(response->Append(dnsHeader));
|
|
SuccessOrQuit(Dns::Name::AppendName(name, *response));
|
|
SuccessOrQuit(response->Append(BigEndian::HostSwap16(qType)));
|
|
SuccessOrQuit(response->Append(BigEndian::HostSwap16(qClass)));
|
|
SuccessOrQuit(Dns::Name::AppendName(name, *response));
|
|
rr.Init(kTypePrivateUse);
|
|
rr.SetTtl(1800);
|
|
rr.SetLength(sizeof(uint32_t));
|
|
SuccessOrQuit(response->Append(rr));
|
|
SuccessOrQuit(response->Append(data));
|
|
Log("Eth_1 sending PrivateUse response for %s", name);
|
|
}
|
|
}
|
|
|
|
if (dnsHeader.GetAnswerCount() == 0)
|
|
{
|
|
Log("Eth_1 sending empty response for %s", name);
|
|
SuccessOrQuit(response->Append(dnsHeader));
|
|
SuccessOrQuit(Dns::Name::AppendName(name, *response));
|
|
SuccessOrQuit(response->Append(BigEndian::HostSwap16(qType)));
|
|
SuccessOrQuit(response->Append(BigEndian::HostSwap16(qClass)));
|
|
}
|
|
|
|
node.mInfraIf.SendUdp(aMessageInfo.GetSockAddr(), aMessageInfo.GetPeerAddr(), UpstreamDns::kDnsPort,
|
|
aMessageInfo.GetPeerPort(), *response);
|
|
handled = true;
|
|
|
|
exit:
|
|
return handled;
|
|
}
|
|
|
|
void HandleDnsResponse(otError aError, const otDnsAddressResponse *aResponse, void *aContext)
|
|
{
|
|
OT_UNUSED_VARIABLE(aError);
|
|
OT_UNUSED_VARIABLE(aResponse);
|
|
OT_UNUSED_VARIABLE(aContext);
|
|
}
|
|
|
|
void HandleDnsRecordResponse(otError aError, const otDnsRecordResponse *aResponse, void *aContext)
|
|
{
|
|
OT_UNUSED_VARIABLE(aError);
|
|
OT_UNUSED_VARIABLE(aResponse);
|
|
OT_UNUSED_VARIABLE(aContext);
|
|
}
|
|
|
|
void SendQuery(Node &aNode, const char *aName, uint16_t aType)
|
|
{
|
|
if (aType == Dns::ResourceRecord::kTypeAaaa)
|
|
{
|
|
SuccessOrQuit(aNode.Get<Dns::Client>().ResolveAddress(aName, HandleDnsResponse, nullptr));
|
|
}
|
|
else
|
|
{
|
|
SuccessOrQuit(aNode.Get<Dns::Client>().QueryRecord(aType, nullptr, aName, HandleDnsRecordResponse, nullptr));
|
|
}
|
|
}
|
|
|
|
void SendRa(Node &aNode, const Ip6::Address &aDnsAddr, const Ip6::Prefix &aPrefix)
|
|
{
|
|
Ip6::Nd::RouterAdvert::TxMessage ra;
|
|
Ip6::Nd::RouterAdvert::Header header;
|
|
Ip6::Nd::Icmp6Packet packet;
|
|
|
|
header.SetToDefault();
|
|
header.SetRouterLifetime(1800);
|
|
SuccessOrQuit(ra.Append(header));
|
|
SuccessOrQuit(ra.AppendPrefixInfoOption(
|
|
aPrefix, 1800, 1800, Ip6::Nd::PrefixInfoOption::kOnLinkFlag | Ip6::Nd::PrefixInfoOption::kAutoConfigFlag));
|
|
SuccessOrQuit(ra.AppendRecursiveDnsServerOption(&aDnsAddr, 1, 1800));
|
|
ra.GetAsPacket(packet);
|
|
aNode.mInfraIf.SendIcmp6Nd(Ip6::Address::GetLinkLocalAllNodesMulticast(), packet.GetBytes(), packet.GetLength());
|
|
}
|
|
|
|
} // namespace
|
|
|
|
/**
|
|
* 11.5. [1.4] [CERT] DNS record types and special cases
|
|
*
|
|
* 11.5.1. Purpose
|
|
* To verify that the BR DUT:
|
|
* - Can resolve A records
|
|
* - Can resolve A records without doing IPv6 AAAA synthesis
|
|
* - Can resolve AAAA records
|
|
* - Can resolve records contributed by different sources (on-mesh, on-AIL, and upstream DNS server)
|
|
* - Supports non-typical record types (RRTypes) for queries
|
|
* - Supports queries using RR type 0xFF00-0xFFFE (65280-65534) “Private Use”
|
|
* - Blocks the “ipv4only.arpa” query
|
|
*/
|
|
void Test_1_4_DNS_TC_5(const char *aJsonFileName)
|
|
{
|
|
Core nexus;
|
|
Node &br1 = nexus.CreateNode();
|
|
Node &ed1 = nexus.CreateNode();
|
|
Node ð1 = nexus.CreateNode();
|
|
Ip6::Address eth1Addr;
|
|
Ip6::Address br1AilAddr;
|
|
Ip6::Prefix guaPrefix;
|
|
|
|
br1.SetName("BR", 1);
|
|
ed1.SetName("ED", 1);
|
|
eth1.SetName("Eth", 1);
|
|
|
|
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelNote));
|
|
|
|
sEth1Node = ð1;
|
|
eth1.mInfraIf.SetUdpHook(HandleUdpHook);
|
|
|
|
AllowLinkBetween(br1, ed1);
|
|
|
|
SuccessOrQuit(eth1Addr.FromString(kEth1Addr));
|
|
SuccessOrQuit(br1AilAddr.FromString(kBr1AilAddr));
|
|
SuccessOrQuit(guaPrefix.FromString(kGuaPrefix));
|
|
|
|
/**
|
|
* Step 1
|
|
* Device: Eth_1, BR_1, ED_1
|
|
* Description (DNS-11.5): Form topology. Thread network is formed.
|
|
* Pass Criteria:
|
|
* - N/A
|
|
*/
|
|
Log("Step 1: Form topology. Thread network is formed.");
|
|
|
|
eth1.Get<ThreadNetif>().Up();
|
|
eth1.mInfraIf.AddAddress(eth1Addr);
|
|
|
|
br1.Form();
|
|
nexus.AdvanceTime(kFormNetworkTime);
|
|
|
|
ed1.Join(br1, Node::kAsFed);
|
|
nexus.AdvanceTime(kJoinNetworkTime);
|
|
|
|
br1.Get<BorderRouter::InfraIf>().Init(1, true);
|
|
br1.mInfraIf.AddAddress(br1AilAddr);
|
|
br1.Get<BorderRouter::RoutingManager>().Init();
|
|
SuccessOrQuit(br1.Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
SuccessOrQuit(br1.Get<Dns::ServiceDiscovery::Server>().Start());
|
|
br1.Get<Dns::ServiceDiscovery::Server>().SetUpstreamQueryEnabled(true);
|
|
|
|
{
|
|
Dns::Client::QueryConfig dnsConfig;
|
|
dnsConfig.Clear();
|
|
AsCoreType(&dnsConfig.mServerSockAddr.mAddress) = br1.Get<Mle::Mle>().GetMeshLocalEid();
|
|
dnsConfig.mServerSockAddr.mPort = 53;
|
|
ed1.Get<Dns::Client>().SetDefaultConfig(dnsConfig);
|
|
}
|
|
|
|
// Send RA for BR to adopt the DNS server address and OMR prefix
|
|
SendRa(eth1, eth1Addr, guaPrefix);
|
|
nexus.AdvanceTime(kStabilizationTime);
|
|
|
|
/**
|
|
* Step 2
|
|
* Device: Eth_1
|
|
* Description (DNS-11.5): Harness instructs device to configure DNS server with
|
|
* records: threadgroup1.org AAAA 2002:1234::E1:1, threadgroup1.org A 192.168.217.1,
|
|
* threadgroup2.org A 192.168.217.2, threadgroup2.org TYPE65285 \# 4 12345678.
|
|
* Note: the record type 0xFF05 is a private range record type, hence it has the
|
|
* symbolic name TYPE65285 associated.
|
|
* Pass Criteria:
|
|
* - N/A
|
|
*/
|
|
Log("Step 2: Eth_1 configures DNS server with records.");
|
|
|
|
/**
|
|
* Step 3
|
|
* Device: Eth_1
|
|
* Description (DNS-11.5): Harness instructs device to start advertising mDNS
|
|
* services on the AIL: Note: the PTR records for services are not shown below;
|
|
* however these are present as usual. $ORIGIN local. Service-test-1.
|
|
* _infra-test._udp ( SRV 0 0 55551 host-test-eth TXT dummy=abcd;thread-test=a49 )
|
|
* service-test-2._infra-test._udp ( SRV 0 0 55552 host-test-eth TXT a=2;thread-test
|
|
* =b50_test ) ) host-test-eth A <IPv4 address of Eth_1>.
|
|
* Pass Criteria:
|
|
* - N/A
|
|
*/
|
|
Log("Step 3: Eth_1 starts advertising mDNS services on the AIL.");
|
|
{
|
|
Dns::Multicast::Core::Service mdnsService;
|
|
Ip6::Address eth1Ip4Addr;
|
|
Ip4::Address ip4Addr;
|
|
|
|
SuccessOrQuit(eth1.Get<Dns::Multicast::Core>().SetLocalHostName("host-test-eth"));
|
|
SuccessOrQuit(eth1.Get<Dns::Multicast::Core>().SetEnabled(true, 1));
|
|
|
|
SuccessOrQuit(ip4Addr.FromString("192.168.217.100"));
|
|
eth1Ip4Addr.InitAsIp4Mapped(ip4Addr);
|
|
eth1.mInfraIf.AddAddress(eth1Ip4Addr);
|
|
eth1.mMdns.SignalIfAddresses(eth1.GetInstance());
|
|
|
|
ClearAllBytes(mdnsService);
|
|
mdnsService.mServiceInstance = "service-test-1";
|
|
mdnsService.mServiceType = "_infra-test._udp";
|
|
mdnsService.mHostName = "host-test-eth";
|
|
static const uint8_t kTxtData1[] = "\x0adummy=abcd\x0fthread-test=a49";
|
|
mdnsService.mTxtData = kTxtData1;
|
|
mdnsService.mTxtDataLength = sizeof(kTxtData1) - 1;
|
|
mdnsService.mPort = 55551;
|
|
SuccessOrQuit(eth1.Get<Dns::Multicast::Core>().RegisterService(mdnsService, 1, nullptr));
|
|
|
|
mdnsService.mServiceInstance = "service-test-2";
|
|
mdnsService.mPort = 55552;
|
|
static const uint8_t kTxtData2[] = "\x03a=2\x14thread-test=b50_test";
|
|
mdnsService.mTxtData = kTxtData2;
|
|
mdnsService.mTxtDataLength = sizeof(kTxtData2) - 1;
|
|
SuccessOrQuit(eth1.Get<Dns::Multicast::Core>().RegisterService(mdnsService, 2, nullptr));
|
|
}
|
|
nexus.AdvanceTime(kStabilizationTime);
|
|
|
|
/**
|
|
* Step 4
|
|
* Device: ED_1
|
|
* Description (DNS-11.5): Harness instructs device to send a DNS query to the DUT
|
|
* with Qtype=AAAA for name “threadgroup1.org”.
|
|
* Pass Criteria:
|
|
* - N/A
|
|
*/
|
|
Log("Step 4: ED_1 sends a DNS query to the DUT with Qtype=AAAA for name threadgroup1.org.");
|
|
SendRa(eth1, eth1Addr, guaPrefix);
|
|
SendQuery(ed1, kThreadGroup1, Dns::ResourceRecord::kTypeAaaa);
|
|
nexus.AdvanceTime(kStabilizationTime);
|
|
|
|
/**
|
|
* Step 5
|
|
* Device: BR_1 (DUT)
|
|
* Description (DNS-11.5): Automatically performs the DNS query via the Eth_1 DNS
|
|
* server, and provides the answer back to ED_1.
|
|
* Pass Criteria:
|
|
* - The DUT MUST respond Rcode=0 (NoError) with answer record: threadgroup1.org
|
|
* AAAA 2002:1234::E1:1
|
|
*/
|
|
Log("Step 5: BR_1 performs the DNS query via Eth_1 and provides the answer to ED_1.");
|
|
|
|
/**
|
|
* Step 6
|
|
* Device: ED_1
|
|
* Description (DNS-11.5): Harness instructs device to send a DNS query to the DUT,
|
|
* with Qtype=A for name “threadgroup1.org”.
|
|
* Pass Criteria:
|
|
* - N/A
|
|
*/
|
|
Log("Step 6: ED_1 sends a DNS query to the DUT with Qtype=A for name threadgroup1.org.");
|
|
SendRa(eth1, eth1Addr, guaPrefix);
|
|
SendQuery(ed1, kThreadGroup1, Dns::ResourceRecord::kTypeA);
|
|
nexus.AdvanceTime(kStabilizationTime);
|
|
|
|
/**
|
|
* Step 7
|
|
* Device: BR_1 (DUT)
|
|
* Description (DNS-11.5): Automatically performs the DNS query via the Eth_1 DNS
|
|
* server, and provides the answer back to ED_1.
|
|
* Pass Criteria:
|
|
* - The DUT MUST respond Rcode=0 (NoError) with answer record: threadgroup1.org A
|
|
* 192.168.217.1
|
|
*/
|
|
Log("Step 7: BR_1 performs the DNS query via Eth_1 and provides the answer to ED_1.");
|
|
|
|
/**
|
|
* Step 8
|
|
* Device: ED_1
|
|
* Description (DNS-11.5): Harness instructs device to send a DNS query to the DUT,
|
|
* with Qtype=AAAA for name “threadgroup2.org”.
|
|
* Pass Criteria:
|
|
* - N/A
|
|
*/
|
|
Log("Step 8: ED_1 sends a DNS query to the DUT with Qtype=AAAA for name threadgroup2.org.");
|
|
SendRa(eth1, eth1Addr, guaPrefix);
|
|
SendQuery(ed1, kThreadGroup2, Dns::ResourceRecord::kTypeAaaa);
|
|
nexus.AdvanceTime(kStabilizationTime);
|
|
|
|
/**
|
|
* Step 9
|
|
* Device: BR_1 (DUT)
|
|
* Description (DNS-11.5): Automatically performs the DNS query via the Eth_1 DNS
|
|
* server, and provides the error answer back to ED_1. Note: this checks that the
|
|
* DUT does not perform AAAA synthesis from the A record.
|
|
* Pass Criteria:
|
|
* - The DUT MUST respond Rcode=0 (NoError) with zero answer records (ANCOUNT=0).
|
|
*/
|
|
Log("Step 9: BR_1 performs the DNS query via Eth_1 and provides the error answer to ED_1.");
|
|
|
|
/**
|
|
* Step 10
|
|
* Device: ED_1
|
|
* Description (DNS-11.5): Harness instructs device to send a DNS query, with
|
|
* Qtype=A for name “host-test-eth.default.service.arpa”.
|
|
* Pass Criteria:
|
|
* - N/A
|
|
*/
|
|
Log("Step 10: ED_1 sends a DNS query with Qtype=A for host-test-eth.default.service.arpa.");
|
|
SendQuery(ed1, "host-test-eth.default.service.arpa", Dns::ResourceRecord::kTypeA);
|
|
nexus.AdvanceTime(kStabilizationTime);
|
|
|
|
/**
|
|
* Step 11
|
|
* Device: BR_1 (DUT)
|
|
* Description (DNS-11.5): Automatically performs the mDNS query on AIL
|
|
* (optionally, if still needed), and provides the answer back to ED_1.
|
|
* Pass Criteria:
|
|
* - The DUT MUST respond Rcode=0 (NoError) with answer record: host-test-eth.
|
|
* default.service.arpa A <IPv4 address of Eth_1>
|
|
*/
|
|
Log("Step 11: BR_1 performs mDNS query on AIL and provides the answer to ED_1.");
|
|
|
|
/**
|
|
* Step 12
|
|
* Device: ED_1
|
|
* Description (DNS-11.5): Harness instructs device to send DNS query Qtype=A for
|
|
* name “ipv4only.arpa”
|
|
* Pass Criteria:
|
|
* - N/A
|
|
*/
|
|
Log("Step 12: ED_1 sends DNS query Qtype=A for name ipv4only.arpa.");
|
|
SendQuery(ed1, "ipv4only.arpa", Dns::ResourceRecord::kTypeA);
|
|
nexus.AdvanceTime(kStabilizationTime);
|
|
|
|
/**
|
|
* Step 13
|
|
* Device: BR_1 (DUT)
|
|
* Description (DNS-11.5): Automatically blocks the ipv4only.arpa query and
|
|
* responds NXDomain error.
|
|
* Pass Criteria:
|
|
* - The DUT MUST respond Rcode=3 (NXDomain) with zero answer records (ANCOUNT=0).
|
|
* - The DUT MUST NOT send a DNS query to Eth_1.
|
|
*/
|
|
Log("Step 13: BR_1 blocks the ipv4only.arpa query and responds NXDomain error.");
|
|
|
|
/**
|
|
* Step 14
|
|
* Device: ED_1
|
|
* Description (DNS-11.5): Harness instructs device to send DNS query with RR type
|
|
* in the private use range Qtype=0xFF05 for name “threadgroup2.org”. To do this
|
|
* with OT CLI, use the following: udp send <BR_1 ML-EID address> 53 -x
|
|
* e13c010000010000000000000c74687265616467726f757032036f726700ff050001 “”
|
|
* Pass Criteria:
|
|
* - N/A
|
|
*/
|
|
Log("Step 14: ED_1 sends DNS query with RR type in private use range Qtype=0xFF05.");
|
|
SendRa(eth1, eth1Addr, guaPrefix);
|
|
SendQuery(ed1, kThreadGroup2, kTypePrivateUse);
|
|
nexus.AdvanceTime(kStabilizationTime);
|
|
|
|
/**
|
|
* Step 15
|
|
* Device: BR_1 (DUT)
|
|
* Description (DNS-11.5): Automatically responds with the requested record.
|
|
* Pass Criteria:
|
|
* - The DUT MUST respond Rcode=0 (NoError) with answer record with binary data
|
|
* (4 bytes): threadgroup2.org 0xFF05 0x12345678
|
|
*/
|
|
Log("Step 15: BR_1 responds with the requested record.");
|
|
|
|
nexus.SaveTestInfo(aJsonFileName);
|
|
}
|
|
|
|
} // namespace Nexus
|
|
} // namespace ot
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
ot::Nexus::Test_1_4_DNS_TC_5((argc > 2) ? argv[2] : "test_1_4_dns_tc_5.json");
|
|
ot::Nexus::Log("All tests passed");
|
|
return 0;
|
|
}
|