• 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        # Enable auto start mode on SRP client
90
91        self.assertEqual(client.srp_client_get_state(), 'Disabled')
92        client.srp_client_enable_auto_start_mode()
93        self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled')
94        self.simulator.go(2)
95
96        self.assertEqual(client.srp_client_get_state(), 'Enabled')
97
98        #-------------------------------------------------------------------
99        # Set host name and enable auto host address on client
100
101        client.srp_client_set_host_name('host')
102        client.srp_client_enable_auto_host_address()
103
104        #-------------------------------------------------------------------
105        # Register a service on client
106
107        client.srp_client_add_service('test_srv', '_test._udo', 12345, 0, 0)
108        self.simulator.go(2)
109        self.check_registered_addresses(client, server)
110
111        #-------------------------------------------------------------------
112        # Add an address and check the SRP client re-registered and updated
113        # server with new address.
114
115        client.add_ipaddr('fd00:1:2:3:4:5:6:7')
116
117        self.simulator.go(5)
118        client_addresses = [addr.strip() for addr in client.get_addrs()]
119        self.assertIn('fd00:1:2:3:4:5:6:7', client_addresses)
120        self.check_registered_addresses(client, server)
121
122        #-------------------------------------------------------------------
123        # Remove the address and check the SRP client re-registered and updated
124        # server.
125
126        client.del_ipaddr('fd00:1:2:3:4:5:6:7')
127
128        self.simulator.go(5)
129        client_addresses = [addr.strip() for addr in client.get_addrs()]
130        self.assertNotIn('fd00:1:2:3:4:5:6:7', client_addresses)
131        self.check_registered_addresses(client, server)
132
133        #-------------------------------------------------------------------
134        # Add an SLAAC on-mesh prefix (which will trigger an address to be
135        # added) and check that the SRP client re-registered and updated
136        # server with the new address.
137
138        client.add_prefix('fd00:abba:cafe:bee::/64', 'paos')
139        client.register_netdata()
140        self.simulator.go(5)
141
142        slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:abba:cafe:bee:')]
143        self.assertEqual(len(slaac_addr), 1)
144        self.check_registered_addresses(client, server)
145
146        #-------------------------------------------------------------------
147        # Add another SLAAC on-mesh prefix and check that the SRP client
148        # re-registered and updated server with all address.
149
150        client.add_prefix('fd00:9:8:7::/64', 'paos')
151        client.register_netdata()
152        self.simulator.go(5)
153
154        slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:9:8:7:')]
155        self.assertEqual(len(slaac_addr), 1)
156        self.check_registered_addresses(client, server)
157
158        #-------------------------------------------------------------------
159        # Remove the on-mesh prefix (which will trigger an address to be
160        # removed) and check that the SRP client re-registered and updated
161        # server with the remaining address.
162
163        client.remove_prefix('fd00:abba:cafe:bee::/64')
164        client.register_netdata()
165        self.simulator.go(5)
166
167        slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:abba:cafe:bee:')]
168        self.assertEqual(len(slaac_addr), 0)
169        self.check_registered_addresses(client, server)
170
171        #-------------------------------------------------------------------
172        # Remove the next on-mesh prefix. Check that SRP client re-registered
173        # now with only ML-EID.
174
175        client.remove_prefix('fd00:9:8:7::/64')
176        client.register_netdata()
177        self.simulator.go(5)
178
179        slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:9:8:7:')]
180        self.assertEqual(len(slaac_addr), 0)
181        self.check_registered_addresses(client, server)
182
183        #-------------------------------------------------------------------
184        # Explicitly set the host addresses (which disables the auto host
185        # address mode) and check that only the new addresses are registered.
186
187        client.srp_client_set_host_address('fd00:f:e:d:c:b:a:9')
188        self.simulator.go(5)
189
190        self.assertEqual(client.srp_client_get_host_state(), 'Registered')
191        server_hosts = server.srp_server_get_hosts()
192        self.assertEqual(len(server_hosts), 1)
193        server_host = server_hosts[0]
194        self.assertEqual(server_host['deleted'], 'false')
195        self.assertEqual(server_host['fullname'], 'host.default.service.arpa.')
196        host_addresses = [addr.strip() for addr in server_host['addresses']]
197        self.assertEqual(len(host_addresses), 1)
198        self.assertEqual(host_addresses[0], 'fd00:f:e:d:c:b:a:9')
199
200        #-------------------------------------------------------------------
201        # Re-enable auto host address mode and check that addresses are
202        # updated and registered properly.
203
204        client.srp_client_enable_auto_host_address()
205        self.simulator.go(5)
206        self.check_registered_addresses(client, server)
207
208    def check_registered_addresses(self, client, server):
209        # Ensure client has registered successfully.
210        self.assertEqual(client.srp_client_get_host_state(), 'Registered')
211
212        # Check the host info on server.
213        server_hosts = server.srp_server_get_hosts()
214        self.assertEqual(len(server_hosts), 1)
215        server_host = server_hosts[0]
216        self.assertEqual(server_host['deleted'], 'false')
217        self.assertEqual(server_host['fullname'], 'host.default.service.arpa.')
218
219        # Check the host addresses on server to match client.
220
221        host_addresses = [addr.strip() for addr in server_host['addresses']]
222        client_addresses = [addr.strip() for addr in client.get_addrs()]
223
224        # All registered addresses must be in client list of addresses.
225
226        for addr in host_addresses:
227            self.assertIn(addr, client_addresses)
228
229        # All addresses on client excluding link-local and mesh-local
230        # addresses must be seen on server side. But if there was
231        # no address, then mesh-local address should be the only
232        # one registered.
233
234        client_mleid = client.get_mleid()
235        checked_address = False
236
237        for addr in client_addresses:
238            if not self.is_address_link_local(addr) and not self.is_address_locator(addr) and addr != client_mleid:
239                self.assertIn(addr, host_addresses)
240                checked_address = True
241
242        if not checked_address:
243            self.assertEqual(len(host_addresses), 1)
244            self.assertIn(client_mleid, host_addresses)
245
246    def is_address_locator(self, addr):
247        # Checks if an IPv6 address is a locator (IID should match `0:ff:fe00:xxxx`)
248        u32s = addr.split(':')
249        self.assertEqual(len(u32s), 8)
250        return ':'.join(u32s[4:]).startswith('0:ff:fe00:')
251
252    def is_address_link_local(self, addr):
253        # Checks if an IPv6 address is link-local
254        return addr.startswith('fe80:')
255
256
257if __name__ == '__main__':
258    unittest.main()
259