xref: /aosp_15_r20/external/openthread/tests/scripts/thread-cert/test_srp_name_conflicts.py (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1#!/usr/bin/env python3
2#
3#  Copyright (c) 2021, 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 if the SRP server can handle name conflicts correctly.
39#
40# Topology:
41#            LEADER (SRP server)
42#           /      \
43#          /        \
44#         /          \
45#     ROUTER1      ROUTER2
46#
47
48SERVER = 1
49CLIENT1 = 2
50CLIENT2 = 3
51
52
53class SrpNameConflicts(thread_cert.TestCase):
54    USE_MESSAGE_FACTORY = False
55    SUPPORT_NCP = False
56
57    TOPOLOGY = {
58        SERVER: {
59            'name': 'SRP_SERVER',
60            'networkkey': '00112233445566778899aabbccddeeff',
61            'mode': 'rdn',
62        },
63        CLIENT1: {
64            'name': 'SRP_CLIENT1',
65            'networkkey': '00112233445566778899aabbccddeeff',
66            'mode': 'rdn',
67        },
68        CLIENT2: {
69            'name': 'SRP_CLIENT2',
70            'networkkey': '00112233445566778899aabbccddeeff',
71            'mode': 'rdn',
72        },
73    }
74
75    def test(self):
76        server = self.nodes[SERVER]
77        client_1 = self.nodes[CLIENT1]
78        client_2 = self.nodes[CLIENT2]
79
80        #
81        # 0. Start the server & client devices.
82        #
83
84        server.srp_server_set_enabled(True)
85        server.start()
86        self.simulator.go(config.LEADER_STARTUP_DELAY)
87        self.assertEqual(server.get_state(), 'leader')
88        self.simulator.go(5)
89
90        client_1.srp_server_set_enabled(False)
91        client_1.start()
92        self.simulator.go(config.ROUTER_STARTUP_DELAY)
93        self.assertEqual(client_1.get_state(), 'router')
94
95        client_2.srp_server_set_enabled(False)
96        client_2.start()
97        self.simulator.go(config.ROUTER_STARTUP_DELAY)
98        self.assertEqual(client_2.get_state(), 'router')
99
100        #
101        # 1. Register a single service and verify that it works.
102        #
103
104        self.assertEqual(client_1.srp_client_get_auto_start_mode(), 'Enabled')
105
106        client_1.srp_client_set_host_name('my-host-1')
107        client_1.srp_client_set_host_address('2001::1')
108        client_1.srp_client_add_service('my-service-1', '_ipps._tcp', 12345)
109        self.simulator.go(2)
110
111        # Verify that the client possesses correct service resources.
112        client_1_service = client_1.srp_client_get_services()[0]
113        self.assertEqual(client_1_service['instance'], 'my-service-1')
114        self.assertEqual(client_1_service['name'], '_ipps._tcp')
115        self.assertEqual(int(client_1_service['port']), 12345)
116        self.assertEqual(int(client_1_service['priority']), 0)
117        self.assertEqual(int(client_1_service['weight']), 0)
118
119        # Verify that the client receives a SUCCESS response for the server.
120        self.assertEqual(client_1_service['state'], 'Registered')
121
122        # Verify that the server accepts the SRP registration and stored
123        # the same service resources.
124        server_service = server.srp_server_get_services()[0]
125        self.assertEqual(server_service['deleted'], 'false')
126        self.assertEqual(server_service['instance'], client_1_service['instance'])
127        self.assertEqual(server_service['name'], client_1_service['name'])
128        self.assertEqual(int(server_service['port']), int(client_1_service['port']))
129        self.assertEqual(int(server_service['priority']), int(client_1_service['priority']))
130        self.assertEqual(int(server_service['weight']), int(client_1_service['weight']))
131        self.assertEqual(server_service['host'], 'my-host-1')
132
133        server_host = server.srp_server_get_hosts()[0]
134        self.assertEqual(server_host['deleted'], 'false')
135        self.assertEqual(server_host['fullname'], server_service['host_fullname'])
136        self.assertEqual(len(server_host['addresses']), 1)
137        self.assertEqual(ipaddress.ip_address(server_host['addresses'][0]), ipaddress.ip_address('2001::1'))
138
139        #
140        # 2. Register with the same host name from the second client and it should fail.
141        #
142
143        self.assertEqual(client_2.srp_client_get_auto_start_mode(), 'Enabled')
144
145        client_2.srp_client_set_host_name('my-host-1')
146        client_2.srp_client_set_host_address('2001::2')
147        client_2.srp_client_add_service('my-service-2', '_ipps._tcp', 12345)
148        self.simulator.go(2)
149
150        # It is expected that the registration will be rejected.
151        client_2_service = client_2.srp_client_get_services()[0]
152        self.assertNotEqual(client_2_service['state'], 'Registered')
153        self.assertNotEqual(client_2.srp_client_get_host_state(), 'Registered')
154
155        self.assertEqual(len(server.srp_server_get_services()), 1)
156        self.assertEqual(len(server.srp_server_get_hosts()), 1)
157
158        client_2.srp_client_clear_host()
159        client_2.srp_client_stop()
160
161        #
162        # 3. Register with the same service name from the second client and it should fail.
163        #
164
165        client_2.srp_client_enable_auto_start_mode()
166        client_2.srp_client_set_host_name('my-host-2')
167        client_2.srp_client_set_host_address('2001::2')
168        client_2.srp_client_add_service('my-service-1', '_ipps._tcp', 12345)
169        self.simulator.go(2)
170
171        # It is expected that the registration will be rejected.
172        client_2_service = client_2.srp_client_get_services()[0]
173        self.assertNotEqual(client_2_service['state'], 'Registered')
174        self.assertNotEqual(client_2.srp_client_get_host_state(), 'Registered')
175
176        self.assertEqual(len(server.srp_server_get_services()), 1)
177        self.assertEqual(len(server.srp_server_get_hosts()), 1)
178
179        client_2.srp_client_clear_host()
180        client_2.srp_client_stop()
181
182        #
183        # 4. Register the same service instance label with a different service name
184        # from the second client and it should pass.
185        #
186
187        client_2.srp_client_enable_auto_start_mode()
188        client_2.srp_client_set_host_name('my-host-2')
189        client_2.srp_client_set_host_address('2001::2')
190        client_2.srp_client_add_service('my-service-1', '_ipps2._tcp', 12345)
191        self.simulator.go(2)
192
193        # It is expected that the registration will be accepted.
194        client_2_service = client_2.srp_client_get_services()[0]
195        self.assertEqual(client_2_service['state'], 'Registered')
196        self.assertEqual(client_2.srp_client_get_host_state(), 'Registered')
197
198        self.assertEqual(len(server.srp_server_get_services()), 2)
199        self.assertEqual(len(server.srp_server_get_hosts()), 2)
200        self.assertEqual(server.srp_server_get_host('my-host-2')['deleted'], 'false')
201        self.assertEqual(server.srp_server_get_service('my-service-1', '_ipps2._tcp')['deleted'], 'false')
202
203        # Remove the host and all services registered on the SRP server.
204        client_2.srp_client_remove_host(remove_key=True)
205        self.simulator.go(2)
206
207        client_2.srp_client_clear_host()
208        client_2.srp_client_stop()
209
210        #
211        # 5. Register with different host & service instance name, it should succeed.
212        #
213
214        client_2.srp_client_enable_auto_start_mode()
215        client_2.srp_client_set_host_name('my-host-2')
216        client_2.srp_client_set_host_address('2001::2')
217        client_2.srp_client_add_service('my-service-2', '_ipps._tcp', 12345)
218        self.simulator.go(2)
219
220        # It is expected that the registration will be accepted.
221        client_2_service = client_2.srp_client_get_services()[0]
222        self.assertEqual(client_2_service['state'], 'Registered')
223        self.assertEqual(client_2.srp_client_get_host_state(), 'Registered')
224
225        self.assertEqual(len(server.srp_server_get_services()), 2)
226        self.assertEqual(len(server.srp_server_get_hosts()), 2)
227        self.assertEqual(server.srp_server_get_host('my-host-2')['deleted'], 'false')
228        self.assertEqual(server.srp_server_get_service('my-service-2', '_ipps._tcp')['deleted'], 'false')
229
230        # Remove the host and all services registered on the SRP server.
231        client_2.srp_client_remove_host(remove_key=True)
232        self.simulator.go(2)
233
234        client_2.srp_client_clear_host()
235        client_2.srp_client_stop()
236
237        #
238        # 6. Register with the same service instance full name before its KEY LEASE expires,
239        #    it is expected to fail.
240        #
241
242        # Remove the service instance from SRP server but retains its name.
243        client_1.srp_client_remove_service('my-service-1', '_ipps._tcp')
244        self.simulator.go(2)
245
246        client_2.srp_client_enable_auto_start_mode()
247        client_2.srp_client_set_host_name('my-host-2')
248        client_2.srp_client_set_host_address('2001::2')
249        client_2.srp_client_add_service('my-service-1', '_ipps._tcp', 12345)
250        self.simulator.go(2)
251
252        # It is expected that the registration will be rejected.
253        client_2_service = client_2.srp_client_get_services()[0]
254        self.assertNotEqual(client_2_service['state'], 'Registered')
255        self.assertNotEqual(client_2.srp_client_get_host_state(), 'Registered')
256
257        # The service 'my-service-1' is removed but its name is retained.
258        # This is why we can see the service record on the SRP server.
259        self.assertEqual(len(server.srp_server_get_services()), 1)
260        self.assertEqual(len(server.srp_server_get_hosts()), 1)
261        self.assertEqual(server.srp_server_get_host('my-host-1')['deleted'], 'false')
262        self.assertEqual(server.srp_server_get_service('my-service-1', '_ipps._tcp')['deleted'], 'true')
263
264        client_2.srp_client_clear_host()
265        client_2.srp_client_stop()
266
267        #
268        # 7. The service instance name can be re-used by another client when
269        #    the service has been permanently removed (the KEY resource is
270        #    removed) from the host.
271        #
272
273        # Client 1 adds back the service, it should success.
274        client_1.srp_client_add_service('my-service-1', '_ipps._tcp', 12345)
275        self.simulator.go(2)
276        self.assertEqual(len(server.srp_server_get_services()), 1)
277        self.assertEqual(len(server.srp_server_get_hosts()), 1)
278        self.assertEqual(server.srp_server_get_host('my-host-1')['deleted'], 'false')
279        self.assertEqual(server.srp_server_get_service('my-service-1', '_ipps._tcp')['deleted'], 'false')
280
281        # Permanently removes the service instance.
282        client_1.srp_client_remove_host(remove_key=True)
283        self.simulator.go(2)
284        self.assertEqual(len(server.srp_server_get_services()), 0)
285        self.assertEqual(len(server.srp_server_get_hosts()), 0)
286
287        # Client 2 registers the same host & service instance name with Client 1.
288        client_2.srp_client_stop()
289        client_2.srp_client_enable_auto_start_mode()
290        client_2.srp_client_clear_host()
291        client_2.srp_client_set_host_name('my-host-1')
292        client_2.srp_client_set_host_address('2001::2')
293        client_2.srp_client_add_service('my-service-1', '_ipps._tcp', 12345)
294        self.simulator.go(2)
295
296        # It is expected that client 2 will success because those names has been
297        # released by client 1.
298        self.assertEqual(len(server.srp_server_get_services()), 1)
299        self.assertEqual(len(server.srp_server_get_hosts()), 1)
300        self.assertEqual(server.srp_server_get_host('my-host-1')['deleted'], 'false')
301        self.assertEqual(server.srp_server_get_service('my-service-1', '_ipps._tcp')['deleted'], 'false')
302
303
304if __name__ == '__main__':
305    unittest.main()
306