1#!/usr/bin/env python3 2# 3# Copyright (c) 2022, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29 30import ipaddress 31import unittest 32 33import command 34import config 35import thread_cert 36 37# Test description: 38# This test verifies SRP client auto host address mode. 39# 40# Topology: 41# SRP client (leader) 42# | 43# | 44# SRP server (router) 45# 46 47CLIENT = 1 48SERVER = 2 49 50 51class SrpAutoHostAddress(thread_cert.TestCase): 52 USE_MESSAGE_FACTORY = False 53 SUPPORT_NCP = False 54 55 TOPOLOGY = { 56 CLIENT: { 57 'name': 'SRP_CLIENT', 58 'mode': 'rdn', 59 }, 60 SERVER: { 61 'name': 'SRP_SERVER', 62 'mode': 'rdn', 63 }, 64 } 65 66 def test(self): 67 client = self.nodes[CLIENT] 68 server = self.nodes[SERVER] 69 70 #------------------------------------------------------------------- 71 # Form the network. 72 73 client.srp_server_set_enabled(False) 74 client.start() 75 self.simulator.go(15) 76 self.assertEqual(client.get_state(), 'leader') 77 78 server.start() 79 self.simulator.go(5) 80 self.assertEqual(server.get_state(), 'router') 81 82 #------------------------------------------------------------------- 83 # Enable SRP server 84 85 server.srp_server_set_enabled(True) 86 self.simulator.go(5) 87 88 #------------------------------------------------------------------- 89 # Check auto start mode on SRP client 90 91 self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled') 92 self.simulator.go(2) 93 94 self.assertEqual(client.srp_client_get_state(), 'Enabled') 95 96 #------------------------------------------------------------------- 97 # Set host name and enable auto host address on client 98 99 client.srp_client_set_host_name('host') 100 client.srp_client_enable_auto_host_address() 101 102 #------------------------------------------------------------------- 103 # Register a service on client 104 105 client.srp_client_add_service('test_srv', '_test._udo', 12345, 0, 0) 106 self.simulator.go(2) 107 self.check_registered_addresses(client, server) 108 109 #------------------------------------------------------------------- 110 # Add an address and check the SRP client re-registered and updated 111 # server with new address. 112 113 client.add_ipaddr('fd00:1:2:3:4:5:6:7') 114 115 self.simulator.go(5) 116 client_addresses = [addr.strip() for addr in client.get_addrs()] 117 self.assertIn('fd00:1:2:3:4:5:6:7', client_addresses) 118 self.check_registered_addresses(client, server) 119 120 #------------------------------------------------------------------- 121 # Remove the address and check the SRP client re-registered and updated 122 # server. 123 124 client.del_ipaddr('fd00:1:2:3:4:5:6:7') 125 126 self.simulator.go(5) 127 client_addresses = [addr.strip() for addr in client.get_addrs()] 128 self.assertNotIn('fd00:1:2:3:4:5:6:7', client_addresses) 129 self.check_registered_addresses(client, server) 130 131 #------------------------------------------------------------------- 132 # Add an SLAAC on-mesh prefix (which will trigger an address to be 133 # added) and check that the SRP client re-registered and updated 134 # server with the new address. 135 136 client.add_prefix('fd00:abba:cafe:bee::/64', 'paos') 137 client.register_netdata() 138 self.simulator.go(5) 139 140 slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:abba:cafe:bee:')] 141 self.assertEqual(len(slaac_addr), 1) 142 self.check_registered_addresses(client, server) 143 144 #------------------------------------------------------------------- 145 # Add another SLAAC on-mesh prefix and check that the SRP client 146 # re-registered and updated server with all address. 147 148 client.add_prefix('fd00:9:8:7::/64', 'paos') 149 client.register_netdata() 150 self.simulator.go(5) 151 152 slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:9:8:7:')] 153 self.assertEqual(len(slaac_addr), 1) 154 self.check_registered_addresses(client, server) 155 156 #------------------------------------------------------------------- 157 # Add a non-preferred SLAAC on-mesh prefix and check that the 158 # set of registered addresses remains unchanged and that the 159 # non-preferred address is not registered by SRP client. 160 161 client.add_prefix('fd00:a:b:c::/64', 'aos') 162 client.register_netdata() 163 self.simulator.go(5) 164 165 slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:a:b:c:')] 166 self.assertEqual(len(slaac_addr), 1) 167 self.check_registered_addresses(client, server) 168 169 #------------------------------------------------------------------- 170 # Remove the on-mesh prefix and check that the SRP client 171 # re-registered and updated server with the remaining address. 172 173 client.remove_prefix('fd00:abba:cafe:bee::/64') 174 client.register_netdata() 175 176 self.simulator.go(5) 177 178 self.check_registered_addresses(client, server) 179 180 #------------------------------------------------------------------- 181 # Remove the next on-mesh prefix. Check that SRP client re-registered 182 # now with only ML-EID. 183 184 client.remove_prefix('fd00:9:8:7::/64') 185 client.register_netdata() 186 187 self.simulator.go(5) 188 189 self.check_registered_addresses(client, server) 190 191 #------------------------------------------------------------------- 192 # Explicitly set the host addresses (which disables the auto host 193 # address mode) and check that only the new addresses are registered. 194 195 client.srp_client_set_host_address('fd00:f:e:d:c:b:a:9') 196 self.simulator.go(5) 197 198 self.assertEqual(client.srp_client_get_host_state(), 'Registered') 199 server_hosts = server.srp_server_get_hosts() 200 self.assertEqual(len(server_hosts), 1) 201 server_host = server_hosts[0] 202 self.assertEqual(server_host['deleted'], 'false') 203 self.assertEqual(server_host['fullname'], 'host.default.service.arpa.') 204 host_addresses = [addr.strip() for addr in server_host['addresses']] 205 self.assertEqual(len(host_addresses), 1) 206 self.assertEqual(host_addresses[0], 'fd00:f:e:d:c:b:a:9') 207 208 #------------------------------------------------------------------- 209 # Re-enable auto host address mode and check that addresses are 210 # updated and registered properly. 211 212 client.srp_client_enable_auto_host_address() 213 self.simulator.go(5) 214 self.check_registered_addresses(client, server) 215 216 def check_registered_addresses(self, client, server): 217 # Ensure client has registered successfully. 218 self.assertEqual(client.srp_client_get_host_state(), 'Registered') 219 220 # Check the host info on server. 221 server_hosts = server.srp_server_get_hosts() 222 self.assertEqual(len(server_hosts), 1) 223 server_host = server_hosts[0] 224 self.assertEqual(server_host['deleted'], 'false') 225 self.assertEqual(server_host['fullname'], 'host.default.service.arpa.') 226 227 # Check the host addresses on server to match client. 228 229 host_addresses = [addr.strip() for addr in server_host['addresses']] 230 231 client_mleid = client.get_mleid() 232 client_addresses = [addr.split(' ')[0] for addr in client.get_addrs(verbose=True) if 'preferred:1' in addr] 233 client_addresses += [client_mleid] 234 235 # All registered addresses must be in client list of addresses. 236 237 for addr in host_addresses: 238 self.assertIn(addr, client_addresses) 239 240 # All preferred addresses on client excluding link-local and 241 # mesh-local addresses must be seen on server side. But if there 242 # was no address, then mesh-local address should be the only 243 # one registered. 244 245 checked_address = False 246 247 for addr in client_addresses: 248 if not self.is_address_link_local(addr) and not self.is_address_locator(addr) and addr != client_mleid: 249 self.assertIn(addr, host_addresses) 250 checked_address = True 251 252 if not checked_address: 253 self.assertEqual(len(host_addresses), 1) 254 self.assertIn(client_mleid, host_addresses) 255 256 def is_address_locator(self, addr): 257 # Checks if an IPv6 address is a locator (IID should match `0:ff:fe00:xxxx`) 258 u32s = addr.split(':') 259 self.assertEqual(len(u32s), 8) 260 return ':'.join(u32s[4:]).startswith('0:ff:fe00:') 261 262 def is_address_link_local(self, addr): 263 # Checks if an IPv6 address is link-local 264 return addr.startswith('fe80:') 265 266 267if __name__ == '__main__': 268 unittest.main() 269