blob: 5086a7baaeadd49c083f0be76dbd9180e334e7aa [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright (c) 2021, 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.
#
import unittest
import config
import thread_cert
# Test description:
#
# This test covers the SRP server's behavior using different address
# modes (unicast or anycast). The address mode indicates how the SRP
# server determines its address and port and how this info is
# published in the Thread Network Data. When using anycast address
# mode, the SRP server and DNS server/resolver will both listen on port
# 53 and they re-use the same socket. This test verifies the behavior of
# both modules in such a situation.
#
#
# Topology:
#
# One leader and two router nodes, all connected. The leader acts as SRP
# server and DNS resolver. One router acts as SRP client, and the
# other acts as DNS client browsing for registered service names.
#
SERVER = 1
CLIENT = 2
BROWSER = 3
DOMAIN = 'default.service.arpa.'
HOST = 'host'
INSTANCE = 'ins1'
SERVICE = '_srv._udp'
SERVICE_PORT = 1313
SRP_SERVER_ANYCAST_PORT = 53
SRP_SERVER_ANYCAST_SEQ_NUM = 17
DNS_RESOLVER_PORT = 53
THREAD_ENTERPRISE_NUMBER = 44970
ANYCAST_SERVICE_NUM = 0x5c
UNICAST_SERVICE_NUM = 0x5d
class TestSrpServerAnycastMode(thread_cert.TestCase):
SUPPORT_NCP = False
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
SERVER: {
'mode': 'rdn',
},
CLIENT: {
'mode': 'rdn',
},
BROWSER: {
'mode': 'rdn',
},
}
def test(self):
server = self.nodes[SERVER]
client = self.nodes[CLIENT]
browser = self.nodes[BROWSER]
#-------------------------------------------------------------------
# Form the network.
server.start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(server.get_state(), 'leader')
client.start()
browser.start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(client.get_state(), 'router')
self.assertEqual(browser.get_state(), 'router')
#-------------------------------------------------------------------
# Go through the entire test twice, first time using anycast address
# mode and second time using unicast address mode.
for addr_mode in ['anycast', 'unicast']:
#---------------------------------------------------------------
# Set the SRP server address mode and start the SRP server.
server.srp_server_set_addr_mode(addr_mode)
if addr_mode == 'anycast':
server.srp_server_set_anycast_seq_num(SRP_SERVER_ANYCAST_SEQ_NUM)
self.assertEqual(server.srp_server_get_anycast_seq_num(), SRP_SERVER_ANYCAST_SEQ_NUM)
self.assertEqual(server.srp_server_get_addr_mode(), addr_mode)
server.srp_server_set_enabled(True)
self.simulator.go(5)
#---------------------------------------------------------------
# Verify the published SRP server info in the Network Data.
netdata_services = client.get_services()
self.assertEqual(len(netdata_services), 1)
netdata_service = netdata_services[0]
self.assertEqual(int(netdata_service[0]), THREAD_ENTERPRISE_NUMBER)
data = bytes.fromhex(netdata_service[1])
self.assertEqual(netdata_service[3], 's')
if addr_mode == 'anycast':
self.assertTrue(len(data) >= 2)
self.assertEqual(data[0], ANYCAST_SERVICE_NUM)
self.assertEqual(data[1], SRP_SERVER_ANYCAST_SEQ_NUM)
else:
self.assertTrue(len(data) >= 1)
self.assertEqual(data[0], UNICAST_SERVICE_NUM)
self.assertEqual(netdata_service[3], 's')
#---------------------------------------------------------------
# Enable auto-start on SRP client. Verify that it does find the
# server and uses the proper address and port number.
client.srp_client_enable_auto_start_mode()
self.simulator.go(5)
if addr_mode == 'anycast':
server_alocs = server.get_ip6_address(config.ADDRESS_TYPE.ALOC)
self.assertEqual(client.srp_client_get_state(), 'Enabled')
self.assertIn(client.srp_client_get_server_address(), server_alocs)
self.assertEqual(client.srp_client_get_server_port(), SRP_SERVER_ANYCAST_PORT)
else:
self.assertIn(client.srp_client_get_server_address(), server.get_mleid())
self.assertEqual(client.srp_client_get_server_port(), server.get_srp_server_port())
#---------------------------------------------------------------
# Add a service on the SRP client and verify its successful
# registration with SRP server.
client.srp_client_set_host_name(HOST)
client.srp_client_set_host_address(client.get_mleid())
client.srp_client_add_service(INSTANCE, SERVICE, SERVICE_PORT)
self.simulator.go(5)
client_services = client.srp_client_get_services()
self.assertEqual(len(client_services), 1)
client_service = client_services[0]
self.assertEqual(client_service['instance'], INSTANCE)
self.assertEqual(client_service['name'], SERVICE)
self.assertEqual(int(client_service['port']), SERVICE_PORT)
self.assertEqual(client_service['state'], 'Registered')
#---------------------------------------------------------------
# Browse for a matching service name and verify that the registered
# service is successfully found. Since there is only one match the
# server should include the service info in additional section.
service_instances = browser.dns_browse(f'{SERVICE}.{DOMAIN}', server.get_mleid(), DNS_RESOLVER_PORT)
self.assertEqual({INSTANCE}, set(service_instances.keys()))
service_instance = service_instances[INSTANCE]
self.assertEqual(service_instance['host'], f'{HOST}.{DOMAIN}')
self.assertEqual(int(service_instance['port']), SERVICE_PORT)
self.assertEqual(service_instance['address'], client.get_mleid())
#---------------------------------------------------------------
# Stop SRP client and server and clear host (and service) on the
# client.
client.srp_client_clear_host()
client.srp_client_stop()
server.srp_server_set_enabled(False)
if __name__ == '__main__':
unittest.main()