• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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