mirror of
https://github.com/espressif/openthread.git
synced 2026-10-22 23:48:18 +00:00
[dnssd] support generic record queries via discovery proxy and SRP (#11357)
This commit enhances the OpenThread DNSSD name server/resolver and its native Discovery Proxy to support queries for arbitrary record types. To enable this, a new set of `otPlatDnssd` APIs are introduced for generic `RecordQuerier`. These APIs mirror the existing APIs in the OpenThread native mDNS module, allowing direct use of the native mDNS implementation. The discovery proxy implementation is updated to start and stop the mDNS `RecordQuerier` when receiving a query for an arbitrary record type, passing the first response record back to the client. The unit tests `test_dnssd_discovery_proxy` and `test_dns_client` are updated to cover all the newly added behaviors in discovery proxy.
This commit is contained in:
@@ -196,11 +196,6 @@ class TestDnssdServerOnBr(thread_cert.TestCase):
|
||||
})
|
||||
|
||||
# check some invalid queries
|
||||
for qtype in ['CNAME']:
|
||||
dig_result = digger.dns_dig(server_addr, host1_full_name, qtype)
|
||||
self._assert_dig_result_matches(dig_result, {
|
||||
'status': 'NOTIMP',
|
||||
})
|
||||
|
||||
for service_name in WRONG_SERVICE_NAMES:
|
||||
dig_result = digger.dns_dig(server_addr, service_name, 'PTR')
|
||||
|
||||
@@ -278,11 +278,6 @@ class TestDnssdServerOnMultiBr(thread_cert.TestCase):
|
||||
self._verify_discovery_proxy_meshcop(br2_addr, br2.get_network_name(), host)
|
||||
|
||||
# 4. Check some invalid queries
|
||||
for qtype in ['CNAME']:
|
||||
dig_result = host.dns_dig(br2_addr, host1_full_name, qtype)
|
||||
self._assert_dig_result_matches(dig_result, {
|
||||
'status': 'NOTIMP',
|
||||
})
|
||||
|
||||
for service_name in WRONG_SERVICE_NAMES:
|
||||
dig_result = host.dns_dig(br2_addr, service_name, 'PTR')
|
||||
|
||||
@@ -3581,6 +3581,52 @@ class NodeImpl:
|
||||
index = index + (5 if result[ins] else 1)
|
||||
return result
|
||||
|
||||
def dns_query(self, rrtype, first_label, next_labels, server=None, port=53):
|
||||
"""
|
||||
Send a DNS query for a given record type and name.
|
||||
|
||||
Output is an array of records (as dictionary) with string keys and values.
|
||||
[
|
||||
{'RecordType': '25',
|
||||
'RecordLength': '78',
|
||||
'TTL': '7105',
|
||||
'Section': 'answer',
|
||||
'Name': 'ins1._IPPS._TCP.DEFAULT.SERVICE.ARPA.',
|
||||
'RecordData': '[001900010000a0610...d45d3]'
|
||||
}
|
||||
]
|
||||
"""
|
||||
cmd = f'dns query {rrtype} {first_label} {next_labels}'
|
||||
if server is not None:
|
||||
cmd += f' {server} {port}'
|
||||
|
||||
self.send_command(cmd)
|
||||
self.simulator.go(10)
|
||||
output = self._expect_command_output()
|
||||
|
||||
# Example output:
|
||||
# DNS query response for ins1._IPPS._TCP.DEFAULT.SERVICE.ARPA.
|
||||
# 0)
|
||||
# RecordType:25, RecordLength:78, TTL:7105, Section:answer
|
||||
# Name:ins1._IPPS._TCP.DEFAULT.SERVICE.ARPA.
|
||||
# RecordData:[00190001000...cdb]
|
||||
# Done
|
||||
|
||||
result = []
|
||||
index = 1 # Skip first line
|
||||
while (index < len(output)):
|
||||
if (index > len(output) - 4):
|
||||
break
|
||||
record = {}
|
||||
for line in output[index + 1:index + 4]:
|
||||
for item in line.strip().split(','):
|
||||
k, v = item.split(':')
|
||||
record[k.strip()] = v.strip()
|
||||
result.append(record)
|
||||
index += 4
|
||||
|
||||
return result
|
||||
|
||||
def set_mliid(self, mliid: str):
|
||||
cmd = f'mliid {mliid}'
|
||||
self.send_command(cmd)
|
||||
|
||||
@@ -209,6 +209,54 @@ class TestDnssd(thread_cert.TestCase):
|
||||
service_instance = client1.dns_resolve_service('ins4', f'{SERVICE}.{DOMAIN}'.upper(), server.get_mleid(), 53)
|
||||
self._assert_service_instance_equal(service_instance, instance4_verify_info)
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Query for KEY record for `ins1` service name
|
||||
|
||||
records = client1.dns_query(25, 'ins1', f'{SERVICE}.{DOMAIN}'.upper(), server.get_mleid(), 53)
|
||||
self.assertEqual(len(records), 1)
|
||||
record = records[0]
|
||||
self.assertEqual(int(record['RecordType']), 25)
|
||||
self.assertEqual(int(record['RecordLength']), 78)
|
||||
self.assertTrue(int(record['TTL']) > 0)
|
||||
self.assertEqual(record['Section'], 'answer')
|
||||
self.assertEqual(record['Name'].lower(), 'ins1._ipps._tcp.default.service.arpa.')
|
||||
self.assertIn('RecordData', record)
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Query for SRV record for `ins1` service name
|
||||
|
||||
records = client1.dns_query(33, 'ins1', f'{SERVICE}.{DOMAIN}'.upper(), server.get_mleid(), 53)
|
||||
self.assertEqual(len(records), 4)
|
||||
|
||||
# SRV record in answer section
|
||||
record = records[0]
|
||||
self.assertEqual(int(record['RecordType']), 33)
|
||||
self.assertTrue(int(record['RecordLength']) > 0)
|
||||
self.assertTrue(int(record['TTL']) > 0)
|
||||
self.assertEqual(record['Section'], 'answer')
|
||||
self.assertEqual(record['Name'].lower(), 'ins1._ipps._tcp.default.service.arpa.')
|
||||
self.assertIn('RecordData', record)
|
||||
|
||||
# Other records TXT and A in additional section
|
||||
for record in records[1:]:
|
||||
self.assertTrue(int(record['RecordLength']) > 0)
|
||||
self.assertIn('RecordData', record)
|
||||
self.assertTrue(int(record['TTL']) > 0)
|
||||
self.assertEqual(record['Section'], 'additional')
|
||||
rrtype = int(record['RecordType'])
|
||||
self.assertIn(rrtype, [16, 28]) # TXT and AAAA
|
||||
if rrtype == 16:
|
||||
self.assertEqual(record['Name'].lower(), 'ins1._ipps._tcp.default.service.arpa.')
|
||||
self.assertEqual(record['RecordData'], '[00]')
|
||||
else:
|
||||
self.assertEqual(record['Name'].lower(), 'host1.default.service.arpa.')
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Query for non-existing A record for `ins1` service name
|
||||
|
||||
records = client1.dns_query(1, 'ins1', f'{SERVICE}.{DOMAIN}'.upper(), server.get_mleid(), 53)
|
||||
self.assertEqual(len(records), 0)
|
||||
|
||||
def _assert_service_instance_equal(self, instance, info):
|
||||
self.assertEqual(instance['host'].lower(), info['host'].lower(), instance)
|
||||
for f in ('port', 'priority', 'weight', 'txt_data'):
|
||||
|
||||
Reference in New Issue
Block a user