mirror of
https://github.com/espressif/openthread.git
synced 2026-07-31 08:07:47 +00:00
[cli] add support for DNS-SD command (#6116)
This commit adds new commands in CLI to support DNS-SD browse and service resolution.
This commit is contained in:
committed by
Jonathan Hui
parent
7084422a0e
commit
4538a5fb7c
@@ -758,6 +758,30 @@ Send DNS Query to obtain IPv6 address for given hostname. The latter two paramet
|
||||
> DNS response for ipv6.google.com - 2a00:1450:401b:801:0:0:0:200e TTL: 300
|
||||
```
|
||||
|
||||
### dns browse \<service-name\> \[DNS server IP\] \[DNS server port\]
|
||||
|
||||
Send a browse (service instance enumeration) DNS query to get the list of services for given service-name.
|
||||
|
||||
```bash
|
||||
> dns browse _service._udp.example.com
|
||||
DNS browse response for _service._udp.example.com.
|
||||
inst1
|
||||
Port:1234, Priority:1, Weight:2, TTL:7200
|
||||
Host:host.example.com.
|
||||
HostAddress:fd00:0:0:0:0:0:0:abcd TTL:7200
|
||||
TXT-Data:(len:11) [096b65793d76616c756500] TTL:7300
|
||||
instance2
|
||||
Port:1234, Priority:1, Weight:2, TTL:7200
|
||||
Host:host.example.com.
|
||||
HostAddress:fd00:0:0:0:0:0:0:abcd TTL:7200
|
||||
TXT-Data:(len:11) [096b65793d76616c756500] TTL:7300
|
||||
Done
|
||||
```
|
||||
|
||||
### dns service \<service-instance-label\> \<service-name\> \[DNS server IP\] \[DNS server port\]
|
||||
|
||||
Send a service instance resolution DNS query for a given service instance. Service instance label is provided first, followed by the service name (note that service instance label can contain dot '.' character).
|
||||
|
||||
### domainname
|
||||
|
||||
Get the Thread Domain Name for Thread 1.2 device.
|
||||
|
||||
+149
-24
@@ -1335,37 +1335,70 @@ exit:
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE
|
||||
|
||||
otError Interpreter::GetDnsServerAddress(uint8_t aArgsLength,
|
||||
char * aArgs[],
|
||||
otSockAddr &aAddress,
|
||||
uint8_t aStartArgsIndex)
|
||||
{
|
||||
// This method gets the optional server address from given `aArgs`
|
||||
// after the `aStartArgsIndex`. The format `[server IPv6 address]
|
||||
// [server port]`.
|
||||
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(aArgsLength >= aStartArgsIndex, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
if (aArgsLength > aStartArgsIndex)
|
||||
{
|
||||
SuccessOrExit(error = ParseAsIp6Address(aArgs[aStartArgsIndex], aAddress.mAddress));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use IPv6 address of default DNS server.
|
||||
SuccessOrExit(error = otIp6AddressFromString(OT_DNS_DEFAULT_SERVER_IP, &aAddress.mAddress));
|
||||
}
|
||||
|
||||
if (aArgsLength > aStartArgsIndex + 1)
|
||||
{
|
||||
SuccessOrExit(error = ParseAsUint16(aArgs[aStartArgsIndex + 1], aAddress.mPort));
|
||||
}
|
||||
else
|
||||
{
|
||||
aAddress.mPort = OT_DNS_DEFAULT_SERVER_PORT;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Interpreter::ProcessDns(uint8_t aArgsLength, char *aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
otSockAddr serverSockAddr;
|
||||
|
||||
serverSockAddr.mPort = OT_DNS_DEFAULT_SERVER_PORT;
|
||||
|
||||
VerifyOrExit(aArgsLength > 0, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
if (strcmp(aArgs[0], "resolve") == 0)
|
||||
{
|
||||
VerifyOrExit(aArgsLength > 1, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
if (aArgsLength > 2)
|
||||
{
|
||||
SuccessOrExit(error = ParseAsIp6Address(aArgs[2], serverSockAddr.mAddress));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use IPv6 address of default DNS server.
|
||||
SuccessOrExit(error = otIp6AddressFromString(OT_DNS_DEFAULT_SERVER_IP, &serverSockAddr.mAddress));
|
||||
}
|
||||
|
||||
if (aArgsLength > 3)
|
||||
{
|
||||
SuccessOrExit(error = ParseAsUint16(aArgs[3], serverSockAddr.mPort));
|
||||
}
|
||||
|
||||
SuccessOrExit(error = GetDnsServerAddress(aArgsLength, aArgs, serverSockAddr, 2));
|
||||
SuccessOrExit(error = otDnsClientResolveAddress(mInstance, &serverSockAddr, aArgs[1], /* aNoRecursion */ false,
|
||||
&Interpreter::HandleDnsResponse, this));
|
||||
&Interpreter::HandleDnsAddressResponse, this));
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
else if (strcmp(aArgs[0], "browse") == 0)
|
||||
{
|
||||
SuccessOrExit(error = GetDnsServerAddress(aArgsLength, aArgs, serverSockAddr, 2));
|
||||
SuccessOrExit(error = otDnsClientBrowse(mInstance, &serverSockAddr, aArgs[1],
|
||||
&Interpreter::HandleDnsBrowseResponse, this));
|
||||
}
|
||||
else if (strcmp(aArgs[0], "service") == 0)
|
||||
{
|
||||
SuccessOrExit(error = GetDnsServerAddress(aArgsLength, aArgs, serverSockAddr, 3));
|
||||
SuccessOrExit(error = otDnsClientResolveService(mInstance, &serverSockAddr, aArgs[1], aArgs[2],
|
||||
&Interpreter::HandleDnsServiceResponse, this));
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
else
|
||||
{
|
||||
ExitNow(error = OT_ERROR_INVALID_COMMAND);
|
||||
@@ -1377,12 +1410,12 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Interpreter::HandleDnsResponse(otError aError, const otDnsAddressResponse *aResponse, void *aContext)
|
||||
void Interpreter::HandleDnsAddressResponse(otError aError, const otDnsAddressResponse *aResponse, void *aContext)
|
||||
{
|
||||
static_cast<Interpreter *>(aContext)->HandleDnsResponse(aError, aResponse);
|
||||
static_cast<Interpreter *>(aContext)->HandleDnsAddressResponse(aError, aResponse);
|
||||
}
|
||||
|
||||
void Interpreter::HandleDnsResponse(otError aError, const otDnsAddressResponse *aResponse)
|
||||
void Interpreter::HandleDnsAddressResponse(otError aError, const otDnsAddressResponse *aResponse)
|
||||
{
|
||||
char hostName[OT_DNS_MAX_NAME_SIZE];
|
||||
otIp6Address address;
|
||||
@@ -1399,7 +1432,7 @@ void Interpreter::HandleDnsResponse(otError aError, const otDnsAddressResponse *
|
||||
while (otDnsAddressResponseGetAddress(aResponse, index, &address, &ttl) == OT_ERROR_NONE)
|
||||
{
|
||||
OutputIp6Address(address);
|
||||
OutputFormat(" TTL: %u ", ttl);
|
||||
OutputFormat(" TTL:%u ", ttl);
|
||||
index++;
|
||||
}
|
||||
|
||||
@@ -1408,6 +1441,98 @@ void Interpreter::HandleDnsResponse(otError aError, const otDnsAddressResponse *
|
||||
|
||||
OutputResult(aError);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
|
||||
void Interpreter::OutputDnsServiceInfo(uint8_t aIndentSize, const otDnsServiceInfo &aServiceInfo)
|
||||
{
|
||||
OutputLine(aIndentSize, "Port:%d, Priority:%d, Weight:%d, TTL:%u", aServiceInfo.mPort, aServiceInfo.mPriority,
|
||||
aServiceInfo.mWeight, aServiceInfo.mTtl);
|
||||
OutputLine(aIndentSize, "Host:%s", aServiceInfo.mHostNameBuffer);
|
||||
OutputFormat(aIndentSize, "HostAddress:");
|
||||
OutputIp6Address(aServiceInfo.mHostAddress);
|
||||
OutputLine(" TTL:%u", aServiceInfo.mHostAddressTtl);
|
||||
OutputFormat(aIndentSize, "TXT-Data:(len:%d) [", aServiceInfo.mTxtDataSize);
|
||||
OutputBytes(aServiceInfo.mTxtData, aServiceInfo.mTxtDataSize);
|
||||
OutputFormat("] TTL:%u", aServiceInfo.mTxtDataTtl);
|
||||
}
|
||||
|
||||
void Interpreter::HandleDnsBrowseResponse(otError aError, const otDnsBrowseResponse *aResponse, void *aContext)
|
||||
{
|
||||
static_cast<Interpreter *>(aContext)->HandleDnsBrowseResponse(aError, aResponse);
|
||||
}
|
||||
|
||||
void Interpreter::HandleDnsBrowseResponse(otError aError, const otDnsBrowseResponse *aResponse)
|
||||
{
|
||||
char name[OT_DNS_MAX_NAME_SIZE];
|
||||
char label[OT_DNS_MAX_LABEL_SIZE];
|
||||
uint8_t txtBuffer[255];
|
||||
otDnsServiceInfo serviceInfo;
|
||||
|
||||
IgnoreError(otDnsBrowseResponseGetServiceName(aResponse, name, sizeof(name)));
|
||||
|
||||
OutputLine("DNS browse response for %s", name);
|
||||
|
||||
if (aError == OT_ERROR_NONE)
|
||||
{
|
||||
uint16_t index = 0;
|
||||
|
||||
while (otDnsBrowseResponseGetServiceInstance(aResponse, index, label, sizeof(label)) == OT_ERROR_NONE)
|
||||
{
|
||||
OutputLine("%s", label);
|
||||
index++;
|
||||
|
||||
serviceInfo.mHostNameBuffer = name;
|
||||
serviceInfo.mHostNameBufferSize = sizeof(name);
|
||||
serviceInfo.mTxtData = txtBuffer;
|
||||
serviceInfo.mTxtDataSize = sizeof(txtBuffer);
|
||||
|
||||
if (otDnsBrowseResponseGetServiceInfo(aResponse, label, &serviceInfo) == OT_ERROR_NONE)
|
||||
{
|
||||
OutputDnsServiceInfo(kIndentSize, serviceInfo);
|
||||
}
|
||||
|
||||
OutputLine("");
|
||||
}
|
||||
}
|
||||
|
||||
OutputResult(aError);
|
||||
}
|
||||
|
||||
void Interpreter::HandleDnsServiceResponse(otError aError, const otDnsServiceResponse *aResponse, void *aContext)
|
||||
{
|
||||
static_cast<Interpreter *>(aContext)->HandleDnsServiceResponse(aError, aResponse);
|
||||
}
|
||||
|
||||
void Interpreter::HandleDnsServiceResponse(otError aError, const otDnsServiceResponse *aResponse)
|
||||
{
|
||||
char name[OT_DNS_MAX_NAME_SIZE];
|
||||
char label[OT_DNS_MAX_LABEL_SIZE];
|
||||
uint8_t txtBuffer[255];
|
||||
otDnsServiceInfo serviceInfo;
|
||||
|
||||
IgnoreError(otDnsServiceResponseGetServiceName(aResponse, label, sizeof(label), name, sizeof(name)));
|
||||
|
||||
OutputLine("DNS service resolution response for %s for service %s", label, name);
|
||||
|
||||
if (aError == OT_ERROR_NONE)
|
||||
{
|
||||
serviceInfo.mHostNameBuffer = name;
|
||||
serviceInfo.mHostNameBufferSize = sizeof(name);
|
||||
serviceInfo.mTxtData = txtBuffer;
|
||||
serviceInfo.mTxtDataSize = sizeof(txtBuffer);
|
||||
|
||||
if (otDnsServiceResponseGetServiceInfo(aResponse, &serviceInfo) == OT_ERROR_NONE)
|
||||
{
|
||||
OutputDnsServiceInfo(/* aIndetSize */ 0, serviceInfo);
|
||||
OutputLine("");
|
||||
}
|
||||
}
|
||||
|
||||
OutputResult(aError);
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
#endif // OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
+10
-2
@@ -554,8 +554,16 @@ private:
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE
|
||||
static void HandleDnsResponse(otError aError, const otDnsAddressResponse *aResponse, void *aContext);
|
||||
void HandleDnsResponse(otError aError, const otDnsAddressResponse *aResponse);
|
||||
otError GetDnsServerAddress(uint8_t aArgsLength, char *aArgs[], otSockAddr &aAddress, uint8_t aStartArgsIndex);
|
||||
static void HandleDnsAddressResponse(otError aError, const otDnsAddressResponse *aResponse, void *aContext);
|
||||
void HandleDnsAddressResponse(otError aError, const otDnsAddressResponse *aResponse);
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
void OutputDnsServiceInfo(uint8_t aIndentSize, const otDnsServiceInfo &aServiceInfo);
|
||||
static void HandleDnsBrowseResponse(otError aError, const otDnsBrowseResponse *aResponse, void *aContext);
|
||||
void HandleDnsBrowseResponse(otError aError, const otDnsBrowseResponse *aResponse);
|
||||
static void HandleDnsServiceResponse(otError aError, const otDnsServiceResponse *aResponse, void *aContext);
|
||||
void HandleDnsServiceResponse(otError aError, const otDnsServiceResponse *aResponse);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
|
||||
|
||||
@@ -2411,12 +2411,13 @@ class NodeImpl:
|
||||
self.simulator.go(10)
|
||||
output = self._expect_command_output(cmd)
|
||||
dns_resp = output[0]
|
||||
# example output: DNS response for host1.default.service.arpa. - fd00:db8:0:0:ae43:4938:4c42:e6af TTL: 7190
|
||||
ip, ttl = dns_resp.split(' - ')[1].split(' TTL: ')
|
||||
ip = ip.strip()
|
||||
ttl = int(ttl)
|
||||
# example output: "DNS response for host1.default.service.arpa. - fd00:db8:0:0:fd3d:d471:1e8c:b60 TTL:7190 "
|
||||
# " fd00:db8:0:0:0:ff:fe00:9000 TTL:7190"
|
||||
addrs = dns_resp.strip().split(' - ')[1].split(' ')
|
||||
ip = [item.strip() for item in addrs[::2]]
|
||||
ttl = [int(item.split('TTL:')[1]) for item in addrs[1::2]]
|
||||
|
||||
return (ip, ttl)
|
||||
return list(zip(ip, ttl))
|
||||
|
||||
|
||||
class Node(NodeImpl, OtCli):
|
||||
|
||||
@@ -88,11 +88,11 @@ class TestDnssd(thread_cert.TestCase):
|
||||
self._config_srp_client_services(CLIENT2, 'ins2', 'host2', 22222, 2, 2, client2_addrs)
|
||||
|
||||
# Test AAAA query using DNS client
|
||||
ip, ttl = self.nodes[CLIENT1].dns_resolve(f"host1.{DOMAIN}", self.nodes[SERVER].get_mleid(), 53)
|
||||
self.assertIn(ipaddress.IPv6Address(ip), map(ipaddress.IPv6Address, client1_addrs))
|
||||
response = self.nodes[CLIENT1].dns_resolve(f"host1.{DOMAIN}", self.nodes[SERVER].get_mleid(), 53)
|
||||
self.assertIn(ipaddress.IPv6Address(response[0][0]), map(ipaddress.IPv6Address, client1_addrs))
|
||||
|
||||
ip, ttl = self.nodes[CLIENT1].dns_resolve(f"host2.{DOMAIN}", self.nodes[SERVER].get_mleid(), 53)
|
||||
self.assertIn(ipaddress.IPv6Address(ip), map(ipaddress.IPv6Address, client2_addrs))
|
||||
response = self.nodes[CLIENT1].dns_resolve(f"host2.{DOMAIN}", self.nodes[SERVER].get_mleid(), 53)
|
||||
self.assertIn(ipaddress.IPv6Address(response[0][0]), map(ipaddress.IPv6Address, client2_addrs))
|
||||
|
||||
# TODO: test other query types using DNS-SD client
|
||||
|
||||
|
||||
Reference in New Issue
Block a user